Merge pull request #1472 from lexi-lambda/pkg-git-credentials
Add support for git-backed packages that require authentication
This commit is contained in:
commit
d9750064b9
|
@ -36,7 +36,9 @@ for information on command-line arguments and flags.
|
||||||
[(git) 9418]
|
[(git) 9418]
|
||||||
[(http) 80]
|
[(http) 80]
|
||||||
[(https) 443])]
|
[(https) 443])]
|
||||||
[#:strict-links? strict-links? any/c #f])
|
[#:strict-links? strict-links? any/c #f]
|
||||||
|
[#:username username (or/c string? #f) (current-git-username)]
|
||||||
|
[#:password password (or/c string? #f) (current-git-password)])
|
||||||
string?]{
|
string?]{
|
||||||
|
|
||||||
Contacts the server at @racket[hostname] and @racket[port]
|
Contacts the server at @racket[hostname] and @racket[port]
|
||||||
|
@ -96,6 +98,27 @@ If @racket[strict-links?] is true, then the checkout fails with an
|
||||||
error if it would produce a symbolic link that refers to an absolute path
|
error if it would produce a symbolic link that refers to an absolute path
|
||||||
or to a relative path that contains up-directory elements.
|
or to a relative path that contains up-directory elements.
|
||||||
|
|
||||||
|
If both @racket[username] and @racket[password] are non-@racket[#f]
|
||||||
|
@emph{and} @racket[transport] is @racket['http] or @racket['https], then
|
||||||
|
the provided credentials are passed to the remote server using HTTP Basic
|
||||||
|
Authentication.
|
||||||
|
|
||||||
@history[#:added "6.1.1.1"
|
@history[#:added "6.1.1.1"
|
||||||
#:changed "6.3" @elem{Added the @racket[initial-error] argument.}
|
#:changed "6.3" @elem{Added the @racket[initial-error] argument.}
|
||||||
#:changed "6.2.900.17" @elem{Added the @racket[strict-links?] argument.}]}
|
#:changed "6.2.900.17" @elem{Added the @racket[strict-links?] argument.}
|
||||||
|
#:changed "6.6.0.5" @elem{Added the @racket[username] and @racket[password] arguments.}
|
||||||
|
#:changed "6.6.0.5" @elem{Changed to raise @racket[exn:fail:git] exceptions
|
||||||
|
instead of @racket[exn:fail].}]}
|
||||||
|
|
||||||
|
@deftogether[(@defparam[current-git-username username (or/c string? #f)]
|
||||||
|
@defparam[current-git-password password (or/c string? #f)])]{
|
||||||
|
Parameters used by @racket[git-checkout] as the default values of the
|
||||||
|
@racket[_username] and @racket[_password] arguments to control
|
||||||
|
authentication with the remote server.
|
||||||
|
|
||||||
|
@history[#:added "6.6.0.5"]}
|
||||||
|
|
||||||
|
@defstruct[(exn:fail:git exn:fail) () #:transparent]{
|
||||||
|
Raised by @racket[git-checkout] due to errors parsing or communicating with the git protocol.
|
||||||
|
|
||||||
|
@history[#:added "6.6.0.5"]}
|
||||||
|
|
|
@ -944,6 +944,10 @@ for @nonterm{key}.
|
||||||
documentation; an empty string, which is the default, disables
|
documentation; an empty string, which is the default, disables
|
||||||
the URL so that the local filesystem is used. This key can be
|
the URL so that the local filesystem is used. This key can be
|
||||||
set only in @exec{installation} scope.}
|
set only in @exec{installation} scope.}
|
||||||
|
@item{@exec{git-checkout-credentials} --- A list of git credentials in the form
|
||||||
|
@nonterm{username}@litchar{:}@nonterm{password} that are tried when downloading
|
||||||
|
packages with git sources using the HTTP or HTTPS protocols. The credentials are
|
||||||
|
currently stored @bold{unencrypted} on the filesystem.}
|
||||||
@item{@exec{trash-max-packages} --- A limit on the number of package implementations
|
@item{@exec{trash-max-packages} --- A limit on the number of package implementations
|
||||||
that are kept in a trash folder when the package is removed or updated.}
|
that are kept in a trash folder when the package is removed or updated.}
|
||||||
@item{@exec{trash-max-seconds} --- A limit on the time since a package is removed or
|
@item{@exec{trash-max-seconds} --- A limit on the time since a package is removed or
|
||||||
|
@ -955,7 +959,8 @@ for @nonterm{key}.
|
||||||
]
|
]
|
||||||
|
|
||||||
@history[#:changed "6.1.1.6" @elem{Added @exec{trash-max-packages} and @exec{trash-max-seconds}.}
|
@history[#:changed "6.1.1.6" @elem{Added @exec{trash-max-packages} and @exec{trash-max-seconds}.}
|
||||||
#:changed "6.3" @elem{Added @exec{network-retries}.}]}
|
#:changed "6.3" @elem{Added @exec{network-retries}.}
|
||||||
|
#:changed "6.6.0.5" @elem{Added @exec{git-checkout-credentials}.}]}
|
||||||
|
|
||||||
|
|
||||||
@subcommand{@command/toc{catalog-show} @nonterm{option} ... @nonterm{package-name} ...
|
@subcommand{@command/toc{catalog-show} @nonterm{option} ... @nonterm{package-name} ...
|
||||||
|
|
82
pkgs/racket-test/tests/pkg/git-http-proxy.rkt
Normal file
82
pkgs/racket-test/tests/pkg/git-http-proxy.rkt
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(provide serve-git-http-proxy!)
|
||||||
|
|
||||||
|
(require net/base64
|
||||||
|
net/uri-codec
|
||||||
|
net/url
|
||||||
|
racket/match
|
||||||
|
racket/port
|
||||||
|
racket/runtime-path
|
||||||
|
racket/string
|
||||||
|
racket/system
|
||||||
|
web-server/http
|
||||||
|
web-server/servlet-env)
|
||||||
|
|
||||||
|
(define (url-path-string url)
|
||||||
|
(string-join (map path/param-path (url-path url))
|
||||||
|
"/" #:before-first "/"))
|
||||||
|
|
||||||
|
(define (url-query-string url)
|
||||||
|
(alist->form-urlencoded (url-query url)))
|
||||||
|
|
||||||
|
(define (verify-authorization header-value)
|
||||||
|
; strip #"Basic " off of the header value
|
||||||
|
(define encoded-value (subbytes header-value 6))
|
||||||
|
(equal? (string-split (bytes->string/utf-8 (base64-decode encoded-value)) ":")
|
||||||
|
'("user" "password")))
|
||||||
|
|
||||||
|
(define (serve-git-http-proxy req)
|
||||||
|
; check if the right Authorization header is provided
|
||||||
|
(define authorization (headers-assq* #"Authorization" (request-headers/raw req)))
|
||||||
|
(cond
|
||||||
|
[(and authorization (verify-authorization (header-value authorization)))
|
||||||
|
(parameterize ([current-environment-variables (environment-variables-copy
|
||||||
|
(current-environment-variables))])
|
||||||
|
; git-http-backend depends on these environment variables to find the git repo
|
||||||
|
(putenv "GIT_PROJECT_ROOT" (path->string (find-system-path 'temp-dir)))
|
||||||
|
(putenv "GIT_HTTP_EXPORT_ALL" "")
|
||||||
|
|
||||||
|
; set standard CGI environment variables
|
||||||
|
(environment-variables-set! (current-environment-variables)
|
||||||
|
#"REQUEST_METHOD" (request-method req))
|
||||||
|
(putenv "PATH_INFO" (url-path-string (request-uri req)))
|
||||||
|
(putenv "QUERY_STRING" (url-query-string (request-uri req)))
|
||||||
|
|
||||||
|
(let ([content-type (headers-assq* #"Content-Type" (request-headers/raw req))])
|
||||||
|
(when content-type
|
||||||
|
(environment-variables-set! (current-environment-variables)
|
||||||
|
#"CONTENT_TYPE" (header-value content-type))))
|
||||||
|
|
||||||
|
; run git-http-backend
|
||||||
|
(match-define (list git-response-port git-body-port _ _ _)
|
||||||
|
(process*/ports #f #f (current-error-port)
|
||||||
|
(find-executable-path "git") "http-backend"))
|
||||||
|
|
||||||
|
; pass POST body to git-http-backend
|
||||||
|
(when (request-post-data/raw req)
|
||||||
|
(write-bytes (request-post-data/raw req) git-body-port))
|
||||||
|
(close-output-port git-body-port)
|
||||||
|
|
||||||
|
; convert CGI headers to ones the web server can understand
|
||||||
|
(define headers
|
||||||
|
(for/list ([line (in-lines git-response-port)]
|
||||||
|
#:break (zero? (string-length line)))
|
||||||
|
(apply header (map string->bytes/utf-8 (string-split line ": ")))))
|
||||||
|
|
||||||
|
; produce a response
|
||||||
|
(response 200 #"OK" (current-seconds) #f headers
|
||||||
|
(λ (out)
|
||||||
|
(copy-port git-response-port out)
|
||||||
|
(close-input-port git-response-port))))]
|
||||||
|
; if authorization fails, return a WWW-Authenticate header
|
||||||
|
[else (response/full 401 #"Authorization Required" (current-seconds)
|
||||||
|
#"text/plain; charset=utf-8"
|
||||||
|
(list (header #"WWW-Authenticate" #"Basic"))
|
||||||
|
(list #"Repository not found."))]))
|
||||||
|
|
||||||
|
(define (serve-git-http-proxy! #:port port)
|
||||||
|
(serve/servlet serve-git-http-proxy
|
||||||
|
#:port port
|
||||||
|
#:command-line? #t
|
||||||
|
#:servlet-regexp #rx""))
|
3
pkgs/racket-test/tests/pkg/test-pkgs/pkg-git/info.rkt
Normal file
3
pkgs/racket-test/tests/pkg/test-pkgs/pkg-git/info.rkt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#lang info
|
||||||
|
|
||||||
|
(define collection 'multi)
|
|
@ -14,6 +14,7 @@
|
||||||
(initialize-catalogs)
|
(initialize-catalogs)
|
||||||
|
|
||||||
$ "raco pkg config --set catalogs http://localhost:9990"
|
$ "raco pkg config --set catalogs http://localhost:9990"
|
||||||
|
$ "raco pkg config --set git-checkout-credentials user:password"
|
||||||
|
|
||||||
$ "racket -l racket/base -l pkg/lib -e '(pkg-config-catalogs)'"
|
$ "racket -l racket/base -l pkg/lib -e '(pkg-config-catalogs)'"
|
||||||
=stdout> "'(\"http://localhost:9990\")\n"
|
=stdout> "'(\"http://localhost:9990\")\n"
|
||||||
|
|
|
@ -251,4 +251,14 @@
|
||||||
$ "racket -e '(require pkg/lib)' -e '(path->pkg (build-path (pkg-directory \"pkg-test1\") \"pkg-test2\"))'"
|
$ "racket -e '(require pkg/lib)' -e '(path->pkg (build-path (pkg-directory \"pkg-test1\") \"pkg-test2\"))'"
|
||||||
=stdout> "\"pkg-test1\"\n"
|
=stdout> "\"pkg-test1\"\n"
|
||||||
$ "raco pkg remove pkg-test2-snd pkg-test1"
|
$ "raco pkg remove pkg-test2-snd pkg-test1"
|
||||||
$ "racket -e '(require pkg-test1)'" =exit> 1)))))
|
$ "racket -e '(require pkg-test1)'" =exit> 1))
|
||||||
|
|
||||||
|
(with-fake-root
|
||||||
|
(shelly-case
|
||||||
|
"git package that requires authentication"
|
||||||
|
$ "raco pkg config --set catalogs http://localhost:9990"
|
||||||
|
$ "raco pkg install pkg-git" =exit> 1
|
||||||
|
$ "raco pkg config --set git-checkout-credentials user:bad-password"
|
||||||
|
$ "raco pkg install pkg-git" =exit> 1
|
||||||
|
$ "raco pkg config --set git-checkout-credentials user:password"
|
||||||
|
$ "raco pkg install pkg-git")))))
|
||||||
|
|
|
@ -10,8 +10,10 @@
|
||||||
racket/list
|
racket/list
|
||||||
racket/format
|
racket/format
|
||||||
racket/port
|
racket/port
|
||||||
|
racket/string
|
||||||
setup/dirs
|
setup/dirs
|
||||||
"shelly.rkt")
|
"shelly.rkt"
|
||||||
|
"git-http-proxy.rkt")
|
||||||
|
|
||||||
(define-runtime-path test-source-directory ".")
|
(define-runtime-path test-source-directory ".")
|
||||||
|
|
||||||
|
@ -167,8 +169,11 @@
|
||||||
(with-thread
|
(with-thread
|
||||||
(λ () (start-pkg-server *index-ht-2* 9991))
|
(λ () (start-pkg-server *index-ht-2* 9991))
|
||||||
(λ ()
|
(λ ()
|
||||||
(with-thread (λ () (start-file-server))
|
(with-thread
|
||||||
t)))))]))
|
(λ () (start-file-server))
|
||||||
|
(λ ()
|
||||||
|
(with-thread (λ () (serve-git-http-proxy! #:port 9996))
|
||||||
|
t)))))))]))
|
||||||
(define-syntax-rule (with-servers e ...)
|
(define-syntax-rule (with-servers e ...)
|
||||||
(with-servers* (λ () e ...)))
|
(with-servers* (λ () e ...)))
|
||||||
|
|
||||||
|
@ -246,7 +251,28 @@
|
||||||
'source
|
'source
|
||||||
"http://localhost:9997/pkg-test2.zip"
|
"http://localhost:9997/pkg-test2.zip"
|
||||||
'dependencies
|
'dependencies
|
||||||
'("pkg-test1"))))
|
'("pkg-test1")))
|
||||||
|
|
||||||
|
(initialize-catalogs/git))
|
||||||
|
|
||||||
|
(define (initialize-catalogs/git)
|
||||||
|
(define pkg-git.git (make-temporary-file "pkg-git-~a.git"))
|
||||||
|
(delete-file pkg-git.git)
|
||||||
|
(parameterize ([current-directory (build-path test-source-directory "test-pkgs")])
|
||||||
|
(copy-directory/files (build-path test-source-directory "test-pkgs" "pkg-git") pkg-git.git))
|
||||||
|
(define checksum
|
||||||
|
(parameterize ([current-directory pkg-git.git])
|
||||||
|
(system "git init")
|
||||||
|
(system "git add -A")
|
||||||
|
(system "git commit -m 'initial commit'")
|
||||||
|
(string-trim
|
||||||
|
(with-output-to-string
|
||||||
|
(λ () (system "git rev-parse HEAD"))))))
|
||||||
|
|
||||||
|
(match-define-values [_ pkg-git.git-filename _] (split-path pkg-git.git))
|
||||||
|
(hash-set! *index-ht-1* "pkg-git"
|
||||||
|
(hasheq 'checksum checksum
|
||||||
|
'source (~a "http://localhost:9996/" (path->string pkg-git.git-filename)))))
|
||||||
|
|
||||||
(define (set-file path content)
|
(define (set-file path content)
|
||||||
(make-parent-directory* path)
|
(make-parent-directory* path)
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
file/gunzip
|
file/gunzip
|
||||||
file/private/check-path
|
file/private/check-path
|
||||||
openssl/sha1
|
openssl/sha1
|
||||||
|
net/base64
|
||||||
net/url
|
net/url
|
||||||
net/head
|
net/head
|
||||||
net/http-client
|
net/http-client
|
||||||
|
@ -16,10 +17,22 @@
|
||||||
;; http://stefan.saasen.me/articles/git-clone-in-haskell-from-the-bottom-up/
|
;; http://stefan.saasen.me/articles/git-clone-in-haskell-from-the-bottom-up/
|
||||||
;; provided many helpful hints for this implementation.
|
;; provided many helpful hints for this implementation.
|
||||||
|
|
||||||
(provide git-checkout)
|
(provide git-checkout
|
||||||
|
current-git-username
|
||||||
|
current-git-password
|
||||||
|
(struct-out exn:fail:git))
|
||||||
|
|
||||||
(define-logger git-checkout)
|
(define-logger git-checkout)
|
||||||
|
|
||||||
|
(define current-git-username (make-parameter #f))
|
||||||
|
(define current-git-password (make-parameter #f))
|
||||||
|
|
||||||
|
(struct exn:fail:git exn:fail () #:transparent)
|
||||||
|
|
||||||
|
(define (raise-git-error name fmt . vals)
|
||||||
|
(raise (exn:fail:git (apply format (string-append "~s: " fmt) name vals)
|
||||||
|
(current-continuation-marks))))
|
||||||
|
|
||||||
;; Like `git clone`, but producing just the checkout
|
;; Like `git clone`, but producing just the checkout
|
||||||
(define (git-checkout host
|
(define (git-checkout host
|
||||||
repo
|
repo
|
||||||
|
@ -35,7 +48,9 @@
|
||||||
#:clean-tmp-dir? [clean-tmp-dir? (not given-tmp-dir)]
|
#:clean-tmp-dir? [clean-tmp-dir? (not given-tmp-dir)]
|
||||||
#:verify-server? [verify? #t]
|
#:verify-server? [verify? #t]
|
||||||
#:port [given-port #f]
|
#:port [given-port #f]
|
||||||
#:strict-links? [strict-links? #f])
|
#:strict-links? [strict-links? #f]
|
||||||
|
#:username [username (current-git-username)]
|
||||||
|
#:password [password (current-git-password)])
|
||||||
(let retry-loop ([given-depth given-depth])
|
(let retry-loop ([given-depth given-depth])
|
||||||
(define tmp-dir (or given-tmp-dir
|
(define tmp-dir (or given-tmp-dir
|
||||||
(make-temporary-file "git~a" 'directory)))
|
(make-temporary-file "git~a" 'directory)))
|
||||||
|
@ -51,7 +66,7 @@
|
||||||
|
|
||||||
(status "Contacting ~a" host)
|
(status "Contacting ~a" host)
|
||||||
(define-values (i o dumb-protocol?)
|
(define-values (i o dumb-protocol?)
|
||||||
(initial-connect transport host verify? port repo status))
|
(initial-connect transport host verify? port repo status username password))
|
||||||
((let/ec esc
|
((let/ec esc
|
||||||
(dynamic-wind
|
(dynamic-wind
|
||||||
void
|
void
|
||||||
|
@ -66,7 +81,7 @@
|
||||||
;; smart protocol provides packets:
|
;; smart protocol provides packets:
|
||||||
(read-pkts i)))
|
(read-pkts i)))
|
||||||
(unless (pair? pkts)
|
(unless (pair? pkts)
|
||||||
(error 'git-checkout "no initial pkts from the server"))
|
(raise-git-error 'git-checkout "no initial pkts from the server"))
|
||||||
|
|
||||||
;; Parse server's initial reply
|
;; Parse server's initial reply
|
||||||
(define server-capabilities (parse-server-capabilities (car pkts)))
|
(define server-capabilities (parse-server-capabilities (car pkts)))
|
||||||
|
@ -106,7 +121,7 @@
|
||||||
|
|
||||||
;; Tell the server that we're ready for the objects
|
;; Tell the server that we're ready for the objects
|
||||||
(write-pkt o "done\n")
|
(write-pkt o "done\n")
|
||||||
(set!-values (i o) (done-step transport host verify? port repo i o))
|
(set!-values (i o) (done-step transport host verify? port repo username password i o))
|
||||||
|
|
||||||
(when depth
|
(when depth
|
||||||
;; If we wrote `deepen`, then the server replies with `shallow`s.
|
;; If we wrote `deepen`, then the server replies with `shallow`s.
|
||||||
|
@ -120,12 +135,12 @@
|
||||||
[(regexp-match? #rx"^shallow " r)
|
[(regexp-match? #rx"^shallow " r)
|
||||||
(loop)]
|
(loop)]
|
||||||
[else
|
[else
|
||||||
(error 'git-checkout "expected shallow, got ~s" r)])))
|
(raise-git-error 'git-checkout "expected shallow, got ~s" r)])))
|
||||||
|
|
||||||
;; Tell the server that we're ready for the objects
|
;; Tell the server that we're ready for the objects
|
||||||
(define nak (read-pkt i))
|
(define nak (read-pkt i))
|
||||||
(unless (equal? #"NAK\n" nak)
|
(unless (equal? #"NAK\n" nak)
|
||||||
(error 'git-checkout "expected NAK, got ~s" nak)))
|
(raise-git-error 'git-checkout "expected NAK, got ~s" nak)))
|
||||||
|
|
||||||
(make-directory* tmp-dir)
|
(make-directory* tmp-dir)
|
||||||
(define tmp (make-tmp-info tmp-dir #:fresh? #t))
|
(define tmp (make-tmp-info tmp-dir #:fresh? #t))
|
||||||
|
@ -189,18 +204,23 @@
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
;; Transports: git, http, and https
|
;; Transports: git, http, and https
|
||||||
|
|
||||||
(define http-request-headers
|
(define (http-request-headers username password)
|
||||||
;; bitbucket.org seems to require a "git" value for "User-Agent",
|
;; bitbucket.org seems to require a "git" value for "User-Agent",
|
||||||
;; otherwise it returns a "broken link" web page
|
;; otherwise it returns a "broken link" web page
|
||||||
'("User-Agent: git/1.9"))
|
(define base-headers '("User-Agent: git/1.9"))
|
||||||
|
;; include an Authorization header if credentials are provided
|
||||||
|
(if (and username password)
|
||||||
|
(cons (~a "Authorization: Basic " (base64-encode (string->bytes/utf-8 (~a username ":" password)) #""))
|
||||||
|
base-headers)
|
||||||
|
base-headers))
|
||||||
|
|
||||||
;; initial-connect: transport-sym string bool natural string status-proc
|
;; initial-connect: transport-sym string bool natural string status-proc string string
|
||||||
;; -> (values input-port output-port boolean)
|
;; -> (values input-port output-port boolean)
|
||||||
;; Contacts the server and returns an output port for writing
|
;; Contacts the server and returns an output port for writing
|
||||||
;; the request (ignored if not needed for the the transport)
|
;; the request (ignored if not needed for the the transport)
|
||||||
;; and an input port from reading the available references. The
|
;; and an input port from reading the available references. The
|
||||||
;; boolean result indicates whether the protocol is "dumb".
|
;; boolean result indicates whether the protocol is "dumb".
|
||||||
(define (initial-connect transport host verify? port repo status)
|
(define (initial-connect transport host verify? port repo status username password)
|
||||||
(case transport
|
(case transport
|
||||||
[(git)
|
[(git)
|
||||||
(define-values (i o) (tcp-or-tunnel-connect "git" host port))
|
(define-values (i o) (tcp-or-tunnel-connect "git" host port))
|
||||||
|
@ -212,7 +232,7 @@
|
||||||
(define-values (i headers)
|
(define-values (i headers)
|
||||||
(parameterize ([current-https-protocol (ssl-context verify?)])
|
(parameterize ([current-https-protocol (ssl-context verify?)])
|
||||||
(get-pure-port/headers (string->url url-str)
|
(get-pure-port/headers (string->url url-str)
|
||||||
http-request-headers
|
(http-request-headers username password)
|
||||||
#:redirections 5)))
|
#:redirections 5)))
|
||||||
(define ok? #f)
|
(define ok? #f)
|
||||||
(dynamic-wind
|
(dynamic-wind
|
||||||
|
@ -224,14 +244,14 @@
|
||||||
"application/x-git-upload-pack-advertisement")
|
"application/x-git-upload-pack-advertisement")
|
||||||
;; "smart" protocol
|
;; "smart" protocol
|
||||||
(unless (regexp-match-peek #px#"^[0-9a-f]{4}#" i)
|
(unless (regexp-match-peek #px#"^[0-9a-f]{4}#" i)
|
||||||
(error 'git-checkout (~a "error reading repository content;\n"
|
(raise-git-error 'git-checkout (~a "error reading repository content;\n"
|
||||||
" response is not consistent with the Git protocol\n"
|
" response is not consistent with the Git protocol\n"
|
||||||
" initial portion: ~s")
|
" initial portion: ~s")
|
||||||
(read-bytes 640 i)))
|
(read-bytes 640 i)))
|
||||||
(define pkt (read-pkt i))
|
(define pkt (read-pkt i))
|
||||||
(define term-pkt (read-pkt i))
|
(define term-pkt (read-pkt i))
|
||||||
(unless (eof-object? term-pkt)
|
(unless (eof-object? term-pkt)
|
||||||
(error 'git-checkout (~a "expected a null packet, received something else\n"
|
(raise-git-error 'git-checkout (~a "expected a null packet, received something else\n"
|
||||||
" packet: ~s")
|
" packet: ~s")
|
||||||
term-pkt))
|
term-pkt))
|
||||||
#f]
|
#f]
|
||||||
|
@ -243,7 +263,7 @@
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(unless ok? (close-input-port i))))]
|
(unless ok? (close-input-port i))))]
|
||||||
[else
|
[else
|
||||||
(error 'git-checkout "unrecognized transport\n given: ~e" transport)]))
|
(raise-git-error 'git-checkout "unrecognized transport\n given: ~e" transport)]))
|
||||||
|
|
||||||
;; want-step: transport-sym string natural string input-port output-port
|
;; want-step: transport-sym string natural string input-port output-port
|
||||||
;; -> (values input-port output-port)
|
;; -> (values input-port output-port)
|
||||||
|
@ -256,12 +276,12 @@
|
||||||
(close-input-port i)
|
(close-input-port i)
|
||||||
(values (open-input-bytes #"") (open-output-bytes))]))
|
(values (open-input-bytes #"") (open-output-bytes))]))
|
||||||
|
|
||||||
;; done-step: transport-sym string bool natural string input-port output-port
|
;; done-step: transport-sym string bool natural string string string input-port output-port
|
||||||
;; -> (values input-port output-port)
|
;; -> (values input-port output-port)
|
||||||
;; Replaces the connection, if appropriate to the transport, after
|
;; Replaces the connection, if appropriate to the transport, after
|
||||||
;; writing the wanted references and before reading the server's
|
;; writing the wanted references and before reading the server's
|
||||||
;; response.
|
;; response.
|
||||||
(define (done-step transport host verify? port repo i o)
|
(define (done-step transport host verify? port repo username password i o)
|
||||||
(case transport
|
(case transport
|
||||||
[(git) (values i o)]
|
[(git) (values i o)]
|
||||||
[(http https)
|
[(http https)
|
||||||
|
@ -274,7 +294,7 @@
|
||||||
"/git-upload-pack"))
|
"/git-upload-pack"))
|
||||||
s
|
s
|
||||||
(append
|
(append
|
||||||
http-request-headers
|
(http-request-headers username password)
|
||||||
(list "Content-Type: application/x-git-upload-pack-request")))))
|
(list "Content-Type: application/x-git-upload-pack-request")))))
|
||||||
(values i (open-output-nowhere))]))
|
(values i (open-output-nowhere))]))
|
||||||
|
|
||||||
|
@ -305,8 +325,7 @@
|
||||||
(define m (regexp-match #px#"^([0-9a-fA-F]{40})[ \t]([^\0\n]+)[\0\n]" pkt))
|
(define m (regexp-match #px#"^([0-9a-fA-F]{40})[ \t]([^\0\n]+)[\0\n]" pkt))
|
||||||
(unless m
|
(unless m
|
||||||
(when initial-error (initial-error))
|
(when initial-error (initial-error))
|
||||||
(error 'git-checkout "could not parse ref pkt\n pkt: ~s"
|
(raise-git-error 'git-checkout "could not parse ref pkt\n pkt: ~s" pkt))
|
||||||
pkt))
|
|
||||||
(define name (caddr m))
|
(define name (caddr m))
|
||||||
(define id (bytes->string/utf-8 (cadr m)))
|
(define id (bytes->string/utf-8 (cadr m)))
|
||||||
(cond
|
(cond
|
||||||
|
@ -351,7 +370,7 @@
|
||||||
(for/list ([ref (in-list refs)])
|
(for/list ([ref (in-list refs)])
|
||||||
(cadr ref))]
|
(cadr ref))]
|
||||||
[else
|
[else
|
||||||
(error 'git "could not find requested reference\n reference: ~a" ref)]))
|
(raise-git-error 'git "could not find requested reference\n reference: ~a" ref)]))
|
||||||
|
|
||||||
(values ref-commit want-commits))
|
(values ref-commit want-commits))
|
||||||
|
|
||||||
|
@ -389,16 +408,16 @@
|
||||||
[else
|
[else
|
||||||
(unless (and (bytes? len-bstr)
|
(unless (and (bytes? len-bstr)
|
||||||
(= 4 (bytes-length len-bstr)))
|
(= 4 (bytes-length len-bstr)))
|
||||||
(error 'git-checkout "error getting pkt length"))
|
(raise-git-error 'git-checkout "error getting pkt length"))
|
||||||
(define len (string->number (bytes->string/utf-8 len-bstr #\?) 16))
|
(define len (string->number (bytes->string/utf-8 len-bstr #\?) 16))
|
||||||
(unless len
|
(unless len
|
||||||
(error 'git-checkout "error getting pkt length\n length string: ~e" len-bstr))
|
(raise-git-error 'git-checkout "error getting pkt length\n length string: ~e" len-bstr))
|
||||||
(cond
|
(cond
|
||||||
[(= len 0) eof] ; flush pkt
|
[(= len 0) eof] ; flush pkt
|
||||||
[else
|
[else
|
||||||
(define payload-len (- len 4))
|
(define payload-len (- len 4))
|
||||||
(unless (payload-len . >= . 0)
|
(unless (payload-len . >= . 0)
|
||||||
(error 'git-checkout "pkt length makes no sense\n length: ~a" len))
|
(raise-git-error 'git-checkout "pkt length makes no sense\n length: ~a" len))
|
||||||
(read-bytes-exactly 'payload payload-len i)])]))
|
(read-bytes-exactly 'payload payload-len i)])]))
|
||||||
|
|
||||||
;; read a list of pkts until an empty packet is found
|
;; read a list of pkts until an empty packet is found
|
||||||
|
@ -427,10 +446,10 @@
|
||||||
(when (and (eof-object? pack-bstr)
|
(when (and (eof-object? pack-bstr)
|
||||||
initial-eof-handler)
|
initial-eof-handler)
|
||||||
(initial-eof-handler))
|
(initial-eof-handler))
|
||||||
(error 'git-checkout "header error\n bytes: ~s" pack-bstr))
|
(raise-git-error 'git-checkout "header error\n bytes: ~s" pack-bstr))
|
||||||
(define vers (read-bytes 4 i))
|
(define vers (read-bytes 4 i))
|
||||||
(unless (equal? vers #"\0\0\0\2")
|
(unless (equal? vers #"\0\0\0\2")
|
||||||
(error 'git-checkout "only version 2 supported"))
|
(raise-git-error 'git-checkout "only version 2 supported"))
|
||||||
(define count-bstr (read-bytes-exactly 'count 4 i))
|
(define count-bstr (read-bytes-exactly 'count 4 i))
|
||||||
(define count (integer-bytes->integer count-bstr #t #t))
|
(define count (integer-bytes->integer count-bstr #t #t))
|
||||||
(define obj-stream-poses (make-hash)) ; for OBJ_OFS_DELTA references
|
(define obj-stream-poses (make-hash)) ; for OBJ_OFS_DELTA references
|
||||||
|
@ -458,7 +477,7 @@
|
||||||
(define obj-stream-pos (file-position i))
|
(define obj-stream-pos (file-position i))
|
||||||
(define c (read-byte-only 'type-and-size i))
|
(define c (read-byte-only 'type-and-size i))
|
||||||
(define type (bitwise-and (arithmetic-shift c -4) #x7))
|
(define type (bitwise-and (arithmetic-shift c -4) #x7))
|
||||||
(when (zero? type) (error 'git-checkout "bad packfile type"))
|
(when (zero? type) (raise-git-error 'git-checkout "bad packfile type"))
|
||||||
(define init-len (bitwise-and c #xF))
|
(define init-len (bitwise-and c #xF))
|
||||||
(define len
|
(define len
|
||||||
(if (msb-set? c)
|
(if (msb-set? c)
|
||||||
|
@ -472,7 +491,7 @@
|
||||||
[(ofs-delta)
|
[(ofs-delta)
|
||||||
(define delta (read-offset-integer i))
|
(define delta (read-offset-integer i))
|
||||||
(hash-ref obj-stream-poses (- obj-stream-pos delta)
|
(hash-ref obj-stream-poses (- obj-stream-pos delta)
|
||||||
(lambda () (error 'git-checkout "OBJ_OFS_DELTA object not found")))]
|
(lambda () (raise-git-error 'git-checkout "OBJ_OFS_DELTA object not found")))]
|
||||||
[else #f]))
|
[else #f]))
|
||||||
(define obj
|
(define obj
|
||||||
(save-object (lambda (o) (zlib-inflate i o)) len type-sym type-info tmp))
|
(save-object (lambda (o) (zlib-inflate i o)) len type-sym type-info tmp))
|
||||||
|
@ -592,9 +611,9 @@
|
||||||
(cond
|
(cond
|
||||||
[(= 1 (length matches)) (car matches)]
|
[(= 1 (length matches)) (car matches)]
|
||||||
[(null? matches)
|
[(null? matches)
|
||||||
(error 'git-checkout "no commit found matching id: ~a" ref)]
|
(raise-git-error 'git-checkout "no commit found matching id: ~a" ref)]
|
||||||
[else
|
[else
|
||||||
(error 'git-checkout "found multiple commits matching id: ~a" ref)]))
|
(raise-git-error 'git-checkout "found multiple commits matching id: ~a" ref)]))
|
||||||
|
|
||||||
(define (id-ref->regexp ref)
|
(define (id-ref->regexp ref)
|
||||||
(regexp (~a "^" (regexp-quote (string-downcase ref)))))
|
(regexp (~a "^" (regexp-quote (string-downcase ref)))))
|
||||||
|
@ -624,7 +643,7 @@
|
||||||
(lambda (i)
|
(lambda (i)
|
||||||
(define m (regexp-try-match #px"^object ([0-9a-fA-F]{40})" i))
|
(define m (regexp-try-match #px"^object ([0-9a-fA-F]{40})" i))
|
||||||
(unless m
|
(unless m
|
||||||
(error 'git-checkout "cannot extract commit from tag file for ~s"
|
(raise-git-error 'git-checkout "cannot extract commit from tag file for ~s"
|
||||||
(bytes->hex-string obj-id)))
|
(bytes->hex-string obj-id)))
|
||||||
(cadr m))))
|
(cadr m))))
|
||||||
(define commit-id (hex-string->bytes (bytes->string/utf-8 commit-id-bstr)))
|
(define commit-id (hex-string->bytes (bytes->string/utf-8 commit-id-bstr)))
|
||||||
|
@ -632,7 +651,7 @@
|
||||||
[(tree)
|
[(tree)
|
||||||
(extract-tree obj-id obj-ids tmp dest-dir strict-links?)]
|
(extract-tree obj-id obj-ids tmp dest-dir strict-links?)]
|
||||||
[else
|
[else
|
||||||
(error 'git-checkout "cannot extract tree from ~a: ~s"
|
(raise-git-error 'git-checkout "cannot extract tree from ~a: ~s"
|
||||||
(object-type obj)
|
(object-type obj)
|
||||||
(bytes->hex-string obj-id))]))
|
(bytes->hex-string obj-id))]))
|
||||||
|
|
||||||
|
@ -642,7 +661,7 @@
|
||||||
(define (extract-commit-info i obj-id)
|
(define (extract-commit-info i obj-id)
|
||||||
(define m (regexp-try-match #px"^tree ([0-9a-fA-F]{40})" i))
|
(define m (regexp-try-match #px"^tree ([0-9a-fA-F]{40})" i))
|
||||||
(unless m
|
(unless m
|
||||||
(error 'git-checkout
|
(raise-git-error 'git-checkout
|
||||||
(~a "cannot extract tree from commit file for ~s\n"
|
(~a "cannot extract tree from commit file for ~s\n"
|
||||||
" content starts: ~s")
|
" content starts: ~s")
|
||||||
(bytes->hex-string obj-id)
|
(bytes->hex-string obj-id)
|
||||||
|
@ -693,7 +712,7 @@
|
||||||
;; submodule; just make a directory placeholder
|
;; submodule; just make a directory placeholder
|
||||||
(make-directory* (build-path dest-dir fn))]
|
(make-directory* (build-path dest-dir fn))]
|
||||||
[else
|
[else
|
||||||
(error 'extract-tree "unknown mode: ~s" mode)])
|
(raise-git-error 'extract-tree "unknown mode: ~s" mode)])
|
||||||
(loop))))))
|
(loop))))))
|
||||||
|
|
||||||
;; extract-tree-entry: input-port -> bytes-or-#f bytes-or-#f path-or-#f
|
;; extract-tree-entry: input-port -> bytes-or-#f bytes-or-#f path-or-#f
|
||||||
|
@ -758,7 +777,7 @@
|
||||||
(for/list ([l (in-lines i)]
|
(for/list ([l (in-lines i)]
|
||||||
#:unless (equal? l ""))
|
#:unless (equal? l ""))
|
||||||
(define m (regexp-match #rx"^P (.*)" l))
|
(define m (regexp-match #rx"^P (.*)" l))
|
||||||
(unless m (error 'git-checkout "error parsing packfile list line\n line: ~e" l))
|
(unless m (raise-git-error 'git-checkout "error parsing packfile list line\n line: ~e" l))
|
||||||
(cadr m)))
|
(cadr m)))
|
||||||
|
|
||||||
;; read-dumb-packfile : string (hashof string object) tmp conn strung status
|
;; read-dumb-packfile : string (hashof string object) tmp conn strung status
|
||||||
|
@ -818,7 +837,7 @@
|
||||||
;; Parse the object description:
|
;; Parse the object description:
|
||||||
(define header-m (regexp-try-match #rx#"^[^\0]*\0" i))
|
(define header-m (regexp-try-match #rx#"^[^\0]*\0" i))
|
||||||
(unless header-m
|
(unless header-m
|
||||||
(error 'git-checkout "bad initial line for object content"))
|
(raise-git-error 'git-checkout "bad initial line for object content"))
|
||||||
(define header (car header-m))
|
(define header (car header-m))
|
||||||
(define header-len (bytes-length header))
|
(define header-len (bytes-length header))
|
||||||
(define type-sym (string->symbol
|
(define type-sym (string->symbol
|
||||||
|
@ -827,7 +846,7 @@
|
||||||
(bytes->string/utf-8 (cadr (or (regexp-match #rx"[^ ]* ([0-9]+)" header)
|
(bytes->string/utf-8 (cadr (or (regexp-match #rx"[^ ]* ([0-9]+)" header)
|
||||||
'(#"" #""))))))
|
'(#"" #""))))))
|
||||||
(unless (memq type-sym valid-types)
|
(unless (memq type-sym valid-types)
|
||||||
(error 'git-checkout "bad type: ~e" type-sym))
|
(raise-git-error 'git-checkout "bad type: ~e" type-sym))
|
||||||
|
|
||||||
(define obj
|
(define obj
|
||||||
(save-object (lambda (o) (copy-port i o))
|
(save-object (lambda (o) (copy-port i o))
|
||||||
|
@ -882,7 +901,7 @@
|
||||||
(define status (let ([m (regexp-match #rx"^[^ ]* ([0-9]+)" status-line)])
|
(define status (let ([m (regexp-match #rx"^[^ ]* ([0-9]+)" status-line)])
|
||||||
(and m (string->number (bytes->string/utf-8 (cadr m))))))
|
(and m (string->number (bytes->string/utf-8 (cadr m))))))
|
||||||
(unless (memv status '(200))
|
(unless (memv status '(200))
|
||||||
(error 'git-checkout "~a\n server respone: ~a"
|
(raise-git-error 'git-checkout "~a\n server respone: ~a"
|
||||||
msg
|
msg
|
||||||
status-line)))
|
status-line)))
|
||||||
|
|
||||||
|
@ -914,7 +933,7 @@
|
||||||
(define (call-with-output-object tmp filename len proc)
|
(define (call-with-output-object tmp filename len proc)
|
||||||
(define (check-len got-len)
|
(define (check-len got-len)
|
||||||
(unless (= len got-len)
|
(unless (= len got-len)
|
||||||
(error 'git-checkout "size mismatch\n expected: ~a\n received: ~a"
|
(raise-git-error 'git-checkout "size mismatch\n expected: ~a\n received: ~a"
|
||||||
len
|
len
|
||||||
got-len)))
|
got-len)))
|
||||||
(cond
|
(cond
|
||||||
|
@ -981,7 +1000,7 @@
|
||||||
(define bstr (read-bytes len i))
|
(define bstr (read-bytes len i))
|
||||||
(unless (and (bytes? bstr)
|
(unless (and (bytes? bstr)
|
||||||
(= (bytes-length bstr) len))
|
(= (bytes-length bstr) len))
|
||||||
(error 'git-checkout (~a "error getting bytes for ~a\n"
|
(raise-git-error 'git-checkout (~a "error getting bytes for ~a\n"
|
||||||
" expected length: ~a\n"
|
" expected length: ~a\n"
|
||||||
" got length: ~a")
|
" got length: ~a")
|
||||||
what
|
what
|
||||||
|
@ -994,8 +1013,7 @@
|
||||||
(define (read-byte-only what i)
|
(define (read-byte-only what i)
|
||||||
(define c (read-byte i))
|
(define c (read-byte i))
|
||||||
(unless (byte? c)
|
(unless (byte? c)
|
||||||
(error 'git-checkout "expected to get a byte for ~a, got enf-of-file"
|
(raise-git-error 'git-checkout "expected to get a byte for ~a, got enf-of-file" what))
|
||||||
what))
|
|
||||||
c)
|
c)
|
||||||
|
|
||||||
;; copy-port-n : input-port output-port natural -> void
|
;; copy-port-n : input-port output-port natural -> void
|
||||||
|
@ -1005,7 +1023,7 @@
|
||||||
(define bstr (read-bytes n i))
|
(define bstr (read-bytes n i))
|
||||||
(unless (and (bytes? bstr)
|
(unless (and (bytes? bstr)
|
||||||
(= (bytes-length bstr) n))
|
(= (bytes-length bstr) n))
|
||||||
(error 'git-checkout "not enough bytes during copy"))
|
(raise-git-error 'git-checkout "not enough bytes during copy"))
|
||||||
(write-bytes bstr o)]
|
(write-bytes bstr o)]
|
||||||
[else
|
[else
|
||||||
(copy-port-n i o 4096)
|
(copy-port-n i o 4096)
|
||||||
|
@ -1068,7 +1086,7 @@
|
||||||
(define cmf (read-byte-only 'zlib-cmf i))
|
(define cmf (read-byte-only 'zlib-cmf i))
|
||||||
(define flg (read-byte-only 'zlib-flag i))
|
(define flg (read-byte-only 'zlib-flag i))
|
||||||
(unless (= 8 (bitwise-and cmf #xF))
|
(unless (= 8 (bitwise-and cmf #xF))
|
||||||
(error 'git-checkout "compression is not `deflate`"))
|
(raise-git-error 'git-checkout "compression is not `deflate`"))
|
||||||
(when (bitwise-bit-set? flg 5)
|
(when (bitwise-bit-set? flg 5)
|
||||||
;; read dictid
|
;; read dictid
|
||||||
(read-bytes-exactly 'dictid 4 i))
|
(read-bytes-exactly 'dictid 4 i))
|
||||||
|
@ -1109,6 +1127,10 @@
|
||||||
(set! ref branch/tag/commit)]
|
(set! ref branch/tag/commit)]
|
||||||
[("--tmp") dir "Write temporary files to <dir>"
|
[("--tmp") dir "Write temporary files to <dir>"
|
||||||
(set! tmp-dir dir)]
|
(set! tmp-dir dir)]
|
||||||
|
[("-u" "--username") username "Username used to authenticate over HTTP(S)"
|
||||||
|
(current-git-username username)]
|
||||||
|
[("-p" "--password") password "Password used to authenticate over HTTP(S)"
|
||||||
|
(current-git-password password)]
|
||||||
[("--quiet") "Suppress status printouts"
|
[("--quiet") "Suppress status printouts"
|
||||||
(set! status-printf void)]
|
(set! status-printf void)]
|
||||||
#:args (host repo dest)
|
#:args (host repo dest)
|
||||||
|
|
24
racket/collects/pkg/private/checkout-credentials.rkt
Normal file
24
racket/collects/pkg/private/checkout-credentials.rkt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(require net/git-checkout
|
||||||
|
racket/list
|
||||||
|
"config.rkt")
|
||||||
|
|
||||||
|
(provide call-with-git-checkout-credentials)
|
||||||
|
|
||||||
|
(define (call-with-git-checkout-credentials thunk)
|
||||||
|
(let loop ([credentials-list (cons #f (get-git-checkout-credentials))])
|
||||||
|
(define credentials (first credentials-list))
|
||||||
|
(with-handlers ([exn:fail:git? (λ (exn)
|
||||||
|
(if (empty? (rest credentials-list))
|
||||||
|
(raise exn)
|
||||||
|
(loop (rest credentials-list))))])
|
||||||
|
(define c (make-custodian))
|
||||||
|
(parameterize ([current-custodian c]
|
||||||
|
[current-git-username (and credentials (hash-ref credentials 'username))]
|
||||||
|
[current-git-password (and credentials (hash-ref credentials 'password))])
|
||||||
|
(dynamic-wind
|
||||||
|
void
|
||||||
|
thunk
|
||||||
|
(lambda ()
|
||||||
|
(custodian-shutdown-all c)))))))
|
|
@ -4,6 +4,7 @@
|
||||||
racket/path
|
racket/path
|
||||||
racket/match
|
racket/match
|
||||||
racket/format
|
racket/format
|
||||||
|
racket/string
|
||||||
net/url
|
net/url
|
||||||
"../path.rkt"
|
"../path.rkt"
|
||||||
"dirs.rkt"
|
"dirs.rkt"
|
||||||
|
@ -37,6 +38,10 @@
|
||||||
(or (current-pkg-network-retries)
|
(or (current-pkg-network-retries)
|
||||||
(read-pkg-cfg/def 'network-retries)))
|
(read-pkg-cfg/def 'network-retries)))
|
||||||
|
|
||||||
|
(define (get-git-checkout-credentials)
|
||||||
|
(or (current-pkg-git-checkout-credentials)
|
||||||
|
(read-pkg-cfg/def 'git-checkout-credentials)))
|
||||||
|
|
||||||
(define (read-pkg-cfg/def k)
|
(define (read-pkg-cfg/def k)
|
||||||
;; Lock is held for the current scope, but if
|
;; Lock is held for the current scope, but if
|
||||||
;; the key is not found in the current scope,
|
;; the key is not found in the current scope,
|
||||||
|
@ -56,6 +61,7 @@
|
||||||
['trash-max-packages 512]
|
['trash-max-packages 512]
|
||||||
['trash-max-seconds (* 60 60 24 2)] ; 2 days
|
['trash-max-seconds (* 60 60 24 2)] ; 2 days
|
||||||
['network-retries 5]
|
['network-retries 5]
|
||||||
|
['git-checkout-credentials '()]
|
||||||
[_ #f]))
|
[_ #f]))
|
||||||
(define c (read-pkg-file-hash (pkg-config-file)))
|
(define c (read-pkg-file-hash (pkg-config-file)))
|
||||||
(define v (hash-ref c k 'none))
|
(define v (hash-ref c k 'none))
|
||||||
|
@ -197,6 +203,35 @@
|
||||||
" current package scope: ~a")
|
" current package scope: ~a")
|
||||||
(current-pkg-scope)))
|
(current-pkg-scope)))
|
||||||
(update-pkg-cfg! 'doc-open-url (if (equal? val "") #f val))]
|
(update-pkg-cfg! 'doc-open-url (if (equal? val "") #f val))]
|
||||||
|
[(list* "git-checkout-credentials" vals)
|
||||||
|
(define (credentials-format-error msg val)
|
||||||
|
(pkg-error (~a msg "\n"
|
||||||
|
" given: ~a\n"
|
||||||
|
" expected: value in the form <username>:<password>")
|
||||||
|
val))
|
||||||
|
(update-pkg-cfg! 'git-checkout-credentials
|
||||||
|
(for/list ([val (in-list vals)])
|
||||||
|
(match (string-split val ":" #:trim? #f)
|
||||||
|
[(list "" _)
|
||||||
|
(credentials-format-error
|
||||||
|
"invalid empty username in git checkout credentials"
|
||||||
|
val)]
|
||||||
|
[(list _ "")
|
||||||
|
(credentials-format-error
|
||||||
|
"invalid empty password in git checkout credentials"
|
||||||
|
val)]
|
||||||
|
[(list username password)
|
||||||
|
`#hasheq((username . ,username)
|
||||||
|
(password . ,password))]
|
||||||
|
[(list* _ _ _)
|
||||||
|
(credentials-format-error
|
||||||
|
"too many elements for git checkout credentials"
|
||||||
|
val)]
|
||||||
|
[(list _)
|
||||||
|
(credentials-format-error
|
||||||
|
"not enough elements for git checkout credentials"
|
||||||
|
val)])))
|
||||||
|
(displayln "WARNING: checkout credentials are stored UNENCRYPTED" (current-error-port))]
|
||||||
[(list* key args)
|
[(list* key args)
|
||||||
(pkg-error "unsupported config key\n key: ~a" key)])]
|
(pkg-error "unsupported config key\n key: ~a" key)])]
|
||||||
[else
|
[else
|
||||||
|
@ -220,6 +255,9 @@
|
||||||
(printf "~a~a\n" indent (read-pkg-cfg/def (string->symbol key)))]
|
(printf "~a~a\n" indent (read-pkg-cfg/def (string->symbol key)))]
|
||||||
["doc-open-url"
|
["doc-open-url"
|
||||||
(printf "~a~a\n" indent (or (read-pkg-cfg/def 'doc-open-url) ""))]
|
(printf "~a~a\n" indent (or (read-pkg-cfg/def 'doc-open-url) ""))]
|
||||||
|
["git-checkout-credentials"
|
||||||
|
(for ([creds (in-list (read-pkg-cfg/def 'git-checkout-credentials))])
|
||||||
|
(printf "~a~a:~a\n" indent (hash-ref creds 'username) (hash-ref creds 'password)))]
|
||||||
[_
|
[_
|
||||||
(pkg-error "unsupported config key\n key: ~e" key)])]
|
(pkg-error "unsupported config key\n key: ~e" key)])]
|
||||||
[(list)
|
[(list)
|
||||||
|
@ -237,6 +275,7 @@
|
||||||
"download-cache-dir"
|
"download-cache-dir"
|
||||||
"download-cache-max-files"
|
"download-cache-max-files"
|
||||||
"download-cache-max-bytes"
|
"download-cache-max-bytes"
|
||||||
|
"git-checkout-credentials"
|
||||||
"trash-max-packages"
|
"trash-max-packages"
|
||||||
"trash-max-seconds"
|
"trash-max-seconds"
|
||||||
"network-retries"))])
|
"network-retries"))])
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"path.rkt"
|
"path.rkt"
|
||||||
"print.rkt"
|
"print.rkt"
|
||||||
"config.rkt"
|
"config.rkt"
|
||||||
|
"checkout-credentials.rkt"
|
||||||
"network.rkt")
|
"network.rkt")
|
||||||
|
|
||||||
(provide download-file!
|
(provide download-file!
|
||||||
|
@ -101,6 +102,8 @@
|
||||||
(define (download!)
|
(define (download!)
|
||||||
(when download-printf
|
(when download-printf
|
||||||
(download-printf "Downloading repository ~a\n" (url->string url)))
|
(download-printf "Downloading repository ~a\n" (url->string url)))
|
||||||
|
(call-with-git-checkout-credentials
|
||||||
|
(lambda ()
|
||||||
(call-with-network-retries
|
(call-with-network-retries
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(git-checkout host #:port port repo
|
(git-checkout host #:port port repo
|
||||||
|
@ -109,10 +112,11 @@
|
||||||
#:status-printf (lambda (fmt . args)
|
#:status-printf (lambda (fmt . args)
|
||||||
(define (strip-ending-newline s)
|
(define (strip-ending-newline s)
|
||||||
(regexp-replace #rx"\n$" s ""))
|
(regexp-replace #rx"\n$" s ""))
|
||||||
(log-pkg-debug (strip-ending-newline (apply format fmt args))))
|
(log-pkg-debug (strip-ending-newline
|
||||||
|
(apply format fmt args))))
|
||||||
#:transport transport
|
#:transport transport
|
||||||
#:strict-links? #t
|
#:strict-links? #t
|
||||||
#:depth 1)))
|
#:depth 1)))))
|
||||||
(set! unpacked? #t)
|
(set! unpacked? #t)
|
||||||
;; package directory as ".tgz" so it can be cached:
|
;; package directory as ".tgz" so it can be cached:
|
||||||
(parameterize ([current-directory dest-dir])
|
(parameterize ([current-directory dest-dir])
|
||||||
|
|
|
@ -34,3 +34,6 @@
|
||||||
|
|
||||||
(define current-pkg-network-retries
|
(define current-pkg-network-retries
|
||||||
(make-parameter #f))
|
(make-parameter #f))
|
||||||
|
|
||||||
|
(define current-pkg-git-checkout-credentials
|
||||||
|
(make-parameter #f))
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
"orig-pkg.rkt"
|
"orig-pkg.rkt"
|
||||||
"git.rkt"
|
"git.rkt"
|
||||||
"prefetch.rkt"
|
"prefetch.rkt"
|
||||||
|
"checkout-credentials.rkt"
|
||||||
"network.rkt")
|
"network.rkt")
|
||||||
|
|
||||||
(provide (struct-out install-info)
|
(provide (struct-out install-info)
|
||||||
|
@ -735,6 +736,8 @@
|
||||||
(define-values (transport host port repo branch path)
|
(define-values (transport host port repo branch path)
|
||||||
(split-git-or-hub-url pkg-url #:type type))
|
(split-git-or-hub-url pkg-url #:type type))
|
||||||
(download-printf "Querying Git references for ~a at ~a\n" pkg-name pkg-url-str)
|
(download-printf "Querying Git references for ~a at ~a\n" pkg-name pkg-url-str)
|
||||||
|
(call-with-git-checkout-credentials
|
||||||
|
(lambda ()
|
||||||
(call-with-network-retries
|
(call-with-network-retries
|
||||||
(lambda ()
|
(lambda ()
|
||||||
;; Supplying `#:dest-dir #f` means that we just resolve `branch`
|
;; Supplying `#:dest-dir #f` means that we just resolve `branch`
|
||||||
|
@ -751,7 +754,7 @@
|
||||||
" the given URL might not refer to a Git repository\n"
|
" the given URL might not refer to a Git repository\n"
|
||||||
" given URL: ~a")
|
" given URL: ~a")
|
||||||
pkg-url-str))
|
pkg-url-str))
|
||||||
#:transport transport)))]
|
#:transport transport)))))]
|
||||||
[(github)
|
[(github)
|
||||||
(match-define (list* user repo branch path)
|
(match-define (list* user repo branch path)
|
||||||
(split-github-url pkg-url))
|
(split-github-url pkg-url))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user