mirror of
				https://github.com/gohugoio/hugo.git
				synced 2024-05-11 05:54:58 +00:00 
			
		
		
		
	Handle symlink change event
Hugo 0.16 announced support for symbolic links for the root folders, /content, /static etc., but this got broken pretty fast. The main problem this commit tries to solve is the matching of file change events to "what changed". An example: ContentDir: /mysites/site/content where /mysites/site/content is a symlink to /mycontent /mycontent: /mypost1.md /post/mypost2.md * A change to mypost1.md (on OS X) will trigger a file change event with name "/mycontent/mypost1.md" * A change to mypost2.md gives event with name "/mysites/site/content/mypost2.md" The first change will not trigger a correct update of Hugo before this commit. This commit fixes this by doing a two-step check: 1. Check if "/mysites/site/content/mypost2.md" is within /mysites/site/content 2. Check if "/mysites/site/content/mypost2.md" is within the real path that /mysites/site/content points to Fixes #2265 Closes #2273
This commit is contained in:
		@@ -481,17 +481,17 @@ func SymbolicWalk(fs afero.Fs, root string, walker filepath.WalkFunc) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Handle the root first
 | 
			
		||||
	fileInfo, err := lstatIfOs(fs, root)
 | 
			
		||||
	fileInfo, realPath, err := getRealFileInfo(fs, root)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return walker(root, nil, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !fileInfo.IsDir() {
 | 
			
		||||
		return nil
 | 
			
		||||
		return fmt.Errorf("Cannot walk regular file %s", root)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := walker(root, fileInfo, err); err != nil && err != filepath.SkipDir {
 | 
			
		||||
	if err := walker(realPath, fileInfo, err); err != nil && err != filepath.SkipDir {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -511,6 +511,40 @@ func SymbolicWalk(fs afero.Fs, root string, walker filepath.WalkFunc) error {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getRealFileInfo(fs afero.Fs, path string) (os.FileInfo, string, error) {
 | 
			
		||||
	fileInfo, err := lstatIfOs(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, "", fmt.Errorf("Cannot read symbolic link '%s', error was: %s", path, err)
 | 
			
		||||
		}
 | 
			
		||||
		fileInfo, err = lstatIfOs(fs, link)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, "", fmt.Errorf("Cannot stat '%s', error was: %s", link, err)
 | 
			
		||||
		}
 | 
			
		||||
		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 realPath, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Code copied from Afero's path.go
 | 
			
		||||
// if the filesystem is OsFs use Lstat, else use fs.Stat
 | 
			
		||||
func lstatIfOs(fs afero.Fs, path string) (info os.FileInfo, err error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,8 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
 | 
			
		||||
	"github.com/spf13/afero"
 | 
			
		||||
	"github.com/spf13/viper"
 | 
			
		||||
)
 | 
			
		||||
@@ -141,6 +143,29 @@ func TestGetRelativePath(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetRealPath(t *testing.T) {
 | 
			
		||||
	d1, err := ioutil.TempDir("", "d1")
 | 
			
		||||
	defer os.Remove(d1)
 | 
			
		||||
	fs := afero.NewOsFs()
 | 
			
		||||
 | 
			
		||||
	rp1, err := GetRealPath(fs, d1)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, d1, rp1)
 | 
			
		||||
 | 
			
		||||
	sym := filepath.Join(os.TempDir(), "d1sym")
 | 
			
		||||
	err = os.Symlink(d1, sym)
 | 
			
		||||
	defer os.Remove(sym)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	rp2, err := GetRealPath(fs, sym)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	// On OS X, the temp folder is itself a symbolic link (to /private...)
 | 
			
		||||
	// This has to do for now.
 | 
			
		||||
	assert.True(t, strings.HasSuffix(rp2, d1))
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMakePathRelative(t *testing.T) {
 | 
			
		||||
	type test struct {
 | 
			
		||||
		inPath, path1, path2, output string
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user