github.com/pdmccormick/importable-docker-buildx@v0.0.0-20240426161518-e47091289030/build/git.go (about)

     1  package build
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path"
     7  	"path/filepath"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/docker/buildx/util/gitutil"
    12  	"github.com/docker/buildx/util/osutil"
    13  	"github.com/moby/buildkit/client"
    14  	specs "github.com/opencontainers/image-spec/specs-go/v1"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  const DockerfileLabel = "com.docker.image.source.entrypoint"
    19  
    20  func getGitAttributes(ctx context.Context, contextPath string, dockerfilePath string) (map[string]string, func(key, dir string, so *client.SolveOpt), error) {
    21  	res := make(map[string]string)
    22  	if contextPath == "" {
    23  		return nil, nil, nil
    24  	}
    25  
    26  	setGitLabels := false
    27  	if v, ok := os.LookupEnv("BUILDX_GIT_LABELS"); ok {
    28  		if v == "full" { // backward compatibility with old "full" mode
    29  			setGitLabels = true
    30  		} else if v, err := strconv.ParseBool(v); err == nil {
    31  			setGitLabels = v
    32  		}
    33  	}
    34  	setGitInfo := true
    35  	if v, ok := os.LookupEnv("BUILDX_GIT_INFO"); ok {
    36  		if v, err := strconv.ParseBool(v); err == nil {
    37  			setGitInfo = v
    38  		}
    39  	}
    40  
    41  	if !setGitLabels && !setGitInfo {
    42  		return nil, nil, nil
    43  	}
    44  
    45  	// figure out in which directory the git command needs to run in
    46  	var wd string
    47  	if filepath.IsAbs(contextPath) {
    48  		wd = contextPath
    49  	} else {
    50  		wd, _ = filepath.Abs(filepath.Join(osutil.GetWd(), contextPath))
    51  	}
    52  	wd = osutil.SanitizePath(wd)
    53  
    54  	gitc, err := gitutil.New(gitutil.WithContext(ctx), gitutil.WithWorkingDir(wd))
    55  	if err != nil {
    56  		if st, err1 := os.Stat(path.Join(wd, ".git")); err1 == nil && st.IsDir() {
    57  			return res, nil, errors.Wrap(err, "git was not found in the system")
    58  		}
    59  		return nil, nil, nil
    60  	}
    61  
    62  	if !gitc.IsInsideWorkTree() {
    63  		if st, err := os.Stat(path.Join(wd, ".git")); err == nil && st.IsDir() {
    64  			return res, nil, errors.New("failed to read current commit information with git rev-parse --is-inside-work-tree")
    65  		}
    66  		return nil, nil, nil
    67  	}
    68  
    69  	root, err := gitc.RootDir()
    70  	if err != nil {
    71  		return res, nil, errors.Wrap(err, "failed to get git root dir")
    72  	}
    73  
    74  	if sha, err := gitc.FullCommit(); err != nil && !gitutil.IsUnknownRevision(err) {
    75  		return res, nil, errors.Wrap(err, "failed to get git commit")
    76  	} else if sha != "" {
    77  		checkDirty := false
    78  		if v, ok := os.LookupEnv("BUILDX_GIT_CHECK_DIRTY"); ok {
    79  			if v, err := strconv.ParseBool(v); err == nil {
    80  				checkDirty = v
    81  			}
    82  		}
    83  		if checkDirty && gitc.IsDirty() {
    84  			sha += "-dirty"
    85  		}
    86  		if setGitLabels {
    87  			res["label:"+specs.AnnotationRevision] = sha
    88  		}
    89  		if setGitInfo {
    90  			res["vcs:revision"] = sha
    91  		}
    92  	}
    93  
    94  	if rurl, err := gitc.RemoteURL(); err == nil && rurl != "" {
    95  		if setGitLabels {
    96  			res["label:"+specs.AnnotationSource] = rurl
    97  		}
    98  		if setGitInfo {
    99  			res["vcs:source"] = rurl
   100  		}
   101  	}
   102  
   103  	if setGitLabels && root != "" {
   104  		if dockerfilePath == "" {
   105  			dockerfilePath = filepath.Join(wd, "Dockerfile")
   106  		}
   107  		if !filepath.IsAbs(dockerfilePath) {
   108  			dockerfilePath = filepath.Join(osutil.GetWd(), dockerfilePath)
   109  		}
   110  		if r, err := filepath.Rel(root, dockerfilePath); err == nil && !strings.HasPrefix(r, "..") {
   111  			res["label:"+DockerfileLabel] = r
   112  		}
   113  	}
   114  
   115  	return res, func(key, dir string, so *client.SolveOpt) {
   116  		if !setGitInfo || root == "" {
   117  			return
   118  		}
   119  		dir, err := filepath.Abs(dir)
   120  		if err != nil {
   121  			return
   122  		}
   123  		if lp, err := osutil.GetLongPathName(dir); err == nil {
   124  			dir = lp
   125  		}
   126  		dir = osutil.SanitizePath(dir)
   127  		if r, err := filepath.Rel(root, dir); err == nil && !strings.HasPrefix(r, "..") {
   128  			so.FrontendAttrs["vcs:localdir:"+key] = r
   129  		}
   130  	}, nil
   131  }