strlst.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package main
  2. import (
  3. "strings"
  4. "fmt"
  5. "flag"
  6. "os"
  7. "path/filepath"
  8. )
  9. const (
  10. EXIT_SUCCESS int = iota
  11. EXIT_ENV_INVALID
  12. EXIT_CONFIG_INVALID
  13. EXIT_SPECIFIED_PATH_INVALID
  14. EXIT_HOME_INVALID
  15. EXIT_SSH_ERROR
  16. EXIT_SCP_ERROR
  17. )
  18. func main() {
  19. // query program name by call
  20. program := os.Args[0][strings.LastIndex(os.Args[0], "/") + 1 : len(os.Args[0])]
  21. // query environment
  22. user, user_ok := os.LookupEnv("USER");
  23. home, home_ok := os.LookupEnv("HOME");
  24. if !(user_ok && home_ok) {
  25. fmt.Fprintf(os.Stderr, "%s: error: environment variables $USER and $HOME need to be set\n", program)
  26. os.Exit(EXIT_ENV_INVALID)
  27. }
  28. // register help functions
  29. flag.Usage = func() {
  30. fmt.Fprintf(os.Stdout, "usage: %s [-s|--save] [-c|--config path] [-l|--list-config] [-e|--print-example-config] [-g|--generate-config path] [-G|--generate-config-auto] command [files]\n", program)
  31. // TODO: default generated by flag pkg is ugly, redo
  32. flag.PrintDefaults()
  33. os.Exit(EXIT_SUCCESS)
  34. }
  35. // add save flag
  36. var save bool
  37. default_save := false
  38. help_save := "saves the result of an operation if true (only for some operations)"
  39. flag.BoolVar(&save, "s", default_save, help_save)
  40. flag.BoolVar(&save, "save", default_save, help_save)
  41. // add configuration file path option (with alias for --config)
  42. var configuration_path string
  43. default_path := fmt.Sprintf("%s/.config/%s/%s", home, user, user)
  44. help_configuration_path := "specifies the file path of the configuration to be used"
  45. flag.StringVar(&configuration_path, "c", default_path, help_configuration_path)
  46. flag.StringVar(&configuration_path, "config", default_path, help_configuration_path)
  47. // add print example configuration flag
  48. var list_config bool
  49. default_list_config := false
  50. help_list_config := "lists current configuration obfuscating the secret and exits"
  51. flag.BoolVar(&list_config, "l", default_list_config, help_list_config)
  52. flag.BoolVar(&list_config, "list-config", default_list_config, help_list_config)
  53. // add print example configuration flag
  54. var print_example_config bool
  55. default_print_example_config := false
  56. help_print_example_config := "prints example configuration if true and exits"
  57. flag.BoolVar(&print_example_config, "e", default_print_example_config, help_print_example_config)
  58. flag.BoolVar(&print_example_config, "print-example-config", default_print_example_config, help_print_example_config)
  59. // add generate example configuration option
  60. var generate_config_path string
  61. default_generate_config_path := ""
  62. help_generate_config := "generates and example configuration to a specified path and exits"
  63. flag.StringVar(&generate_config_path, "g", default_generate_config_path, help_generate_config)
  64. flag.StringVar(&generate_config_path, "generate-config", default_generate_config_path, help_generate_config)
  65. // add generate example configuration auto flag
  66. var generate_config_auto bool
  67. default_generate_config_auto := false
  68. help_generate_config_auto := fmt.Sprintf("generates and example configuration to %s and exits", GetConfigDefaultPath())
  69. flag.BoolVar(&generate_config_auto, "G", default_generate_config_auto, help_generate_config_auto)
  70. flag.BoolVar(&generate_config_auto, "generate-config-auto", default_generate_config_auto, help_generate_config_auto)
  71. // finally parse everything and use arguments afterwards
  72. flag.CommandLine.Parse(os.Args[1:])
  73. // if user wants to print example configuration
  74. if print_example_config {
  75. fmt.Println(CONFIG_EXAMPLE)
  76. return
  77. }
  78. // if user wants to generate example configuration
  79. if generate_config_auto || generate_config_path != "" {
  80. // query default location and split to dir and file
  81. default_path := GetConfigDefaultPath()
  82. // in case user specified his own path
  83. if generate_config_path != "" {
  84. default_path = generate_config_path
  85. // take care to expand unexpanded tilde
  86. fmt.Printf(default_path, strings.HasPrefix(default_path, "~"))
  87. if strings.HasPrefix(default_path, "~") {
  88. default_path = strings.Replace(default_path, "~", GetHomeDir(), 1)
  89. }
  90. }
  91. dir, filename := filepath.Split(default_path)
  92. fmt.Printf("generating configuration at %s\n", default_path)
  93. os.MkdirAll(dir, os.ModePerm)
  94. // TODO: ask user in case file already exists?
  95. err := os.WriteFile(default_path, []byte(CONFIG_EXAMPLE), 0644)
  96. if err != nil {
  97. fmt.Fprintf(os.Stderr, "fatal error: file %s could not be opened for reading\n", filename)
  98. }
  99. return
  100. }
  101. // get and check configuration
  102. config := GetConfiguration(&program, &configuration_path)
  103. if !IsConfigurationValid(&config) {
  104. fmt.Fprintf(os.Stderr, "%s: configuration is invalid: %s\n", program, ConfigurationToString(&config, true))
  105. os.Exit(EXIT_CONFIG_INVALID)
  106. }
  107. // if user wants to list current configuration
  108. if list_config {
  109. fmt.Println(ConfigurationToString(&config, true))
  110. return
  111. }
  112. // print available commands in case user needs them
  113. ExtendedUsage := func() {
  114. fmt.Printf("available commands are: `list`, `push [files]`, `pull [files]`, `commit`\n\n")
  115. flag.Usage()
  116. }
  117. // one command is necessary
  118. if flag.NArg() < 1 {
  119. ExtendedUsage()
  120. }
  121. // split command and (sometimes) optional positional file arguments
  122. arguments := flag.Args()
  123. command, files := arguments[0], arguments[1:]
  124. // show usage in case an invalid command is issued
  125. if IsImplemented(command) {
  126. Exec(command, &config, files, save)
  127. } else {
  128. ExtendedUsage()
  129. }
  130. }