Skip to content

Commit 4c21fb9

Browse files
committed
feat(filesystem): refactor Psl\Filesystem\write_file, Psl\Filesystem\append_file, and Psl\Filesystem\read_file to use Psl\File component.
Signed-off-by: azjezz <azjezz@protonmail.com>
1 parent 5f1071e commit 4c21fb9

16 files changed

+80
-116
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
* introduced a new `Psl\IO\Stream` component.
1616
* refactored `Psl\IO` handles API.
1717
* introduced a new `Psl\File` component.
18+
* refactor `Psl\Filesystem\write_file`, `Psl\Filesystem\append_file`, and `Psl\Filesystem\read_file` to use `Psl\File` component.

docs/component/filesystem.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
#### `Functions`
1818

19-
- [append_file](./../../src/Psl/Filesystem/append_file.php#L18)
19+
- [append_file](./../../src/Psl/Filesystem/append_file.php#L21)
2020
- [canonicalize](./../../src/Psl/Filesystem/canonicalize.php#L15)
2121
- [change_group](./../../src/Psl/Filesystem/change_group.php#L20)
2222
- [change_owner](./../../src/Psl/Filesystem/change_owner.php#L20)
@@ -49,8 +49,8 @@
4949
- [is_symbolic_link](./../../src/Psl/Filesystem/is_symbolic_link.php#L19)
5050
- [is_writable](./../../src/Psl/Filesystem/is_writable.php#L20)
5151
- [read_directory](./../../src/Psl/Filesystem/read_directory.php#L19)
52-
- [read_file](./../../src/Psl/Filesystem/read_file.php#L24)
52+
- [read_file](./../../src/Psl/Filesystem/read_file.php#L23)
5353
- [read_symbolic_link](./../../src/Psl/Filesystem/read_symbolic_link.php#L21)
54-
- [write_file](./../../src/Psl/Filesystem/write_file.php#L18)
54+
- [write_file](./../../src/Psl/Filesystem/write_file.php#L21)
5555

5656

docs/documenter.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use Psl\Type;
1313
use Psl\Vec;
1414

15-
require_once __DIR__ . "/../src/bootstrap.php";
15+
require_once __DIR__ . "/../vendor/autoload.php";
1616

1717
(static function (array $args) {
1818
$command = Str\lowercase($args[1] ?? 'regenerate');

src/Psl/File/ReadHandle.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ final class ReadHandle extends Internal\AbstractHandleWrapper implements ReadHan
2222
*/
2323
public function __construct(string $path)
2424
{
25-
Psl\invariant(Filesystem\is_file($path), '$filename is not a file.');
26-
Psl\invariant(Filesystem\is_readable($path), '$filename is not readable.');
25+
Psl\invariant(Filesystem\is_file($path), 'File "%s" is not a file.', $path);
26+
Psl\invariant(Filesystem\is_readable($path), 'File "%s" is not readable.', $path);
2727

2828
$this->readHandle = Internal\open($path, 'r', read: true, write: false);
2929

src/Psl/File/ReadWriteHandle.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,21 @@ final class ReadWriteHandle extends Internal\AbstractHandleWrapper implements Re
2525
public function __construct(string $path, WriteMode $write_mode = WriteMode::OPEN_OR_CREATE)
2626
{
2727
$is_file = Filesystem\is_file($path);
28-
Psl\invariant(!Filesystem\exists($path) || $is_file, '$path points to a non-file node.');
28+
Psl\invariant(!Filesystem\exists($path) || $is_file, 'File "%s" is not a file.', $path);
2929

3030
$open_or_create = $write_mode === WriteMode::OPEN_OR_CREATE;
3131
$must_create = $write_mode === WriteMode::MUST_CREATE;
3232
if ($must_create && $is_file) {
33-
Psl\invariant_violation('$path already exists.');
33+
Psl\invariant_violation('File "%s" already exists.', $path);
3434
}
3535

3636
$creating = $open_or_create || $must_create;
3737
if (!$creating && !$is_file) {
38-
Psl\invariant_violation('$path does not exist.');
38+
Psl\invariant_violation('File "%s" does not exist.', $path);
3939
}
4040

4141
if ((!$creating || ($open_or_create && $is_file)) && !Filesystem\is_writable($path)) {
42-
Psl\invariant_violation('$path is not writable.');
42+
Psl\invariant_violation('File "%s" is not writable.', $path);
4343
}
4444

4545
if ($creating && !$is_file) {

src/Psl/File/WriteHandle.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,21 @@ final class WriteHandle extends Internal\AbstractHandleWrapper implements WriteH
2424
public function __construct(string $path, WriteMode $write_mode = WriteMode::OPEN_OR_CREATE)
2525
{
2626
$is_file = Filesystem\is_file($path);
27-
Psl\invariant(!Filesystem\exists($path) || $is_file, '$path points to a non-file node.');
27+
Psl\invariant(!Filesystem\exists($path) || $is_file, 'File "%s" is not a file.', $path);
2828

2929
$open_or_create = $write_mode === WriteMode::OPEN_OR_CREATE;
3030
$must_create = $write_mode === WriteMode::MUST_CREATE;
3131
if ($must_create && $is_file) {
32-
Psl\invariant_violation('$path already exists.');
32+
Psl\invariant_violation('File "%s" already exists.', $path);
3333
}
3434

3535
$creating = $open_or_create || $must_create;
3636
if (!$creating && !$is_file) {
37-
Psl\invariant_violation('$path does not exist.');
37+
Psl\invariant_violation('File "%s" does not exist.', $path);
3838
}
3939

4040
if ((!$creating || ($open_or_create && $is_file)) && !Filesystem\is_writable($path)) {
41-
Psl\invariant_violation('$path is not writable.');
41+
Psl\invariant_violation('File "%s" is not writable.', $path);
4242
}
4343

4444
/**

src/Psl/Filesystem/Internal/write_file.php

-67
This file was deleted.

src/Psl/Filesystem/append_file.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
namespace Psl\Filesystem;
66

77
use Psl;
8+
use Psl\File;
9+
use Psl\IO;
10+
use Psl\Str;
811

912
/**
1013
* Append $content to $file.
@@ -17,5 +20,18 @@
1720
*/
1821
function append_file(string $file, string $content): void
1922
{
20-
Internal\write_file($file, $content, true);
23+
try {
24+
$handle = File\open_write_only($file, File\WriteMode::APPEND);
25+
$lock = $handle->lock(File\LockType::EXCLUSIVE);
26+
27+
$handle->writeAll($content);
28+
29+
$lock->release();
30+
$handle->close();
31+
} catch (File\Exception\ExceptionInterface | IO\Exception\ExceptionInterface $previous) {
32+
throw new Exception\RuntimeException(Str\format(
33+
'Failed to write to file "%s".',
34+
$file,
35+
), 0, $previous);
36+
}
2137
}

src/Psl/Filesystem/read_file.php

+15-24
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
namespace Psl\Filesystem;
66

77
use Psl;
8-
use Psl\Internal;
8+
use Psl\File;
9+
use Psl\IO;
910
use Psl\Str;
1011

11-
use function file_get_contents;
12-
1312
/**
1413
* Reads entire file into a string.
1514
*
@@ -19,33 +18,25 @@
1918
*
2019
* @throws Psl\Exception\InvariantViolationException If the file specified by
2120
* $file does not exist, or is not readable.
22-
* @throws Exception\RuntimeException If an error
21+
* @throws Exception\RuntimeException In case of an error.
2322
*/
2423
function read_file(string $file, int $offset = 0, ?int $length = null): string
2524
{
26-
Psl\invariant(exists($file), 'File "%s" does not exist.', $file);
27-
Psl\invariant(is_file($file), 'File "%s" is not a file.', $file);
28-
Psl\invariant(is_readable($file), 'File "%s" is not readable.', $file);
25+
try {
26+
$handle = File\open_read_only($file);
27+
$lock = $handle->lock(File\LockType::SHARED);
2928

30-
if (null === $length) {
31-
[$content, $error] = Internal\box(
32-
static fn() => file_get_contents($file, false, null, $offset)
33-
);
34-
} else {
35-
[$content, $error] = Internal\box(
36-
static fn() => file_get_contents($file, false, null, $offset, $length)
37-
);
38-
}
29+
$handle->seek($offset);
30+
$content = $handle->readAll($length);
3931

40-
// @codeCoverageIgnoreStart
41-
if (false === $content || null !== $error) {
32+
$lock->release();
33+
$handle->close();
34+
35+
return $content;
36+
} catch (File\Exception\ExceptionInterface | IO\Exception\ExceptionInterface $previous) {
4237
throw new Exception\RuntimeException(Str\format(
43-
'Failed to read file "%s": %s.',
38+
'Failed to read file "%s".',
4439
$file,
45-
$error ?? 'internal error',
46-
));
40+
), 0, $previous);
4741
}
48-
// @codeCoverageIgnoreEnd
49-
50-
return $content;
5142
}

src/Psl/Filesystem/write_file.php

+23-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
namespace Psl\Filesystem;
66

77
use Psl;
8+
use Psl\File;
9+
use Psl\IO;
10+
use Psl\Str;
811

912
/**
1013
* Write $content to $file.
@@ -17,5 +20,24 @@
1720
*/
1821
function write_file(string $file, string $content): void
1922
{
20-
Internal\write_file($file, $content, false);
23+
try {
24+
if (namespace\is_file($file)) {
25+
$mode = File\WriteMode::TRUNCATE;
26+
} else {
27+
$mode = File\WriteMode::OPEN_OR_CREATE;
28+
}
29+
30+
$handle = File\open_write_only($file, $mode);
31+
$lock = $handle->lock(File\LockType::EXCLUSIVE);
32+
33+
$handle->writeAll($content);
34+
35+
$lock->release();
36+
$handle->close();
37+
} catch (File\Exception\ExceptionInterface | IO\Exception\ExceptionInterface $previous) {
38+
throw new Exception\RuntimeException(Str\format(
39+
'Failed to write to file "%s".',
40+
$file,
41+
), 0, $previous);
42+
}
2143
}

src/Psl/IO/Internal/ResourceHandle.php

+2
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ public function seek(int $offset): void
160160
throw new Exception\AlreadyClosedException('Handle has already been closed.');
161161
}
162162

163+
Psl\invariant($offset >= 0, '$offset must be a positive-int.');
164+
163165
/** @psalm-suppress PossiblyInvalidArgument */
164166
$result = @fseek($this->resource, $offset);
165167
if (0 !== $result) {

src/Psl/IO/SeekHandleInterface.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface SeekHandleInterface extends HandleInterface
1717
* Offset is relative to the start of the handle - so, the beginning of the
1818
* handle is always offset 0.
1919
*
20-
* @throws Psl\Exception\InvalidArgumentException If $offset is negative.
20+
* @throws Psl\Exception\InvariantViolationException If $offset is negative.
2121
* @throws Exception\AlreadyClosedException If the handle has been already closed.
2222
* @throws Exception\RuntimeException If an error occurred during the operation.
2323
*/

src/Psl/Internal/Loader.php

-1
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,6 @@ final class Loader
391391
'Psl\Html\decode',
392392
'Psl\Html\decode_special_characters',
393393
'Psl\Html\strip_tags',
394-
'Psl\Filesystem\Internal\write_file',
395394
'Psl\Filesystem\change_group',
396395
'Psl\Filesystem\change_owner',
397396
'Psl\Filesystem\change_permissions',

tests/unit/File/ReadWriteHandleTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@ public function testReading(): void
6262
public function testMustCreateExistingFile(): void
6363
{
6464
$this->expectException(InvariantViolationException::class);
65-
$this->expectExceptionMessage('$path already exists.');
65+
$this->expectExceptionMessage('already exists.');
6666

6767
new File\ReadWriteHandle(__FILE__, File\WriteMode::MUST_CREATE);
6868
}
6969

7070
public function testAppendToNonExistingFile(): void
7171
{
7272
$this->expectException(InvariantViolationException::class);
73-
$this->expectExceptionMessage('$path does not exist.');
73+
$this->expectExceptionMessage('does not exist.');
7474

7575
new File\ReadWriteHandle(__FILE__ . '.fake', File\WriteMode::APPEND);
7676
}
@@ -81,7 +81,7 @@ public function testAppendToANonWritableFile(): void
8181
Filesystem\change_permissions($temporary_file, 0555);
8282

8383
$this->expectException(InvariantViolationException::class);
84-
$this->expectExceptionMessage('$path is not writable.');
84+
$this->expectExceptionMessage('is not writable.');
8585

8686
new File\ReadWriteHandle($temporary_file, File\WriteMode::APPEND);
8787
}

tests/unit/File/WriteHandleTest.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ final class WriteHandleTest extends TestCase
1414
public function testMustCreateExistingFile(): void
1515
{
1616
$this->expectException(InvariantViolationException::class);
17-
$this->expectExceptionMessage('$path already exists.');
17+
$this->expectExceptionMessage('already exists.');
1818

1919
new File\WriteHandle(__FILE__, File\WriteMode::MUST_CREATE);
2020
}
2121

2222
public function testAppendToNonExistingFile(): void
2323
{
2424
$this->expectException(InvariantViolationException::class);
25-
$this->expectExceptionMessage('$path does not exist.');
25+
$this->expectExceptionMessage('does not exist.');
2626

2727
$f = new File\WriteHandle(__FILE__ . '.fake', File\WriteMode::APPEND);
2828
$f->write('g');
@@ -34,7 +34,7 @@ public function testAppendToANonWritableFile(): void
3434
Filesystem\change_permissions($temporary_file, 0555);
3535

3636
$this->expectException(InvariantViolationException::class);
37-
$this->expectExceptionMessage('$path is not writable.');
37+
$this->expectExceptionMessage('is not writable.');
3838

3939
new File\WriteHandle($temporary_file, File\WriteMode::APPEND);
4040
}

tests/unit/Filesystem/FileTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function testWriteFileThrowsForNonWritableFiles(): void
110110
Filesystem\change_permissions($file, 0111);
111111

112112
$this->expectException(InvariantViolationException::class);
113-
$this->expectExceptionMessage('File "' . $file . '" is not writeable.');
113+
$this->expectExceptionMessage('File "' . $file . '" is not writable.');
114114

115115
Filesystem\write_file($file, 'hello');
116116
}

0 commit comments

Comments
 (0)