func (a *ACBuild) lock() error { ex, err := util.Exists(a.ContextPath) if err != nil { return err } if !ex { return fmt.Errorf("build not in progress in this working dir - try \"acbuild begin\"") } if a.lockFile != nil { return fmt.Errorf("lock already held by this ACBuild") } a.lockFile, err = os.OpenFile(a.LockPath, os.O_CREATE|os.O_RDWR, 0644) if err != nil { return err } err = syscall.Flock(int(a.lockFile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) if err != nil { if err == syscall.EWOULDBLOCK { return fmt.Errorf("lock already held - is another acbuild running in this working dir?") } return err } return nil }
func runBegin(cmd *cobra.Command, args []string) (exit int) { if len(args) > 1 { stderr("begin: incorrect number of arguments") return 1 } ex, err := util.Exists(path.Join(contextpath, workprefix)) if err != nil { stderr("begin: %v", err) return 1 } if ex { stderr("begin: build already in progress in this working dir") return 1 } err = os.MkdirAll(path.Join(contextpath, workprefix), 0755) if err != nil { stderr("begin: %v", err) return 1 } lockfile, err := getLock() if err != nil { stderr("begin: %v", err) return 1 } defer func() { if err := releaseLock(lockfile); err != nil { stderr("begin: %v", err) exit = 1 } }() if debug { if len(args) == 0 { stderr("Beginning build with an empty ACI") } else { stderr("Beginning build with %s", args[0]) } } if len(args) == 0 { err = lib.Begin(tmpacipath(), "") } else { err = lib.Begin(tmpacipath(), args[0]) } if err != nil { stderr("begin: %v", err) return 1 } return 0 }
func findCmdInPath(pathlist []string, cmd, prefix string) (string, error) { if len(cmd) != 0 && cmd[0] == '/' { return cmd, nil } for _, p := range pathlist { ex, err := util.Exists(path.Join(prefix, p, cmd)) if err != nil { return "", err } if ex { return path.Join(p, cmd), nil } } return "", fmt.Errorf("%s not found in any of: %v", cmd, pathlist) }
// Abort will abort the current build, given the path that the build resources // are stored at. An error will be returned if no build is in progress. func Abort(contextpath string) error { ok, err := util.Exists(contextpath) if err != nil { return err } if !ok { return fmt.Errorf("build not in progress") } err = os.RemoveAll(contextpath) if err != nil { return err } return nil }
// FetchAndRender will fetch the given image and all of its dependencies if // they have not been fetched yet, and will then render them on to the // filesystem if they have not been rendered yet. func (r Registry) FetchAndRender(imagename types.ACIdentifier, labels types.Labels, size uint) error { _, err := r.GetACI(imagename, labels) if err == ErrNotFound { err := r.fetchACIWithSize(imagename, labels, size) if err != nil { return err } } filesToRender, err := acirenderer.GetRenderedACI(imagename, labels, r) if err != nil { return err } for _, fs := range filesToRender { ex, err := util.Exists(path.Join(r.Scratchpath, fs.Key, "rendered")) if err != nil { return err } if ex { //This ACI has already been rendered continue } err = util.UnTar(path.Join(r.Depstore, fs.Key), path.Join(r.Scratchpath, fs.Key), fs.FileMap) if err != nil { return err } rfile, err := os.Create(path.Join(r.Scratchpath, fs.Key, "rendered")) if err != nil { return err } rfile.Close() } return nil }
// FetchAndRender will fetch the given image and all of its dependencies if // they have not been fetched yet, and will then render them on to the // filesystem if they have not been rendered yet. func (r Registry) FetchAndRender(imagename types.ACIdentifier, labels types.Labels, size uint) error { err := r.Fetch(imagename, labels, size, true) if err != nil { return err } filesToRender, err := acirenderer.GetRenderedACI(imagename, labels, r) if err != nil { return err } for _, fs := range filesToRender { ex, err := util.Exists( path.Join(r.DepStoreExpandedPath, fs.Key, "rendered")) if err != nil { return err } if ex { //This ACI has already been rendered continue } err = util.ExtractImage(path.Join(r.DepStoreTarPath, fs.Key), path.Join(r.DepStoreExpandedPath, fs.Key), fs.FileMap) if err != nil { return err } rfile, err := os.Create( path.Join(r.DepStoreExpandedPath, fs.Key, "rendered")) if err != nil { return err } rfile.Close() } return nil }
func getLock() (*os.File, error) { ex, err := util.Exists(path.Join(contextpath, workprefix)) if err != nil { return nil, err } if !ex { return nil, fmt.Errorf("build not in progress in this working dir - try \"acbuild begin\"") } lockfile, err := os.OpenFile(lockpath(), os.O_CREATE|os.O_RDWR, 0644) if err != nil { return nil, err } err = syscall.Flock(int(lockfile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) if err != nil { if err == syscall.EWOULDBLOCK { return nil, fmt.Errorf("lock already held - is another acbuild running in this working dir?") } return nil, err } return lockfile, nil }
// Write will produce the resulting ACI from the current build context, saving // it to the given path, optionally signing it. func (a *ACBuild) Write(output string, overwrite, sign bool, gpgflags []string) (err error) { if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() man, err := util.GetManifest(a.CurrentACIPath) if err != nil { return err } if man.App != nil && len(man.App.Exec) == 0 { fmt.Fprintf(os.Stderr, "warning: exec command was never set.\n") } if man.Name == types.ACIdentifier(placeholdername) { return fmt.Errorf("can't write ACI, name was never set") } fileFlags := os.O_CREATE | os.O_WRONLY ex, err := util.Exists(output) if err != nil { return err } if ex { if !overwrite { return fmt.Errorf("ACI already exists: %s", output) } fileFlags |= os.O_TRUNC } // open/create the aci file ofile, err := os.OpenFile(output, fileFlags, 0644) if err != nil { return err } defer ofile.Close() // setup compression gzwriter := gzip.NewWriter(ofile) defer gzwriter.Close() // create the aci writer aw := aci.NewImageWriter(*man, tar.NewWriter(gzwriter)) err = filepath.Walk(a.CurrentACIPath, aci.BuildWalker(a.CurrentACIPath, aw, nil)) defer aw.Close() if err != nil { return err } if sign { err = signACI(output, output+".asc", gpgflags) if err != nil { os.Remove(output) os.Remove(output + ".asc") return err } } return nil }
// Begin will start a new build, storing the untarred ACI the build operates on // at a.CurrentACIPath. If start is the empty string, the build will begin with // an empty ACI, otherwise the ACI stored at start will be used at the starting // point. func (a *ACBuild) Begin(start string, insecure bool) (err error) { ex, err := util.Exists(a.ContextPath) if err != nil { return err } if ex { return fmt.Errorf("build already in progress in this working dir") } err = os.MkdirAll(a.ContextPath, 0755) if err != nil { return err } if err = a.lock(); err != nil { return err } defer func() { if err1 := a.unlock(); err == nil { err = err1 } }() if start != "" { err = os.MkdirAll(a.CurrentACIPath, 0755) if err != nil { return err } return a.beginFromImage(start, insecure) } err = os.MkdirAll(path.Join(a.CurrentACIPath, aci.RootfsDir), 0755) if err != nil { return err } acid, err := types.NewACIdentifier("acbuild-unnamed") if err != nil { return err } manifest := &schema.ImageManifest{ ACKind: schema.ImageManifestKind, ACVersion: schema.AppContainerVersion, Name: *acid, App: &types.App{ Exec: nil, User: "******", Group: "0", }, } manblob, err := manifest.MarshalJSON() if err != nil { return err } manfile, err := os.Create(path.Join(a.CurrentACIPath, aci.ManifestFile)) if err != nil { return err } _, err = manfile.Write(manblob) if err != nil { return err } err = manfile.Close() if err != nil { return err } return nil }
// Begin will start a new build, storing the untarred ACI the build operates on // at tmpaci. If start is the empty string, the build will begin with an empty // ACI, otherwise the ACI stored at start will be used at the starting point. func Begin(tmpaci, start string) error { ex, err := util.Exists(tmpaci) if err != nil { return err } if ex { return fmt.Errorf("build already in progress? path exists: %s", tmpaci) } err = os.MkdirAll(path.Join(tmpaci, aci.RootfsDir), 0755) if err != nil { return err } if start != "" { ex, err := util.Exists(start) if err != nil { return err } if !ex { return fmt.Errorf("start aci doesn't exist: %s", start) } err = util.UnTar(start, tmpaci, nil) if err != nil { return err } return nil } acid, err := types.NewACIdentifier("acbuild-unnamed") if err != nil { return err } manifest := &schema.ImageManifest{ ACKind: schema.ImageManifestKind, ACVersion: schema.AppContainerVersion, Name: *acid, App: &types.App{ Exec: placeholderexec, User: "******", Group: "0", }, } manblob, err := manifest.MarshalJSON() if err != nil { return err } manfile, err := os.Create(path.Join(tmpaci, aci.ManifestFile)) if err != nil { return err } _, err = manfile.Write(manblob) if err != nil { return err } err = manfile.Close() if err != nil { return err } return nil }