From d03d33d5889a612bddefccdd689094cc517b374a Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Fri, 2 Oct 2020 10:00:00 +0200 Subject: [PATCH] copy tree + folder to memory yamlfs generator --- README.md | 1 - cmd/yamlfs/main.go | 95 ++++++++++++++++++++++++++++++++++++++++ go.mod | 3 ++ go.sum | 6 +++ pkg/composefs/compose.go | 5 +++ pkg/vfs/utils.go | 66 +++++++++++++++++++++++++++- pkg/yamlfs/yamlfs.go | 7 +-- 7 files changed, 175 insertions(+), 8 deletions(-) create mode 100644 cmd/yamlfs/main.go diff --git a/README.md b/README.md index 427c34d..d9a9ce7 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,6 @@ the package `os` by the instance of the virtual filesystem. return nil, err } defer f.Close() - vfs.ReadFile() return ioutil.ReadAll(f) ``` diff --git a/cmd/yamlfs/main.go b/cmd/yamlfs/main.go new file mode 100644 index 0000000..8275d40 --- /dev/null +++ b/cmd/yamlfs/main.go @@ -0,0 +1,95 @@ +/* + * Copyright 2020 Mandelsoft. All rights reserved. + * This file is licensed under the Apache Software License, v. 2 except as noted + * otherwise in the LICENSE file + * + * 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 main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "strconv" + + "github.com/mandelsoft/vfs/pkg/osfs" + "github.com/mandelsoft/vfs/pkg/vfs" + "github.com/mandelsoft/vfs/pkg/yamlfs" +) + +type Config struct { + Go bool + Name string + Pkg string + Copyright string +} + +func ExitOnError(err error) { + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) + } +} + +func main() { + var opts Config + flag.BoolVar(&opts.Go, "go", false, "generate a go file instead of a yaml file") + flag.StringVar(&opts.Name, "name", "YamlFS", "The go variable name to use") + flag.StringVar(&opts.Pkg, "package", "gofs", "Package name to use") + flag.StringVar(&opts.Copyright, "copyright", "", "Package copyright header") + flag.Parse() + args := flag.Args() + + srcDir := "." + dstDir := vfs.PathSeparatorString + if len(args) > 0 { + if len(args) > 1 { + if len(args) > 2 { + ExitOnError(fmt.Errorf("too many arguments")) + } + dstDir = args[1] + } + srcDir = args[0] + } + dst, err := yamlfs.New(nil) + ExitOnError(err) + src := osfs.New() + ExitOnError(vfs.CopyDir(src, srcDir, dst, dstDir)) + data, err := dst.Data() + ExitOnError(err) + if opts.Go { + copyright := "" + if opts.Copyright != "" { + data, err := ioutil.ReadFile(opts.Copyright) + ExitOnError(err) + copyright = string(data) + "\n" + } + fmt.Printf(`%spackage %s + +import ( + "github.com/mandelsoft/vfs/pkg/yamlfs" +) + +func New%s() *yamlfs.YamlFileSystem { + fs, _ := yamlfs.New([]byte(%s)) + return fs +} + +`, copyright, opts.Pkg, opts.Name, strconv.Quote(string(data))) + } else { + fmt.Printf("%s\n", data) + } +} diff --git a/go.mod b/go.mod index 441d4f0..c3789eb 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,11 @@ module github.com/mandelsoft/vfs go 1.13 require ( + github.com/b4b4r07/go-pipe v0.0.0-20191010045404-84b446f57366 // indirect + github.com/joncalhoun/pipe v0.0.0-20170510025636-72505674a733 // indirect github.com/mandelsoft/filepath v0.0.0-20200909114706-3df73d378d55 github.com/onsi/ginkgo v1.14.0 github.com/onsi/gomega v1.10.1 + gopkg.in/pipe.v2 v2.0.0-20140414041502-3c2ca4d52544 // indirect gopkg.in/yaml.v2 v2.3.0 ) diff --git a/go.sum b/go.sum index cad613e..b2a7d45 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/b4b4r07/go-pipe v0.0.0-20191010045404-84b446f57366 h1:FVAkDbBxovi2ID0vaxY7vCGvdKASt9r0TGPM1u4YQyg= +github.com/b4b4r07/go-pipe v0.0.0-20191010045404-84b446f57366/go.mod h1:1ymsiQNa3qebVEEVtuIdhtAXRfjO4qFCFq1bBUOT2HE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -12,6 +14,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/joncalhoun/pipe v0.0.0-20170510025636-72505674a733 h1:/wtaMDeVpoAUkqZl/GT3lvM9nDBmRApu/Uvl7EUc9Ao= +github.com/joncalhoun/pipe v0.0.0-20170510025636-72505674a733/go.mod h1:2MNFZhLx2HMHTN4xKH6FhpoQWqmD8Ato8QOE2hp5hY4= github.com/mandelsoft/filepath v0.0.0-20180115145118-e79b4e7be206 h1:M02UJfGz1+m1oecAZ0JR3vtYmIHWGjzeiB979dDYrD0= github.com/mandelsoft/filepath v0.0.0-20180115145118-e79b4e7be206/go.mod h1:EG0hGSztMG2F0cd5TYTQeCCB2hSJIAom3QuR7zgKMzE= github.com/mandelsoft/filepath v0.0.0-20200901163143-eceff1ab880a h1:MrULybu0xBqZb/VfEJNnyhkBBmBLZ4iKsWhYIfV18YE= @@ -62,6 +66,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/pipe.v2 v2.0.0-20140414041502-3c2ca4d52544 h1:WJH1qsOB4/zb/li+zLMn0vaAUJ5FqPv6HYLI3aQVg1k= +gopkg.in/pipe.v2 v2.0.0-20140414041502-3c2ca4d52544/go.mod h1:UhTeH/yXCK/KY7TX24mqPkaQ7gZeqmWd/8SSS8B3aHw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/composefs/compose.go b/pkg/composefs/compose.go index 0d2c4b7..888ac47 100644 --- a/pkg/composefs/compose.go +++ b/pkg/composefs/compose.go @@ -135,6 +135,11 @@ func (c *ComposedFileSystem) Mount(path string, fs vfs.FileSystem) error { if !fi.IsDir() { return fmt.Errorf("mount failed: mount point %s must be dir", mountp) } + for p := range c.mounts { + if p == mountp || strings.Contains(p, mountp+vfs.PathSeparatorString) { + delete(c.mounts, p) + } + } c.mounts[mountp] = fs return nil } diff --git a/pkg/vfs/utils.go b/pkg/vfs/utils.go index 87da5fa..7513647 100644 --- a/pkg/vfs/utils.go +++ b/pkg/vfs/utils.go @@ -385,7 +385,71 @@ func CopyFile(srcfs FileSystem, src string, dstfs FileSystem, dst string) error defer d.Close() _, err = io.Copy(d, s) - return err + if err != nil { + return err + } + return dstfs.Chmod(dst, fi.Mode()) +} + +// CopyDir recursively copies a directory tree, attempting to preserve permissions. +// Source directory must exist, destination directory may exist. +// Symlinks are ignored and skipped. +func CopyDir(srcfs FileSystem, src string, dstfs FileSystem, dst string) error { + src = Trim(srcfs, src) + dst = Trim(dstfs, dst) + + si, err := srcfs.Stat(src) + if err != nil { + return err + } + if !si.IsDir() { + return NewPathError("CopyDir", src, ErrNotDir) + } + + di, err := dstfs.Stat(dst) + if err != nil && !os.IsNotExist(err) { + return err + } + if err == nil && !di.IsDir() { + return NewPathError("CopyDir", dst, ErrNotDir) + } + + err = dstfs.MkdirAll(dst, si.Mode()) + if err != nil { + return err + } + + entries, err := ReadDir(srcfs, src) + if err != nil { + return err + } + + for _, entry := range entries { + srcPath := Join(srcfs, src, entry.Name()) + dstPath := Join(dstfs, dst, entry.Name()) + + if entry.IsDir() { + err = CopyDir(srcfs, srcPath, dstfs, dstPath) + } else { + // Skip symlinks. + if entry.Mode()&os.ModeSymlink != 0 { + var old string + old, err = srcfs.Readlink(srcPath) + if err == nil { + err = dstfs.Symlink(old, dstPath) + } + if err == nil { + err = os.Chmod(dst, entry.Mode()) + } + } else { + err = CopyFile(srcfs, srcPath, dstfs, dstPath) + } + } + if err != nil { + return err + } + } + return nil } func Touch(fs FileSystem, path string, perm os.FileMode) error { diff --git a/pkg/yamlfs/yamlfs.go b/pkg/yamlfs/yamlfs.go index 6a5e2c3..32cc5ae 100644 --- a/pkg/yamlfs/yamlfs.go +++ b/pkg/yamlfs/yamlfs.go @@ -47,16 +47,11 @@ func New(data []byte) (*YamlFileSystem, error) { func NewByPath(fs vfs.FileSystem, path string) (*YamlFileSystem, error) { var data []byte var err error - var f vfs.File if fs == nil { data, err = ioutil.ReadFile(path) } else { - f, err = fs.Open(path) - if err == nil { - defer f.Close() - data, err = ioutil.ReadAll(f) - } + data, err = vfs.ReadFile(fs, path) } if err != nil { return nil, err