| Age | Commit message (Collapse) | Author |
|
Port Application::getPluginCommands: resolve the local composer with
plugins force-enabled, fall back to Factory::createGlobal, and collect
commands from CommandProvider capability adapters. PhpCommandProxy now
mirrors name/description/aliases/hidden over RPC so `list` output
matches upstream; input definitions remain TODO(plugin).
PhpClass::php_class_name returns an owned String because PHP-backed
proxies only know their class at runtime (the override-skip warning
prints get_class). CommandProvider::getCommands hands out shared
Rc<RefCell> handles since the commands are stored in the application.
Factory::createGlobal now propagates createConfig errors instead of
swallowing them, and Application::getComposer only catches the
exception classes upstream catches, so a ParsingException reaches
doRun's GithubActionError path as in Composer.
Co-Authored-By: Claude Fable 5 <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>
|
|
Rust has no runtime class name, so `Command::get_class` existed purely to
let each command hand back its PHP class name, supplied through the
two-argument variant of `delegate_command_trait_impls_to_inner!` at the
impl site. Replace it with a general `PhpClass` trait plus an
`impl_php_class!` macro, so the name is stated once next to the type
definition and the mechanism is reusable outside commands.
`Command` gains `PhpClass` as a supertrait and drops `get_class`, and
`VcsDriverKind`'s hand-rolled `php_class_name` table moves onto the trait.
Behavior is unchanged: the same class-name strings are reported, and the
base command state still panics when asked for a name it cannot supply.
Co-Authored-By: Claude Opus 5 (1M context) <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>
|
|
regex::Regex::clone() does not share the underlying meta engine's
search-cache pool, so every fresh clone pays a ~10us warmup cost on
its first use. Two changes together eliminate this across nearly all
preg_* call sites:
- A php_regex! macro resolves PHP-style patterns to a per-call-site
&'static regex::Regex (via regex-macro's LazyLock), applied at the
majority of call sites throughout the codebase.
- Call sites still passing dynamic pattern strings go through
PATTERN_CACHE, which now stores Arc<(Regex, bool)> and hands out
Arc::clone()s instead of cloning the Regex itself.
PregPattern::resolve() returns a ResolvedPattern enum (Arc or
'static reference) rather than an owned Regex, so neither path ever
clones the Regex proper.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
|
|
PHP arrays do not distinguish an empty map from an empty list, and
json_encode([]) always emits []. The Serialize impl emitted {} for an
empty associative array, which diverged from Composer when computing
the lock file content-hash for a composer.json with an empty require.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|
|
Add fcntl/select extern "C" declarations and a PhpResource::raw_fd seam so the
symfony Process pipe loop can read a live child's stdout/stderr. Fix fread on a
non-blocking fd (WouldBlock -> "") and the Process null-cwd default. Real
subprocess output capture now works; un-ignore the process_executor tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
proc_open/proc_close/proc_get_status/proc_terminate represented the
process handle as a PhpMixed, which cannot hold a live child process or
its pipes, so they were stubs or todo!(). Model the handle as a new
PhpResource::Process variant and child pipes as a StreamBacking::Pipe,
with a native Descriptor enum for descriptorspec; proc_open now returns
io::Result and fills pipes as IndexMap<i64, PhpResource>.
Rewire the Symfony Process pipes and the Console terminal/cursor onto
the new types, removing the "PhpMixed cannot carry a PhpResource"
todo!()s. The remaining todo!()s are genuine syscall leaves
(proc_terminate signal delivery, stream_select, stream_set_blocking,
posix_kill, pty, fd>=3) left unimplemented since no syscall crate is
introduced.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Redesign PhpResource into a real stream handle (File/Memory backing with
tracked position, eof, closed state) and unify the whole fopen family
(fopen/fwrite/fread/fgets/fgetc/feof/fclose/ftell/fseek/rewind/fstat/
ftruncate/fflush and stream_get_contents/stream_copy_to_stream) on
&PhpResource, replacing the split PhpMixed/PhpResource APIs and their
todo!() stubs. fopen now returns Result; read functions stay String for
now (TODO(phase-e) to move to byte strings).
Propagate the signatures through callers: Process stdout/stderr, Cursor
input, curl header/body handles (extracted into typed maps keyed by job
id), Filesystem copy/safe_copy/files_are_equal, BufferIO, error_handler,
platform, perforce, zip. The proc_open pipe paths cannot carry a
PhpResource in a PhpMixed list, so they are left as todo!() with notes.
|
|
Implements a minimal, PHP-compatible subset of \DOMDocument, \DOMNode and
\DOMNodeList for use by Symfony's XmlDescriptor. save_xml mirrors libxml2's
formatOutput serialization (XML declaration, 2-space indent, self-closing
empty elements, and no pretty-printing of text-bearing elements) and writes
to a std::io::Write sink. Verified byte-for-byte against real PHP libxml.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
ArrayObject was only a thin wrapper around IndexMap<String, PhpMixed>
used as an empty-{} vs empty-[] marker and as the assoc=false JSON
object representation; no reference semantics were involved. Inline its
payload directly into PhpMixed::Object and drop the type along with the
now-dead StdClass.
Side effects of the unification:
- ArrayObject::new was todo!(); the config --global / object-typed get
paths that built PhpMixed::Object(ArrayObject::new(None)) no longer
panic.
- base_config_command wrote 'config' as PhpMixed::Array(empty), emitting
[] instead of {}; now matches PHP's new \ArrayObject ({}).
- The dead is::<StdClass>()/is::<ArrayObject>() instanceof checks in
JsonManipulator are replaced with the faithful as_object() mapping.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|
|
apcu_fetch/apcu_add only ran when apcuPrefix was non-null, but
Composer never calls setApcuPrefix on the loaders it instantiates
itself; the prefix is only emitted into the generated target-project
autoload_real.php. So the cache branches were unreachable in Shirabe's
execution paths. Remove the apcu shim and the now-dead lookups.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|
|
Fill in the shim functions that have an easy, accurate pure-Rust port:
array (merge/flip/fill_keys/slice/search/is_list), string (substr_count,
strpbrk, raw/urlencode, ucfirst/ucwords, strstr, strcspn, explode limit,
str_replace arrays), mb_* (strlen/substr/str_split), sort callbacks
(uasort/uasort_map/uksort), levenshtein, intdiv, ceil, ctype_digit,
json_encode, count_mixed and the PhpMixed/to_* boolean casts.
Runtime- or crate-dependent and hard-to-port-accurately stubs (sprintf,
version_compare, natural sort, hashing, etc.) are left as todo!().
|
|
Port PHP setUp/tearDown across the ported integration tests using
same-named set_up()/tear_down() functions and a TearDown struct whose
Drop runs tear_down(). Fixture-init setUp returns its fixtures;
tmpdir-style setUp/tearDown carry state in TearDown fields. Parts that
depend on unported infrastructure (PHPUnit mocks, Config::merge, the PHP
error handler) stay todo!() and are only wired into ignored stubs to
avoid breaking live tests.
Also fix shirabe-php-shim putenv to handle the no-'=' form (PHP unsets
the variable), which Platform::clear_env relies on for the env-clearing
tearDowns.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Faithfully port every method, field and constant of Symfony's
Process.php into process.rs, replacing the reduced stub. Add the
supporting pipes module (PipesInterface/AbstractPipes/UnixPipes/
WindowsPipes), ProcessUtils and the missing process exceptions
(LogicException/InvalidArgumentException) with constructors.
Methods now return anyhow::Result where PHP throws, take the env
argument and a bool-returning callback, and borrow &mut for
status-updating accessors; all callers are updated accordingly.
Extend the php-shim with proc_open/proc_close (PHP-compatible
signatures), proc_get_status, proc_terminate, posix_kill, uniqid,
ftruncate, ftell_stream, fseek3, stream_get_contents3 and env
helpers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Back parse_url/parse_url_all with reqwest::Url and add the
FILTER_VALIDATE_URL and FILTER_VALIDATE_BOOLEAN arms to filter_var, so
Config::prohibit_url_by_config no longer hits todo!(). reqwest::Url is
not a byte-for-byte port of PHP's parser; the divergences are noted with
TODO(phase-c).
Switch the scheme in_array in prohibit_url_by_config to strict: the
needle is a string-or-null and the haystack holds only non-numeric
string literals, so loose and strict comparison are provably equivalent
here, avoiding a dependency on PHP loose `==` semantics.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Replace the todo!() with a std-only check on the path's permission bits.
A TODO notes this approximates PHP's access(2)/W_OK and can diverge for
files the current user does not own; to be refined with a syscall crate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Port Symfony's Application::doRenderThrowable so command failures render
the error box instead of hitting todo!(). This unblocks six CLI no-panic
tests (config, depends, global, prohibits, remove, repository), whose
ignore attributes are now removed.
Also fill in the php-shim functions on the render path that were still
todo!(): php_exception_get_code, intval, str_pad, str_split,
mb_detect_encoding, mb_convert_encoding, mb_strwidth, mb_convert_variables.
PHP file/line and the verbose getTrace() block have no faithful Rust
equivalent; file/line use PHP's own 'n/a' fallback and the trace block is
intentionally omitted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
The List and Array variants of PhpMixed boxed their elements
unnecessarily. Store PhpMixed values directly and update all callers
accordingly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Composer's Application::getComposer() calls exit(1) when a required
Composer instance fails to build under areExceptionsCaught(). Replace the
deep std::process::exit with a php-shim ExitException that mirrors PHP's
`exit` construct: it bypasses parent::doRun()'s catch and Symfony's
renderThrowable (excluded at both broad catches), so the already-written
plain error message is not re-rendered and the process exits with code 1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Was a todo!() that panicked while building HTTP downloader options
(browse, and the stream/remote filesystem option merging). Recurses only
when both the existing and replacing value are arrays, merging assoc
arrays by key and lists by index; otherwise the replacing value wins.
Verified against PHP on a nested http/ssl option structure.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Was a todo!() that panicked in Factory::get_lock_file (require, and the
file/gzip downloaders). Handles the four PATHINFO_* single-component
options by reusing dirname/basename, computing extension and filename
around the last dot of the basename. Verified against PHP for eight
representative paths, including dotfiles and trailing-dot names.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Was a todo!() that panicked when ProcessExecutor::reset_max_jobs probed
COMPOSER_MAX_PARALLEL_PROCESSES (archive, diagnose, init, ...). Ints and
floats are numeric; strings delegate to the existing is_numeric_string,
which agrees with PHP across the tested vectors. Booleans, null and
arrays are not numeric.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Was a todo!() that panicked for every command reading composer.json
(validate, status, show, update, ...). Parses via serde_json (built with
preserve_order, so insertion order is kept) and converts to PhpMixed.
Mirrors PHP's flagless json_decode: returns null rather than erroring on
malformed input, and decodes objects to ArrayObject when assoc is false,
to an associative array when true. Out-of-i64 and fractional numbers
become floats, matching PHP's default non-bigint behaviour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|
|
|
|
|
|
|
|
PHP's random_int/random_bytes are cryptographically secure, but Composer
does not rely on that property, so a non-cryptographic PRNG suffices.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
|
|
The free preg_* functions, the CaptureKey type, and the PREG_* constants
move from the pcre crate into shirabe-php-shim, where the rest of the
PHP standard-library shims live. Colliding names take a 2 suffix
(preg_match2, preg_split2, etc.) since the shim already exposes
differently-shaped variants. Preg keeps its public API and delegates to
the relocated functions; CaptureKey is re-exported from composer::pcre
so consumers are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Replace the todo!() stubs backing the Preg class and the standalone
preg_* shim helpers with regex-crate implementations.
|
|
|
|
PHP wraps fopen/file_get_contents/file_put_contents in set_error_handler
to capture warning text into error_message. Rust reports I/O failures
through return values rather than warnings, so this side channel cannot
work; replace the calls with TODO(phase-c) notes and leave error_message
empty until the I/O layer surfaces a reason. Also remove the now-unused
set_error_handler_closure shim and make set_error_handler a no-op.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Composer\Console\Application embedded Symfony's Application as an
`inner` field and delegated to it, so polymorphic calls inside the
Symfony base (e.g. doRun -> $this->getLongVersion()) resolved to
Symfony's own methods and never reached Composer's overrides. As a
result `--version` bypassed Composer's getLongVersion()/doRun()
entirely.
Flatten the PHP inheritance chain into the single shirabe Application
struct: take in the Symfony base methods (parent-calling overrides kept
under a `base_` prefix) and drop the `inner` delegation. Replace the
Symfony Application struct in shirabe-external-packages with an
`Application` trait that the merged struct implements, so commands and
descriptors can reference it without a reverse crate dependency.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Convert every sprintf() call with a compile-time literal format string to
format!, implementing Display for PhpMixed (delegating to php_to_string) so
PhpMixed values render with PHP string semantics through {}. Also merge the
format!-wrapped and conditional-literal dynamic sites into single format!
calls. Genuinely runtime format strings (table styles, configurable error
messages, command synopsis, progress-bar modifiers, regex-built messages)
still go through sprintf.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Replace todo!() stubs reached on the `composer --version` path so the
command runs without panicking and exits cleanly:
- introspection (function_exists, class_exists, extension_loaded,
defined) via white-lists modeling a standard Linux PHP CLI
- type casts: php_to_string/strval, php_truthy/boolval, substr,
byte_at, explode, strtr_array
- config/env: error_reporting, ini_get, date_default_timezone_*,
server_get/server_contains_key, php_uname("s")
- IO: turn PhpResource into an enum (Stdin/Stdout/Stderr/File) and
implement fwrite/fflush/stream_isatty/php_fopen resource helpers
- shutdown/exit: register_shutdown_function + run_shutdown_functions,
exit, error_get_last
- preg_match_all_offset_capture via the regex crate; the formatter
pattern drops PCRE possessive quantifiers (original kept in a
comment with a TODO)
proc_open reports unavailable for now (TODO(phase-c)); terminal-size
and tty detection fall back to defaults. sprintf calls on this path
are rewritten with format!(). OutputFormatterStyleInterface gains
clone_box to return shared styles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
|
|
The server_argv() shim merely wrapped command-line arguments, so call
std::env::args() directly at each use site and drop the unused shim.
|