Skip to content

Commit 9a57005

Browse files
committed
Adds new tree command
1 parent 668f352 commit 9a57005

File tree

6 files changed

+232
-1
lines changed

6 files changed

+232
-1
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
77

88
## [Unreleased]
99

10+
## [v4.3.0] - 2025-02-07
11+
12+
### Added
13+
- New `tree` command, that displays the source and dist package structure. Closes [#48](https://github.com/raphaelstolt/lean-package-validator/issues/48).
14+
1015
## [v4.2.0] - 2025-02-06
1116

1217
### Added

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,54 @@ The `--overwrite|-o` option overwrites an existing `.lpv` file.
192192
The `--preset` option allows to choose from a predefined set of glob pattern.
193193
Available presets are `PHP`, `Python`, and `Go`. With `PHP` being the default.
194194

195+
The `tree` command allows you to inspect the __flat__ `source` and `dist package` structure of the given project.
196+
197+
``` bash
198+
lean-package-validator tree [<directory>] --src
199+
200+
Package: stolt/lean-package-validator
201+
.
202+
├── bin
203+
├── coverage-reports
204+
├── example
205+
├── .git
206+
├── .github
207+
├── .idea
208+
├── .phpunit.cache
209+
├── src
210+
├── tests
211+
├── vendor
212+
├── box.json.dist
213+
├── CHANGELOG.md
214+
├── composer.json
215+
├── composer.lock
216+
├── .editorconfig
217+
├── .gitattributes
218+
├── .gitignore
219+
├── .gitmessage
220+
├── LICENSE.md
221+
├── lpv-logo.png
222+
├── peck.json
223+
├── .php-cs-fixer.php
224+
├── phpstan.neon.dist
225+
├── phpunit.xml.dist
226+
└── README.md
227+
228+
10 directories, 15 files
229+
```
230+
231+
``` bash
232+
lean-package-validator tree [<directory>] --dist-package
233+
234+
Package: stolt/lean-package-validator
235+
.
236+
├── bin
237+
├── composer.json
238+
└── src
239+
240+
2 directories, 1 file
241+
```
242+
195243
## Utilisation via Composer scripts, cpx, or it's dedicated GitHub Action
196244

197245
To avoid that changes coming from contributions or own modifications slip into release/dist archives it

bin/lean-package-validator

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ if (false === $autoloaded) {
2525
\define('VERSION', '4.2.0');
2626

2727
use Stolt\LeanPackage\Commands\InitCommand;
28+
use Stolt\LeanPackage\Commands\TreeCommand;
2829
use Stolt\LeanPackage\Commands\ValidateCommand;
2930
use Stolt\LeanPackage\Analyser;
3031
use Stolt\LeanPackage\Archive;
3132
use Stolt\LeanPackage\Archive\Validator;
3233
use Stolt\LeanPackage\Presets\Finder;
3334
use Stolt\LeanPackage\Presets\PhpPreset;
35+
use Stolt\LeanPackage\Tree;
3436
use Symfony\Component\Console\Application;
3537

3638
$finder = new Finder(new PhpPreset());
@@ -44,9 +46,10 @@ $validateCommand = new ValidateCommand(
4446
$analyser,
4547
new Validator($archive)
4648
);
49+
$treeCommand = new TreeCommand(new Tree($archive));
4750

4851
$application = new Application('Lean package validator', VERSION);
4952
$application->addCommands(
50-
[$initCommand, $validateCommand]
53+
[$initCommand, $validateCommand, $treeCommand]
5154
);
5255
$application->run();

src/Commands/TreeCommand.php

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Stolt\LeanPackage\Commands;
6+
7+
use Stolt\LeanPackage\Exceptions\GitNotAvailable;
8+
use Stolt\LeanPackage\Exceptions\TreeNotAvailable;
9+
use Stolt\LeanPackage\Helpers\Str as OsHelper;
10+
use Stolt\LeanPackage\Tree;
11+
use Symfony\Component\Console\Command\Command;
12+
use Symfony\Component\Console\Input\InputArgument;
13+
use Symfony\Component\Console\Input\InputInterface;
14+
use Symfony\Component\Console\Input\InputOption;
15+
use Symfony\Component\Console\Output\OutputInterface;
16+
17+
final class TreeCommand extends Command
18+
{
19+
private Tree $tree;
20+
21+
private string $directoryToOperateOn;
22+
23+
public function __construct(Tree $tree)
24+
{
25+
$this->tree = $tree;
26+
parent::__construct();
27+
}
28+
29+
/**
30+
* Command configuration.
31+
*
32+
* @return void
33+
*/
34+
protected function configure(): void
35+
{
36+
$this->directoryToOperateOn = WORKING_DIRECTORY;
37+
$this->setName('tree');
38+
$description = 'Displays the source structure of a given '
39+
. "project/micro-package repository or it's dist package";
40+
$this->setDescription($description);
41+
42+
$directoryDescription = 'The directory of a project/micro-package repository';
43+
44+
$this->addArgument(
45+
'directory',
46+
InputArgument::OPTIONAL,
47+
$directoryDescription,
48+
$this->directoryToOperateOn
49+
);
50+
51+
$srcDescription = 'Show the flat src structure of the project/micro-package repository';
52+
$distPackageDescription = 'Show the flat dist package structure of the project/micro-package';
53+
54+
$this->addOption('src', null, InputOption::VALUE_NONE, $srcDescription);
55+
$this->addOption('dist-package', null, InputOption::VALUE_NONE, $distPackageDescription);
56+
}
57+
58+
protected function execute(InputInterface $input, OutputInterface $output): int
59+
{
60+
$directory = (string) $input->getArgument('directory');
61+
62+
if ($directory !== $this->directoryToOperateOn) {
63+
if (!\file_get_contents($directory) || !\is_dir($directory)) {
64+
$warning = "Warning: The provided directory "
65+
. "'$directory' does not exist or is not a directory.";
66+
$outputContent = '<error>' . $warning . '</error>';
67+
$output->writeln($outputContent);
68+
69+
return Command::FAILURE;
70+
}
71+
}
72+
73+
$showSrcTree = $input->getOption('src');
74+
$showDistPackageTree = $input->getOption('dist-package');
75+
76+
if ($showSrcTree) {
77+
$verboseOutput = '+ Showing flat structure of package source.';
78+
$output->writeln($verboseOutput, OutputInterface::VERBOSITY_VERBOSE);
79+
80+
$output->writeln('Package: <info>' . $this->getPackageName() . '</info>');
81+
$output->write($this->tree->getTreeForSrc($this->directoryToOperateOn));
82+
83+
return Command::SUCCESS;
84+
}
85+
86+
if ($showDistPackageTree) {
87+
$verboseOutput = '+ Showing flat structure of dist package.';
88+
$output->writeln($verboseOutput, OutputInterface::VERBOSITY_VERBOSE);
89+
90+
$output->writeln('Package: <info>' . $this->getPackageName() . '</info>');
91+
$output->write($this->tree->getTreeForDistPackage($this->directoryToOperateOn));
92+
93+
return Command::SUCCESS;
94+
}
95+
96+
return Command::FAILURE;
97+
}
98+
99+
protected function getPackageName(): string
100+
{
101+
$composerContentAsJson = \json_decode(\file_get_contents('composer.json'), true);
102+
return \trim($composerContentAsJson['name']);
103+
}
104+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
namespace Stolt\LeanPackage\Exceptions;
3+
4+
class TreeNotAvailable extends \Exception
5+
{
6+
}

src/Tree.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace Stolt\LeanPackage;
4+
5+
use Stolt\LeanPackage\Exceptions\GitNotAvailable;
6+
use Stolt\LeanPackage\Exceptions\TreeNotAvailable;
7+
use Stolt\LeanPackage\Helpers\Str as OsHelper;
8+
9+
final class Tree
10+
{
11+
private Archive $archive;
12+
13+
/**
14+
* @throws TreeNotAvailable
15+
* @throws GitNotAvailable
16+
*/
17+
public function __construct(Archive $archive)
18+
{
19+
if (!$this->detectTreeCommand()) {
20+
throw new TreeNotAvailable();
21+
}
22+
23+
$this->archive = $archive;
24+
25+
if (!$this->archive->isGitCommandAvailable()) {
26+
throw new GitNotAvailable();
27+
}
28+
}
29+
30+
public function getTreeForSrc(string $directory): string
31+
{
32+
\exec(
33+
'tree -aL 1 --dirsfirst ' . \escapeshellarg($directory) . ' 2>&1',
34+
$output
35+
);
36+
37+
$output[0] = '.';
38+
39+
return \implode(PHP_EOL, $output) . PHP_EOL;
40+
}
41+
42+
public function getTreeForDistPackage(string $directory): string
43+
{
44+
$this->archive->createArchive();
45+
46+
\exec(
47+
'tar --list --exclude="*/*" --file ' . \escapeshellarg($this->archive->getFilename()) . ' | tree -aL 1 --dirsfirst --fromfile . 2>&1',
48+
$output
49+
);
50+
51+
$this->archive->removeArchive();
52+
53+
return \implode(PHP_EOL, $output) . PHP_EOL;
54+
}
55+
56+
protected function detectTreeCommand(string $command = 'tree'): bool
57+
{
58+
\exec('where ' . $command . ' 2>&1', $output, $returnValue);
59+
if ((new OsHelper())->isWindows() === false) {
60+
\exec('which ' . $command . ' 2>&1', $output, $returnValue);
61+
}
62+
63+
return $returnValue === 0;
64+
}
65+
}

0 commit comments

Comments
 (0)