Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
d13e040
require php 8.4
Baptouuuu Nov 9, 2025
148d063
remove remnants of phpunit
Baptouuuu Nov 9, 2025
4d4143e
update dependencies
Baptouuuu Nov 9, 2025
bd41d17
remove dependency to symfony
Baptouuuu Nov 9, 2025
65fa4e8
silently ignore links when reading from filesystem
Baptouuuu Nov 9, 2025
a821bfb
verify path length before trying to remove it
Baptouuuu Nov 9, 2025
2f8f1d2
remove unused constant
Baptouuuu Nov 9, 2025
2e481ef
Filesystem::mount() now returns an Attempt instead of throwing
Baptouuuu Nov 9, 2025
8615a1a
remove deprecated InMemory::new()
Baptouuuu Nov 9, 2025
1e51a7b
use promoted properties
Baptouuuu Nov 9, 2025
d25f0b7
use exclude method instead of negating condition
Baptouuuu Nov 9, 2025
da97e8a
discard errors when checking if a file exists
Baptouuuu Nov 9, 2025
52f12f8
flag Directory::removed() as internal
Baptouuuu Nov 9, 2025
30dae56
force specifying the case sensitivity at mount time
Baptouuuu Nov 10, 2025
0942c01
better integrate case sensitivity tests in blackbox
Baptouuuu Nov 10, 2025
fa23c1f
add representation of relative tree path to translate it to a concret…
Baptouuuu Nov 10, 2025
b371e07
fix path containing a double /
Baptouuuu Nov 10, 2025
ca5d091
compute the absolute path to remove as late as possible
Baptouuuu Nov 10, 2025
be44a52
add bridge while transitionning from old interface to a final class
Baptouuuu Nov 10, 2025
0d2ad08
add the next internal interface
Baptouuuu Nov 10, 2025
80bdaf6
add Implementation::exists()
Baptouuuu Nov 10, 2025
64dce4c
remove the need for Filesystem to implement Adapter
Baptouuuu Nov 10, 2025
5635e1d
add method to read from a path
Baptouuuu Nov 10, 2025
414cec5
add method to list tree paths
Baptouuuu Nov 10, 2025
e804a25
remove dead code
Baptouuuu Nov 10, 2025
34c5744
remove duplicated logic to recursively traverse directories
Baptouuuu Nov 10, 2025
44455da
make sure the implementations only return relative names and not the …
Baptouuuu Nov 10, 2025
1a7fa3b
remove dead code
Baptouuuu Nov 10, 2025
9302eca
remove dead code
Baptouuuu Nov 10, 2025
8683979
add Implementation::remove()
Baptouuuu Nov 10, 2025
8744688
simplify reading from the filesystem
Baptouuuu Nov 11, 2025
1c2749f
let the bridge handle the logic to create/delete files/directories
Baptouuuu Nov 11, 2025
611a7e0
handle case sensitivity in the bridge
Baptouuuu Nov 11, 2025
447eade
prevent writing unchanged file/directory
Baptouuuu Nov 11, 2025
f681820
remove dead code
Baptouuuu Nov 11, 2025
fadb579
change implementation type to prevent reaching an impossible case
Baptouuuu Nov 11, 2025
42236ce
use null when media type is not parseable to let use the default one
Baptouuuu Nov 11, 2025
192cc67
encapsulate the knownledge if the path to read is a file/directory or…
Baptouuuu Nov 11, 2025
3c09017
let the bridge work with any implementation
Baptouuuu Nov 11, 2025
78819db
give a more easy access to the file name being written
Baptouuuu Nov 11, 2025
5cde856
give a more easy access to the directory name being created
Baptouuuu Nov 11, 2025
31803a4
give a more easy access to the file/directory name to remove
Baptouuuu Nov 11, 2025
a3465b9
make sure to always list with a tree path representing a directory
Baptouuuu Nov 11, 2025
e4a4213
make InMemory implement Implementation
Baptouuuu Nov 11, 2025
f7c9f4d
make Adapter a final class
Baptouuuu Nov 11, 2025
6739d8c
CS
Baptouuuu Nov 11, 2025
4637c7d
Merge branch 'adapter-as-final-class' into next
Baptouuuu Nov 11, 2025
3a74e90
bump blackbox
Baptouuuu Nov 11, 2025
f297bd4
remove wip
Baptouuuu Nov 11, 2025
6b6fa9f
remove custom exceptions
Baptouuuu Nov 11, 2025
c9aa41b
add missing return type
Baptouuuu Nov 18, 2025
2920298
add mechanism to let the caller decide if the mounted directory shoul…
Baptouuuu Nov 19, 2025
c36151c
remove warnings
Baptouuuu Dec 13, 2025
6216fcc
use IO to read file media type
Baptouuuu Dec 13, 2025
f615ed9
use IO to list files
Baptouuuu Dec 13, 2025
ceea075
use IO to check if files/directories exist
Baptouuuu Dec 13, 2025
3617138
fix removing files starting with the same name as the one added
Baptouuuu Dec 13, 2025
a06325f
use IO to create files/directories
Baptouuuu Dec 14, 2025
14801f9
remove duplication of path length verification
Baptouuuu Dec 14, 2025
0318886
use IO to remove files
Baptouuuu Dec 14, 2025
5609332
avoid validating the same path multiple times
Baptouuuu Dec 14, 2025
a4e3403
improve the way to access different kinds of files
Baptouuuu Dec 14, 2025
862db59
remove Content::atPath()
Baptouuuu Dec 14, 2025
394f8e3
rely on the kind of file to know what to do
Baptouuuu Dec 14, 2025
20b78b6
let the read function handles links listed in a directory
Baptouuuu Dec 14, 2025
8bf8d4d
fail when trying to remove a link
Baptouuuu Dec 14, 2025
5feb57f
add missing dependency
Baptouuuu Dec 14, 2025
c5fc22e
add extensive ci
Baptouuuu Dec 15, 2025
3ad26a6
run properties on a simulated disk
Baptouuuu Dec 15, 2025
9c9ef47
test case insensitive simulated disks
Baptouuuu Dec 17, 2025
026ec1b
rename read into access for consistency with innmind/io
Baptouuuu Dec 17, 2025
7d7a6d3
take into account the number of scenarii per proof
Baptouuuu Jan 25, 2026
b021137
tag dependencies
Baptouuuu Jan 25, 2026
cfdc73c
fix documentation
Baptouuuu Jan 25, 2026
10cb9d2
fix Concat use
Baptouuuu Jan 25, 2026
88cbbbd
fix Concat use
Baptouuuu Jan 25, 2026
df05621
fix Concat use
Baptouuuu Jan 25, 2026
6587c45
remove dead code
Baptouuuu Jan 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,3 @@ jobs:
uses: innmind/github-workflows/.github/workflows/psalm-matrix.yml@main
cs:
uses: innmind/github-workflows/.github/workflows/cs.yml@main
with:
php-version: '8.2'
12 changes: 12 additions & 0 deletions .github/workflows/extensive.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Extensive CI

on:
push:
tags:
- '*'
paths:
- '.github/workflows/extensive.yml'

jobs:
blackbox:
uses: innmind/github-workflows/.github/workflows/extensive.yml@main
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
composer.lock
vendor
.phpunit.result.cache
.cache
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# Changelog

## [Unreleased]

### Added

- `Innmind\Filesystem\Recover`

### Changed

- Requires PHP `8.4`
- Links are not silently ignored when listing files/directories. An error is still returned when trying to remove a link.
- `Innmind\Filesystem\Adapter\Filesystem::mount()` now returns an `Innmind\Immutable\Attempt`
- `Innmind\Filesystem\Directory::removed()` is now flagged as internal
- `Innmind\Filesystem\Adapter` is now a final class
- `Innmind\Filesystem\Adapter\Filesystem` is now flagged as internal
- `Innmind\Filesystem\Adapter\InMemory` is now flagged as internal
- `Innmind\Filesystem\Adapter\Logger` is now flagged as internal
- `Innmind\Filesystem\Adapter::mount()` no longer automatically create the directory if it doesn't exist

### Removed

- `Innmind\Filesystem\Adapter\InMemory::new()`
- `Innmind\Filesystem\Adapter\Filesystem::withCaseSensitivity()`, case sensitivity can be specified as the second argument of `::mount()`
- `Innmind\Filesystem\Exception\*`
- `Innmind\Filesystem\File\Content::atPath()`, use `Content::io()` instead

## 8.1.0 - 2025-05-09

### Added
Expand Down
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use Innmind\Filesystem\{
File,
File\Content,
Directory,
Adapter\Filesystem,
Adapter,
};
use Innmind\Url\Path;

Expand All @@ -34,14 +34,13 @@ $directory = Directory::named('uploads')->add(
Content::ofString(\file_get_contents($_FILES['my_upload']['tmp_name'])),
),
);
$adapter = Filesystem::mount(Path::of('/var/www/web/'));
$adapter = Adapter::mount(Path::of('/var/www/web/'))->unwrap();
$_ = $adapter
->add($directory)
->unwrap();
```

This example show you how you can create a new directory `uploads` in the folder `/var/www/web/` of your filesystem and create the uploaded file into it.

**Note**: For performance reasons the filesystem adapter only persist to disk the files that have changed (achievable via the immutable nature of file objects).

All adapters implements [`Adapter`](src/Adapter.php), so you can easily replace them; especially for unit tests, that's why the library comes with an [`InMemory`](src/Adapter/InMemory.php) adapter that only keeps the files into memory so you won't mess up your file system.
> [!NOTE]
> For performance reasons the filesystem adapter only persist to disk the files that have changed (achievable via the immutable nature of file objects).
9 changes: 5 additions & 4 deletions blackbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
Application::new($argv)
->disableMemoryLimit() // because the generated trees can be quite large
->scenariiPerProof(20)
->when(
\getenv('BLACKBOX_SET_SIZE') !== false,
static fn(Application $app) => $app->scenariiPerProof((int) \getenv('BLACKBOX_SET_SIZE')),
)
->when(
\getenv('ENABLE_COVERAGE') !== false,
static fn(Application $app) => $app
Expand All @@ -26,9 +30,6 @@
)
->scenariiPerProof(1),
)
->when(
\method_exists(Application::class, 'allowProofsToNotMakeAnyAssertions'),
static fn($app) => $app->allowProofsToNotMakeAnyAssertions(),
)
->allowProofsToNotMakeAnyAssertions()
->tryToProve(Load::everythingIn(__DIR__.'/proofs/'))
->exit();
18 changes: 9 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
"issues": "http://github.com/Innmind/filesystem/issues"
},
"require": {
"php": "~8.2",
"innmind/immutable": "~4.15|~5.0",
"symfony/filesystem": "~6.0|~7.0",
"innmind/media-type": "~2.1",
"innmind/url": "~4.2",
"php": "~8.4",
"innmind/immutable": "~6.0",
"innmind/media-type": "~3.0",
"innmind/url": "~5.0",
"psr/log": "~3.0",
"innmind/io": "^3.0.1",
"innmind/validation": "~2.0"
"innmind/io": "~4.0",
"innmind/validation": "~3.0"
},
"autoload": {
"psr-4": {
Expand All @@ -37,9 +36,10 @@
}
},
"require-dev": {
"innmind/static-analysis": "^1.2.1",
"innmind/black-box": "^6.0.2",
"innmind/static-analysis": "~1.3",
"innmind/black-box": "~6.5",
"innmind/coding-standard": "~2.0",
"symfony/filesystem": "~6.0|~7.0|~8.0",
"ramsey/uuid": "^4.6"
},
"conflict": {
Expand Down
10 changes: 6 additions & 4 deletions documentation/case_sensitivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ If you're dealing with a case insensitive filesystem then you need to specify it

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
CaseSensitivity,
};
use Innmind\Url\Path;

$adapter = Filesystem::mount(Path::of('somewhere/'))
->withCaseSensitivity(CaseSensitivity::insensitive);
$adapter instanceof Filesystem; // true, use $adapter as usual
$adapter = Adapter::mount(
Path::of('somewhere/'),
CaseSensitivity::insensitive,
)->unwrap()
$adapter instanceof Adapter; // true, use $adapter as usual
```

!!! tip ""
Expand Down
8 changes: 4 additions & 4 deletions documentation/testing/in_app.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# In your application

In your application you'll use most of the time the `Filesystem` adapter but in your tests writing to the filesystem can be slow. Instead you can use the `InMemory` adapter.
In your application you'll use most of the time the `Adapter::mount()` adapter but in your tests writing to the filesystem can be slow. Instead you can use the `Adapter::inMemory()` one.

```php
use Innmind\Filesystem\Adapter\InMemory;
use Innmind\Filesystem\Adapter;

$filesystem = InMemory::emulateFilesystem();
$filesystem = Adapter::inMemory();
// use $filesystem as usual
```

This adapter is tested against the same [properties](own_adapter.md) as `Filesystem` to make sure there is no divergence of behaviour between the two.
This adapter is tested against the same [properties](https://innmind.org/BlackBox/getting-started/property/) as `Adapter::mount()` to make sure there is no divergence of behaviour between the two.
27 changes: 0 additions & 27 deletions documentation/testing/own_adapter.md

This file was deleted.

6 changes: 3 additions & 3 deletions documentation/use_cases/backup_directory.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Backup a directory

```php
use Innmind\Filesystem\Adapter\Filesystem;
use Innmind\Filesystem\Adapter;
use Innmind\Url\Path;

$source = Filesystem::mount(Path::of('/var/data/'));
$backup = Filesystem::mount(Path::of('/volumes/backup/'));
$source = Adapter::mount(Path::of('/var/data/'))->unwrap();
$backup = Adapter::mount(Path::of('/volumes/backup/'))->unwrap();
$source
->root()
->foreach(static fn($file) => $backup->add($file)->unwrap());
Expand Down
8 changes: 4 additions & 4 deletions documentation/use_cases/delete_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
Name,
};
use Innmind\Url\Path;

$filesystem = Filesystem::mount(Path::of('/var/data/'));
$filesystem = Adapter::mount(Path::of('/var/data/'))->unwrap();
$_ = $filesystem
->remove(Name::of('some file'))
->unwrap();
Expand All @@ -21,14 +21,14 @@ If the file doesn't exist it will do nothing and if the name corresponds to a di

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
Name,
Directory,
};
use Innmind\Url\Path;
use Innmind\Immutable\Predicate\Instance;

$filesystem = Filesystem::mount(Path::of('/var/data/'));
$filesystem = Adapter::mount(Path::of('/var/data/'))->unwrap();
$filesystem
->get(Name::of('some directory'))
->keep(Instance::of(Directory::class)) //(1)
Expand Down
7 changes: 4 additions & 3 deletions documentation/use_cases/load_ftp_files.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Say you have a client that push csv files in an unstructured manner inside a FTP

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
File,
Directory,
};
Expand All @@ -24,11 +24,12 @@ function flatten(File|Directory $file): Sequence
return Sequence::of($file);
}

Filesystem::mount(Path::of('/path/to/ftp/directory/'))
Adapter::mount(Path::of('/path/to/ftp/directory/'))
->unwrap()
->root()
->all()
->flatMap(flatten(...))
->foreach(static fn(File $csv) => doYourStuff($csv));
```

The advantage of this approach is that you can easily test the whole program behaviour by replacing the `Filesystem` adapter by a `InMemory` one.
The advantage of this approach is that you can easily test the whole program behaviour by replacing the `Adapter::mount()` adapter by `Adapter::inMemory()`.
16 changes: 8 additions & 8 deletions documentation/use_cases/modify_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
File,
Name,
};
Expand All @@ -34,8 +34,8 @@ $release = static function(File $changelog) use ($insertRelease): File {
),
);
}
$filesystem = Filesystem::mount(Path::of('some/repository/'));
$tmp = Filesystem::mount(Path::of('/tmp/'));
$filesystem = Adapter::mount(Path::of('some/repository/'))->unwrap();
$tmp = Adapter::mount(Path::of('/tmp/'))->unwrap();
$filesystem
->get(Name::of('CHANGELOG.md'))
->keep(Instance::of(File::class))
Expand All @@ -59,7 +59,7 @@ This example modifies the `CHANGELOG.md` file to replace the `## [Unreleased]` t

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
File,
File\Content,
File\Content\Line,
Expand Down Expand Up @@ -88,8 +88,8 @@ $update = static function(File $users) use ($updateUser): File {
static fn($content) => $content->flatMap(static fn($line) => $updateUser($line)),
);
};
$filesystem = Filesystem::mount(Path::of('/var/data/'));
$tmp = Filesystem::mount(Path::of('/tmp/'));
$filesystem = Adapter::mount(Path::of('/var/data/'))->unwrap();
$tmp = Adapter::mount(Path::of('/tmp/'))->unwrap();
$filesystem
->get(Name::of('users.csv'))
->keep(Instance::of(File::class))
Expand All @@ -113,7 +113,7 @@ This example will insert the user `Jane Doe` after `John Doe` wherever he is in

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
File,
File\Content,
Name,
Expand All @@ -134,7 +134,7 @@ $merge = static function(File $file1, File $file2): File {
),
);
};
$filesystem = Filesystem::mount(Path::of('/var/data/'));
$filesystem = Adapter::mount(Path::of('/var/data/'))->unwrap();
$users1 = $filesystem
->get(Name::of('users1.csv'))
->keep(Instance::of(File::class));
Expand Down
12 changes: 6 additions & 6 deletions documentation/use_cases/persist_hand_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
File,
File\Content,
};
use Innmind\Url\Path;

$filesystem = Filesystem::mount(Path::of('/var/data/'));
$filesystem = Adapter::mount(Path::of('/var/data/'))->unwrap();
$_ = $filesystem
->add(File::named('some name'), Content::none())
->unwrap();
Expand All @@ -22,7 +22,7 @@ This is equivalent of running the cli command `touch '/var/data/some name'`.

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
File,
File\Content,
File\Content\Line,
Expand All @@ -33,7 +33,7 @@ use Innmind\Immutable\{
Str,
};

$filesystem = Filesystem::mount(Path::of('/var/data/'));
$filesystem = Adapter::mount(Path::of('/var/data/'))->unwrap();
$_ = $filesystem
->add(File::named(
'some name',
Expand All @@ -52,14 +52,14 @@ When the file is persisted the _end of line_ character will be automatically add

```php
use Innmind\Filesystem\{
Adapter\Filesystem,
Adapter,
File,
File\Content,
Directory,
};
use Innmind\Url\Path;

$filesystem = Filesystem::mount(Path::of('/var/data/'));
$filesystem = Adapter::mount(Path::of('/var/data/'))->unwrap();
$_ = $filesystem
->add(
Directory::named('whatever')->add(
Expand Down
Loading