Skip to content

Commit

Permalink
Merge pull request #23 from ramsey
Browse files Browse the repository at this point in the history
Implement status operator for reading working tree status
  • Loading branch information
sebastianfeldmann authored Apr 3, 2021
2 parents 8bdbc4e + d32a369 commit 426acdd
Show file tree
Hide file tree
Showing 10 changed files with 935 additions and 0 deletions.
99 changes: 99 additions & 0 deletions src/Command/Status/Porcelain/PathList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

/**
* This file is part of SebastianFeldmann\Git.
*
* (c) Sebastian Feldmann <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianFeldmann\Git\Command\Status\Porcelain;

use SebastianFeldmann\Cli\Command\OutputFormatter;
use SebastianFeldmann\Git\Status\Path;

/**
* Class PathList
*
* @package SebastianFeldmann\Git
* @author Sebastian Feldmann <[email protected]>
* @link https://github.com/sebastianfeldmann/git
* @since Class available since Release ?.?.?
*/
class PathList implements OutputFormatter
{
/**
* Nul-byte used as a separator in `--porcelain=v1 -z` output.
*/
private const NUL_BYTE = "\x00";

/**
* Format the output.
*
* @param array $output
* @return iterable
*/
public function format(array $output): iterable
{
if (empty($output)) {
return [];
}

$statusLine = implode('', $output);
$paths = [];

foreach ($this->parseStatusLine($statusLine) as $pathParts) {
$paths[] = new Path(...$pathParts);
}

return $paths;
}

/**
* Parse the status line and return a 3-tuple of path parts.
*
* - 0: status code
* - 1: path
* - 2: original path, if renamed or copied
*
* @return array{
* 0: non-empty-string,
* 1: non-empty-string,
* 2: non-empty-string|null
* }
*/
private function parseStatusLine(string $statusLine): array
{
$pathParts = [];

$parts = array_reverse($this->splitOnNulByte($statusLine));

while ($parts) {
$part = array_pop($parts);
$statusCode = substr($part, 0, 2);
$path = substr($part, 3);

$originalPath = null;
if (in_array($statusCode[0], [Path::COPIED, Path::RENAMED])) {
$originalPath = array_pop($parts);
}

$pathParts[] = [$statusCode, $path, $originalPath];
}

return $pathParts;
}

/**
* Split the status line on the nul-byte.
*
* @param string $statusLine
* @return array
*/
private function splitOnNulByte(string $statusLine): array
{
return explode(self::NUL_BYTE, trim($statusLine, self::NUL_BYTE));
}
}
57 changes: 57 additions & 0 deletions src/Command/Status/WorkingTreeStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

/**
* This file is part of SebastianFeldmann\Git.
*
* (c) Sebastian Feldmann <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianFeldmann\Git\Command\Status;

use SebastianFeldmann\Git\Command\Base;

/**
* Class GetWorkingTreeStatus
*
* @package SebastianFeldmann\Git
* @author Sebastian Feldmann <[email protected]>
* @link https://github.com/sebastianfeldmann/git
* @since Class available since Release ?.?.?
*/
class WorkingTreeStatus extends Base
{
/**
* Ignore submodules.
*
* @var string
*/
private $ignoreSubmodules = '';

/**
* Set ignore submodules.
*
* @param bool $bool
*
* @return \SebastianFeldmann\Git\Command\Status\WorkingTreeStatus
*/
public function ignoreSubmodules(bool $bool = true): WorkingTreeStatus
{
$this->ignoreSubmodules = $this->useOption('--ignore-submodules', $bool);
return $this;
}

/**
* Return the command to execute.
*
* @return string
* @throws \RuntimeException
*/
protected function getGitCommand(): string
{
return 'status --porcelain=v1 -z'
. $this->ignoreSubmodules;
}
}
40 changes: 40 additions & 0 deletions src/Operator/Status.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/**
* This file is part of SebastianFeldmann\Git.
*
* (c) Sebastian Feldmann <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace SebastianFeldmann\Git\Operator;

use SebastianFeldmann\Git\Command\Status\WorkingTreeStatus;
use SebastianFeldmann\Git\Command\Status\Porcelain\PathList;

/**
* Class Status
*
* @package SebastianFeldmann\Git
* @author Sebastian Feldmann <[email protected]>
* @link https://github.com/sebastianfeldmann/git
* @since Class available since Release ?.?.?
*/
class Status extends Base
{
/**
* Returns a list of paths in the working tree and index, with statuses.
*
* @return \SebastianFeldmann\Git\Status\Path[]
*/
public function getWorkingTreeStatus(): iterable
{
$cmd = (new WorkingTreeStatus($this->repo->getRoot()))->ignoreSubmodules();

$result = $this->runner->run($cmd, new PathList());

return $result->getFormattedOutput();
}
}
10 changes: 10 additions & 0 deletions src/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,16 @@ public function getDiffOperator(): Operator\Diff
return $this->getOperator('Diff');
}

/**
* Get status operator.
*
* @return \SebastianFeldmann\Git\Operator\Status
*/
public function getStatusOperator(): Operator\Status
{
return $this->getOperator('Status');
}

/**
* Return requested operator.
*
Expand Down
Loading

0 comments on commit 426acdd

Please sign in to comment.