aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src
AgeCommit message (Collapse)Author
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>
2026-06-27refactor(command): replace composer_full_mut with shared composer_fullnsfisis
The compiler confirms none of the call sites invoke a &mut self method on the returned Composer, so the exclusive RefMut borrow was never needed and only risked borrow check conflict. Switch every site to the shared composer_full borrow and drop the now-dead composer_full_mut helper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27fix(validate-command): release Composer borrow before dispatching CommandEventnsfisis
Holding a RefMut<Composer> across execute() conflicted with the shared borrow taken inside EventDispatcher::get_script_listeners, panicking with "RefCell already mutably borrowed". All accessors used here take &self, so a shared borrow suffices. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27refactor: fix compiler warnings and clippy warningsnsfisis
2026-06-26test(cli): force --no-interaction so init does not hang under a TTYnsfisis
The cli_tests suite runs the real CLI; under a TTY Composer's do_run logic keeps interaction enabled, so `init` blocks on stdin. Holding the #[serial] mutex while blocked made later tests (e.g. audit) appear to time out. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26feat(show-command): port the real configure() input definitionnsfisis
ShowCommand::configure registered an empty set_definition (placeholder), so every show invocation failed with option/argument-does-not-exist. Port the full argument/option list (package, version, --all/--locked/--installed/--platform/ --available/--self/--tree/--latest/--outdated/--format/... ) from PHP ShowCommand::configure. Completion-suggestion closures and the format allowed-value list are dropped to match the current InputArgument/InputOption API. Un-ignores 14 ShowCommandTest cases; the remaining 28 keep faithful bodies but stay ignored (show-rendering output gaps and remote-HTTP paths), reasons updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26fix(remove-command,pool-builder): drop Composer re-entrancy and ↵nsfisis
PRE_POOL_CREATE todo RemoveCommand::execute held composer_full_mut across deactivate_installed_plugins and event dispatch, both of which re-enter the same RefCell (composer.rs:500/446); it only uses &self getters, so borrow it immutably. PoolBuilder dispatched PluginEvents::PRE_POOL_CREATE by building an event that required moving the (unclonable) repositories/Request — left as todo!(). The event is purely plugin-facing and its result is never read in the no-plugin path (Pool::new reads self.packages directly), so skip it with a TODO(plugin) note. Removes the composer.rs re-entrancy and two todo!()s from the remove install path; remove's tests now reach the unregistered-installers blocker (factory.rs). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26fix(check-platform-reqs-command): add PlatformRepository to existing compositensfisis
execute nested the already-built InstalledRepository inside a second InstalledRepository, tripping the assertion that an InstalledRepository may not contain another. PHP adds a PlatformRepository to the existing composite via addRepository; do the same. Un-ignores CheckPlatformReqsCommandTest::test_failed_platform_requirement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26test(cli): un-ignore archive/browse/clear-cache/init smoke testsnsfisis
These no-longer-panic after the table/command chokepoint fixes; diagnose and require still panic and stay ignored. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26refactor(symfony-table): model rows/cells with enums instead of PhpMixednsfisis
The Table helper modeled a row's cells as PhpMixed and recovered the concrete TableCell/TableSeparator types via runtime instance_of, leaving the entire mixed/array bridge (to_row_vec, cell_colspan, row_get, ...) as todo!(). Replace that with proper Row/Cell enums: Row = HeaderDivider | Separator(TableSeparator) | Cells(Vec<Cell>) Cell = Null | Value(String) | Cell(TableCell) | Separator(TableSeparator) The internal header/body boundary that PHP detects by object identity ($divider === $row) becomes the dedicated Row::HeaderDivider variant. Style arguments (PHP string|TableStyle) become a StyleName enum, so Table::new no longer panics in resolve_style's instance_of stub; TableStyle derives Clone so named styles resolve from the registry. PhpMixed-based callers (SymfonyStyle::table, render_table, auditor's sanitize) bridge via From<PhpMixed> for Cell/Row at the boundary. Un-ignores LicensesCommandTest text-format cases (4) and BaseDependencyCommandTest::why; output matches PHP exactly. Removes ~15 impl todo!()s in the Table helper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26fix(dump-autoload-command): borrow Composer immutably in executensfisis
execute only calls &self getters on the Composer, but borrowed it via composer_full_mut. The held RefMut deadlocked the re-entrant shared borrow taken by EventDispatcher::dispatch -> get_script_listeners -> PartialComposerHandle::borrow_partial, panicking on every invocation. Un-ignores all 12 DumpAutoloadCommandTest cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26fix(repository-command,config): delimited Preg pattern and list-form reposnsfisis
RepositoryCommand's JSON-arg detection used the un-delimited regex r"^\s*\{"; the PHP source is the delimited '{^\s*\{}', which compile_php_pattern requires. Config::merge only extracted repositories from PhpMixed::Array; a JSON array decodes to PhpMixed::List (an array with integer keys in PHP) and was silently dropped. Handle List by mapping to integer string keys. Un-ignores all 10 remaining RepositoryCommandTest cases (16/16 pass). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26feat(dependency-resolver): wire operation get_package and unblock solver testsnsfisis
Override OperationInterface::get_package for Install/Uninstall/MarkAlias* operations so trait-object dispatch no longer hits the default todo!(), and implement Rule::is_caused_by_lock's locked-repository lookup via Request::get_locked_repository (LockArrayRepository::get_packages is infallible). Change PackageInterface::get_type to return String (matching PHP getType(): string) so AliasPackage can delegate live to its aliasOf handle across the RefCell instead of an impossible &str borrow. Un-ignores 25 SolverTest cases; 2 alias cases stay ignored pending a real solver alias-resolution discrepancy. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26test: recover binary_installer full-compat port; implement posix_getpwuidnsfisis
The stashed binary_installer port was blocked on posix_getpwuid (reached via Platform::is_virtual_box_guest); implement it via getpwuid(3) extern "C". The 4 install-and-exec tests now pass with the stream I/O and Process cwd fixes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26test: port 32 command/repository/downloader testsnsfisis
Add create_installed_json/create_composer_lock test helpers. Port command (8), repository path/forgejo/perforce/vcs (11), and fossil/hg/download_manager (13) tests. Fix production porting bugs: root_package_loader/forgejo_url/version_bumper regex delimiters, repository_manager create_repository_by_class, array_loader isset, licenses_command RefCell borrow; implement disk_free_space and touch2/touch3 via libc. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26test: port 24 command/repository/package/util tests; add TlsHelpernsfisis
Port command (9), util gitlab/forgejo/tls (6), package (6), repository (3) tests. Implement TlsHelper. Fix porting bugs: config_command extra merge, RootAliasPackage setters, ValidatingArrayLoader isset, repository_factory name generation, forgejo exception code, version_parser error chaining. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>