// Glob returns the names of all files matching pattern or nil // if there is no matching file. The syntax of patterns is the same // as in path.Match. The pattern may describe hierarchical names such as // /usr/*/bin/ed. // // Glob ignores file system errors such as I/O errors reading directories. // The only possible returned error is ErrBadPattern, when pattern // is malformed. func Glob(fs vfs.FileSystem, pattern string) (matches []string, err error) { if !hasMeta(pattern) { if _, err = fs.Lstat(pattern); err != nil { return nil, nil } return []string{pattern}, nil } dir, file := path.Split(pattern) switch dir { case "": dir = "." case string(separator): // nothing default: dir = dir[0 : len(dir)-1] // chop off trailing separator } if !hasMeta(dir) { return glob(fs, dir, file, nil) } var m []string m, err = Glob(fs, dir) if err != nil { return } for _, d := range m { matches, err = glob(fs, d, file, matches) if err != nil { return } } return }
// Walk walks the filesystem rooted at root, calling walkFn for each file or // directory in the filesystem, including root. All errors that arise visiting files // and directories are filtered by walkFn. The files are walked in lexical // order. func Walk(fs vfs.FileSystem, root string, walkFn filepath.WalkFunc) error { info, err := fs.Lstat(root) if err != nil { return walkFn(root, nil, err) } return walk(fs, root, info, walkFn) }
// ReadCached reads a Tree's configuration from all of its source unit // definition files (which may either be in a local VFS rooted at a // .srclib-cache/<COMMITID> dir, or a remote VFS). It does not read // the Srcfile; the Srcfile's directives are already accounted for in // the cached source unit definition files. // // bdfs should be a VFS obtained from a call to // (buildstore.RepoBuildStore).Commit. func ReadCached(bdfs vfs.FileSystem) (*Tree, error) { if _, err := bdfs.Lstat("."); os.IsNotExist(err) { return nil, fmt.Errorf("build cache dir does not exist (did you run `srclib config` to create it)?") } else if err != nil { return nil, err } // Collect all **/*.unit.json files. var unitFiles []string unitSuffix := buildstore.DataTypeSuffix(unit.SourceUnit{}) w := fs.WalkFS(".", rwvfs.Walkable(rwvfs.ReadOnly(bdfs))) for w.Step() { if err := w.Err(); err != nil { return nil, err } if path := w.Path(); strings.HasSuffix(path, unitSuffix) { unitFiles = append(unitFiles, path) } } // Parse units sort.Strings(unitFiles) units := make([]*unit.SourceUnit, len(unitFiles)) par := parallel.NewRun(runtime.GOMAXPROCS(0)) for i_, unitFile_ := range unitFiles { i, unitFile := i_, unitFile_ par.Acquire() go func() { defer par.Release() f, err := bdfs.Open(unitFile) if err != nil { par.Error(err) return } if err := json.NewDecoder(f).Decode(&units[i]); err != nil { f.Close() par.Error(err) return } if err := f.Close(); err != nil { par.Error(err) return } }() } if err := par.Wait(); err != nil { return nil, err } return &Tree{SourceUnits: units}, nil }
// GetFileWithOptions gets a file and observes the options specified // in opt. If fs implements FileGetter, fs.GetFileWithOptions is // called; otherwise the options are applied on the client side after // fetching the whole file. func GetFileWithOptions(fs vfs.FileSystem, path string, opt GetFileOptions) (*FileWithRange, error) { if fg, ok := fs.(FileGetter); ok { return fg.GetFileWithOptions(path, opt) } fi, err := fs.Lstat(path) if err != nil { return nil, err } e := newTreeEntry(fi) fwr := FileWithRange{TreeEntry: e} if fi.Mode().IsDir() { ee, err := readDir(fs, path, opt.RecurseSingleSubfolder, true) if err != nil { return nil, err } sort.Sort(TreeEntriesByTypeByName(ee)) e.Entries = ee } else if fi.Mode().IsRegular() { f, err := fs.Open(path) if err != nil { return nil, err } defer f.Close() contents, err := ioutil.ReadAll(f) if err != nil { return nil, err } e.Contents = contents if empty := (GetFileOptions{}); opt != empty { fr, _, err := ComputeFileRange(contents, opt) if err != nil { return nil, err } // Trim to only requested range. e.Contents = e.Contents[fr.StartByte:fr.EndByte] fwr.FileRange = *fr } } return &fwr, nil }
// walk recursively descends path, calling walkFn. func walk(fs vfs.FileSystem, path string, info os.FileInfo, walkFn filepath.WalkFunc) error { err := walkFn(path, info, nil) if err != nil { if info.IsDir() && err == filepath.SkipDir { return nil } return err } if !info.IsDir() { return nil } names, err := readDirNames(fs, path) if err != nil { return walkFn(path, info, err) } for _, name := range names { filename := pathpkg.Join(path, name) fileInfo, err := fs.Lstat(filename) if err != nil { if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { return err } } else { err = walk(fs, filename, fileInfo, walkFn) if err != nil { if !fileInfo.IsDir() || err != filepath.SkipDir { return err } } } } return nil }