Continue git implementation

This commit is contained in:
Dennis Eichhorn 2016-05-07 21:55:48 +02:00
parent 29707c4203
commit 482d6166cd
5 changed files with 448 additions and 81 deletions

View File

@ -55,8 +55,8 @@ class Author
*/ */
public function __construct(string $name = '', string $email = '') public function __construct(string $name = '', string $email = '')
{ {
$this->name = $name; $this->name = escapeshellarg($name);
$this->email = $email; $this->email = escapeshellarg($email);
} }
/** /**

View File

@ -46,7 +46,7 @@ class Branch
*/ */
public function __construct(string $name = '') public function __construct(string $name = '')
{ {
$this->name = $name; $this->setName($name);
} }
/** /**
@ -59,7 +59,7 @@ class Branch
*/ */
public function setName(string $name) public function setName(string $name)
{ {
$this->name = $name; $this->name = escapeshellarg($name);
} }
/** /**

View File

@ -102,13 +102,23 @@ class Commit
*/ */
public function __construct(string $id = '') public function __construct(string $id = '')
{ {
$this->id = escapeshellarg($id);
$this->author = new Author(); $this->author = new Author();
$this->branch = new Branch(); $this->branch = new Branch();
$this->tag = new Tag(); $this->tag = new Tag();
}
if (!empty($id)) { /**
// todo: fill base info * Get commit id.
} *
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getId()
{
return $this->id;
} }
/** /**
@ -121,6 +131,8 @@ class Commit
*/ */
public function addFile(string $path) public function addFile(string $path)
{ {
$path = escapeshellarg($path);
if (!isset($this->files[$path])) { if (!isset($this->files[$path])) {
$this->files[$path] = []; $this->files[$path] = [];
} }
@ -164,7 +176,7 @@ class Commit
*/ */
public function setMessage(string $message) public function setMessage(string $message)
{ {
$this->message = $message; $this->message = escapeshellarg($message);
} }
/** /**
@ -305,6 +317,21 @@ class Commit
return $this->date ?? new \DateTime('now'); return $this->date ?? new \DateTime('now');
} }
/**
* Set commit date.
*
* @param \DateTime $date Commit date
*
* @return void
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function setDate(\DateTime $date)
{
$this->date = $date;
}
/** /**
* Set commit repository. * Set commit repository.
* *

View File

@ -16,6 +16,7 @@
namespace phpOMS\Utils\Git; namespace phpOMS\Utils\Git;
use phpOMS\System\File\PathException; use phpOMS\System\File\PathException;
use phpOMS\Validation\Validator;
/** /**
* Repository class * Repository class
@ -54,6 +55,14 @@ class Repository
*/ */
private $envOptions = []; private $envOptions = [];
/**
* Current branch.
*
* @var Branch
* @since 1.0.0
*/
private $branch = null;
/** /**
* Constructor * Constructor
* *
@ -64,6 +73,7 @@ class Repository
*/ */
public function __construct(string $path) public function __construct(string $path)
{ {
$this->branch = $this->getActiveBranch();
$this->setPath($path); $this->setPath($path);
} }
@ -109,13 +119,16 @@ class Repository
$this->path = realpath($path); $this->path = realpath($path);
if ($this->path === false || !Validator::startsWith($this->path, ROOT_PATH)) {
throw new PathException($path);
}
if (file_exists($this->path . '/.git') && is_dir($this->path . '/.git')) { if (file_exists($this->path . '/.git') && is_dir($this->path . '/.git')) {
$this->bare = false; $this->bare = false;
// Is this a bare repo? } elseif (is_file($this->path . '/config')) { // Is this a bare repo?
} elseif (is_file($this->path . '/config')) { $parseIni = parse_ini_file($this->path . '/config');
$parse_ini = parse_ini_file($this->path . '/config');
if ($parse_ini['bare']) { if ($parseIni['bare']) {
$this->bare = true; $this->bare = true;
} }
} }
@ -126,14 +139,14 @@ class Repository
* *
* @param string $cmd Command to run * @param string $cmd Command to run
* *
* @return string * @return array
* *
* @throws \Exception * @throws \Exception
* *
* @since 1.0.0 * @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com> * @author Dennis Eichhorn <d.eichhorn@oms.com>
*/ */
private function run(string $cmd) : string private function run(string $cmd) : array
{ {
$cmd = Git::getBin() . ' ' . $cmd; $cmd = Git::getBin() . ' ' . $cmd;
$pipes = []; $pipes = [];
@ -165,7 +178,37 @@ class Repository
throw new \Exception($stderr); throw new \Exception($stderr);
} }
return $stdout; return $this->parseLines($stdout);
}
/**
* Parse lines.
*
* @param string $lines Result of git command
*
* @return array
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
private function parseLines(string $lines) : array
{
$lines = preg_replace('/!\\t+/', '|', $lines);
$lines = preg_replace('!\s+!', ' ', $lines);
$lineArray = preg_split('/\\r\\n|\\r|\\n/', $lines);
foreach ($lineArray as $key => $line) {
$lineArray[$key] = trim($line, ' |');
if (empty($line)) {
unset($lineArray[$key]);
} else {
$lineArray[$key] = $line;
}
}
return $lineArray;
} }
/** /**
@ -191,10 +234,22 @@ class Repository
*/ */
public function status() : string public function status() : string
{ {
return $this->run('status'); return implode("\n", $this->run('status'));
} }
public function add($files = '*') /**
* Files to add to commit.
*
* @param string|array $files Files to commit
*
* @return string
*
* @throws \Exception
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function add($files = '*') : string
{ {
if (is_array($files)) { if (is_array($files)) {
$files = '"' . implode('" "', $files) . '"'; $files = '"' . implode('" "', $files) . '"';
@ -202,7 +257,7 @@ class Repository
throw new \Exception('Wrong type'); throw new \Exception('Wrong type');
} }
return $this->run('add ' . $files . ' -v'); return implode("\n", $this->run('add ' . $files . ' -v'));
} }
public function rm($files = '*', bool $cached = false) : string public function rm($files = '*', bool $cached = false) : string
@ -216,9 +271,20 @@ class Repository
return $this->run('rm ' . ($cached ? '--cached ' : '') . $files); return $this->run('rm ' . ($cached ? '--cached ' : '') . $files);
} }
public function commit($msg = '', $all = true) : string /**
* Commit files.
*
* @param Commit $commit Commit to commit
* @param bool $all Commit all
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function commit(Commit $commit, $all = true) : string
{ {
return $this->run('commit ' . ($all ? '-av' : '-v') . ' -m' . escapeshellarg($msg)); return implode("\n", $this->run('commit ' . ($all ? '-av' : '-v') . ' -m ' . escapeshellarg($commit->getMessage())));
} }
public function cloneTo(string $target) : string public function cloneTo(string $target) : string
@ -248,19 +314,41 @@ class Repository
return $this->run('clone ' . $source . ' ' . $this->path); return $this->run('clone ' . $source . ' ' . $this->path);
} }
/**
* Clean.
*
* @param bool $dirs Directories?
* @param bool $force Force?
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function clean(bool $dirs = false, bool $force = false) : string public function clean(bool $dirs = false, bool $force = false) : string
{ {
return $this->run('clean ' . ($force ? ' -f' : '') . ($dirs ? ' -d' : '')); return implode("\n", $this->run('clean' . ($force ? ' -f' : '') . ($dirs ? ' -d' : '')));
} }
public function createBranch(string $branch, bool $force = false) : string /**
* Create local branch.
*
* @param Branch $branch Branch
* @param bool $force Force?
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function createBranch(Branch $branch, bool $force = false) : string
{ {
return $this->run('branch ' . ($force ? '-D' : '-d') . ' ' . $branch); return implode("\n", $this->run('branch ' . ($force ? '-D' : '-d') . ' ' . $branch->getName()));
} }
public function getBranches() : array public function getBranches() : array
{ {
$branches = explode('\n', $this->run('branch')); $branches = $this->run('branch');
foreach ($branches as $key => &$branch) { foreach ($branches as $key => &$branch) {
$branch = trim($branch); $branch = trim($branch);
@ -275,7 +363,7 @@ class Repository
public function getBranchesRemote() : array public function getBranchesRemote() : array
{ {
$branches = explode("\n", $this->run('branch -r')); $branches = $this->run('branch -r');
foreach ($branches as $key => &$branch) { foreach ($branches as $key => &$branch) {
$branch = trim($branch); $branch = trim($branch);
@ -288,120 +376,257 @@ class Repository
return $branches; return $branches;
} }
/**
* Get active Branch.
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getActiveBranch() : string public function getActiveBranch() : string
{ {
$branches = $this->getBranches(); if (!isset($branch)) {
$active = preg_grep('/^\*/', $branches); $branches = $this->getBranches();
reset($active); $active = preg_grep('/^\*/', $branches);
reset($active);
return current($active); $this->branch = new Branch(current($active));
}
return $this->branch;
} }
public function checkout($branch) : string /**
* Checkout.
*
* @param Branch $branch Branch to checkout
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function checkout(Branch $branch) : string
{ {
return $this->run('checkout ' . $branch); $result = implode("\n", $this->run('checkout ' . $branch->getName()));
$this->branch = null;
return $result;
} }
public function merge($branch) : string /**
* Merge with branch.
*
* @param Branch $branch Branch to merge from
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function merge(Branch $branch) : string
{ {
return $this->run('merge ' . $branch . ' --no-ff'); return implode("\n", $this->run('merge ' . $branch->getName() . ' --no-ff'));
} }
/**
* Fetch.
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function fetch() : string public function fetch() : string
{ {
return $this->run('fetch'); return implode("\n", $this->run('fetch'));
} }
public function addTag(string $tag, string $message = null) : string /**
* Create tag.
*
* @param Tag $tag Tag to create
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function createTag(Tag $tag) : string
{ {
return $this->run('tag -a ' . $tag . ' -m ' . escapeshellarg($message ?? $tag)); return implode("\n", $this->run('tag -a ' . $tag->getName() . ' -m ' . escapeshellarg($tag->getMessage())));
} }
public function getTags(string $pattern) : string /**
* Get all tags.
*
* @param string $pattern Tag pattern
*
* @return Tag[]
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getTags(string $pattern = '') : array
{ {
$tags = explode('\n', $this->run('tag -l ' . $pattern)); $pattern = empty($pattern) ? ' -l ' . $pattern : '';
$lines = $this->run('tag' . $pattern);
$tags = [];
foreach ($tags as $key => &$tag) { foreach ($lines as $key => $tag) {
$tag = trim($tag); $tags[$tag] = new Tag($tag);
if ($tag === '') {
unset($tags[$key]);
}
} }
return $tags; return $tags;
} }
public function push(string $remote, string $branch) : string /**
* Push.
*
* @param string $remote Remote repository
* @param Branch $branch Branch to pull
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function push(string $remote, Branch $branch) : string
{ {
return $this->run('push --tags ' . $remote . ' ' . $branch); $remote = escapeshellarg($remote);
return implode("\n", $this->run('push --tags ' . $remote . ' ' . $branch->getName()));
} }
public function pull(string $remote, string $branch) : string /**
* Pull.
*
* @param string $remote Remote repository
* @param Branch $branch Branch to pull
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function pull(string $remote, Branch $branch) : string
{ {
return $this->run('pull ' . $remote . ' ' . $branch); $remote = escapeshellarg($remote);
}
return implode("\n", $this->run('pull ' . $remote . ' ' . $branch->getName()));
public function log(string $format = null) : string
{
return !isset($format) ? $this->run('log') : $this->run('log --pretty=format:"' . $format . '"');
} }
/**
* Set repository description.
*
* @param string $description Repository description
*
* @return void
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function setDescription(string $description) public function setDescription(string $description)
{ {
file_put_contents($this->getDirectoryPath(), $description); file_put_contents($this->getDirectoryPath(), $description);
} }
/**
* Get repository description.
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getDescription() : string public function getDescription() : string
{ {
return file_get_contents($this->getDirectoryPath() . '/description'); return file_get_contents($this->getDirectoryPath() . '/description');
} }
/**
* Set environment value.
*
* @param string $key Key
* @param string $value Value
*
* @return void
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function setEnv(string $key, string $value) public function setEnv(string $key, string $value)
{ {
$this->envOptions[$key] = $value; $this->envOptions[$key] = $value;
} }
/**
* Get commit by id.
*
* @param string $commit Commit id
*
* @return Commit
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getCommit(string $commit) : Commit public function getCommit(string $commit) : Commit
{ {
return $this->run('log --format=%B -n 1 ' . $commit); $commit = escapeshellarg($commit);
$lines = $this->run('log show --name-only ' . $commit);
$count = count($lines);
preg_match('/[0-9ABCDEFabcdef]{40}/', $lines[0], $matches);
$author = explode(':', $lines[1]);
$author = explode('<', trim($author[1]));
$date = explode(':', $lines[2]);
$commit = new Commit($matches[0]);
$commit->setAuthor(new Author(trim($author[0]), rtrim($author[1], '>')));
$commit->setDate(new \DateTime(trim($date[1])));
$commit->setMessage($lines[3]);
$commit->setTag(new Tag());
$commit->setRepository($this);
$commit->setBranch($this->branch);
for ($i = 4; $i < $count; $i++) {
$commit->addFile($lines[$i]);
}
return $commit;
} }
/** /**
* Count Commits. * Count commits.
* *
* @return string * @param \DateTime $start Start date
* @param \DateTime $end End date
*
* @return array
* *
* @since 1.0.0 * @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com> * @author Dennis Eichhorn <d.eichhorn@oms.com>
*/ */
public function getCommitsCount(\DateTime $start = null, \DateTime $end = null, Author $author = null) : int public function getCommitsCount(\DateTime $start = null, \DateTime $end = null) : array
{ {
$result = $this->normalizeResult($this->run('shortlog -s -n --all')); if (!isset($start)) {
$start = new \DateTime('1970-12-31');
}
return ['']; if (!isset($end)) {
} $end = new \DateTime('now');
}
private function normalizeResult(string $result) : string $lines = $this->run('shortlog -s -n --since="' . $start->format('Y-m-d') . '" --before="' . $end->format('Y-m-d') . '" --all');
{ $commits = [];
str_replace('\t', '|', trim($result));
}
/** foreach ($lines as $line) {
* Get commits by author. $count = explode('|', $line);
* $commits[$count[1]] = $count[0];
* @param Author $author Commits by author }
* @param \DateTime $start Commits from
* @param \DateTime $end Commits to return $commits;
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getCommitsBy(Author $author, \DateTime $start = null, \DateTime $end) : array
{
return $this->run('git log --before="' . $end->format('Y-m-d') . '" --after="' . $start->format('Y-m-d') . '" --author="' . $author->getName() . '" --reverse --pretty=format:"%cd %h %s" --date=short');
} }
/** /**
@ -417,6 +642,50 @@ class Repository
return $this->run('config --get remote.origin.url'); return $this->run('config --get remote.origin.url');
} }
/**
* Get commits by author.
*
* @param \DateTime $start Commits from
* @param \DateTime $end Commits to
* @param Author $author Commits by author
*
* @return Commit[]
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getCommitsBy(\DateTime $start = null, \DateTime $end = null, Author $author = null) : array
{
if (!isset($start)) {
$start = new \DateTime('1970-12-31');
}
if (!isset($end)) {
$end = new \DateTime('now');
}
if (!isset($author)) {
$author = '';
} else {
$author = ' --author="' . $author->getName() . '"';
}
$lines = $this->run('git log --before="' . $end->format('Y-m-d') . '" --after="' . $start->format('Y-m-d') . '"' . $author . ' --reverse --date=short');
$count = count($lines);
$commits = [];
for ($i = 0; $i < $count; $i++) {
$match = preg_match('/[0-9ABCDEFabcdef]{40}/', $lines[$i], $matches);
if ($match !== false && $match !== 0) {
$commit = $this->getCommit($matches[0]);
$commits[$commit->getId()] = $commit;
}
}
return $commits;
}
/** /**
* Get newest commit. * Get newest commit.
* *
@ -425,8 +694,12 @@ class Repository
* @since 1.0.0 * @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com> * @author Dennis Eichhorn <d.eichhorn@oms.com>
*/ */
public function getNewest() : string public function getNewest() : Commit
{ {
return $this->run('log --name-status HEAD^..HEAD'); $lines = $this->run('log --name-status HEAD^..HEAD');
preg_match('[0-9ABCDEFabcdef]{40}', $lines[0], $matches);
return $this->getCommit($matches[0]);
} }
} }

View File

@ -28,5 +28,72 @@ namespace phpOMS\Utils\Git;
*/ */
class Tag class Tag
{ {
/**
* Name.
*
* @var string
* @since 1.0.0
*/
private $name = '';
/**
* Message.
*
* @var string
* @since 1.0.0
*/
private $message = '';
/**
* Constructor
*
* @param string $name Tag name/version
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function __construct(string $name = '')
{
$this->name = escapeshellarg($name);
}
/**
* Set tag name
*
* @param string $message Tag message
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function setMessage(string $message)
{
$this->message = escapeshellarg($message);
}
/**
* Get tag message
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getMessage() : string
{
return $this->message;
}
/**
* Get tag name
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getName() : string
{
return $this->name;
}
} }