Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14058066
D7687.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
4 KB
Referenced Files
None
Subscribers
None
D7687.diff
View Options
Index: src/applications/diffusion/engine/DiffusionCommitHookEngine.php
===================================================================
--- src/applications/diffusion/engine/DiffusionCommitHookEngine.php
+++ src/applications/diffusion/engine/DiffusionCommitHookEngine.php
@@ -61,28 +61,27 @@
return $err;
}
+ /**
+ * @task git
+ */
private function executeGitHook() {
$updates = $this->parseGitUpdates($this->getStdin());
- // TODO: Do useful things.
+ // TODO: Do cheap checks: non-ff commits, mutating refs without access,
+ // creating or deleting things you can't touch. We can do all non-content
+ // checks here.
- return 0;
- }
-
- private function executeSubversionHook() {
+ $updates = $this->findGitNewCommits($updates);
- // TODO: Do useful things here, too.
+ // TODO: Now, do content checks.
return 0;
}
- private function executeMercurialHook() {
-
- // TODO: Here, too, useful things should be done.
-
- return 0;
- }
+ /**
+ * @task git
+ */
private function parseGitUpdates($stdin) {
$updates = array();
@@ -92,14 +91,109 @@
if (count($parts) != 3) {
throw new Exception(pht('Expected "old new ref", got "%s".', $line));
}
- $updates[] = array(
+ $update = array(
'old' => $parts[0],
+ 'old.short' => substr($parts[0], 0, 8),
'new' => $parts[1],
+ 'new.short' => substr($parts[1], 0, 8),
'ref' => $parts[2],
);
+
+ if (preg_match('(^refs/heads/)', $update['ref'])) {
+ $update['type'] = 'branch';
+ } else if (preg_match('(^refs/tags/)', $update['ref'])) {
+ $update['type'] = 'tag';
+ } else {
+ $update['type'] = 'unknown';
+ }
+
+ $updates[] = $update;
+ }
+
+ $updates = $this->findGitMergeBases($updates);
+
+ return $updates;
+ }
+
+
+ /**
+ * @task git
+ */
+ private function findGitMergeBases(array $updates) {
+ $empty = str_repeat('0', 40);
+
+ $futures = array();
+ foreach ($updates as $key => $update) {
+ // Updates are in the form:
+ //
+ // <old hash> <new hash> <ref>
+ //
+ // If the old hash is "00000...", the ref is being created (either a new
+ // branch, or a new tag). If the new hash is "00000...", the ref is being
+ // deleted. If both are nonempty, the ref is being updated. For updates,
+ // we'll figure out the `merge-base` of the old and new objects here. This
+ // lets us reject non-FF changes cheaply; later, we'll figure out exactly
+ // which commits are new.
+
+ if ($update['old'] == $empty) {
+ $updates[$key]['operation'] = 'create';
+ } else if ($update['new'] == $empty) {
+ $updates[$key]['operation'] = 'delete';
+ } else {
+ $updates[$key]['operation'] = 'update';
+ $futures[$key] = $this->getRepository()->getLocalCommandFuture(
+ 'merge-base %s %s',
+ $update['old'],
+ $update['new']);
+ }
+ }
+
+ foreach (Futures($futures)->limit(8) as $key => $future) {
+ list($stdout) = $future->resolvex();
+ $updates[$key]['merge-base'] = rtrim($stdout, "\n");
+ }
+
+ return $updates;
+ }
+
+ private function findGitNewCommits(array $updates) {
+ $futures = array();
+ foreach ($updates as $key => $update) {
+ if ($update['type'] == 'delete') {
+ // Deleting a branch or tag can never create any new commits.
+ continue;
+ }
+
+ // NOTE: This piece of magic finds all new commits, by walking backward
+ // from the new value to the value of *any* existing ref in the
+ // repository. Particularly, this will cover the cases of a new branch, a
+ // completely moved tag, etc.
+ $futures[$key] = $this->getRepository()->getLocalCommandFuture(
+ 'log --format=%s %s --not --all',
+ '%H',
+ $update['new']);
+ }
+
+ foreach (Futures($futures)->limit(8) as $key => $future) {
+ list($stdout) = $future->resolvex();
+ $commits = phutil_split_lines($stdout, $retain_newlines = false);
+ $updates[$key]['commits'] = $commits;
}
return $updates;
}
+ private function executeSubversionHook() {
+
+ // TODO: Do useful things here, too.
+
+ return 0;
+ }
+
+ private function executeMercurialHook() {
+
+ // TODO: Here, too, useful things should be done.
+
+ return 0;
+ }
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Nov 18, 9:17 AM (2 d, 1 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6738497
Default Alt Text
D7687.diff (4 KB)
Attached To
Mode
D7687: Do the heavy lifting for git commit hooks
Attached
Detach File
Event Timeline
Log In to Comment