github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/tpl/os/os.go (about)

     1  // Copyright 2017 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 os provides template functions for interacting with the operating
    15  // system.
    16  package os
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	_os "os"
    22  
    23  	"github.com/gohugoio/hugo/deps"
    24  	"github.com/spf13/afero"
    25  	"github.com/spf13/cast"
    26  )
    27  
    28  // New returns a new instance of the os-namespaced template functions.
    29  func New(d *deps.Deps) *Namespace {
    30  	var rfs afero.Fs
    31  	if d.Fs != nil {
    32  		rfs = d.Fs.WorkingDir
    33  		if d.PathSpec != nil && d.PathSpec.BaseFs != nil {
    34  			rfs = afero.NewReadOnlyFs(afero.NewCopyOnWriteFs(d.PathSpec.BaseFs.Content.Fs, d.Fs.WorkingDir))
    35  		}
    36  
    37  	}
    38  
    39  	return &Namespace{
    40  		readFileFs: rfs,
    41  		deps:       d,
    42  	}
    43  }
    44  
    45  // Namespace provides template functions for the "os" namespace.
    46  type Namespace struct {
    47  	readFileFs afero.Fs
    48  	deps       *deps.Deps
    49  }
    50  
    51  // Getenv retrieves the value of the environment variable named by the key.
    52  // It returns the value, which will be empty if the variable is not present.
    53  func (ns *Namespace) Getenv(key interface{}) (string, error) {
    54  	skey, err := cast.ToStringE(key)
    55  	if err != nil {
    56  		return "", nil
    57  	}
    58  
    59  	return _os.Getenv(skey), nil
    60  }
    61  
    62  // readFile reads the file named by filename in the given filesystem
    63  // and returns the contents as a string.
    64  func readFile(fs afero.Fs, filename string) (string, error) {
    65  	if filename == "" {
    66  		return "", errors.New("readFile needs a filename")
    67  	}
    68  
    69  	b, err := afero.ReadFile(fs, filename)
    70  	if err != nil {
    71  		return "", err
    72  	}
    73  
    74  	return string(b), nil
    75  }
    76  
    77  // ReadFile reads the file named by filename relative to the configured WorkingDir.
    78  // It returns the contents as a string.
    79  // There is an upper size limit set at 1 megabytes.
    80  func (ns *Namespace) ReadFile(i interface{}) (string, error) {
    81  	s, err := cast.ToStringE(i)
    82  	if err != nil {
    83  		return "", err
    84  	}
    85  
    86  	if ns.deps.PathSpec != nil {
    87  		s = ns.deps.PathSpec.RelPathify(s)
    88  	}
    89  
    90  	return readFile(ns.readFileFs, s)
    91  }
    92  
    93  // ReadDir lists the directory contents relative to the configured WorkingDir.
    94  func (ns *Namespace) ReadDir(i interface{}) ([]_os.FileInfo, error) {
    95  	path, err := cast.ToStringE(i)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	list, err := afero.ReadDir(ns.deps.Fs.WorkingDir, path)
   101  	if err != nil {
   102  		return nil, fmt.Errorf("failed to read directory %q: %s", path, err)
   103  	}
   104  
   105  	return list, nil
   106  }
   107  
   108  // FileExists checks whether a file exists under the given path.
   109  func (ns *Namespace) FileExists(i interface{}) (bool, error) {
   110  	path, err := cast.ToStringE(i)
   111  	if err != nil {
   112  		return false, err
   113  	}
   114  
   115  	if path == "" {
   116  		return false, errors.New("fileExists needs a path to a file")
   117  	}
   118  
   119  	status, err := afero.Exists(ns.readFileFs, path)
   120  	if err != nil {
   121  		return false, err
   122  	}
   123  
   124  	return status, nil
   125  }
   126  
   127  // Stat returns the os.FileInfo structure describing file.
   128  func (ns *Namespace) Stat(i interface{}) (_os.FileInfo, error) {
   129  	path, err := cast.ToStringE(i)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	if path == "" {
   135  		return nil, errors.New("fileStat needs a path to a file")
   136  	}
   137  
   138  	r, err := ns.readFileFs.Stat(path)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	return r, nil
   144  }