English | 中文文档
Package: super-kernel/composer-source-reference-plugin · Packagist · Documentation index
Composer gives a package installed from a local path repository a reference that does not follow the package's source, so composer.lock can stay the same while the code behind it changes. super-kernel/composer-source-reference-plugin replaces that reference, for super-kernel/* path packages, with one computed from the package's production source. A change to that source then changes composer.lock, and everything that trusts the lock, such as the build metadata of skernel build, sees it.
The plugin works only inside Composer, during composer update. Packages installed from Packagist, the root package, and packages of other vendors are left alone, and nothing scans source when the application starts.
Require the plugin in the project that installs the path packages and permit it in config.allow-plugins. A path package takes its version from its directory, such as dev-main for a checkout of the main branch, so require it with a constraint that accepts that version, such as *.
The project's manifest, saved as composer.json, with a copy of super-kernel/filesystem in ../packages/filesystem:
{
"name": "acme/billing",
"type": "project",
"repositories": [
{
"type": "path",
"url": "../packages/filesystem"
}
],
"require": {
"super-kernel/composer-source-reference-plugin": "^1.0.0-alpha.2",
"super-kernel/filesystem": "*"
},
"minimum-stability": "dev",
"prefer-stable": true,
"config": {
"allow-plugins": {
"super-kernel/composer-source-reference-plugin": true
}
}
}Composer loads a plugin only after it is installed, and the plugin must be loaded before Composer builds its dependency pool. Introducing the plugin therefore takes two updates: the first installs it, the second computes the references. From then on, every composer update does both.
composer update
composer updatecomposer.lock then records the path package with a dist.reference of sk-source-v1- followed by 64 hexadecimal digits, such as:
sk-source-v1-7681e1c9d13c586b0e646fead9ad081cdfe5440425fde9f384062aa9c4ec63f5
During each update, the plugin processes a package only when all of these hold:
- its name starts with
super-kernel/; - it comes from a
pathrepository, with a non-empty URL and an original reference; - the update resolves it: a package kept locked or fixed by the update, such as one not named in
composer update <package>, and an alias keep their current reference.
The reference is a hash of:
- the package name;
- the reference that Composer computed for the path repository, so changes to the package's
composer.jsonor to the repository's options still change the result; - every file that the package's production
autoloadrules reach, throughpsr-0,psr-4,classmap, andfiles, as its package-relative path and its bytes, sorted by path.
Files that exclude-from-classmap matches are left out of psr-0, psr-4, and classmap. The package's autoload-dev, its tests, its documentation, and any file no production rule reaches do not count. The absolute location of the checkout, file times, inode data, and the order in which the filesystem lists directories never affect the result, so the same source gives the same reference on every machine. A reference that the plugin already generated is recognized and not hashed again, so repeated updates are stable.
After a change to a production source file of the path package, an update of that package writes a new reference. Restoring the file restores the previous reference; changing a file outside the production rules, such as a document, changes nothing.
composer update super-kernel/filesystemThe metadata that skernel build generates records a hash of composer.lock. A new reference changes the lock, so the next start raises SuperKernel\Metadata\Exception\BuildRequiredException with the message The metadata generated by SKERNEL <version> does not match the current composer.lock. Run `skernel build` to generate the project metadata. Run skernel build after the update, or start with skernel run, which builds first. This is how a change in a local package reaches the application without any scan at start.
composer update --no-plugins does not load the plugin, so Composer writes its own path references again, and the lock no longer follows the source. composer install installs the references already in the lock.
The plugin fails the update instead of writing a reference from a partial scan. Every error is a RuntimeException that Composer reports and that stops the update.
| Situation | Message |
|---|---|
| An autoload path with a null byte | Autoload paths must not contain null bytes. |
| An absolute autoload path | Autoload path "<path>" must be package-relative. |
An autoload path with .. |
Autoload paths must not contain ".." segments. |
A wildcard other than *, or a wildcard outside classmap |
Classmap paths support only the "*" wildcard. or Only classmap paths may contain the "*" wildcard. |
| An autoload path that resolves outside the package, such as through a symbolic link | Autoload path "<path>" resolves outside package root "<root>". |
A files entry that is not a regular file |
Autoload file "<path>" is not a regular file. |
An autoload field that is not an array, or a list with non-string entries |
autoload.<field> must be an array. or <context> must contain only strings. |
An invalid exclude-from-classmap pattern |
Invalid classmap exclusion pattern "<pattern>"., Classmap exclusion patterns must not contain null bytes., or Classmap exclusion patterns must not contain ".." segments. |
| A classmap pattern or source directory that cannot be read | Unable to expand classmap pattern "<path>". or Unable to scan source directory "<path>". |
| A source file that cannot be read | Unable to hash source file "<path>". |
| The path package's directory is missing | Path package directory "<url>" is unavailable. |
A missing optional inclusion, such as a psr-4 directory that does not exist, contributes no files and is not an error.
super-kernel/metadatacompares the hash ofcomposer.lockrecorded byskernel buildwith the current lock and raisesBuildRequiredExceptionwhen they differ.skernel buildregenerates the metadata from the updated lock;skernel runbuilds before it starts the application.- The plugin depends on no other SuperKernel package, and no SuperKernel package requires it; it serves projects that install SuperKernel packages from local paths.
Do not update the lock with --no-plugins in a project that relies on these references. Composer then writes its own path references, and later source changes no longer change composer.lock, so skernel build is not required and the application keeps metadata for the old source. Run composer update with plugins enabled.