Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/diffusion/query/lowlevel/DiffusionLowLevelGitRefQuery.php
12242 views
1
<?php
2
3
/**
4
* Execute and parse a low-level Git ref query using `git for-each-ref`. This
5
* is useful for returning a list of tags or branches.
6
*/
7
final class DiffusionLowLevelGitRefQuery extends DiffusionLowLevelQuery {
8
9
private $refTypes;
10
11
public function withRefTypes(array $ref_types) {
12
$this->refTypes = $ref_types;
13
return $this;
14
}
15
16
protected function executeQuery() {
17
$type_branch = PhabricatorRepositoryRefCursor::TYPE_BRANCH;
18
$type_tag = PhabricatorRepositoryRefCursor::TYPE_TAG;
19
$type_ref = PhabricatorRepositoryRefCursor::TYPE_REF;
20
21
$ref_types = $this->refTypes;
22
if (!$ref_types) {
23
$ref_types = array($type_branch, $type_tag, $type_ref);
24
}
25
26
$ref_types = array_fuse($ref_types);
27
28
$with_branches = isset($ref_types[$type_branch]);
29
$with_tags = isset($ref_types[$type_tag]);
30
$with_refs = isset($refs_types[$type_ref]);
31
32
$repository = $this->getRepository();
33
34
$prefixes = array();
35
36
$branch_prefix = 'refs/heads/';
37
$tag_prefix = 'refs/tags/';
38
39
if ($with_refs || count($ref_types) > 1) {
40
// If we're loading refs or more than one type of ref, just query
41
// everything.
42
$prefix = 'refs/';
43
} else {
44
if ($with_branches) {
45
$prefix = $branch_prefix;
46
}
47
if ($with_tags) {
48
$prefix = $tag_prefix;
49
}
50
}
51
52
$branch_len = strlen($branch_prefix);
53
$tag_len = strlen($tag_prefix);
54
55
list($stdout) = $repository->execxLocalCommand(
56
'for-each-ref --sort=%s --format=%s -- %s',
57
'-creatordate',
58
$this->getFormatString(),
59
$prefix);
60
61
$stdout = rtrim($stdout);
62
if (!strlen($stdout)) {
63
return array();
64
}
65
66
$remote_prefix = 'refs/remotes/';
67
$remote_len = strlen($remote_prefix);
68
69
// NOTE: Although git supports --count, we can't apply any offset or
70
// limit logic until the very end because we may encounter a HEAD which
71
// we want to discard.
72
73
$lines = explode("\n", $stdout);
74
$results = array();
75
foreach ($lines as $line) {
76
$fields = $this->extractFields($line);
77
78
$refname = $fields['refname'];
79
if (!strncmp($refname, $branch_prefix, $branch_len)) {
80
$short = substr($refname, $branch_len);
81
$type = $type_branch;
82
} else if (!strncmp($refname, $tag_prefix, $tag_len)) {
83
$short = substr($refname, $tag_len);
84
$type = $type_tag;
85
} else if (!strncmp($refname, $remote_prefix, $remote_len)) {
86
// If we've found a remote ref that we didn't recognize as naming a
87
// branch, just ignore it. This can happen if we're observing a remote,
88
// and that remote has its own remotes. We don't care about their
89
// state and they may be out of date, so ignore them.
90
continue;
91
} else {
92
$short = $refname;
93
$type = $type_ref;
94
}
95
96
// If this isn't a type of ref we care about, skip it.
97
if (empty($ref_types[$type])) {
98
continue;
99
}
100
101
// If this is the local HEAD, skip it.
102
if ($short == 'HEAD') {
103
continue;
104
}
105
106
$creator = $fields['creator'];
107
$matches = null;
108
if (preg_match('/^(.*) ([0-9]+) ([0-9+-]+)$/', $creator, $matches)) {
109
$fields['author'] = $matches[1];
110
$fields['epoch'] = (int)$matches[2];
111
} else {
112
$fields['author'] = null;
113
$fields['epoch'] = null;
114
}
115
116
$commit = nonempty($fields['*objectname'], $fields['objectname']);
117
118
$ref = id(new DiffusionRepositoryRef())
119
->setRefType($type)
120
->setShortName($short)
121
->setCommitIdentifier($commit)
122
->setRawFields($fields);
123
124
$results[] = $ref;
125
}
126
127
return $results;
128
}
129
130
/**
131
* List of git `--format` fields we want to grab.
132
*/
133
private function getFields() {
134
return array(
135
'objectname',
136
'objecttype',
137
'refname',
138
'*objectname',
139
'*objecttype',
140
'subject',
141
'creator',
142
);
143
}
144
145
/**
146
* Get a string for `--format` which enumerates all the fields we want.
147
*/
148
private function getFormatString() {
149
$fields = $this->getFields();
150
151
foreach ($fields as $key => $field) {
152
$fields[$key] = '%('.$field.')';
153
}
154
155
return implode('%01', $fields);
156
}
157
158
/**
159
* Parse a line back into fields.
160
*/
161
private function extractFields($line) {
162
$fields = $this->getFields();
163
$parts = explode("\1", $line, count($fields));
164
165
$dict = array();
166
foreach ($fields as $index => $field) {
167
$dict[$field] = idx($parts, $index);
168
}
169
170
return $dict;
171
}
172
173
}
174
175