[
  {
    "path": ".gitignore",
    "content": ".vendor\n\n# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n*.test\n\n# Folders\n_obj/\n_test/\nbin/\n_vendor/\nbuild/\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n\n*.swp\n**.orig\n.env\n\n# OSX\n.DS_Store\n._*\n.Spotlight-V100\n.Trashes\n\n# Linux\n*~\n.directory\n\n# Windows\nThumbs.db\nDesktop.ini\n\n# RubyMine\n.idea/\n\n# TextMate\n*.tmproj\n*.tmproject\ntmtags\n\n# Vim\n.*.sw[a-z]\n*.un~\nSession.vim\ntags\n\n# Emacs\n\\#*\\#\n/.emacs.desktop\n/.emacs.desktop.lock\n.elc\nauto-save-list\ntramp\n.\\#*\n\n# Vagrant\n.vagrant\n"
  },
  {
    "path": "Goopfile",
    "content": "github.com/onsi/ginkgo/ginkgo\ngithub.com/onsi/gomega\ncode.google.com/p/go.tools/go/vcs\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014 Irrational Industries, Inc. d.b.a. Nitrous.IO.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "NO_COLOR=\\033[0m\nOK_COLOR=\\033[32;01m\nERROR_COLOR=\\033[31;01m\nWARN_COLOR=\\033[33;01m\nBIN_NAME=goop\n\nall: build\n\nbuild:\n\t@mkdir -p build/\n\t@echo \"$(OK_COLOR)==> Installing dependencies$(NO_COLOR)\"\n\tgo get -d -v ./...\n\t@echo \"$(OK_COLOR)==> Building$(NO_COLOR)\"\n\tgo install -x ./...\n\tcp $(GOPATH)/bin/$(BIN_NAME) build/$(BIN_NAME)\n\nformat:\n\tgo fmt ./...\n\ntest:\n\t@echo \"$(OK_COLOR)==> Testing...$(NO_COLOR)\"\n\t@go list -f '{{range .TestImports}}{{.}} {{end}}' ./... | xargs -n1 go get -d\n\t@goop exec ginkgo -r -trace -keepGoing\n\n.PHONY: all build format test\n"
  },
  {
    "path": "README.md",
    "content": "Goop\n====\n\n![Goopie](https://raw.githubusercontent.com/nitrous-io/goop/master/goopie.png)\n\nA dependency manager for Go (golang), inspired by Bundler. It is different from other dependency managers in that it does not force you to mess with your `GOPATH`.\n\n### Getting Started\n\n1. Install Goop: `go get github.com/nitrous-io/goop`\n\n2. Create `Goopfile`. Revision reference (e.g. Git SHA hash) is optional, but recommended. Prefix hash with `#`. (This is to futureproof the file format.)\n\n   Example:\n   ```\n   github.com/mattn/go-sqlite3\n   github.com/gorilla/context #14f550f51af52180c2eefed15e5fd18d63c0a64a\n   github.com/dotcloud/docker/pkg/proxy #v1.0.1 // comment\n   github.com/gorilla/mux !git@github.com:nitrous-io/mux.git // override repo url\n   ```\n\n3. Run `goop install`. This will install packages inside a subdirectory called `.vendor` and create `Goopfile.lock`, recording exact versions used for each package and its dependencies. Subsequent `goop install` runs will ignore `Goopfile` and install the versions specified in `Goopfile.lock`. You should check this file in to your source version control. It's a good idea to add `.vendor` to your version control system's ignore settings (e.g. `.gitignore`).\n\n4. Run commands using `goop exec` (e.g. `goop exec make`). This will execute your command in an environment that has correct `GOPATH` and `PATH` set.\n\n5. Go commands can be run without the `exec` keyword (e.g. `goop go test`).\n\n### Other commands\n\n* Run `goop update` to ignore an existing `Goopfile.lock`, and update to latest versions of packages (as specified in `Goopfile`).\n\n* Running `eval $(goop env)` will modify `GOPATH` and `PATH` in current shell session, allowing you to run commands without `goop exec`.\n\n### Caveat\n\nGoop currently only supports Git and Mercurial. This should be fine for 99% of the cases, but you are more than welcome to make a pull request that adds support for Subversion and Bazaar.\n\n- - -\n[Work on awesome golang projects, like Goop, at Nitrous.IO](http://www.nitrous.io/jobs/?utm_source=nitrous.io&utm_medium=goop_readme&utm_campaign=goop_readme)\n\nCopyright (c) 2014 Irrational Industries, Inc. d.b.a. Nitrous.IO.<br>\nThis software is licensed under the [MIT License](http://github.com/nitrous-io/goop/raw/master/LICENSE).\n"
  },
  {
    "path": "colors/colors.go",
    "content": "package colors\n\nconst (\n\tReset = \"\\033[0m\"\n\tOK    = \"\\033[0;32m\"\n\tError = \"\\033[0;31m\"\n\tWarn  = \"\\033[0;33m\"\n)\n"
  },
  {
    "path": "goop/goget.go",
    "content": "package goop\n\nimport (\n\t\"io\"\n\t\"os/exec\"\n\t\"regexp\"\n)\n\nvar goGetDownloadRe = regexp.MustCompile(`(?m)^(\\S+)\\s+\\(download\\)$`)\n\ntype DownloadRecorder struct {\n\tdownloads map[string]struct{}\n\twriter    io.Writer\n}\n\nfunc NewDownloadRecorder(writer io.Writer) *DownloadRecorder {\n\treturn &DownloadRecorder{downloads: map[string]struct{}{}, writer: writer}\n}\n\nfunc (d *DownloadRecorder) Write(p []byte) (n int, err error) {\n\ts := string(p)\n\tmatches := goGetDownloadRe.FindAllStringSubmatch(s, -1)\n\tif matches != nil {\n\t\tfor _, m := range matches {\n\t\t\td.downloads[m[1]] = struct{}{}\n\t\t}\n\t}\n\treturn d.writer.Write(p)\n}\n\nfunc (d *DownloadRecorder) Downloads() []string {\n\ts := make([]string, 0, len(d.downloads))\n\tfor k, _ := range d.downloads {\n\t\ts = append(s, k)\n\t}\n\treturn s\n}\n\nfunc (g *Goop) goGet(pkgpath string, gopath string) ([]string, error) {\n\tcmd := exec.Command(\"go\", \"get\", \"-d\", \"-v\", \"./...\")\n\tenv := g.patchedEnv(true)\n\tenv[\"GOPATH\"] = gopath\n\tcmd.Dir = pkgpath\n\tcmd.Env = env.Strings()\n\tcmd.Stdin = g.stdin\n\tcmd.Stdout = g.stdout\n\tdlRec := NewDownloadRecorder(g.stderr)\n\tcmd.Stderr = dlRec\n\terr := cmd.Run()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn dlRec.Downloads(), nil\n}\n"
  },
  {
    "path": "goop/goop.go",
    "content": "package goop\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"code.google.com/p/go.tools/go/vcs\"\n\n\t\"github.com/nitrous-io/goop/colors\"\n\t\"github.com/nitrous-io/goop/parser\"\n\t\"github.com/nitrous-io/goop/pkg/env\"\n)\n\ntype UnsupportedVCSError struct {\n\tVCS string\n}\n\nfunc (e *UnsupportedVCSError) Error() string {\n\treturn fmt.Sprintf(\"%s is not supported.\", e.VCS)\n}\n\ntype Goop struct {\n\tdir    string\n\tstdin  io.Reader\n\tstdout io.Writer\n\tstderr io.Writer\n}\n\nfunc NewGoop(dir string, stdin io.Reader, stdout io.Writer, stderr io.Writer) *Goop {\n\treturn &Goop{dir: dir, stdin: stdin, stdout: stdout, stderr: stderr}\n}\n\nfunc (g *Goop) patchedEnv(replaceGopath bool) env.Env {\n\te := env.NewEnv()\n\n\tbinPath := path.Join(g.vendorDir(), \"bin\")\n\n\tif replaceGopath {\n\t\te[\"GOPATH\"] = g.vendorDir()\n\t} else {\n\t\te.Prepend(\"GOPATH\", g.vendorDir())\n\t}\n\te[\"GOBIN\"] = binPath\n\te.Prepend(\"PATH\", binPath)\n\n\treturn e\n}\n\nfunc (g *Goop) PrintEnv() {\n\tgopath := os.Getenv(\"GOPATH\")\n\tif gopath == \"\" {\n\t\tg.stdout.Write([]byte(fmt.Sprintf(\"GOPATH=%s\\n\", g.vendorDir())))\n\t} else {\n\t\tg.stdout.Write([]byte(fmt.Sprintf(\"GOPATH=%s:%s\\n\", g.vendorDir(), gopath)))\n\t}\n\tg.stdout.Write([]byte(fmt.Sprintf(\"PATH=%s:%s\\n\", path.Join(g.vendorDir(), \"bin\"), os.Getenv(\"PATH\"))))\n}\n\nfunc (g *Goop) Exec(name string, args ...string) error {\n\tvname := path.Join(g.vendorDir(), \"bin\", name)\n\t_, err := os.Stat(vname)\n\tif err == nil {\n\t\tname = vname\n\t}\n\tcmd := exec.Command(name, args...)\n\tcmd.Env = g.patchedEnv(false).Strings()\n\tcmd.Stdin = g.stdin\n\tcmd.Stdout = g.stdout\n\tcmd.Stderr = g.stderr\n\treturn cmd.Run()\n}\n\nfunc (g *Goop) Install() error {\n\twriteLockFile := false\n\tf, err := os.Open(path.Join(g.dir, \"Goopfile.lock\"))\n\tif err == nil {\n\t\tg.stdout.Write([]byte(colors.OK + \"Using Goopfile.lock...\" + colors.Reset + \"\\n\"))\n\t} else {\n\t\tf, err = os.Open(path.Join(g.dir, \"Goopfile\"))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\twriteLockFile = true\n\t}\n\treturn g.parseAndInstall(f, writeLockFile)\n}\n\nfunc (g *Goop) Update() error {\n\tf, err := os.Open(path.Join(g.dir, \"Goopfile\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn g.parseAndInstall(f, true)\n}\n\nfunc (g *Goop) parseAndInstall(goopfile *os.File, writeLockFile bool) error {\n\tdefer goopfile.Close()\n\n\tdeps, err := parser.Parse(goopfile)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsrcPath := path.Join(g.vendorDir(), \"src\")\n\ttmpGoPath := path.Join(g.vendorDir(), \"tmp\")\n\ttmpSrcPath := path.Join(tmpGoPath, \"src\")\n\n\terr = os.RemoveAll(tmpGoPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = os.MkdirAll(tmpSrcPath, 0775)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trepos := map[string]*vcs.RepoRoot{}\n\tlockedDeps := map[string]*parser.Dependency{}\n\n\tfor _, dep := range deps {\n\t\tif dep.URL == \"\" {\n\t\t\tg.stdout.Write([]byte(colors.OK + \"=> Fetching \" + dep.Pkg + \"...\" + colors.Reset + \"\\n\"))\n\t\t} else {\n\t\t\tg.stdout.Write([]byte(colors.OK + \"=> Fetching \" + dep.Pkg + \" from \" + dep.URL + \"...\" + colors.Reset + \"\\n\"))\n\t\t}\n\n\t\trepo, err := repoForDep(dep)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\trepos[dep.Pkg] = repo\n\n\t\tpkgPath := path.Join(srcPath, repo.Root)\n\t\ttmpPkgPath := path.Join(tmpSrcPath, repo.Root)\n\n\t\terr = os.MkdirAll(path.Join(tmpPkgPath, \"..\"), 0775)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnoclone := false\n\n\t\texists, err := pathExists(pkgPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttmpExists, err := pathExists(tmpPkgPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif exists {\n\t\t\t// if package already exists, just symlink package dir and skip cloning\n\t\t\tg.stderr.Write([]byte(colors.Warn + \"Warning: \" + pkgPath + \" already exists; skipping!\" + colors.Reset + \"\\n\"))\n\t\t\tif !tmpExists {\n\t\t\t\terr = os.Symlink(pkgPath, tmpPkgPath)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tnoclone = true\n\t\t} else {\n\t\t\tnoclone = tmpExists\n\t\t}\n\n\t\tif !noclone {\n\t\t\t// clone repo\n\t\t\terr = g.clone(repo.VCS.Cmd, repo.Repo, tmpPkgPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// if rev is not given, record current rev in path\n\t\tif dep.Rev == \"\" {\n\t\t\trev, err := g.currentRev(repo.VCS.Cmd, tmpPkgPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdep.Rev = rev\n\t\t}\n\t\tlockedDeps[dep.Pkg] = dep\n\n\t\t// checkout specified rev\n\t\terr = g.checkout(repo.VCS.Cmd, tmpPkgPath, dep.Rev)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor _, dep := range deps {\n\t\tg.stdout.Write([]byte(colors.OK + \"=> Fetching dependencies for \" + dep.Pkg + \"...\" + colors.Reset + \"\\n\"))\n\n\t\trepo := repos[dep.Pkg]\n\t\ttmpPkgPath := path.Join(tmpSrcPath, repo.Root)\n\n\t\t// fetch sub-dependencies\n\t\tsubdeps, err := g.goGet(tmpPkgPath, tmpGoPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, subdep := range subdeps {\n\t\t\tsubdepRepo, err := vcs.RepoRootForImportPath(subdep, true)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tsubdepPkgPath := path.Join(tmpSrcPath, subdepRepo.Root)\n\n\t\t\trev, err := g.currentRev(subdepRepo.VCS.Cmd, subdepPkgPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\terr = g.checkout(subdepRepo.VCS.Cmd, subdepPkgPath, rev)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\trepos[subdep] = subdepRepo\n\t\t\tlockedDeps[subdep] = &parser.Dependency{Pkg: subdep, Rev: rev}\n\t\t}\n\t}\n\n\tfor _, dep := range lockedDeps {\n\t\tg.stdout.Write([]byte(colors.OK + \"=> Installing \" + dep.Pkg + \"...\" + colors.Reset + \"\\n\"))\n\n\t\trepo := repos[dep.Pkg]\n\t\tpkgPath := path.Join(srcPath, repo.Root)\n\t\ttmpPkgPath := path.Join(tmpSrcPath, repo.Root)\n\n\t\terr = os.MkdirAll(path.Join(pkgPath, \"..\"), 0775)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlfi, err := os.Lstat(tmpPkgPath)\n\t\tif err != nil && !os.IsNotExist(err) {\n\t\t\treturn err\n\t\t}\n\t\tif err == nil {\n\t\t\tif lfi.Mode()&os.ModeSymlink == 0 {\n\t\t\t\t// move package to vendor path\n\t\t\t\terr = os.RemoveAll(pkgPath)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\terr = os.Rename(tmpPkgPath, pkgPath)\n\t\t\t} else {\n\t\t\t\t// package already in vendor path, just remove the symlink\n\t\t\t\terr = os.Remove(tmpPkgPath)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, dep := range lockedDeps {\n\t\t// install\n\t\trepo := repos[dep.Pkg]\n\t\tpkgPath := path.Join(srcPath, repo.Root)\n\t\tcmd := g.command(pkgPath, \"go\", \"install\", \"-x\", dep.Pkg)\n\t\tcmd.Env = g.patchedEnv(true).Strings()\n\t\tcmd.Run()\n\t}\n\n\terr = os.RemoveAll(tmpGoPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// in order to minimize diffs, we sort lockedDeps first and write the\n\t// sorted results\n\tif writeLockFile {\n\t\tlf, err := os.Create(path.Join(g.dir, \"Goopfile.lock\"))\n\t\tdefer lf.Close()\n\n\t\tvar keys []string\n\t\tfor k := range lockedDeps {\n\t\t\tkeys = append(keys, k)\n\t\t}\n\t\tsort.Strings(keys)\n\n\t\tfor _, k := range keys {\n\t\t\tdep := lockedDeps[k]\n\t\t\t_, err = lf.WriteString(dep.String() + \"\\n\")\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tg.stdout.Write([]byte(colors.OK + \"=> Done!\" + colors.Reset + \"\\n\"))\n\n\treturn nil\n}\n\nfunc (g *Goop) vendorDir() string {\n\treturn path.Join(g.dir, \".vendor\")\n}\n\nfunc (g *Goop) currentRev(vcsCmd string, path string) (string, error) {\n\tswitch vcsCmd {\n\tcase \"git\":\n\t\tcmd := exec.Command(\"git\", \"rev-parse\", \"--verify\", \"HEAD\")\n\t\tcmd.Dir = path\n\t\tcmd.Stderr = g.stderr\n\t\trev, err := cmd.Output()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t} else {\n\t\t\treturn strings.TrimSpace(string(rev)), err\n\t\t}\n\tcase \"hg\":\n\t\tcmd := exec.Command(\"hg\", \"log\", \"-r\", \".\", \"--template\", \"{node}\")\n\t\tcmd.Dir = path\n\t\tcmd.Stderr = g.stderr\n\t\trev, err := cmd.Output()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t} else {\n\t\t\treturn strings.TrimSpace(string(rev)), err\n\t\t}\n\t}\n\treturn \"\", &UnsupportedVCSError{VCS: vcsCmd}\n}\n\nfunc (g *Goop) clone(vcsCmd string, url string, clonePath string) error {\n\tswitch vcsCmd {\n\tcase \"git\":\n\t\treturn g.command(\"\", \"git\", \"clone\", url, clonePath).Run()\n\tcase \"hg\":\n\t\treturn g.command(\"\", \"hg\", \"clone\", url, clonePath).Run()\n\t}\n\treturn &UnsupportedVCSError{VCS: vcsCmd}\n}\n\nfunc (g *Goop) checkout(vcsCmd string, path string, tag string) error {\n\tg.stdout.Write([]byte(\"Checking out \\\"\" + tag + \"\\\"\\n\"))\n\tswitch vcsCmd {\n\tcase \"git\":\n\t\terr := g.command(path, \"git\", \"fetch\").Run()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn g.quietCommand(path, \"git\", \"checkout\", tag).Run()\n\tcase \"hg\":\n\t\terr := g.command(path, \"hg\", \"pull\").Run()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn g.quietCommand(path, \"hg\", \"update\", tag).Run()\n\t}\n\treturn &UnsupportedVCSError{VCS: vcsCmd}\n}\n\nfunc (g *Goop) command(path string, name string, args ...string) *exec.Cmd {\n\tcmd := exec.Command(name, args...)\n\tcmd.Dir = path\n\tcmd.Stdin = g.stdin\n\tcmd.Stdout = g.stdout\n\tcmd.Stderr = g.stderr\n\treturn cmd\n}\n\nfunc (g *Goop) quietCommand(path string, name string, args ...string) *exec.Cmd {\n\tcmd := g.command(path, name, args...)\n\tcmd.Stdout = nil\n\tcmd.Stderr = nil\n\treturn cmd\n}\n\nfunc repoForDep(dep *parser.Dependency) (*vcs.RepoRoot, error) {\n\tif dep.URL != \"\" {\n\t\treturn RepoRootForImportPathWithURLOverride(dep.Pkg, dep.URL)\n\t}\n\treturn vcs.RepoRootForImportPath(dep.Pkg, true)\n}\n\n// pathExists returns:\n// * (true, nil) if path exists\n// * (false, nil) if path does not exist\n// * (false, err) if error happened during stat\nfunc pathExists(path string) (bool, error) {\n\t_, err := os.Stat(path)\n\tswitch {\n\tcase err != nil && !os.IsNotExist(err): // unexpected err\n\t\treturn false, err\n\tcase err != nil && os.IsNotExist(err):\n\t\treturn false, nil\n\tcase err == nil:\n\t\treturn true, nil\n\tdefault:\n\t\tpanic(\"never reached\")\n\t}\n}\n"
  },
  {
    "path": "goop/goop_test.go",
    "content": "package goop_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc Test(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRunSpecs(t, \"goop\")\n}\n"
  },
  {
    "path": "goop/vcs.go",
    "content": "package goop\n\nimport (\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"code.google.com/p/go.tools/go/vcs\"\n)\n\nfunc GuessVCS(url string) string {\n\tswitch {\n\tcase strings.HasPrefix(url, \"https://github.com\"):\n\t\treturn \"git\"\n\tcase strings.HasPrefix(url, \"git://\"):\n\t\treturn \"git\"\n\tcase strings.HasPrefix(url, \"git+ssh://\"):\n\t\treturn \"git\"\n\tcase strings.HasPrefix(url, \"git@\"):\n\t\treturn \"git\"\n\tcase strings.HasPrefix(url, \"ssh://hg@\"):\n\t\treturn \"hg\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc IdentifyVCS(url string) string {\n\tv := map[string][]string{\n\t\t\"git\": []string{\"git\", \"ls-remote\"},\n\t\t\"hg\":  []string{\"hg\", \"identify\"},\n\t}\n\ttryVCS := func(vcs string) bool {\n\t\tcmd := v[vcs]\n\t\tdelete(v, vcs)\n\t\treturn exec.Command(cmd[0], append(cmd[1:], url)...).Run() == nil // use vcs.VCS.Ping?\n\t}\n\tguess := GuessVCS(url)\n\tif guess != \"\" && v[guess] != nil {\n\t\tif tryVCS(guess) {\n\t\t\treturn guess\n\t\t}\n\t}\n\tfor k, _ := range v {\n\t\tif tryVCS(k) {\n\t\t\treturn k\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc RepoRootForImportPathWithURLOverride(importPath string, url string) (*vcs.RepoRoot, error) {\n\trepo, err := vcs.RepoRootForImportPathStatic(importPath, \"ignore\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\trepo.Repo = url\n\treturn repo, nil\n}\n"
  },
  {
    "path": "goop/vcs_test.go",
    "content": "package goop_test\n\nimport (\n\t\"github.com/nitrous-io/goop/goop\"\n\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar _ = Describe(\"vcs\", func() {\n\ttests := []struct {\n\t\timportPath string\n\t\turl        string\n\t\tguess      string\n\t\tactual     string\n\t\trepoRoot   string\n\t}{\n\t\t{\"github.com/dotcloud/docker/pkg/term\", \"git://github.com/dotcloud/docker.git\", \"git\", \"git\", \"github.com/dotcloud/docker\"},\n\t\t{\"github.com/mattn/go-sqlite3\", \"git://github.com/mattn/go-sqlite3.git\", \"git\", \"git\", \"github.com/mattn/go-sqlite3\"},\n\t\t{\"github.com/mattn/go-sqlite3\", \"https://github.com/mattn/go-sqlite3.git\", \"git\", \"git\", \"github.com/mattn/go-sqlite3\"},\n\t\t{\"github.com/mattn/go-sqlite3\", \"git+ssh://git@github.com/mattn/go-sqlite3.git\", \"git\", \"git\", \"github.com/mattn/go-sqlite3\"},\n\t\t{\"github.com/mattn/go-sqlite3\", \"git@github.com:mattn/go-sqlite3.git\", \"git\", \"git\", \"github.com/mattn/go-sqlite3\"},\n\t\t{\"github.com/nitrous-io/no-such\", \"git@github.com/nitrous-io/no-such\", \"git\", \"\", \"github.com/nitrous-io/no-such\"},\n\t\t{\"bitbucket.org/kardianos/osext\", \"ssh://hg@bitbucket.org/kardianos/osext\", \"hg\", \"hg\", \"bitbucket.org/kardianos/osext\"},\n\t\t{\"bitbucket.org/kardianos/osext\", \"https://bitbucket.org/kardianos/osext\", \"\", \"hg\", \"bitbucket.org/kardianos/osext\"},\n\t\t{\"bitbucket.org/ymotongpoo/go-bitarray\", \"git@bitbucket.org:ymotongpoo/go-bitarray.git\", \"git\", \"git\", \"bitbucket.org/ymotongpoo/go-bitarray\"},\n\t\t{\"bitbucket.org/ymotongpoo/go-bitarray\", \"https://bitbucket.org/ymotongpoo/go-bitarray.git\", \"\", \"git\", \"bitbucket.org/ymotongpoo/go-bitarray\"},\n\t\t{\"code.google.com/p/go.tools/go/vcs\", \"https://code.google.com/p/go.tools/\", \"\", \"hg\", \"code.google.com/p/go.tools\"},\n\t\t// not supported yet - {\"example.com/foo/go-sqlite3\", \"git@github.com:mattn/go-sqlite3.git\", \"git\", \"git\", \"example.com/foo/go-sqlite3\"},\n\t}\n\n\tDescribe(\"GuessVCS()\", func() {\n\t\tfor _, test := range tests {\n\t\t\tt := test\n\t\t\tContext(t.url, func() {\n\t\t\t\tIt(\"returns \"+t.guess, func() {\n\t\t\t\t\tExpect(goop.GuessVCS(t.url)).To(Equal(t.guess))\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t})\n\n\t// slow test: this test requires network connection\n\tXDescribe(\"IdentifyVCS()\", func() {\n\t\tfor _, test := range tests {\n\t\t\tt := test\n\t\t\tContext(t.url, func() {\n\t\t\t\tIt(\"returns \"+t.actual, func() {\n\t\t\t\t\tExpect(goop.IdentifyVCS(t.url)).To(Equal(t.actual))\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t})\n\n\tDescribe(\"RepoRootForImportPathWithURLOverride()\", func() {\n\t\tfor _, test := range tests {\n\t\t\tt := test\n\t\t\tContext(t.url, func() {\n\t\t\t\tIt(\"returns \"+t.repoRoot, func() {\n\t\t\t\t\trepo, err := goop.RepoRootForImportPathWithURLOverride(t.importPath, t.url)\n\t\t\t\t\tExpect(err).To(BeNil())\n\t\t\t\t\tExpect(repo).NotTo(BeNil())\n\t\t\t\t\tExpect(repo.Repo).To(Equal(t.url))\n\t\t\t\t\tExpect(repo.Root).To(Equal(t.repoRoot))\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t})\n})\n"
  },
  {
    "path": "main.go",
    "content": "package main\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/nitrous-io/goop/colors\"\n\t\"github.com/nitrous-io/goop/goop\"\n)\n\nfunc main() {\n\tname := path.Base(os.Args[0])\n\n\tpwd, err := os.Getwd()\n\tif err != nil {\n\t\tos.Stderr.WriteString(colors.Error + name + \": failed to determine present working directory!\" + colors.Reset + \"\\n\")\n\t}\n\n\tg := goop.NewGoop(path.Join(pwd), os.Stdin, os.Stdout, os.Stderr)\n\n\tif len(os.Args) < 2 {\n\t\tprintUsage()\n\t}\n\n\tcmd := os.Args[1]\n\tswitch cmd {\n\tcase \"help\":\n\t\tprintUsage()\n\tcase \"install\":\n\t\terr = g.Install()\n\tcase \"update\":\n\t\terr = g.Update()\n\tcase \"exec\":\n\t\tif len(os.Args) < 3 {\n\t\t\tprintUsage()\n\t\t}\n\t\terr = g.Exec(os.Args[2], os.Args[3:]...)\n\tcase \"go\":\n\t\tif len(os.Args) < 3 {\n\t\t\tprintUsage()\n\t\t}\n\t\terr = g.Exec(\"go\", os.Args[2:]...)\n\tcase \"env\":\n\t\tg.PrintEnv()\n\tdefault:\n\t\terr = errors.New(`unrecognized command \"` + cmd + `\"`)\n\t}\n\n\tif err != nil {\n\t\terrMsg := err.Error()\n\t\tcode := 1\n\n\t\t// go does not provide a cross-platform way to get exit status, so inspect error message instead\n\t\t// https://code.google.com/p/go/source/browse/src/pkg/os/exec_posix.go#119\n\t\tif strings.HasPrefix(errMsg, \"exit status \") {\n\t\t\tcode, err = strconv.Atoi(errMsg[len(\"exit status \"):])\n\t\t\tif err != nil {\n\t\t\t\tcode = 1\n\t\t\t}\n\t\t\terrMsg = \"Command failed with \" + errMsg\n\t\t}\n\n\t\tos.Stderr.WriteString(colors.Error + name + \": \" + errMsg + colors.Reset + \"\\n\")\n\t\tos.Exit(code)\n\t}\n}\n\nfunc printUsage() {\n\tos.Stdout.WriteString(strings.TrimSpace(usage) + \"\\n\\n\")\n\tos.Exit(0)\n}\n\nconst usage = `\nGoop is a tool for managing Go dependencies.\n\n        goop command [arguments]\n\nThe commands are:\n\n    install     install the dependencies specified by Goopfile or Goopfile.lock\n    update      update dependencies to their latest versions\n    env         print GOPATH and PATH environment variables, with the vendor path prepended\n    exec        execute a command in the context of the installed dependencies\n    go          execute a go command in the context of the installed dependencies\n    help        print this message\n`\n"
  },
  {
    "path": "parser/dependency.go",
    "content": "package parser\n\nimport \"strings\"\n\ntype Dependency struct {\n\tPkg string\n\tRev string\n\tURL string\n}\n\nfunc (d *Dependency) String() string {\n\ts := make([]string, 0, 3)\n\ts = append(s, d.Pkg)\n\tif d.Rev != \"\" {\n\t\ts = append(s, \"#\"+d.Rev)\n\t}\n\tif d.URL != \"\" {\n\t\ts = append(s, \"!\"+d.URL)\n\t}\n\treturn strings.Join(s, \" \")\n}\n"
  },
  {
    "path": "parser/parser.go",
    "content": "package parser\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n)\n\ntype ParseError struct {\n\tLineNum  uint\n\tLineText string\n\tMessage  string\n}\n\nconst (\n\tCommentOrPackage = iota\n\tURLOr\n)\n\nconst (\n\tTokenComment = \"//\"\n\tTokenRev     = \"#\"\n\tTokenURL     = \"!\"\n)\n\nfunc (e *ParseError) Error() string {\n\treturn fmt.Sprintf(\"Parse failed at line %d - %s\\n  %s\", e.LineNum, e.LineText, e.Message)\n}\n\nfunc Parse(r io.Reader) ([]*Dependency, error) {\n\ts := bufio.NewScanner(r)\n\tln := uint(0)\n\tdeps := []*Dependency{}\n\n\tfor s.Scan() {\n\t\tln++\n\t\tline := strings.TrimSpace(s.Text())\n\t\ttokens := strings.Fields(line)\n\n\t\tif line == \"\" || strings.HasPrefix(tokens[0], TokenComment) {\n\t\t\tcontinue\n\t\t}\n\n\t\tdep := &Dependency{Pkg: tokens[0]}\n\t\tparseErr := &ParseError{LineNum: ln, LineText: line}\n\n\t\tfor _, t := range tokens[1:] {\n\t\t\tif strings.HasPrefix(t, TokenComment) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tswitch {\n\t\t\tcase strings.HasPrefix(t, TokenRev):\n\t\t\t\tif dep.Rev != \"\" {\n\t\t\t\t\tparseErr.Message = \"Multiple revisions given\"\n\t\t\t\t\treturn nil, parseErr\n\t\t\t\t}\n\t\t\t\tdep.Rev = t[1:]\n\t\t\tcase strings.HasPrefix(t, TokenURL):\n\t\t\t\tif dep.URL != \"\" {\n\t\t\t\t\tparseErr.Message = \"Multiple URLs given\"\n\t\t\t\t\treturn nil, parseErr\n\t\t\t\t}\n\t\t\t\tdep.URL = t[1:]\n\t\t\tdefault:\n\t\t\t\tparseErr.Message = \"Unrecognized token given\"\n\t\t\t\treturn nil, parseErr\n\t\t\t}\n\t\t}\n\t\tdeps = append(deps, dep)\n\t}\n\n\tif err := s.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn deps, nil\n}\n"
  },
  {
    "path": "parser/parser_test.go",
    "content": "package parser_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/nitrous-io/goop/parser\"\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc Test(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRunSpecs(t, \"parser\")\n}\n\nvar _ = Describe(\"parser\", func() {\n\tDescribe(\"Parse()\", func() {\n\t\tvar (\n\t\t\tdeps []*parser.Dependency\n\t\t\terr  error\n\t\t)\n\n\t\tContext(\"empty Goopfile\", func() {\n\t\t\tBeforeEach(func() {\n\t\t\t\tdeps, err = parser.Parse(bytes.NewBufferString(\"\"))\n\t\t\t})\n\n\t\t\tIt(\"returns an empty slice\", func() {\n\t\t\t\tExpect(err).To(BeNil())\n\t\t\t\tExpect(deps).NotTo(BeNil())\n\t\t\t\tExpect(deps).To(HaveLen(0))\n\t\t\t})\n\t\t})\n\n\t\tContext(\"one entry\", func() {\n\t\t\tContext(\"with no revision specified\", func() {\n\t\t\t\tBeforeEach(func() {\n\t\t\t\t\tdeps, err = parser.Parse(bytes.NewBufferString(`\n\t\t\t\t\t\tgithub.com/nitrous-io/goop\n\t\t\t\t\t`))\n\t\t\t\t})\n\n\t\t\t\tIt(\"parses and returns a slice containing one dependency item\", func() {\n\t\t\t\t\tExpect(err).To(BeNil())\n\t\t\t\t\tExpect(deps).To(HaveLen(1))\n\t\t\t\t\tExpect(deps[0]).To(Equal(&parser.Dependency{Pkg: \"github.com/nitrous-io/goop\", Rev: \"\"}))\n\t\t\t\t})\n\t\t\t})\n\n\t\t\tContext(\"with revision specified\", func() {\n\t\t\t\tIt(\"parses and returns a slice containing one dependency item\", func() {\n\t\t\t\t\tdeps, err = parser.Parse(bytes.NewBufferString(`\n\t\t\t\t\t\tgithub.com/nitrous-io/goop #09f0feb1b103933bd9985f0a85e01eeaad8d75c8\n\t\t\t\t\t`))\n\t\t\t\t\tExpect(err).To(BeNil())\n\t\t\t\t\tExpect(deps).To(HaveLen(1))\n\t\t\t\t\tExpect(deps[0]).To(Equal(&parser.Dependency{\n\t\t\t\t\t\tPkg: \"github.com/nitrous-io/goop\",\n\t\t\t\t\t\tRev: \"09f0feb1b103933bd9985f0a85e01eeaad8d75c8\",\n\t\t\t\t\t}))\n\t\t\t\t})\n\n\t\t\t\tIt(\"ignores whitespace\", func() {\n\t\t\t\t\tdeps, err = parser.Parse(bytes.NewBufferString(`\n\t\t\t\t\t\tgithub.com/nitrous-io/goop      #09f0feb1b103933bd9985f0a85e01eeaad8d75c8\n\t\t\t\t\t`))\n\t\t\t\t\tExpect(err).To(BeNil())\n\t\t\t\t\tExpect(deps).To(HaveLen(1))\n\t\t\t\t\tExpect(deps[0]).To(Equal(&parser.Dependency{\n\t\t\t\t\t\tPkg: \"github.com/nitrous-io/goop\",\n\t\t\t\t\t\tRev: \"09f0feb1b103933bd9985f0a85e01eeaad8d75c8\",\n\t\t\t\t\t}))\n\t\t\t\t})\n\t\t\t})\n\n\t\t\tContext(\"with custom repo url\", func() {\n\t\t\t\tBeforeEach(func() {\n\t\t\t\t\tdeps, err = parser.Parse(bytes.NewBufferString(`\n\t\t\t\t\t\tgithub.com/nitrous-io/goop !git@github.com:foo/goop\n\t\t\t\t\t`))\n\t\t\t\t})\n\n\t\t\t\tIt(\"parses and returns a slice containing one dependency item\", func() {\n\t\t\t\t\tExpect(err).To(BeNil())\n\t\t\t\t\tExpect(deps).To(HaveLen(1))\n\t\t\t\t\tExpect(deps[0]).To(Equal(&parser.Dependency{\n\t\t\t\t\t\tPkg: \"github.com/nitrous-io/goop\",\n\t\t\t\t\t\tURL: \"git@github.com:foo/goop\",\n\t\t\t\t\t}))\n\t\t\t\t})\n\t\t\t})\n\n\t\t\tContext(\"with a comment\", func() {\n\t\t\t\tBeforeEach(func() {\n\t\t\t\t\tdeps, err = parser.Parse(bytes.NewBufferString(`\n\t\t\t\t\t\tgithub.com/nitrous-io/goop // hello world\n\t\t\t\t\t`))\n\t\t\t\t})\n\t\t\t})\n\n\t\t\tContext(\"with unparseable garbage\", func() {\n\t\t\t\tBeforeEach(func() {\n\t\t\t\t\tdeps, err = parser.Parse(bytes.NewBufferString(`\n\t\t\t\t\t\tgithub.com/nitrous-io/goop (*@#&!@(*#)@$F@sdgu8$!\n\t\t\t\t\t`))\n\t\t\t\t})\n\n\t\t\t\tIt(\"fails and returns parse error\", func() {\n\t\t\t\t\tExpect(err).NotTo(BeNil())\n\t\t\t\t\tExpect(deps).To(BeNil())\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\n\t\tContext(\"multiple entries\", func() {\n\t\t\tBeforeEach(func() {\n\t\t\t\tdeps, err = parser.Parse(bytes.NewBufferString(`\n\t\t\t\t\tgithub.com/nitrous-io/goop #09f0feb1b103933bd9985f0a85e01eeaad8d75c8\n\n\t\t\t\t\tgithub.com/gorilla/mux\n\t\t\t\t\t  github.com/gorilla/context #14f550f51af52180c2eefed15e5fd18d63c0a64a // future versions don't work\n\t\t\t\t\tgithub.com/foo/bar #ffffffffffffffffffffffffffffffffffffffff !git@github.com:baz/bar\n\n\t\t\t\t\t// don't upgrade this to 1.0.4\n\t\t\t\t\tgithub.com/hello/world !git@github.com:bye/world #v1.0.3 // I REPEAT, DON'T!\n\t\t\t\t`))\n\t\t\t})\n\n\t\t\tIt(\"parses and returns a slice containing multiple dependency items\", func() {\n\t\t\t\tExpect(err).To(BeNil())\n\t\t\t\tExpect(deps).To(HaveLen(5))\n\t\t\t\tExpect(deps[0]).To(Equal(&parser.Dependency{\n\t\t\t\t\tPkg: \"github.com/nitrous-io/goop\",\n\t\t\t\t\tRev: \"09f0feb1b103933bd9985f0a85e01eeaad8d75c8\",\n\t\t\t\t}))\n\t\t\t\tExpect(deps[1]).To(Equal(&parser.Dependency{\n\t\t\t\t\tPkg: \"github.com/gorilla/mux\",\n\t\t\t\t\tRev: \"\",\n\t\t\t\t}))\n\t\t\t\tExpect(deps[2]).To(Equal(&parser.Dependency{\n\t\t\t\t\tPkg: \"github.com/gorilla/context\",\n\t\t\t\t\tRev: \"14f550f51af52180c2eefed15e5fd18d63c0a64a\",\n\t\t\t\t}))\n\t\t\t\tExpect(deps[3]).To(Equal(&parser.Dependency{\n\t\t\t\t\tPkg: \"github.com/foo/bar\",\n\t\t\t\t\tRev: \"ffffffffffffffffffffffffffffffffffffffff\",\n\t\t\t\t\tURL: \"git@github.com:baz/bar\",\n\t\t\t\t}))\n\t\t\t\tExpect(deps[4]).To(Equal(&parser.Dependency{\n\t\t\t\t\tPkg: \"github.com/hello/world\",\n\t\t\t\t\tRev: \"v1.0.3\",\n\t\t\t\t\tURL: \"git@github.com:bye/world\",\n\t\t\t\t}))\n\t\t\t})\n\t\t})\n\t})\n})\n"
  },
  {
    "path": "pkg/env/env.go",
    "content": "package env\n\nimport (\n\t\"bytes\"\n\t\"os\"\n)\n\ntype Env map[string]string\n\nfunc NewEnv() Env {\n\te := Env{}\n\tosenv := os.Environ()\n\n\tfor _, l := range osenv {\n\t\tkv := bytes.SplitN([]byte(l), []byte(\"=\"), 2)\n\t\tk := string(kv[0])\n\t\tif len(kv) == 2 {\n\t\t\te[k] = string(kv[1])\n\t\t} else {\n\t\t\te[k] = \"\"\n\t\t}\n\t}\n\n\treturn e\n}\n\nfunc (e Env) Strings() []string {\n\ts := make([]string, 0, len(e))\n\tfor k, v := range e {\n\t\ts = append(s, k+\"=\"+v)\n\t}\n\treturn s\n}\n\nfunc (e Env) Prepend(key string, val string) {\n\toldv := e[key]\n\tif oldv == \"\" {\n\t\te[key] = val\n\t\treturn\n\t}\n\te[key] = val + \":\" + oldv\n}\n"
  },
  {
    "path": "pkg/env/env_test.go",
    "content": "package env_test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/nitrous-io/goop/pkg/env\"\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nfunc Test(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRunSpecs(t, \"env\")\n}\n\nvar _ = Describe(\"env\", func() {\n\tvar e env.Env\n\n\tBeforeEach(func() {\n\t\tos.Setenv(\"_GOOP_ENV_TEST_FOO\", \"foo\")\n\t\tos.Setenv(\"_GOOP_ENV_TEST_BAR\", \"bar=bar bar\")\n\t\tos.Setenv(\"_GOOP_ENV_TEST_EMPTY\", \"\")\n\n\t\te = env.NewEnv()\n\t})\n\n\tAfterEach(func() {\n\t\tos.Setenv(\"_GOOP_ENV_TEST_FOO\", \"\")\n\t\tos.Setenv(\"_GOOP_ENV_TEST_BAR\", \"\")\n\t\tos.Setenv(\"_GOOP_ENV_TEST_EMPTY\", \"\")\n\t})\n\n\tDescribe(\"NewEnv()\", func() {\n\t\tIt(\"returns a new env map using current env vars\", func() {\n\t\t\tExpect(e[\"_GOOP_ENV_TEST_FOO\"]).To(Equal(\"foo\"))\n\t\t\tExpect(e[\"_GOOP_ENV_TEST_BAR\"]).To(Equal(\"bar=bar bar\"))\n\t\t\tExpect(e[\"_GOOP_ENV_TEST_EMPTY\"]).To(BeEmpty())\n\t\t})\n\t})\n\n\tDescribe(\"Strings()\", func() {\n\t\tIt(\"returns a copy of strings representing the env, in the form key=value\", func() {\n\t\t\ts := e.Strings()\n\t\t\tExpect(s).To(ContainElement(\"_GOOP_ENV_TEST_FOO=foo\"))\n\t\t\tExpect(s).To(ContainElement(\"_GOOP_ENV_TEST_BAR=bar=bar bar\"))\n\t\t\tExpect(s).To(ContainElement(\"_GOOP_ENV_TEST_EMPTY=\"))\n\t\t})\n\t})\n\n\tDescribe(\"Prepend()\", func() {\n\t\tContext(\"when a given key has a value\", func() {\n\t\t\tIt(\"prepends new value to the existing value\", func() {\n\t\t\t\te.Prepend(\"_GOOP_ENV_TEST_FOO\", \"lol\")\n\t\t\t\tExpect(e[\"_GOOP_ENV_TEST_FOO\"]).To(Equal(\"lol:foo\"))\n\t\t\t\te.Prepend(\"_GOOP_ENV_TEST_FOO\", \"hello\")\n\t\t\t\tExpect(e[\"_GOOP_ENV_TEST_FOO\"]).To(Equal(\"hello:lol:foo\"))\n\t\t\t})\n\t\t})\n\n\t\tContext(\"when a given key is empty\", func() {\n\t\t\tIt(\"sets new value\", func() {\n\t\t\t\te.Prepend(\"_GOOP_ENV_TEST_EMPTY\", \"foo\")\n\t\t\t\tExpect(e[\"_GOOP_ENV_TEST_EMPTY\"]).To(Equal(\"foo\"))\n\t\t\t\te.Prepend(\"_GOOP_ENV_TEST_EMPTY\", \"lol\")\n\t\t\t\tExpect(e[\"_GOOP_ENV_TEST_EMPTY\"]).To(Equal(\"lol:foo\"))\n\t\t\t})\n\t\t})\n\n\t\tContext(\"when a given key does not exist\", func() {\n\t\t\tBeforeEach(func() {\n\t\t\t\tdelete(e, \"_GOOP_ENV_TEST_EMPTY\")\n\t\t\t})\n\n\t\t\tIt(\"sets new value\", func() {\n\t\t\t\te.Prepend(\"_GOOP_ENV_TEST_EMPTY\", \"foo\")\n\t\t\t\tExpect(e[\"_GOOP_ENV_TEST_EMPTY\"]).To(Equal(\"foo\"))\n\t\t\t\te.Prepend(\"_GOOP_ENV_TEST_EMPTY\", \"lol\")\n\t\t\t\tExpect(e[\"_GOOP_ENV_TEST_EMPTY\"]).To(Equal(\"lol:foo\"))\n\t\t\t})\n\t\t})\n\t})\n})\n"
  }
]