aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/util/remote_filesystem.rs
AgeCommit message (Collapse)Author
2026-08-23fix(fs): carry file_get_contents results as bytesnsfisis
file_get_contents() and file_get_contents_with_max_length() return Vec<u8> instead of a from_utf8_lossy'd String. Call sites whose consumer takes a &str still convert lossily and are marked TODO(bytes). file_get_contents_with_max_length() now reads at most the requested number of bytes instead of the whole file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18refactor(preg): add preg_is_match for existence-only call sitesnsfisis
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>
2026-08-18refactor(preg): drop the offset argument from preg_matchnsfisis
Every call site but one passed offset 0. The remaining one, the UTF-8 chunking loop in Application, slices the subject instead: its pattern has no anchor or lookaround, so matching a suffix is equivalent to starting the search at that offset. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18refactor(pcre): inline Preg into its call sites and drop the cratensfisis
Preg had shed everything it owned: after the last few rounds its methods were one-line forwards to the shim's preg_*(), differing only in a default argument or a wrapper the caller unwrapped anyway. The 460 call sites now name the shim function, and shirabe-pcre is gone from the workspace along with its LICENSE entry. The forwards expand as they read: isMatch becomes preg_match2(.., 0).is_some() (is_none() where PHP negates it), isMatch3 and match3 drop the .is_some(), matchAll counts through preg_match_all2(..).occurrence_count(), and replace4/replace5 spell out the limit and count arguments preg_replace2 takes. Callbacks are the one place the shapes differ: preg_replace_callback carries an error out of the callback, so the fourteen infallible closures wrap their result in Ok() and expect() it back. Config::process() is the fifteenth, and it drops the `error` cell it captured to smuggle a failure past a closure that could only return a String. The `?` in the closure now carries it, which is what the PHP does -- a throw from the callback leaves preg_replace_callback at the failing match rather than running the remaining replacements and reporting the last error. The module doc that explained why composer/pcre's exceptions and *StrictGroups() variants have no counterpart moves to the shim's preg module, where the functions it describes live. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18refactor(preg): split PregMatches reads into get() and name()nsfisis
PregMatches keyed both forms of a capture group through CaptureKey, so every read built one: a usize wrapped in an enum, or worse, a String allocated to name a group that regex::Captures can look up from a &str. It now mirrors regex::Captures instead -- get() takes the group number, name() the group name -- and the enum drops out of the type entirely. That is 285 call sites across 59 files, and the named ones carry most of the win: `matches.get(&CaptureKey::ByName("host".to_string()))` reads as `matches.name("host")`. ProcessExecutor loses a `user_key` binding that existed only to build the key once. CaptureKey stays as the key type of PregMatchesAll and PregMatchesAllWithOffsets, where numbered and named entries share one IndexMap and a key type is the point. Five files still name it. Also retargets the two preg_match_all comments that described the occurrence count through `matches[&CaptureKey::ByIndex(0)].len()`, an Index impl these types no longer carry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17refactor(pcre): return the Preg $matches instead of filling an out-paramnsfisis
`Composer\Pcre\Preg` fills `$matches` through a by-ref parameter, and the port mirrored that with a `&mut` (or `Option<&mut>`) out-param plus a bool or count return. Callers had to declare an empty map one line ahead of the call, and the type never said the map is only meaningful when the call matched. Return the matches instead: - match3/match4/is_match3/is_match4 -> Option<PregMatchedGroups> - is_match_named -> Option<PregNamedGroups> - match_all2/is_match_all -> PregMatchesAll - is_match_all_with_offsets3 -> PregMatchesAllWithOffsets Nothing is lost: the bool is `Option::is_some()`, and the occurrence count is the length of any one column of a PREG_PATTERN_ORDER map, now spelled `PregMatchesAll::occurrence_count()`. is_match() still answers the bool question directly for callers that want no groups. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17refactor(preg): wrap the preg_* $matches maps in newtypesnsfisis
The five IndexMap shapes that the preg_* functions and Preg fill in are now distinct types generated by preg_match_map!, so a matches map no longer interchanges with any other map of the same key and value type. Index<usize> is kept alongside Index<&Q> because call sites such as config_command and event_dispatcher reach for a group by its position in the map rather than by its capture key.
2026-08-16refactor(php-shim): split json_decode into assoc and obj variantsnsfisis
The assoc flag was always a literal at every call site, so the boolean carried no information the function name could not. json_decode_assoc and json_decode_obj make the resulting PhpMixed shape visible at the call site. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16refactor(php-shim): give parse_url a typed UrlComponents resultnsfisis
parse_url now returns Option<UrlComponents> instead of a PhpMixed array, and the component-selecting overload with the PHP_URL_* constants is gone: callers read the field they want. Two call sites change behaviour as a result, both towards PHP: * CurlDownloader::handle_redirect tested scheme and host with is_null(), so an unparsable Location header (PhpMixed::Bool(false)) counted as an absolute URL. PHP's truthiness test sends it to the relative-path branch. * Url::get_origin appended a literal port 0, which PHP treats as falsy and leaves off. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15feat(php-shim): drop the modelled PHP version constantsnsfisis
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>
2026-08-12docs(todo): retag TODO markers by root causensfisis
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09refactor(pcre): extract composer/pcre into the shirabe-pcre cratensfisis
Move `Composer\Pcre` out of shirabe-external-packages and into its own crate, so the path is `shirabe_pcre::preg::Preg` instead of `shirabe_external_packages::composer::pcre::preg::Preg`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08feat(php-shim): give ported exceptions PHP's class hierarchynsfisis
Ported exceptions were flat structs reached with `downcast_ref`, so Composer's `catch (\RuntimeException $e)` only matched the exact leaf type and `get_class($e)` had nothing to report. Each exception now embeds an instance of the class it extends and travels inside an `AnyThrowable`; `Catch::catch`/`catch_mut` walk that chain, and `PhpClass::php_class_name` yields the PHP FQCN. Dropping the `std::error::Error` impls from the exception types leaves `AnyThrowable` as the only route into an `anyhow::Error`, so the walk cannot be bypassed. A `no_exception_downcast` linter catches the `downcast::<X>()` calls that would now silently answer `None`. Three sites change behavior as a result: the `TransportException` exit-code override reaches `MaxFileSizeExceededException`, the `catch (\LogicException)` in findSimilar() reaches its subclasses, and rendered exception titles carry the real class name rather than a guess. `get_class_err()` is no longer a `todo!()`, which re-enables FilesystemRepositoryTest::testCorruptedRepositoryFile. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01feat(php-shim): implement Phar/PharData and the zlib/bzip2 functionsnsfisis
Adopt the tar, flate2, and bzip2 crates to fill in the phar.rs and compress.rs todos: PharData tar/zip reading, building, and whole-archive compression, plus a native .phar reader that follows the php.net file-format manual and verifies hash-based signatures. Callers now propagate the constructor/extract errors PHP throws, and fwrite accepts byte strings so gzread no longer needs lossy UTF-8. The native .phar writing API stays todo!() (no call sites; Composer's Compiler is not ported) and OPENSSL phar signatures are accepted unverified (TODO(phase-c)). This unblocks Tar::getComposerJson and the tar/phar/gzip downloaders; tar_test (7), artifact_repository_test (2), and phar_archiver_test zip (1) are un-ignored. The archive command itself still panics because ArchiveManager::archive always generates glob excludes whose look-ahead regexes the regex crate cannot compile; converting those patterns to regex-compatible ones is a separate, still-undecided work item. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25refactor: replace redundant clones with movesnsfisis
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-20fix(php-shim): use PhpMixed::to_bool() for PHP truthy castsnsfisis
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.
2026-07-20fix(remote-filesystem): read scheme-less local paths in get_remote_contentsnsfisis
PHP's getRemoteContents calls file_get_contents unconditionally: the same stream wrapper reads file:// URLs, plain local paths and network schemes. The Rust port only handled the explicit "file" scheme, so a scheme-less local packages.json repository failed with "file could not be downloaded". Extend the local branch to empty schemes; the http(s) stub is unchanged. This clears the first blocker of the create-project functional test; its ignore reason now documents the remaining ones (live network and Glob::to_regex emitting PCRE lookaheads the regex crate cannot compile), which need a user decision. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18perf(regex): eliminate per-call clone overhead in preg_* dispatchnsfisis
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>
2026-07-16refactor(remote-filesystem): return headers from copy/get_contentsnsfisis
Wrap RemoteFilesystem in Rc<RefCell<>> inside HttpDownloader, in prep for the upcoming &self conversion of add()/get(). copy()/get_contents() now bundle the response headers into their return value instead of requiring a follow-up get_last_headers() call, since two separate calls through a shared RefCell could otherwise race: nothing would guarantee the reader observes the headers from its own request rather than one clobbered by a concurrently borrowed call. get_last_headers() itself is left in place, mirroring RemoteFilesystem::getLastHeaders() in PHP.
2026-07-16fix(proxy-manager): correct singleton lifecycle and simplify to a plain Mutexnsfisis
reset() eagerly rebuilt the ProxyManager singleton immediately, capturing env vars before a caller could set them for the next request. PHP's reset() just nulls the static instance; getInstance() lazily constructs on next use. Match that so proxy env vars set after reset() are observed. get_instance() also ensured the singleton was constructed under its own lock, dropped that lock, and returned the bare Mutex; every caller then took a second, independent lock. A reset() landing in that gap would leave the caller observing None and panicking on .as_ref().unwrap(), a state the old eager-reconstructing reset() could not produce. Return the already-locked MutexGuard from get_instance() instead, so construction and use happen under one lock, and update all call sites accordingly. Holding that guard across a loop body then deadlocked in diagnose_command, since check_http_proxy transitively re-enters get_instance() via HttpDownloader -> CurlDownloader, and std::sync::Mutex is not reentrant. Re-acquire the lock fresh each iteration with a short-lived guard instead. Finally, Mutex::new is a const fn, so the OnceLock wrapper around it was unnecessary indirection; a bare static Mutex<Option<ProxyManager>> initializes to the same state without the get_or_init/get dance. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05feat(remote-filesystem): support file:// URLs in get_remote_contentsnsfisis
get_remote_contents was a full stub always returning None, so any file:// download raised a TransportException. Read local files directly for the file scheme, mirroring PHP's file_get_contents transparently handling the file:// stream wrapper. Also fixes file_get_contents5 to strip the file:// prefix like the 0-arg variant already did.
2026-06-28refactor: add linternsfisis
2026-06-27refactor: fix compiler warnings and clippy warningsnsfisis
2026-06-26feat(http): reimplement CurlDownloader on reqwest; port 15 more testsnsfisis
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>
2026-06-24chore: unwrap meaningless PhpMixed::String()nsfisis
2026-06-21refactor(php-shim): split filter_var into per-filter functionsnsfisis
Replace the dispatch-on-constant filter_var() and filter_var_with_options() with dedicated filter_var_boolean/url/email/ip and filter_var_int_with_range, dropping the FILTER_VALIDATE_* constants and updating all call sites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21refactor(math): use method-style max/min/clamp over std::cmpnsfisis
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20refactor(php-shim): drop Box wrapping from PhpMixed List/Arraynsfisis
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>
2026-06-20refactor: auto-fix clippy warningsnsfisis
2026-06-14refactor(pcre): drop Result from Preg method return typesnsfisis
The Preg methods panic on PCRE failure (per the file header rationale), so their anyhow::Result wrappers never carried an Err. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14refactor(pcre): drop strict-groups Preg variantsnsfisis
Rust's type system already distinguishes participating from non-participating capture groups via Option, so the *StrictGroups methods add no safety here. Remove them and switch callers to the plain variants.
2026-06-13refactor(http): drop unworkable set_error_handler warning capturensfisis
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>
2026-06-12refactor(php-shim): replace literal sprintf calls with format!nsfisis
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>
2026-06-11feat(console): resolve phase-b TODOs in doRun and IO wiringnsfisis
Wire up ConsoleIO with HelperSet/QuestionHelper, register the ErrorHandler with the IO instance, and fall back to a default output in run(). Replace resolved phase-b TODOs across the console, command, io, factory, installer, dependency_resolver, and util modules; reclassify the remaining blockers (typed Symfony command registry, stdin resource caching) as phase-c. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10feat(phase-c): resolve cross-module phase-b TODOsnsfisis
2026-06-04refactor: drop stale phase-b TODO comments resolved by current codensfisis
These TODOs describe work already done: writeError per-line iteration (github, remote_filesystem, svn_downloader) and reference equality via std::ptr::eq (download_manager). No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03feat(php-shim): align fwrite/touch2/PHP_OS_FAMILY/PHP_URL_SCHEME with PHPnsfisis
Adjust fwrite to return int|false equivalent (Option<i64>), add touch2 with mtime, implement PHP_OS_FAMILY via std::env::consts::OS, and swap the PHP_URL_HOST placeholders for the now-available PHP_URL_SCHEME. Wire these into locker, filesystem, platform, and remote_filesystem. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29refactor(io): unify IOInterface params to Rc<RefCell<dyn _>>nsfisis
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26feat(factory): construct PluginManager after Rc::new_cyclicnsfisis
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26refactor(io): share IOInterface via Rc<RefCell<dyn _>> handlensfisis
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20refactor: re-export module items to shorten import pathsnsfisis
2026-05-20fix(compile): fix all remaining compile errorsnsfisis
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19fix(compile): fix more random compile errorsnsfisis
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19fix(compile): fix various compile errorsnsfisis
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17fix(shirabe): correct invalid import paths and add missing dependencynsfisis
2026-05-17chore(style): cargo fmtnsfisis
2026-05-16feat(port): port RemoteFilesystem.phpnsfisis
2026-05-12feat(init): add scaffold filesnsfisis