Path: blob/master/src/applications/diffusion/query/lowlevel/DiffusionLowLevelGitRefQuery.php
12242 views
<?php12/**3* Execute and parse a low-level Git ref query using `git for-each-ref`. This4* is useful for returning a list of tags or branches.5*/6final class DiffusionLowLevelGitRefQuery extends DiffusionLowLevelQuery {78private $refTypes;910public function withRefTypes(array $ref_types) {11$this->refTypes = $ref_types;12return $this;13}1415protected function executeQuery() {16$type_branch = PhabricatorRepositoryRefCursor::TYPE_BRANCH;17$type_tag = PhabricatorRepositoryRefCursor::TYPE_TAG;18$type_ref = PhabricatorRepositoryRefCursor::TYPE_REF;1920$ref_types = $this->refTypes;21if (!$ref_types) {22$ref_types = array($type_branch, $type_tag, $type_ref);23}2425$ref_types = array_fuse($ref_types);2627$with_branches = isset($ref_types[$type_branch]);28$with_tags = isset($ref_types[$type_tag]);29$with_refs = isset($refs_types[$type_ref]);3031$repository = $this->getRepository();3233$prefixes = array();3435$branch_prefix = 'refs/heads/';36$tag_prefix = 'refs/tags/';3738if ($with_refs || count($ref_types) > 1) {39// If we're loading refs or more than one type of ref, just query40// everything.41$prefix = 'refs/';42} else {43if ($with_branches) {44$prefix = $branch_prefix;45}46if ($with_tags) {47$prefix = $tag_prefix;48}49}5051$branch_len = strlen($branch_prefix);52$tag_len = strlen($tag_prefix);5354list($stdout) = $repository->execxLocalCommand(55'for-each-ref --sort=%s --format=%s -- %s',56'-creatordate',57$this->getFormatString(),58$prefix);5960$stdout = rtrim($stdout);61if (!strlen($stdout)) {62return array();63}6465$remote_prefix = 'refs/remotes/';66$remote_len = strlen($remote_prefix);6768// NOTE: Although git supports --count, we can't apply any offset or69// limit logic until the very end because we may encounter a HEAD which70// we want to discard.7172$lines = explode("\n", $stdout);73$results = array();74foreach ($lines as $line) {75$fields = $this->extractFields($line);7677$refname = $fields['refname'];78if (!strncmp($refname, $branch_prefix, $branch_len)) {79$short = substr($refname, $branch_len);80$type = $type_branch;81} else if (!strncmp($refname, $tag_prefix, $tag_len)) {82$short = substr($refname, $tag_len);83$type = $type_tag;84} else if (!strncmp($refname, $remote_prefix, $remote_len)) {85// If we've found a remote ref that we didn't recognize as naming a86// branch, just ignore it. This can happen if we're observing a remote,87// and that remote has its own remotes. We don't care about their88// state and they may be out of date, so ignore them.89continue;90} else {91$short = $refname;92$type = $type_ref;93}9495// If this isn't a type of ref we care about, skip it.96if (empty($ref_types[$type])) {97continue;98}99100// If this is the local HEAD, skip it.101if ($short == 'HEAD') {102continue;103}104105$creator = $fields['creator'];106$matches = null;107if (preg_match('/^(.*) ([0-9]+) ([0-9+-]+)$/', $creator, $matches)) {108$fields['author'] = $matches[1];109$fields['epoch'] = (int)$matches[2];110} else {111$fields['author'] = null;112$fields['epoch'] = null;113}114115$commit = nonempty($fields['*objectname'], $fields['objectname']);116117$ref = id(new DiffusionRepositoryRef())118->setRefType($type)119->setShortName($short)120->setCommitIdentifier($commit)121->setRawFields($fields);122123$results[] = $ref;124}125126return $results;127}128129/**130* List of git `--format` fields we want to grab.131*/132private function getFields() {133return array(134'objectname',135'objecttype',136'refname',137'*objectname',138'*objecttype',139'subject',140'creator',141);142}143144/**145* Get a string for `--format` which enumerates all the fields we want.146*/147private function getFormatString() {148$fields = $this->getFields();149150foreach ($fields as $key => $field) {151$fields[$key] = '%('.$field.')';152}153154return implode('%01', $fields);155}156157/**158* Parse a line back into fields.159*/160private function extractFields($line) {161$fields = $this->getFields();162$parts = explode("\1", $line, count($fields));163164$dict = array();165foreach ($fields as $index => $field) {166$dict[$field] = idx($parts, $index);167}168169return $dict;170}171172}173174175