Turn workspace.Workspace into an interface and move all the logic into docker.Workspace. Fixes #120
--- a/docker/build.go Tue Sep 12 21:13:14 2017 -0500
+++ b/docker/build.go Tue Sep 12 23:04:15 2017 -0500
@@ -63,7 +63,7 @@
src, dest := tasks.ParseFilePath(base, environment.Mapper(src, fullEnv))
cleanDest := filepath.Clean(filepath.Join(tmpDir, dest))
- if err = exportFile(name, st.Workspace.Name, src, cleanDest, st); err != nil {
+ if err = exportFile(name, st.Workspace.Name(), src, cleanDest, st); err != nil { @@ -72,7 +72,7 @@
params := map[string]interface{}{
- "workspace": st.Workspace.Name,
+ "workspace": st.Workspace.Name(), err = Docker(name, exportTemplate, params, st)
--- a/docker/docker_test.go Tue Sep 12 21:13:14 2017 -0500
+++ b/docker/docker_test.go Tue Sep 12 23:04:15 2017 -0500
@@ -34,5 +34,6 @@
s.RegisterPlugin(junit.NewPlugin())
s.AddSuite(&dockerSuite{})
+ s.AddSuite(&workspaceSuite{}) --- a/docker/export.go Tue Sep 12 21:13:14 2017 -0500
+++ b/docker/export.go Tue Sep 12 23:04:15 2017 -0500
@@ -93,16 +93,18 @@
+ dockerWorkspace := st.Workspace.(*Workspace) if strings.ContainsRune(file, '*') {
- mountPoint := environment.Mapper(st.Workspace.MountPoint, fullEnv)
+ mountPoint := environment.Mapper(dockerWorkspace.mountPoint, fullEnv) - if err := exportGlob(name, st.Workspace.Name, mountPoint, file, st); err != nil {
+ if err := exportGlob(name, st.Workspace.Name(), mountPoint, file, st); err != nil { src, dest := tasks.ParseFilePath("", file)
- if err := exportFile(name, st.Workspace.Name, src, dest, st); err != nil {
+ if err := exportFile(name, st.Workspace.Name(), src, dest, st); err != nil { --- a/docker/import.go Tue Sep 12 21:13:14 2017 -0500
+++ b/docker/import.go Tue Sep 12 23:04:15 2017 -0500
@@ -41,7 +41,7 @@
params := map[string]interface{}{
- "workspaceID": st.Workspace.Name,
+ "workspaceID": st.Workspace.Name(), err := Docker(name, importTemplate, params, st)
--- a/docker/network.go Tue Sep 12 21:13:14 2017 -0500
+++ b/docker/network.go Tue Sep 12 23:04:15 2017 -0500
@@ -33,8 +33,8 @@
- createTemplate = `network create {{.Name}}`
- destroyTemplate = `network rm {{.Name}}`
+ networkCreateTemplate = `network create {{.Name}}` + networkDestroyTemplate = `network rm {{.Name}}` func NewNetwork(st *state.State) (*Network, error) {
@@ -48,7 +48,7 @@
- _, _, err := DockerOutput("create network", createTemplate, params, st)
+ _, _, err := DockerOutput("create network", networkCreateTemplate, params, st) @@ -67,5 +67,5 @@
- return Docker("remove network", destroyTemplate, params, network.state)
+ return Docker("remove network", networkDestroyTemplate, params, network.state) --- a/docker/run.go Tue Sep 12 21:13:14 2017 -0500
+++ b/docker/run.go Tue Sep 12 23:04:15 2017 -0500
@@ -175,6 +175,8 @@
fmt.Sprintf("convey-%d-task=%s", os.Getpid(), name),
+ dockerWorkspace := st.Workspace.(*Workspace) // build the dict for the template
params := map[string]interface{}{
@@ -193,7 +195,7 @@
"SSHAuthSock": os.Getenv("SSH_AUTH_SOCK"),
"WorkDir": environment.Mapper(r.WorkDir, fullEnv),
- "WorkspacePath": environment.Mapper(st.Workspace.MountPoint, fullEnv),
+ "WorkspacePath": environment.Mapper(dockerWorkspace.mountPoint, fullEnv), "WorkspaceMount": environment.Mapper(workSpace, fullEnv),
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docker/workspace.go Tue Sep 12 23:04:15 2017 -0500
@@ -0,0 +1,102 @@
+ * Copyright 2016-2017 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/>. + "github.com/aphistic/gomol" + "github.com/satori/go.uuid" + "bitbucket.org/rw_grim/convey/logging" + "bitbucket.org/rw_grim/convey/state" + logger *gomol.LogAdapter + wsCreateTemplate = `create --name={{.Name}} convey/workspace` + wsDestroyTemplate = `rm -v {{.Name}}` + volumeMountTemplate = `inspect --format "{{.Format}}" {{.Volume}}` + volumeMountFormat = `{{range .Mounts}}{{if eq .Destination \"/workspace\" }}{{.Source}}{{end}}{{end}}` +func (ws *Workspace) findMountPoint(st *state.State) error { + params := map[string]interface{}{ + "Volume": ws.volumeName, + "Format": volumeMountFormat, + stdout, stderr, err := DockerOutput("findMountPoint", volumeMountTemplate, params, st) + ws.logger.Errorf("%s", stderr) + ws.mountPoint = strings.TrimSpace(stdout) +func NewWorkspace(st *state.State) (*Workspace, error) { + name: uuid.NewV4().String(), + logger: logging.NewAdapter("workspace"), + params := map[string]interface{}{ + out, _, err := DockerOutput("create workspace", wsCreateTemplate, params, st) + ws.volumeName = strings.TrimSpace(out) + err = ws.findMountPoint(st) + ws.logger.Debugf("created workspace: %#v", ws) +func (ws *Workspace) Name() string { +func (ws *Workspace) Destroy() error { + params := map[string]interface{}{ + return Docker("remove workspace", wsDestroyTemplate, params, ws.state) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docker/workspace_test.go Tue Sep 12 23:04:15 2017 -0500
@@ -0,0 +1,38 @@
+ * Copyright 2016-2017 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/>. + "github.com/aphistic/sweet" + . "github.com/onsi/gomega" + "bitbucket.org/rw_grim/convey/workspace" +type workspaceSuite struct{} +func (s *workspaceSuite) TestImplementsWorkspace(t sweet.T) { + var ws workspace.Workspace + fmt.Printf("%#v %v", ws, ws) + Expect(ws).To(Not(BeNil())) --- a/plans/plans.go Tue Sep 12 21:13:14 2017 -0500
+++ b/plans/plans.go Tue Sep 12 23:04:15 2017 -0500
@@ -28,7 +28,6 @@
"bitbucket.org/rw_grim/convey/stages"
"bitbucket.org/rw_grim/convey/state"
"bitbucket.org/rw_grim/convey/tasks"
- "bitbucket.org/rw_grim/convey/workspace"
"bitbucket.org/rw_grim/convey/yaml"
@@ -51,14 +50,14 @@
logger.Info("creating workspace...")
- ws, err := workspace.Create()
+ ws, err := docker.NewWorkspace(st) logger.Fatal("failed to create workspace")
- logger.Infof("created workspace %s", st.Workspace.Name)
+ logger.Infof("created workspace %s", st.Workspace.Name()) @@ -73,13 +72,13 @@
// remove the workspace (if requested)
- logger.Infof("not removing workspace %s as requested", st.Workspace.Name)
+ logger.Infof("not removing workspace %s as requested", st.Workspace.Name()) - logger.Infof("removing workspace %s", 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.Fatalf("failed to remove workspace %s", st.Workspace.Name()) - logger.Infof("removed workspace %s", st.Workspace.Name)
+ logger.Infof("removed workspace %s", st.Workspace.Name()) --- a/state/state.go Tue Sep 12 21:13:14 2017 -0500
+++ b/state/state.go Tue Sep 12 23:04:15 2017 -0500
@@ -28,7 +28,7 @@
- Workspace *workspace.Workspace
+ Workspace workspace.Workspace --- a/workspace/workspace.go Tue Sep 12 21:13:14 2017 -0500
+++ b/workspace/workspace.go Tue Sep 12 23:04:15 2017 -0500
@@ -17,78 +17,7 @@
- "github.com/aphistic/gomol"
- "github.com/satori/go.uuid"
- "bitbucket.org/rw_grim/convey/command"
- "bitbucket.org/rw_grim/convey/logging"
- logger *gomol.LogAdapter
+type Workspace interface {
- createTemplate = `docker create --name={{.Name}} convey/workspace`
- destroyTemplate = `docker rm -v {{.Name}}`
- volumeMountTemplate = `docker inspect --format "{{.Format}}" {{.Volume}}`
- volumeMountFormat = `{{range .Mounts}}{{if eq .Destination \"/workspace\" }}{{.Source}}{{end}}{{end}}`
-func (ws *Workspace) findMountPoint() error {
- params := map[string]interface{}{
- "Volume": ws.VolumeName,
- "Format": volumeMountFormat,
- out, _, err := command.RunOutput("findMountPoint", volumeMountTemplate, params, time.Minute)
- ws.MountPoint = strings.TrimSpace(out)
-func Create() (*Workspace, error) {
- Name: uuid.NewV4().String(),
- logger: logging.NewAdapter("workspace"),
- params := map[string]interface{}{
- out, _, err := command.RunOutput("create workspace", createTemplate, params, time.Minute)
- ws.VolumeName = strings.TrimSpace(out)
- err = ws.findMountPoint()
- ws.logger.Debugf("created workspace: %#v", ws)
-func (ws *Workspace) Destroy() error {
- params := map[string]interface{}{
- return command.Run("remove workspace", destroyTemplate, params, time.Minute)