mirror of
				https://github.com/gohugoio/hugo.git
				synced 2024-05-11 05:54:58 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			130 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2017 The Hugo Authors. All rights reserved.
 | 
						|
//
 | 
						|
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
// you may not use this file except in compliance with the License.
 | 
						|
// You may obtain a copy of the License at
 | 
						|
// http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, software
 | 
						|
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
// See the License for the specific language governing permissions and
 | 
						|
// limitations under the License.
 | 
						|
 | 
						|
package commands
 | 
						|
 | 
						|
import (
 | 
						|
	"path/filepath"
 | 
						|
 | 
						|
	"github.com/gohugoio/hugo/common/herrors"
 | 
						|
	"github.com/gohugoio/hugo/hugolib/filesystems"
 | 
						|
 | 
						|
	"github.com/fsnotify/fsnotify"
 | 
						|
	"github.com/gohugoio/hugo/helpers"
 | 
						|
	"github.com/spf13/fsync"
 | 
						|
)
 | 
						|
 | 
						|
type staticSyncer struct {
 | 
						|
	c *commandeer
 | 
						|
}
 | 
						|
 | 
						|
func newStaticSyncer(c *commandeer) (*staticSyncer, error) {
 | 
						|
	return &staticSyncer{c: c}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (s *staticSyncer) isStatic(filename string) bool {
 | 
						|
	return s.c.hugo().BaseFs.SourceFilesystems.IsStatic(filename)
 | 
						|
}
 | 
						|
 | 
						|
func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
 | 
						|
	c := s.c
 | 
						|
 | 
						|
	syncFn := func(sourceFs *filesystems.SourceFilesystem) (uint64, error) {
 | 
						|
		publishDir := helpers.FilePathSeparator
 | 
						|
 | 
						|
		if sourceFs.PublishFolder != "" {
 | 
						|
			publishDir = filepath.Join(publishDir, sourceFs.PublishFolder)
 | 
						|
		}
 | 
						|
 | 
						|
		syncer := fsync.NewSyncer()
 | 
						|
		syncer.NoTimes = c.Cfg.GetBool("noTimes")
 | 
						|
		syncer.NoChmod = c.Cfg.GetBool("noChmod")
 | 
						|
		syncer.ChmodFilter = chmodFilter
 | 
						|
		syncer.SrcFs = sourceFs.Fs
 | 
						|
		syncer.DestFs = c.Fs.PublishDir
 | 
						|
		if c.renderStaticToDisk {
 | 
						|
			syncer.DestFs = c.Fs.PublishDirStatic
 | 
						|
		}
 | 
						|
 | 
						|
		// prevent spamming the log on changes
 | 
						|
		logger := helpers.NewDistinctErrorLogger()
 | 
						|
 | 
						|
		for _, ev := range staticEvents {
 | 
						|
			// Due to our approach of layering both directories and the content's rendered output
 | 
						|
			// into one we can't accurately remove a file not in one of the source directories.
 | 
						|
			// If a file is in the local static dir and also in the theme static dir and we remove
 | 
						|
			// it from one of those locations we expect it to still exist in the destination
 | 
						|
			//
 | 
						|
			// If Hugo generates a file (from the content dir) over a static file
 | 
						|
			// the content generated file should take precedence.
 | 
						|
			//
 | 
						|
			// Because we are now watching and handling individual events it is possible that a static
 | 
						|
			// event that occupies the same path as a content generated file will take precedence
 | 
						|
			// until a regeneration of the content takes places.
 | 
						|
			//
 | 
						|
			// Hugo assumes that these cases are very rare and will permit this bad behavior
 | 
						|
			// The alternative is to track every single file and which pipeline rendered it
 | 
						|
			// and then to handle conflict resolution on every event.
 | 
						|
 | 
						|
			fromPath := ev.Name
 | 
						|
 | 
						|
			relPath, found := sourceFs.MakePathRelative(fromPath)
 | 
						|
 | 
						|
			if !found {
 | 
						|
				// Not member of this virtual host.
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			// Remove || rename is harder and will require an assumption.
 | 
						|
			// Hugo takes the following approach:
 | 
						|
			// If the static file exists in any of the static source directories after this event
 | 
						|
			// Hugo will re-sync it.
 | 
						|
			// If it does not exist in all of the static directories Hugo will remove it.
 | 
						|
			//
 | 
						|
			// This assumes that Hugo has not generated content on top of a static file and then removed
 | 
						|
			// the source of that static file. In this case Hugo will incorrectly remove that file
 | 
						|
			// from the published directory.
 | 
						|
			if ev.Op&fsnotify.Rename == fsnotify.Rename || ev.Op&fsnotify.Remove == fsnotify.Remove {
 | 
						|
				if _, err := sourceFs.Fs.Stat(relPath); herrors.IsNotExist(err) {
 | 
						|
					// If file doesn't exist in any static dir, remove it
 | 
						|
					logger.Println("File no longer exists in static dir, removing", relPath)
 | 
						|
					_ = c.Fs.PublishDirStatic.RemoveAll(relPath)
 | 
						|
 | 
						|
				} else if err == nil {
 | 
						|
					// If file still exists, sync it
 | 
						|
					logger.Println("Syncing", relPath, "to", publishDir)
 | 
						|
 | 
						|
					if err := syncer.Sync(relPath, relPath); err != nil {
 | 
						|
						c.logger.Errorln(err)
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					c.logger.Errorln(err)
 | 
						|
				}
 | 
						|
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			// For all other event operations Hugo will sync static.
 | 
						|
			logger.Println("Syncing", relPath, "to", publishDir)
 | 
						|
			if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
 | 
						|
				c.logger.Errorln(err)
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		return 0, nil
 | 
						|
	}
 | 
						|
 | 
						|
	_, err := c.doWithPublishDirs(syncFn)
 | 
						|
	return err
 | 
						|
}
 |