change Git package references to use default branch

If a Git package source does not include "#" followed by a ref, then
use the branch/commit designated by a server as the default branch or
commit (i.e., the one for the "HEAD" symref), instead of assuming the
branch "master".

This is technically a backward-incompatible change to the
interpretation of Git package sources, but explicit branch
specification continues to work the same. For the forseeable future,
to support recent versions, packages in a branch other than "master"
will still need to be specified using the branch name, such as
including "#main" at the end of the package source. Eventually,
relevant versions of Racket will support the new default.

Relevant to #3672
This commit is contained in:
Matthew Flatt 2021-02-19 09:54:28 -07:00
parent f0e41cf143
commit cff766ab84
6 changed files with 77 additions and 44 deletions

View File

@ -383,8 +383,8 @@ is:
@inset{@exec{https://github.com/@nonterm{user}/@nonterm{package}.git}}
If you want the package to be @nonterm{branch} or @nonterm{tag}
instead of @exec{master}, then add @filepath{#@nonterm{branch}} or
If you want the package to be at @nonterm{branch} or @nonterm{tag}
instead of the default branch, then add @filepath{#@nonterm{branch}} or
@filepath{#@nonterm{tag}} to the end of the package source. If your
package is a subdirectory @nonterm{path} within the repository, add
@filepath{?path=@nonterm{path}} to the end of the package source.

View File

@ -120,7 +120,7 @@ develops only a few of them. The intended workflow is as follows:
repository by setting an @exec{upstream} remote, e.g. @exec{git
remote add upstream @nonterm{url-of-central-repo}}. This gives you
the option to periodically pull in commits from the central
repository with @exec{git pull --ff-only upstream master}.}
repository with @exec{git pull --ff-only upstream}.}
Alternatively, use @exec{git} to clone the target @nonterm{url}
first, and then supply the local clone's path as @nonterm{dir} in

View File

@ -249,14 +249,15 @@ where @nonterm{scheme} is @litchar{git}, @litchar{http}, or
reference). The @nonterm{path} can contain multiple
@litchar{/}-separated elements to form a path within the repository,
and it defaults to the empty path. The @nonterm{rev} can be a branch,
tag, or commit, and it defaults to @exec{master}.
tag, or commit, and it defaults to using the default branch as reported
by the server.
@margin-note{Due to properties of the Git protocol, the archive might
be accessed more efficiently when @nonterm{rev} refers to a branch or
tag (even if it is written as a commit). In those cases, the content
typically can be obtained without downloading irrelevant history.}
For example, @filepath{http://bitbucket.org/game/tic-tac-toe#master}
For example, @filepath{http://bitbucket.org/game/tic-tac-toe#main}
is a Git package source.
A checkout of the repository at @nonterm{rev} provides the content of
@ -285,7 +286,7 @@ URLs is the same as for a Git repository reference starting
@optional{@exec{.git}}@optional{@exec{/}}@optional{@exec{?path=}@nonterm{path}}@;
@optional{@exec{#}@nonterm{rev}}}
For example, @filepath{git://github.com/game/tic-tac-toe#master}
For example, @filepath{git://github.com/game/tic-tac-toe#main}
is a GitHub package source.
@margin-note{A Github repository source that starts with

View File

@ -53,8 +53,8 @@
$ "raco pkg remove pkg-test1-git-different-checksum"
$ "racket -l pkg-test1/number" =exit> 1))))
(test-remote "git://github.com/mflatt/pkg-test")
(test-remote "https://github.com/mflatt/pkg-test.git")
(test-remote "git://github.com/racket/test-pkg-1")
(test-remote "https://github.com/racket/test-pkg-1.git")
(test-remote "https://bitbucket.org/mflatt/pkg-test.git")
(define (try-git-repo label type+repo)
@ -69,10 +69,26 @@
$ (~a "raco pkg update " type+repo)
(finally
(delete-directory/files tmp-dir)))))
(try-git-repo
"remote/github with auto prefix and with branch"
"--type github mflatt/pkg-test?path=pkg-test1/#alt")
"--type github racket/test-pkg-1?path=pkg-test1/#alt")
(try-git-repo
"remote/git type"
"--type git https://bitbucket.org/mflatt/pkg-test?path=pkg-test1#alt"))
"--type git https://bitbucket.org/mflatt/pkg-test?path=pkg-test1#alt")
(define (try-git-repo-using-default-branch label repo)
(define tmp-dir (make-temporary-file "~a-clone" 'directory))
(shelly-wind
$ (~a "raco pkg install " repo)
$ "racket -l test-pkg-2/twelve" =stdout> "12\n"
$ (~a "raco pkg update --clone " tmp-dir " test-pkg-2")
$ "racket -l test-pkg-2/twelve" =stdout> "12\n"
$ (~a "raco pkg update " repo)
$ "raco pkg remove " repo
(finally
(delete-directory/files tmp-dir))))
(try-git-repo-using-default-branch
"remote/git with default branch"
"https://github.com/racket/test-pkg-2.git"))

View File

@ -41,7 +41,7 @@
(string-join (map (compose ~a path/param-path)
(url-path/no-slash pkg-url))
"/")
(or (url-fragment pkg-url) "master")
(or (url-fragment pkg-url) 'head)
(extract-git-path pkg-url)))
(define (split-git-or-hub-url pkg-url #:type [type #f])

View File

@ -206,13 +206,19 @@
clone-dir)
(make-directory* clone-dir)
(parameterize ([current-directory clone-dir])
(git #:status status "clone" "-b" branch pkg-no-query ".")))
(apply git #:status status "clone"
(append
(if (eq? branch 'head) null (list "-b" branch))
(list pkg-no-query ".")))))
(unless working-dir
(parameterize ([current-directory clone-dir])
(download-printf "Fetching from remote repository ~a\n"
pkg-no-query)
(git #:status status "fetch" pkg-no-query branch)))
(apply git #:status status "fetch"
(append
(list pkg-no-query)
(if (eq? branch 'head) null (list branch))))))
(cond
[tmp-dir
@ -225,7 +231,11 @@
(download-printf "Cloning repository locally for staging\n")
(git #:status status "clone" "--shared" clone-dir tmp-dir)
(parameterize ([current-directory tmp-dir])
(git #:status status "checkout" (or checksum branch)))
(apply git #:status status "checkout"
(cond
[checksum => list]
[(eq? branch 'head) null]
[else (list branch)])))
(lift-git-directory-content tmp-dir path)]
[else
(download-printf "Using clone directory directly for metadata\n")])
@ -771,43 +781,49 @@
(current-continuation-marks))))
#:transport transport)))))]
[(github)
(match-define (list* user repo branch path)
(split-github-url pkg-url))
(match-define (list* user repo url-branch path)
(split-github-url pkg-url))
(define (query-json path kind)
(define api-u
(url "https" #f "api.github.com" #f #t
(map (λ (x) (path/param x empty))
path)
(append query
(if (and (github-client_id)
(github-client_secret))
(list (cons 'client_id (github-client_id))
(cons 'client_secret (github-client_secret)))
empty))
#f))
(download-printf "Querying GitHub ~a for ~a\n" kind pkg-name)
(log-pkg-debug "Querying GitHub at ~a" (url->string api-u))
(define api-bs
(call/input-url+200
api-u port->bytes
#:who 'query-github
#:headers (list (format "User-Agent: raco-pkg/~a" (version)))))
(unless api-bs
(error 'package-url->checksum
"could not connect to GitHub\n URL: ~a"
(url->string
(struct-copy url api-u
[query query]))))
(read-json (open-input-bytes api-bs)))
(define branch (cond
[(eq? url-branch 'head)
(define info (query-json (list "repos" user repo) 'head))
(hash-ref info 'default_branch)]
[else url-branch]))
(or
(for/or ([kind '("branches" "tags")])
(define api-u
(url "https" #f "api.github.com" #f #t
(map (λ (x) (path/param x empty))
(list "repos" user repo kind))
(append query
(if (and (github-client_id)
(github-client_secret))
(list (cons 'client_id (github-client_id))
(cons 'client_secret (github-client_secret)))
empty))
#f))
(download-printf "Querying GitHub ~a for ~a\n" kind pkg-name)
(log-pkg-debug "Querying GitHub at ~a" (url->string api-u))
(define api-bs
(call/input-url+200
api-u port->bytes
#:who 'query-github
#:headers (list (format "User-Agent: raco-pkg/~a" (version)))))
(unless api-bs
(error 'package-url->checksum
"could not connect to GitHub\n URL: ~a"
(url->string
(struct-copy url api-u
[query query]))))
(define branches
(read-json (open-input-bytes api-bs)))
(define branches (query-json (list "repos" user repo kind) kind))
(unless (and (list? branches)
(andmap hash? branches)
(andmap (λ (b) (hash-has-key? b 'name)) branches)
(andmap (λ (b) (hash-has-key? b 'commit)) branches))
(error 'package-url->checksum
"Invalid response from Github: ~e"
api-bs))
branches))
(for/or ([b (in-list branches)])
(and (equal? (hash-ref b 'name) branch)
(hash-ref (hash-ref b 'commit) 'sha))))