Skip to content
This repository was archived by the owner on Sep 21, 2023. It is now read-only.

Commit 0ca5d36

Browse files
Merge pull request #74 from debricked/add-supported-files-command
Add files:find command
2 parents d5fc879 + ee5ad9b commit 0ca5d36

7 files changed

Lines changed: 547 additions & 88 deletions

File tree

src/Command/FindAndUploadFilesCommand.php

Lines changed: 29 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
namespace App\Command;
1313

1414
use App\Analysis\SnippetAnalysis;
15-
use App\Model\DependencyFileFormat;
16-
use App\Model\FileGroup;
15+
use App\Service\FileGroupFinder;
1716
use App\Utility\Utility;
1817
use Debricked\Shared\API\API;
1918
use Symfony\Component\Console\Command\Command;
@@ -23,12 +22,13 @@
2322
use Symfony\Component\Console\Input\InputOption;
2423
use Symfony\Component\Console\Output\OutputInterface;
2524
use Symfony\Component\Console\Style\SymfonyStyle;
26-
use Symfony\Component\Finder\Finder;
25+
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
2726
use Symfony\Component\Finder\SplFileInfo;
2827
use Symfony\Component\HttpFoundation\Request;
2928
use Symfony\Component\Mime\Part\DataPart;
3029
use Symfony\Component\Mime\Part\Multipart\FormDataPart;
3130
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
31+
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
3232
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
3333
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
3434
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
@@ -40,7 +40,7 @@ class FindAndUploadFilesCommand extends Command
4040

4141
protected static $defaultName = 'debricked:find-and-upload-files';
4242

43-
private const ARGUMENT_BASE_DIRECTORY = 'base-directory';
43+
public const ARGUMENT_BASE_DIRECTORY = 'base-directory';
4444
public const ARGUMENT_USERNAME = 'username';
4545
public const ARGUMENT_PASSWORD = 'password';
4646
private const ARGUMENT_REPOSITORY_NAME = 'repository-name';
@@ -49,10 +49,10 @@ class FindAndUploadFilesCommand extends Command
4949
private const ARGUMENT_INTEGRATION_NAME = 'integration-name';
5050
private const OPTION_BRANCH_NAME = 'branch-name';
5151
private const OPTION_DEFAULT_BRANCH = 'default-branch';
52-
private const OPTION_DIRECTORIES_TO_EXCLUDE = 'excluded-directories';
52+
public const OPTION_DIRECTORIES_TO_EXCLUDE = 'excluded-directories';
5353
private const OPTION_SNIPPET_ANALYSIS = 'snippet-analysis';
5454
private const OPTION_KEEP_ZIP = 'keep-zip';
55-
private const OPTION_RECURSIVE_FILE_SEARCH = 'recursive-file-search';
55+
public const OPTION_RECURSIVE_FILE_SEARCH = 'recursive-file-search';
5656
private const OPTION_UPLOAD_ALL_FILES = 'upload-all-files';
5757
private const OPTION_AUTHOR = 'author';
5858

@@ -187,40 +187,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
187187
'Failed to get current working directory, command might be searching through unexpected directories and files'
188188
);
189189
}
190-
191190
/** @var string $baseDirectory */
192191
$baseDirectory = $input->getArgument(self::ARGUMENT_BASE_DIRECTORY);
193-
194-
$io->writeln('Getting supported dependency file names from Debricked', OutputInterface::VERBOSITY_VERBOSE);
195-
196-
try {
197-
$dependencyFileNamesResponse = $api->makeApiCall(
198-
Request::METHOD_GET,
199-
'/api/1.0/open/files/supported-formats'
200-
);
201-
$dependencyFileFormats = \json_decode($dependencyFileNamesResponse->getContent(), true);
202-
} catch (TransportExceptionInterface $e) {
203-
$io->error("Failed to get supported dependency file names: {$e->getMessage()}");
204-
205-
return 1;
206-
} catch (ClientExceptionInterface|RedirectionExceptionInterface|ServerExceptionInterface $e) {
207-
/* @noinspection PhpUnhandledExceptionInspection */
208-
$io->error("Failed to get supported dependency file names: {$e->getResponse()->getContent(false)}");
209-
210-
return 1;
211-
}
212-
213-
$directoriesToExcludeString = \strval($input->getOption(self::OPTION_DIRECTORIES_TO_EXCLUDE));
214192
$searchDirectory = "{$workingDirectory}/{$baseDirectory}";
215193
$searchDirectory = preg_replace('#/+#', '/', $searchDirectory); // remove duplicate slashes.
216194

217-
$finder = new Finder();
218-
$finder->ignoreDotFiles(false);
219-
$finder->files()->in($searchDirectory);
220-
if (empty($directoriesToExcludeString) === false && \is_array(
221-
$directoriesToExcludeArray = \explode(',', $directoriesToExcludeString)
222-
)) {
223-
$finder->exclude($directoriesToExcludeArray);
195+
$directoriesToExcludeString = \strval($input->getOption(self::OPTION_DIRECTORIES_TO_EXCLUDE));
196+
$directoriesToExcludeArray = [];
197+
if (empty($directoriesToExcludeString) === false) {
198+
$directoriesToExcludeArray = \explode(',', $directoriesToExcludeString) ?? [];
224199
} else {
225200
$io->note('No directories will be ignored');
226201
}
@@ -231,7 +206,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
231206

232207
return 1;
233208
} elseif ($recursiveFileSearch === false) {
234-
$finder->depth(0);
235209
$io->note('Recursive search is disabled, only base directory will be searched');
236210
}
237211

@@ -246,46 +220,27 @@ protected function execute(InputInterface $input, OutputInterface $output): int
246220

247221
$uploadId = null;
248222

249-
$dependencyFileFormats = DependencyFileFormat::make($dependencyFileFormats);
250-
$numberOfMatchedFiles = 0;
251-
// Find lock files
252-
$lockFileRegexes = \array_merge(...\array_map(fn ($format) => $format->getLockFileRegexes(), $dependencyFileFormats));
253-
$lockFiles = [];
254-
foreach ($finder as $file) {
255-
if (Utility::pregMatchInArray($file->getFilename(), $lockFileRegexes)) {
256-
$lockFiles[$file->getPathname()] = $file;
257-
++$numberOfMatchedFiles;
258-
}
259-
}
223+
try {
224+
$io->writeln('Getting supported dependency file names from Debricked', OutputInterface::VERBOSITY_VERBOSE);
225+
$fileGroups = FileGroupFinder::find($api, $searchDirectory, $recursiveFileSearch, $directoriesToExcludeArray);
226+
} catch (TransportExceptionInterface $e) {
227+
$io->error("Failed to get supported dependency file names: {$e->getMessage()}");
260228

261-
/** Find dependency files and create FileGroups(@see FileGroup) */
262-
$fileGroups = [];
263-
foreach ($finder as $file) {
264-
if (($dependencyFileFormat = DependencyFileFormat::findFormatByFileName($dependencyFileFormats, $file->getFilename())) !== null) {
265-
$fileGroup = new FileGroup($file, $dependencyFileFormat);
266-
$lockFileRegexes = $dependencyFileFormat->getLockFileRegexes();
267-
// Find matching lock file
268-
foreach ($lockFileRegexes as $lockFileRegex) {
269-
foreach ($lockFiles as $key => $lockFile) {
270-
$quotedLockfilePath = \preg_quote($file->getPath(), '/');
271-
if (\preg_match("/$quotedLockfilePath\/$lockFileRegex/", $key) === 1) {
272-
$fileGroup->addLockFile($lockFile);
273-
unset($lockFiles[$key]);
274-
break;
275-
}
276-
}
277-
}
278-
$fileGroups[] = $fileGroup;
279-
++$numberOfMatchedFiles;
280-
}
229+
return 1;
230+
} catch (HttpExceptionInterface $e) {
231+
/* @noinspection PhpUnhandledExceptionInspection */
232+
$io->error("Failed to get supported dependency file names: {$e->getResponse()->getContent(false)}");
233+
234+
return 1;
235+
} catch (DirectoryNotFoundException $e) {
236+
$io->error("Failed to find directory: {$e->getMessage()}");
237+
238+
return 1;
281239
}
282240

283-
// Create FileGroups from leftover lock files.
284-
foreach ($lockFiles as $key => $lockFile) {
285-
$lockFileGroup = new FileGroup(null, null);
286-
$lockFileGroup->addLockFile($lockFile);
287-
$fileGroups[] = $lockFileGroup;
288-
unset($lockFiles[$key]);
241+
$numberOfMatchedFiles = 0;
242+
foreach ($fileGroups as $fileGroup) {
243+
$numberOfMatchedFiles += count($fileGroup->getFiles());
289244
}
290245

291246
if ($numberOfMatchedFiles > 0) {
@@ -341,6 +296,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
341296
}
342297
$uploadAllFiles = $uploadAllFiles && $numberOfMatchedFiles > 0;
343298
if ($enableSnippetAnalysis === true || $uploadAllFiles === true) {
299+
$finder = FileGroupFinder::makeFinder($searchDirectory, $recursiveFileSearch, $directoriesToExcludeArray);
344300
$zip = null;
345301
$progressBar = null;
346302
if ($uploadAllFiles === true) {

src/Command/FindFilesCommand.php

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
<?php
2+
/**
3+
* @license
4+
*
5+
* Copyright (C) debricked AB
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code (usually found in the root of this application).
9+
*/
10+
11+
namespace App\Command;
12+
13+
use App\Service\FileGroupFinder;
14+
use Debricked\Shared\API\API;
15+
use Symfony\Component\Console\Command\Command;
16+
use Symfony\Component\Console\Input\InputArgument;
17+
use Symfony\Component\Console\Input\InputInterface;
18+
use Symfony\Component\Console\Input\InputOption;
19+
use Symfony\Component\Console\Output\OutputInterface;
20+
use Symfony\Component\Console\Style\SymfonyStyle;
21+
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
22+
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
23+
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
24+
use Symfony\Contracts\HttpClient\HttpClientInterface;
25+
26+
class FindFilesCommand extends Command
27+
{
28+
use Style;
29+
30+
protected static $defaultName = 'debricked:files:find';
31+
32+
private const OPTION_JSON = 'json';
33+
34+
private HttpClientInterface $debrickedClient;
35+
36+
public function __construct(HttpClientInterface $debrickedClient, $name = null)
37+
{
38+
parent::__construct($name);
39+
40+
$this->debrickedClient = $debrickedClient;
41+
}
42+
43+
protected function configure(): void
44+
{
45+
$this
46+
->setDescription('Find and output dependency files in given base directory')
47+
->addArgument(
48+
FindAndUploadFilesCommand::ARGUMENT_USERNAME,
49+
InputArgument::REQUIRED,
50+
'Your Debricked username. Set to an empty string if you use an access token.',
51+
)
52+
->addArgument(
53+
FindAndUploadFilesCommand::ARGUMENT_PASSWORD,
54+
InputArgument::REQUIRED,
55+
'Your Debricked password or access token',
56+
)
57+
->addArgument(
58+
FindAndUploadFilesCommand::ARGUMENT_BASE_DIRECTORY,
59+
InputArgument::REQUIRED,
60+
'The base directory (relative to current working directory) to recursively find dependency files in. Default is current working directory.',
61+
)
62+
->addOption(
63+
'json',
64+
null,
65+
InputOption::VALUE_NONE,
66+
'Use this option to output files in json'
67+
)
68+
->addOption(
69+
FindAndUploadFilesCommand::OPTION_RECURSIVE_FILE_SEARCH,
70+
null,
71+
InputOption::VALUE_REQUIRED,
72+
'Set to 0 to disable recursive search - only base directory will be searched',
73+
1
74+
)
75+
->addOption(
76+
FindAndUploadFilesCommand::OPTION_DIRECTORIES_TO_EXCLUDE,
77+
null,
78+
InputOption::VALUE_REQUIRED,
79+
'Enter a comma separated list of directories to exclude. Such as: --excluded-directories="vendor,node_modules,tests"',
80+
'vendor,node_modules,tests'
81+
);
82+
}
83+
84+
public function execute(InputInterface $input, OutputInterface $output): int
85+
{
86+
$io = new SymfonyStyle($input, $output);
87+
$api = new API(
88+
$this->debrickedClient,
89+
\strval($input->getArgument(FindAndUploadFilesCommand::ARGUMENT_USERNAME)),
90+
\strval($input->getArgument(FindAndUploadFilesCommand::ARGUMENT_PASSWORD))
91+
);
92+
93+
$baseDirectory = $input->getArgument(FindAndUploadFilesCommand::ARGUMENT_BASE_DIRECTORY);
94+
$workingDirectory = \getcwd();
95+
if ($workingDirectory === false) {
96+
$io->warning(
97+
'Failed to get current working directory, command might be searching through unexpected directories and files'
98+
);
99+
}
100+
$searchDirectory = "{$workingDirectory}/{$baseDirectory}";
101+
$searchDirectory = preg_replace('#/+#', '/', $searchDirectory); // remove duplicate slashes.
102+
103+
$recursiveFileSearch = (bool) $input->getOption(FindAndUploadFilesCommand::OPTION_RECURSIVE_FILE_SEARCH);
104+
$directoriesToExcludeString = $input->getOption(FindAndUploadFilesCommand::OPTION_DIRECTORIES_TO_EXCLUDE);
105+
$directoriesToExcludeArray = [];
106+
if (empty($directoriesToExcludeString) === false) {
107+
$directoriesToExcludeArray = \explode(',', $directoriesToExcludeString) ?? [];
108+
} else {
109+
$io->note('No directories will be ignored');
110+
}
111+
112+
try {
113+
$fileGroups = FileGroupFinder::find($api, $searchDirectory, $recursiveFileSearch, $directoriesToExcludeArray);
114+
} catch (TransportExceptionInterface $e) {
115+
$io->error("Failed to get supported dependency file names: {$e->getMessage()}");
116+
117+
return Command::FAILURE;
118+
} catch (HttpExceptionInterface $e) {
119+
/* @noinspection PhpUnhandledExceptionInspection */
120+
$io->error("Failed to get supported dependency file names: {$e->getResponse()->getContent(false)}");
121+
122+
return Command::FAILURE;
123+
} catch (DirectoryNotFoundException $e) {
124+
$io->error("Failed to find directory: {$e->getMessage()}");
125+
126+
return Command::FAILURE;
127+
}
128+
129+
// Output file groups
130+
$json = (bool) $input->getOption(FindFilesCommand::OPTION_JSON);
131+
if ($json) {
132+
try {
133+
$jsonEncodedFileGroups = \json_encode($fileGroups, JSON_THROW_ON_ERROR);
134+
} catch (\JsonException $e) {
135+
$io->error("Failed to encode JSON: {$e->getMessage()}");
136+
137+
return Command::FAILURE;
138+
}
139+
$io->writeln($jsonEncodedFileGroups);
140+
} else {
141+
foreach ($fileGroups as $fileGroup) {
142+
$fileGroup->ioPrint($io, $searchDirectory);
143+
}
144+
}
145+
146+
return 0;
147+
}
148+
}

0 commit comments

Comments
 (0)