1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
package main
import (
"flag"
"fmt"
"strings"
"github.com/charmbracelet/log"
"github.com/peterbourgon/ff/v3"
"github.com/peterbourgon/ff/v3/ffyaml"
)
type cliArgs struct {
RepoDir string
SSH sshArgs
HTTP httpArgs
Meta metaArgs
Profile profileArgs
Log logArgs
}
type sshArgs struct {
AuthorizedKeys string
CloneURL string
Port int
HostKey string
}
type httpArgs struct {
CloneURL string
Port int
}
type metaArgs struct {
Title string
Description string
}
type profileArgs struct {
Username string
Email string
Links []profileLink
}
type profileLink struct {
Name string
URL string
}
type logArgs struct {
Level log.Level
JSON bool
}
func parseArgs(args []string) (c cliArgs, e error) {
fs := flag.NewFlagSet("ugitd", flag.ContinueOnError)
fs.String("config", "ugit.yaml", "Path to config file")
c = cliArgs{
RepoDir: ".ugit",
SSH: sshArgs{
AuthorizedKeys: ".ssh/authorized_keys",
CloneURL: "ssh://localhost:8448",
Port: 8448,
HostKey: ".ssh/ugit_ed25519",
},
HTTP: httpArgs{
CloneURL: "http://localhost:8449",
Port: 8449,
},
Meta: metaArgs{
Title: "ugit",
Description: "Minimal git server",
},
Log: logArgs{
Level: log.InfoLevel,
},
}
fs.Func("log.level", "Logging level", func(s string) error {
lvl, err := log.ParseLevel(s)
if err != nil {
return err
}
c.Log.Level = lvl
return nil
})
fs.BoolVar(&c.Log.JSON, "log.json", c.Log.JSON, "Print logs in JSON(L) format")
fs.StringVar(&c.RepoDir, "repo-dir", c.RepoDir, "Path to directory containing repositories")
fs.StringVar(&c.SSH.AuthorizedKeys, "ssh.authorized-keys", c.SSH.AuthorizedKeys, "Path to authorized_keys")
fs.StringVar(&c.SSH.CloneURL, "ssh.clone-url", c.SSH.CloneURL, "SSH clone URL base")
fs.IntVar(&c.SSH.Port, "ssh.port", c.SSH.Port, "SSH port")
fs.StringVar(&c.SSH.HostKey, "ssh.host-key", c.SSH.HostKey, "SSH host key (created if it doesn't exist)")
fs.StringVar(&c.HTTP.CloneURL, "http.clone-url", c.HTTP.CloneURL, "HTTP clone URL base")
fs.IntVar(&c.HTTP.Port, "http.port", c.HTTP.Port, "HTTP port")
fs.StringVar(&c.Meta.Title, "meta.title", c.Meta.Title, "App title")
fs.StringVar(&c.Meta.Description, "meta.description", c.Meta.Description, "App description")
fs.StringVar(&c.Profile.Username, "profile.username", c.Profile.Username, "Username for index page")
fs.StringVar(&c.Profile.Email, "profile.email", c.Profile.Email, "Email for index page")
fs.Func("profile.links", "Link(s) for index page", func(s string) error {
parts := strings.SplitN(s, ",", 2)
if len(parts) != 2 {
return fmt.Errorf("invalid profile link %q", s)
}
c.Profile.Links = append(c.Profile.Links, profileLink{
Name: parts[0],
URL: parts[1],
})
return nil
})
return c, ff.Parse(fs, args,
ff.WithEnvVarPrefix("UGIT"),
ff.WithConfigFileFlag("config"),
ff.WithAllowMissingConfigFile(true),
ff.WithConfigFileParser(ffyaml.Parser),
)
}
|