Merge pull request #304 from thockin/5-main-struct

Add a "main struct" with methods
This commit is contained in:
Kubernetes Prow Robot 2020-11-13 04:48:24 -08:00 committed by GitHub
commit 14b9e286f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 132 additions and 98 deletions

View File

@ -164,10 +164,12 @@ const (
metricKeyNoOp = "noop" metricKeyNoOp = "noop"
) )
type submodulesMode string
const ( const (
submodulesRecursive = "recursive" submodulesRecursive submodulesMode = "recursive"
submodulesShallow = "shallow" submodulesShallow submodulesMode = "shallow"
submodulesOff = "off" submodulesOff submodulesMode = "off"
) )
func init() { func init() {
@ -249,6 +251,20 @@ func setGlogFlags() {
vFlag.Value.Set(strconv.Itoa(*flVerbose)) vFlag.Value.Set(strconv.Itoa(*flVerbose))
} }
// repoSync represents the remote repo and the local sync of it.
type repoSync struct {
cmd string // the git command to run
root string // absolute path to the root directory
repo string // remote repo to sync
branch string // remote branch to sync
rev string // the rev or SHA to sync
depth int // for shallow sync
submodules submodulesMode // how to handle submodules
chmod int // mode to change repo to, or 0
link string // the name of the symlink to publish under `root`
authURL string // a URL to re-fetch credentials, or ""
}
func main() { func main() {
// In case we come up as pid 1, act as init. // In case we come up as pid 1, act as init.
if os.Getpid() == 1 { if os.Getpid() == 1 {
@ -298,7 +314,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
switch *flSubmodules { switch submodulesMode(*flSubmodules) {
case submodulesRecursive, submodulesShallow, submodulesOff: case submodulesRecursive, submodulesShallow, submodulesOff:
default: default:
fmt.Fprintf(os.Stderr, "ERROR: --submodules must be one of %q, %q, or %q", submodulesRecursive, submodulesShallow, submodulesOff) fmt.Fprintf(os.Stderr, "ERROR: --submodules must be one of %q, %q, or %q", submodulesRecursive, submodulesShallow, submodulesOff)
@ -425,12 +441,26 @@ func main() {
} }
} }
// Capture the various git parameters.
git := &repoSync{
cmd: *flGitCmd,
root: absRoot,
repo: *flRepo,
branch: *flBranch,
rev: *flRev,
depth: *flDepth,
submodules: submodulesMode(*flSubmodules),
chmod: *flChmod,
link: *flLink,
authURL: *flAskPassURL,
}
// This context is used only for git credentials initialization. There are no long-running operations like // This context is used only for git credentials initialization. There are no long-running operations like
// `git clone`, so hopefully 30 seconds will be enough. // `git clone`, so hopefully 30 seconds will be enough.
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
if *flUsername != "" && *flPassword != "" { if *flUsername != "" && *flPassword != "" {
if err := setupGitAuth(ctx, *flUsername, *flPassword, *flRepo); err != nil { if err := git.SetupAuth(ctx, *flUsername, *flPassword); err != nil {
log.Error(err, "ERROR: can't set up git auth") log.Error(err, "ERROR: can't set up git auth")
os.Exit(1) os.Exit(1)
} }
@ -444,21 +474,12 @@ func main() {
} }
if *flCookieFile { if *flCookieFile {
if err := setupGitCookieFile(ctx); err != nil { if err := git.SetupCookieFile(ctx); err != nil {
log.Error(err, "ERROR: can't set up git cookie file") log.Error(err, "ERROR: can't set up git cookie file")
os.Exit(1) os.Exit(1)
} }
} }
if *flAskPassURL != "" {
if err := callGitAskPassURL(ctx, *flAskPassURL); err != nil {
askpassCount.WithLabelValues(metricKeyError).Inc()
log.Error(err, "ERROR: failed to call ASKPASS callback URL", "url", *flAskPassURL)
os.Exit(1)
}
askpassCount.WithLabelValues(metricKeySuccess).Inc()
}
// The scope of the initialization context ends here, so we call cancel to release resources associated with it. // The scope of the initialization context ends here, so we call cancel to release resources associated with it.
cancel() cancel()
@ -516,7 +537,7 @@ func main() {
for { for {
start := time.Now() start := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), *flSyncTimeout) ctx, cancel := context.WithTimeout(context.Background(), *flSyncTimeout)
if changed, hash, err := syncRepo(ctx, *flRepo, *flBranch, *flRev, *flDepth, absRoot, *flLink, *flAskPassURL, *flSubmodules); err != nil { if changed, hash, err := git.SyncRepo(ctx); err != nil {
updateSyncMetrics(metricKeyError, start) updateSyncMetrics(metricKeyError, start)
if *flMaxSyncFailures != -1 && failCount >= *flMaxSyncFailures { if *flMaxSyncFailures != -1 && failCount >= *flMaxSyncFailures {
// Exit after too many retries, maybe the error is not recoverable. // Exit after too many retries, maybe the error is not recoverable.
@ -543,11 +564,11 @@ func main() {
if *flOneTime { if *flOneTime {
os.Exit(0) os.Exit(0)
} }
if isHash, err := revIsHash(ctx, *flRev, absRoot); err != nil { if isHash, err := git.RevIsHash(ctx); err != nil {
log.Error(err, "can't tell if rev is a git hash, exiting", "rev", *flRev) log.Error(err, "can't tell if rev is a git hash, exiting", "rev", git.rev)
os.Exit(1) os.Exit(1)
} else if isHash { } else if isHash {
log.V(0).Info("rev appears to be a git hash, no further sync needed", "rev", *flRev) log.V(0).Info("rev appears to be a git hash, no further sync needed", "rev", git.rev)
sleepForever() sleepForever()
} }
initialSync = false initialSync = false
@ -609,12 +630,12 @@ func addUser() error {
return err return err
} }
// updateSymlink atomically swaps the symlink to point at the specified // UpdateSymlink atomically swaps the symlink to point at the specified
// directory and cleans up the previous worktree. If there was a previous // directory and cleans up the previous worktree. If there was a previous
// worktree, this returns the path to it. // worktree, this returns the path to it.
func updateSymlink(ctx context.Context, gitRoot, link, newDir string) (string, error) { func (git *repoSync) UpdateSymlink(ctx context.Context, newDir string) (string, error) {
// Get currently-linked repo directory (to be removed), unless it doesn't exist // Get currently-linked repo directory (to be removed), unless it doesn't exist
linkPath := filepath.Join(gitRoot, link) linkPath := filepath.Join(git.root, git.link)
oldWorktreePath, err := filepath.EvalSymlinks(linkPath) oldWorktreePath, err := filepath.EvalSymlinks(linkPath)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return "", fmt.Errorf("error accessing current worktree: %v", err) return "", fmt.Errorf("error accessing current worktree: %v", err)
@ -622,19 +643,19 @@ func updateSymlink(ctx context.Context, gitRoot, link, newDir string) (string, e
// newDir is absolute, so we need to change it to a relative path. This is // newDir is absolute, so we need to change it to a relative path. This is
// so it can be volume-mounted at another path and the symlink still works. // so it can be volume-mounted at another path and the symlink still works.
newDirRelative, err := filepath.Rel(gitRoot, newDir) newDirRelative, err := filepath.Rel(git.root, newDir)
if err != nil { if err != nil {
return "", fmt.Errorf("error converting to relative path: %v", err) return "", fmt.Errorf("error converting to relative path: %v", err)
} }
const tmplink = "tmp-link" const tmplink = "tmp-link"
log.V(1).Info("creating tmp symlink", "root", gitRoot, "dst", newDirRelative, "src", tmplink) log.V(1).Info("creating tmp symlink", "root", git.root, "dst", newDirRelative, "src", tmplink)
if _, err := runCommand(ctx, gitRoot, "ln", "-snf", newDirRelative, tmplink); err != nil { if _, err := runCommand(ctx, git.root, "ln", "-snf", newDirRelative, tmplink); err != nil {
return "", fmt.Errorf("error creating symlink: %v", err) return "", fmt.Errorf("error creating symlink: %v", err)
} }
log.V(1).Info("renaming symlink", "root", gitRoot, "old_name", tmplink, "new_name", link) log.V(1).Info("renaming symlink", "root", git.root, "oldName", tmplink, "newName", git.link)
if _, err := runCommand(ctx, gitRoot, "mv", "-T", tmplink, link); err != nil { if _, err := runCommand(ctx, git.root, "mv", "-T", tmplink, git.link); err != nil {
return "", fmt.Errorf("error replacing symlink: %v", err) return "", fmt.Errorf("error replacing symlink: %v", err)
} }
@ -657,30 +678,30 @@ func setRepoReady() {
repoReady = true repoReady = true
} }
// addWorktreeAndSwap creates a new worktree and calls updateSymlink to swap the symlink to point to the new worktree // AddWorktreeAndSwap creates a new worktree and calls UpdateSymlink to swap the symlink to point to the new worktree
func addWorktreeAndSwap(ctx context.Context, gitRoot, link, branch, rev string, depth int, hash string, submoduleMode string) error { func (git *repoSync) AddWorktreeAndSwap(ctx context.Context, hash string) error {
log.V(0).Info("syncing git", "rev", rev, "hash", hash) log.V(0).Info("syncing git", "rev", git.rev, "hash", hash)
args := []string{"fetch", "-f", "--tags"} args := []string{"fetch", "-f", "--tags"}
if depth != 0 { if git.depth != 0 {
args = append(args, "--depth", strconv.Itoa(depth)) args = append(args, "--depth", strconv.Itoa(git.depth))
} }
args = append(args, "origin", branch) args = append(args, "origin", git.branch)
// Update from the remote. // Update from the remote.
if _, err := runCommand(ctx, gitRoot, *flGitCmd, args...); err != nil { if _, err := runCommand(ctx, git.root, git.cmd, args...); err != nil {
return err return err
} }
// GC clone // GC clone
if _, err := runCommand(ctx, gitRoot, *flGitCmd, "gc", "--prune=all"); err != nil { if _, err := runCommand(ctx, git.root, git.cmd, "gc", "--prune=all"); err != nil {
return err return err
} }
// Make a worktree for this exact git hash. // Make a worktree for this exact git hash.
worktreePath := filepath.Join(gitRoot, "rev-"+hash) worktreePath := filepath.Join(git.root, "rev-"+hash)
_, err := runCommand(ctx, gitRoot, *flGitCmd, "worktree", "add", worktreePath, "origin/"+branch) _, err := runCommand(ctx, git.root, git.cmd, "worktree", "add", worktreePath, "origin/"+git.branch)
log.V(0).Info("adding worktree", "path", worktreePath, "branch", fmt.Sprintf("origin/%s", branch)) log.V(0).Info("adding worktree", "path", worktreePath, "branch", fmt.Sprintf("origin/%s", git.branch))
if err != nil { if err != nil {
return err return err
} }
@ -689,7 +710,7 @@ func addWorktreeAndSwap(ctx context.Context, gitRoot, link, branch, rev string,
// /git/.git/worktrees/<worktree-dir-name>. Replace it with a reference // /git/.git/worktrees/<worktree-dir-name>. Replace it with a reference
// using relative paths, so that other containers can use a different volume // using relative paths, so that other containers can use a different volume
// mount name. // mount name.
worktreePathRelative, err := filepath.Rel(gitRoot, worktreePath) worktreePathRelative, err := filepath.Rel(git.root, worktreePath)
if err != nil { if err != nil {
return err return err
} }
@ -699,7 +720,7 @@ func addWorktreeAndSwap(ctx context.Context, gitRoot, link, branch, rev string,
} }
// Reset the worktree's working copy to the specific rev. // Reset the worktree's working copy to the specific rev.
_, err = runCommand(ctx, worktreePath, *flGitCmd, "reset", "--hard", hash) _, err = runCommand(ctx, worktreePath, git.cmd, "reset", "--hard", hash)
if err != nil { if err != nil {
return err return err
} }
@ -707,24 +728,24 @@ func addWorktreeAndSwap(ctx context.Context, gitRoot, link, branch, rev string,
// Update submodules // Update submodules
// NOTE: this works for repo with or without submodules. // NOTE: this works for repo with or without submodules.
if submoduleMode != submodulesOff { if git.submodules != submodulesOff {
log.V(0).Info("updating submodules") log.V(0).Info("updating submodules")
submodulesArgs := []string{"submodule", "update", "--init"} submodulesArgs := []string{"submodule", "update", "--init"}
if submoduleMode == submodulesRecursive { if git.submodules == submodulesRecursive {
submodulesArgs = append(submodulesArgs, "--recursive") submodulesArgs = append(submodulesArgs, "--recursive")
} }
if depth != 0 { if git.depth != 0 {
submodulesArgs = append(submodulesArgs, "--depth", strconv.Itoa(depth)) submodulesArgs = append(submodulesArgs, "--depth", strconv.Itoa(git.depth))
} }
_, err = runCommand(ctx, worktreePath, *flGitCmd, submodulesArgs...) _, err = runCommand(ctx, worktreePath, git.cmd, submodulesArgs...)
if err != nil { if err != nil {
return err return err
} }
} }
// Change the file permissions, if requested. // Change the file permissions, if requested.
if *flChmod != 0 { if git.chmod != 0 {
mode := fmt.Sprintf("%#o", *flChmod) mode := fmt.Sprintf("%#o", git.chmod)
log.V(0).Info("changing file permissions", "mode", mode) log.V(0).Info("changing file permissions", "mode", mode)
_, err = runCommand(ctx, "", "chmod", "-R", mode, worktreePath) _, err = runCommand(ctx, "", "chmod", "-R", mode, worktreePath)
if err != nil { if err != nil {
@ -741,8 +762,15 @@ func addWorktreeAndSwap(ctx context.Context, gitRoot, link, branch, rev string,
} }
} }
// Reset the root's rev (so we can prune and so we can rely on it later).
_, err = runCommand(ctx, git.root, git.cmd, "reset", "--hard", hash)
if err != nil {
return err
}
log.V(0).Info("reset root to hash", "path", git.root, "hash", hash)
// Flip the symlink. // Flip the symlink.
oldWorktree, err := updateSymlink(ctx, gitRoot, link, worktreePath) oldWorktree, err := git.UpdateSymlink(ctx, worktreePath)
if err != nil { if err != nil {
return err return err
} }
@ -753,7 +781,7 @@ func addWorktreeAndSwap(ctx context.Context, gitRoot, link, branch, rev string,
if err := os.RemoveAll(oldWorktree); err != nil { if err := os.RemoveAll(oldWorktree); err != nil {
return fmt.Errorf("error removing directory: %v", err) return fmt.Errorf("error removing directory: %v", err)
} }
if _, err := runCommand(ctx, gitRoot, *flGitCmd, "worktree", "prune"); err != nil { if _, err := runCommand(ctx, git.root, git.cmd, "worktree", "prune"); err != nil {
return err return err
} }
} }
@ -761,24 +789,25 @@ func addWorktreeAndSwap(ctx context.Context, gitRoot, link, branch, rev string,
return nil return nil
} }
func cloneRepo(ctx context.Context, repo, branch, rev string, depth int, gitRoot string) error { // CloneRepo does an initial clone of the git repo.
args := []string{"clone", "--no-checkout", "-b", branch} func (git *repoSync) CloneRepo(ctx context.Context) error {
if depth != 0 { args := []string{"clone", "--no-checkout", "-b", git.branch}
args = append(args, "--depth", strconv.Itoa(depth)) if git.depth != 0 {
args = append(args, "--depth", strconv.Itoa(git.depth))
} }
args = append(args, repo, gitRoot) args = append(args, git.repo, git.root)
log.V(0).Info("cloning repo", "origin", repo, "path", gitRoot) log.V(0).Info("cloning repo", "origin", git.repo, "path", git.root)
_, err := runCommand(ctx, "", *flGitCmd, args...) _, err := runCommand(ctx, "", git.cmd, args...)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "already exists and is not an empty directory") { if strings.Contains(err.Error(), "already exists and is not an empty directory") {
// Maybe a previous run crashed? Git won't use this dir. // Maybe a previous run crashed? Git won't use this dir.
log.V(0).Info("git root exists and is not empty (previous crash?), cleaning up", "path", gitRoot) log.V(0).Info("git root exists and is not empty (previous crash?), cleaning up", "path", git.root)
err := os.RemoveAll(gitRoot) err := os.RemoveAll(git.root)
if err != nil { if err != nil {
return err return err
} }
_, err = runCommand(ctx, "", *flGitCmd, args...) _, err = runCommand(ctx, "", git.cmd, args...)
if err != nil { if err != nil {
return err return err
} }
@ -790,18 +819,18 @@ func cloneRepo(ctx context.Context, repo, branch, rev string, depth int, gitRoot
return nil return nil
} }
// localHashForRev returns the locally known hash for a given rev. // LocalHashForRev returns the locally known hash for a given rev.
func localHashForRev(ctx context.Context, rev, gitRoot string) (string, error) { func (git *repoSync) LocalHashForRev(ctx context.Context) (string, error) {
output, err := runCommand(ctx, gitRoot, *flGitCmd, "rev-parse", rev) output, err := runCommand(ctx, git.root, git.cmd, "rev-parse", git.rev)
if err != nil { if err != nil {
return "", err return "", err
} }
return strings.Trim(string(output), "\n"), nil return strings.Trim(string(output), "\n"), nil
} }
// remoteHashForRef returns the upstream hash for a given ref. // RemoteHashForRef returns the upstream hash for a given ref.
func remoteHashForRef(ctx context.Context, ref, gitRoot string) (string, error) { func (git *repoSync) RemoteHashForRef(ctx context.Context, ref string) (string, error) {
output, err := runCommand(ctx, gitRoot, *flGitCmd, "ls-remote", "-q", "origin", ref) output, err := runCommand(ctx, git.root, git.cmd, "ls-remote", "-q", "origin", ref)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -809,9 +838,9 @@ func remoteHashForRef(ctx context.Context, ref, gitRoot string) (string, error)
return parts[0], nil return parts[0], nil
} }
func revIsHash(ctx context.Context, rev, gitRoot string) (bool, error) { func (git *repoSync) RevIsHash(ctx context.Context) (bool, error) {
// If git doesn't identify rev as a commit, we're done. // If git doesn't identify rev as a commit, we're done.
output, err := runCommand(ctx, gitRoot, *flGitCmd, "cat-file", "-t", rev) output, err := runCommand(ctx, git.root, git.cmd, "cat-file", "-t", git.rev)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -824,38 +853,38 @@ func revIsHash(ctx context.Context, rev, gitRoot string) (bool, error) {
// hash, the output will be the same hash as the input. Of course, a user // hash, the output will be the same hash as the input. Of course, a user
// could specify "abc" and match "abcdef12345678", so we just do a prefix // could specify "abc" and match "abcdef12345678", so we just do a prefix
// match. // match.
output, err = localHashForRev(ctx, rev, gitRoot) output, err = git.LocalHashForRev(ctx)
if err != nil { if err != nil {
return false, err return false, err
} }
return strings.HasPrefix(output, rev), nil return strings.HasPrefix(output, git.rev), nil
} }
// syncRepo syncs the branch of a given repository to the link at the given rev. // SyncRepo syncs the branch of a given repository to the link at the given rev.
// returns (1) whether a change occured, (2) the new hash, and (3) an error if one happened // returns (1) whether a change occured, (2) the new hash, and (3) an error if one happened
func syncRepo(ctx context.Context, repo, branch, rev string, depth int, gitRoot, link string, authURL string, submoduleMode string) (bool, string, error) { func (git *repoSync) SyncRepo(ctx context.Context) (bool, string, error) {
if authURL != "" { if git.authURL != "" {
// For ASKPASS Callback URL, the credentials behind is dynamic, it needs to be // For ASKPASS Callback URL, the credentials behind is dynamic, it needs to be
// re-fetched each time. // re-fetched each time.
if err := callGitAskPassURL(ctx, authURL); err != nil { if err := git.CallAskPassURL(ctx); err != nil {
askpassCount.WithLabelValues(metricKeyError).Inc() askpassCount.WithLabelValues(metricKeyError).Inc()
return false, "", fmt.Errorf("failed to call GIT_ASKPASS_URL: %v", err) return false, "", fmt.Errorf("failed to call GIT_ASKPASS_URL: %v", err)
} }
askpassCount.WithLabelValues(metricKeySuccess).Inc() askpassCount.WithLabelValues(metricKeySuccess).Inc()
} }
target := filepath.Join(gitRoot, link) target := filepath.Join(git.root, git.link)
gitRepoPath := filepath.Join(target, ".git") gitRepoPath := filepath.Join(target, ".git")
var hash string var hash string
_, err := os.Stat(gitRepoPath) _, err := os.Stat(gitRepoPath)
switch { switch {
case os.IsNotExist(err): case os.IsNotExist(err):
// First time. Just clone it and get the hash. // First time. Just clone it and get the hash.
err = cloneRepo(ctx, repo, branch, rev, depth, gitRoot) err = git.CloneRepo(ctx)
if err != nil { if err != nil {
return false, "", err return false, "", err
} }
hash, err = localHashForRev(ctx, rev, gitRoot) hash, err = git.LocalHashForRev(ctx)
if err != nil { if err != nil {
return false, "", err return false, "", err
} }
@ -863,39 +892,39 @@ func syncRepo(ctx context.Context, repo, branch, rev string, depth int, gitRoot,
return false, "", fmt.Errorf("error checking if repo exists %q: %v", gitRepoPath, err) return false, "", fmt.Errorf("error checking if repo exists %q: %v", gitRepoPath, err)
default: default:
// Not the first time. Figure out if the ref has changed. // Not the first time. Figure out if the ref has changed.
local, remote, err := getRevs(ctx, target, branch, rev) local, remote, err := git.GetRevs(ctx)
if err != nil { if err != nil {
return false, "", err return false, "", err
} }
if local == remote { if local == remote {
log.V(1).Info("no update required", "rev", rev, "local", local, "remote", remote) log.V(1).Info("no update required", "rev", git.rev, "local", local, "remote", remote)
return false, "", nil return false, "", nil
} }
log.V(0).Info("update required", "rev", rev, "local", local, "remote", remote) log.V(0).Info("update required", "rev", git.rev, "local", local, "remote", remote)
hash = remote hash = remote
} }
return true, hash, addWorktreeAndSwap(ctx, gitRoot, link, branch, rev, depth, hash, submoduleMode) return true, hash, git.AddWorktreeAndSwap(ctx, hash)
} }
// getRevs returns the local and upstream hashes for rev. // GetRevs returns the local and upstream hashes for rev.
func getRevs(ctx context.Context, localDir, branch, rev string) (string, string, error) { func (git *repoSync) GetRevs(ctx context.Context) (string, string, error) {
// Ask git what the exact hash is for rev. // Ask git what the exact hash is for rev.
local, err := localHashForRev(ctx, rev, localDir) local, err := git.LocalHashForRev(ctx)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
// Build a ref string, depending on whether the user asked to track HEAD or a tag. // Build a ref string, depending on whether the user asked to track HEAD or a tag.
ref := "" ref := ""
if rev == "HEAD" { if git.rev == "HEAD" {
ref = "refs/heads/" + branch ref = "refs/heads/" + git.branch
} else { } else {
ref = "refs/tags/" + rev ref = "refs/tags/" + git.rev
} }
// Figure out what hash the remote resolves ref to. // Figure out what hash the remote resolves ref to.
remote, err := remoteHashForRef(ctx, ref, localDir) remote, err := git.RemoteHashForRef(ctx, ref)
if err != nil { if err != nil {
return "", "", err return "", "", err
} }
@ -947,16 +976,18 @@ func runCommandWithStdin(ctx context.Context, cwd, stdin, command string, args .
return stdout, nil return stdout, nil
} }
func setupGitAuth(ctx context.Context, username, password, gitURL string) error { // SetupAuth configures the local git repo to use a username and password when
// accessing the repo.
func (git *repoSync) SetupAuth(ctx context.Context, username, password string) error {
log.V(1).Info("setting up git credential store") log.V(1).Info("setting up git credential store")
_, err := runCommand(ctx, "", *flGitCmd, "config", "--global", "credential.helper", "store") _, err := runCommand(ctx, "", git.cmd, "config", "--global", "credential.helper", "store")
if err != nil { if err != nil {
return fmt.Errorf("can't configure git credential helper: %w", err) return fmt.Errorf("can't configure git credential helper: %w", err)
} }
creds := fmt.Sprintf("url=%v\nusername=%v\npassword=%v\n", gitURL, username, password) creds := fmt.Sprintf("url=%v\nusername=%v\npassword=%v\n", git.repo, username, password)
_, err = runCommandWithStdin(ctx, "", creds, *flGitCmd, "credential", "approve") _, err = runCommandWithStdin(ctx, "", creds, git.cmd, "credential", "approve")
if err != nil { if err != nil {
return fmt.Errorf("can't configure git credentials: %w", err) return fmt.Errorf("can't configure git credentials: %w", err)
} }
@ -993,7 +1024,7 @@ func setupGitSSH(setupKnownHosts bool) error {
return nil return nil
} }
func setupGitCookieFile(ctx context.Context) error { func (git *repoSync) SetupCookieFile(ctx context.Context) error {
log.V(1).Info("configuring git cookie file") log.V(1).Info("configuring git cookie file")
var pathToCookieFile = "/etc/git-secret/cookie_file" var pathToCookieFile = "/etc/git-secret/cookie_file"
@ -1004,18 +1035,21 @@ func setupGitCookieFile(ctx context.Context) error {
} }
if _, err = runCommand(ctx, "", if _, err = runCommand(ctx, "",
*flGitCmd, "config", "--global", "http.cookiefile", pathToCookieFile); err != nil { git.cmd, "config", "--global", "http.cookiefile", pathToCookieFile); err != nil {
return fmt.Errorf("can't configure git cookiefile: %w", err) return fmt.Errorf("can't configure git cookiefile: %w", err)
} }
return nil return nil
} }
// CallAskPassURL consults the specified URL looking for git credentials in the
// response.
//
// The expected ASKPASS callback output are below, // The expected ASKPASS callback output are below,
// see https://git-scm.com/docs/gitcredentials for more examples: // see https://git-scm.com/docs/gitcredentials for more examples:
// username=xxx@example.com // username=xxx@example.com
// password=ya29.xxxyyyzzz // password=ya29.xxxyyyzzz
func callGitAskPassURL(ctx context.Context, url string) error { func (git *repoSync) CallAskPassURL(ctx context.Context) error {
log.V(1).Info("calling GIT_ASKPASS URL to get credentials") log.V(1).Info("calling GIT_ASKPASS URL to get credentials")
var netClient = &http.Client{ var netClient = &http.Client{
@ -1024,7 +1058,7 @@ func callGitAskPassURL(ctx context.Context, url string) error {
return http.ErrUseLastResponse return http.ErrUseLastResponse
}, },
} }
httpReq, err := http.NewRequestWithContext(ctx, "GET", url, nil) httpReq, err := http.NewRequestWithContext(ctx, "GET", git.authURL, nil)
if err != nil { if err != nil {
return fmt.Errorf("can't create auth request: %w", err) return fmt.Errorf("can't create auth request: %w", err)
} }
@ -1056,7 +1090,7 @@ func callGitAskPassURL(ctx context.Context, url string) error {
} }
} }
if err := setupGitAuth(ctx, username, password, *flRepo); err != nil { if err := git.SetupAuth(ctx, username, password); err != nil {
return err return err
} }