| Age | Commit message (Collapse) | Author |
|
Options and arguments were stored and passed as PhpMixed even though
Symfony only ever puts a string, a bool, a list of strings or null in
one. get_option already narrowed to InputOptionValue at the boundary;
this widens that enum into InputValue and pushes it through
InputInterface, InputOption/InputArgument defaults, the Input storage,
ArgvInput/ArrayInput/StringInput/CompletionInput, Command::add_option
and add_argument, and the Composer-side wrappers.
Two neighbouring string|int unions get types of their own:
InputDefinition::{get_argument,has_argument} take an ArgumentName, and
ArrayInput keys its parameters by ParameterName. has_parameter_option
and get_parameter_option take the values they look for as &[&str],
which is what PHP's `(array) $values` cast produced anyway.
Two behaviours change along the way. Input::set_option on a negated
option now negates with PHP's loose bool cast rather than treating a
non-bool as false, matching `!$value`. ArrayInput::parse now resolves
an integer key to an argument position instead of looking up an
argument literally named "0".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
`InputInterface::get_option` returned `PhpMixed`, so the negation branch
of `Input::get_option` reproduced PHP's `return !$value;` as
`!value.as_bool().unwrap_or(false)`, which inverts the result for a
string value instead of leaving it `false`. It now returns
`InputOptionValue`, whose `to_bool` is PHP's truthiness cast.
The narrowing also removes the `Vec<PhpMixed>` element handling the
commands carried for array options: `as_array` hands back `&[String]`,
so the `filter_map(|v| v.as_string())` chains at eight call sites
collapse. Its other accessors keep `PhpMixed`'s names and meanings
(`is_null`, `as_bool`, `as_string`, `to_bool`), and
`From<InputOptionValue> for PhpMixed` covers the callers that feed the
value back into an `IndexMap<String, PhpMixed>` or a `PhpMixed`
parameter.
`Input` keeps its parsed options and `InputOption` its defaults as
`PhpMixed`, so `Input::get_option` is where the narrowing happens and
where a value outside the domain panics.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The capture groups were discarded at 162 of the preg_match call sites,
which only tested the Option. They now call preg_is_match, which lets the
regex engine skip capture tracking.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
PHP fills `$matches` through a by-ref parameter, which the port mirrored
with a `&mut` out-param plus a bool or count return. Every caller then
had to declare an empty binding one line ahead of the call, and nothing
in the type said the binding is only meaningful when the call succeeded.
Return the matches instead: preg_match() and preg_match2() hand back an
Option, and the three preg_match_all* functions hand back the collection
they used to fill.
The occurrence count the two map-shaped preg_match_all* functions used
to return is the length of any one of the map's columns, so it is not
lost -- Preg::match_all() and friends derive it via occurrence_count().
preg_replace2() keeps its `count: Option<&mut usize>`: that one is not
derivable from the replaced string, and callers that do not want it pay
nothing for passing None.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
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 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>
|
|
Command::setProcessTitle has no caller: neither Composer nor the ported
Symfony Console code sets a process title, so run()'s title branch could
never fire. The shim it called into was unimplementable anyway — PHP
rewrites its own argv block, which Rust hands out only as owned copies.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Every parent module in the symfony-* crates already re-exported its leaf
modules with `pub use`, so each item was reachable by two paths. Make the
leaf modules private and route all callers through the single re-exported
path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
shirabe-symfony-console crate
Move `Symfony\Component\Console` out of shirabe-external-packages and
into its own crate, so the path is
`shirabe_symfony_console::application::Application` instead of
`shirabe_external_packages::symfony::console::application::Application`.
The `delegate_to_inner!` and `delegate_command_trait_impls_to_inner!`
macros move with it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|