silk.git.remote.

List the branches, tags, and other references of a remote Git repository over HTTP or HTTPS, like git ls-remote.

When to use#

Call GitRemote.listRefs with the URL of a repository, such as https://github.com/silk-lang/silk.git, to get its references as a RefList from silk.git.refs. Then look up a branch or a tag, or find the default branch with RefList.head. Narrow the list with ListOptions.prefix, such as refs/tags/, which large repositories answer much faster. The request goes through the Http service of silk.http.client, so tests can give a fake server.

Details#

It speaks the smart HTTP protocol of Git. By default it asks for protocol version 2 and sends an ls-refs command with the prefixes, so the server filters the list. A server that answers with version 0 sends all references in its first response, and the list is filtered on the client. A dumb HTTP server, which serves the info/refs file, is read too. For each annotated tag the result has the peeled object, and HEAD has the default branch as its target when the server reports it. Redirects of the first request are followed, and the second request goes to the URL that the first one ended at.

The functions GitRemote.parseAdvertisement, GitRemote.parseLsRefs, and GitRemote.parseDumbRefs read a response body that you got another way.

Errors#

  • GitRefError from silk.git.refs if the response is not a reference advertisement, is malformed, or is an ERR packet from the server.

  • HttpError from silk.http.client if the request fails or the status is not from 200 to 299. A private repository without credentials usually answers 401 or 404.

  • OutOfMemoryError if the Allocator fails.

Gotchas#

The URL is used as given, so it must be the repository URL that git clone accepts, without /info/refs. Only HTTP and HTTPS URLs work, not SSH or git://. For a private repository, set the Authorization header with ListOptions.authorization, such as Basic with a token.

Examples#

List the tags of a repository from a fake server#

silk
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.collections.list { List }
import silk.core.option { Option }
import silk.core.result { Result }
import silk.git.refs { GitRefError, Ref }
import silk.git.remote { GitRemote, ListOptions }
import silk.http.client { Http, HttpError, Request, Response }

struct DumbServer {}

impl Http for DumbServer {
  effect fn sendAll(self: &mut Self, requests: List<Request<'_>>) -> List<Result<Response, HttpError>>
    ! OutOfMemoryError
    ? &mut Allocator {
    return run Http.sendEach(move requests) |> Effect.provideMut<Http>(&mut self.*)
  }

  effect fn send(self: &mut Self, request: Request<'_>) -> Response
    ! HttpError | OutOfMemoryError
    ? &mut Allocator {
    return run Response.make(200, b"95d09f2b10159347eece71399a7e2e907ea3df4f\trefs/tags/v1.0.0\n")
  }
}

effect fn tagged() -> bool ! GitRefError | HttpError | OutOfMemoryError ? &mut Http | &mut Allocator {
  let mut options = ListOptions.make()
  run options.prefix("refs/tags/")
  let refs = run GitRemote.listRefs("https://git.example.com/app.git", &options)
  return match refs.resolve("v1.0.0") {
    Option<&Ref>.Some { value } => value.isTag()
    Option<&Ref>.None => false
  }
}

pub effect fn main() -> i32 ! GitRefError | HttpError | OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let mut server = DumbServer {}
  let found = run tagged() |> Effect.provideMut<Http>(&mut server)
    |> Effect.provideMut<Allocator>(&mut allocator)
  if found {
    return 0
  }
  return 1
}

Import as GitRemote with import silk.git.remote { GitRemote }.

Public declarations: 4.

DEFAULT_MAX_BODY_BYTES#

silk
pub const DEFAULT_MAX_BODY_BYTES: usize

The default limit of each response body, in bytes: 64 MiB.

GitProtocol#

silk
pub enum GitProtocol

The Git protocol version that GitRemote.listRefs asks for.

Version2#

silk
Version2

Ask for version 2, and fall back to version 0 when the server does not speak it. The server filters the references by prefix. This is the default.

Version0#

silk
Version0

Ask for version 0 only. The server sends all references in one response, and the client filters them.

Implementation Debug for GitProtocol#

silk
impl Debug for GitProtocol

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> ()
    ! WriterError
    ? &mut Writer

Writes the name of the variant, such as Version2.

ListOptions#

silk
pub struct ListOptions

What GitRemote.listRefs asks for: the prefixes of the names to list, the credentials, the protocol, and the body limit.

Details#

ListOptions.make lists every reference with protocol version 2, no credentials, and a limit of DEFAULT_MAX_BODY_BYTES for each response body. A reference is listed when its full name starts with one of the prefixes, or always when there are none. So refs/tags/ lists the tags and refs/heads/ the branches. HEAD is listed only with no prefixes or with a prefix that it starts with, such as HEAD.

Implementation ListOptions#

silk
impl ListOptions

Associated function make#

silk
pub fn make() -> ListOptions

Returns the options that list every reference with protocol version 2, no credentials, and a limit of DEFAULT_MAX_BODY_BYTES for each response body. It does not allocate.

Method prefix#

silk
pub effect fn prefix(self: &mut Self, prefix: string) -> ()
    ! OutOfMemoryError
    ? &mut Allocator

Adds prefix to the prefixes of the names to list, such as refs/tags/ or refs/heads/.

Details#

A reference is listed when its full name starts with any of the prefixes. The comparison is of bytes, so refs/heads/v also matches refs/heads/v2-dev.

Errors#

  • OutOfMemoryError if the Allocator cannot supply the copy of prefix.

Method authorization#

silk
pub effect fn authorization(self: &mut Self, value: string) -> ()
    ! OutOfMemoryError
    ? &mut Allocator

Sets the value of the Authorization header of each request, such as Basic and the Base64 of user:token, or Bearer and a token.

Errors#

  • OutOfMemoryError if the Allocator cannot supply the copy of value.

Gotchas#

The Http provider does not send the header to another origin after a redirect.

Method protocol#

silk
pub fn protocol(self: Self, protocol: GitProtocol) -> ListOptions

Returns the options with the protocol version protocol.

Method maxBodyBytes#

silk
pub fn maxBodyBytes(self: Self, limit: usize) -> ListOptions

Returns the options with the limit of each response body set to limit bytes.

Method prefixes#

silk
pub fn prefixes(self: &Self) -> &[String]

Returns the prefixes of the names to list, in the order they were added.

GitRemote#

silk
pub struct GitRemote

Functions that list the references of a remote repository.

Implementation GitRemote#

silk
impl GitRemote

Associated function listRefs#

silk
pub effect fn listRefs(url: string, options: &ListOptions) -> RefList
    ! GitRefError | HttpError | OutOfMemoryError
    ? &mut Http | &mut Allocator

Returns the references of the repository at url that options selects, like git ls-remote.

Details#

It sends GET <url>/info/refs?service=git-upload-pack. With protocol version 2, it asks for version 2 in the Git-Protocol header. When the server answers with version 2, it then sends POST <url>/git-upload-pack with an ls-refs command that has the prefixes and asks for peeled tags and symbolic targets. A server that answers with version 0 or 1 lists all references in its first answer, and they are filtered here. A dumb server answers with the plain info/refs file, which has no HEAD.

A trailing / of url is removed. When the first request is redirected, the second goes to the URL where the first one ended. The references are in the order of the server: HEAD first, then by name.

Errors#

  • GitRefError.NotGitRepository if the answer is not a reference advertisement.

  • GitRefError.Malformed if the advertisement is broken.

  • GitRefError.ServerError if the server answers with an ERR packet.

  • GitRefError.Unsupported if a version 2 server does not offer ls-refs.

  • HttpError if a request fails, or the status is not from 200 to 299.

  • OutOfMemoryError if the Allocator fails.

Associated function parseAdvertisement#

silk
pub effect fn parseAdvertisement(body: &[u8], prefixes: &[String]) -> RefList
    ! GitRefError | OutOfMemoryError
    ? &mut Allocator

Returns the references of a version 0 or version 1 advertisement in body whose names start with one of prefixes, or all of them when prefixes is empty.

Details#

body is the answer to GET <url>/info/refs?service=git-upload-pack or the start of the output of git-upload-pack: an optional # service= packet and flush, an optional version 1 packet, then one packet for each reference, and a flush. The first reference has the capabilities after a NUL byte. A symref=HEAD:<target> capability sets the target of HEAD, and a line <id> <name>^{} sets the peeled object of the reference before it. An empty repository advertises no references, and the result then has only an unborn HEAD when the server reports its target.

Errors#

  • GitRefError.Malformed if a packet or a line is broken.

  • GitRefError.ServerError if the body has an ERR packet.

  • OutOfMemoryError if the Allocator fails.

Associated function parseLsRefs#

silk
pub effect fn parseLsRefs(body: &[u8], prefixes: &[String]) -> RefList
    ! GitRefError | OutOfMemoryError
    ? &mut Allocator

Returns the references in body, the answer of a version 2 server to an ls-refs command, whose names start with one of prefixes, or all of them when prefixes is empty.

Details#

Each packet is <id> <name>, then optional symref-target:<target> and peeled:<id> attributes, and a flush ends the list. A line that starts with unborn instead of an id is a symbolic reference whose target does not exist yet, so its id is None.

Errors#

  • GitRefError.Malformed if a packet or a line is broken.

  • GitRefError.ServerError if the body has an ERR packet.

  • OutOfMemoryError if the Allocator fails.

Associated function parseDumbRefs#

silk
pub effect fn parseDumbRefs(body: &[u8], prefixes: &[String]) -> RefList
    ! GitRefError | OutOfMemoryError
    ? &mut Allocator

Returns the references in body, the info/refs file of a dumb HTTP server, whose names start with one of prefixes, or all of them when prefixes is empty.

Details#

Each line is <id>, a tab, and the name, and ends with LF. A line whose name ends with ^{} sets the peeled object of the reference before it. The file has no HEAD.

Errors#

  • GitRefError.NotGitRepository if a line is not an id, a tab, and a name, for example in an HTML page.

  • OutOfMemoryError if the Allocator fails.

Category: Version control.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.

View the source of this page