@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
3/**
4 * @task config Configuring Repository Engines
5 * @task internal Internals
6 */
7abstract class PhabricatorRepositoryEngine extends Phobject {
8
9 private $repository;
10 private $verbose;
11
12 /**
13 * @task config
14 */
15 public function setRepository(PhabricatorRepository $repository) {
16 $this->repository = $repository;
17 return $this;
18 }
19
20
21 /**
22 * @task config
23 */
24 protected function getRepository() {
25 if ($this->repository === null) {
26 throw new PhutilInvalidStateException('setRepository');
27 }
28
29 return $this->repository;
30 }
31
32
33 /**
34 * @task config
35 */
36 public function setVerbose($verbose) {
37 $this->verbose = $verbose;
38 return $this;
39 }
40
41
42 /**
43 * @task config
44 */
45 public function getVerbose() {
46 return $this->verbose;
47 }
48
49
50 public function getViewer() {
51 return PhabricatorUser::getOmnipotentUser();
52 }
53
54 protected function newRepositoryLock(
55 PhabricatorRepository $repository,
56 $lock_key,
57 $lock_device_only) {
58
59 $lock_parts = array(
60 'repositoryPHID' => $repository->getPHID(),
61 );
62
63 if ($lock_device_only) {
64 $device = AlmanacKeys::getLiveDevice();
65 if ($device) {
66 $lock_parts['devicePHID'] = $device->getPHID();
67 }
68 }
69
70 return PhabricatorGlobalLock::newLock($lock_key, $lock_parts);
71 }
72
73 /**
74 * @task internal
75 */
76 protected function log($pattern /* ... */) {
77 if ($this->getVerbose()) {
78 $console = PhutilConsole::getConsole();
79 $argv = func_get_args();
80 array_unshift($argv, "%s\n");
81 call_user_func_array(array($console, 'writeOut'), $argv);
82 }
83 return $this;
84 }
85
86 final protected function queueCommitImportTask(
87 PhabricatorRepository $repository,
88 $commit_phid,
89 $task_priority,
90 $via) {
91
92 $vcs = $repository->getVersionControlSystem();
93 switch ($vcs) {
94 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
95 $class = 'PhabricatorRepositoryGitCommitMessageParserWorker';
96 break;
97 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
98 $class = 'PhabricatorRepositorySvnCommitMessageParserWorker';
99 break;
100 case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
101 $class = 'PhabricatorRepositoryMercurialCommitMessageParserWorker';
102 break;
103 default:
104 throw new Exception(
105 pht(
106 'Unknown repository type "%s"!',
107 $vcs));
108 }
109
110 $data = array(
111 'commitPHID' => $commit_phid,
112 );
113
114 if ($via !== null) {
115 $data['via'] = $via;
116 }
117
118 $options = array(
119 'priority' => $task_priority,
120 'objectPHID' => $commit_phid,
121 'containerPHID' => $repository->getPHID(),
122 );
123
124 PhabricatorWorker::scheduleTask($class, $data, $options);
125 }
126
127 /**
128 * @param PhabricatorRepository $repository
129 * @param array<PhabricatorRepositoryCommitRef> $refs
130 */
131 final protected function getImportTaskPriority(
132 PhabricatorRepository $repository,
133 array $refs) {
134 assert_instances_of($refs, PhabricatorRepositoryCommitRef::class);
135
136 // If the repository is importing for the first time, we schedule tasks
137 // at IMPORT priority, which is very low. Making progress on importing a
138 // new repository for the first time is less important than any other
139 // daemon task.
140
141 // If the repository has finished importing and we're just catching up
142 // on recent commits, we usually schedule discovery at COMMIT priority,
143 // which is slightly below the default priority.
144
145 // Note that followup tasks and triggered tasks (like those generated by
146 // Herald or Harbormaster) will queue at DEFAULT priority, so that each
147 // commit tends to fully import before we start the next one. This tends
148 // to give imports fairly predictable progress. See T11677 for some
149 // discussion.
150
151 if ($repository->isImporting()) {
152 $this->log(
153 pht(
154 'Importing %s commit(s) at low priority ("PRIORITY_IMPORT") '.
155 'because this repository is still importing.',
156 phutil_count($refs)));
157
158 return PhabricatorWorker::PRIORITY_IMPORT;
159 }
160
161 // See T13369. If we've discovered a lot of commits at once, import them
162 // at lower priority.
163
164 // This is mostly aimed at reducing the impact that synchronizing thousands
165 // of commits from a remote upstream has on other repositories. The queue
166 // is "mostly FIFO", so queueing a thousand commit imports can stall other
167 // repositories.
168
169 // In a perfect world we'd probably give repositories round-robin queue
170 // priority, but we don't currently have the primitives for this and there
171 // isn't a strong case for building them.
172
173 // Use "a whole lot of commits showed up at once" as a heuristic for
174 // detecting "someone synchronized an upstream", and import them at a lower
175 // priority to more closely approximate fair scheduling.
176
177 if (count($refs) >= PhabricatorRepository::LOWPRI_THRESHOLD) {
178 $this->log(
179 pht(
180 'Importing %s commits at low priority ("PRIORITY_IMPORT") '.
181 'because many commits were discovered at once.',
182 phutil_count($refs)));
183
184 return PhabricatorWorker::PRIORITY_IMPORT;
185 }
186
187 // Otherwise, import at normal priority.
188
189 if ($refs) {
190 $this->log(
191 pht(
192 'Importing %s commit(s) at normal priority ("PRIORITY_COMMIT").',
193 phutil_count($refs)));
194 }
195
196 return PhabricatorWorker::PRIORITY_COMMIT;
197 }
198
199
200}