//export Glob func Glob(cPackage *C.char, cIncludes **C.char, numIncludes int, cExcludes **C.char, numExcludes int, includeHidden bool) **C.char { packageName := C.GoString(cPackage) includes := cStringArrayToStringSlice(cIncludes, numIncludes, "") prefixedExcludes := cStringArrayToStringSlice(cExcludes, numExcludes, packageName) excludes := cStringArrayToStringSlice(cExcludes, numExcludes, "") filenames := core.Glob(packageName, includes, prefixedExcludes, excludes, includeHidden) return stringSliceToCStringArray(filenames) }
func moveOutputs(state *core.BuildState, target *core.BuildTarget) ([]string, bool, error) { // Before we write any outputs, we must remove the old hash file to avoid it being // left in an inconsistent state. if err := os.RemoveAll(ruleHashFileName(target)); err != nil { return nil, true, err } changed := false tmpDir := target.TmpDir() outDir := target.OutDir() for _, output := range target.Outputs() { tmpOutput := path.Join(tmpDir, output) realOutput := path.Join(outDir, output) if !core.PathExists(tmpOutput) { return nil, true, fmt.Errorf("Rule %s failed to create output %s", target.Label, tmpOutput) } // If output is a symlink, dereference it. Otherwise, for efficiency, // we can just move it without a full copy (saves copying large .jar files etc). dereferencedPath, err := filepath.EvalSymlinks(tmpOutput) if err != nil { return nil, true, err } // NB. false -> not filegroup, we wouldn't be here if it was. outputChanged, err := moveOutput(target, dereferencedPath, realOutput, false) if err != nil { return nil, true, err } changed = changed || outputChanged } if changed { log.Debug("Outputs for %s have changed", target.Label) } else { log.Debug("Outputs for %s are unchanged", target.Label) } // Optional outputs get moved but don't contribute to the hash or for incrementality. // Glob patterns are supported on these. extraOuts := []string{} for _, output := range core.Glob(tmpDir, target.OptionalOutputs, nil, nil, true) { log.Debug("Discovered optional output %s", output) tmpOutput := path.Join(tmpDir, output) realOutput := path.Join(outDir, output) if _, err := moveOutput(target, tmpOutput, realOutput, false); err != nil { return nil, changed, err } extraOuts = append(extraOuts, output) } return extraOuts, changed, nil }
// RetrieveArtifact takes in the artifact path as a parameter and checks in the base server // file directory to see if the file exists in the given path. If found, the function will // return whatever's been stored there, which might be a directory and therefore contain // multiple files to be returned. func (cache *Cache) RetrieveArtifact(artPath string) (map[string][]byte, error) { ret := map[string][]byte{} if core.IsGlob(artPath) { for _, art := range core.Glob(cache.rootPath, []string{artPath}, nil, nil, true) { fullPath := path.Join(cache.rootPath, art) lock := cache.lockFile(fullPath, false, 0) body, err := ioutil.ReadFile(fullPath) if lock != nil { lock.RUnlock() } if err != nil { return nil, err } ret[art] = body } return ret, nil } fullPath := path.Join(cache.rootPath, artPath) lock := cache.lockFile(artPath, false, 0) if lock == nil { // Can happen if artPath is a directory; we only store artifacts as files. // (This is a debatable choice; it's a bit crap either way). if info, err := os.Stat(fullPath); err == nil && info.IsDir() { return cache.retrieveDir(artPath) } return nil, os.ErrNotExist } defer lock.RUnlock() if err := filepath.Walk(fullPath, func(name string, info os.FileInfo, err error) error { if err != nil { return err } else if !info.IsDir() { body, err := ioutil.ReadFile(name) if err != nil { return err } ret[name[len(cache.rootPath)+1:]] = body } return nil }); err != nil { return nil, err } return ret, nil }