-
-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Filesystem] Introduce filesystem component
- Loading branch information
Showing
26 changed files
with
802 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem\Exception; | ||
|
||
use Psl\Exception; | ||
|
||
interface ExceptionInterface extends Exception\ExceptionInterface | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem\Exception; | ||
|
||
use Psl\Exception; | ||
|
||
class RuntimeException extends Exception\RuntimeException implements ExceptionInterface | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem\Internal; | ||
|
||
use FilesystemIterator; | ||
use Psl\Filesystem; | ||
use Psl\Filesystem\Exception; | ||
use Psl\Internal; | ||
use Psl\Str; | ||
|
||
use function chgrp; | ||
use function lchgrp; | ||
|
||
/** | ||
* @param iterable<string> $files | ||
* @param string|int $group | ||
* | ||
* @throws Exception\RuntimeException If unable to change the ownership for | ||
* the given file. | ||
*/ | ||
function change_group(iterable $files, $group, bool $recursive = false): void | ||
{ | ||
foreach ($files as $file) { | ||
if ($recursive && Filesystem\is_directory($file) && !Filesystem\is_link($file)) { | ||
change_group(new FilesystemIterator($file), $group, true); | ||
} | ||
|
||
if (Filesystem\is_link($file)) { | ||
$fun = static fn(): bool => lchgrp($file, $group); | ||
} else { | ||
$fun = static fn(): bool => chgrp($file, $group); | ||
} | ||
|
||
[$success, $error] = Internal\box($fun); | ||
if (!$success) { | ||
throw new Exception\RuntimeException(Str\format( | ||
'Failed to change the group for file "%s": %s', | ||
$file, | ||
$error ?? 'internal error.', | ||
)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem\Internal; | ||
|
||
use FilesystemIterator; | ||
use Psl\Filesystem; | ||
use Psl\Filesystem\Exception; | ||
use Psl\Internal; | ||
use Psl\Str; | ||
|
||
use function chown; | ||
use function lchown; | ||
|
||
/** | ||
* @param iterable<string> $files | ||
* @param string|int $user | ||
* | ||
* @throws Exception\RuntimeException If unable to change the ownership for | ||
* the given file. | ||
*/ | ||
function change_owner(iterable $files, $user, bool $recursive = false): void | ||
{ | ||
foreach ($files as $file) { | ||
if ($recursive && Filesystem\is_directory($file) && !Filesystem\is_link($file)) { | ||
change_owner(new FilesystemIterator($file), $user, true); | ||
} | ||
|
||
if (Filesystem\is_link($file)) { | ||
$fun = static fn(): bool => lchown($file, $user); | ||
} else { | ||
$fun = static fn(): bool => chown($file, $user); | ||
} | ||
|
||
[$success, $error] = Internal\box($fun); | ||
if (!$success) { | ||
throw new Exception\RuntimeException(Str\format( | ||
'Failed to change owner for file "%s": %s', | ||
$file, | ||
$error ?? 'internal error.', | ||
)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem\Internal; | ||
|
||
use FilesystemIterator; | ||
use Psl\Filesystem; | ||
use Psl\Filesystem\Exception; | ||
use Psl\Internal; | ||
use Psl\Str; | ||
|
||
use function chmod; | ||
|
||
/** | ||
* @param iterable<string> $files | ||
* | ||
* @throws Exception\RuntimeException If unable to change the ownership for | ||
* the given file. | ||
*/ | ||
function change_permissions(iterable $files, int $permission, bool $recursive = false): void | ||
{ | ||
foreach ($files as $file) { | ||
if ($recursive && Filesystem\is_directory($file) && !Filesystem\is_link($file)) { | ||
change_permissions(new FilesystemIterator($file), $permission, true); | ||
} | ||
|
||
[$success, $error] = Internal\box(static fn(): bool => chmod($file, $permission)); | ||
if (!$success) { | ||
throw new Exception\RuntimeException(Str\format( | ||
'Failed to change permissions for file "%s": %s', | ||
$file, | ||
$error ?? 'internal error.', | ||
)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem; | ||
|
||
use Psl; | ||
|
||
/** | ||
* Change the group ownership of $filename. | ||
* | ||
* @param bool $recursive Whether change the group ownership recursively or not. | ||
* | ||
* @throws Exception\RuntimeException If unable to change the group ownership for $filename. | ||
* @throws Psl\Exception\InvariantViolationException If $filename does not exist. | ||
*/ | ||
function change_group(string $filename, int $group, bool $recursive = false): void | ||
{ | ||
Psl\invariant(exists($filename), '$filename does not exists.'); | ||
|
||
Internal\change_owner([$filename], $group, $recursive); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem; | ||
|
||
use Psl; | ||
|
||
/** | ||
* Change the owner of $filename. | ||
* | ||
* @param bool $recursive Whether change the owner recursively or not. | ||
* | ||
* @throws Exception\RuntimeException If unable to change the ownership for $filename. | ||
* @throws Psl\Exception\InvariantViolationException If $filename does not exist. | ||
*/ | ||
function change_owner(string $filename, int $user, bool $recursive = false): void | ||
{ | ||
Psl\invariant(exists($filename), '$filename does not exist.'); | ||
|
||
Internal\change_owner([$filename], $user, $recursive); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem; | ||
|
||
use Psl; | ||
|
||
/** | ||
* Changes mode permission of $filename. | ||
* | ||
* @param bool $recursive Whether change the mode recursively or not. | ||
* | ||
* @throws Exception\RuntimeException If unable to change the mode for the given $filename. | ||
* @throws Psl\Exception\InvariantViolationException If $filename does not exists. | ||
*/ | ||
function change_permissions(string $filename, int $permissions, bool $recursive = false): void | ||
{ | ||
Psl\invariant(exists($filename), '$filename does not exist.'); | ||
|
||
Internal\change_permissions([$filename], $permissions, $recursive); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem; | ||
|
||
use Psl; | ||
use Psl\Internal; | ||
use Psl\Str; | ||
|
||
use function fclose; | ||
use function fopen; | ||
use function stream_copy_to_stream; | ||
|
||
/** | ||
* Change the group ownership of $filename. | ||
* | ||
* | ||
* @throws Exception\RuntimeException If unable to change the group ownership for $filename. | ||
* @throws Psl\Exception\InvariantViolationException If $source does not exist or is not readable. | ||
*/ | ||
function copy(string $source, string $destination, bool $overwrite = false): void | ||
{ | ||
Psl\invariant(is_file($source) && is_readable($source), '$source does not exist or is not readable.'); | ||
|
||
if (!$overwrite && is_file($destination)) { | ||
return; | ||
} | ||
|
||
/** | ||
* @psalm-suppress InvalidArgument - callable is not pure.. | ||
*/ | ||
$source_stream = Internal\suppress(static fn() => fopen($source, 'rb')); | ||
if (false === $source_stream) { | ||
throw new Exception\RuntimeException('Failed to open $source file for reading'); | ||
} | ||
|
||
/** | ||
* @psalm-suppress InvalidArgument - callable is not pure.. | ||
*/ | ||
$destination_stream = Internal\suppress(static fn() => fopen($destination, 'wb')); | ||
if (false === $destination_stream) { | ||
throw new Exception\RuntimeException('Failed to open $destination file for writing.'); | ||
} | ||
|
||
$copied_bytes = stream_copy_to_stream($source_stream, $destination_stream); | ||
fclose($source_stream); | ||
fclose($destination_stream); | ||
|
||
$total_bytes = file_size($source); | ||
|
||
// preserve executable permission bits | ||
change_permissions( | ||
$destination, | ||
get_permissions($destination) | (get_permissions($source) & 0111) | ||
); | ||
|
||
if ($copied_bytes !== $total_bytes) { | ||
throw new Exception\RuntimeException(Str\format( | ||
'Failed to copy the whole content of "%s" to "%s" ( %g of %g bytes copied ).', | ||
$source, | ||
$destination, | ||
$copied_bytes, | ||
$total_bytes | ||
)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem; | ||
|
||
use Psl\Internal; | ||
use Psl\Str; | ||
|
||
use function mkdir; | ||
|
||
/** | ||
* Create the directory specified by $directory. | ||
* | ||
* @throws Exception\RuntimeException If unable to create the directory. | ||
*/ | ||
function create_directory(string $directory, int $permissions = 0777): void | ||
{ | ||
[$result, $error_message] = Internal\box( | ||
static fn() => mkdir($directory, $permissions, true) | ||
); | ||
|
||
if (false === $result && !is_directory($directory)) { | ||
throw new Exception\RuntimeException(Str\format( | ||
'Failed to create directory "%s": %s.', | ||
$directory, | ||
$error_message ?? 'internal error' | ||
)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Psl\Filesystem; | ||
|
||
use Psl\Internal; | ||
use Psl\Str; | ||
|
||
use function touch; | ||
|
||
/** | ||
* Create the file specified by $filename. | ||
* | ||
* @param int|null $time The touch time as a Unix timestamp, | ||
* If not supplied the current system time is used. | ||
* | ||
* @param int|null $access_time The access time as a Unix timestamp, | ||
* If not supplied the current system time is used. | ||
* | ||
* @throws Exception\RuntimeException If unable to create the file. | ||
*/ | ||
function create_file(string $filename, ?int $time = null, ?int $access_time = null): void | ||
{ | ||
if (null === $access_time && null === $time) { | ||
$fun = static fn(): bool => touch($filename); | ||
} elseif (null === $access_time) { | ||
$fun = static fn(): bool => touch($filename, $time); | ||
} else { | ||
$fun = static fn(): bool => touch($filename, $time ?? $access_time, $access_time); | ||
} | ||
|
||
[$result, $error_message] = Internal\box($fun); | ||
if (false === $result && !is_file($filename)) { | ||
throw new Exception\RuntimeException(Str\format( | ||
'Failed to create file "%s": %s.', | ||
$filename, | ||
$error_message ?? 'internal error' | ||
)); | ||
} | ||
} |
Oops, something went wrong.