From 85823eb4f8e5e3510aedc6ad2c5b1760a2a8f7c9 Mon Sep 17 00:00:00 2001 From: Steve Streeting Date: Mon, 27 Jul 2015 15:09:22 +0100 Subject: [PATCH] Add support for checking out specific paths --- commands/command_checkout.go | 15 ++++++--- lfs/util.go | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/commands/command_checkout.go b/commands/command_checkout.go index 4c6cb2e4..ff8a25ab 100644 --- a/commands/command_checkout.go +++ b/commands/command_checkout.go @@ -19,15 +19,15 @@ var ( func checkoutCommand(cmd *cobra.Command, args []string) { - // No params - checkoutAll() + // Parameters are filters + checkoutWithIncludeExclude(args, nil) } func init() { RootCmd.AddCommand(checkoutCmd) } -func checkoutAll() { +func checkoutWithIncludeExclude(include []string, exclude []string) { ref, err := git.CurrentRef() if err != nil { Panic(err, "Could not checkout") @@ -45,13 +45,20 @@ func checkoutAll() { checkoutWithChan(c, &wait) for _, pointer := range pointers { - c <- pointer + if lfs.FilenamePassesIncludeExcludeFilter(pointer.Name, include, exclude) { + c <- pointer + } + } close(c) wait.Wait() } +func checkoutAll() { + checkoutWithIncludeExclude(nil, nil) +} + // Populate the working copy with the real content of objects where the file is // either missing, or contains a matching pointer placeholder, from a list of pointers. // If the file exists but has other content it is left alone diff --git a/lfs/util.go b/lfs/util.go index e7817716..22b2dbda 100644 --- a/lfs/util.go +++ b/lfs/util.go @@ -5,6 +5,8 @@ import ( "io" "os" "path/filepath" + "runtime" + "strings" ) type CallbackReader struct { @@ -86,3 +88,64 @@ func wrapProgressError(err error, event, filename string) error { return nil } + +// Return whether a given filename passes the include / exclude path filters +// Only paths that are in includePaths and outside excludePaths are passed +// If includePaths is empty that filter always passes and the same with excludePaths +// Both path lists support wildcard matches +func FilenamePassesIncludeExcludeFilter(filename string, includePaths, excludePaths []string) bool { + if len(includePaths) == 0 && len(excludePaths) == 0 { + return true + } + + // For Win32, becuase git reports files with / separators + cleanfilename := filepath.Clean(filename) + if len(includePaths) > 0 { + matched := false + for _, inc := range includePaths { + matched, _ = filepath.Match(inc, filename) + if !matched && IsWindows() { + // Also Win32 match + matched, _ = filepath.Match(inc, cleanfilename) + } + if !matched { + // Also support matching a parent directory without a wildcard + if strings.HasPrefix(cleanfilename, inc+string(filepath.Separator)) { + matched = true + } + } + if matched { + break + } + + } + if !matched { + return false + } + } + + if len(excludePaths) > 0 { + for _, ex := range excludePaths { + matched, _ := filepath.Match(ex, filename) + if !matched && IsWindows() { + // Also Win32 match + matched, _ = filepath.Match(ex, cleanfilename) + } + if matched { + return false + } + // Also support matching a parent directory without a wildcard + if strings.HasPrefix(cleanfilename, ex+string(filepath.Separator)) { + return false + } + + } + } + + return true +} + +// Are we running on Windows? Need to handle some extra path shenanigans +func IsWindows() bool { + return runtime.GOOS == "windows" +}