Compare commits

..

5 Commits

Author SHA1 Message Date
vilmibm 9dbec05b3f Merge branch 'master' of http://git.tilde.town/tildetown/town-launcher 2020-06-10 05:43:49 +00:00
vilmibm 8115522703 add admin bucket back 2020-06-10 05:35:41 +00:00
vilmibm 66d91bd1ba update readme 2020-06-10 05:35:34 +00:00
vilmibm c686492998 support Maintainer field 2020-06-09 04:36:29 +00:00
vilmibm f685a9baa2 few things
- code cleanup
- remove buckets from invocation (preserve on disk)
- add maintainer to doc schema
2020-06-09 04:30:34 +00:00
2 changed files with 64 additions and 44 deletions

View File

@ -20,15 +20,16 @@ longDesc: |
Policies that governed servers like this in the past. It will open the elinks browser to a Policies that governed servers like this in the past. It will open the elinks browser to a
page on the wiki. page on the wiki.
examples: | examples: |
$ aup # open the aup $ town aup # open the aup
$ aup --rainbow # open the aup with rainbow colors $ town aup --rainbow # open the aup with rainbow colors
maintainer: vilmibm
``` ```
and using the launcher is like: and using the launcher is like:
$ town aup $ town aup
$ town aup --rainbow $ town aup --rainbow
$ town contrib writo $ town writo
$ town admin ban vilmibm $ town admin ban vilmibm
You can see all the commands with `town help` as well as their descriptions; `town help You can see all the commands with `town help` as well as their descriptions; `town help
@ -40,10 +41,10 @@ account).
Remaining TODOs: Remaining TODOs:
- [ ] fix arg passing
- [ ] make tab completion available for common shells - [ ] make tab completion available for common shells
- [ ] test with a command that makes use of stdin/stdout
- [ ] document / script submitting a tool for inclusion in contrib - [ ] document / script submitting a tool for inclusion in contrib
- [ ] add all existing commands to the buckets
- [ ] make little wrappers for things like `mail` and `chat` - [ ] make little wrappers for things like `mail` and `chat`
- [ ] add to users' paths - [x] fix arg passing
- [x] test with a command that makes use of stdin/stdout
- [x] add all existing commands to the buckets
- [x] add to users' paths

89
main.go
View File

@ -13,21 +13,16 @@ import (
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
const binroot = "/town/launcher" const binroot = "/town/commands"
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "town", Use: "town",
Short: "Run commands unique to tilde.town", Short: "Run commands unique to tilde.town",
} }
var contribCmd = &cobra.Command{
Use: "contrib",
Short: "community-maintained town commands",
}
var adminCmd = &cobra.Command{ var adminCmd = &cobra.Command{
Use: "admin", Use: "admin",
Short: "commands used for administering the town", Short: "Run administrative commands",
} }
func isAdmin() (bool, error) { func isAdmin() (bool, error) {
@ -53,34 +48,13 @@ func isAdmin() (bool, error) {
} }
return false, nil return false, nil
} }
func init() { func parseCommands(targetCmd *cobra.Command, path string) error {
rootCmd.AddCommand(contribCmd)
parseCommands(rootCmd, "core")
parseCommands(contribCmd, "contrib")
admin, err := isAdmin()
if err != nil {
panic(fmt.Sprintf("failed to check admin status: %s", err))
}
if admin {
rootCmd.AddCommand(adminCmd)
parseCommands(adminCmd, "admin")
}
// I feel like the example/documentation yaml can be frontmatter for non-binary files. to start
// i'll just do the accompanying yaml file.
}
func parseCommands(targetCmd *cobra.Command, path string) {
binPath := filepath.Join(binroot, path) binPath := filepath.Join(binroot, path)
files, err := ioutil.ReadDir(binPath) files, err := ioutil.ReadDir(binPath)
if err != nil { if err != nil {
panic(fmt.Sprintf("failed to list directory %s: %s", binPath, err)) return fmt.Errorf("failed to list directory %s: %s", binPath, err)
} }
for _, file := range files { for _, file := range files {
@ -88,12 +62,15 @@ func parseCommands(targetCmd *cobra.Command, path string) {
parseCommand(targetCmd, filepath.Join(binPath, file.Name())) parseCommand(targetCmd, filepath.Join(binPath, file.Name()))
} }
} }
return nil
} }
type commandDoc struct { type commandDoc struct {
ShortDesc string `yaml:"shortDesc"` ShortDesc string `yaml:"shortDesc"`
LongDesc string `yaml:"longDesc"` LongDesc string `yaml:"longDesc"`
Examples string Examples string
Maintainer string
} }
func parseCommand(targetCmd *cobra.Command, yamlPath string) { func parseCommand(targetCmd *cobra.Command, yamlPath string) {
@ -103,20 +80,25 @@ func parseCommand(targetCmd *cobra.Command, yamlPath string) {
_, err := os.Stat(executablePath) _, err := os.Stat(executablePath)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "could not find matching executable for %s; skipping...", yamlPath) fmt.Fprintf(os.Stderr, "could not find matching executable for %s; skipping...\n", yamlPath)
return return
} }
yamlBytes, err := ioutil.ReadFile(yamlPath) yamlBytes, err := ioutil.ReadFile(yamlPath)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "could not read %s; skipping...", yamlPath) fmt.Fprintf(os.Stderr, "could not read %s; skipping...\n", yamlPath)
return return
} }
doc := commandDoc{} doc := commandDoc{}
err = yaml.Unmarshal(yamlBytes, &doc) err = yaml.Unmarshal(yamlBytes, &doc)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "could not parse %s; skipping...", yamlPath) fmt.Fprintf(os.Stderr, "could not parse %s; skipping...\n", yamlPath)
return
}
if doc.Maintainer == "" {
fmt.Fprintf(os.Stderr, "%s is missing maintainer field; skipping...\n", yamlPath)
return return
} }
@ -132,6 +114,8 @@ func parseCommand(targetCmd *cobra.Command, yamlPath string) {
parsedCmd.Long = doc.LongDesc parsedCmd.Long = doc.LongDesc
} }
parsedCmd.Long += fmt.Sprintf("\nMaintained by %s; reach out to them via mail or chat with questions", doc.Maintainer)
if doc.Examples != "" { if doc.Examples != "" {
parsedCmd.Example = doc.Examples parsedCmd.Example = doc.Examples
} }
@ -149,6 +133,41 @@ func execWrapper(executablePath string) func(*cobra.Command, []string) error {
} }
} }
func main() { func cli() int {
rootCmd.Execute() err := parseCommands(rootCmd, "core")
if err != nil {
fmt.Fprintf(os.Stderr, "failed to parse core commands: %s", err)
return 1
}
err = parseCommands(rootCmd, "contrib")
if err != nil {
fmt.Fprintf(os.Stderr, "failed to parse contrib commands: %s", err)
return 1
}
admin, err := isAdmin()
if err != nil {
fmt.Fprintf(os.Stderr, "failed to check admin status: %s", err)
return 2
}
if admin {
rootCmd.AddCommand(adminCmd)
err = parseCommands(adminCmd, "admin")
if err != nil {
fmt.Fprintf(os.Stderr, "failed to parse admin commands: %s", err)
return 1
}
}
// I feel like the example/documentation yaml can be frontmatter for non-binary files. to start
// i'll just do the accompanying yaml file.
rootCmd.Execute()
return 0
}
func main() {
os.Exit(cli())
} }