| Age | Commit message (Collapse) | Author |
|
A plugin can now hand an InstallerInterface implementation to
InstallationManager::addInstaller across the wire, and a legacy
composer-installer package is loaded as one; both are backed by a
PhpInstallerProxy forwarding the whole installer contract to the entity in
the PHP worker. An installer returning a real promise is an explicit error
until promises can cross the boundary.
InstallationManager takes installers as shared handles instead of boxes, so
the object identity removeInstaller and PluginManager's registeredPlugins
compare against survives registration, and holds them in a RefCell:
Installer::run keeps a shared borrow of the manager for the whole run, and a
plugin activated inside it registers its installer from there. The type
cache keys on the installer itself, like upstream, so re-entrant
registration cannot leave a stale index behind. InstallerInterface::supports
is fallible for the same reason getCapabilities and getCommands are: it
answers over RPC.
Cloning a proxy stub clones the Rust-side entity and rebinds the copy to the
fresh handle. Previously only the classes declaring __clone got a throwing
body, and the rest let two stubs share (and twice release) one handle.
Package entities answer with AnyPackage::dup, which already carries
BasePackage::__clone and the RootAliasPackage override; the others are an
explicit error.
The package proxy covers the whole PackageInterface surface; only the link
maps and the release date still lack a wire image for their value objects.
PluginManager gains a test-only seam for the reported Plugin API version,
and the three PluginInstallerTest cases that need it are ported.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
InstallationManager::execute now takes &self (the mock recorder moved
into a RefCell) and its callers hold only shared borrows: plugin
registration inside a batch re-enters the same manager handle through
Composer::getInstallationManager()->getInstallPath(), which panicked
on the RefCell re-borrow under the &mut shape — the same re-entrancy
the repository side already fixed, unreachable from the ported tests
because they call PluginInstaller::install directly like PHPUnit does.
The worker-side InstalledVersions mirror now matches the full tail of
FilesystemRepository::write: unconditional reload plus the
reflection-based selfDir/installedIsLocalDir restore. The previous
class_exists(false) guard rested on a lazy-load assumption that does
not hold in the worker (its real ClassLoader only knows the Composer
checkout's vendor dir, so a later lazy load would read the checkout's
installed.php, not the project's); the mirror is now skipped only when
the class is not autoloadable at all, i.e. no plugin runtime and hence
no observer code. Boot-time seeding stays TODO(plugin).
Also from the review: registered_plugins entries are removed only
after the deactivate/uninstall loop (PHP unsets last, and a throw must
leave the entry observable); extra.class keeps associative-array
values and fails loudly on non-strings instead of silently dropping
them; the two discarded write() results now propagate (they carry the
reload-push failure); register_package's allow-plugins skip message is
DEBUG like the addPlugin side; the loader-eviction divergence of
REGISTERED_LOADERS and the lossy UTF-8 spots carry searchable
markers; the test-only proxy downcast follows the __ naming rule; the
R-table dispatch clones the entity out instead of holding the table
borrow across the handler; the IO/PartialComposer stubs turn a
plugin-side `new NullIO()` into an explicit error instead of an
ArgumentCountError; and the empty() emulation covers float 0.0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
Implement the remainder of PluginManager::registerPackage: the plugin
autoload map is built by the ported createLoader/parseAutoloads and
served to the worker over the existing reverse-RPC autoloader, files
entries go through a composerRequire-equivalent glue call, and
already-defined classes take the upstream _composer_tmp rename/eval
path. Instantiation uses the new NewObject/CallPhpMethod lanes backed
by a P table in the worker; PhpPluginProxy adapts the resulting handle
to PluginInterface, with $composer/$io exposed to plugin callbacks via
an R table (unsupported methods stay explicit errors). Hand-written
proxy stubs cover Composer, PartialComposer and the IO hierarchy, and
the stub autoloader is re-prepended after loading the Composer PHP
runtime so its vendor autoloader cannot shadow proxied FQCNs.
FilesystemRepository::write now mirrors InstalledVersions::reload into
a running worker (class_exists-guarded, so an unloaded class keeps its
upstream lazy-load behavior), removing the previously undefined
observation window.
The installer pipeline passes the installed repository as a shared
handle instead of a long-lived `&mut dyn`: plugin registration runs
inside InstallationManager::execute and re-enters the same local
repository through the RepositoryManager, which would panic on the
RefCell re-borrow under the old shape.
PluginInterface lifecycle methods now take an owned ComposerHandle
(plugins retain $composer past the call) and return anyhow::Result
(PHP plugin code may throw); the plugin list uses shared ownership so
the identity comparison of removePlugin survives the dual storage in
registeredPlugins, matching PHP reference semantics.
Ports the activate/upgrade/uninstall tests of PluginInstallerTest,
serialized across the shared worker process whose persistent class
table is exactly what exercises the rename path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
Implement the two script execution paths that previously stopped at
todo!(): a Class::method listener is invoked as CallStaticMethod with the
event crossing the boundary as a proxy-stub handle, and a Command-class
listener runs inside a throwaway bare Symfony Application hosted by the
worker via a generated snippet, its BufferedOutput written back through
the dispatcher's IO. makeAutoloader is ported for real (canonical-package
hash, setDevMode, buildPackageMap/parseAutoloads/createLoader), and the
class_exists/is_callable/is_a/defined guards now query the worker, whose
script autoloader resolves classes by asking the Rust-side ClassLoader
over the reverse channel. EventInterface gains as_any (the IOInterface
downcast pattern) so the concrete event type is reachable behind the
trait object. Application::do_run now registers ScriptAliasCommand
entries as typed commands, unblocking the run-script --list/alias tests;
the dev-mode-to-generator test is ported with local mockall mocks. The
remaining ignored tests carry re-verified reasons: the listener methods
live on the PHPUnit test class itself (unloadable in the worker), or the
test needs live import of a user PHP Command class into the Application.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
The only missing seam was the PHP test's
ReflectionMethod(getPhpExecCommand) access; add the test-only
__get_php_exec_command wrapper and port the test on the existing
get_listeners override and process-executor mock infrastructure.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
The old reason blamed missing mock infrastructure, but a spy against
dyn AutoloadGeneratorInterface is perfectly writable. The actual blocker
is that make_autoloader (PHP makeAutoloader, called from doDispatch's
script branches, where setDevMode is invoked) is an intentional no-op in
the port, so set_dev_mode is never reached and a spy would observe
nothing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
The ignore reason went stale: the getListeners override seam and a real
ProcessExecutor wired to the IO already cover the PHP setup, and IOStub
is the PHPUnit IOInterface-mock equivalent. IOStub now records
writeError calls (writeRaw was already recorded) so the
expects(once)->with(...) spies on writeError/writeRaw can be reproduced
as call-list equality assertions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
support
ProcessExecutor::execute_async's mock branch was an unimplemented
todo!(), blocking every test whose code path calls it (feature-branch
git diffing, system-unzip/7z fallback extraction). Implement it by:
- Adding Process::__mock (mirroring the existing ZipArchive::__mock
pattern) so execute_async can resolve with a fabricated, already-
terminated Process instead of spawning a real subprocess.
- Extracting the sync mock's expectation-matching logic into a shared
ProcessExecutor::mock_match, wrapping the mock state in a RefCell so
it works from execute_async's &self/&mut self receivers.
- Setting error_output/capture_output from the mock branch, matching
PHP's ProcessExecutorMock::executeAsync sharing doExecute with the
sync path; execute_async now takes &mut self for this (safe, since
the borrow only needs to live through the synchronous setup, not
across the .await).
- Turning a strict-mode expectation mismatch from a panic!() into a
shirabe_php_shim::RuntimeException Err, mirroring PHPUnit's
AssertionFailedError extending \RuntimeException: PHP call sites
that catch (\RuntimeException $e) around a mocked git/hg/svn call
(e.g. Git::get_mirror_default_branch, GitDriver::supports) treat a
mismatch as an ordinary recoverable failure, and now so does the
port. The RefMut is dropped before firing an expectation's optional
callback so a re-entrant callback doesn't panic on double-borrow.
Also fixes two real bugs found while porting test_private_repository_
no_interaction: GitHub::authorize_oauth and GitLab::authorize_oauth
checked their domains config via PhpMixed::as_array(), which only
matches the Array (map) variant, but github-domains/gitlab-domains
default to PhpMixed::List, so the check always returned false and OAuth
token lookup was silently skipped. Use the in_array shim instead,
matching PHP's in_array() semantics. Also fix Git::run_command's
"capture credentials from git remote -v" call, which used the panic-
swallowing execute_args wrapper instead of a fallible execute(), so a
mock mismatch there couldn't reach get_mirror_default_branch's catch.
Un-ignores:
- zip_downloader_test::test_system_unzip_only_{good,failed}
- zip_downloader_test::test_non_windows_fallback_{good,failed}
- event_dispatcher_test::test_dispatcher_outputs_error_on_failed_command
- root_package_loader_test::test_feature_branch_pretty_version
- version_guesser_test::test_guess_version_reads_and_respects_non_feature_branches_configuration_for_arbitrary_naming{,_regex}
- version_guesser_test::test_remote_branches_are_selected
- github_driver_test::test_private_repository_no_interaction (also
adds the missing #[serial], since it seeds the shared Git::VERSION
static that vcs_repository_test::test_load_versions depends on for
real)
- init_command_test::test_get_git_config, made deterministic by
pointing HOME at a throwaway dir with its own .gitconfig instead of
depending on the host's global git config
Deduplicates the GitVersionGuard/RestoreEnv test-drop-guard idioms into
tests/common/test_case.rs instead of reimplementing them per file.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
No test logic changes.
|
|
|
|
|
|
|
|
Port perforce (36), locker (10), composer_repository (7), installation_manager
(6), file_downloader (5), and event_dispatcher (6) tests via the mock infra.
Fix production porting bugs surfaced en route: BufferIO::get_output look-behind
regex, ComposerRepository list-form package iteration and initialize dispatch,
gethostname and spl_autoload_functions shims; add EventDispatcher get_listeners
test seam.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
The per-file stub!/encode_stub!/etc. macros generated #[ignore]d test
functions but obscured the individual test bodies. Expanding them inline
removes the macro indirection so future ports can fill in each function
directly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Port PHP setUp/tearDown across the ported integration tests using
same-named set_up()/tear_down() functions and a TearDown struct whose
Drop runs tear_down(). Fixture-init setUp returns its fixtures;
tmpdir-style setUp/tearDown carry state in TearDown fields. Parts that
depend on unported infrastructure (PHPUnit mocks, Config::merge, the PHP
error handler) stay todo!() and are only wired into ignored stubs to
avoid breaking live tests.
Also fix shirabe-php-shim putenv to handle the no-'=' form (PHP unsets
the variable), which Platform::clear_env relies on for the env-clearing
tearDowns.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
All ignored: these mock IO/HttpDownloader (curl)/ProcessExecutor/installers,
use ZipArchive/JsonManipulator todo!()s, need Symfony console or schema
validation, reflect into ClassLoader, or run end-to-end install/functional
fixtures. Wires up the event_dispatcher test target.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|