-
Notifications
You must be signed in to change notification settings - Fork 49
Document packing an application into one phar #392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
koriym
wants to merge
7
commits into
master
Choose a base branch
from
docs/phar-deployment
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
e6f0a59
Exclude MyVendor.Ticket from Jekyll build
koriym c955c9b
Document Phar deployment
koriym 394b874
Imports need no change, and the error table is the final one
koriym 82c22b5
Name the API that exists
koriym 8c57c6a
Merge remote-tracking branch 'upstream/master' into docs/phar-deployment
koriym 1eff0a7
Name the fromInjector case once
koriym 970caea
Merge master, and answer the review
koriym File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| --- | ||
| layout: docs-en | ||
| title: Phar | ||
| category: Manual | ||
| permalink: /manuals/1.0/en/phar.html | ||
| --- | ||
|
|
||
| # Phar | ||
|
|
||
| A [phar](https://www.php.net/manual/en/intro.phar.php) is the application as one file: the code, `vendor/`, and the compiled DI scripts in a single archive. The boot reads the archive and writes nothing into it — a deploy is a copy of one file, a rollback is the file before it. | ||
|
|
||
| ```text | ||
| prod-app.phar the application, vendor/, compiled DI scripts | ||
| /tmp/MyVendor/MyProject/prod-app everything the runtime writes | ||
| ``` | ||
|
|
||
| Requires BEAR.Package 1.23+. | ||
|
|
||
| ## Make your application a phar | ||
|
|
||
| The build script compiles, then packs. Both steps are on the compiler: | ||
|
|
||
| ```php | ||
| <?php | ||
| // bin/compile.php | ||
| use BEAR\Package\Compiler; | ||
|
|
||
| require dirname(__DIR__) . '/vendor/autoload.php'; | ||
|
|
||
| ini_set('memory_limit', '-1'); | ||
|
|
||
| $context = 'prod-hal-app'; | ||
| $writeDir = getenv('APP_WRITE_DIR') ?: null; | ||
|
|
||
| $compiler = new Compiler('MyVendor\MyProject', $context, dirname(__DIR__), $writeDir); | ||
| $code = $compiler(); | ||
|
|
||
| exit($code === 0 ? $compiler->phar() : $code); | ||
| ``` | ||
|
|
||
| The script names the application, the context it boots — the same one `public/index.php` uses — and reads the write directory from the environment. The rest it does not have to say, because packing is the framework's business: `src/`, `public/`, `vendor/` and the DI scripts with their compile marker go in; logs, caches, `.env`, `autoload.php`, `preload.php` and `tests/` stay out. The marker is `.bear-compile.json`, and it is what `phar()` reads to decide: `app`, `context`, `tmpDir`, `writeDir`, `time`. The `.env` file stays out, but the values it held are compiled into the DI scripts, and those ship: treat the archive as a secret. `phar.readonly` is handled in a child process, so there is no ini flag to remember. | ||
|
|
||
| ```bash | ||
| APP_WRITE_DIR=/tmp php bin/compile.php | ||
| ``` | ||
|
|
||
| ```text | ||
| Compiled: 16 resource classes | ||
| Phar: /app/var/build/prod-hal-app.phar (7.5MB, 2100 files) | ||
| Writes: /tmp | ||
| ``` | ||
|
|
||
| `__invoke()` and `phar()` are separate steps, so a build pipeline can compile in one job and pack in another. `phar()` packs what is on disk and refuses a context that was never compiled, or one compiled for another write directory. It writes `{appDir}/var/build/{context}.phar`; another entry or another output are its two arguments. Compiling several contexts is a loop in your script; `preload.php` and `autoload.php` are written to fixed paths, so rename them between contexts as [Production](production.html#compilation-recommended) shows. | ||
|
|
||
| ## Run | ||
|
|
||
| ```bash | ||
| APP_WRITE_DIR=/tmp php var/build/prod-hal-app.phar get '/index?name=BEAR' | ||
| ``` | ||
|
|
||
| The stub runs `public/index.php` from inside the archive, so `dirname(__DIR__)` in `src/Injector.php` is `phar:///path/prod-hal-app.phar`. The entry points are the ones [read-only deployments](production.html#writable-paths) shows; nothing else changes. | ||
|
|
||
| php-fpm runs a file, not an archive, so the entry point sits next to it and loads the autoloader from inside: | ||
|
|
||
| ```php | ||
| <?php | ||
| // index.php, in the same directory as prod-hal-app.phar | ||
| require 'phar://' . __DIR__ . '/prod-hal-app.phar/vendor/autoload.php'; | ||
|
|
||
| exit((new MyVendor\MyProject\Bootstrap())('prod-hal-app', $GLOBALS, $_SERVER, getenv('APP_WRITE_DIR') ?: null)); | ||
| ``` | ||
|
|
||
| ## Two rules | ||
|
|
||
| **One write directory, the same absolute path at the build and at the boot.** The compiled scripts hold the paths they were compiled with, so an archive is built for one write directory. `APP_WRITE_DIR` is that one place: the build reads it and the boot reads it. Imported applications receive it from the container, so nothing else names it. | ||
|
|
||
| **No binding that derives a runtime path from `$appMeta->appDir`.** The compiled scripts carry the `Meta` of the build, so the injected `appDir` is the build directory, not `phar://…`; `tmpDir` and `logDir` are the write directory and are correct. Anything that reads a file at runtime — a template directory, a data file — takes its path from `__DIR__`, which resolves inside the archive. | ||
|
|
||
| ## Imported applications | ||
|
|
||
| An [imported application](import.html) in the archive is a second application: its own `Meta`, its own compiled scripts, its own write directory. It needs no change at all - the container hands it the write directory the host was given: | ||
|
|
||
| ```php | ||
| $this->install(new ImportAppModule([ | ||
| new ImportApp('greeting', 'ImportVendor\Greeting', 'prod-app') | ||
| ])); | ||
| ``` | ||
|
|
||
| The compile boots the application, that boot compiles each imported application into its own tree (`Compiled DI scripts on demand` in the build log is that), and the pack ships their DI scripts automatically. An imported application resolves its own directory at boot, so it follows the archive. | ||
|
|
||
| ## When the build stops | ||
|
|
||
| Everything that used to fail at the deploy fails at the build, with the path in the message: | ||
|
|
||
| | Error | Meaning | | ||
| |---|---| | ||
| | `PharNotCompiledException` | The context was never compiled: `phar()` packs what is on disk | | ||
| | `PharImportsUnreadableException` | The compiled container declares its imports in a form this version cannot read: recompile with the version that packs | | ||
| | `PharWritesInsideArchiveException` | An application — the host or an import — was compiled to write into the tree. Compile with `APP_WRITE_DIR` set | | ||
| | `PharWriteDirMismatchException` | An import writes somewhere other than under the host's write directory: it was compiled before the host was given this one | | ||
| | `PharImportOutsideTreeException` | An imported application lies outside the tree being packed and cannot ship in it | | ||
| | `PharEntryNotFoundException` | No `public/index.php`; pass another entry to `Compiler::phar()` | | ||
| | `PharEntryNotPackedException` | The entry exists but does not ship: nothing loose at the application root does | | ||
| | `PharStaleOutputException` | An archive of a previous build survived at the output path and could not be removed | | ||
| | `PharSymlinkedDirectoryException` | A directory in the tree is a symlink, which `Phar` cannot pack | | ||
|
|
||
| At boot, an archive started without `APP_WRITE_DIR` stops with `WriteDirRequiredException`, and one started with a different `APP_WRITE_DIR` than the build stops with `CompiledForAnotherWriteDirException`, naming both directories. | ||
|
|
||
| Background: [BEAR.Package#426](https://github.com/bearsunday/BEAR.Package/issues/426). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.