fix relative paths resolver, add comments

This commit is contained in:
yggverse 2024-06-25 23:25:32 +03:00
parent 88cde4a0d8
commit 1d6f24c4ed
2 changed files with 85 additions and 46 deletions

View file

@ -243,7 +243,7 @@ class Cli
// Absolute option skipped, make local path relative // Absolute option skipped, make local path relative
if (!$this->option->absolute) if (!$this->option->absolute)
{ {
$local = Filesystem::getFilenameRelativeToDirname( $local = $this->filesystem->getFilenameRelativeToDirname(
$local, $local,
dirname( dirname(
$filename $filename

View file

@ -59,11 +59,22 @@ class Filesystem
} }
} }
/*
* Return --target realpath
*
* Currently not in use.
*/
public function getFilepath(): string public function getFilepath(): string
{ {
return $this->_filepath; return $this->_filepath;
} }
/*
* Build local filepath from \Yggverse\Net\Address
*
* Return absolute filename using --target defined
* Method doesn't check result location for exist.
*/
public function getFilenameFromNetAddress( public function getFilenameFromNetAddress(
\Yggverse\Net\Address $address, \Yggverse\Net\Address $address,
?string $index = null ?string $index = null
@ -122,6 +133,15 @@ class Filesystem
return $filename; return $filename;
} }
/*
* Save data string to destination.
*
* This method also builds recursive directory path
* and overwrites existing files (data) on exist.
*
* $filename must start from --target defined
* $data is plain gemtext or binary (media) string
*/
public function save( public function save(
string $filename, string $filename,
string $data string $data
@ -130,7 +150,11 @@ class Filesystem
if (!str_starts_with($filename, $this->_filepath)) if (!str_starts_with($filename, $this->_filepath))
{ {
throw new \Exception( throw new \Exception(
_('Target filename out of storage location') sprintf(
_('Filename "%s" out of filesystem root "%s"'),
$filename,
$this->_filepath
)
); );
} }
@ -175,69 +199,84 @@ class Filesystem
); );
} }
// Helpers /*
public static function getFilenameRelativeToDirname( * Build relative $filename path to given $dirname
*
* Method does not and must not check location for exist
* $filename and $dirname must contain --target defined.
*
* This implementation compatible with --external option
* resulting path get format: ../domain.com/path/to/file
*/
public function getFilenameRelativeToDirname(
string $filename, string $filename,
string $dirname string $dirname
): string ): string
{ {
// Validate paths // Require absolute $filename
if (empty($filename)) if (!str_starts_with($filename, DIRECTORY_SEPARATOR))
{ {
throw new \Exception( throw new \Exception(
'Filename is could not be empty' 'Absolute filename required'
); );
} }
if (empty($dirname)) // Require absolute $dirname
if (!str_starts_with($dirname, DIRECTORY_SEPARATOR))
{ {
throw new \Exception( throw new \Exception(
'Dirname is could not be empty' 'Absolute dirname required'
); );
} }
if (str_starts_with($filename, $dirname)) // Require valid $filename root location
if (!str_starts_with($filename, $this->_filepath))
{ {
return ltrim( throw new \Exception(
str_replace( sprintf(
_('Filename "%s" out of filesystem root "%s"'),
$filename,
$this->_filepath
)
);
}
// Require valid $dirname root location
if (!str_starts_with($dirname, $this->_filepath))
{
throw new \Exception(
sprintf(
_('Dirname "%s" out of filesystem root "%s"'),
$dirname, $dirname,
DIRECTORY_SEPARATOR, $this->_filepath
$filename )
);
}
// Build path
return str_repeat( // iterate ../ up to the --target location
sprintf(
'..%s',
DIRECTORY_SEPARATOR
),
substr_count(
ltrim( // strip leading slash from $dirname
str_replace( // strip --target prefix from $dirname
$this->_filepath,
DIRECTORY_SEPARATOR,
$dirname
),
DIRECTORY_SEPARATOR
), ),
DIRECTORY_SEPARATOR DIRECTORY_SEPARATOR
); ) + 1
} ) . ltrim( // strip leading slash from $filename
str_replace( // strip --target prefix from $filename
$filepath = explode( $this->_filepath,
DIRECTORY_SEPARATOR,
dirname(
$filename
)
);
$segments = [];
foreach(
explode(
DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR,
$dirname $filename
) as $level => $directory) ),
{ DIRECTORY_SEPARATOR
if (isset($filepath[$level]) && $filepath[$level] == $directory)
{
continue;
}
$segments[] = '..';
}
$segments[] = basename(
$filename
);
return implode(
DIRECTORY_SEPARATOR,
$segments
); );
} }
} }