Skip to content

Commit c69629e

Browse files
Wilfredgithub-actions[bot]
authored andcommitted
Update guides/hack from HHVM repository
1 parent a58af98 commit c69629e

File tree

4 files changed

+546
-172
lines changed

4 files changed

+546
-172
lines changed
Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,89 @@
1-
# Introduction
1+
# Introduction to Packages
22

3-
Packages are an extension to modules for HHVM and Hack which allows developers to more easily configure which files to build and deploy.
3+
Packages are a file-based mechanism for organizing code into logical units with explicit dependencies and fine-grained deployment control.
44

5-
## Package definitions
6-
A **package** is defined by a set of modules meant to be deployed together. Packages are configured in a toml file called `PACKAGES.toml` located at the root of your codebase (next to .hhconfig).
5+
## Key Concepts
6+
7+
**Packages** group related files in your codebase (e.g., production code, test code, experimental features).
8+
9+
**Deployments** define which packages to build and run together.
10+
11+
**Package relationships:** Packages explicitly include other packages to access their symbols, creating a dependency graph.
12+
13+
## Quick Example
14+
15+
Packages are configured in a TOML file called `PACKAGES.toml` located at the root of your codebase (next to `.hhconfig`):
716

817
```toml PACKAGES.toml
918
[packages]
1019

1120
[packages.production]
12-
uses=["prod.*", "my_prod"] # Package contains all modules that start with `prod`, and the module "my_prod".
21+
include_paths = ["//flib/"]
1322

1423
[packages.test]
15-
uses=["test.*"]
16-
includes=["production"] # Package depends on the production package
24+
include_paths = ["//flib/test/"]
25+
includes = ["production"] # test depends on production
26+
27+
[deployments]
28+
29+
[deployments.production]
30+
packages = ["production"]
31+
32+
[deployments.test]
33+
packages = ["test", "production"] # must include dependencies
34+
```
35+
36+
In this example:
37+
- The `production` package contains all files in `//flib/` (but not those in //flib/test/)
38+
- The `test` package contains files in `//flib/test/` and can access symbols defined in files in the production package
39+
- Two deployments are defined: one for production-only and one that includes tests
40+
41+
## How Packages Work
42+
43+
Each file in your codebase belongs to exactly one package. The same file path cannot appear in multiple packages' `include_paths` clauses.
44+
45+
## File package membership
46+
47+
Files can be assigned to packages in two ways:
48+
49+
### 1. Via `include_paths` in PACKAGES.toml
50+
51+
The `include_paths` clause specifies which files belong to a package:
52+
- Items are relative paths starting with `//` (representing the root directory)
53+
- A path ending with `/` (e.g., `"//flib/"`) includes all files recursively in that directory
54+
- A path without trailing `/` (e.g., `"//flib/foo.php"`) includes only that specific file
55+
56+
### 2. Via `__PackageOverride` file attribute
57+
58+
A file can override its package membership using the `__PackageOverride` attribute:
59+
60+
```hack no-extract
61+
<?hh
62+
<<file: __PackageOverride('production')>>
63+
// This file now belongs to the 'production' package
1764
```
1865

19-
Every module can be in at most one package, so the same module cannot be part of two packages. Therefore, the same glob cannot appear in the uses clause of two different modules.
66+
## Precedence rules
67+
68+
When determining which package a file belongs to:
69+
1. If a file has a `__PackageOverride` attribute, it belongs to that package
70+
2. Otherwise, if the full (relative-to-php-root) file path appears in an `include_paths` clause, it belongs to that package
71+
3. Otherwise, the file belongs to the package whose `include_paths` contains the file's nearest ancestor directory (i.e. the longest prefix match)
72+
4. If none of the above apply, the file belongs to the **default package**
73+
74+
## Default package
75+
76+
Any file not specified in any package (neither via `include_paths` nor `__PackageOverride`) belongs to the implicit "default" package. Symbols within the default package are not accessible from other packages. The default package:
77+
- Cannot be explicitly defined with the name "default" (the name is reserved)
78+
- Cannot be referenced via its name in `includes` and `soft_includes` lists
79+
- Can be made explicit by creating a package that includes `"//"`
80+
81+
**Example of making default explicit:**
82+
```toml
83+
[packages.orphans]
84+
include_paths = ["//"]
85+
```
2086

21-
## Overlaps in module globs
22-
- It is an error for the same module glob to appear in multiple package definitions. Given a module with name foo.bar, we resolve what package the module belongs to with the following precedence:
23-
- If a package lists foo.bar directly in its use clause, foo.bar belongs to that package. If multiple packages list foo.bar directly, we throw an error at package definition.
24-
- If no package directly references the module, but a package has a prefix which matches foo.bar (in this case, foo.* for example), foo.bar belongs to the package with that prefix. If multiple packages list a prefix of the module, we take the most specific prefix, i.e. the longest prefix that matches.
25-
- If no package references the module in its use clause, the module belongs to the default package.
87+
This creates a package that captures all files not in other packages.
2688

2789
Once you've defined a set of packages, you can deploy them using [deployments](/docs/hack/packages/deployments).
Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,90 @@
11
# Deployments
22

3-
Once you've defined a set of packages, you can deploy them using **deployments**.
3+
## What is a Deployment?
44

5-
## Deployments
6-
A **deployment** is defined as a set of packages. Deployments are also defined in PACKAGES.toml:
5+
A **deployment** is a set of packages built and deployed together. One may think of it as a build target configuration telling HHVM which code to compile and run.
6+
7+
**Key requirements:**
8+
- A deployment must be **transitively closed** with respect to package dependencies
9+
- If package A includes package B, and A is deployed, B must also be explicitly deployed
10+
11+
## Defining Deployments
12+
13+
Deployments are defined in the `[deployments]` section of `PACKAGES.toml`:
714

815
```toml PACKAGES.toml
916
[packages]
1017

1118
[packages.production]
12-
uses=["prod.*", "my_prod"] # Package contains all modules that start with `prod`, and the module "my_prod".
19+
include_paths = ["//flib/"]
1320

1421
[packages.test]
15-
uses=["test.*"]
16-
includes=["production"] # Package depends on the production package
22+
include_paths = ["//flib/test/"]
23+
includes = ["production"]
1724

1825
[deployments]
26+
1927
[deployments.production]
20-
packages=["production"]
28+
packages = ["production"]
2129

2230
[deployments.test]
23-
packages=["test", "production"] # Since the test package includes production, they must be deployed together.
31+
packages = ["test", "production"] # Must include production since test depends on it
32+
```
33+
34+
### Transitive Closure Requirement
35+
36+
The `packages` list must include all transitive dependencies:
37+
38+
```toml
39+
[packages.core]
40+
include_paths = ["//flib/core/"]
41+
42+
[packages.utils]
43+
include_paths = ["//flib/utils/"]
44+
includes = ["core"]
45+
46+
[packages.app]
47+
include_paths = ["//flib/app/"]
48+
includes = ["utils"]
49+
50+
[deployments.app]
51+
# Error: Missing core
52+
# packages = ["app", "utils"]
53+
54+
# Correct: Includes all transitive dependencies
55+
packages = ["app", "utils", "core"]
56+
```
57+
58+
Even though `app` only directly includes `utils`, the deployment must explicitly list all three packages.
59+
60+
## Using Deployments with HHVM
61+
62+
Specify the active deployment:
63+
64+
```ini
65+
Eval.Runtime.ActiveDeployment = production
2466
```
2567

26-
When building in [repo authoritative](/docs/hack/../hhvm/advanced-usage/repo-authoritative) mode, you can pass in the build configuration `Eval.ActiveDeployment = <deployment>` to set the active deployment. HHVM will then include only the files in the active deployment when building.
68+
When running in [repo authoritative](/docs/hhvm/advanced-usage/repo-authoritative) mode, HHVM only compiles and runs files from packages in the specified deployment. References to undeployed packages cause runtime errors (e.g., "Class not found" or "Call to undefined function"). When running in other modes, the active deployment serves only to modify semantics of `package` checks and the `__RequirePackage` attribute.
2769

28-
## Deployment domains
29-
In CLI-server mode, HHVM can direct different domains to different deployments, allowing you to treat a web request as if it were built in repo mode with a specific deployment. You can set the `domains` value of to any deployment to a list of regexes:
70+
71+
### Force Symbol References (Legacy)
72+
73+
For migration purposes, one can use the `ForceEnableSymbolRefs` option to allow additional "symbolically-referenced" files to be built alongside the active deployment. Note that this only affects [repo authoritative](/docs/hhvm/advanced-usage/repo-authoritative) mode.
74+
75+
## Soft Packages (Migration Support)
76+
77+
Deployments can specify `soft_packages` for files intended to be later excluded:
3078

3179
```toml
3280
[deployments.production]
33-
packages=["production"]
34-
domains=["^.*my_website\.com"]
81+
packages = ["production"]
82+
soft_packages = ["legacy_code"]
3583
```
36-
The domains field matches on the `Host` field of any web request that HHVM serves. In this example, traffic that hits `my_website.com` will be treated as if the active deployment were production. Note that a hostname can match multiple regexes, but the **first** deployment listed which has a regex that matches the hostname will be used.
84+
85+
Accessing soft-deployed package symbols logs a warning instead of throwing an error, allowing identification of dynamic boundary violations.
86+
87+
**Rules:**
88+
- Soft-included packages must be at least soft-deployed
89+
- Hard-included packages must be hard-deployed
90+
- `package_exists()` returns `false` for soft packages. See [Cross Package Usage](/docs/hack/packages/cross-package-calls) for details.

0 commit comments

Comments
 (0)