| package utils |
| |
| import ( |
| "fmt" |
| "io/ioutil" |
| "os" |
| "runtime" |
| "strings" |
| |
| "github.com/docker/docker/pkg/archive" |
| "github.com/docker/docker/pkg/stringid" |
| ) |
| |
| var globalTestID string |
| |
| // TestDirectory creates a new temporary directory and returns its path. |
| // The contents of directory at path `templateDir` is copied into the |
| // new directory. |
| func TestDirectory(templateDir string) (dir string, err error) { |
| if globalTestID == "" { |
| globalTestID = stringid.GenerateNonCryptoID()[:4] |
| } |
| prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, GetCallerName(2)) |
| if prefix == "" { |
| prefix = "docker-test-" |
| } |
| dir, err = ioutil.TempDir("", prefix) |
| if err = os.Remove(dir); err != nil { |
| return |
| } |
| if templateDir != "" { |
| if err = archive.CopyWithTar(templateDir, dir); err != nil { |
| return |
| } |
| } |
| return |
| } |
| |
| // GetCallerName introspects the call stack and returns the name of the |
| // function `depth` levels down in the stack. |
| func GetCallerName(depth int) string { |
| // Use the caller function name as a prefix. |
| // This helps trace temp directories back to their test. |
| pc, _, _, _ := runtime.Caller(depth + 1) |
| callerLongName := runtime.FuncForPC(pc).Name() |
| parts := strings.Split(callerLongName, ".") |
| callerShortName := parts[len(parts)-1] |
| return callerShortName |
| } |
| |
| // ReplaceOrAppendEnvValues returns the defaults with the overrides either |
| // replaced by env key or appended to the list |
| func ReplaceOrAppendEnvValues(defaults, overrides []string) []string { |
| cache := make(map[string]int, len(defaults)) |
| for i, e := range defaults { |
| parts := strings.SplitN(e, "=", 2) |
| cache[parts[0]] = i |
| } |
| |
| for _, value := range overrides { |
| // Values w/o = means they want this env to be removed/unset. |
| if !strings.Contains(value, "=") { |
| if i, exists := cache[value]; exists { |
| defaults[i] = "" // Used to indicate it should be removed |
| } |
| continue |
| } |
| |
| // Just do a normal set/update |
| parts := strings.SplitN(value, "=", 2) |
| if i, exists := cache[parts[0]]; exists { |
| defaults[i] = value |
| } else { |
| defaults = append(defaults, value) |
| } |
| } |
| |
| // Now remove all entries that we want to "unset" |
| for i := 0; i < len(defaults); i++ { |
| if defaults[i] == "" { |
| defaults = append(defaults[:i], defaults[i+1:]...) |
| i-- |
| } |
| } |
| |
| return defaults |
| } |