| Age | Commit message (Collapse) | Author |
|
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
Operations are only ever constructed by the dependency resolver, so a
plugin has no way to inject an implementation of its own and the set is
closed. Modelling it as an enum, like AnyPackage, removes the
OperationInterface trait together with its two parallel downcast
mechanisms (as_any() + downcast_ref, and as_*_operation()) and the
get_package() default method that panicked on UpdateOperation.
The PHP idiom `$op instanceof UpdateOperation ? getTargetPackage() :
getPackage()`, written out at six call sites, becomes
AnyOperation::get_target_package(). InstallationManager's three blocks
that matched on the type string and then recovered the type with
expect() collapse into exhaustive matches.
SolverOperation keeps only its TYPE constant; the shared
getOperationType()/__toString() implementations move to AnyOperation,
which also drops the five Self::TYPE.to_string() allocations.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
|
|
is_callable
RequireCommand registers an inline listener on InstallerEvents::PRE_OPERATIONS_EXEC
to track dependency_resolution_completed, mirroring PHP's `function () use
(&$dependencyResolutionCompleted) { ... }`. This is Composer's own code, not a
Plugin subscriber, but it went through the shared non-string-callable path, which
checked is_callable() against a hardcoded PhpMixed::Null and always failed,
breaking every `require` that reaches the install step.
Callable::Closure now carries the actual Rc<dyn Fn> instead of being a data-less
placeholder, and is invoked directly (Closures are always callable in PHP). The
ArrayCallable path used by future Plugin subscribers is untouched.
Un-ignoring the two require_command_test cases that cited this bug reveals two
separate, pre-existing issues (a missing ext-requirement warning message, and a
RefCell re-entrancy panic in ConsoleIO::ask_question); their #[ignore] reasons
are updated to describe the real current blocker instead of the now-fixed one.
|
|
4a5a9556 split each installer/installer-slow fixture into its own
#[test] fn (with #[ignore] on known failures) so they could be triaged
one at a time, and said explicitly that it should be reverted to a
single loop-based test per group once triage was done. Only
github-issues-7665.test still fails, and its cause is now understood
(see the previous commit): an upstream Composer defect, not a porting
bug. Restore the three loop-based tests, skipping that one fixture
inline with a TODO(phase-d) comment instead of a per-fixture #[ignore].
|
|
The ignore reason for slow_github_issues_7665 said "unknown reason,
needs further investigation." Investigation since then traced the
mismatch to an upstream Composer defect: Problem::getPrettyString's
RULE_LEARNED tie-break comparator (getSortableString() <=>
getSortableString()) is not transitive, and the values it compares are
literal ids that shift with the platform package count, which
Installer::createPlatformRepo() derives from the real ambient PHP
runtime and which Composer's own test suite never mocks. This fixture
is brittle to whichever extensions are installed on the machine
generating or running it. Nothing to fix on the Rust side; this is an
upstream Composer bug (composer/composer#12111 introduced the
comparator).
|
|
Problem::getPrettyString sorts same-priority reasons by
getSortableString(), whose RULE_LEARNED key is a '-'-joined literal id
string (e.g. "-95"). PHP's <=> compares two numeric strings
numerically, but the port used plain String::cmp (byte-wise), which
reverses relative order for same-length negative-number keys. Added
shirabe_php_shim::loosely_compare to approximate PHP's <=> for this
pattern (numeric compare when both sides parse as numbers, else byte
compare) and switched the sort comparator to use it.
The diagnosis this replaces (from the commit being amended) blamed
Pool package-id assignment order diverging from PHP under
COMPOSER_POOL_OPTIMIZER=0. That was disproven this session: direct
instrumentation of both PHP and the Rust port confirmed identical
relative package-id order, including on the ~335-package
github-issues-7665 fixture (ids matched up to a constant +2 offset
from a platform-mock package count difference). The sort comparator
was the actual bug, not package loading order.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
create_extension_hint's --ignore-platform-req suggestion list sorted
missing extensions alphabetically before deduping. PHP's array_unique
removes duplicates while preserving first-occurrence order instead,
which for this call site matches the order problems were reported in
(root-require-not-found problems before SAT-conflict problems).
Replaced the sort+dedup with the existing order-preserving
shirabe_php_shim::array_unique, which was already ported for exactly
this PHP semantic but wasn't used here.
|
|
PHPUnit's expectException/expectExceptionMessage wrap the whole rest
of InstallerTest::doTestIntegration, so a fixture's expected exception
can legitimately come from FactoryMock::create() itself (root package
construction), not just the later install/update run. The Rust port
only checked for that at one point, after the run, and unconditionally
unwrapped Factory::__create_mock's result — so a fixture like
install-self-from-root.test (root package requiring itself, which
throws during root package construction) panicked on that unwrap
instead of being caught and compared against the expected message.
Capture the construction Result and, when an exception was expected,
run the same normalize/contains/assert check the later block already
uses before returning early, matching PHPUnit's behavior of running no
further test-method code once the expected exception has fired.
|
|
ArrayDumper::dump built the mirrors field as PhpMixed::Array keyed by
stringified index ("0", "1", ...), which this codebase's PhpMixed
JSON serialization renders as an object. PHP just assigns the plain,
sequentially-keyed mirrors array directly, which json_encode renders
as a JSON array. Use PhpMixed::List instead, matching the actual
shape written to composer.lock.
|
|
Package::set_source_dist_references and LockTransaction's dist-url
mirroring both used {(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i, but the regex
crate has no look-around support at all and panics compiling it. Per
docs/dev/regex-porting.md, rewrote the boundary assertions into
capturing groups and switched to Preg::replace_callback, which
re-emits the captured delimiters around the replaced reference.
|
|
For a simple, non-lazy composer repository (no providers-url/
metadata-url/providers-lazy-url), load_packages() delegates to
self.inner.load_packages() (PHP: parent::loadPackages()). PHP's
ArrayRepository::loadPackages() calls $this->getPackages(), which
virtual-dispatches through ComposerRepository::getPackages() down to
ComposerRepository::initialize() (the real HTTP/file fetch).
Composition doesn't get that dispatch for free: self.inner is a bare
ArrayRepository, so self.inner.load_packages() ends up calling
ArrayRepository::initialize() — a no-op stub that just sets an empty
package list — instead of ComposerRepository::initialize(). The
repository's packages.json fetched and parsed successfully, but the
result was silently discarded, so the repo always looked empty.
get_packages() already carries the identical guard with the same
diagnosis in its own comment; load_packages() was just missing it.
Documented the same latent gap in find_package/find_packages/count/
has_package, which call into ArrayRepository the same unguarded way
but aren't known to be exercised by any test yet.
|
|
PHP's InstallerTest::setUp() does chdir(__DIR__) before every test so
relative "type": "path" repository URLs in fixtures resolve against
composer/tests/Composer/Test; tearDown() restores the previous cwd.
This was never ported, only the env-var clears were, so any fixture
declaring a relative path repo failed at PathRepository::initialize()
with "the `url` supplied for the path (...) repository does not
exist" — not a missing PathRepository feature, just an unset cwd.
Turned TearDown into a real guard that captures and chdirs on
construction and restores on Drop. Since set_current_dir is
process-wide state and tests run concurrently by default, added
#[serial] to test_installer (the only call site not already inside a
#[serial] macro-generated fn) so no two TearDown-holding tests can
race on cwd; serial_test's plain #[serial] shares one unnamed lock
across the whole binary, so this is sufficient.
|
|
PoolBuilder::build_pool() and warn_about_non_matching_update_allow_list()
called get_canonical_packages() on the locked repository during a
partial update, but PHP's PoolBuilder uses the plain getPackages().
get_canonical_packages() unwraps AliasPackage down to its base package,
discarding the alias's own version identity.
Locker::get_locked_repository() wraps a lock entry with
extra.branch-alias in a single CompleteAliasPackage rather than adding
a separate base object, so canonicalizing it silently dropped the
locked branch-alias version (e.g. 2.2.x-dev), leaving only the raw
dev-master version behind. For a package excluded from the partial
update's allow-list, that meant its locked branch-alias version could
no longer satisfy the root's constraint, producing a spurious solver
conflict instead of keeping the package pinned exactly as locked.
Fixed the same bug in AuditCommand's --locked package listing, which
had the identical get_canonical_packages()/getPackages() mismatch
against AuditCommand.php.
|
|
Two shim gaps made the extension-related branches of solver-problem
messages wrong:
- phpversion($ext) with a non-empty extension can't be known statically
(it's shirabe-php-shim's todo!()); Problem::get_missing_package_reason
now calls shirabe_php_rpc::phpversion, the same RPC bridge
platform::runtime::Runtime::get_extension_version already uses.
- extension_loaded's hardcoded allowlist was missing "pcre", a mandatory
always-compiled-in PHP extension, so ext-pcre was misreported as
"missing from your system" instead of "disabled by your platform
config" whenever a platform override disabled it.
Also fix XdebugHandler::getAllIniFiles() always returning `[""]`
(a php-runtime stub): create_extension_hint()'s early-return guard
(`paths[0] empty && len==1`) fired unconditionally, silently dropping
the entire "To enable extensions..." hint from every solver-problem
message that mentions missing extensions. shirabe-external-packages
can't depend on shirabe-php-rpc (shirabe-php-rpc already depends on
shirabe-external-packages), so IniHelper::get_all() queries a new
get_all_ini_files RPC command directly instead of going through the
stub.
This exposed that XdebugHandler is never constructed with a name
because bin/composer's restart-without-Xdebug bootstrap was never
ported to main.rs, making COMPOSER_ORIGINAL_INIS-driven behavior
unreachable; documented with a TODO(phase-c) and updated
ini_helper_test.rs's ignore reasons (and ignored test_with_no_ini,
which only passed before by coincidence with the old stub's constant
output) to match.
|
|
PHP's readTestFile splits sections with a regex that leaves a section's
own trailing newline attached when it is the file's last section
(verified against real PHP); for install-without-lock.test and
update-without-lock.test, --EXPECT-LOCK-- is that last section, so its
raw content is "false\n", not "false". PHP's `$expectLock === 'false'`
check therefore also misses, but PHP falls through to
JsonFile::parseJson("false\n"), which json_decodes to boolean false
anyway, and every downstream check in doTestIntegration branches on
PHP truthiness of $expectLock, so the outcome is unaffected either way.
The Rust port only mirrored the literal string comparison, so the
same "false\n" produced ExpectLock::Json(Value::Bool(false)) instead
of ExpectLock::Never, and do_test_integration's Json arm unconditionally
read composer.lock, panicking because config.lock=false means no lock
file is ever written. Parse EXPECT-LOCK as JSON first and classify by
PHP truthiness of the result, matching what doTestIntegration actually
checks instead of the raw string.
|
|
The b'>' match arm in strip_tags's state machine never pushed the
character to the output buffer when encountered outside a tag (state
0), unlike every other special-character arm (!, ?, -, and the
catch-all) which does push in that state. Every literal '>' not part
of an HTML-like tag was silently dropped.
This corrupted "=>" into "=" in Composer's operation trace strings
(e.g. "Upgrading foo/bar (1.0.0 => 1.1.0)"), which go through
strip_tags to remove the <info>/<comment> markup before comparison,
un-ignoring 82 integration tests that were asserting on that exact
arrow.
|
|
Locker::get_stability_flags returned IndexMap<String, String>, converting
each value via PhpMixed::as_string(), which only matches the String
variant. composer.lock's "stability-flags" values are always JSON
integers (BasePackage::STABILITIES), so every flag silently decoded to
"" and installer.rs's downstream .parse::<i64>() defaulted it to 0
(stable). This made any locked package pinned via a non-stable
stability-flags entry look "unacceptable" during `composer install`,
silently dropping it from the solver's pool instead of fixing/requiring
it — turning a real dependency conflict into a spurious "lock file needs
changes" result. Return i64 directly, matching
RootPackageInterface::get_stability_flags and set_lock_data's existing
convention for this same PHP array shape.
|
|
do_test_integration built the Locker's composer.json content string with
serde_json::to_string, which doesn't escape slashes, while the fixture's
auto-computed lock "hash" field used JsonFile::encode_with_options with
slashes escaped (mirroring PHP's json_encode default). Since virtually
every package name contains a "/", this made Locker::isFresh() spuriously
report every such lock as stale, unignoring 12 fixtures that depended on
the lock being recognized as fresh during `install`.
|
|
Replace the three loop-based test functions (each iterating all
fixtures with a shared SKIP_INSTALLER_* skip list) with macro-generated
per-fixture test functions, so a single failing or panicking fixture
no longer hides the pass/fail status of the rest. Known-failing
fixtures keep their TODO(phase-d) reasons via #[ignore] on their own
test instead of a shared skip list. All generated tests are #[serial]
since they mutate global env vars (COMPOSER_POOL_OPTIMIZER,
COMPOSER_FUND) that would otherwise race across parallel test threads.
This is an interim structure for triaging the ~131 ignored fixtures
one at a time; it should be reverted to a single loop-based test per
group (matching Composer's directory-scanned fixtures) once they are
resolved.
|
|
reload to PHP runtime
Rust has no PHP interpreter, so eval() can never be ported faithfully.
safely_load_installed_versions()'s job of priming Composer\InstalledVersions
before plugins run only matters within a single shared PHP process, which
the RPC-based plugin architecture does not have; the PHP runtime process
can call InstalledVersions::reload() itself instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
Audited every remaining method in the Symfony Filesystem port against
composer/vendor/symfony/filesystem/Filesystem.php and tagged each
divergence with a searchable TODO(phase-c): the missing self::$lastError
propagation, copy()'s collapsed fopen-failure messages and skipped mtime
preservation, exists()'s missing PHP_MAXPATHLEN guard, do_remove()'s
unported rename/rollback safety trick and its Unix short-circuit gap,
symlink()'s unported Windows path-normalization/copy_on_windows fallback,
link_exception()'s unported error-code-1314 message, read_link()'s
missing canonicalize=true overload and its Windows PHP<7.4 quirk, and
mirror()'s missing getRealPath()/filesCreatedWhileMirroring dedup.
Windows-only branches were previously left with plain comments claiming
they "never run on Unix" instead of the required TODO marker, which
understates them as permanently out of scope rather than unported work.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
Real symfony/console OutputStyle is abstract and never defines these
methods itself (title/section/table/ask/... stay abstract, deferred to
SymfonyStyle). The Rust impl block was a porting artifact never invoked
anywhere: OutputStyle is only used as SymfonyStyle's concrete `inner`
field, and every StyleInterface call site goes through SymfonyStyle's
own full implementation. new_line, which SymfonyStyle::new_line does
delegate to, moves to an inherent method to keep that call working.
|
|
Since Process is php-native with no Rust-fidelity obligation (see
plugin-class-classification.md), this port only needs to cover what
Rust-ported Composer code actually calls. Made the pipes/process_utils
modules pub(crate) (nothing outside symfony/process used them) and
rebuilt with `--force-warn dead_code` (normally allowed workspace-wide)
to find genuinely unreachable methods: Process lost 17 methods, 5
constants, and a private clone helper; ExecutableFinder lost two unused
suffix setters; AbstractPipes lost handle_error, whose only caller (a
stream_select error-handler registration) was never wired up.
Removing several of those setters (set_pty, set_idle_timeout,
disable_output/enable_output, set_options) then left the fields they
used to write with no remaining writer, so they hold one constant value
on every reachable path: pty always false, idle_timeout always None,
output_disabled always false, options always {suppress_errors,
bypass_shell}. Audited by value (not just call-graph reachability) and
removed everything that depended on the now-constant value:
- pty: is_pty(), is_pty_supported(), the PTY descriptor branch in
UnixPipes::get_descriptors(), and the now-unconstructed
Descriptor::Pty variant in shirabe-php-shim (plus its proc_open
match arm).
- idle_timeout: get_idle_timeout() and check_timeout()'s idle branch;
ProcessTimedOutException collapses to the single reachable timeout
type (dropped timeout_type/TYPE_GENERAL/TYPE_IDLE/is_general_timeout/
is_idle_timeout/get_exceeded_timeout).
- output_disabled: is_output_disabled(), build_callback()'s disabled
variant, get_descriptors()'s output_disabled term, and the
always-false guard in read_pipes_for_output()/ProcessFailedException
(its output section is now unconditional).
- options: Drop::drop()'s create_new_console branch can never fire
(that key can no longer exist), so it always just stops the process.
- has_callback/last_output_time: left write-only once their only
readers (the branches above) were gone.
- have_read_support: constant true once output_disabled collapsed, so
removed from PipesInterface, UnixPipes (incl. its /dev/null
null-stream branch), WindowsPipes, and Process::wait()'s dead guard.
No behavior change: every removed item/branch had zero callers, or was
constant on every reachable call site.
|
|
A plugin can reach ProcessExecutor::executeAsync() through the
rust-proxy stub, which resolves with a real Symfony Process instance
that can't be reconstructed on the Rust side (its state is tied to
whichever process calls proc_open(), and it refuses serialization).
Add execute_async_php() as a todo!() stub, documented as a dual-
instantiation split in plugin-class-classification.md: Rust-internal
callers keep using execute_async(), while the plugin path must forward
spawning to the PHP child once the RPC channel exists.
|
|
advisories
get_security_advisories cloned each package's full metadata blob
(hundreds of versions for popular packages) just to peek at its
"security-advisories" field. Same pattern already fixed in
load_async_packages by 2862d2da; move ownership through pattern
matches and IndexMap::shift_remove instead.
Measured with laravel/laravel create-project: response processing in
the security-advisories metadata branch drops ~80% (236ms -> 48ms),
and the whole run_security_advisory_filter phase drops from ~420-500ms
to ~250-270ms. End-to-end, shirabe now matches or edges out upstream
Composer (6.57s vs 6.85s in this run) instead of trailing by ~1.2s.
|
|
metadata
load_async_packages cloned each response's version metadata up to
three times (spec_list/response, response_arr, versions_mixed, then
every per-version field) before building the versions Vec. Move
ownership through pattern matches and IndexMap::shift_remove instead.
Measured with laravel/laravel create-project: per-batch response
processing time in load_async_packages drops ~39% (1.30s -> 0.80s
cumulative), narrowing the E2E gap vs upstream Composer from 1.37s to
1.14s on average.
|
|
A dead worker and a live one hitting a framing bug both surface as a
raw socket I/O error (e.g. "Broken pipe"), which doesn't say whether
the child crashed, was signaled, or is still running. Query the
child's exit status via try_wait() and attach it as anyhow::Context
so the panic message shows the root cause directly.
|
|
JsonFile::write_with_options() used the caller-supplied JsonEncodeOptions
verbatim, ignoring self.indent (set by read()'s detect_indenting), unlike
PHP's write() which always passes $this->indent to encode() regardless of
the $options argument. Un-ignore test_preserve_indentation_after_read.
|
|
The negated remaining-width subtraction was cast straight to usize,
overflowing whenever it went negative (e.g. an abandoned-package
warning ate the available width) and panicking on slice indexing.
Route through the shim's substr(), which mirrors PHP's negative-length
semantics and clamps instead of overflowing.
|
|
test_pool_builder
build_pool never populated skipped_load for locked packages skipped due
to the update allow list (nor their replace targets), so load_package's
skipped_load-driven transitive-unlock branch never fired.
load_packages_marked_for_loading never recorded loaded packages into
loaded_per_repo, so repositories had no way to dedupe already-loaded
versions when a constraint got re-expanded, producing duplicate pool
entries.
unlock_package looked up a locked package's removal index via the
position in a Vec snapshot of self.packages.values() instead of its
actual IndexMap key, so after earlier removals the wrong entry (or
none) got removed, leaving stale locked packages in the pool.
Fixing all three lets test_pool_builder run un-ignored.
|
|
shirabe_php_shim::chr() returned a Rust String, which lossily
re-encodes bytes >= 0x80 as UTF-8 replacement characters. ip_get_mask,
ip_get_network, and ip_map_to_6 relied on chr() to build raw in_addr
and netmask byte arrays, corrupting IPv4-in-IPv6 mappings and CIDR
netmasks. Build the Vec<u8> byte arrays directly instead of
round-tripping through String, and un-ignore test_ip_address and
test_ip_range now that the underlying bug is fixed.
chr()'s only other caller (http_downloader.rs, an ASCII ESC byte in a
regex pattern) didn't need the indirection either, so remove the shim
function entirely.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
The ignored tests raced on the process-wide HTTP_PROXY/etc env vars
and the ProxyManager::INSTANCE mutex, causing spurious PoisonError
panics when run in parallel. Adding #[serial_test::serial], the same
annotation test_instantiation already used, fixes the race with no
other changes needed.
|
|
Several call sites coerced PhpMixed to bool via `.as_bool()` (which
only matches a literal Bool variant) where the corresponding PHP code
does a plain `(bool)` cast or truthy check (isset()/array_key_exists()
+ implicit bool conversion). This silently dropped truthy non-bool
values (e.g. String("true"), String("1"), Int(1)) to their unwrap_or
default instead of PHP's actual truthy result. Switched these sites to
PhpMixed::to_bool(), which implements PHP's full truthy-cast rules.
|
|
74 tests carried a bare #[ignore] with no explanation. Re-ran each:
25 now pass and had the attribute removed; the remaining 49 got a
concise reason (todo!() stubs, regex-crate PCRE gaps, PhpMixed type
mismatches, config bool-coercion bugs, missing skipped_load wiring
in PoolBuilder, etc.) so future work can find and fix them by grep.
No production code or test logic/assertions were changed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
parseIgnoreWithApply distinguishes ['CVE-123' => 'reason'] from
[0 => 'CVE-123'] by checking is_int($key) in PHP. AuditConfig only
matched on the value's type, so a canonical-int-keyed string value
was mistaken for an id => reason pair. Expose canonical_int_key from
the php-shim to replicate PHP's key-canonicalization rule and
unignore test_mixed_formats.
|
|
execute() held &config.borrow() across check_http/check_composer_repo/
check_composer_audit, which reach HttpDownloader -> CurlDownloader::
download; that method does self.config.borrow_mut() on the same
Config RefCell, panicking with "RefCell already borrowed" once the
phpinfo panic that previously masked this was fixed.
Switch those three helpers to take the Rc<RefCell<Config>> handle
(matching check_version's existing pattern) and borrow only where a
field is actually read, so no borrow spans the downstream network
call. Un-ignore the now-passing run_diagnose smoke test and
test_cmd_fail; test_cmd_success stays ignored, now for two separate
reasons: it needs real network access (as the PHP original does), and
shirabe_php_shim::OPENSSL_VERSION_NUMBER is a hardcoded stub (0) that
always trips check_platform's TLSv1.1/1.2 support check regardless of
the real linked OpenSSL, forcing a non-zero exit code.
|
|
DiagnoseCommand::check_platform needed phpinfo() output but
shirabe-php-shim's ob_start()/phpinfo()/ob_get_clean() are unmodeled
todo!()s. Add a phpinfo dispatch entry to the PHP worker (capturing
output the same way extension_info already does) and a get_phpinfo()
wrapper, then switch check_platform to call it directly.
This unblocks the phpinfo-related panic in diagnose; the ignored
tests now hit a separate RefCell double-borrow bug in check_http, so
their ignore reasons are updated to point at that instead.
|
|
capture_stderr_separately routed the tester through ConsoleOutput,
which detects color/hyperlink support from the real process STDOUT
before the stream is swapped to the memory buffer. When STDOUT is a
real tty, decoration leaks into the captured output. The PHP original
never passes this option and get_error_output() was unused here, so
drop it to match and keep the assertion deterministic.
|
|
The shim date() renders in UTC only (no timezone database) while PHP's
date() uses the system default timezone, so get_relative_time misses the
"today" match and prints "this week" whenever the local date differs
from the UTC date (daily 00:00-09:00 JST on this machine). Verified by
running the test with and without TZ=UTC at 07:40 JST. Mark the gap with
a TODO(phase-c) in the shim; fixing it needs a timezone database (a new
crate), which is a user decision.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
Measured the actual panic site: DiagnoseCommand::check_platform reaches
the todo!() ob_start()/ob_get_clean() shims while capturing phpinfo(),
the same root cause already recorded in
tests/command/diagnose_command_test.rs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
The Ref temporaries created by input.borrow() inside the argument
expressions of the determine_requirements call lived until the end of
the whole call statement, so ConsoleIO::ask_question's borrow_mut() on
the same shared input RefCell panicked with "RefCell already borrowed"
when the command prompted for packages. Hoist the argument computations
into locals so no borrow is held across the call, and un-ignore the
run_require CLI test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
PHP only runs this test when the zip extension is not loaded; the Rust
port has unconditional zip support, so that precondition cannot exist.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
The ignore reason was stale: create_repository_by_class now dispatches
every repository class this test registers, and the test passes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
PHP's `?:` chain in getComposerInformation short-circuits, so
getBranches() only runs when the tags search is falsy. The eager port
issued an extra git/refs/heads API request that PHP never makes.
Un-ignore test_public_repository_archived, which this fixes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
The previous ignore reason blamed unmodeled extension info; the actual
blockers are the TODO(plugin) stubs resource_bundle_get (returns Null,
dropping lib-icu-cldr) and imagick_get_version_string (returns "",
dropping lib-imagick-imagemagick), both pending dynamic method dispatch
on PHP objects via the plugin RPC mechanism.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
The ignore reason went stale: AliasPackage::get_source_type is
implemented (delegates to alias_of) and the test passes as-is.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
The regex crate parses PCRE's possessive \d{1,5}+ as a stacked
repetition (?:\d{1,5})+, i.e. \d+, so date versions like 20121020
matched the classical pattern and normalized to 20121020.0.0.0 instead
of falling through to the date(time) pattern like PHP. The plain
\d{1,5} is equivalent to the possessive form here per the
regex-porting rules. Un-ignore test_find_recommended_require_version
which this had blocked.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|