@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 DifferentialAffectedPathEngine
4 extends Phobject {
5
6 private $revision;
7 private $diff;
8
9 public function setRevision(DifferentialRevision $revision) {
10 $this->revision = $revision;
11 return $this;
12 }
13
14 public function getRevision() {
15 return $this->revision;
16 }
17
18 public function setDiff(DifferentialDiff $diff) {
19 $this->diff = $diff;
20 return $this;
21 }
22
23 public function getDiff() {
24 return $this->diff;
25 }
26
27 public function updateAffectedPaths() {
28 $revision = $this->getRevision();
29 $diff = $this->getDiff();
30 $repository = $revision->getRepository();
31
32 if ($repository) {
33 $repository_id = $repository->getID();
34 } else {
35 $repository_id = null;
36 }
37
38 $paths = $this->getAffectedPaths();
39
40 $path_ids =
41 PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths(
42 $paths);
43
44 $table = new DifferentialAffectedPath();
45 $conn = $table->establishConnection('w');
46
47 $sql = array();
48 foreach ($path_ids as $path_id) {
49 $sql[] = qsprintf(
50 $conn,
51 '(%nd, %d, %d)',
52 $repository_id,
53 $path_id,
54 $revision->getID());
55 }
56
57 queryfx(
58 $conn,
59 'DELETE FROM %R WHERE revisionID = %d',
60 $table,
61 $revision->getID());
62 if ($sql) {
63 foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) {
64 queryfx(
65 $conn,
66 'INSERT INTO %R (repositoryID, pathID, revisionID) VALUES %LQ',
67 $table,
68 $chunk);
69 }
70 }
71 }
72
73 public function destroyAffectedPaths() {
74 $revision = $this->getRevision();
75
76 $table = new DifferentialAffectedPath();
77 $conn = $table->establishConnection('w');
78
79 queryfx(
80 $conn,
81 'DELETE FROM %R WHERE revisionID = %d',
82 $table,
83 $revision->getID());
84 }
85
86 public function getAffectedPaths() {
87 $revision = $this->getRevision();
88 $diff = $this->getDiff();
89 $repository = $revision->getRepository();
90
91 $path_prefix = null;
92 if ($repository) {
93 $local_root = $diff->getSourceControlPath();
94 if ($local_root) {
95 // We're in a working copy which supports subdirectory checkouts (e.g.,
96 // SVN) so we need to figure out what prefix we should add to each path
97 // (e.g., trunk/projects/example/) to get the absolute path from the
98 // root of the repository. DVCS systems like Git and Mercurial are not
99 // affected.
100
101 // Normalize both paths and check if the repository root is a prefix of
102 // the local root. If so, throw it away. Note that this correctly
103 // handles the case where the remote path is "/".
104 $local_root = id(new PhutilURI($local_root))->getPath();
105 $local_root = rtrim($local_root, '/');
106
107 $repo_root = id(new PhutilURI($repository->getRemoteURI()))->getPath();
108 $repo_root = rtrim($repo_root, '/');
109
110 if (!strncmp($repo_root, $local_root, strlen($repo_root))) {
111 $path_prefix = substr($local_root, strlen($repo_root));
112 }
113 }
114 }
115
116 $changesets = $diff->getChangesets();
117
118 $paths = array();
119 foreach ($changesets as $changeset) {
120 $paths[] = $path_prefix.'/'.$changeset->getFilename();
121 }
122
123 // Mark this as also touching all parent paths, so you can see all pending
124 // changes to any file within a directory.
125 $all_paths = array();
126 foreach ($paths as $local) {
127 foreach (DiffusionPathIDQuery::expandPathToRoot($local) as $path) {
128 $all_paths[$path] = true;
129 }
130 }
131 $all_paths = array_keys($all_paths);
132
133 return $all_paths;
134 }
135
136}