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 = '')
{
$this->name = $name;
$this->email = $email;
$this->name = escapeshellarg($name);
$this->email = escapeshellarg($email);
}
/**

View File

@ -46,7 +46,7 @@ class Branch
*/
public function __construct(string $name = '')
{
$this->name = $name;
$this->setName($name);
}
/**
@ -59,7 +59,7 @@ class Branch
*/
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 = '')
{
$this->id = escapeshellarg($id);
$this->author = new Author();
$this->branch = new Branch();
$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)
{
$path = escapeshellarg($path);
if (!isset($this->files[$path])) {
$this->files[$path] = [];
}
@ -164,7 +176,7 @@ class Commit
*/
public function setMessage(string $message)
{
$this->message = $message;
$this->message = escapeshellarg($message);
}
/**
@ -305,6 +317,21 @@ class Commit
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.
*

View File

@ -16,6 +16,7 @@
namespace phpOMS\Utils\Git;
use phpOMS\System\File\PathException;
use phpOMS\Validation\Validator;
/**
* Repository class
@ -54,6 +55,14 @@ class Repository
*/
private $envOptions = [];
/**
* Current branch.
*
* @var Branch
* @since 1.0.0
*/
private $branch = null;
/**
* Constructor
*
@ -64,6 +73,7 @@ class Repository
*/
public function __construct(string $path)
{
$this->branch = $this->getActiveBranch();
$this->setPath($path);
}
@ -109,13 +119,16 @@ class Repository
$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')) {
$this->bare = false;
// Is this a bare repo?
} elseif (is_file($this->path . '/config')) {
$parse_ini = parse_ini_file($this->path . '/config');
} elseif (is_file($this->path . '/config')) { // Is this a bare repo?
$parseIni = parse_ini_file($this->path . '/config');
if ($parse_ini['bare']) {
if ($parseIni['bare']) {
$this->bare = true;
}
}
@ -126,14 +139,14 @@ class Repository
*
* @param string $cmd Command to run
*
* @return string
* @return array
*
* @throws \Exception
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
private function run(string $cmd) : string
private function run(string $cmd) : array
{
$cmd = Git::getBin() . ' ' . $cmd;
$pipes = [];
@ -165,7 +178,37 @@ class Repository
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
{
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)) {
$files = '"' . implode('" "', $files) . '"';
@ -202,7 +257,7 @@ class Repository
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
@ -216,9 +271,20 @@ class Repository
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
@ -248,19 +314,41 @@ class Repository
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
{
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
{
$branches = explode('\n', $this->run('branch'));
$branches = $this->run('branch');
foreach ($branches as $key => &$branch) {
$branch = trim($branch);
@ -275,7 +363,7 @@ class Repository
public function getBranchesRemote() : array
{
$branches = explode("\n", $this->run('branch -r'));
$branches = $this->run('branch -r');
foreach ($branches as $key => &$branch) {
$branch = trim($branch);
@ -288,120 +376,257 @@ class Repository
return $branches;
}
/**
* Get active Branch.
*
* @return string
*
* @since 1.0.0
* @author Dennis Eichhorn <d.eichhorn@oms.com>
*/
public function getActiveBranch() : string
{
$branches = $this->getBranches();
$active = preg_grep('/^\*/', $branches);
reset($active);
if (!isset($branch)) {
$branches = $this->getBranches();
$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
{
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) {
$tag = trim($tag);
if ($tag === '') {
unset($tags[$key]);
}
foreach ($lines as $key => $tag) {
$tags[$tag] = new Tag($tag);
}
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);
}
public function log(string $format = null) : string
{
return !isset($format) ? $this->run('log') : $this->run('log --pretty=format:"' . $format . '"');
$remote = escapeshellarg($remote);
return implode("\n", $this->run('pull ' . $remote . ' ' . $branch->getName()));
}
/**
* 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)
{
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
{
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)
{
$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
{
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
* @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
{
str_replace('\t', '|', trim($result));
}
$lines = $this->run('shortlog -s -n --since="' . $start->format('Y-m-d') . '" --before="' . $end->format('Y-m-d') . '" --all');
$commits = [];
/**
* Get commits by author.
*
* @param Author $author Commits by author
* @param \DateTime $start Commits from
* @param \DateTime $end Commits to
*
* @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');
foreach ($lines as $line) {
$count = explode('|', $line);
$commits[$count[1]] = $count[0];
}
return $commits;
}
/**
@ -417,6 +642,50 @@ class Repository
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.
*
@ -425,8 +694,12 @@ class Repository
* @since 1.0.0
* @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
{
/**
* 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;
}
}