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
page on the wiki.
examples: |
$ aup # open the aup
$ aup --rainbow # open the aup with rainbow colors
$ town aup # open the aup
$ town aup --rainbow # open the aup with rainbow colors
maintainer: vilmibm
```
and using the launcher is like:
$ town aup
$ town aup --rainbow
$ town contrib writo
$ town writo
$ town admin ban vilmibm
You can see all the commands with `town help` as well as their descriptions; `town help
@ -40,10 +41,10 @@ account).
Remaining TODOs:
- [ ] fix arg passing
- [ ] 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
- [ ] add all existing commands to the buckets
- [ ] 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

93
main.go
View File

@ -13,21 +13,16 @@ import (
"gopkg.in/yaml.v3"
)
const binroot = "/town/launcher"
const binroot = "/town/commands"
var rootCmd = &cobra.Command{
Use: "town",
Short: "Run commands unique to tilde.town",
}
var contribCmd = &cobra.Command{
Use: "contrib",
Short: "community-maintained town commands",
}
var adminCmd = &cobra.Command{
Use: "admin",
Short: "commands used for administering the town",
Short: "Run administrative commands",
}
func isAdmin() (bool, error) {
@ -53,34 +48,13 @@ func isAdmin() (bool, error) {
}
return false, nil
}
func init() {
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) {
func parseCommands(targetCmd *cobra.Command, path string) error {
binPath := filepath.Join(binroot, path)
files, err := ioutil.ReadDir(binPath)
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 {
@ -88,12 +62,15 @@ func parseCommands(targetCmd *cobra.Command, path string) {
parseCommand(targetCmd, filepath.Join(binPath, file.Name()))
}
}
return nil
}
type commandDoc struct {
ShortDesc string `yaml:"shortDesc"`
LongDesc string `yaml:"longDesc"`
Examples string
ShortDesc string `yaml:"shortDesc"`
LongDesc string `yaml:"longDesc"`
Examples string
Maintainer string
}
func parseCommand(targetCmd *cobra.Command, yamlPath string) {
@ -103,20 +80,25 @@ func parseCommand(targetCmd *cobra.Command, yamlPath string) {
_, err := os.Stat(executablePath)
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
}
yamlBytes, err := ioutil.ReadFile(yamlPath)
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
}
doc := commandDoc{}
err = yaml.Unmarshal(yamlBytes, &doc)
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
}
@ -132,6 +114,8 @@ func parseCommand(targetCmd *cobra.Command, yamlPath string) {
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 != "" {
parsedCmd.Example = doc.Examples
}
@ -149,6 +133,41 @@ func execWrapper(executablePath string) func(*cobra.Command, []string) error {
}
}
func main() {
func cli() int {
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())
}