| Age | Commit message (Collapse) | Author |
|
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>
|
|
This is the type Filesystem::directory_size() actually iterates, and it
swallowed a failed stat as 0 the same way. PHP's iterator yields
\SplFileInfo there, so raise the same \RuntimeException it would.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
fstat and lstat now return Option<FileStat> instead of a PhpMixed array, so
Platform::is_tty and Filesystem::is_junction read `mode` as a field. The
array carried each of the 13 values twice — once under its numeric index and
once under its name — which no caller relied on, and building it spelled the
field list out four times.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
PhpDirHandle recorded the opened path and nothing else, and its only
caller asked just whether the open had succeeded. A resource type that
has to gain readdir and closedir before it means anything is worse than
the std::fs::read_dir call it wraps, so Filesystem::isReadable now makes
that call directly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The two TODOs marked deferred work that nothing reaches.
FILE_USE_INCLUDE_PATH appears nowhere in Composer or its vendored
dependencies, and the only site passing LOCK_EX to file_put_contents is
Symfony's Filesystem::appendToFile(), which no caller invokes and which
raises the flag only when handed a third argument. The stream $context
is dropped just as narrowly: the network scheme that would carry one is
already marked at the call site in RemoteFilesystem, leaving the shim
reachable through the local-file branch alone.
Record what these functions do and do not support instead, so the tags
stay a list of work that is actually pending.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The comment claimed the port loses the file type bits that PHP's
fileperms() reports. It does not: MetadataExt::mode() hands back the raw
st_mode, the same value php_stat() returns for FS_PERMS, and both agree
on directories, regular files and executables.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
fileperms swallowed metadata errors and reported a mode of 0, which the
callers could not tell apart from a real (if implausible) mode: the zip
archiver stored entries with no permission bits, and Filesystem::copy
chmod-ed the target to 0. It now returns Result<u32, io::Error> so both
callers propagate the failure. The switch to u32 also drops the casts
around the mode arithmetic and ZipArchive's entry attributes.
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>
|
|
PathDownloader builds an ArchivableFilesFinder and hands it to
Filesystem::mirror as the iterator that selects what to copy, so a path
package installed by mirroring drops what .gitattributes marks
export-ignore, what .gitignore excludes and the VCS directories. The
port dropped the argument, and mirrored the source tree whole.
Every method mirror() calls on the entries it walks is derived from the
pathname, so the iterator is modeled as a list of pathnames rather than
as a Traversable of SplFileInfo.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
doRemove() renames a directory to a random hidden name before emptying
it, and undoes that rename when the final rmdir fails, so a concurrent
process cannot recreate the path mid-removal. It also walks one level at
a time through FilesystemIterator instead of flattening the whole tree,
and lets an inner rmdir failure pass, both as upstream does.
copy() keeps the mode fopen($targetFile, 'w') would have left rather
than the origin's, symlink() and mirror() call readlink() and
getLinkTarget() where upstream does, and a directory iterator that
cannot be opened propagates its UnexpectedValueException instead of
being swallowed or flattened into an IOException.
Error message text is out of scope per docs/known-incompatibilities.md,
so the three TODO(phase-c) markers that only tracked wording are gone,
along with linkException()'s Windows-only branch. So are the arguments
no caller varies -- symlink()'s copyOnWindows, mirror()'s iterator and
options, copy()'s overwriteNewerFiles -- which removes the last
TODO(phase-c) in the file.
New shim functions: readlink, filesystem_iterator, stream_is_local,
strrev and SplFileInfo::getLinkTarget. base64_encode takes bytes so
random_bytes() can feed it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
mkdir, rmdir, unlink and symlink each had a bool version and a _result
twin returning the io::Error, which left two names for one call. Keep
only the Result form and let the callers that want a boolean spell out
.is_ok(). Call sites that discard the outcome, as their PHP originals
do, are unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Symfony wraps its native filesystem calls in box(), which captures the
warning text of a failed call into self::$lastError and appends it to
the IOException message. The port dropped that text because the shim's
mkdir, rmdir, unlink and symlink only return PHP's bare false.
Give each of those a Result-returning variant carrying the io::Error,
and use it to restore the appended reason. That also makes two
conditions portable: doRemove()'s "Permission denied" test, and
linkException()'s Windows error code 1314 special case.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
The shim's PATH_SEPARATOR was hardcoded to ":", so every PATH list was
split and joined on the wrong character off Unix. std::env::split_paths
and join_paths use the platform's separator, which also lets the bin-dir
membership test in EventDispatcher compare list entries instead of
regex-matching the raw PATH string.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The shim's DIRECTORY_SEPARATOR was hardcoded to "/", so every ported
`'\\' === DIRECTORY_SEPARATOR` check compared against a constant that
does not track the target platform. std::path::MAIN_SEPARATOR and
MAIN_SEPARATOR_STR carry the same meaning as PHP's constant and resolve
per platform, so the Windows branches are selected on Windows targets.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
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>
|
|
pathinfo only ever receives a string and only ever returns one for the
single-component options it supports, so the PhpMixed wrapping forced
every call site to pack and unpack the value again.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
Port the Symfony Filesystem branches this file had left out:
* copy() preserves the origin mtime via touch()
* exists() rejects paths longer than PHP_MAXPATHLEN - 2, so its return
type becomes anyhow::Result<bool>
* doRemove()'s symlink branch keeps the DIRECTORY_SEPARATOR disjunct,
which stops it from throwing on Unix where upstream never does
* symlink() normalizes separators and mirrors instead of linking when
copyOnWindows is set
* mirror() skips entries whose real path is the target directory or was
already created earlier in the same call
PHP_MAXPATHLEN is new in shirabe-php-shim.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
|
The shim's filesystem entry points took `&str` even though each one resolves
to a local path through `std::fs` or a syscall, so callers holding a `PathBuf`
had to stringify it at the call site. They now take `impl AsRef<Path>`, the
form `file_exists`, `is_dir`, `unlink` and the rest of the already-converted
set use.
`Phar`, `PharData` and `ZipArchive` keep their archive path as a `PathBuf`.
`PharData::compress` names the compressed sibling by appending the suffix to
the file name rather than formatting the path into a `String`.
Arguments PHP resolves through a stream wrapper (`fopen`, `file_put_contents`,
`include`) still take `&str`, as do the byte-string operations (`dirname`,
`basename`, `pathinfo`) and archive-internal entry names, which are `/`-joined
logical names rather than OS paths.
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>
|
|
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>
|
|
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.
|
|
Extends no_banned_use to cover std::any::Any, std::io::Read/Write, and
std::process::Command, and teaches the linter to allow `as _` imports
so trait methods can still be brought into scope without binding the
banned name. Fully qualifies all existing usages across the codebase.
|
|
Give DirectoryIteratorEntry a backing path (mirroring
RecursiveIteratorFileInfo) and make directory_iterator enumerate entries,
returning Result to match PHP DirectoryIterator's UnexpectedValueException
on an unopenable directory. Wire the new Result through DumpCompletionCommand's
get_supported_shells.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|
|
Add create_installed_json/create_composer_lock test helpers. Port command (8),
repository path/forgejo/perforce/vcs (11), and fossil/hg/download_manager (13)
tests. Fix production porting bugs: root_package_loader/forgejo_url/version_bumper
regex delimiters, repository_manager create_repository_by_class, array_loader
isset, licenses_command RefCell borrow; implement disk_free_space and
touch2/touch3 via libc.
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>
|
|
Port autoload_generator (24), bitbucket (14), suggested_packages (11),
git_driver (6), archive_manager (3), and a bump command test. Fix the
ApplicationTester output-capture root cause (php://memory streams must be
readable regardless of fopen mode). Implement posix_getuid/geteuid, the PCRE
'A' anchored modifier, php_strip_whitespace, stream_get_wrappers, is_callable
scalars; fix preg_quote angle-bracket escaping and class-map parser regexes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Replace the todo!() json_schema::Validator stub with the jsonschema crate.
Errors are surfaced as 'property : message'; the message wording follows the
jsonschema crate and is *not* justinrainbow-compatible.
Port the ComposerSchemaTest and JsonFileTest schema cases to the new wording
(noted per test).
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.
|
|
JsonFile's schema paths previously relied on php_dir() (__DIR__), which has
no runtime equivalent. Add a build.rs that copies composer-schema.json and
composer-lock-schema.json next to the built executable, and resolve them with
std::env::current_exe(). FilesystemRepository now embeds InstalledVersions.php
directly via include_str! instead of reading it through php_dir().
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Give RecursiveDirectoryIterator/RecursiveIteratorIterator real backing
data: the iterator walks the tree in SELF_FIRST/CHILD_FIRST order, yields
SplFileInfo-like entries (is_dir/is_file/is_link/get_pathname/get_size),
and a Cell cursor lets get_sub_pathname() report the current entry.
Implement the std-backed file helpers: lstat, mkdir (umask-aware via
DirBuilder), symlink, chmod, fileperms, fileowner, is_executable,
unlink_silent, touch (create-if-absent), file()/file_put_contents3/
file_get_contents5, tempnam, umask (via /proc/self/status), and a glob()
supporting *, ?, [...] and {..} brace expansion.
The PhpMixed-keyed fopen stream family, disk_free_space, touch with an
explicit time, opendir and DirectoryIterator remain TODO(phase-d): they
need a PhpMixed stream representation or syscalls std does not expose.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|