From cff766ab84dcc5d9dc969930611e0b8c150bfaf6 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Fri, 19 Feb 2021 09:54:28 -0700 Subject: [PATCH] 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 --- .../pkg/scribblings/getting-started.scrbl | 4 +- .../pkg/scribblings/git-workflow.scrbl | 2 +- pkgs/racket-doc/pkg/scribblings/pkg.scrbl | 7 +- pkgs/racket-test/tests/pkg/tests-network.rkt | 26 ++++-- racket/collects/pkg/private/repo-path.rkt | 2 +- racket/collects/pkg/private/stage.rkt | 80 +++++++++++-------- 6 files changed, 77 insertions(+), 44 deletions(-) diff --git a/pkgs/racket-doc/pkg/scribblings/getting-started.scrbl b/pkgs/racket-doc/pkg/scribblings/getting-started.scrbl index 3d9f66321b..35b476f9c2 100644 --- a/pkgs/racket-doc/pkg/scribblings/getting-started.scrbl +++ b/pkgs/racket-doc/pkg/scribblings/getting-started.scrbl @@ -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. diff --git a/pkgs/racket-doc/pkg/scribblings/git-workflow.scrbl b/pkgs/racket-doc/pkg/scribblings/git-workflow.scrbl index f7601c987d..6ccaaceea8 100644 --- a/pkgs/racket-doc/pkg/scribblings/git-workflow.scrbl +++ b/pkgs/racket-doc/pkg/scribblings/git-workflow.scrbl @@ -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 diff --git a/pkgs/racket-doc/pkg/scribblings/pkg.scrbl b/pkgs/racket-doc/pkg/scribblings/pkg.scrbl index 747890e8fa..e8cb361446 100644 --- a/pkgs/racket-doc/pkg/scribblings/pkg.scrbl +++ b/pkgs/racket-doc/pkg/scribblings/pkg.scrbl @@ -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 diff --git a/pkgs/racket-test/tests/pkg/tests-network.rkt b/pkgs/racket-test/tests/pkg/tests-network.rkt index 7749d42af6..efc73c47f3 100644 --- a/pkgs/racket-test/tests/pkg/tests-network.rkt +++ b/pkgs/racket-test/tests/pkg/tests-network.rkt @@ -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")) diff --git a/racket/collects/pkg/private/repo-path.rkt b/racket/collects/pkg/private/repo-path.rkt index 307c355ae0..8077f3263b 100644 --- a/racket/collects/pkg/private/repo-path.rkt +++ b/racket/collects/pkg/private/repo-path.rkt @@ -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]) diff --git a/racket/collects/pkg/private/stage.rkt b/racket/collects/pkg/private/stage.rkt index b5142d7bd7..11264ce063 100644 --- a/racket/collects/pkg/private/stage.rkt +++ b/racket/collects/pkg/private/stage.rkt @@ -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))))