Beispiel #1
0
func Shell() {
	sighup := autorestart.NotifyOnSighup()
	args, err := flags.ParseArgs(&Opts, os.Args[1:])
	if err != nil {
		err2, ok := err.(*flags.Error)
		if ok && err2.Type == flags.ErrHelp {
			return
		}
		alog.Printf("Error parsing command-line options: %s\n", err)
		return
	}
	if Opts.NoColor {
		alog.DisableColor()
	}
	ignorePart = stringset.New(filepath.SplitList(Opts.IgnorePart)...)
	ignoreSuffix = filepath.SplitList(Opts.IgnoreSuffix)
	ignoreSubstring = filepath.SplitList(Opts.IgnoreSubstring)
	deletePart = stringset.New(filepath.SplitList(Opts.DeletePart)...)
	deleteSuffix = filepath.SplitList(Opts.DeleteSuffix)
	deleteSubstring = filepath.SplitList(Opts.DeleteSubstring)
	if Opts.Child {
		if len(args) < 1 {
			alog.Fatalln("Not enough arguments, need 1")
		}
		RootPath = args[0]
		execChild()
		return
	}

	if len(args) < 2 {
		alog.Fatalln("Not enough arguments, need 2")
	}
	RootPath = args[0]
	remoteFullPath := args[1]
	remoteFullPathParts := strings.SplitN(remoteFullPath, ":", 2)
	remoteHost, remoteRoot := remoteFullPathParts[0], remoteFullPathParts[1]
	alog.Printf("@(dim:nsync started, syncing) @(cyan:%s) @(dim:to) @(cyan:%s)@(dim::)@(cyan:%s)\n", RootPath, remoteHost, remoteRoot)
	onChildExit := make(chan error)
	go connectChildForever(remoteHost, remoteRoot, onChildExit)
	go execParent()
	select {
	case <-sighup:
		killChildSshProcess()
	case <-onChildExit:
		// Restart everything if the child drops out (this is kludgy but effective)
	case <-time.After(20 * time.Minute):
		// Restart periodically, at least until I figure out what causes hangs
	}
}
Beispiel #2
0
func main() {
	log.EnableColorTemplate()
	log.AddAnsiColorCode("error", 31)
	log.AddAnsiColorCode("commit", 32)
	log.AddAnsiColorCode("path", 36)
	var args []string = os.Args[1:]
	if len(args) == 0 {
		fmt.Println("You must specify a gut-command, e.g. `gut sync ...`")
		os.Exit(1)
	}
	var cmd = args[0]
	if IsGitCommand(cmd) {
		if IsDangerousGitCommand(cmd) {
			if len(args) < 2 || args[1] != "--danger" {
				status := log.New(os.Stderr, "", 0)
				status.Printf("@(dim:In order to prevent damage caused by accidentally using `)gut %s ...@(dim:`)\n", cmd)
				status.Printf("@(dim:in cases where `)git %s ...@(dim:` was intended, you must append `)--danger@(dim:`)\n", cmd)
				status.Printf("@(dim:immediately after the command, i.e. `)gut %s --danger ...@(dim:`.)\n", cmd)
				status.Printf("@(dim:Alternatively, you could invoke) gut @(dim:directly at) @(path:%s)@(dim:.)\n", GutExePath)
				status.Printf("@(dim:The commands that require this flag are:) %s\n", strings.Join(DangerousGitCommands, " "))
				os.Exit(1)
			}
			// Split the "--danger" flag out before handing off the args list to the gut-command:
			if len(args) > 2 {
				args = append(args[:1], args[2:]...)
			} else {
				args = args[:1]
			}
		}
		homeDir, err := homedir.Dir()
		if err != nil {
			log.Bail(err)
		}
		var gutExe = path.Join(homeDir, GutExePath[2:])
		syscall.Exec(gutExe, append([]string{gutExe}, args...), os.Environ())
		fmt.Printf("Failed to exec %s", gutExe)
		os.Exit(1)
	}
	autorestart.CleanUpChildZombiesQuietly()
	go autorestart.RestartOnChange()
	status := log.New(os.Stderr, "", 0)
	args = args[1:]
	parser := flags.NewParser(&OptsCommon, flags.IgnoreUnknown)
	var argsRemaining, err = parser.ParseArgs(args)
	if err != nil {
		printUsageInfoAndExit()
	}
	if OptsCommon.NoColor {
		log.DisableColor()
	}
	if OptsCommon.Version {
		status.Printf("gut-sync %s\n", GutVersion)
		os.Exit(0)
	}
	bismuth.SetVerbose(OptsCommon.Verbose)

	go func() {
		sigintChan := make(chan os.Signal, 1)
		signal.Notify(sigintChan, os.Interrupt)
		<-sigintChan
		Shutdown("Received SIGINT.", 1)
	}()
	go func() {
		sighupChan := autorestart.NotifyOnSighup()
		<-sighupChan
		Shutdown("Received SIGHUP.", 0)
	}()

	if cmd == "build" {
		var local = NewSyncContext()
		err := local.Connect()
		if err != nil {
			status.Bail(err)
		}
		err = local.CheckLocalDeps()
		if err != nil {
			status.Bail(err)
		}
		didSomething, err := EnsureBuild(local, local)
		if err != nil {
			status.Bail(err)
		}
		if !didSomething {
			status.Printf("@(dim:gut) " + GitVersion + " @(dim:has already been built.)\n")
		}
	} else if cmd == "sync" {
		var remoteArgs, err = flags.ParseArgs(&OptsSync, argsRemaining)
		if err != nil {
			printUsageInfoAndExit()
		}

		ready := make(chan error)

		local := NewSyncContext()
		err = local.ParseSyncPath(OptsSync.Positional.LocalPath)
		if err != nil {
			status.Bail(err)
		}
		if len(remoteArgs) > 0 && os.Getenv("SSH_AUTH_SOCK") == "" {
			log.Printf("@(error:SSH_AUTH_SOCK is not set in environment. Start up an ssh agent first before running gut-sync.)\n")
			Shutdown("", 1)
		}
		go func() {
			err = local.Connect()
			if err != nil {
				status.Bail(err)
			}
			err = local.CheckLocalDeps()
			if err != nil {
				status.Bail(err)
			}
			local.KillAllViaPidfiles()
			local.SaveDaemonPid("gut", os.Getpid())
			ready <- nil
		}()

		remotes := []*SyncContext{}
		for _, remotePath := range remoteArgs {
			remote := NewSyncContext()
			remotes = append(remotes, remote)
			err = remote.ParseSyncPath(remotePath)
			if err != nil {
				status.Bail(err)
			}
			go func(_remote *SyncContext) {
				err = _remote.Connect()
				if err != nil {
					status.Printf("@(error:Failed to connect to %s: %s)\n", remote.Hostname(), err)
					Shutdown("", 1)
				}
				_remote.KillAllViaPidfiles()
				err = _remote.CheckRemoteDeps()
				if err != nil {
					status.Bail(err)
				}
				ready <- nil
			}(remote)
		}

		for i := 0; i < len(remotes)+1; i++ {
			<-ready
		}

		err = Sync(local, remotes)
		if err != nil {
			status.Bail(err)
		}
	}
}
Beispiel #3
0
func main() {
	sighup := autorestart.NotifyOnSighup()
	_, err := flags.ParseArgs(&Opts, os.Args)
	if err != nil {
		err2, ok := err.(*flags.Error)
		if ok && err2.Type == flags.ErrHelp {
			return
		}
		alog.Printf("Error parsing command-line options: %s\n", err)
		return
	}
	if goPath == "" {
		alog.Printf("GOPATH is not set in the environment. Please set GOPATH first, then retry.\n")
		alog.Printf("For help setting GOPATH, see https://golang.org/doc/code.html\n")
		return
	}
	if Opts.NoColor {
		alog.DisableColor()
	} else {
		alog.AddAnsiColorCode("time", alog.ColorBlue)
	}
	alog.Printf("@(dim:autoinstall started.)\n")
	if Opts.MaxWorkers == 0 {
		Opts.MaxWorkers = runtime.GOMAXPROCS(0)
	}
	pluralProcess := ""
	if Opts.MaxWorkers != 1 {
		pluralProcess = "es"
	}
	alog.Printf("@(dim:Building all packages in) @(dim,cyan:%s)@(dim: using up to )@(dim,cyan:%d)@(dim: process%s.)\n", goPath, Opts.MaxWorkers, pluralProcess)
	if !Opts.Verbose {
		alog.Printf("@(dim:Use) --verbose @(dim:to show all messages during startup.)\n")
	}

	listener := watcher.NewListener()
	listener.Path = srcRoot
	// "_workspace" is a kludge to avoid recursing into Godeps workspaces
	// "node_modules" is a kludge to avoid walking into typically-huge node_modules trees
	listener.IgnorePart = stringset.New(".git", ".hg", "node_modules", "_workspace", "etld")
	listener.NotifyOnStartup = true
	listener.DebounceDuration = 200 * time.Millisecond
	listener.Start()

	// Delete any straggler tmp files, carefully
	files, err := ioutil.ReadDir(tmpdir)
	if err == nil {
		for _, file := range files {
			if filepath.Ext(file.Name()) == ".tmp" {
				os.Remove(filepath.Join(tmpdir, file.Name()))
			}
		}
	} else if os.IsNotExist(err) {
		err = os.MkdirAll(tmpdir, 0700)
		if err != nil {
			alog.Printf("@(error:Error creating temp directory at %s: %v)\n", tmpdir, err)
			return
		}
	} else {
		alog.Printf("@(error:Error checking contents of temp directory at %s: %v)\n", tmpdir, err)
		return
	}

	go processPathTriggers(listener.NotifyChan)
	go dispatcher()

	<-sighup
	startupLogger.Close()
}