// SymbolicWalk is like filepath.Walk, but it supports the root being a // symbolic link. It will still not follow symbolic links deeper down in // the file structure func SymbolicWalk(fs afero.Fs, root string, walker filepath.WalkFunc) error { // Handle the root first fileInfo, err := lstatIfOs(fs, root) if err != nil || !fileInfo.IsDir() { return nil } if err != nil { return walker(root, nil, err) } if err := walker(root, fileInfo, err); err != nil && err != filepath.SkipDir { return err } rootContent, err := afero.ReadDir(fs, root) if err != nil { return walker(root, nil, err) } for _, fi := range rootContent { afero.Walk(fs, filepath.Join(root, fi.Name()), walker) } return nil }
// checkDir returns true if dst is a non-empty directory and src is a file func (s *Syncer) checkDir(dst, src string) (b bool, err error) { // read file info dstat, err := os.Stat(dst) if os.IsNotExist(err) { return false, nil } else if err != nil { return false, err } sstat, err := os.Stat(src) if err != nil { return false, err } // return false is dst is not a directory or src is a directory if !dstat.IsDir() || sstat.IsDir() { return false, nil } // dst is a directory and src is a file // check if dst is non-empty // read dst directory files, err := afero.ReadDir(s.DestFs, dst) if err != nil { return false, err } if len(files) > 0 { return true, nil } return false, nil }
// readDirFromWorkingDir listst the directory content relative to the // configured WorkingDir. func readDirFromWorkingDir(i interface{}) ([]os.FileInfo, error) { path := cast.ToString(i) list, err := afero.ReadDir(hugofs.WorkingDir(), path) if err != nil { return nil, fmt.Errorf("Failed to read Directory %s with error message %s", path, err) } return list, nil }
func globFiles(fs afero.Fs, targetPath, pattern string) []string { children, err := afero.ReadDir(fs, targetPath) if err != nil { panic(err) } var matches []string for _, child := range children { if glob.Glob(pattern, child.Name()) { matches = append(matches, path.Join(targetPath, child.Name())) } } return matches }
// SymbolicWalk is like filepath.Walk, but it supports the root being a // symbolic link. It will still not follow symbolic links deeper down in // the file structure func SymbolicWalk(fs afero.Fs, root string, walker filepath.WalkFunc) error { // Sanity check if len(root) < 4 { return WalkRootTooShortError } // Handle the root first fileInfo, realPath, err := getRealFileInfo(fs, root) if err != nil { return walker(root, nil, err) } if !fileInfo.IsDir() { return fmt.Errorf("Cannot walk regular file %s", root) } if err := walker(realPath, fileInfo, err); err != nil && err != filepath.SkipDir { return err } rootContent, err := afero.ReadDir(fs, root) if err != nil { return walker(root, nil, err) } for _, fi := range rootContent { if err := afero.Walk(fs, filepath.Join(root, fi.Name()), walker); err != nil { return err } } return nil }
// sync updates dst to match with src, handling both files and directories. func (s *Syncer) sync(dst, src string) { // sync permissions and modification times after handling content defer s.syncstats(dst, src) // read files info dstat, err := s.DestFs.Stat(dst) if err != nil && !os.IsNotExist(err) { panic(err) } sstat, err := s.SrcFs.Stat(src) if err != nil && os.IsNotExist(err) { return // src was deleted before we could copy it } check(err) if !sstat.IsDir() { // src is a file // delete dst if its a directory if dstat != nil && dstat.IsDir() { check(s.DestFs.RemoveAll(dst)) } if !s.equal(dst, src) { // perform copy df, err := s.DestFs.Create(dst) check(err) defer df.Close() sf, err := s.SrcFs.Open(src) if os.IsNotExist(err) { return } check(err) defer sf.Close() _, err = io.Copy(df, sf) if os.IsNotExist(err) { return } check(err) } return } // src is a directory // make dst if necessary if dstat == nil { // dst does not exist; create directory check(s.DestFs.MkdirAll(dst, 0755)) // permissions will be synced later } else if !dstat.IsDir() { // dst is a file; remove and create directory check(s.DestFs.Remove(dst)) check(s.DestFs.MkdirAll(dst, 0755)) // permissions will be synced later } // go through sf files and sync them files, err := afero.ReadDir(s.SrcFs, src) if os.IsNotExist(err) { return } check(err) // make a map of filenames for quick lookup; used in deletion // deletion below m := make(map[string]bool, len(files)) for _, file := range files { dst2 := filepath.Join(dst, file.Name()) src2 := filepath.Join(src, file.Name()) s.sync(dst2, src2) m[file.Name()] = true } // delete files from dst that does not exist in src if s.Delete { files, err = afero.ReadDir(s.DestFs, dst) check(err) for _, file := range files { if !m[file.Name()] { check(s.DestFs.RemoveAll(filepath.Join(dst, file.Name()))) } } } }