simple program for visiting other townies' home directories
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

143 lignes
2.6 KiB

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
}