Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

git: Fix submodule fetch, rewrite logic #104

Merged
merged 1 commit into from
Jun 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 42 additions & 45 deletions builder/source/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,90 +65,87 @@ func NewGit(uri, ref string) (*GitSource, error) {
return g, nil
}

// submodules will handle setup of the git submodules after a
// reset has taken place.
func (g *GitSource) submodules() error {
cmd := exec.Command("git", "submodule", "update", "--init", "--recursive")
// clone shallow clones an upstream git repository to the local disk.
func (g *GitSource) clone() error {
// Create a blobless clone without checking out a ref
cmd := exec.Command("git", "clone", "--filter=blob:none", "--no-checkout", g.URI, g.ClonePath)

cmd.Dir = g.ClonePath
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout

return cmd.Run()
}

// For some reason git blobless clones create pack files with 600 permissions. These break future operations
// as those files cannot be read by non-root users. Fix those permissions so things work as they should.
func (g *GitSource) fixPermissions() error {
cmd := exec.Command("bash", "-c", "chmod +r .git/objects/pack/*.promisor")
// updateRefs checks the upstream for new refs and tags in case we need them for future git commands.
func (g *GitSource) updateRefs() error {
// --tags: Update git tags as well
// --force: Force overwrite any refs locally (such as when upstream moves a tag)
cmd := exec.Command("git", "fetch", "--tags", "--force", "origin")

cmd.Dir = g.ClonePath
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout

return cmd.Run()
}

// clone shallow clones an upstream git repository to the local disk.
func clone(uri, path, ref string) error {
var cmd *exec.Cmd
// switch will switch to the given ref.
func (g *GitSource) switchRef() error {
cmd := exec.Command("git", "switch", "--discard-changes", "--detach", g.Ref)

// Create a blobless clone without checking out a ref
initCmd := exec.Command("git", "clone", "--filter=blob:none", "--no-checkout", uri, path)
initCmd.Stdout = os.Stdout
initCmd.Stderr = os.Stdout
cmd.Dir = g.ClonePath
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout

if err := initCmd.Run(); err != nil {
return err
}
return cmd.Run()
}

// Checkout the ref we want
cmd = exec.Command("git", "switch", "--discard-changes", "--recurse-submodules", "--detach", ref)
cmd.Dir = path
// submodules will handle setup of the git submodules after a
// reset has taken place.
func (g *GitSource) submodules() error {
// --init initializes the submodule if it hasn't been initialized alredy
cmd := exec.Command("git", "submodule", "update", "--init", "--filter=blob:none", "--recursive")

cmd.Dir = g.ClonePath
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout

return cmd.Run()
}

// reset fetches the new git reference (a tag or commit SHA1 hash) and
// hard resets the repository on that reference.
func reset(path, ref string) error {
fetchArgs := []string{
"fetch",
"--tags",
"origin",
}

fetchCmd := exec.Command("git", fetchArgs...)
fetchCmd.Dir = path

if err := fetchCmd.Run(); err != nil {
return err
}
// For some reason git blobless clones create pack files with 600 permissions. These break future operations
// as those files cannot be read by non-root users. Fix those permissions so things work as they should.
func (g *GitSource) fixPermissions() error {
cmd := exec.Command("bash", "-c", `find . -name "*.promisor" -type f -exec chmod +r "{}" \;`)

resetCmd := exec.Command("git", "switch", "--discard-changes", "--recurse-submodules", "--detach", ref)
resetCmd.Dir = path
cmd.Dir = g.ClonePath

return resetCmd.Run()
return cmd.Run()
}

// Fetch will attempt to download the git tree locally. If it already exists
// then we'll make an attempt to update it.
func (g *GitSource) Fetch() error {
// First things first, make sure we have a destination
if !PathExists(g.ClonePath) {
if err := clone(g.URI, g.ClonePath, g.Ref); err != nil {
if err := g.clone(); err != nil {
return err
}
} else {
// Repo already exists locally, try to reset to the new reference
if err := reset(g.ClonePath, g.Ref); err != nil {
// Repo already exists locally, get the latest refs from origin
if err := g.updateRefs(); err != nil {
return err
}
}

// Check out submodules
err := g.submodules()
// Checkout the ref we want
err := g.switchRef()
if err != nil {
return err
}

// Update or checkout submodules
err = g.submodules()
if err != nil {
return err
}
Expand Down