@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class DiffusionLastModifiedQueryConduitAPIMethod
4 extends DiffusionQueryConduitAPIMethod {
5
6 public function getAPIMethodName() {
7 return 'diffusion.lastmodifiedquery';
8 }
9
10 public function getMethodDescription() {
11 return pht('Get the commits at which paths were last modified.');
12 }
13
14 protected function defineReturnType() {
15 return 'map<string, string>';
16 }
17
18 protected function defineCustomParamTypes() {
19 return array(
20 'paths' => 'required map<string, string>',
21 );
22 }
23
24 protected function getGitResult(ConduitAPIRequest $request) {
25 $drequest = $this->getDiffusionRequest();
26 $repository = $drequest->getRepository();
27
28 $paths = $request->getValue('paths');
29 $results = $this->loadCommitsFromCache($paths);
30
31 foreach ($paths as $path => $commit) {
32 if (array_key_exists($path, $results)) {
33 continue;
34 }
35 list($hash) = $repository->execxLocalCommand(
36 'log -n1 %s %s -- %s',
37 '--format=%H',
38 gitsprintf('%s', $commit),
39 $path);
40 $results[$path] = trim($hash);
41 }
42
43 return $results;
44 }
45
46 protected function getSVNResult(ConduitAPIRequest $request) {
47 $drequest = $this->getDiffusionRequest();
48 $repository = $drequest->getRepository();
49
50 $results = array();
51 foreach ($request->getValue('paths') as $path => $commit) {
52 $history_result = DiffusionQuery::callConduitWithDiffusionRequest(
53 $request->getUser(),
54 $drequest,
55 'diffusion.historyquery',
56 array(
57 'commit' => $commit,
58 'path' => $path,
59 'limit' => 1,
60 'offset' => 0,
61 'needDirectChanges' => true,
62 'needChildChanges' => true,
63 ));
64
65 $history_array = DiffusionPathChange::newFromConduit(
66 $history_result['pathChanges']);
67 if ($history_array) {
68 $results[$path] = head($history_array)
69 ->getCommit()
70 ->getCommitIdentifier();
71 }
72 }
73
74 return $results;
75 }
76
77 protected function getMercurialResult(ConduitAPIRequest $request) {
78 $drequest = $this->getDiffusionRequest();
79 $repository = $drequest->getRepository();
80
81 $paths = $request->getValue('paths');
82 $results = $this->loadCommitsFromCache($paths);
83
84 foreach ($paths as $path => $commit) {
85 if (array_key_exists($path, $results)) {
86 continue;
87 }
88
89 list($hash) = $repository->execxLocalCommand(
90 'log --template %s --limit 1 --removed --rev %s -- %s',
91 '{node}',
92 hgsprintf('reverse(ancestors(%s))', $commit),
93 nonempty(ltrim($path, '/'), '.'));
94 $results[$path] = trim($hash);
95 }
96
97 return $results;
98 }
99
100 private function loadCommitsFromCache(array $map) {
101 $drequest = $this->getDiffusionRequest();
102 $repository = $drequest->getRepository();
103
104 $path_map = id(new DiffusionPathIDQuery(array_keys($map)))
105 ->loadPathIDs();
106
107 $commit_query = id(new DiffusionCommitQuery())
108 ->setViewer($drequest->getUser())
109 ->withRepository($repository)
110 ->withIdentifiers(array_values($map));
111 $commit_query->execute();
112
113 $commit_map = $commit_query->getIdentifierMap();
114 $commit_map = mpull($commit_map, 'getID');
115
116 $graph_cache = new PhabricatorRepositoryGraphCache();
117
118 $results = array();
119
120 // Spend no more than this many total seconds trying to satisfy queries
121 // via the graph cache.
122 $remaining_time = 10.0;
123 foreach ($map as $path => $commit) {
124 $path_id = idx($path_map, $path);
125 if (!$path_id) {
126 continue;
127 }
128 $commit_id = idx($commit_map, $commit);
129 if (!$commit_id) {
130 continue;
131 }
132
133 $t_start = microtime(true);
134 $cache_result = $graph_cache->loadLastModifiedCommitID(
135 $commit_id,
136 $path_id,
137 $remaining_time);
138 $t_end = microtime(true);
139
140 if ($cache_result !== false) {
141 $results[$path] = $cache_result;
142 }
143
144 $remaining_time -= ($t_end - $t_start);
145 if ($remaining_time <= 0) {
146 break;
147 }
148 }
149
150 if ($results) {
151 $commits = id(new DiffusionCommitQuery())
152 ->setViewer($drequest->getUser())
153 ->withRepository($repository)
154 ->withIDs($results)
155 ->execute();
156 foreach ($results as $path => $id) {
157 $commit = idx($commits, $id);
158 if ($commit) {
159 $results[$path] = $commit->getCommitIdentifier();
160 } else {
161 unset($results[$path]);
162 }
163 }
164 }
165
166 return $results;
167 }
168
169}