diff --git a/src/applications/diffusion/protocol/DiffusionGitUploadPackWireProtocol.php b/src/applications/diffusion/protocol/DiffusionGitUploadPackWireProtocol.php --- a/src/applications/diffusion/protocol/DiffusionGitUploadPackWireProtocol.php +++ b/src/applications/diffusion/protocol/DiffusionGitUploadPackWireProtocol.php @@ -187,61 +187,76 @@ // \0 // // ... + // + // See T13309. The end of this list (which may be empty if a repository + // does not have any refs) has a list of zero or more of these: + // + // shallow + // + // These entries are present if the repository is a shallow clone + // which was made with the "--depth" flag. + // + // Note that "shallow" frames do not advertise capabilities, and if + // a repository has only "shallow" frames, capabilities are never + // advertised. $bytes = $frame['bytes']; $matches = array(); if ($is_first) { - $ok = preg_match( - '('. - '^'. - '(?P[0-9a-f]{40})'. - ' '. - '(?P[^\0\n]+)'. - '\0'. - '(?P[^\n]+)'. - '\n'. - '\z'. - ')', - $bytes, - $matches); - if (!$ok) { + $capabilities_pattern = '\0(?P[^\n]+)'; + } else { + $capabilities_pattern = ''; + } + + $ok = preg_match( + '('. + '^'. + '(?:'. + '(?P[0-9a-f]{40}) (?P[^\0\n]+)'.$capabilities_pattern. + '|'. + 'shallow (?P[0-9a-f]{40})'. + ')'. + '\n'. + '\z'. + ')', + $bytes, + $matches); + + if (!$ok) { + if ($is_first) { throw new Exception( pht( 'Unexpected "git upload-pack" initial protocol frame: expected '. - '" \0\n", got "%s".', + '" \0\n", or '. + '"shallow \n", got "%s".', $bytes)); - } - } else { - $ok = preg_match( - '('. - '^'. - '(?P[0-9a-f]{40})'. - ' '. - '(?P[^\0\n]+)'. - '\n'. - '\z'. - ')', - $bytes, - $matches); - if (!$ok) { + } else { throw new Exception( pht( 'Unexpected "git upload-pack" protocol frame: expected '. - '" \n", got "%s".', + '" \n", or "shallow \n", got "%s".', $bytes)); } } - $hash = $matches['hash']; - $name = $matches['name']; + if (isset($matches['shallow'])) { + $name = null; + $hash = $matches['shallow']; + $is_shallow = true; + } else { + $name = $matches['name']; + $hash = $matches['hash']; + $is_shallow = false; + } - if ($is_first) { + if (isset($matches['capabilities'])) { $capabilities = $matches['capabilities']; } $refs[] = array( 'hash' => $hash, 'name' => $name, + 'shallow' => $is_shallow, ); } @@ -252,10 +267,16 @@ ->setCapabilities($capabilities); foreach ($refs as $ref) { - $ref_list->addRef( - id(new DiffusionGitWireProtocolRef()) - ->setName($ref['name']) - ->setHash($ref['hash'])); + $wire_ref = id(new DiffusionGitWireProtocolRef()) + ->setHash($ref['hash']); + + if ($ref['shallow']) { + $wire_ref->setIsShallow(true); + } else { + $wire_ref->setName($ref['name']); + } + + $ref_list->addRef($wire_ref); } // TODO: Here, we have a structured list of refs. In a future change, @@ -275,10 +296,19 @@ // a little surprising, but is consistent with the native behavior of the // protocol. + // Likewise, we don't send back any capabilities if we're sending only + // "shallow" frames. + $output = array(); $is_first = true; foreach ($refs as $ref) { - if ($is_first) { + $is_shallow = $ref->getIsShallow(); + + if ($is_shallow) { + $result = sprintf( + "shallow %s\n", + $ref->getHash()); + } else if ($is_first) { $result = sprintf( "%s %s\0%s\n", $ref->getHash(), diff --git a/src/applications/diffusion/protocol/DiffusionGitWireProtocolRef.php b/src/applications/diffusion/protocol/DiffusionGitWireProtocolRef.php --- a/src/applications/diffusion/protocol/DiffusionGitWireProtocolRef.php +++ b/src/applications/diffusion/protocol/DiffusionGitWireProtocolRef.php @@ -5,6 +5,7 @@ private $name; private $hash; + private $isShallow; public function setName($name) { $this->name = $name; @@ -24,9 +25,19 @@ return $this->hash; } + public function setIsShallow($is_shallow) { + $this->isShallow = $is_shallow; + return $this; + } + + public function getIsShallow() { + return $this->isShallow; + } + public function newSortVector() { return id(new PhutilSortVector()) - ->addString($this->getName()); + ->addInt((int)$this->getIsShallow()) + ->addString((string)$this->getName()); } }