Skip to content

Commit

Permalink
Symlink improvement (#57)
Browse files Browse the repository at this point in the history
* build: upgrade dependencies

* build: upgrade dependencies to new versions

* test: satisfy mess detector

* ci: upgrade ci

* ci: remove scrutinizer

* test: create testbed for new functionality of #51

* feature: sync sym links
closes #51

* wip: symlink source uses real path
for #56

* feature: improve handling of symlinks
closes #56

* feature: do not mention skipped links

* tweak: split long line
  • Loading branch information
g105b authored Jul 7, 2023
1 parent 5764001 commit 5d1ee6a
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 53 deletions.
20 changes: 16 additions & 4 deletions src/Command/SyncCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,25 @@ private function performSymlinkSync(
$sync = new SymlinkSync($source, $destination);
$sync->exec();

$countDirectories = count($sync->getLinkedDirectoriesList());
$countFiles = count($sync->getLinkedFilesList());
$countSkipped = count($sync->getSkippedList());
$countFailed = count($sync->getFailedList());

if($countDirectories + $countFiles + $countFailed === 0
&& $countSkipped > 0) {
return;
}

if(!$arguments->contains("silent")) {
$this->write("Linked: directories ");
$this->write((string)count($sync->getLinkedDirectoriesList()));
$this->write("Linked: directories ");
$this->write((string)$countDirectories);
$this->write(", files ");
$this->write((string)count($sync->getLinkedFilesList()));
$this->write((string)$countFiles);
$this->write(", skipped ");
$this->write((string)$countSkipped);
$this->write(", failed ");
$this->write((string)count($sync->getFailedList()));
$this->write((string)$countFailed);
$this->writeLine(".");
}
}
Expand Down
23 changes: 21 additions & 2 deletions src/SymlinkSync.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,26 @@ public function exec(int $settings = 0):void {
$this->skipped = [];
$this->failed = [];

$targetSource = realpath($this->source);

if(is_link($this->destination)) {
$linkTarget = readlink($this->destination);

if($targetSource !== $linkTarget) {
unlink($this->destination);
}
else {
array_push($this->skipped, $this->destination);
return;
}
}

if(is_dir($this->source)) {
if(!is_dir(dirname($this->destination))) {
mkdir(dirname($this->destination), recursive: true);
}

if(symlink($this->source, $this->destination)) {
if(symlink($targetSource, $this->destination)) {
array_push($this->linkedDirectories, $this->destination);
}
else {
Expand All @@ -35,7 +49,7 @@ public function exec(int $settings = 0):void {
mkdir(dirname($this->destination), recursive: true);
}

if(symlink($this->source, $this->destination)) {
if(symlink($targetSource, $this->destination)) {
array_push($this->linkedFiles, $this->destination);
}
else {
Expand Down Expand Up @@ -66,4 +80,9 @@ public function getCombinedLinkedList():array {
public function getFailedList():array {
return $this->failed;
}

/** @return array<string> */
public function getSkippedList():array {
return $this->skipped;
}
}
47 changes: 47 additions & 0 deletions test/phpunit/SymlinkSyncTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,51 @@ public function testSymLink_file():void {
$linkedAll = $sut->getCombinedLinkedList();
self::assertCount(1, $linkedAll);
}

public function testSymLink_changeDirPath():void {
$baseDir = $this->getRandomTmp();
$sourceDirOld = "$baseDir/data/upload-old";
$sourceDirNew = "$baseDir/data/upload-new";
$destDir = "$baseDir/www/data/upload";

$relativeFilePath = "subdir1/subdir2/example.file";
$filePath = "$sourceDirOld/$relativeFilePath";
if(!is_dir(dirname($filePath))) {
mkdir(dirname($filePath), recursive: true);
}
file_put_contents($filePath, "Hello, Sync!");

$sut = new SymlinkSync($sourceDirOld, $destDir);
$sut->exec();

self::assertFileExists("$destDir/$relativeFilePath");
rename($sourceDirOld, $sourceDirNew);
self::assertFileDoesNotExist("$destDir/$relativeFilePath");

$sut = new SymlinkSync($sourceDirNew, $destDir);
$sut->exec();
self::assertFileExists("$destDir/$relativeFilePath");
}

public function testSymLink_multipleCallsToExec():void {
$baseDir = $this->getRandomTmp();
$sourceDir = "$baseDir/data/upload";
$destDir = "$baseDir/www/data/upload";

$filePath = "$sourceDir/subdir1/subdir2/example.file";
if(!is_dir(dirname($filePath))) {
mkdir(dirname($filePath), recursive: true);
}
file_put_contents($filePath, "Hello, Sync!");

$sut = new SymlinkSync($sourceDir, $destDir);
$sut->exec();
self::assertCount(1, $sut->getCombinedLinkedList());
self::assertCount(0, $sut->getFailedList());
self::assertCount(0, $sut->getSkippedList());
$sut->exec();
self::assertCount(0, $sut->getLinkedFilesList());
self::assertCount(0, $sut->getFailedList());
self::assertCount(1, $sut->getSkippedList());
}
}
67 changes: 20 additions & 47 deletions test/phpunit/SyncTestCase.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php
namespace Gt\Sync\Test;
use Exception;
use FilesystemIterator;
use PHPUnit\Framework\TestCase;
use RecursiveDirectoryIterator;
Expand All @@ -14,29 +15,7 @@ public function tearDown():void {
return;
}

$directory = new RecursiveDirectoryIterator(
$baseTmp,
FilesystemIterator::KEY_AS_PATHNAME
| FilesystemIterator::CURRENT_AS_FILEINFO
);
$iterator = new RecursiveIteratorIterator(
$directory,
RecursiveIteratorIterator::CHILD_FIRST
);
foreach($iterator as $filePath => $file) {
/** @var $file SplFileInfo */
if($file->getFilename() === "."
|| $file->getFilename() === "..") {
continue;
}

if($file->isDir()) {
rmdir($filePath);
}
else {
unlink($filePath);
}
}
$this->recursiveDeleteDirectory($baseTmp);
}

protected function getRandomTmp():string {
Expand Down Expand Up @@ -116,35 +95,29 @@ protected function getRandomSubdirectoryFromDirectory(string $dir):string {
}

protected function recursiveDeleteDirectory(string $dir):void {
$directory = new RecursiveDirectoryIterator(
$dir,
RecursiveDirectoryIterator::SKIP_DOTS
| RecursiveDirectoryIterator::KEY_AS_PATHNAME
| RecursiveDirectoryIterator::CURRENT_AS_FILEINFO
);
$iterator = new RecursiveIteratorIterator(
$directory,
RecursiveIteratorIterator::CHILD_FIRST
);

foreach($iterator as $pathName => $file) {
/** @var $file SplFileInfo */
if($file->getFilename() === "."
|| $file->getFilename() === "..") {
continue;
}
if (!is_dir($dir)) {
throw new Exception('Invalid directory to delete: $dir');
}

if(is_dir($pathName)) {
rmdir($pathName);
$directory = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO);
$iterator = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::CHILD_FIRST);

/**
* @var string $pathName
* @var SplFileInfo $fileInfo
*/
foreach ($iterator as $pathName => $fileInfo) {
if($fileInfo->isLink() || $fileInfo->isFile()) {
if(!unlink($pathName)) {
throw new Exception('Failed to delete file: ' . $pathName);
}
}
else {
unlink($pathName);
if(!rmdir($pathName)) {
throw new Exception('Failed to delete directory: ' . $pathName);
}
}
}

if(is_dir($dir)) {
rmdir($dir);
}
}

protected static function assertDirectoryContentsIdentical(
Expand Down

0 comments on commit 5d1ee6a

Please sign in to comment.