aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src
AgeCommit message (Collapse)Author
2026-07-04fix(console-application): implement --profile via IOInterface::enable_debuggingnsfisis
The --profile flag parsed the option but never actually enabled the timing/memory output, because ConsoleIO::enableDebugging existed only as an inherent method, unreachable through the `dyn IOInterface` handle held by Application. Promote enable_debugging to an IOInterface trait method (default panics, since only ConsoleIO/BufferIO ever legitimately receive this call) so do_run can invoke it directly without downcasting.
2026-07-04feat(plugin-installer): implement PluginInstaller::get_plugin_managernsfisis
Wires PartialComposer.as_full() to fetch the PluginManager, replacing the todo!() stub. Mirrors PHP's assertion that $this->composer must be a fully-loaded Composer instance.
2026-07-04fix(search-command): use as_list() to read variadic tokens argumentnsfisis
ArgvInput stores variadic arguments as PhpMixed::List, not PhpMixed::Array, so as_array() always returned None and the search query was silently empty, causing packagist to reject every request with a 400 Bad Request.
2026-07-04fix(platform-repository): avoid infinite recursion in addOverriddenPackagensfisis
PHP's addOverriddenPackage calls parent::addPackage() (a non-virtual call straight to ArrayRepository), but the port called self.add_package, re-entering PlatformRepository::add_package. Since the newly created override package's name also starts with "php-", this recursed forever and blew the stack.
2026-07-04feat(config): use shirabe-branded default home/cache/data dirsnsfisis
Avoid colliding with an existing Composer installation on the same machine by defaulting COMPOSER_HOME/CACHE_DIR/DATA_DIR paths to shirabe/Shirabe instead of composer/Composer, while keeping the env var names, composer.json/lock, and vendor/composer/ unchanged for ecosystem compatibility.
2026-07-04fix(package): reset repository/id on package clonensfisis
AnyPackage::dup() (PHP's `clone $package`) copied the `repository` and `id` fields verbatim instead of resetting them like PHP's BasePackage::__clone() does. LibraryInstaller::install() relies on the duplicate being unbound so it can register the package with the local repository; without the reset, add_package() silently failed with "A package can only be added to one repository", leaving installed.json empty after every install/create-project run.
2026-07-04fix(event-dispatcher): avoid reentrant RefCell panicsnsfisis
Two related "already borrowed" panics reachable from AutoloadGenerator::dump() (which holds the local-repository, installation-manager, and config RefCells for the duration of its own statement, per the temporary-lifetime-extension pattern fixed separately in create_project_command.rs): - ensure_bin_dir_is_in_path called config.borrow_mut() to read "bin-dir", but Config::get only needs &self; use borrow() so it can coexist with an outer borrow instead of conflicting with it. - make_autoloader's real body needed composer_handle.borrow_mut() plus the same local-repository/installation-manager RefCells the caller already holds mutably, which cannot be made reentrant-safe without a larger restructuring. Since all 3 call sites already discard its return value, and its only effect (registering a Composer-generated ClassLoader for autoloading during event-listener PHP execution) is unobservable in this port — there's no embedded PHP interpreter to register it into, and class_exists for user-defined classes is a hardcoded-false shim so the caller's very next check always treats the class as unavailable regardless — make it a genuine no-op. This unblocks the post-autoload-dump event for any script listener naming a PHP class (e.g. Illuminate\Foundation\ComposerScripts), which every create-project/install run reaches once real packages get installed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04fix(installer): preserve fixedRootPackage identity for solver poolnsfisis
PHP's createRepositorySet does `$this->fixedRootPackage = clone $this->package;` once and then passes that same object both to `new RootPackageRepository($this->fixedRootPackage)` and, later, to createRequest($this->fixedRootPackage) — object identity matters because the solver assigns a pool id by mutating the package object itself. The port instead called RootPackageInterfaceHandle::dup() a second time when registering the RootPackageRepository, producing a second object that never went through the pool and so never got an id. create_request's `request.fix_package(root_package_handle)` then referenced a package with id -1, which add_rules_for_request treats as a real bug: "Fixed package ... was not added to solver pool." This surfaced whenever a create-project run reached the second-stage install (i.e. every dist-installed project with real dependencies). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04fix(create-project-command): split chained config.borrow_mut() callsnsfisis
install_project's fluent builder chain called config.borrow_mut() four times inline as method arguments. Rust extends every argument temporary's lifetime to the end of the enclosing statement, so the first borrow_mut() was still alive when the second one ran, panicking with "already borrowed". Compute each value into a local before the chain instead, matching the pattern already used in install/update/require/remove_command.rs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04fix(php-rpc): wire Runtime::invoke/get_extension_info/extensionsnsfisis
Route the platform-repository seams that need real PHP introspection through php-rpc instead of todo!()/hardcoded shims: - Runtime::invoke now handles the two dynamic callables PlatformRepository actually reaches (inet_pton, curl_version) via new php-rpc calls; other callables remain unsupported. - Runtime::get_extension_info uses a new `extension_info` php-rpc call (ReflectionExtension::info() + output buffering) instead of todo!(). - Runtime::get_extensions/get_extension_version now query the real PHP process (get_loaded_extensions, phpversion) instead of the shirabe-php-shim's hardcoded "standard CLI environment" model, so platform requirement checks see the extensions actually installed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04fix(pcre): restore missing regex delimiters in ported patternsnsfisis
Several Preg::*() call sites lost their PHP delimiter (and in one case the `i` modifier) during porting, since preg_*() expects the delimiter to be preserved in the caller's pattern literal and stripped internally. This made compile_php_pattern panic or silently misparse the pattern. Un-ignore the Version tests that were blocked by this bug.
2026-07-02feat(php-rpc): implement Runtime::has_constant/get_constant via php-rpcnsfisis
Runtime::hasConstant/getConstant need a real PHP interpreter's defined()/ constant() to answer platform requirement checks (e.g. PHP_ZTS, PHP_INT_SIZE), which the shim can't provide since Rust constants aren't queryable by string. Extend shirabe-php-rpc's protocol to carry one string argument and return the full PHP scalar range, add defined/constant dispatch entries to the worker, and wire Runtime and get_php_version/get_php_binary onto them.
2026-07-02chore(lint): ban std::io::Read/Write, Any, Command use importsnsfisis
Extends no_banned_use to cover std::any::Any, std::io::Read/Write, and std::process::Command, and teaches the linter to allow `as _` imports so trait methods can still be brought into scope without binding the banned name. Fully qualifies all existing usages across the codebase.
2026-07-02fix(platform-repository): wire ensure_initialized into RepositoryInterfacensfisis
PlatformRepository::initialize() (php-version/extension detection) was never invoked: the RepositoryInterface impl delegated straight to the inner ArrayRepository without the ensure_initialized lazy-init guard that sibling repositories (FilesystemRepository, PathRepository) use. As a result pool.what_provides("php") was always empty, and any package requiring php failed platform resolution. Also fixes the trait search() bypassing PlatformRepository's own SEARCH_VENDOR override.
2026-07-01test(application): port two doRun script-command testsnsfisis
Port testNoPluginsDisablesPluginsWhenScriptCommandsExist and testScriptCommandTakesPriorityOverAbbreviatedBuiltinCommand. Both stay #[ignore]d because do_run panics at the script-registration todo!() (application.rs:2461) when composer.json has scripts. Add a test-only ApplicationHandle::__get_composer accessor so the first test's getPluginManager assertions can be expressed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01feat(php-rpc): query real PHP version and binary for --versionnsfisis
Add a minimal shirabe-php-rpc crate that spawns the system PHP as a child process and asks it for runtime information over a Unix domain socket, then use it to fill the `--version` PHP line with the real \PHP_VERSION and \PHP_BINARY instead of fixed placeholder values. See docs/dev/php-rpc.md for the design and scope. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30refactor(git): replace is_callable with RunCommandOutput traitnsfisis
Model Git::runCommand's mixed $commandOutput parameter with the RunCommandOutput trait (one impl per PHP mode: discard, by-ref capture, callable handler), mirroring ProcessExecutor's IntoExecOutput. This moves the is_callable($commandOutput) value-inspection into the type system and drops the dependency on the shim's incomplete is_callable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29feat(repository): instantiate vcs, artifact, path repositories by classnsfisis
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29feat(vcs): clone io handle in ForgejoDriver git/OAuth setupnsfisis
Resolve the two todo!() placeholders by passing self.inner.io.clone() to VcsDriverBase::new and Forgejo::new, matching the PHP source's $this->io arguments and the GitHub/GitLab driver idiom. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29feat(console): implement StringInput stringification in global proxynsfisis
StringInput inherits __toString from ArgvInput in PHP; mirror that with a Display impl delegating to its inner ArgvInput, and use it in GlobalCommand::input_to_string. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29feat(require): update locker hash with stability flags rewriternsfisis
Resolve the remaining todo! in update_requirements_after_resolution by passing the stability-flags rewriter closure to Locker::update_hash, porting the static closure from RequireCommand.php. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29feat(audit): implement get_packages non-locked branchnsfisis
Port AuditCommand::getPackages's non-locked path: build an InstalledRepository from the local repository and return its packages, filtered by RootPackage requires when --no-dev is set. The prior TODO(phase-c) assumption (InstalledRepository::new vs get_local_repository type mismatch) no longer holds since both sides use RepositoryInterfaceHandle. Enables the two previously ignored audit command tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29feat(package): implement RootAliasPackage root getters via owned returnsnsfisis
It is faithful to PHP's by-value array/string semantics. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29fix(json): use php_truthy for JsonManipulator content validity guardsnsfisis
The `!@json_decode($children)` guards in addSubNode/removeSubNode were translated as `is_null() || as_bool() == Some(false)`, which drops PHP's other falsy cases (empty array/string, "0", 0). At the removeSubNode site (assoc=true) this diverged from Composer: an empty object node decodes to an empty array, which PHP treats as falsy and aborts on, but the Rust guard kept going. Replace both with php_truthy, the faithful rendering of PHP `!`, preserving the deliberate empty-`{}` behavior difference between the assoc=false (addSubNode) and assoc=true (removeSubNode) sites. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29fix(advisory): pass IO as shared handle to Auditor::auditnsfisis
Auditor::audit took io as &mut dyn IOInterface, forcing the audit and installer post-audit call sites to hold a borrow_mut() on the shared IO RefCell for the whole call. During advisory fetching the repositories write to their own clones of the same handle, so the borrow_mut() collided with their borrow() and panicked with 'RefCell already mutably borrowed' on 'audit --locked'. Take the Rc<RefCell<dyn IOInterface>> handle instead so writes borrow briefly and never overlap. Un-ignore the locked-audit regression test that this unblocks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29refactor(json): replace seld/jsonlint with serde_jsonnsfisis
Validate JSON syntax with serde_json's parse errors in JsonFile, and detect duplicate keys in ConfigValidator with a hand-written serde visitor, dropping the now-unused JsonParser/Lexer/DuplicateKeyException ports. ParsingException is kept as the thrown error type and downcast signal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29chore(lint): ban bare `use anyhow::Result` and fully qualify itnsfisis
Add a no_banned_use linter that forbids importing anyhow::Result, and update all call sites to reference it via its fully-qualified path so it is never confused with std::result::Result. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28fix(repository): flatten InstalledRepository and unwrap filter repos in shownsfisis
flattenRepositories must recurse into InstalledRepository (which extends CompositeRepository in PHP) and ShowCommand must unwrap FilterRepository when categorizing repos. Without this, installed/locked/platform packages all fell through to the "available" bucket, dropping the version column and per-section grouping. Un-ignores 10 show_command tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28fix(installer): execute install/update/uninstall ops in execute_batchnsfisis
execute_batch only awaited prepare(), leaving the install/update/ uninstall + cleanup + repo.write promise chain as a todo!() stub, so packages were downloaded to cache but never installed into the target directory. Wire the operation step (mirroring PHP's promise chain), propagate errors from the install/update/uninstall wrappers instead of swallowing them with .ok()?, and write the repo after each op. Un-ignore the create-project functional tests and the install/remove command tests this unblocks. The remaining --no-install case still fails on a separate install-path bug; its ignore reason is updated to match.
2026-06-28test(installer): port InstallerTest unit and integration harnessnsfisis
Port composer/tests/Composer/Test/InstallerTest.php. testInstaller (the provideInstaller cases) is fully ported and passes; the three integration tests port doTestIntegration in full (the .test fixture loader, FactoryMock, the in-process console Application with install/update commands, and the PHPUnit assertStringMatchesFormat matcher) and remain #[ignore]'d since the install pipeline is not yet executable end-to-end. Add test-only `__`-seams to the concrete types the test depends on, since their consumers (e.g. Locker takes the concrete InstallationManager) and the subclass-style mocks have no trait to mock: InstallationManager (recording mock + as_any), Factory (__create_mock), VersionGuesser, and InstalledFilesystemRepository. The production path (mock: false) is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28fix(http): avoid nested tokio runtime panic in download pathnsfisis
The CurlDownloader owned a tokio runtime and block_on'd reqwest from its sync tick(), while the repository/installer/downloader sync bridges each created another Runtime and block_on'd async fns that reach that leaf. Driving one Runtime::block_on from within another panics with "Cannot start a runtime from within a runtime", hit by `require` when fetching p2 metadata. Switch CurlDownloader to a blocking reqwest client (its own internal thread, never nested) and replace the per-call Runtime::new().block_on bridges with a no-reactor sync_executor::block_on helper. No awaited future parks on a reactor once the only async I/O is blocking, so the helper can be nested freely. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28fix(util): restore PHP delimiters in ported regex patternsnsfisis
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28refactor: add linternsfisis
2026-06-28feat(package): impl alias getter delegation via owned String returnsnsfisis
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28feat(repository): impl RepositoryInterface for Artifact/Path/Vcs reposnsfisis
The structural methods are inherited from ArrayRepository in PHP, where the lazy package load is driven by the overridden initialize(). Without virtual dispatch, each repository now ensures that load via a &self ensure_initialized() before delegating to the inner ArrayRepository. This required moving the repositories' lazily-populated state behind interior mutability (RefCell/Cell) and adding &self find_package_internal /find_packages_internal helpers on ArrayRepository. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28test(console): port DocumentationTest::testCommandnsfisis
Add __base_application accessor on ApplicationHandle so the test can build an ApplicationDescription the way console commands do. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27feat(installer): register default installers after Composer Rc is builtnsfisis
LibraryInstaller and PluginInstaller upgrade the Composer back-reference in their constructors, so they could not be built inside Rc::new_cyclic where the weak handle is not yet upgradeable. Defer create_default_ installers until after the cyclic Rc is established, where the weak handle resolves, and implement it to register Library -> Plugin -> Metapackage with a single shared BinaryInstaller. To share one BinaryInstaller (as Composer does), LibraryInstaller's binary_installer becomes Rc<RefCell<dyn BinaryInstallerInterface>> instead of an owned Box; PluginInstaller and the __set_binary_installer test seam follow. This clears "Unknown installer type: metapackage". Un-ignores the six remove tests that now pass; the remaining install/remove tests are re-labeled for the next blocker (InstallationManager::execute_batch still leaves the install/cleanup/repo.write promise chain as a todo!() stub, so package operations do not actually execute). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27feat(command/update): port UpdateCommand input definitionnsfisis
Replace the empty set_definition stub with the full InputArgument/ InputOption set from Composer's UpdateCommand. The symfony input modeling was already complete; this was the last command still passing an empty definition, which made it reject its own options. Un-ignores test_no_security_blocking_allows_insecure_packages (now passing) and re-labels the six remaining update tests with their actual blockers (regex porting, resolver temporary-constraint, interactive mode, bump-after-update solver pool) since the old "empty InputDefinition" reason no longer applies. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27refactor(http): present reqwest instead of faking curl_versionnsfisis
- StreamContextFactory: User-Agent reports the HTTP stack as "reqwest" - RequestProxy::supports_secure_proxy: always true (reqwest+rustls can always TLS to a proxy); drop the now-dead curl<7.52 guard in get_curl_options - DiagnoseCommand::get_curl_version: phase-D TODO placeholder Empirically verified: reqwest sends no default User-Agent (shirabe sets it explicitly) and accepts https:// proxy URLs. init+install output stays byte-identical to Composer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27fix(json): encode empty stdClass fields as {} not []nsfisis
Empty PhpMixed::Array now serializes as [], so the several places that build a PHP `new \stdClass` via an empty Array were emitting [] where Composer writes {}. Use PhpMixed::Object for those empty-object cases: - InitCommand: require / require-dev - Locker::fixupJsonDataType: stability-flags / platform / platform-dev - JsonConfigSource fallback: require/config keys that must stay objects Align the affected test expectations with Composer: JsonFile::read() decodes with assoc=true, collapsing the on-disk {} back to [], so reads expect []. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27fix(autoload): correct generated autoloader blank linesnsfisis
PHP heredocs drop the newline before the closing marker, so a two-blank-line fragment must port to "\n\n", not "\n\n\n", and the static initializer needs a "\n" after the $initializer placeholder. This makes autoload_real.php and autoload_static.php byte-identical to Composer's output. Rewrite the templates as raw strings mirroring the PHP heredocs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27test: port Composer tests unblocked by mockall, add seamsnsfisis
Port 11 categories of previously-ignored Composer tests now reachable with the mockall crate: DownloadManager, VCS/Perforce/File downloaders, VersionSelector, PlatformRepository, Auditor, installer/FilesystemRepository, RootPackageLoader, util auth/http, commands, and Cache. Extract test seams additively on concrete structs as *Interface traits (Runtime, HhvmDetector, VersionGuesser, RepositorySet, Perforce, BinaryInstaller) plus mock-field seams (Cache, Filesystem); consumers take trait objects. Mocks are defined locally in the test crates via mockall::mock!, since automock-generated mocks are cfg(test)-gated and invisible across the integration-test boundary. dataProviders are ported in full; tests blocked by unported shims stay #[ignore] with documented reasons rather than reduced or weakened. Fix product bugs surfaced by the ports: - util/github: use the exception code, not the HTTP status, for 401/403 - advisory: serialize empty audit maps as [] to match PHP json_encode - repository/filesystem and downloader/file: fix RefCell double-borrow panics Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27fix(command/show): match PHP null/isset semantics in package outputnsfisis
Three porting mismatches caused show/info output to diverge from PHP: - "not found" hint appended " in /composer.json" whenever the working-dir key existed; PHP uses isset(), which is false for the null default. Now only appended when the value is non-null. - printPackages and generatePackageTree inserted "" for a missing description instead of null, so isset() rendered a spurious trailing space (and JSON emitted "" instead of null). Both now preserve null. Un-ignores the eight rendering-gap tests these fix (plus one already passing), and rewrites the remaining ignore reasons to name the real blocker (package categorization, --no-dev filtering, RefCell borrow, installer resolution) instead of a stale generic message. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27fix(json): include property name in required-property errorsnsfisis
The jsonschema crate reports a missing required property against its parent object, leaving the instance path empty at the root. This skipped the "PROPERTY : MESSAGE" formatting that Composer produces. Append the missing property name to the path so the output shape matches. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27refactor(composer): hold managers behind *Interface traitsnsfisis
Composer/PartialComposer exposed its RepositoryManager, InstallationManager, EventDispatcher, Locker, DownloadManager, AutoloadGenerator and ArchiveManager as concrete types, but Composer's public setters (setDownloadManager() etc.) let plugins swap in subclasses. Introduce a *Interface trait per manager and store each as Rc<RefCell<dyn ...Interface>> so a replacement is honored. Only Composer's slots and the sinks fed from its accessors become trait objects; managers injected concretely at construction keep their concrete references, matching PHP semantics. Fluent setters on the affected classes now return () and Locker::update_hash is de-generified to a boxed FnOnce so the traits stay object-safe. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27refactor(main): minor refactoringnsfisis
2026-06-27fix(package-repository): load entries with default CompletePackage classnsfisis
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27fix(filesystem-repository): avoid RefCell double borrow on installed.phpnsfisis
file_put_contents_if_modified held a filesystem borrow_mut() receiver while its argument re-borrowed the same RefCell via dump_to_php_code(), panicking with "RefCell already borrowed". Build the file contents before taking the borrow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27fix(locker): build InstalledRepository with locked and root reposnsfisis
getMissingRequirementInfo created an empty InstalledRepository (both repos were left commented out as a stub), so every locked requirement was reported as "not present in the lock file". Pass [lockedRepo, rootRepo] to the constructor as the PHP does. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27feat(php-shim): drop shutdown function shim, defer OOM message to PHPnsfisis
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>