package main import ( "errors" "flag" "fmt" "io/fs" "os" "os/exec" "path/filepath" "strings" ) const codeDir = "/nezuko/code/" func checkRepoName(name string) (string, error) { if strings.Contains(name, "/") { return "", fmt.Errorf("invalid name %q: contains slashes", name) } if !strings.HasSuffix(name, ".git") { name += ".git" } return name, nil } func checkRepoNames(args []string) ([]string, error) { if len(args) == 0 { return nil, fmt.Errorf("missing operand\nUse %s -help for usage info", filepath.Base(os.Args[0])) } names := make([]string, len(args)) var errs []error for i, arg := range args { var err error names[i], err = checkRepoName(arg) if err != nil { errs = append(errs, err) } } if len(errs) > 0 { return nil, errors.Join(errs...) } return names, nil } func createRepo(name string) error { dir := filepath.Join(codeDir, name) fmt.Printf("mkdir %s\n", dir) if err := os.Mkdir(dir, 0755); err != nil { return err } fmt.Printf("cd %s && git init --bare\n", dir) git := exec.Command("git", "init", "--bare") git.Dir = dir git.Stdout = os.Stdout git.Stderr = os.Stderr if err := git.Run(); err != nil { return err } hook := filepath.Join(dir, "hooks/post-update") hookSample := hook + ".sample" fmt.Printf("mv %s %s\n", hookSample, hook) if err := os.Rename(hookSample, hook); err != nil { return err } return nil } func create() { flag.Usage = func() { fmt.Fprintf(os.Stderr, `Usage: create [REPO]... Create a new git repo named REPO. `) } flag.Parse() names, err := checkRepoNames(flag.Args()) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } exitCode := 0 for _, name := range names { if err := createRepo(name); err != nil { fmt.Fprintln(os.Stderr, err) exitCode = 1 } } os.Exit(exitCode) } func fileExists(path string) bool { _, err := os.Stat(path) return !errors.Is(err, fs.ErrNotExist) } func deleteRepo(name string) error { dir := filepath.Join(codeDir, name) fmt.Printf("rm -rf %s\n", dir) if !fileExists(dir) { return fmt.Errorf("repo %q does not exist", name) } if err := os.RemoveAll(dir); err != nil { return err } return nil } func delete() { flag.Usage = func() { fmt.Fprintf(os.Stderr, `Usage: delete [REPO]... Delete the git repo named REPO. `) } flag.Parse() names, err := checkRepoNames(flag.Args()) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } exitCode := 0 for _, name := range names { if err := deleteRepo(name); err != nil { fmt.Fprintln(os.Stderr, err) exitCode = 1 } } os.Exit(exitCode) } func help() { fmt.Printf(`Available commands: create create a new git repo delete delete a git repo help print this message `) } func main() { switch filepath.Base(os.Args[0]) { case "create": create() case "delete": delete() default: help() } }