| Age | Commit message (Collapse) | Author |
|
Split date() into date_utc() and date_local(), the latter resolving the
system's local timezone through the tzfile crate ($TZ, then
/etc/localtime, falling back to UTC when neither is readable). The
timestamps Composer renders for humans -- the GitHub OAuth token note,
the GitHub API rate limit reset time, the Perforce client spec fields and
the "today" check of the show command -- now go through date_local().
PHP resolves its default timezone from the date.timezone ini setting,
which Shirabe does not read, so date_default_timezone_get/set have no
input left to model and are dropped from the shim and its callers. The
resulting difference is recorded in docs/known-incompatibilities.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The shim reported a fixed PHP 8.1.0 through PHP_VERSION, PHP_VERSION_ID,
the major/minor/release triple and the PHP_WINDOWS_VERSION_* trio. Their
uses split in two.
Some guarded branches PHP only needs on runtimes this port cannot be:
proc_get_status reports the exit status on every call, so Symfony's
pre-8.3 exit-code cache has nothing to work around; hash_raw and
hash_file always offer xxh3, so the sha1 fallback is unreachable; and
http_get_last_response_headers is always available, so the pre-8.4
$http_response_header branch is gone. safeJunctions reads the host
Windows version rather than PHP state, and joins the Windows work on
hold.
The rest ask about the PHP the user actually runs, and now reach the
worker through a new php-rpc PhpVersion payload: the startup banner and
the 7.2.5 warning, self-update's min-php filter, the ext-*
recommendation in VersionSelector, the stream User-Agent, and whether
PhpFileParser scans for enums.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The constant was None and defined("HHVM_VERSION") reports it undefined, so
every branch guarded by it was dead: shirabe is a Rust binary and never runs
on HHVM. HhvmDetector keeps probing for an `hhvm` binary in PATH, which is
what actually produces the hhvm platform package.
Two of the dropped branches ask about the PHP runtime that consumes the
result rather than about shirabe itself -- the class loader's Hack file
lookup and the class map parser's enum scanning -- so both get a
TODO(php-runtime) marker.
|
|
PHP_INT_MAX/MIN/SIZE have exact Rust counterparts under the int -> i64
mapping, so the call sites use i64::MAX directly. PHP_INT_SIZE is
queried from the PHP runtime where it is actually needed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The SignalHandler port was a no-op stub, so all four of Composer's abort
paths were dead code: nothing removed a half-created project, reverted
composer.json, or cleaned up half-installed packages.
Composer runs those handlers from pcntl callbacks, which a Rust signal
handler cannot do -- it may touch nothing beyond atomics. SignalSubscription
records the signal instead, and the abort runs from checkpoints on the normal
call stack, where the clean-up can borrow the state it needs. That also
resolves the closure-capture TODO(phase-c)s in RequireCommand and
InstallationManager, and replaces exit_with_last_signal's exit(0) with the
restore-and-re-raise Seld\Signal does.
A subscription is live only inside the four abort regions, so elsewhere the
signals keep their default disposition and kill the process at once. It is
installed without SA_RESTART so a signal interrupts an interactive prompt
rather than resuming the read. A signal reaches only the innermost
subscription, reproducing SignalHandler's single-stack dispatch.
Drop SignalRegistry, SignalableCommandInterface and the Application wiring
for them: nothing in Composer reaches that path, and SignalHandler discards
whatever they register. Signal handling from plugins and scripts is
undefined behavior; see docs/dev/signals.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
isSigchildEnabled() detects a PHP built with --enable-sigchild, where PHP
reaps children itself and proc_get_status()/proc_terminate() stop reporting
or reaching them. Shirabe spawns child processes from Rust, so that build
option cannot affect them and every sigchild branch was unreachable.
Removing the branches retires the state that existed only to feed them:
fallbackStatus (written by the fourth pipe and by doSignal, read only by
the sigchild merge in updateStatus) and useFileHandles (whose sole reader
was the sigchild condition). shirabe-php-shim loses phpinfo(),
INFO_GENERAL and posix_kill(), which had no other callers.
DiagnoseCommand keeps its --enable-sigchild warning: it reports on the
user's PHP installation, not on how Shirabe runs processes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
These parameters kept the leading underscore they were given while their
function bodies were still todo!(), and the underscore now reads as "this
argument is ignored" for arguments the bodies do use.
Removing the prefix stops it from suppressing four clippy lints, fixed
alongside: one redundant field name, and three `&mut Vec` parameters that
only need a slice.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The shim raises no PHP-level errors, so error_get_last() always returned
None and every message built from it lost its trailing reason. Now that
the fs mutators and php_strip_whitespace carry an io::Error, take the
reason from the call that actually failed instead of a global last-error
slot.
Filesystem::unlinkImplementation returns that error rather than a bool so
ensureDirectoryExists, unlink and rmdir can report it, and PhpFileParser
appends it to the "following message may be helpful" hint. The wording
is Rust's io::Error text, not PHP's warning text, for the same reason
noted in symfony/filesystem.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
InstalledVersions is a runtime API for plugins and project code; Composer
itself never reads it. Its consumers run in the PHP worker against the copy
FilesystemRepository dumps to vendor/composer/InstalledVersions.php, whose
static state is already kept in sync by __shirabe_installed_versions_reload.
Nothing in Rust read the mirrored statics, so reload() and the reflection
setters were no-ops.
The tests covered only the Rust port, not the PHP class the worker loads, so
they assert nothing about compatibility; they are left as todo!() skeletons.
This also removes the shim functions method_exists, php_dir and
require_php_file, whose only caller was the deleted module.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Composer turns the cycle collector off around the dependency solver, but
Rust has no GC, so the gc_collect_cycles/gc_disable/gc_enable shims were
no-ops. Remove the call sites and the now-callerless shim functions.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The only live caller passed the constant 'array_merge', so the list
concatenation is written out in place, as ClassLoader::get_prefixes
already does. That leaves the shim function without callers.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Its doc-by-reference sibling call_user_func_array now carries the full
reason text.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
Problem reported the platform php version from the shim's compile-time
PHP_VERSION constant, and the shim's phpversion() hit todo!() for any
extension. Go through the RPC bridge instead, as PHP's
Composer\Platform\Runtime does, and drop the shim function that now has
no callers.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
shirabe never runs on HHVM, so the HHVM_VERSION_ID branches are dead.
Dropping them leaves the shim's unimplemented `constant()` without a
caller, so remove it as well.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
The shim reported setExternalAttributesName as missing, so ZipArchiver took
the branch for libzip below 0.11.2 and every archived entry got the zip
crate's default mode. The attributes now travel as arguments to add_file and
add_empty_dir, because the crate fixes an entry's external attributes when
the entry is started and offers no way to amend one already written.
unix_permissions keeps only the low 9 mode bits, on top of which the crate
restores S_IFREG and S_IFDIR, so setuid/setgid/sticky bits and other file
types are still dropped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
The deadline is a constant baked in at build time, so PHP's define() of
COMPOSER_DEV_WARNING_TIME cannot make Application take that branch.
Application now holds the deadline in a field that __set_dev_warning_time
overrides, letting testDevWarning run instead of staying ignored. The
define() shim, whose only caller was that test, goes away with it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Composer defines COMPOSER_DEV_WARNING_TIME from its phar stub when the
compiled version is a commit hash rather than a tag, so the value exists
only in the build artifact. It was a todo!() in the PHP shim, leaving the
warning branch in Application::do_run unreachable.
A build script now derives it the way Compiler does, from git describe
and the HEAD commit date, and composer::COMPOSER_DEV_WARNING_TIME holds
the result as a Rust constant instead of a runtime-defined one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Getting a rule's identity meant spl_object_hash(&*rule.borrow()), so the
solver borrowed a RefCell just to read an address, and a second function
spl_object_hash_process existed because one generic fn cannot tell Rc<T>
from &T.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
PHP's version_compare takes its operator as a string, so the shim's port
did too, and Constraint carried two families of operator constants plus
translation tables to convert between the string form and its own int
codes. Five copies of those tables had accumulated across Constraint,
CompilingMatcher and the plugin value bridge.
version_compare now takes a CmpOp, which makes an invalid operator
unrepresentable and removes the tables' reason to exist. Constraint
stores a CmpOp and keeps only the string parsing its constructor needs;
getOperator, compile and CompilingMatcher::match speak CmpOp as well.
PHP's OP_* numbering stays observable: a plugin reads the raw integer off
the Constraint object over RPC, so get_operator_constant and its new
inverse hold that 0..5 mapping.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
|
|
Replace the todo!() bodies with real ports. Four autoload-generator
tests now run for real; the rest stay #[ignore]d, but each ignore reason
now names the concrete missing symbol instead of a vague subsystem.
Production additions the ports need: the deprecated
AuthHelper::addAuthenticationHeader wrapper,
EventDispatcher::__set_dispatch_script_override as the seam for PHPUnit
onlyMethods(['dispatchScript']), and a define() stub in the shim.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Retag every Shirabe-authored TODO comment to one of the fixed tags:
phase-c, phase-d, plugin, php-runtime, phase-e.
Upstream-authored TODO comments from Composer/Symfony are left
untouched to preserve the ported code shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
Several shim functions were left as todo!() because the standard library
exposes no equivalent and no syscall crate was available. Adding nix
unblocks them:
- proc_open now wires descriptors beyond stderr, creating the pipe itself
and installing the child end with dup2(2) from pre_exec
- proc_terminate and posix_kill deliver arbitrary signals via kill(2)
- get_current_user reports the owner of the running executable
- php_uname answers every mode from uname(2) instead of only "s" and "r"
It also closes gaps that were previously approximated:
- fstat stats the stdio streams and pipes rather than reporting failure
- touch stamps mtime/atime on an existing path, including directories
- is_writable/is_executable use access(2) instead of permission bits
- umask falls back to the read-modify-write umask(2) off Linux
The hand-written repr(C) structs and extern "C" declarations for getpwuid,
utime, statvfs, fcntl and select are replaced by their nix wrappers, which
in turn lets disk_free_space drop its Linux-only cfg.
cli_set_process_title, setproctitle and the pcntl_signal pair stay as
todo!(): the first two need access to the process's own argv block, and
the latter two depend on the signal-handling subsystem rather than on
sigaction(2) itself.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The audit in .ken/php-shim-copying.md judged 14 functions in
shirabe-php-shim (plus php_wordwrap in shirabe-external-packages) to be
line-by-line transcriptions or structural imitations of php-src. PHP's
relicensing to 3-clause BSD makes keeping them legal, but the boundary
between BSD-derived and MIT code was invisible in the source tree.
Moving them into their own crate puts the license into the build
metadata (so NOTICE generation follows the binary), makes a reverse
dependency a compile error, and encodes the origin in the module path,
which mirrors php-src's ext tree. Each function records its origin in a
fixed-format doc comment, and a new php_src_derivation_boundary linter
fails if `php-src` appears in any Rust source outside the crate.
Public paths under shirabe_php_shim:: are unchanged: functions that are
themselves derived are re-exported with `pub use`, and the wrappers that
only validate arguments stay on the MIT side.
This also resolves the duplicate wordwrap implementation.
shirabe_php_shim::wordwrap was todo!(), so SymfonyStyle::block panicked,
while shirabe-external-packages carried its own copy. Both now go
through the single port, verified against real PHP on 13 cases covering
multi-character breaks and cut.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
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.
|
|
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>
|
|
|
|
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Compiled Rust never loads a class by name, so the registered callback is dropped.
Return success so callers that register an autoloader during startup can proceed.
Kept the TODO(phase-d) comment: this is an unblocking stub, not a faithful
implementation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Replace the libcurl-shim CurlDownloader with a reqwest+tokio implementation per
the .ken sketch, resolving the construction panic that blocked command tests
(mock path via __new_mock is untouched). Port remote_filesystem (7), hg/svn
driver (4), zip_archiver/git_exclude_filter (4) tests. Fix hg/svn/git_exclude
regex-delimiter and svn result-propagation porting bugs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
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>
|
|
The PCRE delimiter `(?<!^|as|[=>< ,]) *(?<!-)[, ](?!-) *(?!,|as|$)` used to
split AND-constraints relies on look-around, which the regex crate cannot
compile (parse_constraints panicked). Reproduce its semantics in a hand-written
`split_and_constraints` scanner shared by VersionParser and RootPackageLoader.
Also model `method_exists` for the class-name form (shirabe runs no dumped
Composer ClassLoader) and un-ignore the InstalledVersions tests, serialized via
`#[serial]` since they share global static state.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Port php_version_compare (canonicalization + special-form ordering) and
expose it via version_compare()/version_compare_2(). Implement clone()
(via Clone), spl_object_hash()/spl_object_hash_process() (address-based),
get_loaded_extensions() and the main-version case of phpversion().
Interpreter/reflection/autoload/eval/$GLOBALS/memory-accounting and
Windows-only SAPI helpers remain TODO(phase-d): they have no equivalent
in the compiled shim.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
json_encode/json_encode_ex now return anyhow::Result<String> instead of
Option, so callers no longer need json_last_error() to get the failure
reason.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|