summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2026-09-02 21:14:37 -0700
committerRose Hogenson <rosehogenson@posteo.net>2026-09-02 22:21:13 -0700
commit0fc1cd727c327d50c99a772f05135ed9d09bd153 (patch)
treef80810a2735778d8879e6d9ef2abb8cb7a245413
parentc05dbd42b0c4c0b609037c35bb80e9c4ae7f6341 (diff)
downloadgit-shell-commands-0fc1cd727c327d50c99a772f05135ed9d09bd153.tar.zst
Add a describe command to set repo description
-rw-r--r--git-shell-commands.go127
1 files changed, 83 insertions, 44 deletions
diff --git a/git-shell-commands.go b/git-shell-commands.go
index 720fb69..cbcc32c 100644
--- a/git-shell-commands.go
+++ b/git-shell-commands.go
@@ -15,6 +15,10 @@ import (
const codeDir = "/nezuko/code/"
+func shellQuote(s string) string {
+ return "'" + strings.ReplaceAll(s, "'", `'\''`) + "'"
+}
+
func checkRepoName(name string) (string, error) {
if strings.Contains(name, "/") {
return "", fmt.Errorf("invalid name %q: contains slashes", name)
@@ -25,55 +29,42 @@ func checkRepoName(name string) (string, error) {
return name, nil
}
-func createRepo(name string) error {
- dir := filepath.Join(codeDir, name)
- fmt.Fprintf(os.Stderr, "mkdir %s\n", dir)
- if err := os.Mkdir(dir, 0755); err != nil {
- return err
- }
- fmt.Fprintf(os.Stderr, "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
- }
- return nil
-}
-
func create() error {
flag.Usage = func() {
- fmt.Fprintf(os.Stderr, `Usage: create [REPO]...
+ fmt.Fprintf(os.Stderr, `Usage: create REPO
Create a new git repo named REPO.
`)
}
+ d := flag.String("d", "", "description")
flag.Parse()
args := flag.Args()
if len(args) == 0 {
return fmt.Errorf("missing operand\nUse create -help for usage info")
}
- 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(args) > 1 {
+ return fmt.Errorf("too many positional arguments\nUse create -help for usage info")
}
- if len(errs) > 0 {
- return errors.Join(errs...)
+ name, err := checkRepoName(args[0])
+ if err != nil {
+ return err
}
- failed := false
- for _, name := range names {
- if err := createRepo(name); err != nil {
- fmt.Fprintln(os.Stderr, err)
- failed = true
- }
+ dir := filepath.Join(codeDir, name)
+ fmt.Fprintf(os.Stderr, "mkdir %s\n", shellQuote(dir))
+ if err := os.Mkdir(dir, 0755); err != nil {
+ return err
+ }
+ fmt.Fprintf(os.Stderr, "cd %s && git init --bare\n", shellQuote(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
}
- if failed {
- return fmt.Errorf("failed to create repo")
+ if *d != "" {
+ if err := setRepoDescription(name, *d); err != nil {
+ return err
+ }
}
return nil
}
@@ -85,7 +76,7 @@ func fileExists(path string) bool {
func delete() error {
flag.Usage = func() {
- fmt.Fprintf(os.Stderr, `Usage: delete [REPO]
+ fmt.Fprintf(os.Stderr, `Usage: delete REPO
Delete the git repo named REPO.
`)
}
@@ -108,7 +99,7 @@ Delete the git repo named REPO.
if !scanner.Scan() || scanner.Text() != shortName {
return fmt.Errorf("name does not match")
}
- fmt.Fprintf(os.Stderr, "rm -rf %s\n", dir)
+ fmt.Fprintf(os.Stderr, "rm -rf %s\n", shellQuote(dir))
if !fileExists(dir) {
return fmt.Errorf("repo %q does not exist", name)
}
@@ -118,8 +109,53 @@ Delete the git repo named REPO.
return nil
}
+func setRepoDescription(repo, description string) error {
+ descriptionPath := filepath.Join(codeDir, repo, "description")
+ fmt.Fprintf(os.Stderr, "echo %s > %s\n", shellQuote(description), shellQuote(descriptionPath))
+ desc, err := os.Create(descriptionPath)
+ if err != nil {
+ return err
+ }
+ defer desc.Close()
+ if _, err := fmt.Fprintln(desc, description); err != nil {
+ return err
+ }
+ if err := desc.Close(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func describe() error {
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, `Usage: describe -d DESCRIPTION REPO
+Set the description for REPO.
+`)
+ }
+ d := flag.String("d", "", "description")
+ flag.Parse()
+ args := flag.Args()
+ if len(args) == 0 {
+ return fmt.Errorf("missing operand\nUse describe -help for usage info")
+ }
+ if len(args) > 1 {
+ return fmt.Errorf("too many positional arguments\nUse describe -help for usage info")
+ }
+ if *d == "" {
+ return fmt.Errorf("missing required flag -d\nUse describe -help for usage info")
+ }
+ name, err := checkRepoName(args[0])
+ if err != nil {
+ return err
+ }
+ if err := setRepoDescription(name, *d); err != nil {
+ return err
+ }
+ return nil
+}
+
func installFile(srcPath, dstPath string) error {
- fmt.Fprintf(os.Stderr, "cp %s %s && chmod +x %[2]s\n", srcPath, dstPath)
+ fmt.Fprintf(os.Stderr, "cp %s %s && chmod +x %[2]s\n", shellQuote(srcPath), shellQuote(dstPath))
src, err := os.Open(srcPath)
if err != nil {
return err
@@ -161,9 +197,9 @@ func install() error {
if err := installFile(selfPath, helpPath); err != nil {
return err
}
- for _, cmd := range []string{"create", "delete"} {
+ for _, cmd := range []string{"create", "delete", "describe"} {
cmdPath := filepath.Join(dir, cmd)
- fmt.Fprintf(os.Stderr, "ln -f %s %s\n", helpPath, cmdPath)
+ fmt.Fprintf(os.Stderr, "ln -f %s %s\n", shellQuote(helpPath), shellQuote(cmdPath))
if err := os.Remove(cmdPath); err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
@@ -176,9 +212,10 @@ func install() error {
func help() {
fmt.Printf(`Available commands:
- create create a new git repo
- delete delete a git repo
- help print this message
+ create create a new git repo
+ delete delete a git repo
+ describe set repo description
+ help print this message
`)
}
@@ -189,6 +226,8 @@ func main() {
err = create()
case "delete":
err = delete()
+ case "describe":
+ err = describe()
case "git-shell-commands":
err = install()
default: