@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 * Pushes a repository to its mirrors.
5 */
6final class PhabricatorRepositoryMirrorEngine
7 extends PhabricatorRepositoryEngine {
8
9 public function pushToMirrors() {
10 $viewer = $this->getViewer();
11 $repository = $this->getRepository();
12
13 if (!$repository->canMirror()) {
14 return;
15 }
16
17 if (PhabricatorEnv::getEnvConfig('phabricator.silent')) {
18 $this->log(
19 pht('This software is running in silent mode; declining to mirror.'));
20 return;
21 }
22
23 $uris = id(new PhabricatorRepositoryURIQuery())
24 ->setViewer($viewer)
25 ->withRepositories(array($repository))
26 ->execute();
27
28 $io_mirror = PhabricatorRepositoryURI::IO_MIRROR;
29
30 $exceptions = array();
31 foreach ($uris as $mirror) {
32 if ($mirror->getIsDisabled()) {
33 continue;
34 }
35
36 $io_type = $mirror->getEffectiveIOType();
37 if ($io_type != $io_mirror) {
38 continue;
39 }
40
41 try {
42 $this->pushRepositoryToMirror($repository, $mirror);
43 } catch (Exception $ex) {
44 $exceptions[] = $ex;
45 }
46 }
47
48 if ($exceptions) {
49 throw new PhutilAggregateException(
50 pht(
51 'Exceptions occurred while mirroring the "%s" repository.',
52 $repository->getDisplayName()),
53 $exceptions);
54 }
55 }
56
57 private function pushRepositoryToMirror(
58 PhabricatorRepository $repository,
59 PhabricatorRepositoryURI $mirror_uri) {
60
61 $this->log(
62 pht(
63 'Pushing to remote "%s"...',
64 $mirror_uri->getEffectiveURI()));
65
66 if ($repository->isGit()) {
67 $this->pushToGitRepository($repository, $mirror_uri);
68 } else if ($repository->isHg()) {
69 $this->pushToHgRepository($repository, $mirror_uri);
70 } else {
71 throw new Exception(pht('Unsupported VCS!'));
72 }
73 }
74
75 private function pushToGitRepository(
76 PhabricatorRepository $repository,
77 PhabricatorRepositoryURI $mirror_uri) {
78
79 // See T5965. Test if we have any refs to mirror. If we have nothing, git
80 // will exit with an error ("No refs in common and none specified; ...")
81 // when we run "git push --mirror".
82
83 // If we don't have any refs, we just bail out. (This is arguably sort of
84 // the wrong behavior: to mirror an empty repository faithfully we should
85 // delete everything in the remote.)
86
87 list($stdout) = $repository->execxLocalCommand(
88 'for-each-ref --count 1 --');
89 if (!strlen($stdout)) {
90 return;
91 }
92
93 $argv = array(
94 'push --verbose --mirror -- %P',
95 $mirror_uri->getURIEnvelope(),
96 );
97
98 $future = $mirror_uri->newCommandEngine()
99 ->setArgv($argv)
100 ->newFuture();
101
102 $future
103 ->setCWD($repository->getLocalPath())
104 ->resolvex();
105 }
106
107 private function pushToHgRepository(
108 PhabricatorRepository $repository,
109 PhabricatorRepositoryURI $mirror_uri) {
110
111 $argv = array(
112 'push --verbose --rev tip -- %P',
113 $mirror_uri->getURIEnvelope(),
114 );
115
116 $future = $mirror_uri->newCommandEngine()
117 ->setArgv($argv)
118 ->newFuture();
119
120 try {
121 $future
122 ->setCWD($repository->getLocalPath())
123 ->resolvex();
124 } catch (CommandException $ex) {
125 if (preg_match('/no changes found/', $ex->getStdout())) {
126 // mercurial says nothing changed, but that's good
127 } else {
128 throw $ex;
129 }
130 }
131 }
132
133}