9f13e1d5bd25a54a1514716be2455ade6c60169e
[web.mtrack] / MTrackWeb / Hook / Git / Bridge.php
1 <?php  
2
3
4 // needs to be run from git-recieve (and it has to be the only thing run.
5
6 class MTrackWeb_Hook_Git_Bridge extends  MTrackWeb_Hook_Bridge
7 {
8     
9     
10     var $repo;
11     var $files = array();
12     var $log = array();
13     var $commits = array();
14     var $fileActions = array(); // file=> delete / modify etc..
15     
16     /**
17     * fills up repo, files, log, commits by running log on the STDIN
18     */
19     function __construct($repo) 
20     {
21         
22         
23         
24         $this->repo = $repo;
25         
26         while (($line = fgets(STDIN)) !== false) {
27           
28             list($old, $new, $ref) = explode(' ', trim($line), 3);
29             $this->commits[] = $new;
30             
31             $fp = $this->repo->impl()->git('log', '--no-color', '--name-status',
32                             '--date=rfc', $ref, "$old..$new");
33               
34               
35             $props = array();
36             $line = fgets($fp);
37             if (!preg_match("/^commit\s+(\S+)$/", $line)) {
38                 throw new Exception("unexpected output from git log: $line");
39             }
40             // read key: value properties like Author: / Date: 
41             while (($line = fgets($fp)) !== false) {
42                 $line = rtrim($line);
43                 if (!strlen($line)) break;
44                 if (preg_match("/^(\S+):\s*(.*)\s*$/", $line, $M)) {
45                   $props[$M[1]] = $M[2];
46                 }
47             }
48             // read the commit log.
49             while (($line = fgets($fp)) !== false) {
50                 $line = rtrim($line);
51                 if (strncmp($line, '    ', 4)) {
52                   break;
53                 }
54                 $this->log[] = substr($line, 4);
55             }
56           
57           
58             do {
59                 if (preg_match("/^(.+)\s+(\S+)\s*$/", $line, $M)) {
60                     $st = $M[1];
61                     $file = $M[2];
62                     $this->files[$file] = $new;
63                     $this->fileActions[$file] = $st;
64                 }
65             
66             } while (($line = fgets($fp)) !== false);
67         }
68     }
69
70
71     function enumChangedOrModifiedFileNames()
72     {
73         $ret = array();
74         foreach($this->files as $f=>$com) {
75             if ($this->fileActions[$f] == 'D') {
76                 continue;
77             }
78             $ret[] = $f;
79         }
80         return $ret;
81     }
82
83     function getCommitMessage()
84     {
85         $log = join("\n", $this->log);
86         $log = preg_replace('/\[([a-fA-F0-9]+)\]/',
87           "[changeset:" . $this->repo->getBrowseRootName() . ",\$1]", $log);
88         return $log;
89     }
90
91     function getFileStream($path)
92     {
93         $rev = $this->files[$path];
94
95         // There may be a better way...
96         // ls-tree to determine the hash of the file from this change:
97         $fp = $this->repo->impl()->git('ls-tree', '-r', $rev, $path);
98         $line = fgets($fp);
99         $fp = null;
100         list($mode, $type, $hash, $name) = preg_split("/\s+/", $line);
101         // now we can cat that blob
102         return $this->repo->impl()->git('cat-file', 'blob', $hash);
103     }
104
105     function getChangesetDescriptor()
106     {
107         $cs = array();
108         foreach ($this->commits as $ref) {
109             $cs[] = '[changeset:' . $this->repo->getBrowseRootName() . ",$ref]";
110         }
111         return join(", ", $cs);
112     }
113 }