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 }