URI: 
       hashing_fs.go - hugo - [fork] hugo port for 9front
  HTML git clone https://git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
       hashing_fs.go (2676B)
       ---
            1 // Copyright 2019 The Hugo Authors. All rights reserved.
            2 //
            3 // Licensed under the Apache License, Version 2.0 (the "License");
            4 // you may not use this file except in compliance with the License.
            5 // You may obtain a copy of the License at
            6 // http://www.apache.org/licenses/LICENSE-2.0
            7 //
            8 // Unless required by applicable law or agreed to in writing, software
            9 // distributed under the License is distributed on an "AS IS" BASIS,
           10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           11 // See the License for the specific language governing permissions and
           12 // limitations under the License.
           13 
           14 package hugofs
           15 
           16 import (
           17         "hash"
           18         "os"
           19 
           20         "github.com/cespare/xxhash/v2"
           21         "github.com/spf13/afero"
           22 )
           23 
           24 var (
           25         _ afero.Fs            = (*hashingFs)(nil)
           26         _ FilesystemUnwrapper = (*hashingFs)(nil)
           27 )
           28 
           29 // FileHashReceiver will receive the filename an the content's MD5 sum on file close.
           30 type FileHashReceiver interface {
           31         OnFileClose(name string, checksum uint64)
           32 }
           33 
           34 type hashingFs struct {
           35         afero.Fs
           36         hashReceiver FileHashReceiver
           37 }
           38 
           39 // NewHashingFs creates a new filesystem that will receive MD5 checksums of
           40 // any written file content on Close. Note that this is probably not a good
           41 // idea for "full build" situations, but when doing fast render mode, the amount
           42 // of files published is low, and it would be really nice to know exactly which
           43 // of these files where actually changed.
           44 // Note that this will only work for file operations that use the io.Writer
           45 // to write content to file, but that is fine for the "publish content" use case.
           46 func NewHashingFs(delegate afero.Fs, hashReceiver FileHashReceiver) afero.Fs {
           47         return &hashingFs{Fs: delegate, hashReceiver: hashReceiver}
           48 }
           49 
           50 func (fs *hashingFs) UnwrapFilesystem() afero.Fs {
           51         return fs.Fs
           52 }
           53 
           54 func (fs *hashingFs) Create(name string) (afero.File, error) {
           55         f, err := fs.Fs.Create(name)
           56         if err == nil {
           57                 f = fs.wrapFile(f)
           58         }
           59         return f, err
           60 }
           61 
           62 func (fs *hashingFs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
           63         f, err := fs.Fs.OpenFile(name, flag, perm)
           64         if err == nil && isWrite(flag) {
           65                 f = fs.wrapFile(f)
           66         }
           67         return f, err
           68 }
           69 
           70 func (fs *hashingFs) wrapFile(f afero.File) afero.File {
           71         return &hashingFile{File: f, h: xxhash.New(), hashReceiver: fs.hashReceiver}
           72 }
           73 
           74 func (fs *hashingFs) Name() string {
           75         return "hashingFs"
           76 }
           77 
           78 type hashingFile struct {
           79         hashReceiver FileHashReceiver
           80         h            hash.Hash64
           81         afero.File
           82 }
           83 
           84 func (h *hashingFile) Write(p []byte) (n int, err error) {
           85         n, err = h.File.Write(p)
           86         if err != nil {
           87                 return
           88         }
           89         return h.h.Write(p)
           90 }
           91 
           92 func (h *hashingFile) Close() error {
           93         h.hashReceiver.OnFileClose(h.Name(), h.h.Sum64())
           94         return h.File.Close()
           95 }