grim/convey

We need to clean up the workspace directory even while testing
// Convey
// Copyright 2016-2019 Gary Kramlich <grim@reaperworld.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package workspace
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
func (ws *Workspace) TaskDirectory(name string) (string, error) {
dir := filepath.Join(ws.path, name)
err := os.MkdirAll(dir, 0700)
return dir, err
}
// CopyFile copies the contents from src to dst atomically.
// If dst does not exist, CopyFile creates it with permissions perm.
// If the copy fails, CopyFile aborts and dst is preserved.
func (ws *Workspace) copyFile(src, dst string, perm os.FileMode) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
tmp, err := ioutil.TempFile(filepath.Dir(dst), "")
if err != nil {
return err
}
_, err = io.Copy(tmp, in)
if err != nil {
tmp.Close()
os.Remove(tmp.Name())
return err
}
if err = tmp.Close(); err != nil {
os.Remove(tmp.Name())
return err
}
if err = os.Chmod(tmp.Name(), perm); err != nil {
os.Remove(tmp.Name())
return err
}
return os.Rename(tmp.Name(), dst)
}
func (ws *Workspace) copyDir(src, dst string, perm os.FileMode) error {
err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
// make sure we're copying files that are at the same level as convey.yml or
// deeper.
if !strings.HasPrefix(path, ws.parent) {
return fmt.Errorf(
"attempted to copy %q which is outside of the run context of %q",
path,
ws.parent,
)
}
// make sure we're don't try to import anything from the .convey directory
if strings.HasPrefix(path, ws.root) {
return nil
}
// at this point we're going to do something so we need to the real
// destination name
realDst := filepath.Join(ws.volumePath, strings.TrimPrefix(path, ws.parent))
// if path is a directory, create it
if info.IsDir() {
err := os.Mkdir(realDst, info.Mode())
// this will get called with the root of the volume, so we need to
// handle the error if it exists.
if os.IsExist(err) {
return nil
}
return err
}
// at this point we have a file so let's copy it
return ws.copyFile(path, realDst, info.Mode())
})
return err
}
func (ws *Workspace) Import(src, dst string) error {
realDst := filepath.Join(ws.volumePath, dst)
file, err := os.Stat(src)
if err != nil {
return err
}
if file.IsDir() {
return ws.copyDir(src, realDst, file.Mode())
}
return ws.copyFile(src, realDst, file.Mode())
}
func (ws *Workspace) Export(src, dst string) error {
file, err := os.Stat(src)
if err != nil {
return err
}
if file.IsDir() {
return ws.copyDir(src, dst, file.Mode())
}
return ws.copyFile(src, dst, file.Mode())
}