Skip to content

Commit

Permalink
Merge pull request #34 from pact-foundation/executable-installer
Browse files Browse the repository at this point in the history
refactor(2.0): Add ExecutableInstaller
  • Loading branch information
tienvx authored Apr 17, 2024
2 parents 5f3de63 + b116404 commit a69ede7
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 6 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,14 @@ jobs:
run: ./vendor/bin/phpunit --testsuite=Integration

unit:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
needs:
- php-cs-fixer
strategy:
matrix:
php: [8.1, 8.2, 8.3]
dependencies: [ 'lowest', 'highest' ]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
Expand All @@ -79,4 +80,4 @@ jobs:
run: |
composer global require php-coveralls/php-coveralls
php-coveralls --coverage_clover=clover.xml -v
if: ${{ github.event_name == 'push' && matrix.php == '8.1' && matrix.dependencies == 'highest' }}
if: ${{ github.event_name == 'push' && matrix.os == 'ubuntu-latest' && matrix.php == '8.1' && matrix.dependencies == 'highest' }}
33 changes: 33 additions & 0 deletions src/Installer/ExecutableInstaller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace LastCall\DownloadsPlugin\Installer;

use Composer\Installer\BinaryInstaller;
use Composer\IO\IOInterface;
use Composer\Util\Platform;
use Composer\Util\ProcessExecutor;
use LastCall\DownloadsPlugin\Composer\Package\ExtraDownloadInterface;

class ExecutableInstaller implements ExecutableInstallerInterface
{
public function __construct(private IOInterface $io)
{
}

public function install(ExtraDownloadInterface $extraDownload): void
{
foreach ($extraDownload->getExecutablePaths() as $path) {
if (Platform::isWindows() || Platform::isWindowsSubsystemForLinux()) {
$proxy = $path.'.bat';
if (file_exists($proxy)) {
$this->io->writeError(sprintf(' Skipped installation of bin %s.bat proxy for package %s: a .bat proxy was already installed', $path, $extraDownload->getName()));
} else {
$caller = BinaryInstaller::determineBinaryCaller($path);
file_put_contents($proxy, '@'.$caller.' "%~dp0'.ProcessExecutor::escape(basename($proxy, '.bat')).'" %*');
}
} else {
chmod($path, 0777 & ~umask());
}
}
}
}
10 changes: 10 additions & 0 deletions src/Installer/ExecutableInstallerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace LastCall\DownloadsPlugin\Installer;

use LastCall\DownloadsPlugin\Composer\Package\ExtraDownloadInterface;

interface ExecutableInstallerInterface
{
public function install(ExtraDownloadInterface $extraDownload): void;
}
6 changes: 3 additions & 3 deletions tests/Unit/Composer/Package/ExtraDownloadTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function testGetInstallPathWhenParentPackageIsInstalled(): void
$parent = new Package($parentName, 'any version', 'any pretty version');
$this->createExtraDownload($parent, $this->hash);
$this->assertSame(
realpath(__DIR__.'/../../../../vendor/composer/').'/../'.$parentName.'/'.$this->path,
realpath(__DIR__.'/../../../../vendor/composer/').'/../'.$parentName.\DIRECTORY_SEPARATOR.$this->path,
$this->extraDownload->getInstallPath()
);
}
Expand All @@ -79,8 +79,8 @@ public function testGetExecutablePathsWhenParentPackageIsInstalled(): void
$parent = new Package($parentName, 'any version', 'any pretty version');
$this->createExtraDownload($parent, $this->hash);
$this->assertSame([
realpath(__DIR__.'/../../../../vendor/composer/').'/../'.$parentName.'/file1',
realpath(__DIR__.'/../../../../vendor/composer/').'/../'.$parentName.'/path/to/file2',
realpath(__DIR__.'/../../../../vendor/composer/').'/../'.$parentName.\DIRECTORY_SEPARATOR.'file1',
realpath(__DIR__.'/../../../../vendor/composer/').'/../'.$parentName.\DIRECTORY_SEPARATOR.'path/to/file2',
], $this->extraDownload->getExecutablePaths());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function testConvertToAbsoluteWhenPackageIsInstalled(): void
->method('getName')
->willReturn($name);
$this->assertSame(
realpath(__DIR__.'/../../../../../vendor/composer/').'/../'.$name.'/'.$this->relative,
realpath(__DIR__.'/../../../../../vendor/composer/').'/../'.$name.\DIRECTORY_SEPARATOR.$this->relative,
$this->installPath->convertToAbsolute($this->relative)
);
}
Expand Down
88 changes: 88 additions & 0 deletions tests/Unit/Installer/ExecutableInstallerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace LastCall\DownloadsPlugin\Tests\Unit\Installer;

use Composer\IO\IOInterface;
use LastCall\DownloadsPlugin\Composer\Package\ExtraDownloadInterface;
use LastCall\DownloadsPlugin\Installer\ExecutableInstaller;
use LastCall\DownloadsPlugin\Installer\ExecutableInstallerInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use VirtualFileSystem\FileSystem;

class ExecutableInstallerTest extends TestCase
{
private ?FileSystem $fs = null;
private IOInterface|MockObject $io;
private ExtraDownloadInterface|MockObject $extraDownload;
private ExecutableInstallerInterface $installer;
private string $name = 'vendor/package-name:executable-file';
private array $executablePaths = [
false => '/path/to/files/file1',
true => '/path/to/files/other/path/to/file2',
];

protected function setUp(): void
{
$this->fs = new FileSystem();
$this->io = $this->createMock(IOInterface::class);
$this->extraDownload = $this->createMock(ExtraDownloadInterface::class);
$this->installer = new ExecutableInstaller($this->io);
$this->createDirectoryAndFiles();
}

protected function tearDown(): void
{
$this->fs = null;
}

public function testInstall(): void
{
$this->extraDownload
->expects($this->once())
->method('getExecutablePaths')
->willReturn(array_map(fn (string $path) => $this->fs->path($path), $this->executablePaths));
if (\PHP_OS_FAMILY === 'Windows') {
$this->extraDownload
->expects($this->once())
->method('getName')
->willReturn($this->name);
$this->io
->expects($this->once())
->method('writeError')
->with(' Skipped installation of bin '.$this->fs->path('/path/to/files/other/path/to/file2.bat').' proxy for package '.$this->name.': a .bat proxy was already installed');
}
$this->installer->install($this->extraDownload);
foreach ($this->executablePaths as $hasProxy => $path) {
if (\PHP_OS_FAMILY === 'Windows') {
$proxy = $path.'.bat';
if (!$hasProxy) {
$this->assertStringEqualsFile(
$this->fs->path($proxy),
'@php "%~dp0file1" %*'
);
}
} else {
$this->assertTrue(is_executable($this->fs->path($path)));
}
}
}

private function createDirectoryAndFiles(): void
{
foreach ($this->executablePaths as $hasProxy => $path) {
$this->fs->createDirectory(\dirname($path), true);
$content = implode(\PHP_EOL, [
'#!/usr/bin/env php',
'<?php',
"echo 'Hello from php file!';",
]);
$this->fs->createFile($path, $content);
chmod($this->fs->path($path), 0600);
if (\PHP_OS_FAMILY === 'Windows' && $hasProxy) {
$proxy = $path.'.bat';
$this->fs->createFile($proxy, 'proxy content');
}
}
}
}

0 comments on commit a69ede7

Please sign in to comment.