Issue 112: Missing git information for some files (final fix)

This commit is contained in:
Nathan Adams 2016-04-23 12:01:09 -05:00
parent 1fdddf2501
commit 3f699e0afd
3 changed files with 130 additions and 54 deletions

View File

@ -0,0 +1,29 @@
<?php
function IDF_Migrations_32ExternalFile_up()
{
$table = Pluf::factory('IDF_Scm_Cache_Git')->getSqlTable();
$sql = array();
$sql["MySQL"] = "ALTER TABLE " . $table . " CHANGE COLUMN `githash` TEXT NOT NULL DEFAULT '' AFTER `project`;";
$db = Pluf::db();
$engine = Pluf::f('db_engine');
$db->execute($sql[$engine]);
}
function IDF_Migrations_32ExternalFile_down()
{
$table = Pluf::factory('IDF_Scm_Cache_Git')->getSqlTable();
$sql = array();
$sql["MySQL"] = "ALTER TABLE " . $table . " CHANGE COLUMN `githash` VARCHAR(40) NOT NULL AFTER `project`;";
$db = Pluf::db();
$engine = Pluf::f('db_engine');
$db->execute($sql[$engine]);
}

View File

@ -50,10 +50,10 @@ class IDF_Scm_Cache_Git extends Pluf_Model
*/ */
public function store($infos) public function store($infos)
{ {
foreach ($infos as $blob) { foreach ($infos as $key => $blob) {
$cache = new IDF_Scm_Cache_Git(); $cache = new IDF_Scm_Cache_Git();
$cache->project = $this->_project; $cache->project = $this->_project;
$cache->githash = $blob->hash; $cache->githash = $key;
$blob->title = IDF_Commit::toUTF8($blob->title); $blob->title = IDF_Commit::toUTF8($blob->title);
$cache->content = IDF_Commit::toUTF8($blob->date) . chr(31) $cache->content = IDF_Commit::toUTF8($blob->date) . chr(31)
. IDF_Commit::toUTF8($blob->author) . chr(31) . IDF_Commit::toUTF8($blob->author) . chr(31)
@ -123,9 +123,8 @@ class IDF_Scm_Cache_Git extends Pluf_Model
), ),
'githash' => 'githash' =>
array( array(
'type' => 'Pluf_DB_Field_Varchar', 'type' => 'Pluf_DB_Field_Text',
'blank' => false, 'blank' => false,
'size' => 40,
'index' => true, 'index' => true,
), ),
'content' => 'content' =>

View File

@ -343,7 +343,7 @@ class IDF_Scm_Git extends IDF_Scm
$res[] = $file; $res[] = $file;
} }
// Grab the details for each blob and return the list. // Grab the details for each blob and return the list.
return $this->getTreeDetails($res); return $this->getTreeDetails($res, $commit);
} }
/** /**
@ -718,13 +718,13 @@ class IDF_Scm_Git extends IDF_Scm
* @param array Tree information * @param array Tree information
* @return array Updated tree information * @return array Updated tree information
*/ */
public function getTreeDetails($tree) public function getTreeDetails($tree, $commit)
{ {
$n = count($tree); $n = count($tree);
$details = array(); $details = array();
for ($i=0;$i<$n;$i++) { for ($i=0;$i<$n;$i++) {
if ($tree[$i]->type == 'blob') { if ($tree[$i]->type == 'blob') {
$details[sha1($tree[$i]->hash . $tree[$i]->fullpath)] = $i; $details[sha1($tree[$i]->hash . $tree[$i]->fullpath) . ":" . $tree[$i]->hash . ":" . $tree[$i]->fullpath] = $i;
} }
} }
if (!count($details)) { if (!count($details)) {
@ -742,7 +742,7 @@ class IDF_Scm_Git extends IDF_Scm
} }
} }
if (count($toapp)) { if (count($toapp)) {
$res = $this->appendBlobInfoCache($toapp); $res = $this->appendBlobInfoCache($toapp, $commit);
foreach ($details as $blob => $idx) { foreach ($details as $blob => $idx) {
if (isset($res[$blob])) { if (isset($res[$blob])) {
$tree[$idx]->date = $res[$blob]->date; $tree[$idx]->date = $res[$blob]->date;
@ -766,62 +766,110 @@ class IDF_Scm_Git extends IDF_Scm
* @param array The blob for which we need the information * @param array The blob for which we need the information
* @return array The information * @return array The information
*/ */
public function appendBlobInfoCache($blobs) public function appendBlobInfoCache($blobs, $commit)
{ {
$rawlog = array(); $rawlog = array();
$cmd = Pluf::f('idf_exec_cmd_prefix', '') $cmd = Pluf::f('idf_exec_cmd_prefix', '')
.sprintf('GIT_DIR=%s '.Pluf::f('git_path', 'git').' log --raw --abbrev=40 --pretty=oneline -5000 --skip=%%s', .sprintf('GIT_DIR=%s '.Pluf::f('git_path', 'git').' log --raw --abbrev=40 --pretty=oneline -5000 --skip=%%s %s',
escapeshellarg($this->repo)); escapeshellarg($this->repo), $commit);
$skip = 0; $skip = 0;
$res = array(); $res = array();
self::exec('IDF_Scm_Git::appendBlobInfoCache', self::exec('IDF_Scm_Git::appendBlobInfoCache',
sprintf($cmd, $skip), $rawlog); sprintf($cmd, $skip), $rawlog);
while (count($rawlog) and count($blobs)) {
$rawlog = implode("\n", array_reverse($rawlog)); $fileinfoarr = [];
$tmpRes = []; $lookup = [];
foreach(explode("\n", $rawlog) as $line) { $cache = [];
if ($line[0] != ":") { //This is the commit number line
$commit = explode(" ", $line)[0]; $currentcommit = null;
$fc = $this->getCommit($commit);
foreach($tmpRes as $r) { $rawlog = implode("\n", array_reverse($rawlog));
$res[$r["hash"]] = (object) [ foreach(explode("\n", $rawlog) as $line) {
"hash" => $r["hash"], if ($line[0] == ":") {
"date" => $fc->date, $matches = preg_split('/\s/', $line);
"title" => $fc->title, $currentFileHash = $matches[3];
"author" => $fc->author $file = $matches[5];
]; $fileinfoarr[] = [
} "filehash" => $currentFileHash,
$tmpRes = []; "file" => $file
} else { ];
$sides = explode("\t", $line); } else {
$leftSide = trim($sides[0]); $matches = preg_split('/\s/', $line);
$rightSide = trim($sides[1]); $currentcommit = $matches[0];
$leftSideSplit = explode(" ", $leftSide); if ($fileinfoarr) {
$newHash = sha1($leftSideSplit[3] . $rightSide); $lookup[$currentcommit] = $fileinfoarr;
$tmpRes[$newHash] = [ $fileinfoarr = [];
"hash" => $newHash
];
unset($blobs[$newHash]);
} }
} }
$rawlog = array();
$skip += 5000;
if ($skip > 20000) {
// We are in the case of the import of a big old
// repository, we can store as unknown the commit info
// not to try to retrieve them each time.
foreach ($blobs as $blob => $idx) {
$res[$blob] = (object) array('hash' => $blob,
'date' => '0',
'title' => '----',
'author' => 'Unknown');
}
break;
}
self::exec('IDF_Scm_Git::appendBlobInfoCache',
sprintf($cmd, $skip), $rawlog);
} }
$this->cacheBlobInfo($res);
$commitData = $this->getCommit($commit);
foreach($blobs as $blobKey => $blobVal) {
list($newhash, $hash, $file) = explode(":", $blobKey);
if (isset($lookup[$commitData->commit])) {
$test = $lookup[$commitData->commit];
} else {
if (isset($lookup[$commitData->parents[0]])) { //tag?
$test = $lookup[$commitData->parents[0]];
} else {
$test = [];
}
}
$found = false;
foreach($test as $fileinfo) {
if ($fileinfo["filehash"] == $hash && $fileinfo["file"] == $file) {
$found = true;
$res[$blobKey] = (object) [
"hash" => $newhash,
"date" => $commitData->date,
"title" => $commitData->title,
"author" => $commitData->author
];
$cache[$blobKey] = $res[$blobKey];
}
}
if (!$found) {
foreach ($lookup as $key=>$val) {
foreach($val as $fileinfo) {
if ($fileinfo["filehash"] == $hash && $fileinfo["file"] == $file) {
$commitTempData = $this->getCommit($key);
$res[$blobKey] = (object) [
"hash" => $newhash,
"date" => $commitTempData->date,
"title" => $commitTempData->title,
"author" => $commitTempData->author
];
$cache[$blobKey] = $res[$blobKey];
$found = true;
break;
}
}
}
}
// If it's still not found - find the first commit where it's modified and use that
if (!$found) {
foreach ($lookup as $key=>$val) {
foreach($val as $fileinfo) {
if ($fileinfo["file"] == $file) {
$commitTempData = $this->getCommit($key);
$res[$blobKey] = (object) [
"hash" => $newhash,
"date" => $commitTempData->date,
"title" => $commitTempData->title,
"author" => $commitTempData->author
];
$cache[$blobKey] = $res[$blobKey];
break;
}
}
}
}
}
$this->cacheBlobInfo($cache);
return $res; return $res;
} }