Skip to content

Commit ddf83da

Browse files
authored
Support absolute path in --composer-json (#98)
1 parent 48167b9 commit ddf83da

File tree

8 files changed

+137
-105
lines changed

8 files changed

+137
-105
lines changed

bin/composer-dependency-analyser

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ $stopwatch = new Stopwatch();
3434

3535
try {
3636
$options = $initializer->initCliOptions($cwd, $argv);
37-
$composerJson = $initializer->initComposerJson($cwd, $options);
37+
$composerJson = $initializer->initComposerJson($options);
3838
$initializer->initComposerAutoloader($composerJson);
3939
$configuration = $initializer->initConfiguration($options, $composerJson);
4040
$classLoaders = $initializer->initComposerClassLoaders();

src/Analyser.php

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,15 @@
2121
use function array_filter;
2222
use function array_key_exists;
2323
use function array_keys;
24-
use function array_pop;
25-
use function end;
2624
use function explode;
2725
use function file_get_contents;
2826
use function get_declared_classes;
2927
use function get_declared_interfaces;
3028
use function get_declared_traits;
3129
use function get_defined_constants;
3230
use function get_defined_functions;
33-
use function implode;
3431
use function in_array;
3532
use function is_file;
36-
use function preg_split;
3733
use function str_replace;
3834
use function strlen;
3935
use function strpos;
@@ -407,33 +403,7 @@ private function normalizePath(string $filePath): string
407403
$filePath = substr($filePath, strlen($pharPrefix));
408404
}
409405

410-
return $this->doNormalizePath($filePath);
411-
}
412-
413-
/**
414-
* Based on Nette\Utils\FileSystem::normalizePath
415-
*
416-
* @license https://github.com/nette/utils/blob/v4.0.4/license.md
417-
*/
418-
private function doNormalizePath(string $path): string
419-
{
420-
/** @var list<string> $parts */
421-
$parts = $path === ''
422-
? []
423-
: preg_split('~[/\\\\]+~', $path);
424-
$result = [];
425-
426-
foreach ($parts as $part) {
427-
if ($part === '..' && $result !== [] && end($result) !== '..' && end($result) !== '') {
428-
array_pop($result);
429-
} elseif ($part !== '.') {
430-
$result[] = $part;
431-
}
432-
}
433-
434-
return $result === ['']
435-
? DIRECTORY_SEPARATOR
436-
: implode(DIRECTORY_SEPARATOR, $result);
406+
return Path::normalize($filePath);
437407
}
438408

439409
/**

src/ComposerJson.php

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,10 @@
1313
use function file_get_contents;
1414
use function glob;
1515
use function is_array;
16-
use function is_dir;
1716
use function is_file;
1817
use function json_decode;
1918
use function json_last_error;
2019
use function json_last_error_msg;
21-
use function preg_match;
22-
use function realpath;
23-
use function rtrim;
2420
use function strpos;
2521
use const ARRAY_FILTER_USE_KEY;
2622
use const JSON_ERROR_NONE;
@@ -54,7 +50,9 @@ class ComposerJson
5450
* @throws InvalidPathException
5551
* @throws InvalidConfigException
5652
*/
57-
public function __construct(string $composerJsonPath)
53+
public function __construct(
54+
string $composerJsonPath
55+
)
5856
{
5957
$basePath = dirname($composerJsonPath);
6058

@@ -132,17 +130,7 @@ private function extractAutoloadPaths(string $basePath, array $autoload, bool $i
132130
*/
133131
private function realpath(string $path): string
134132
{
135-
if (!is_file($path) && !is_dir($path)) {
136-
throw new InvalidPathException("Path from composer.json '$path' is not a file not a directory.");
137-
}
138-
139-
$realPath = realpath($path);
140-
141-
if ($realPath === false) {
142-
throw new InvalidPathException("Path from composer.json '$path' is invalid: unable to realpath");
143-
}
144-
145-
return $realPath;
133+
return Path::realpath($path);
146134
}
147135

148136
/**
@@ -192,23 +180,11 @@ private function parseComposerJson(string $composerJsonPath): array
192180

193181
private function resolveComposerAutoloadPath(string $basePath, string $vendorDir): string
194182
{
195-
$vendorDir = rtrim($vendorDir, '/');
196-
197-
if ($this->isAbsolutePath($vendorDir)) {
198-
return $vendorDir . '/autoload.php';
183+
if (Path::isAbsolute($vendorDir)) {
184+
return Path::normalize($vendorDir . '/autoload.php');
199185
}
200186

201-
return $basePath . '/' . $vendorDir . '/autoload.php';
202-
}
203-
204-
/**
205-
* Based on Nette\Utils\FileSystem::isAbsolute
206-
*
207-
* @license https://github.com/nette/utils/blob/v4.0.4/license.md
208-
*/
209-
private function isAbsolutePath(string $vendorDir): bool
210-
{
211-
return (bool) preg_match('#([a-z]:)?[/\\\\]|[a-z][a-z0-9+.-]*://#Ai', $vendorDir);
187+
return Path::normalize($basePath . '/' . $vendorDir . '/autoload.php');
212188
}
213189

214190
}

src/Config/Configuration.php

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
use ShipMonk\ComposerDependencyAnalyser\Config\Ignore\IgnoreList;
66
use ShipMonk\ComposerDependencyAnalyser\Exception\InvalidConfigException;
77
use ShipMonk\ComposerDependencyAnalyser\Exception\InvalidPathException;
8+
use ShipMonk\ComposerDependencyAnalyser\Path;
89
use function array_merge;
910
use function in_array;
10-
use function is_dir;
11-
use function is_file;
1211
use function preg_match;
13-
use function realpath;
1412
use function strpos;
1513

1614
class Configuration
@@ -153,7 +151,7 @@ public function addForceUsedSymbols(array $symbols): self
153151
*/
154152
public function addPathToScan(string $path, bool $isDev): self
155153
{
156-
$this->pathsToScan[] = new PathToScan($this->realpath($path), $isDev);
154+
$this->pathsToScan[] = new PathToScan(Path::realpath($path), $isDev);
157155
return $this;
158156
}
159157

@@ -172,26 +170,26 @@ public function addPathsToScan(array $paths, bool $isDev): self
172170
}
173171

174172
/**
173+
* @param list<string> $paths
175174
* @return $this
176175
* @throws InvalidPathException
177176
*/
178-
public function addPathToExclude(string $path): self
177+
public function addPathsToExclude(array $paths): self
179178
{
180-
$this->pathsToExclude[] = $this->realpath($path);
179+
foreach ($paths as $path) {
180+
$this->addPathToExclude($path);
181+
}
182+
181183
return $this;
182184
}
183185

184186
/**
185-
* @param list<string> $paths
186187
* @return $this
187188
* @throws InvalidPathException
188189
*/
189-
public function addPathsToExclude(array $paths): self
190+
public function addPathToExclude(string $path): self
190191
{
191-
foreach ($paths as $path) {
192-
$this->addPathToExclude($path);
193-
}
194-
192+
$this->pathsToExclude[] = Path::realpath($path);
195193
return $this;
196194
}
197195

@@ -205,7 +203,7 @@ public function ignoreErrorsOnPath(string $path, array $errorTypes): self
205203
{
206204
$this->checkAllowedErrorTypeForPathIgnore($errorTypes);
207205

208-
$realpath = $this->realpath($path);
206+
$realpath = Path::realpath($path);
209207

210208
$previousErrorTypes = $this->ignoredErrorsOnPath[$realpath] ?? [];
211209
$this->ignoredErrorsOnPath[$realpath] = array_merge($previousErrorTypes, $errorTypes);
@@ -270,7 +268,7 @@ public function ignoreErrorsOnPackageAndPath(string $packageName, string $path,
270268
$this->checkAllowedErrorTypeForPathIgnore($errorTypes);
271269
$this->checkAllowedErrorTypeForPackageIgnore($errorTypes);
272270

273-
$realpath = $this->realpath($path);
271+
$realpath = Path::realpath($path);
274272

275273
$previousErrorTypes = $this->ignoredErrorsOnPackageAndPath[$packageName][$realpath] ?? [];
276274
$this->ignoredErrorsOnPackageAndPath[$packageName][$realpath] = array_merge($previousErrorTypes, $errorTypes);
@@ -402,24 +400,6 @@ private function isFilepathWithinPath(string $filePath, string $path): bool
402400
return strpos($filePath, $path) === 0;
403401
}
404402

405-
/**
406-
* @throws InvalidPathException
407-
*/
408-
private function realpath(string $filePath): string
409-
{
410-
if (!is_file($filePath) && !is_dir($filePath)) {
411-
throw new InvalidPathException("'$filePath' is not a file nor directory");
412-
}
413-
414-
$realPath = realpath($filePath);
415-
416-
if ($realPath === false) {
417-
throw new InvalidPathException("Unable to realpath '$filePath'");
418-
}
419-
420-
return $realPath;
421-
}
422-
423403
/**
424404
* @throws InvalidConfigException
425405
*/

src/Initializer.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public function initConfiguration(
7272
): Configuration
7373
{
7474
if ($options->config !== null) {
75-
$configPath = $this->cwd . '/' . $options->config;
75+
$configPath = Path::resolve($this->cwd, $options->config);
7676

7777
if (!is_file($configPath)) {
7878
throw new InvalidConfigException("Invalid config path given, {$configPath} is not a file.");
@@ -144,11 +144,11 @@ public function initConfiguration(
144144
* @throws InvalidPathException
145145
* @throws InvalidConfigException
146146
*/
147-
public function initComposerJson(string $cwd, CliOptions $options): ComposerJson
147+
public function initComposerJson(CliOptions $options): ComposerJson
148148
{
149149
$composerJsonPath = $options->composerJson !== null
150-
? ($cwd . '/' . $options->composerJson)
151-
: ($cwd . '/composer.json');
150+
? Path::resolve($this->cwd, $options->composerJson)
151+
: Path::normalize($this->cwd . '/composer.json');
152152

153153
return new ComposerJson($composerJsonPath);
154154
}

src/Path.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace ShipMonk\ComposerDependencyAnalyser;
4+
5+
use ShipMonk\ComposerDependencyAnalyser\Exception\InvalidPathException;
6+
use function array_pop;
7+
use function end;
8+
use function implode;
9+
use function is_dir;
10+
use function is_file;
11+
use function preg_match;
12+
use function preg_split;
13+
use function realpath;
14+
use const DIRECTORY_SEPARATOR;
15+
16+
/**
17+
* Inspired by Nette\Utils\FileSystem
18+
*
19+
* @license https://github.com/nette/utils/blob/v4.0.4/license.md
20+
*/
21+
class Path
22+
{
23+
24+
/**
25+
* @throws InvalidPathException
26+
*/
27+
public static function realpath(string $path): string
28+
{
29+
if (!is_file($path) && !is_dir($path)) {
30+
throw new InvalidPathException("'$path' is not a file nor directory");
31+
}
32+
33+
$realPath = realpath($path);
34+
35+
if ($realPath === false) {
36+
throw new InvalidPathException("Unable to realpath '$path'");
37+
}
38+
39+
return $realPath;
40+
}
41+
42+
public static function resolve(string $basePath, string $path): string
43+
{
44+
return self::isAbsolute($path)
45+
? self::normalize($path)
46+
: self::normalize($basePath . '/' . $path);
47+
}
48+
49+
public static function isAbsolute(string $vendorDir): bool
50+
{
51+
return (bool) preg_match('#([a-z]:)?[/\\\\]|[a-z][a-z0-9+.-]*://#Ai', $vendorDir);
52+
}
53+
54+
public static function normalize(string $path): string
55+
{
56+
/** @var list<string> $parts */
57+
$parts = $path === ''
58+
? []
59+
: preg_split('~[/\\\\]+~', $path);
60+
$result = [];
61+
62+
foreach ($parts as $part) {
63+
if ($part === '..' && $result !== [] && end($result) !== '..' && end($result) !== '') {
64+
array_pop($result);
65+
} elseif ($part !== '.') {
66+
$result[] = $part;
67+
}
68+
}
69+
70+
return $result === ['']
71+
? DIRECTORY_SEPARATOR
72+
: implode(DIRECTORY_SEPARATOR, $result);
73+
}
74+
75+
}

tests/ComposerJsonTest.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
use function json_encode;
1010
use function mkdir;
1111
use function realpath;
12+
use function strtr;
1213
use function sys_get_temp_dir;
14+
use const DIRECTORY_SEPARATOR;
1315

1416
class ComposerJsonTest extends TestCase
1517
{
@@ -20,7 +22,7 @@ public function testComposerJson(): void
2022
$composerJson = new ComposerJson($composerJsonPath);
2123

2224
self::assertSame(
23-
dirname($composerJsonPath) . '/custom-vendor/autoload.php',
25+
strtr(dirname($composerJsonPath) . '/custom-vendor/autoload.php', '/', DIRECTORY_SEPARATOR),
2426
$composerJson->composerAutoloadPath
2527
);
2628

@@ -57,7 +59,7 @@ public function testAbsoluteCustomVendorDir(): void
5759
$composerJson = new ComposerJson($generatedComposerJson);
5860

5961
self::assertSame(
60-
sys_get_temp_dir() . '/autoload.php',
62+
strtr(sys_get_temp_dir() . '/autoload.php', '/', DIRECTORY_SEPARATOR),
6163
$composerJson->composerAutoloadPath
6264
);
6365
}
@@ -85,7 +87,7 @@ public function testUseVendorBesideGivenComposerJsonNotCwdOne(): void
8587
$composerJson = new ComposerJson($generatedComposerJson);
8688

8789
self::assertSame(
88-
sys_get_temp_dir() . '/vendor-beside/data/autoload.php',
90+
strtr(sys_get_temp_dir() . '/vendor-beside/data/autoload.php', '/', DIRECTORY_SEPARATOR),
8991
$composerJson->composerAutoloadPath
9092
);
9193
}

0 commit comments

Comments
 (0)