github.com/nycdavid/zeus@v0.0.0-20201208104106-9ba439429e03/go/cmd/zeus/zeus.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"path"
     8  	"strings"
     9  	"syscall"
    10  
    11  	"time"
    12  
    13  	"github.com/burke/zeus/go/config"
    14  	"github.com/burke/zeus/go/filemonitor"
    15  	slog "github.com/burke/zeus/go/shinylog"
    16  	"github.com/burke/zeus/go/zeusclient"
    17  	"github.com/burke/zeus/go/zeusmaster"
    18  	"github.com/burke/zeus/go/zeusversion"
    19  )
    20  
    21  var color bool = true
    22  
    23  func main() {
    24  	args := os.Args[1:]
    25  	configFile := "zeus.json"
    26  	simpleStatus := false
    27  	fileChangeDelay := filemonitor.DefaultFileChangeDelay
    28  
    29  	for ; args != nil && len(args) > 0 && args[0][0] == '-'; args = args[1:] {
    30  		switch args[0] {
    31  		case "--no-color":
    32  			color = false
    33  			slog.DisableColor()
    34  		case "--simple-status":
    35  			slog.DisableColor()
    36  			simpleStatus = true
    37  		case "--log":
    38  			tracefile, err := os.OpenFile(args[1], os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
    39  			if err == nil {
    40  				slog.SetTraceLogger(slog.NewTraceLogger(tracefile))
    41  				args = args[1:]
    42  			} else {
    43  				fmt.Printf("Could not open trace file %s\n", args[1])
    44  				return
    45  			}
    46  		case "--file-change-delay":
    47  			if len(args) > 1 {
    48  				delay, err := time.ParseDuration(args[1])
    49  				if err != nil {
    50  					execManPage("zeus")
    51  				}
    52  				args = args[1:]
    53  				fileChangeDelay = delay
    54  			} else {
    55  				execManPage("zeus")
    56  			}
    57  		case "--config":
    58  			_, err := os.Stat(args[1])
    59  			if err != nil {
    60  				fmt.Printf("Config file doesn't exist: %s (%e)\n", args[1], err)
    61  				return
    62  			}
    63  			configFile = args[1]
    64  			args = args[1:]
    65  		case "--version":
    66  			printVersion()
    67  			return
    68  		}
    69  	}
    70  	if len(args) == 0 {
    71  		execManPage("zeus")
    72  		return
    73  	}
    74  
    75  	if generalHelpRequested(args) {
    76  		execManPage("zeus")
    77  	} else if args[0] == "help" {
    78  		commandSpecificHelp(args)
    79  	} else if args[0] == "version" {
    80  		printVersion()
    81  	} else if args[0] == "start" {
    82  		os.Exit(zeusmaster.Run(configFile, fileChangeDelay, simpleStatus))
    83  	} else if args[0] == "init" {
    84  		zeusInit()
    85  	} else if args[0] == "commands" {
    86  		zeusCommands(configFile)
    87  	} else {
    88  		tree := config.BuildProcessTree(configFile, nil)
    89  		for _, name := range tree.AllCommandsAndAliases() {
    90  			if args[0] == name {
    91  				// Don't confuse the master by sending *full* args to
    92  				// it; just those that are not zeus-specific.
    93  				os.Exit(zeusclient.Run(args, os.Stdin, os.Stdout, os.Stderr))
    94  			}
    95  		}
    96  
    97  		commandNotFound(args[0])
    98  	}
    99  }
   100  
   101  func execManPage(page string) {
   102  	binaryPath := os.Args[0]
   103  	gemDir := path.Dir(path.Dir(binaryPath))
   104  	manDir := path.Join(gemDir, "man/build")
   105  	zeus := path.Join(manDir, page)
   106  	syscall.Exec("/usr/bin/env", []string{"/usr/bin/env", "man", zeus}, os.Environ())
   107  }
   108  
   109  func red() string {
   110  	if color {
   111  		return "\x1b[31m"
   112  	}
   113  	return ""
   114  }
   115  
   116  func reset() string {
   117  	if color {
   118  		return "\x1b[0m"
   119  	}
   120  	return ""
   121  }
   122  
   123  func copyFile(from, to string) (err error) {
   124  	var src, dst *os.File
   125  	wd, _ := os.Getwd()
   126  	target := path.Join(wd, to)
   127  
   128  	if src, err = os.Open(from); err != nil {
   129  		slog.Colorized("      {red}fail{reset}  " + to)
   130  		return err
   131  	}
   132  	defer src.Close()
   133  
   134  	if dst, err = os.OpenFile(target, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666); err != nil {
   135  		slog.Colorized("    {red}exists{reset}  " + to)
   136  		return err
   137  	}
   138  	defer dst.Close()
   139  
   140  	if _, err = io.Copy(dst, src); err != nil {
   141  		slog.Colorized("      {red}fail{reset}  " + to)
   142  		return err
   143  	}
   144  
   145  	slog.Colorized("    {brightgreen}create{reset}  " + to)
   146  	return nil
   147  }
   148  
   149  func zeusInit() {
   150  	binaryPath := os.Args[0]
   151  	gemDir := path.Dir(path.Dir(binaryPath))
   152  	jsonPath := path.Join(gemDir, "examples/custom_plan/zeus.json")
   153  	planPath := path.Join(gemDir, "examples/custom_plan/custom_plan.rb")
   154  	copyFile(jsonPath, "zeus.json")
   155  	copyFile(planPath, "custom_plan.rb")
   156  }
   157  
   158  func zeusCommands(configFile string) {
   159  	tree := config.BuildProcessTree(configFile, nil)
   160  	for _, command := range tree.Commands {
   161  		alia := strings.Join(command.Aliases, ", ")
   162  		var aliasPart string
   163  		if len(alia) > 0 {
   164  			aliasPart = " (alias: " + alia + ")"
   165  		}
   166  		println("zeus " + command.Name + aliasPart)
   167  	}
   168  }
   169  
   170  func commandNotFound(command string) {
   171  	println(red() + "Could not find command \"" + command + "\"." + reset())
   172  }
   173  
   174  func commandSpecificHelp(args []string) {
   175  	if args[1] == "start" {
   176  		execManPage("zeus-start")
   177  	} else if args[1] == "init" {
   178  		execManPage("zeus-init")
   179  	} else {
   180  		println(red() + "Command-level help is not yet fully implemented." + reset())
   181  	}
   182  }
   183  
   184  func generalHelpRequested(args []string) bool {
   185  	helps := []string{"help", "--help", "-h", "--help", "-?", "?"}
   186  	if len(args) == 1 {
   187  		for _, str := range helps {
   188  			if args[0] == str {
   189  				return true
   190  			}
   191  		}
   192  	}
   193  	return false
   194  }
   195  
   196  func printVersion() {
   197  	println("Zeus version " + zeusversion.VERSION)
   198  }