// Atomic deploy by symlink // 1. rsync maindir => backupdir // 2. mv -T backuplink destdir // 3. rsync srcdir => maindir // 4. mv -T mainlink destdir func DeployWithSymlink(srcDir, destDir string) error { mainLink := destDir + ".drootmain" backupLink := destDir + ".drootbackup" mainDir := destDir + ".d/main" backupDir := destDir + ".d/backup" for _, dir := range []string{mainDir, backupDir} { if err := fileutils.CreateIfNotExists(dir, true); err != nil { // mkdir -p return fmt.Errorf("Failed to create directory %s: %s", dir, err) } } // Return error if the working directory that droot internally uses exists for _, link := range []string{mainLink, backupLink, destDir} { if !osutil.IsSymlink(link) && (osutil.ExistsFile(link) || osutil.ExistsDir(link)) { return fmt.Errorf("%s already exists. Please use another directory as --dest option or delete %s", link, link) } } if err := osutil.Symlink(mainDir, mainLink); err != nil { return fmt.Errorf("Failed to create symlink %s: %s", mainLink, err) } if err := osutil.Symlink(backupDir, backupLink); err != nil { return fmt.Errorf("Failed to create symlink %s: %s", backupLink, err) } log.Info("-->", "Syncing", "from", mainDir, "to", backupDir) if err := Rsync(mainDir, backupDir); err != nil { return fmt.Errorf("Failed to rsync: %s", err) } log.Info("-->", "Renaming", "from", backupLink, "to", destDir) if err := os.Rename(backupLink, destDir); err != nil { return fmt.Errorf("Failed to rename %s: %s", destDir, err) } log.Info("-->", "Syncing", "from", srcDir, "to", mainDir) if err := Rsync(srcDir, mainDir); err != nil { return fmt.Errorf("Failed to rsync: %s", err) } log.Info("-->", "Renaming", "from", mainLink, "to", destDir) if err := os.Rename(mainLink, destDir); err != nil { return fmt.Errorf("Failed to rename %s: %s", destDir, err) } return nil }
func ResolveRootDir(dir string) (string, error) { var err error if !osutil.ExistsDir(dir) { return dir, fmt.Errorf("No such directory %s:", dir) } dir, err = fp.Abs(dir) if err != nil { return dir, err } if osutil.IsSymlink(dir) { dir, err = os.Readlink(dir) if err != nil { return dir, err } } return fp.Clean(dir), nil }
func doRm(c *cli.Context) error { optRootDir := c.String("root") if optRootDir == "" { cli.ShowCommandHelp(c, "run") return errors.New("--root option required") } rootDir, err := mounter.ResolveRootDir(optRootDir) if err != nil { return err } mnt := mounter.NewMounter(rootDir) if err := mnt.UmountRoot(); err != nil { return err } if osutil.IsSymlink(optRootDir) { return deploy.CleanupSymlink(optRootDir) } log.Info("-->", "Removing", rootDir) return osutil.RunCmd("rm", "-fr", rootDir) }