Skip to content

Commit 9c7c1c5

Browse files
authored
Enhance usability of the command (#40)
- Make prefix argument an optional option which defaults to a random prefix - Add prefix to all the files found in the current working directory when no path given - Throw an error when the output directory already exists and is not writeable - Add a force option for non-interactive mode to be able to add prefixes although the output directory already exists and is not empty (without the option the process is interrupted) - Make the errors a bit more readable by adding a color to the file paths - Mock the filesystem in the command unit tests to control the calls being made and ensure no `remove()` is called by mistake and change the output dir to something different than the project dir... cost me a few project deletion
1 parent 25a5dcd commit 9c7c1c5

File tree

5 files changed

+250
-73
lines changed

5 files changed

+250
-73
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ help:
1515

1616
build: ## Build the PHAR
1717
build: bin/php-scoper
18+
rm -rf build
1819
rm composer.lock
1920
composer install --no-dev --prefer-dist --classmap-authoritative
21+
php -d zend.enable_gc=0 bin/php-scoper add-prefix --force
2022
php -d zend.enable_gc=0 $(BOX) build
23+
mv build/bin/php-scoper.phar bin/
2124
composer install
2225

2326

box.json.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"output": "bin/php-scoper.phar",
33
"main": "bin/php-scoper",
4+
"base-path": "build",
45
"directories": [
56
"src"
67
],

src/Console/Command/AddPrefixCommand.php

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@
2929

3030
final class AddPrefixCommand extends Command
3131
{
32-
/** @internal */
33-
const PREFIX_ARG = 'prefix';
3432
/** @internal */
3533
const PATH_ARG = 'paths';
3634
/** @internal */
37-
const OUTPUT_DIR = 'output-dir';
35+
const PREFIX_OPT = 'prefix';
36+
/** @internal */
37+
const OUTPUT_DIR_OPT = 'output-dir';
38+
/** @internal */
39+
const FORCE_OPT = 'force';
3840

3941
private $fileSystem;
4042
private $handle;
@@ -58,23 +60,30 @@ protected function configure()
5860
$this
5961
->setName('add-prefix')
6062
->setDescription('Goes through all the PHP files found in the given paths to apply the given prefix to namespaces & FQNs.')
61-
->addArgument(
62-
self::PREFIX_ARG,
63-
InputArgument::REQUIRED,
64-
'The namespace prefix to add'
65-
)
6663
->addArgument(
6764
self::PATH_ARG,
68-
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
65+
InputArgument::IS_ARRAY,
6966
'The path(s) to process.'
7067
)
7168
->addOption(
72-
self::OUTPUT_DIR,
69+
self::PREFIX_OPT,
70+
'p',
71+
InputOption::VALUE_REQUIRED,
72+
'The namespace prefix to add'
73+
)
74+
->addOption(
75+
self::OUTPUT_DIR_OPT,
7376
'o',
7477
InputOption::VALUE_REQUIRED,
7578
'The output directory in which the prefixed code will be dumped.',
7679
'build'
7780
)
81+
->addOption(
82+
self::FORCE_OPT,
83+
'f',
84+
InputOption::VALUE_NONE,
85+
'Deletes any existing content in the output directory without any warning'
86+
)
7887
;
7988
}
8089

@@ -95,15 +104,15 @@ protected function execute(InputInterface $input, OutputInterface $output)
95104
);
96105

97106
$logger->outputScopingStart(
98-
$input->getArgument(self::PREFIX_ARG),
107+
$input->getOption(self::PREFIX_OPT),
99108
$input->getArgument(self::PATH_ARG)
100109
);
101110

102111
try {
103112
$this->handle->__invoke(
104-
$input->getArgument(self::PREFIX_ARG),
113+
$input->getOption(self::PREFIX_OPT),
105114
$input->getArgument(self::PATH_ARG),
106-
$input->getOption(self::OUTPUT_DIR),
115+
$input->getOption(self::OUTPUT_DIR_OPT),
107116
$logger
108117
);
109118
} catch (Throwable $throwable) {
@@ -117,7 +126,13 @@ protected function execute(InputInterface $input, OutputInterface $output)
117126

118127
private function validatePrefix(InputInterface $input)
119128
{
120-
$prefix = trim($input->getArgument(self::PREFIX_ARG));
129+
$prefix = $input->getOption(self::PREFIX_OPT);
130+
131+
if (null === $prefix) {
132+
$prefix = uniqid('PhpScoper');
133+
} else {
134+
$prefix = trim($prefix);
135+
}
121136

122137
if (1 === preg_match('/(?<prefix>.*?)\\\\*$/', $prefix, $matches)) {
123138
$prefix = $matches['prefix'];
@@ -127,12 +142,12 @@ private function validatePrefix(InputInterface $input)
127142
throw new RuntimeException(
128143
sprintf(
129144
'Expected "%s" argument to be a non empty string.',
130-
self::PREFIX_ARG
145+
self::PREFIX_OPT
131146
)
132147
);
133148
}
134149

135-
$input->setArgument(self::PREFIX_ARG, $prefix);
150+
$input->setOption(self::PREFIX_OPT, $prefix);
136151
}
137152

138153
private function validatePaths(InputInterface $input)
@@ -151,28 +166,47 @@ function (string $path) use ($cwd, $fileSystem) {
151166
$input->getArgument(self::PATH_ARG)
152167
);
153168

169+
if (0 === count($paths)) {
170+
$paths[] = $cwd;
171+
}
172+
154173
$input->setArgument(self::PATH_ARG, $paths);
155174
}
156175

157176
private function validateOutputDir(InputInterface $input, OutputStyle $io)
158177
{
159-
$outputDir = $input->getOption(self::OUTPUT_DIR);
178+
$outputDir = $input->getOption(self::OUTPUT_DIR_OPT);
160179

161180
if (false === $this->fileSystem->isAbsolutePath($outputDir)) {
162181
$outputDir = getcwd().DIRECTORY_SEPARATOR.$outputDir;
163182
}
164183

165-
$input->setOption(self::OUTPUT_DIR, $outputDir);
184+
$input->setOption(self::OUTPUT_DIR_OPT, $outputDir);
166185

167186
if (false === $this->fileSystem->exists($outputDir)) {
168187
return;
169188
}
170189

190+
if (false === is_writable($outputDir)) {
191+
throw new RuntimeException(
192+
sprintf(
193+
'Expected "<comment>%s</comment>" to be writeable.',
194+
$outputDir
195+
)
196+
);
197+
}
198+
199+
if ($input->getOption(self::FORCE_OPT)) {
200+
$this->fileSystem->remove($outputDir);
201+
202+
return;
203+
}
204+
171205
if (false === is_dir($outputDir)) {
172206
$canDeleteFile = $io->confirm(
173207
sprintf(
174-
'Expected "%s" to be a directory but found a file instead. It will be removed, do you wish '
175-
.'to proceed?',
208+
'Expected "<comment>%s</comment>" to be a directory but found a file instead. It will be '
209+
.'removed, do you wish to proceed?',
176210
$outputDir
177211
),
178212
false
@@ -183,15 +217,21 @@ private function validateOutputDir(InputInterface $input, OutputStyle $io)
183217
}
184218

185219
$this->fileSystem->remove($outputDir);
186-
}
187-
188-
if (false === is_writable($outputDir)) {
189-
throw new RuntimeException(
220+
} else {
221+
$canDeleteFile = $io->confirm(
190222
sprintf(
191-
'Expected "%s" to be writeable.',
223+
'The output directory "<comment>%s</comment>" already exists. Continuing will erase its'
224+
.' content, do you wish to proceed?',
192225
$outputDir
193-
)
226+
),
227+
false
194228
);
229+
230+
if (false === $canDeleteFile) {
231+
return;
232+
}
233+
234+
$this->fileSystem->remove($outputDir);
195235
}
196236
}
197237
}

tests/Console/Command/AddPrefixCommandIntegrationTest.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,13 @@ protected function setUp()
5757
return;
5858
}
5959

60-
$this->cwd = getcwd();
61-
6260
$application = create_application();
6361
$application->setAutoExit(false);
6462
$application->setCatchExceptions(false);
6563

6664
$this->appTester = new ApplicationTester($application);
6765

66+
$this->cwd = getcwd();
6867
$this->tmp = make_tmp_dir('scoper', __CLASS__);
6968
}
7069

@@ -82,11 +81,12 @@ public function test_scope_the_given_paths()
8281
{
8382
$input = [
8483
'add-prefix',
85-
'prefix' => 'MyPrefix',
84+
'--prefix' => 'MyPrefix',
8685
'paths' => [
8786
self::FIXTURE_PATH,
8887
],
8988
'--output-dir' => $this->tmp,
89+
'--no-interaction' => null,
9090
];
9191

9292
$this->appTester->run($input);
@@ -100,12 +100,12 @@ public function test_scope_in_quiet_mode()
100100
{
101101
$input = [
102102
'add-prefix',
103-
'prefix' => 'MyPrefix',
103+
'--prefix' => 'MyPrefix',
104104
'paths' => [
105105
self::FIXTURE_PATH,
106106
],
107107
'--output-dir' => $this->tmp,
108-
'--quiet',
108+
'--quiet' => null,
109109
];
110110

111111
$this->appTester->run($input);
@@ -122,11 +122,12 @@ public function test_scope_in_normal_mode()
122122
{
123123
$input = [
124124
'add-prefix',
125-
'prefix' => 'MyPrefix',
125+
'--prefix' => 'MyPrefix',
126126
'paths' => [
127127
self::FIXTURE_PATH,
128128
],
129129
'--output-dir' => $this->tmp,
130+
'--no-interaction' => null,
130131
];
131132

132133
$this->appTester->run($input);
@@ -162,12 +163,13 @@ public function test_scope_in_verbose_mode()
162163
{
163164
$input = [
164165
'add-prefix',
165-
'prefix' => 'MyPrefix',
166+
'--prefix' => 'MyPrefix',
166167
'paths' => [
167168
self::FIXTURE_PATH,
168169
],
169170
'--output-dir' => $this->tmp,
170-
'-v',
171+
'-v' => null,
172+
'--no-interaction' => null,
171173
];
172174

173175
$this->appTester->run($input);

0 commit comments

Comments
 (0)