Skip to content

Commit 576b558

Browse files
committed
initial commit
0 parents  commit 576b558

File tree

8 files changed

+401
-0
lines changed

8 files changed

+401
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## IDE
2+
.idea
3+
4+
## composer
5+
composer.lock
6+
vendor

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
phpstan:
2+
vendor/bin/phpstan analyse

composer.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "utilitte/console",
3+
"require": {
4+
"php": ">= 8.1",
5+
"phpstan/phpstan": "^1.5",
6+
"nette/utils": "^3.2",
7+
"utilitte/asserts": "^1.2"
8+
},
9+
"autoload": {
10+
"psr-4": {
11+
"Utilitte\\Console\\": "src"
12+
}
13+
}
14+
}

phpstan.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
parameters:
2+
level: 9
3+
paths:
4+
- src
5+
editorUrl: 'file://%%file%%'

src/CommandLine.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Utilitte\Console;
4+
5+
use LogicException;
6+
7+
final class CommandLine
8+
{
9+
10+
private static string $currentDir;
11+
12+
public static function passthru(string $command, ?string $workingDir = null): int
13+
{
14+
if ($workingDir) {
15+
$command = sprintf('cd "%s" && %s', $workingDir, $command);
16+
}
17+
18+
passthru($command, $result);
19+
20+
return $result;
21+
}
22+
23+
/**
24+
* @param string $command
25+
* @param bool $silent
26+
* @return string[]
27+
*/
28+
public static function command(string $command, bool $silent = false): array
29+
{
30+
if ($silent) {
31+
$state = exec($command, $output, $return);
32+
} else {
33+
$state = system($command, $return);
34+
$output[0] = $state;
35+
}
36+
37+
if ($state === false) {
38+
throw new LogicException("Command $command errored");
39+
}
40+
41+
if ($return !== 0) {
42+
throw new LogicException("Command $command exited with code $return", 1);
43+
}
44+
45+
return $output;
46+
}
47+
48+
public static function getCwd(): string
49+
{
50+
if (!isset(self::$currentDir)) {
51+
$working = getcwd();
52+
53+
if ($working === false) {
54+
throw new LogicException('Cannot get current working dir.');
55+
}
56+
57+
self::$currentDir = $working;
58+
}
59+
60+
return self::$currentDir;
61+
}
62+
63+
}

src/ComposerFile.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Utilitte\Console;
4+
5+
use InvalidArgumentException;
6+
use LogicException;
7+
use Nette\Utils\FileSystem;
8+
use Nette\Utils\Json;
9+
use Nette\Utils\JsonException;
10+
use Utilitte\Asserts\TypeAssert;
11+
12+
final class ComposerFile
13+
{
14+
15+
private string $file;
16+
17+
/** @var mixed[] */
18+
private array $contents;
19+
20+
public function __construct(private string $directory)
21+
{
22+
$file = $directory . '/composer.json';
23+
24+
if (!file_exists($file)) {
25+
throw new InvalidArgumentException(sprintf('Composer file %s does not exist.', $file));
26+
}
27+
28+
$this->file = $file;
29+
30+
try {
31+
$this->contents = (array) Json::decode(FileSystem::read($file), Json::FORCE_ARRAY);
32+
} catch (JsonException $e) {
33+
throw new InvalidArgumentException(sprintf('Composer file %s is not a valid json.', $file), previous: $e);
34+
}
35+
}
36+
37+
public function getName(): string
38+
{
39+
return TypeAssert::string($this->getSection('name'));
40+
}
41+
42+
/**
43+
* @return array<string, string>
44+
*/
45+
public function getRequire(): array
46+
{
47+
/** @var array<string, string> $require */
48+
$require = $this->getSectionWithDefault('require', []);
49+
50+
return $require;
51+
}
52+
53+
/**
54+
* @return array<string, string>
55+
*/
56+
public function getDevRequire(): array
57+
{
58+
/** @var array<string, string> $require */
59+
$require = $this->getSectionWithDefault('dev-require', []);
60+
61+
return $require;
62+
}
63+
64+
/**
65+
* @return array<string, string>
66+
*/
67+
public function getLibraries(): array
68+
{
69+
$libs = [];
70+
foreach (array_merge($this->getRequire(), $this->getDevRequire()) as $name => $version) {
71+
if (!str_contains($name, '/')) {
72+
continue;
73+
}
74+
75+
$libs[$name] = $version;
76+
}
77+
78+
return $libs;
79+
}
80+
81+
public function getLibraryPath(string $name): string
82+
{
83+
return $this->directory . '/vendor/' . $name;
84+
}
85+
86+
private function getSection(string $section): mixed
87+
{
88+
return $this->contents[$section]
89+
??
90+
throw new LogicException(sprintf('Composer file %s does not have section %s.', $this->file, $section));
91+
}
92+
93+
private function getSectionWithDefault(string $section, mixed $default): mixed
94+
{
95+
return $this->contents[$section] ?? $default;
96+
}
97+
98+
public static function getParsedFileNullable(string $directory): ?self
99+
{
100+
try {
101+
return new self($directory);
102+
} catch (InvalidArgumentException) {
103+
return null;
104+
}
105+
}
106+
107+
}

src/Git.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Utilitte\Console;
4+
5+
use LogicException;
6+
7+
final class Git
8+
{
9+
10+
public function __construct(
11+
private string $directory,
12+
)
13+
{
14+
}
15+
16+
public function isGitDirectory(): bool
17+
{
18+
return is_dir($this->directory . '/.git');
19+
}
20+
21+
public function hasUncommittedFiles(): bool
22+
{
23+
$this->validate();
24+
25+
return (bool) $this->command('git status -s');
26+
}
27+
28+
/**
29+
* @return string[]
30+
*/
31+
public function getUncommitedFiles(): array
32+
{
33+
return $this->command('git status -s');
34+
}
35+
36+
public function hasUnpushedCommits(): bool
37+
{
38+
$this->validate();
39+
40+
$return = $this->command('git status -s -b');
41+
42+
return str_contains($return[0], '[ahead');
43+
}
44+
45+
/**
46+
* @return string[]
47+
*/
48+
private function command(string $command): array
49+
{
50+
return CommandLine::command(sprintf('cd "%s" && %s', $this->directory, $command), true);
51+
}
52+
53+
private function validate(): void
54+
{
55+
if (!$this->isGitDirectory()) {
56+
throw new LogicException(sprintf('Directory %s, is not a git directory.', $this->directory));
57+
}
58+
}
59+
60+
}

0 commit comments

Comments
 (0)