app/cli.go
184 lines · 5106 bytes · executable
1package app
2
3import (
4 "bufio"
5 "bytes"
6 "encoding/json"
7 "html/template"
8 "os"
9 "time"
10)
11
12// ExecuteCommandLineArguments parses argv, applying the flags that override
13// config and running one-shot commands such as --help and --add-instance. Some
14// of those commands exit the process rather than return.
15func ExecuteCommandLineArguments() {
16 var helpmsg = `SkunkyArt v{{.Version}} [{{.Description}}]
17Usage:
18 - [-c|--config] | path to config
19 - [-a|--add-instance] | generates 'instances.json' and 'INSTANCES.md' files with ur instance
20 - [-h|--help] | returns this message
21Example:
22 ./skunkyart -c config.json
23Copyright lost+skunk and zerolabs, X11. https://gitbay.org/krz/skunky-art/releases`
24
25 a := os.Args[1:]
26 for n, x := range a {
27 switch x {
28 case "-c", "--config":
29 if n+1 < len(a) {
30 CFG.cfg = a[n+1]
31 cfgExplicit = true
32 } else {
33 exit("Not enought arguments", 1)
34 }
35 case "-h", "--help":
36 var buf bytes.Buffer
37 t := template.New("help")
38 tryWithExitStatus(func() error {
39 if _, err := t.Parse(helpmsg); err != nil {
40 return err
41 }
42 return t.Execute(&buf, &Release)
43 }(), 1)
44 exit(buf.String(), 0)
45 case "-a", "--add-instance":
46 addInstance()
47 }
48 }
49}
50
51type settingsUrls struct {
52 I2P string `json:"i2p,omitempty"`
53 Ygg string `json:"ygg,omitempty"`
54 Tor string `json:"tor,omitempty"`
55 Clearnet string `json:"clearnet,omitempty"`
56}
57
58type settingsParams struct {
59 Nsfw bool `json:"nsfw"`
60 Proxy bool `json:"proxy"`
61 HideAI bool `json:"hide-ai"`
62 Theme string `json:"theme"`
63}
64
65type settings struct {
66 Title string `json:"title"`
67 Country string `json:"country"`
68 ModifiedSrc string `json:"modified-src,omitempty"`
69 Urls settingsUrls `json:"urls"`
70 Settings settingsParams `json:"settings"`
71}
72
73func addInstance() {
74 prompt := func(txt string, necessary bool) string {
75 input := bufio.NewScanner(os.Stdin)
76 for {
77 print(txt)
78 print(": ")
79 input.Scan()
80
81 if i := input.Text(); necessary && i == "" {
82 println("Please specify the", txt)
83 } else {
84 return i
85 }
86 }
87 }
88
89 var settingsVar struct {
90 Instances []settings `json:"instances"`
91 }
92 // 0644: both files are committed to the repository and are meant to be
93 // world-readable, so gosec's 0600 default does not apply.
94 instancesJSON, err := os.OpenFile("instances.json", os.O_CREATE|os.O_WRONLY, 0644) //nolint:gosec // G302
95 if err != nil {
96 exit(err.Error(), 1)
97 }
98 defer func() { try(instancesJSON.Close()) }()
99
100 instancesFile, err := os.OpenFile("INSTANCES.md", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) //nolint:gosec // G302
101 if err != nil {
102 exit(err.Error(), 1)
103 }
104 defer func() { try(instancesFile.Close()) }()
105
106 for {
107 if string(instances) == "" {
108 print("\rDownloading instance list...")
109 } else {
110 println("\r\033[2KDownloaded!")
111 try(json.Unmarshal(instances, &settingsVar))
112
113 settingsVar.Instances = append(settingsVar.Instances, settings{
114 Title: prompt("Title", true),
115 Country: prompt("Country", true),
116 ModifiedSrc: prompt("Link to modified sources", false),
117 Settings: settingsParams{
118 Nsfw: CFG.Nsfw,
119 Proxy: CFG.Proxy,
120 HideAI: CFG.HideAI,
121 Theme: CFG.Theme,
122 },
123 Urls: settingsUrls{
124 Clearnet: prompt("Clearnet link", false),
125 Ygg: prompt("Yggdrasil link", false),
126 Tor: prompt("Onion link", false),
127 I2P: prompt("I2P link", false),
128 },
129 })
130
131 j, err := json.MarshalIndent(&settingsVar, "", " ")
132 try(err)
133
134 try(func() error { _, err := instancesJSON.Write(j); return err }())
135
136 settingsVar := &settingsVar.Instances[len(settingsVar.Instances)-1]
137 var mdstr bytes.Buffer
138
139 mdbuilder := func(yes bool, link string, title string) {
140 switch {
141 case yes && (title != "" && link != ""):
142 mdstr.WriteString("[")
143 mdstr.WriteString(title)
144 mdstr.WriteString("](")
145 mdstr.WriteString(link)
146 mdstr.WriteString(")")
147 case yes && link != "":
148 mdstr.WriteString("[Yes](")
149 mdstr.WriteString(link)
150 mdstr.WriteString(")")
151 case yes:
152 mdstr.WriteString("Yes")
153 default:
154 mdstr.WriteString("No")
155 }
156 mdstr.WriteString("|")
157 }
158
159 mdstr.WriteString("\n|")
160 mdbuilder(settingsVar.Urls.Clearnet != "", settingsVar.Urls.Clearnet, settingsVar.Title)
161
162 urls := []string{settingsVar.Urls.Ygg, settingsVar.Urls.I2P, settingsVar.Urls.Tor}
163 for i, l := 0, len(urls); i < l; i++ {
164 url := urls[i]
165 mdbuilder(url != "", url, "")
166 }
167
168 settings := []bool{settingsVar.Settings.Nsfw, settingsVar.Settings.Proxy}
169 for i, l := 0, len(settings); i < l; i++ {
170 mdbuilder(settings[i], "", "")
171 }
172
173 mdbuilder(settingsVar.ModifiedSrc != "", settingsVar.ModifiedSrc, "")
174
175 mdstr.WriteString(settingsVar.Country)
176 mdstr.WriteString("|")
177
178 try(func() error { _, err := instancesFile.Write(mdstr.Bytes()); return err }())
179 break
180 }
181 time.Sleep(500 * time.Millisecond)
182 }
183 exit("Done! Now add the files 'instances.json' and 'INSTANCES.md' to the 'main' branch by merge request to https://gitbay.org/krz/skunky-art", 0)
184}