--- a/docker/build.go Mon Jan 15 16:19:58 2018 -0600
+++ b/docker/build.go Mon Jan 15 16:20:18 2018 -0600
@@ -17,7 +17,6 @@
@@ -58,14 +57,12 @@
// create out build directory
- tmpDir, err := ioutil.TempDir("", "convey-build-")
+ buildDir := filepath.Join(st.Directory, name) + err = os.MkdirAll(buildDir, 0700) - // Remove the dir on defer OR on signal exit (first one to happen)
- defer st.CleanupList.Add(func() { os.RemoveAll(tmpDir) })()
dockerfile, err := environment.Mapper(b.Dockerfile, fullEnv)
@@ -77,7 +74,7 @@
// export the files to it
for _, src := range files {
src, dest := tasks.ParseFilePath(base, src)
- cleanDest := filepath.Clean(filepath.Join(tmpDir, dest))
+ cleanDest := filepath.Clean(filepath.Join(buildDir, dest)) if err = exportFile(name, st.Workspace.Name(), src, cleanDest, st); err != nil {
@@ -87,7 +84,7 @@
// copy the dockerfile to the temp directory
params := map[string]interface{}{
+ "destination": buildDir, "workspace": st.Workspace.Name(),
@@ -112,8 +109,8 @@
params = map[string]interface{}{
- "dockerfile": filepath.Join(tmpDir, filepath.Base(dockerfile)),
- "buildContext": tmpDir,
+ "dockerfile": filepath.Join(buildDir, filepath.Base(dockerfile)), + "buildContext": buildDir, --- a/docker/environment.go Mon Jan 15 16:19:58 2018 -0600
+++ b/docker/environment.go Mon Jan 15 16:20:18 2018 -0600
@@ -53,28 +53,18 @@
- // Create a temp directory we can export files from the current
- // container into. We can't read directly from the volume, and
- // we don't want to require reading only environment files on
- tmpDir, err := ioutil.TempDir("", "convey-environment-")
+ // create a directory in our state for the task + envDir := filepath.Join(st.Directory, name) + err = os.MkdirAll(envDir, 0700) - // Remove temp dir on app exit
- cleanupFn := st.CleanupList.Add(func() { os.RemoveAll(tmpDir) })
- // Call cleanup function on defer, which may instead be called
- // if the cleanup thread traps a signal.
for _, file := range files {
// Export the file into the temp directory and maintain the
// structure of the file (for ease of error messages, so we
// get the file a/b/c/env instead of env).
- dest := filepath.Clean(filepath.Join(tmpDir, file))
+ dest := filepath.Clean(filepath.Join(envDir, file)) if err = exportFile(name, st.Workspace.Name(), file, dest, st); err != nil {
--- a/docker/run.go Mon Jan 15 16:19:58 2018 -0600
+++ b/docker/run.go Mon Jan 15 16:20:18 2018 -0600
@@ -95,27 +95,16 @@
{{.Image}}{{if .Command}} {{.Command}}{{end}}`
// writeScript will write a shell script to the given tempfile for the given commands
-func (r *Run) writeScript(st *state.State, fullEnv []string) (string, string, string, error) {
- // figure out the current working directory
- // now get the absolute path
- absPwd, err := filepath.Abs(pwd)
+func (r *Run) writeScript(name string, st *state.State, fullEnv []string) (string, string, string, error) { + // make sure the scripts directory exist in our state directory + scriptsDir := filepath.Join(st.Directory, name) + err := os.MkdirAll(scriptsDir, 0700) // create the temp file to write the script to
- script, err := ioutil.TempFile(absPwd, "convey-script-")
- // set scriptFile to the name of the temp file
- scriptFile := script.Name()
+ scriptFile := filepath.Join(scriptsDir, "script") @@ -137,11 +126,11 @@
// write the script to the file
- script.WriteString(strings.Join(scripts, "\n"))
- // make the script executable to the user
- os.Chmod(scriptFile, 0700)
+ []byte(strings.Join(scripts, "\n")), return scriptFile, entryPoint, commandArg, nil
@@ -157,7 +146,17 @@
cid := strings.TrimSpace(stdout)
+ st.Cleanup(func(logger *gomol.LogAdapter) { + logger.Debugf("stopping container %s", cid) + err := StopContainer(cid, logger, st) + logger.Warnf("failed to stop container %s: %s", cid, err.Error()) + logger.Infof("stopped container %s", cid) logger.Infof("started detached container %s", cid)
@@ -296,17 +295,10 @@
// if we're using a script defined in the yaml, create it and override
- scriptFile, entryPoint, commandArg, err = r.writeScript(st, fullEnv)
+ scriptFile, entryPoint, commandArg, err = r.writeScript(name, st, fullEnv)
- // Be sure to clean up the script on app exit
- cleanupFn := st.CleanupList.Add(func() { os.Remove(scriptFile) })
- // Call cleanup function on defer, which may instead be called
- // if the cleanup thread traps a signal.
taskLabel := normalize.Normalize(
--- a/main.go Mon Jan 15 16:19:58 2018 -0600
+++ b/main.go Mon Jan 15 16:20:18 2018 -0600
@@ -26,7 +26,6 @@
"github.com/alecthomas/kingpin"
"github.com/aphistic/gomol"
- "bitbucket.org/rw_grim/convey/cleanup"
"bitbucket.org/rw_grim/convey/config"
"bitbucket.org/rw_grim/convey/environment"
"bitbucket.org/rw_grim/convey/loaders/bitbucket"
@@ -205,6 +204,9 @@
if err := logging.Setup(*color, *verbose); err != nil {
fmt.Printf("failed to setup logging: %s\n", err)
@@ -212,6 +214,9 @@
defer gomol.ShutdownLoggers()
+ // now defer the state shutdown so we can still log loader := determineLoader()
@@ -244,11 +249,8 @@
- cleanupList := cleanup.NewList()
+ // set the state's variables and validate it - st.CleanupList = cleanupList
st.DisableDeprecated = *disableDeprecated
st.ForceSequential = *forceSequential
--- a/plans/plans.go Mon Jan 15 16:19:58 2018 -0600
+++ b/plans/plans.go Mon Jan 15 16:20:18 2018 -0600
@@ -56,6 +56,14 @@
logger.Infof("created network %s", st.Network.Name())
+ st.Cleanup(func(logger *gomol.LogAdapter) { + logger.Infof("removing network %s", st.Network.Name()) + if err := st.Network.Destroy(); err != nil { + logger.Fatalf("failed to remove network %s", st.Network.Name()) + logger.Infof("removed network %s", st.Network.Name()) logger.Info("creating workspace...")
@@ -71,47 +79,11 @@
-func (p *Plan) teardown(logger *gomol.LogAdapter, st *state.State) {
- // run through the DetachedContainers and stop them
- for _, cid := range st.GetDetached() {
- logger.Infof("removing detached container %s", cid)
- docker.StopContainer(cid, logger, st)
- // remove the workspace (if requested)
- logger.Infof("not removing workspace %s as requested", st.Workspace.Name())
- logger.Infof("removing workspace %s", st.Workspace.Name())
- if err := st.Workspace.Destroy(); err != nil {
- logger.Fatalf("failed to remove workspace %s", st.Workspace.Name())
- logger.Infof("removed workspace %s", st.Workspace.Name())
- logger.Infof("removing network %s", st.Network.Name())
- if err := st.Network.Destroy(); err != nil {
- logger.Fatalf("failed to remove network %s", st.Network.Name())
- logger.Infof("removed network %s", st.Network.Name())
// Execute runs the plan.
func (p *Plan) Execute(path string, tasks map[string]tasks.Task, env []string, st *state.State) error {
logger := logging.NewAdapter(path)
planEnv := environment.Merge(env, p.Environment)
- // Teardown plan on defer on app exit
- cleanupFn := st.CleanupList.Add(func() { p.teardown(logger, st) })
- // Call cleanup function on defer, which may instead be called
- // if the cleanup thread traps a signal.
if err := p.setup(logger, st); err != nil {
--- a/state/state.go Mon Jan 15 16:19:58 2018 -0600
+++ b/state/state.go Mon Jan 15 16:20:18 2018 -0600
@@ -19,13 +19,17 @@
- "bitbucket.org/rw_grim/convey/cleanup"
+ "github.com/aphistic/gomol" "bitbucket.org/rw_grim/convey/environment"
+ "bitbucket.org/rw_grim/convey/logging" "bitbucket.org/rw_grim/convey/network"
"bitbucket.org/rw_grim/convey/workspace"
@@ -34,8 +38,11 @@
// State holds all of the runtime data during a run.
+ logger *gomol.LogAdapter + cleanupList *cleanupList - CleanupList *cleanup.List
Workspace workspace.Workspace
@@ -82,10 +89,43 @@
// New creates a new state.
+ dir, err := createDirectory() + logger: logging.NewAdapter("state"), + cleanupList: newCleanupList(), runningContainers: map[string]struct{}{},
detachedContainers: map[string]struct{}{},
+// createDirectory creates the state directory for this run. +func createDirectory() (string, error) { + parent := filepath.Join(pwd, ".convey") + err = os.MkdirAll(parent, 0700) + dir, err := ioutil.TempDir(parent, "") // Valid validates whether the state is correct or not.
@@ -255,7 +295,6 @@
// is used to map a slice within an extended task.
func (st *State) WrapWithExpandableEnv(env, expandable []string, delimiter string) *State {
- CleanupList: st.CleanupList,
KeepWorkspace: st.KeepWorkspace,