2 <?php # vim:ts=2:sw=2:et:ft=php:
3 /* For licensing and copyright terms, see the file named LICENSE */
5 // hg-commit-hook what [mtrackconfig]
6 // the cwd is the repo path
7 die("MAKE INTO CLASS");
8 putenv("GATEWAY_INTERFACE=");
11 if (isset($argv[2])) {
12 putenv("MTRACK_CONFIG_FILE=" . $argv[2]);
14 include dirname(__FILE__) . '/../inc/common.php';
15 if (file_exists(MTrackConfig::get('core', 'vardir') . '/.initializing')) {
19 ini_set('display_errors', true);
20 $HG = MTrackConfig::get('tools', 'hg');
24 $HG_NODE = $_ENV['HG_NODE'];
25 if (!isset($_ENV['HG_PARENT1']) || !strlen($_ENV['HG_PARENT1'])) {
26 # figure out the parent
27 $p = stream_get_contents(run($HG, 'log', "-r$HG_NODE",
28 '--template', '{parents}'));
29 foreach (preg_split("/\s+/", $p) as $item) {
30 if (preg_match("/^(\d+):(\S+)$/", $item, $M)) {
38 $HG_PARENT1 = $_ENV['HG_PARENT1'];
42 class HgCommitHookBridge implements IMTrackCommitHookBridge2 {
44 function __construct($repo) {
48 function getChanges() {
52 $log = popen("$HG log -r$HG_NODE: --template '{node|short}\n{author|email}\n{date|hgdate}\n{desc|nonempty|tabindent}\n'", 'r');
55 $c = new MTrackCommitHookChangeEvent;
59 $c->rev = "[changeset:" . $this->repo->getBrowseRootName() . ",$node]";
61 $author = trim(fgets($log));
62 $c->changeby = mtrack_canon_username($author);
65 if (!preg_match("/^(\d+)\s+\d+$/", $date, $M)) {
66 throw new Exception("failed to parse date $date");
68 $c->ctime = MTrackDB::unixtime((int)$M[1]);
73 if ($line === false) {
76 if (preg_match("/^[a-fA-F0-9]+$/", $line)) {
79 $msg .= substr($line, 1);
81 $c->changelog = rtrim($msg);
83 } while ($line !== false);
88 function enumChangedOrModifiedFileNames() {
93 $fp = popen("$HG log -r$HG_NODE: --template '{files}\n'", 'r');
94 while (($line = fgets($fp)) !== false) {
95 foreach (preg_split("/\s+/", $line) as $path) {
104 function getCommitMessage() {
107 $fp = popen("$HG log -r$HG_NODE: --template '{desc}\n\n'", 'r');
108 $log = stream_get_contents($fp);
109 $log = preg_replace('/\[(\d+)\]/',
110 "[changeset:" . $this->repo->getBrowseRootName() . ",\$1]", $log);
114 function getFileStream($path) {
117 return popen("$HG cat $path", 'r');
120 function getChangesetDescriptor() {
124 $nodes = popen("$HG log -r$HG_NODE: --template '{node|short}\n'", 'r');
125 while (($line = fgets($nodes)) !== false) {
127 $cs[] = '[changeset:' . $this->repo->getBrowseRootName() . ",$n]";
129 return join(", ", $cs);
134 $repo = MTrackRepo::loadByLocation(getcwd());
135 $bridge = new HgCommitHookBridge($repo);
136 /* for pushes, respect OS indication of who this is, unless we don't
137 * know; we'll use the info from the changeset in that case */
138 $author = 'anonymous';
139 if (strstr($action, 'group')) {
140 $author = MTrackAuth::whoami();
142 if ($author == 'anonymous') {
144 shell_exec("$HG log -r$HG_NODE: --template '{author|email}'"));
146 $author = mtrack_canon_username($author);
147 MTrackAuth::su($author);
148 $checker = new MTrackCommitChecker($repo);
151 case 'pretxnchangegroup':
152 $checker->preCommit($bridge);
155 $checker->postCommit($bridge);
158 } catch (Exception $e) {
159 /* Errors must render to STDERR, or they won't show up in the hg client */
160 fwrite(STDERR, "\n" . $e->getMessage() .
162 $e->getTraceAsString() .
163 "\n\n ** Commit failed [$action]\n");
170 $args = func_get_args();
172 foreach ($args as $a) {
174 foreach ($a as $arg) {
184 foreach ($all_args as $i => $arg) {
188 $cmd .= escapeshellarg($arg);
192 return popen($cmd, 'r');