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: wrap upstream gitutil cli #2005

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ARG XX_VERSION=1.2.1
ARG DOCKER_VERSION=24.0.2
ARG GOTESTSUM_VERSION=v1.9.0
ARG REGISTRY_VERSION=2.8.0
ARG BUILDKIT_VERSION=v0.11.6
ARG BUILDKIT_VERSION=master

# xx is a helper for cross-compilation
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
Expand Down
13 changes: 7 additions & 6 deletions build/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"

"github.com/docker/buildx/util/gitutil"
bkgitutil "github.com/moby/buildkit/util/gitutil"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -49,22 +50,22 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
wd, _ = filepath.Abs(filepath.Join(cwd, contextPath))
}

gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(wd))
gitc, err := gitutil.New(bkgitutil.WithDir(wd))
if err != nil {
if st, err := os.Stat(path.Join(wd, ".git")); err == nil && st.IsDir() {
return res, errors.New("buildx: git was not found in the system. Current commit information was not captured by the build")
}
return
}

if !gitc.IsInsideWorkTree() {
if !gitc.IsInsideWorkTree(ctx) {
if st, err := os.Stat(path.Join(wd, ".git")); err == nil && st.IsDir() {
return res, errors.New("buildx: failed to read current commit information with git rev-parse --is-inside-work-tree")
}
return res, nil
}

if sha, err := gitc.FullCommit(); err != nil && !gitutil.IsUnknownRevision(err) {
if sha, err := gitc.FullCommit(ctx); err != nil && !gitutil.IsUnknownRevision(err) {
return res, errors.Wrapf(err, "buildx: failed to get git commit")
} else if sha != "" {
checkDirty := false
Expand All @@ -73,7 +74,7 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
checkDirty = v
}
}
if checkDirty && gitc.IsDirty() {
if checkDirty && gitc.IsDirty(ctx) {
sha += "-dirty"
}
if setGitLabels {
Expand All @@ -84,7 +85,7 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
}
}

if rurl, err := gitc.RemoteURL(); err == nil && rurl != "" {
if rurl, err := gitc.RemoteURL(ctx); err == nil && rurl != "" {
if setGitLabels {
res["label:"+specs.AnnotationSource] = rurl
}
Expand All @@ -94,7 +95,7 @@ func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath st
}

if setGitLabels {
if root, err := gitc.RootDir(); err != nil {
if root, err := gitc.WorkTree(ctx); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need the RootDir func otherwise root will always be empty here.

return res, errors.Wrapf(err, "buildx: failed to get git root dir")
} else if root != "" {
if dockerfilePath == "" {
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/runc v1.1.7 // indirect
github.com/opencontainers/runc v1.1.9 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
Expand Down Expand Up @@ -179,3 +179,5 @@ require (
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

replace github.com/moby/buildkit => github.com/jedevc/buildkit v0.8.2-0.20230816145044-96097aa7c4f0
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ github.com/in-toto/in-toto-golang v0.5.0 h1:hb8bgwr0M2hGdDsLjkJ3ZqJ8JFLL/tgYdAxF
github.com/in-toto/in-toto-golang v0.5.0/go.mod h1:/Rq0IZHLV7Ku5gielPT4wPHJfH1GdHMCq8+WPxw8/BE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jedevc/buildkit v0.8.2-0.20230816145044-96097aa7c4f0 h1:3IbPFkidmZrZEiTzRNfsM72feiuc1tZA9OLDUwusL6k=
github.com/jedevc/buildkit v0.8.2-0.20230816145044-96097aa7c4f0/go.mod h1:BIvNtlrvok2xTC734ZNhQVGayvMB1Dz8bFuArWTLnnM=
github.com/jinzhu/gorm v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw=
github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k=
Expand Down Expand Up @@ -372,8 +374,6 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzC
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/buildkit v0.12.1-0.20230804094609-b49a8873179b h1:LUpEbvxcyM0NuWk54WwNjDVZ5YujyCm1CudzZpqaohE=
github.com/moby/buildkit v0.12.1-0.20230804094609-b49a8873179b/go.mod h1:bs0LeDdh7AQpYXLiPNUt+hzDjRxMg+QeLq1a1r0awFM=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
Expand Down Expand Up @@ -407,8 +407,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8=
github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk=
github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM=
github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
github.com/opencontainers/runtime-spec v1.1.0-rc.2 h1:ucBtEms2tamYYW/SvGpvq9yUN0NEVL6oyLEwDcTSrk8=
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
Expand Down
15 changes: 8 additions & 7 deletions tests/bake.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/containerd/continuity/fs/fstest"
"github.com/docker/buildx/util/gitutil"
bkgitutil "github.com/moby/buildkit/util/gitutil"
"github.com/moby/buildkit/util/testutil/integration"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -66,7 +67,7 @@ EOT
)
dirDest := t.TempDir()

git, err := gitutil.New(gitutil.WithWorkingDir(dir))
git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err)

gitutil.GitInit(git, t)
Expand Down Expand Up @@ -100,7 +101,7 @@ EOT
)
dirDest := t.TempDir()

git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
git, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err)

gitutil.GitInit(git, t)
Expand Down Expand Up @@ -134,14 +135,14 @@ EOT
)
dirDest := t.TempDir()

gitSpec, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
gitSpec, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err)
gitutil.GitInit(gitSpec, t)
gitutil.GitAdd(gitSpec, t, "docker-bake.hcl")
gitutil.GitCommit(gitSpec, t, "initial commit")
addrSpec := gitutil.GitServeHTTP(gitSpec, t)

gitSrc, err := gitutil.New(gitutil.WithWorkingDir(dirSrc))
gitSrc, err := gitutil.New(bkgitutil.WithDir(dirSrc))
require.NoError(t, err)
gitutil.GitInit(gitSrc, t)
gitutil.GitAdd(gitSrc, t, "foo")
Expand Down Expand Up @@ -175,7 +176,7 @@ COPY super-cool.txt /
)
dirDest := t.TempDir()

git, err := gitutil.New(gitutil.WithWorkingDir(dir))
git, err := gitutil.New(bkgitutil.WithDir(dir))
require.NoError(t, err)
gitutil.GitInit(git, t)
gitutil.GitAdd(git, t, "docker-bake.hcl", "bar")
Expand Down Expand Up @@ -215,7 +216,7 @@ EOT
)
dirDest := t.TempDir()

git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
git, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err)

gitutil.GitInit(git, t)
Expand Down Expand Up @@ -262,7 +263,7 @@ EOT
)
dirDest := t.TempDir()

git, err := gitutil.New(gitutil.WithWorkingDir(dirSpec))
git, err := gitutil.New(bkgitutil.WithDir(dirSpec))
require.NoError(t, err)

gitutil.GitInit(git, t)
Expand Down
118 changes: 28 additions & 90 deletions util/gitutil/gitutil.go
Original file line number Diff line number Diff line change
@@ -1,111 +1,73 @@
package gitutil

import (
"bytes"
"context"
"net/url"
"os"
"os/exec"
"path/filepath"
"strings"

bkgitutil "github.com/moby/buildkit/util/gitutil"
"github.com/pkg/errors"
)

// Git represents an active git object
type Git struct {
ctx context.Context
wd string
gitpath string
}

// Option provides a variadic option for configuring the git client.
type Option func(b *Git)

// WithContext sets context.
func WithContext(ctx context.Context) Option {
return func(b *Git) {
b.ctx = ctx
}
}

// WithWorkingDir sets working directory.
func WithWorkingDir(wd string) Option {
return func(b *Git) {
b.wd = wd
}
// GitCLI represents an active git object
type GitCLI struct {
bkgitutil.GitCLI
}

// New initializes a new git client
func New(opts ...Option) (*Git, error) {
var err error
c := &Git{
ctx: context.Background(),
}

for _, opt := range opts {
opt(c)
func New(opts ...bkgitutil.Option) (*GitCLI, error) {
cli, err := bkgitutil.NewGitCLI(opts...)
if err != nil {
return nil, err
}

c.gitpath, err = gitPath(c.wd)
gitpath, err := gitPath(cli.Dir())
if err != nil {
return nil, errors.New("git not found in PATH")
}

return c, nil
cli = cli.New(bkgitutil.WithGitBinary(gitpath))
return &GitCLI{*cli}, nil
}

func (c *Git) IsInsideWorkTree() bool {
out, err := c.clean(c.run("rev-parse", "--is-inside-work-tree"))
func (cli *GitCLI) IsInsideWorkTree(ctx context.Context) bool {
out, err := cli.clean(cli.Run(ctx, "rev-parse", "--is-inside-work-tree"))
return out == "true" && err == nil
}

func (c *Git) IsDirty() bool {
out, err := c.run("status", "--porcelain", "--ignored")
return strings.TrimSpace(out) != "" || err != nil
}

func (c *Git) RootDir() (string, error) {
return c.clean(c.run("rev-parse", "--show-toplevel"))
func (cli *GitCLI) IsDirty(ctx context.Context) bool {
out, err := cli.Run(ctx, "status", "--porcelain", "--ignored")
return strings.TrimSpace(string(out)) != "" || err != nil
}

func (c *Git) GitDir() (string, error) {
dir, err := c.RootDir()
if err != nil {
return "", err
}
return filepath.Join(dir, ".git"), nil
}

func (c *Git) RemoteURL() (string, error) {
func (cli *GitCLI) RemoteURL(ctx context.Context) (string, error) {
// Try to get the remote URL from the origin remote first
if ru, err := c.clean(c.run("remote", "get-url", "origin")); err == nil && ru != "" {
if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", "origin")); err == nil && ru != "" {
return stripCredentials(ru), nil
}
// If that fails, try to get the remote URL from the upstream remote
if ru, err := c.clean(c.run("remote", "get-url", "upstream")); err == nil && ru != "" {
if ru, err := cli.clean(cli.Run(ctx, "remote", "get-url", "upstream")); err == nil && ru != "" {
return stripCredentials(ru), nil
}
return "", errors.New("no remote URL found for either origin or upstream")
}

func (c *Git) FullCommit() (string, error) {
return c.clean(c.run("show", "--format=%H", "HEAD", "--quiet", "--"))
func (cli *GitCLI) FullCommit(ctx context.Context) (string, error) {
return cli.clean(cli.Run(ctx, "show", "--format=%H", "HEAD", "--quiet", "--"))
}

func (c *Git) ShortCommit() (string, error) {
return c.clean(c.run("show", "--format=%h", "HEAD", "--quiet", "--"))
func (cli *GitCLI) ShortCommit(ctx context.Context) (string, error) {
return cli.clean(cli.Run(ctx, "show", "--format=%h", "HEAD", "--quiet", "--"))
}

func (c *Git) Tag() (string, error) {
func (cli *GitCLI) Tag(ctx context.Context) (string, error) {
var tag string
var err error
for _, fn := range []func() (string, error){
func() (string, error) {
return c.clean(c.run("tag", "--points-at", "HEAD", "--sort", "-version:creatordate"))
return cli.clean(cli.Run(ctx, "tag", "--points-at", "HEAD", "--sort", "-version:creatordate"))
},
func() (string, error) {
return c.clean(c.run("describe", "--tags", "--abbrev=0"))
return cli.clean(cli.Run(ctx, "describe", "--tags", "--abbrev=0"))
},
} {
tag, err = fn()
Expand All @@ -116,32 +78,8 @@ func (c *Git) Tag() (string, error) {
return tag, err
}

func (c *Git) run(args ...string) (string, error) {
var extraArgs = []string{
"-c", "log.showSignature=false",
}

args = append(extraArgs, args...)
cmd := exec.CommandContext(c.ctx, c.gitpath, args...)
if c.wd != "" {
cmd.Dir = c.wd
}

// Override the locale to ensure consistent output
cmd.Env = append(os.Environ(), "LC_ALL=C")

stdout := bytes.Buffer{}
stderr := bytes.Buffer{}
cmd.Stdout = &stdout
cmd.Stderr = &stderr

if err := cmd.Run(); err != nil {
return "", errors.New(stderr.String())
}
return stdout.String(), nil
}

func (c *Git) clean(out string, err error) (string, error) {
func (cli *GitCLI) clean(dt []byte, err error) (string, error) {
out := string(dt)
out = strings.ReplaceAll(strings.Split(out, "\n")[0], "'", "")
if err != nil {
err = errors.New(strings.TrimSuffix(err.Error(), "\n"))
Expand Down
Loading