Skip to content

Commit a9c82a1

Browse files
committed
Code refactoring
1 parent 634ce4b commit a9c82a1

15 files changed

+274
-285
lines changed

src/Application/Bootloader/GitClientBootloader.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
namespace Butschster\ContextGenerator\Application\Bootloader;
66

7-
use Butschster\ContextGenerator\Lib\Git\GitClient;
8-
use Butschster\ContextGenerator\Lib\Git\GitClientInterface;
7+
use Butschster\ContextGenerator\Lib\Git\CommandsExecutor;
8+
use Butschster\ContextGenerator\Lib\Git\CommandsExecutorInterface;
99
use Spiral\Boot\Bootloader\Bootloader;
1010

1111
final class GitClientBootloader extends Bootloader
@@ -14,7 +14,7 @@ final class GitClientBootloader extends Bootloader
1414
public function defineSingletons(): array
1515
{
1616
return [
17-
GitClientInterface::class => GitClient::class,
17+
CommandsExecutorInterface::class => CommandsExecutor::class,
1818
];
1919
}
2020
}

src/Lib/Git/GitClient.php renamed to src/Lib/Git/CommandsExecutor.php

Lines changed: 127 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@
55
namespace Butschster\ContextGenerator\Lib\Git;
66

77
use Butschster\ContextGenerator\Application\Logger\LoggerPrefix;
8+
use Butschster\ContextGenerator\DirectoriesInterface;
89
use Butschster\ContextGenerator\Lib\Git\Exception\GitClientException;
10+
use Butschster\ContextGenerator\Lib\Git\Exception\GitCommandException;
911
use Psr\Log\LoggerInterface;
12+
use Spiral\Files\Exception\FilesException;
13+
use Spiral\Files\FilesInterface;
14+
use Symfony\Component\Process\Process;
1015

11-
final class GitClient implements GitClientInterface
16+
/**
17+
* Executes git commands and handles their results.
18+
*/
19+
final class CommandsExecutor implements CommandsExecutorInterface
1220
{
1321
/**
1422
* Static cache of validated repositories
@@ -17,28 +25,37 @@ final class GitClient implements GitClientInterface
1725
private static array $validatedRepositories = [];
1826

1927
public function __construct(
20-
#[LoggerPrefix(prefix: 'git-client')]
28+
private readonly FilesInterface $files,
29+
private readonly DirectoriesInterface $dirs,
30+
#[LoggerPrefix(prefix: 'git-commands-executor')]
2131
private readonly ?LoggerInterface $logger = null,
2232
) {}
2333

34+
/**
35+
* Execute a Git command and return the output as an array of lines.
36+
*
37+
* @inheritDoc
38+
*/
2439
public function execute(string $repository, string $command): array
2540
{
26-
$this->validateRepository($repository);
41+
$repoPath = (string) $this->dirs->getRootPath()->join($repository);
42+
43+
$this->validateRepository($repoPath);
2744

2845
$currentDir = \getcwd();
2946
$output = [];
3047
$returnCode = 0;
3148

3249
try {
3350
// Change to the repository directory
34-
\chdir($repository);
51+
\chdir($repoPath);
3552

3653
// Add 'git' prefix to the command if not already present
3754
$fullCommand = $this->prepareCommand($command);
3855

3956
$this->logger?->debug('Executing Git command', [
4057
'command' => $fullCommand,
41-
'repository' => $repository,
58+
'repository' => $repoPath,
4259
]);
4360

4461
// Execute the command with error output capture
@@ -69,12 +86,47 @@ public function execute(string $repository, string $command): array
6986
}
7087
}
7188

89+
/**
90+
* Execute a Git command and return the output as a string.
91+
*
92+
* @inheritDoc
93+
*/
7294
public function executeString(string $repository, string $command): string
7395
{
7496
$output = $this->execute($repository, $command);
97+
7598
return \implode(PHP_EOL, $output);
7699
}
77100

101+
/**
102+
* Execute a Git command using an array of command parts.
103+
*
104+
* @inheritDoc
105+
*/
106+
public function executeCommand(array $command): string
107+
{
108+
// Prepend 'git' to the command array
109+
$gitCommand = ['git'];
110+
$fullCommand = \array_merge($gitCommand, $command);
111+
112+
$process = new Process($fullCommand, (string) $this->dirs->getRootPath());
113+
$process->run();
114+
115+
if (!$process->isSuccessful()) {
116+
throw new GitCommandException(
117+
\sprintf('Git command failed: %s', $process->getErrorOutput()),
118+
$process->getExitCode(),
119+
);
120+
}
121+
122+
return $process->getOutput();
123+
}
124+
125+
/**
126+
* Check if a directory is a valid Git repository.
127+
*
128+
* @inheritDoc
129+
*/
78130
public function isValidRepository(string $repository): bool
79131
{
80132
// Return cached result if available
@@ -129,6 +181,76 @@ public function isValidRepository(string $repository): bool
129181
}
130182
}
131183

184+
/**
185+
* Applies a git patch to a file.
186+
*
187+
* @inheritDoc
188+
*/
189+
public function applyPatch(string $filePath, string $patchContent): string
190+
{
191+
$rootPath = $this->dirs->getRootPath();
192+
$file = $rootPath->join($filePath);
193+
194+
// Ensure the file exists
195+
if (!$file->exists()) {
196+
throw new GitCommandException(\sprintf('File "%s" does not exist', $filePath));
197+
}
198+
199+
// Create a temporary file for the patch
200+
try {
201+
$patchFile = $this->files->tempFilename();
202+
} catch (FilesException $e) {
203+
$this->logger?->error('Failed to create temporary file for patch', [
204+
'error' => $e->getMessage(),
205+
]);
206+
207+
throw new GitCommandException('Failed to create temporary file for patch', 0, $e);
208+
}
209+
210+
try {
211+
// Write the patch content to a temporary file
212+
$this->files->write($patchFile, $patchContent, FilesInterface::READONLY);
213+
214+
// Apply the patch using git apply command
215+
$process = new Process(
216+
['git', 'apply', '--whitespace=nowarn', $patchFile],
217+
(string) $rootPath,
218+
);
219+
220+
$process->run();
221+
222+
// Check if the command was successful
223+
if (!$process->isSuccessful()) {
224+
throw new GitCommandException(
225+
\sprintf('Failed to apply patch: %s', $process->getErrorOutput()),
226+
$process->getExitCode(),
227+
);
228+
}
229+
230+
return \sprintf('Successfully applied patch to %s', $filePath);
231+
} finally {
232+
if ($this->files->exists($patchFile)) {
233+
$this->files->delete($patchFile);
234+
}
235+
}
236+
}
237+
238+
/**
239+
* Checks if the given directory is a git repository.
240+
*
241+
* @return bool True if the directory is a git repository, false otherwise
242+
* @internal This method is kept for backward compatibility
243+
*/
244+
public function isGitRepository(): bool
245+
{
246+
try {
247+
$this->executeCommand(['rev-parse', '--is-inside-work-tree']);
248+
return true;
249+
} catch (GitCommandException) {
250+
return false;
251+
}
252+
}
253+
132254
/**
133255
* Validate that the repository directory exists and is a valid Git repository
134256
* Uses cached results when available
@@ -138,13 +260,6 @@ public function isValidRepository(string $repository): bool
138260
*/
139261
private function validateRepository(string $repository): void
140262
{
141-
if (!\is_dir($repository)) {
142-
$this->logger?->error('Repository directory does not exist', [
143-
'repository' => $repository,
144-
]);
145-
throw new \InvalidArgumentException(\sprintf('Git repository "%s" does not exist', $repository));
146-
}
147-
148263
if (!$this->isValidRepository($repository)) {
149264
$this->logger?->error('Not a valid Git repository', [
150265
'repository' => $repository,

src/Lib/Git/GitClientInterface.php renamed to src/Lib/Git/CommandsExecutorInterface.php

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
namespace Butschster\ContextGenerator\Lib\Git;
66

77
use Butschster\ContextGenerator\Lib\Git\Exception\GitClientException;
8+
use Butschster\ContextGenerator\Lib\Git\Exception\GitCommandException;
89

910
/**
10-
* Provides a clean abstraction layer for interacting with Git repositories.
11+
* Comprehensive interface for executing Git commands and operations.
1112
*/
12-
interface GitClientInterface
13+
interface CommandsExecutorInterface
1314
{
1415
/**
15-
* Execute a Git command and return the output as an array of lines
16+
* Execute a Git command and return the output as an array of lines.
1617
*
1718
* @param string $repository Path to the Git repository
1819
* @param string $command Git command to execute (without 'git' prefix)
@@ -22,7 +23,7 @@ interface GitClientInterface
2223
public function execute(string $repository, string $command): array;
2324

2425
/**
25-
* Execute a Git command and return the output as a string
26+
* Execute a Git command and return the output as a string.
2627
*
2728
* @param string $repository Path to the Git repository
2829
* @param string $command Git command to execute (without 'git' prefix)
@@ -32,10 +33,29 @@ public function execute(string $repository, string $command): array;
3233
public function executeString(string $repository, string $command): string;
3334

3435
/**
35-
* Check if a directory is a valid Git repository
36+
* Execute a Git command using an array of command parts.
37+
*
38+
* @param array<string> $command Command parts to execute (without 'git' prefix)
39+
* @return string Command output as a string
40+
* @throws GitCommandException If the command execution fails
41+
*/
42+
public function executeCommand(array $command): string;
43+
44+
/**
45+
* Check if a directory is a valid Git repository.
3646
*
3747
* @param string $repository Path to the Git repository
3848
* @return bool True if the directory is a valid Git repository
3949
*/
4050
public function isValidRepository(string $repository): bool;
51+
52+
/**
53+
* Applies a git patch to a file.
54+
*
55+
* @param string $filePath Path to the file to patch
56+
* @param string $patchContent Content of the patch to apply
57+
* @return string Result message
58+
* @throws GitCommandException If the patch application fails
59+
*/
60+
public function applyPatch(string $filePath, string $patchContent): string;
4161
}

src/Lib/Git/GitCommandsExecutor.php

Lines changed: 0 additions & 113 deletions
This file was deleted.

0 commit comments

Comments
 (0)