Skip to content

Commit

Permalink
Add input parameter filter for git commands
Browse files Browse the repository at this point in the history
This adds a new input parameter filter to assist in working with large
git projects. The param filter sets the git filter-spec argument when
fetching repositories. Only one argument can be provided, the combined
form can be used to set multiple filters. When using filter combined
with a subdir the checkout will now also be sparse to further reduce the
number of workspace files.
  • Loading branch information
emcfarlane committed Jan 16, 2025
1 parent 81b9a5e commit 47450c9
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 100 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## [Unreleased]

- No changes yet.
- Add input parameter `fitler` for use with git inputs. This sets the filter
argument for the git fetch command.

## [v1.49.0] - 2025-01-07

Expand Down
9 changes: 9 additions & 0 deletions private/buf/buffetch/internal/git_ref.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type gitRef struct {
depth uint32
recurseSubmodules bool
subDirPath string
filter string
}

func newGitRef(
Expand All @@ -51,6 +52,7 @@ func newGitRef(
depth uint32,
recurseSubmodules bool,
subDirPath string,
filter string,
) (*gitRef, error) {
gitScheme, path, err := getGitSchemeAndPath(format, path)
if err != nil {
Expand All @@ -74,6 +76,7 @@ func newGitRef(
recurseSubmodules,
depth,
subDirPath,
filter,
), nil
}

Expand All @@ -85,6 +88,7 @@ func newDirectGitRef(
recurseSubmodules bool,
depth uint32,
subDirPath string,
filter string,
) *gitRef {
return &gitRef{
format: format,
Expand All @@ -94,6 +98,7 @@ func newDirectGitRef(
depth: depth,
recurseSubmodules: recurseSubmodules,
subDirPath: subDirPath,
filter: filter,
}
}

Expand Down Expand Up @@ -125,6 +130,10 @@ func (r *gitRef) SubDirPath() string {
return r.subDirPath
}

func (r *gitRef) Filter() string {
return r.filter
}

func (*gitRef) ref() {}
func (*gitRef) bucketRef() {}
func (*gitRef) gitRef() {}
Expand Down
10 changes: 9 additions & 1 deletion private/buf/buffetch/internal/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ type GitRef interface {
RecurseSubmodules() bool
// Will be empty instead of "." for root directory
SubDirPath() string
// Filter spec to use, see the --filter option in git rev-list.
Filter() string
gitRef()
}

Expand All @@ -217,8 +219,9 @@ func NewGitRef(
depth uint32,
recurseSubmodules bool,
subDirPath string,
filter string,
) (GitRef, error) {
return newGitRef("", path, gitName, depth, recurseSubmodules, subDirPath)
return newGitRef("", path, gitName, depth, recurseSubmodules, subDirPath, filter)
}

// ModuleRef is a module reference.
Expand Down Expand Up @@ -353,6 +356,7 @@ func NewDirectParsedGitRef(
recurseSubmodules bool,
depth uint32,
subDirPath string,
filter string,
) ParsedGitRef {
return newDirectGitRef(
format,
Expand All @@ -362,6 +366,7 @@ func NewDirectParsedGitRef(
recurseSubmodules,
depth,
subDirPath,
filter,
)
}

Expand Down Expand Up @@ -557,6 +562,9 @@ type RawRef struct {
// requested GitRef will be included when cloning the requested branch
// (or the repo's default branch if GitBranch is empty).
GitDepth uint32
// Only set for git formats.
// The filter spec to use, see the --filter option in git rev-list.
GitFilter string
// Only set for archive formats.
ArchiveStripComponents uint32
// Only set for proto file ref format.
Expand Down
2 changes: 2 additions & 0 deletions private/buf/buffetch/internal/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ func (r *reader) getGitBucket(
git.CloneToBucketOptions{
Name: gitRef.GitName(),
RecurseSubmodules: gitRef.RecurseSubmodules(),
SubDir: gitRef.SubDirPath(),
Filter: gitRef.Filter(),
},
); err != nil {
return nil, nil, fmt.Errorf("could not clone %s: %v", gitURL, err)
Expand Down
3 changes: 3 additions & 0 deletions private/buf/buffetch/internal/ref_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ func (a *refParser) getRawRef(
rawRef.GitCommitOrTag = value
case "ref":
rawRef.GitRef = value
case "filter":
rawRef.GitFilter = value
case "depth":
depth, err := parseGitDepth(value)
if err != nil {
Expand Down Expand Up @@ -519,6 +521,7 @@ func getGitRef(
rawRef.GitDepth,
rawRef.GitRecurseSubmodules,
rawRef.SubDirPath,
rawRef.GitFilter,
)
}

Expand Down
50 changes: 34 additions & 16 deletions private/pkg/git/cloner.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,21 @@ func (c *cloner) CloneToBucket(
return err
}
}

// Build the args for the fetch command.
fetchArgs := []string{}
fetchArgs = append(fetchArgs, gitConfigAuthArgs...)
fetchArgs = append(
fetchArgs,
"fetch",
"--depth", depthArg,
// Required on branches matching the current branch of git init.
"--update-head-ok",
)
if options.Filter != "" {
fetchArgs = append(fetchArgs, "--filter", options.Filter)
}

// First, try to fetch the fetchRef directly. If the ref is not found, we
// will try to fetch the fallback ref with a depth to allow resolving partial
// refs locally. If the fetch fails, we will return an error.
Expand All @@ -134,14 +149,7 @@ func (c *cloner) CloneToBucket(
if err := execext.Run(
ctx,
"git",
execext.WithArgs(append(
gitConfigAuthArgs,
"fetch",
"--depth", depthArg,
"--update-head-ok", // Required on branches matching the current branch of git init.
"origin",
fetchRef,
)...),
execext.WithArgs(append(fetchArgs, "origin", fetchRef)...),
execext.WithEnv(app.Environ(envContainer)),
execext.WithStderr(buffer),
execext.WithDir(baseDir.Path()),
Expand All @@ -156,14 +164,24 @@ func (c *cloner) CloneToBucket(
if err := execext.Run(
ctx,
"git",
execext.WithArgs(append(
gitConfigAuthArgs,
"fetch",
"--depth", depthArg,
"--update-head-ok", // Required on branches matching the current branch of git init.
"origin",
fallbackRef,
)...),
execext.WithArgs(append(fetchArgs, "origin", fallbackRef)...),
execext.WithEnv(app.Environ(envContainer)),
execext.WithStderr(buffer),
execext.WithDir(baseDir.Path()),
); err != nil {
return newGitCommandError(err, buffer)
}
}

// As a further optimization, if a filter is applied with a subdir, we run
// a sparse checkout to reduce the size of the working directory.
buffer.Reset()
if options.Filter != "" && options.SubDir != "" {
// Set the subdir for sparse checkout.
if err := execext.Run(
ctx,
"git",
execext.WithArgs("sparse-checkout", "set", options.SubDir),
execext.WithEnv(app.Environ(envContainer)),
execext.WithStderr(buffer),
execext.WithDir(baseDir.Path()),
Expand Down
2 changes: 2 additions & 0 deletions private/pkg/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ type CloneToBucketOptions struct {
Matcher storage.Matcher
Name Name
RecurseSubmodules bool
SubDir string
Filter string
}

// NewCloner returns a new Cloner.
Expand Down
Loading

0 comments on commit 47450c9

Please sign in to comment.