aboutsummaryrefslogtreecommitdiffhomepage
path: root/helpers/path.go
diff options
context:
space:
mode:
Diffstat (limited to 'helpers/path.go')
-rw-r--r--helpers/path.go228
1 files changed, 114 insertions, 114 deletions
diff --git a/helpers/path.go b/helpers/path.go
index 36bd3269b..12ddfeb56 100644
--- a/helpers/path.go
+++ b/helpers/path.go
@@ -26,6 +26,8 @@ import (
"github.com/gohugoio/hugo/config"
+ "github.com/gohugoio/hugo/hugofs"
+
"github.com/gohugoio/hugo/common/hugio"
_errors "github.com/pkg/errors"
"github.com/spf13/afero"
@@ -172,32 +174,6 @@ func ReplaceExtension(path string, newExt string) string {
return f + "." + newExt
}
-// GetFirstThemeDir gets the root directory of the first theme, if there is one.
-// If there is no theme, returns the empty string.
-func (p *PathSpec) GetFirstThemeDir() string {
- if p.ThemeSet() {
- return p.AbsPathify(filepath.Join(p.ThemesDir, p.Themes()[0]))
- }
- return ""
-}
-
-// GetThemesDir gets the absolute root theme dir path.
-func (p *PathSpec) GetThemesDir() string {
- if p.ThemeSet() {
- return p.AbsPathify(p.ThemesDir)
- }
- return ""
-}
-
-// GetRelativeThemeDir gets the relative root directory of the current theme, if there is one.
-// If there is no theme, returns the empty string.
-func (p *PathSpec) GetRelativeThemeDir() string {
- if p.ThemeSet() {
- return strings.TrimPrefix(filepath.Join(p.ThemesDir, p.Themes()[0]), FilePathSeparator)
- }
- return ""
-}
-
func makePathRelative(inPath string, possibleDirectories ...string) (string, error) {
for _, currentPath := range possibleDirectories {
@@ -379,6 +355,107 @@ func prettifyPath(in string, b filepathPathBridge) string {
return b.Join(b.Dir(in), name, "index"+ext)
}
+type NamedSlice struct {
+ Name string
+ Slice []string
+}
+
+func (n NamedSlice) String() string {
+ if len(n.Slice) == 0 {
+ return n.Name
+ }
+ return fmt.Sprintf("%s%s{%s}", n.Name, FilePathSeparator, strings.Join(n.Slice, ","))
+}
+
+func ExtractAndGroupRootPaths(paths []string) []NamedSlice {
+ if len(paths) == 0 {
+ return nil
+ }
+
+ pathsCopy := make([]string, len(paths))
+ hadSlashPrefix := strings.HasPrefix(paths[0], FilePathSeparator)
+
+ for i, p := range paths {
+ pathsCopy[i] = strings.Trim(filepath.ToSlash(p), "/")
+ }
+
+ sort.Strings(pathsCopy)
+
+ pathsParts := make([][]string, len(pathsCopy))
+
+ for i, p := range pathsCopy {
+ pathsParts[i] = strings.Split(p, "/")
+ }
+
+ var groups [][]string
+
+ for i, p1 := range pathsParts {
+ c1 := -1
+
+ for j, p2 := range pathsParts {
+ if i == j {
+ continue
+ }
+
+ c2 := -1
+
+ for i, v := range p1 {
+ if i >= len(p2) {
+ break
+ }
+ if v != p2[i] {
+ break
+ }
+
+ c2 = i
+ }
+
+ if c1 == -1 || (c2 != -1 && c2 < c1) {
+ c1 = c2
+ }
+ }
+
+ if c1 != -1 {
+ groups = append(groups, p1[:c1+1])
+ } else {
+ groups = append(groups, p1)
+ }
+ }
+
+ groupsStr := make([]string, len(groups))
+ for i, g := range groups {
+ groupsStr[i] = strings.Join(g, "/")
+ }
+
+ groupsStr = UniqueStringsSorted(groupsStr)
+
+ var result []NamedSlice
+
+ for _, g := range groupsStr {
+ name := filepath.FromSlash(g)
+ if hadSlashPrefix {
+ name = FilePathSeparator + name
+ }
+ ns := NamedSlice{Name: name}
+ for _, p := range pathsCopy {
+ if !strings.HasPrefix(p, g) {
+ continue
+ }
+
+ p = strings.TrimPrefix(p, g)
+ if p != "" {
+ ns.Slice = append(ns.Slice, p)
+ }
+ }
+
+ ns.Slice = UniqueStrings(ExtractRootPaths(ns.Slice))
+
+ result = append(result, ns)
+ }
+
+ return result
+}
+
// ExtractRootPaths extracts the root paths from the supplied list of paths.
// The resulting root path will not contain any file separators, but there
// may be duplicates.
@@ -425,98 +502,21 @@ func FindCWD() (string, error) {
return path, nil
}
-// 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 root != "" && len(root) < 4 {
- return errors.New("path is too short")
- }
-
- // 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
- }
-
- // Some of Hugo's filesystems represents an ordered root folder, i.e. project first, then theme folders.
- // Make sure that order is preserved. afero.Walk will sort the directories down in the file tree,
- // but we don't care about that.
- rootContent, err := readDir(fs, root, false)
-
- 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
- }
+// SymbolicWalk is like filepath.Walk, but it follows symbolic links.
+func SymbolicWalk(fs afero.Fs, root string, walker hugofs.WalkFunc) error {
+ if _, isOs := fs.(*afero.OsFs); isOs {
+ // Mainly to track symlinks.
+ fs = hugofs.NewBaseFileDecorator(fs)
}
- return nil
+ w := hugofs.NewWalkway(hugofs.WalkwayConfig{
+ Fs: fs,
+ Root: root,
+ WalkFn: walker,
+ })
-}
-
-func readDir(fs afero.Fs, dirname string, doSort bool) ([]os.FileInfo, error) {
- f, err := fs.Open(dirname)
- if err != nil {
- return nil, err
- }
- list, err := f.Readdir(-1)
- f.Close()
- if err != nil {
- return nil, err
- }
- if doSort {
- sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
- }
- return list, nil
-}
-
-func getRealFileInfo(fs afero.Fs, path string) (os.FileInfo, string, error) {
- fileInfo, err := LstatIfPossible(fs, path)
- realPath := path
-
- if err != nil {
- return nil, "", err
- }
-
- if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink {
- link, err := filepath.EvalSymlinks(path)
- if err != nil {
- return nil, "", _errors.Wrapf(err, "Cannot read symbolic link %q", path)
- }
- fileInfo, err = LstatIfPossible(fs, link)
- if err != nil {
- return nil, "", _errors.Wrapf(err, "Cannot stat %q", link)
- }
- realPath = link
- }
- return fileInfo, realPath, nil
-}
-
-// GetRealPath returns the real file path for the given path, whether it is a
-// symlink or not.
-func GetRealPath(fs afero.Fs, path string) (string, error) {
- _, realPath, err := getRealFileInfo(fs, path)
-
- if err != nil {
- return "", err
- }
+ return w.Walk()
- return realPath, nil
}
// LstatIfPossible can be used to call Lstat if possible, else Stat.