2 const GLib = imports.gi.GLib;
4 const XObject = imports.XObject.XObject;
5 const Event = imports.Scm.Git.Event.Event;
6 const Spawn = imports.Spawn.Spawn;
7 const File = imports.File.File;
10 Repo = XObject.define(
13 XObject.extend(this,cfg);
14 this.gitdir = cfg.repopath + "/.git";
16 if (!File.isDirectory(this.gitdir)) {
17 this.gitdir = this.repopath;
19 //Repo.superclass.constructor.call(this,cfg);
22 imports.Scm.Repo.Repo, // or Object
30 getMetaData : function() {
37 getBranches : function()
39 if (this.branches !== false) {
44 var bl = this.git([ 'branch', {
50 bl.forEach(function(line) {
51 // * master 61e7e7d oneliner
52 var active = line[0]=='*';
53 line = line.substring(2);
55 var parts = line.split(/\s+/);
56 if (parts[0] == '->') {
57 return; // it's an alias like remotes/origin/HEAD -> origin/master
59 this.branches[parts[0]] = parts[1];
61 this.curBranch = parts[0];
68 public function getTags()
70 if ($this->tags !== null) {
73 $this->tags = array();
74 $fp = $this->git('tag');
75 while ($line = fgets($fp)) {
77 $this->tags[$line] = $line;
83 public function readdir($path, $object = null, $ident = null)
87 if ($object === null) {
91 $rev = $this->resolveRevision(null, $object, $ident);
94 $path = rtrim($path, '/') . '/';
97 $fp = $this->git('ls-tree', $rev, $path);
100 require_once 'MTrack/SCM/Git/File.php';
101 while ($line = fgets($fp)) {
102 // blob = file, tree = dir..
103 list($mode, $type, $hash, $name) = preg_split("/\s+/", $line);
104 //echo '<PRE>';echo $line ."\n</PRE>";
105 $res[] = new MTrack_SCM_Git_File($this, "$name", $rev, $type == 'tree', $hash);
110 public function file($path, $object = null, $ident = null)
112 if ($object == null) {
113 $branches = $this->getBranches();
114 if (isset($branches['master'])) {
122 $rev = $this->resolveRevision(null, $object, $ident);
123 require_once 'MTrack/SCM/Git/File.php';
124 return new MTrack_SCM_Git_File($this, $path, $rev);
129 * @param string path (can be empty - eg. '')
130 * @param {number|date} limit how many to fetch
131 * @param {string} object = eg. rev|tag|branch (use 'rev' here and ident=HASH to retrieve a speific revision
132 * @param {string} ident =
135 * - fetch on revision?: '.',1,'rev','xxxxxxxxxx'
138 * range... object ='rev' ident ='master..release'
141 history: function(path, limit , object, ident)
143 limit = limit || false;
144 object = object || false;
145 ident = ident || false;
147 var args = [ 'log' ];
150 if (object !== false) {
151 rev = this.resolveRevision(false, object, ident); // from scm...
152 args.push( '' + rev);
154 args.push( "master" );
159 //args.push("--name-status";
165 if (limit !== false) {
166 if (typeof(limit) == 'number') {
167 arg['max-count'] = limit;
168 } else if (typeof(limit) == 'object') {
170 arg['max-count']= limit[1];
183 //echo '<PRE>';print_r($args);echo '</PRE>';
184 path = path[0] == '/' ? path.substring(1) : path;
186 args.push({ '' : true });
189 // print_R(array($args, '--' ,$path));exit;
190 var fp = this.git(args).split("\n");
195 var line = fp.shift() + "\n";
197 if (line.match(/^commit/)) {
198 if (commit !== false) {
199 commits.push( commit );
207 if (commit !== false) {
208 commits.push( commit );
211 //print(JSON.stringify(commits,null,4));
214 commits.forEach( function(c) {
215 // print(typeof(Event)); print(JSON.stringify(c));
216 var ev = new Event( {commit : c, repo: _t });
223 diff : function(path, from, to)
226 from = from || false;
232 if ($path instanceof MTrackSCMFile) {
233 if ($from === null) {
239 // if it's a file event.. we are even lucker..
240 if ($path instanceof MTrackSCMFileEvent) {
241 return $this->git('log', '--max-count=1', '--format=format:', '--patch', $from, '--', $path->name);
245 // diff ignoring white space..
246 args = [ 'diff' , { 'w' : true} ]
253 args.push(from+'..'+to);
254 args.push( { '' : true });
255 if (typeof(path) != 'string') {
256 path.forEach(function(p) { args.push(p); })
258 return this.git(args);
263 dayTree: function (path, limit , object, ident)
266 var ar = this.history(path, limit , object, ident);
268 // the point of this is to extract all the revisions, and group them.
272 //echo '<PRE>';print_R($ar);
274 // need to get a 2 dimensional array of
275 // files along top, and commints down.
281 ar.forEach(function( commit) {
283 var files = commit.files;
284 var day = commit.cday;
285 if (typeof(days[day]) == 'undefined') {
292 var time= commit.ctime;
293 if (typeof(days[day]['children'][time]) == 'undefined' ) {
294 days[day]['children'][time] = {
296 'rev' : day + ' ' + time,
300 days[day]['children'][time]['children'].push( {
301 'text' : commit.changelog,
310 dcn = dr['children'];
314 to['rev'] = to['children'][0]['rev'];
315 dr['children'].push( to);
317 dr['rev'] = dr['children'][0]['rev'];
329 changedFiles :function(path, object, ident)
331 object = object || false;
332 ident = ident || false;
334 var args = [ 'diff', { 'numstat' : true} , { 'w' : true } ];
337 if (object !== false) {
338 rev = this.resolveRevision(false, object, ident); // from scm...
339 args.push( '' + rev);
341 args.push( "master" );
343 path = path[0] == '/' ? path.substring(1) : path;
345 args.push({ '' : true });
347 // in theory you could click a number of them and only merge those changes..
348 // need to do a git diff.. and just get a list of files..
350 var res = this.git(args).split("\n");
351 res.forEach( function(line) {
355 var ar = line.split("\t");
356 if (ar.length !=3 ) {
377 merge : function(branch_from, branch_to, rev, files, use_merge)
380 var mi = this.history("/", 1, "rev", rev);
381 // echo '<PRE>';print_R($mi);exit;
384 this.git([ 'checkout', { 'b': true }, to]);
385 //$wd->git('checkout', '-b', $this->release, 'remotes/origin/'. $this->release);
389 //$patchfile = $this->tempName('txt');
392 if (files !== false) {
397 if (is_array($files)) {
399 var diff = this.diff(files, from, to);
404 args : [ 'patch' , '-p1' ] ,
405 env : [ "HOME=" + GLib.get_home_dir() ],
417 ; //eg . patch -p1 < /var/lib/php5/MTrackTMPgZFeAN.txt
419 // if no files -- it means all?/
420 // although we should check to see if this is valid..
421 this.git([' merge', { 'squash' : true }, rev ]);
426 $commit = (object) array(
427 'when' => $mi[0]->ctime,
428 'reason' => $_REQUEST['message'],
429 'name' => $this->authUser->name,
430 'email' => $this->authUser->email,
433 $res = $wd->commit($commit);
434 if (!is_array($files)) {
435 // we do an actually merge commit seperatly from the merge diff, so that
436 // our logs show a nice history in each of those commits.
437 // not sure if this is a good idea or not..
438 $wd->git('merge', '-m', "Merge Commit with working branch (no code changed)" , $rev);
445 // $wd->checkout($this->release);
446 // generate the patch
448 // commit with message..
465 public function getWorkingCopy()
467 require_once 'MTrack/SCM/Git/WorkingCopy.php';
468 return new MTrack_SCM_Git_WorkingCopy($this);
471 public function getRelatedChanges($revision) // pretty nasty.. could end up with 1000's of changes..
476 $fp = $this->git('rev-parse', "$revision^");
477 while (($line = fgets($fp)) !== false) {
478 $parents[] = trim($line);
481 // Ugh!: http://stackoverflow.com/questions/1761825/referencing-the-child-of-a-commit-in-git
482 $fp = $this->git('rev-list', '--all', '--parents');
483 while (($line = fgets($fp)) !== false) {
484 $hashes = preg_split("/\s+/", $line);
485 $kid = array_shift($hashes);
486 if (in_array($revision, $hashes)) {
491 return array($parents, $kids);
497 git: function(args_in)
499 // convert arguments.
501 //print(JSON.stringify(args_in,null,4));
503 'git-dir' : this.gitdir,
508 if (this.gitdir != this.repopath) {
509 args_in.unshift( { "work-tree" : this.gitdir } );
512 args_in.forEach(function(arg) {
513 if (typeof(arg) == 'string') {
517 if (typeof(arg) == 'object') {
521 args.push(k.length != 1 ? ('--' + k) : ('-' + k));
530 this.lastCmd = args.join(" ");
533 print( args.join(" "));
536 var env = [ "HOME=" + GLib.get_home_dir() ];
537 // do not need to set gitpath..
538 //if (File.exists(this.repo + '/.git/config')) {
539 //env.push("GITPATH=" + this.repo );
542 //print(JSON.stringify(args,null,4)); Seed.quit();
546 env : env, // optional
552 //print(JSON.stringify(sp,null,4)); Seed.quit();
554 //print("GOT: " + output)
555 // parse output for some commands ?