town/cmd/visit/main.go

144 lines
2.6 KiB
Go
Raw Normal View History

2022-07-30 13:51:51 +00:00
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/charmbracelet/glamour"
)
func main() {
var err error
if len(os.Args) > 2 {
fmt.Println("expected zero or one arguments")
}
if len(os.Args) > 1 {
arg := os.Args[1]
switch arg {
case "-r", "--random":
err = visitRandomUser()
default:
err = visitUsername(os.Args[1])
}
} else {
err = visitPrompt()
}
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
}
func visitRandomUser() error {
rand.Seed(time.Now().UnixNano())
usernames, err := getUsernames()
if err != nil {
return err
}
return visitUser(usernames[rand.Intn(len(usernames))])
}
func visitUsername(username string) error {
usernames, err := getUsernames()
if err != nil {
return err
}
for _, name := range usernames {
if name == username {
return visitUser(username)
}
}
return fmt.Errorf("no such user: %s", username)
}
func visitPrompt() error {
usernames, err := getUsernames()
if err != nil {
return err
}
username := ""
prompt := &survey.Select{
Message: "Choose a townie to visit!",
Options: usernames,
}
survey.AskOne(prompt, &username)
return visitUser(username)
}
func visitUser(username string) error {
files, err := ioutil.ReadDir(filepath.Join("/home", username))
if err != nil {
return fmt.Errorf("user is not accepting visitors (could not read user's home directory: %w)", err)
}
for _, file := range files {
if !isReadme(file.Name()) {
continue
}
path := filepath.Join("/home", username, file.Name())
data, err := ioutil.ReadFile(path)
if err != nil {
break
}
if isMarkdown(file.Name()) {
r, _ := glamour.NewTermRenderer(glamour.WithAutoStyle())
out, err := r.RenderBytes(data)
if err == nil {
fmt.Println(string(out))
return nil
}
}
fmt.Println(string(data))
return nil
}
// TODO handle .plan and .project files
fmt.Println("TODO non-readme fallback")
return nil
}
func isReadme(filename string) bool {
fn := strings.ToLower(filename)
return strings.HasPrefix(fn, "readme") || strings.HasPrefix(fn, "welcome")
}
func isMarkdown(filename string) bool {
fn := strings.ToLower(filename)
return strings.HasSuffix(fn, ".md") || strings.HasSuffix(fn, ".markdown")
}
func getUsernames() ([]string, error) {
cmd := exec.Command("/bin/bash", "-c", "town stats | jq -r '.users|map(.username)'")
output, err := cmd.Output()
if err != nil {
return nil, err
}
usernames := []string{}
err = json.Unmarshal(output, &usernames)
if err != nil {
return nil, err
}
return usernames, nil
}