github.com/falafeljan/pkger@v0.18.0/pkging/stdos/stdos.go (about)

     1  package stdos
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/markbates/pkger/here"
    10  	"github.com/markbates/pkger/internal/maps"
    11  	"github.com/markbates/pkger/pkging"
    12  )
    13  
    14  var _ pkging.Pkger = &Pkger{}
    15  
    16  type Pkger struct {
    17  	Here  here.Info
    18  	infos *maps.Infos
    19  }
    20  
    21  // New returns *Pkger for the provided here.Info
    22  func New(her here.Info) (*Pkger, error) {
    23  	p := &Pkger{
    24  		infos: &maps.Infos{},
    25  		Here:  her,
    26  	}
    27  	p.infos.Store(her.ImportPath, her)
    28  	return p, nil
    29  }
    30  
    31  // Create creates the named file with mode 0666 (before umask) - It's actually 0644, truncating it if it already exists. If successful, methods on the returned File can be used for I/O; the associated file descriptor has mode O_RDWR.
    32  func (fx *Pkger) Create(name string) (pkging.File, error) {
    33  	pt, err := fx.Parse(name)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	her, err := fx.Info(pt.Pkg)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	name = filepath.Join(her.Dir, pt.Name)
    44  	f, err := os.Create(name)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	nf := &File{
    50  		File:   f,
    51  		her:    her,
    52  		path:   pt,
    53  		pkging: fx,
    54  	}
    55  
    56  	info, err := f.Stat()
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	nf.info = pkging.NewFileInfo(info)
    61  	return nf, nil
    62  }
    63  
    64  // Current returns the here.Info representing the current Pkger implementation.
    65  func (f *Pkger) Current() (here.Info, error) {
    66  	return f.Here, nil
    67  }
    68  
    69  // Info returns the here.Info of the here.Path
    70  func (f *Pkger) Info(p string) (here.Info, error) {
    71  	info, ok := f.infos.Load(p)
    72  	if ok {
    73  		return info, nil
    74  	}
    75  
    76  	info, err := here.Package(p)
    77  	if err != nil {
    78  		return info, err
    79  	}
    80  	f.infos.Store(p, info)
    81  	return info, nil
    82  }
    83  
    84  // MkdirAll creates a directory named path, along with any necessary parents, and returns nil, or else returns an error. The permission bits perm (before umask) are used for all directories that MkdirAll creates. If path is already a directory, MkdirAll does nothing and returns nil.
    85  func (f *Pkger) MkdirAll(p string, perm os.FileMode) error {
    86  	pt, err := f.Parse(p)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	info, err := f.Info(pt.Pkg)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	return os.MkdirAll(filepath.Join(info.Dir, p), perm)
    95  }
    96  
    97  // Open opens the named file for reading. If successful, methods on the returned file can be used for reading; the associated file descriptor has mode O_RDONLY.
    98  func (fx *Pkger) Open(name string) (pkging.File, error) {
    99  	pt, err := fx.Parse(name)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	her, err := fx.Info(pt.Pkg)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	name = filepath.Join(her.Dir, pt.Name)
   110  	f, err := os.Open(name)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	nf := &File{
   116  		File:   f,
   117  		her:    her,
   118  		path:   pt,
   119  		pkging: fx,
   120  	}
   121  
   122  	info, err := f.Stat()
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	nf.info = pkging.NewFileInfo(info)
   127  
   128  	return nf, nil
   129  }
   130  
   131  // Parse the string in here.Path format.
   132  func (f *Pkger) Parse(p string) (here.Path, error) {
   133  	return f.Here.Parse(p)
   134  }
   135  
   136  // Stat returns a FileInfo describing the named file.
   137  func (fx *Pkger) Stat(name string) (os.FileInfo, error) {
   138  	pt, err := fx.Parse(name)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	her, err := fx.Info(pt.Pkg)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	info, err := os.Stat(filepath.Join(her.Dir, pt.Name))
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  
   153  	info = pkging.NewFileInfo(info)
   154  
   155  	return info, nil
   156  }
   157  
   158  // Walk walks the file tree rooted at root, calling walkFn for each file or directory in the tree, including root. All errors that arise visiting files and directories are filtered by walkFn. The files are walked in lexical order, which makes the output deterministic but means that for very large directories Walk can be inefficient. Walk does not follow symbolic links. - That is from the standard library. I know. Their grammar teachers can not be happy with them right now.
   159  func (f *Pkger) Walk(p string, wf filepath.WalkFunc) error {
   160  	pt, err := f.Parse(p)
   161  	if err != nil {
   162  		return err
   163  	}
   164  
   165  	info, err := f.Info(pt.Pkg)
   166  	if err != nil {
   167  		return err
   168  	}
   169  
   170  	fp := filepath.Join(info.Dir, pt.Name)
   171  	err = filepath.Walk(fp, func(path string, fi os.FileInfo, err error) error {
   172  		if err != nil {
   173  			return err
   174  		}
   175  
   176  		pt, err := f.Parse(fmt.Sprintf("%s:%s", pt.Pkg, path))
   177  		if err != nil {
   178  			return err
   179  		}
   180  
   181  		info, err := f.Info(pt.Pkg)
   182  		if err != nil {
   183  			return err
   184  		}
   185  
   186  		path = strings.TrimPrefix(path, info.Dir)
   187  		path = strings.ReplaceAll(path, "\\", "/")
   188  		pt.Name = path
   189  		return wf(pt.String(), pkging.NewFileInfo(fi), nil)
   190  	})
   191  
   192  	return err
   193  }
   194  
   195  // Remove removes the named file or (empty) directory.
   196  func (fx *Pkger) Remove(name string) error {
   197  	pt, err := fx.Parse(name)
   198  	if err != nil {
   199  		return err
   200  	}
   201  
   202  	info, err := fx.Info(pt.Pkg)
   203  	if err != nil {
   204  		return err
   205  	}
   206  
   207  	return os.Remove(filepath.Join(info.Dir, pt.Name))
   208  }
   209  
   210  // RemoveAll removes path and any children it contains. It removes everything it can but returns the first error it encounters. If the path does not exist, RemoveAll returns nil (no error).
   211  func (fx *Pkger) RemoveAll(name string) error {
   212  	pt, err := fx.Parse(name)
   213  	if err != nil {
   214  		return err
   215  	}
   216  
   217  	info, err := fx.Info(pt.Pkg)
   218  	if err != nil {
   219  		return err
   220  	}
   221  
   222  	return os.RemoveAll(filepath.Join(info.Dir, pt.Name))
   223  }