Skip to content

Commit a5334a2

Browse files
committed
migrate zine to leatherman
1 parent a107641 commit a5334a2

File tree

12 files changed

+956
-0
lines changed

12 files changed

+956
-0
lines changed

README.mdwn

+4
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,10 @@ frequently without exhausting github api limits.
461461

462462
`yaml2json` reads YAML on stdin and writes JSON on stdout.
463463

464+
### `zine`
465+
466+
`zine` does read only operations on notes.
467+
464468
## Debugging
465469

466470
In an effort to make debugging simpler, I've created three ways to see what

dispatch.go

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ require (
1515
github.com/headzoo/ut v0.0.0-20181013193318-a13b5a7a02ca // indirect
1616
github.com/icza/backscanner v0.0.0-20180226082541-a77511ef4f0f
1717
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 // indirect
18+
github.com/jmoiron/sqlx v1.2.0 // indirect
19+
github.com/mattn/go-sqlite3 v1.14.5 // indirect
1820
github.com/pierrec/lz4/v3 v3.3.2
1921
github.com/prometheus/client_golang v1.8.0
2022
github.com/prometheus/common v0.15.0

go.sum

+6
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBD
163163
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
164164
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
165165
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
166+
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
167+
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
166168
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
167169
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
168170
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -182,13 +184,17 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
182184
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
183185
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
184186
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
187+
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
185188
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
186189
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
187190
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
188191
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
189192
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
190193
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
191194
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
195+
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
196+
github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
197+
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
192198
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
193199
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
194200
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=

help_generated.go

+6
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,10 @@ frequently without exhausting github api limits.
462462
463463
` + "`" + `yaml2json` + "`" + ` reads YAML on stdin and writes JSON on stdout.
464464
465+
### ` + "`" + `zine` + "`" + `
466+
467+
` + "`" + `zine` + "`" + ` does read only operations on notes.
468+
465469
## Debugging
466470
467471
In an effort to make debugging simpler, I've created three ways to see what
@@ -564,5 +568,7 @@ func init() {
564568
"update": readme[12843:13066],
565569

566570
"yaml2json": readme[13066:13143],
571+
572+
"zine": readme[13143:13199],
567573
}
568574
}

internal/tool/notes/db.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package notes
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
7+
"github.com/frioux/leatherman/internal/dropbox"
8+
"github.com/jmoiron/sqlx"
9+
_ "github.com/mattn/go-sqlite3"
10+
)
11+
12+
func loadDB(cl dropbox.Client) (*sqlx.DB, func(), error) {
13+
d, err := ioutil.TempDir("", "")
14+
if err != nil {
15+
return nil, func() {}, err
16+
}
17+
cleanup := func() { os.RemoveAll(d) }
18+
19+
r, err := cl.Download("/notes/.posts.db")
20+
if err != nil {
21+
return nil, cleanup, err
22+
}
23+
24+
b, err := ioutil.ReadAll(r)
25+
if err != nil {
26+
return nil, cleanup, err
27+
}
28+
29+
if err := ioutil.WriteFile(d+"/.posts.db", b, 0600); err != nil {
30+
return nil, cleanup, err
31+
}
32+
33+
dbh, err := sqlx.Open("sqlite3", "file:"+d+"/.posts.db?_sync=OFF&_journal=OFF&_vacuum=0")
34+
if err != nil {
35+
return nil, cleanup, err
36+
}
37+
38+
return dbh, cleanup, nil
39+
}

internal/tool/zine/commands.go

+232
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
package zine
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"flag"
7+
"fmt"
8+
"io"
9+
"os"
10+
"path/filepath"
11+
"regexp"
12+
"strings"
13+
"text/template"
14+
)
15+
16+
var commands = map[string]func([]string) error{
17+
"render": Render,
18+
"q": Q,
19+
"debug": Debug,
20+
}
21+
22+
/*
23+
Run does read only operations on notes.
24+
25+
Command: zine
26+
*/
27+
func Run(args []string, _ io.Reader) error {
28+
command := "render"
29+
if len(args) > 1 {
30+
command = args[1]
31+
}
32+
33+
cmd, ok := commands[command]
34+
if !ok {
35+
return fmt.Errorf("unknown command «%s»; valid commands are 'render' and 'q'\n", command)
36+
}
37+
38+
if err := cmd(args[1:]); err != nil {
39+
return err
40+
}
41+
42+
return nil
43+
}
44+
45+
// Q runs a query against the corpus.
46+
func Q(args []string) error {
47+
var root, sql, tpl string
48+
49+
flags := flag.NewFlagSet("q", flag.ContinueOnError)
50+
flags.StringVar(&root, "root", "./content", "root input directory")
51+
flags.StringVar(&sql, "sql", "SELECT * FROM _", "sql to run")
52+
flags.StringVar(&tpl, "tpl", `{{join . "\t"}}`, "template to run")
53+
if err := flags.Parse(args[1:]); err != nil {
54+
return err
55+
}
56+
57+
t := template.New("x")
58+
t.Funcs(template.FuncMap{
59+
"join": func(is map[string]interface{}, sep string) string {
60+
s := make([]string, 0, len(is))
61+
for i := range is {
62+
s = append(s, fmt.Sprint(is[i]))
63+
}
64+
return strings.Join(s, sep)
65+
},
66+
})
67+
68+
t, err := t.Parse(tpl)
69+
if err != nil {
70+
return err
71+
}
72+
73+
z, err := newZine()
74+
if err != nil {
75+
return err
76+
}
77+
z.root = root
78+
if err := z.load(nil); err != nil {
79+
return err
80+
}
81+
82+
ret, err := z.q(sql, flags.Args()...)
83+
if err != nil {
84+
return err
85+
}
86+
87+
for _, out := range ret {
88+
if err := t.Execute(os.Stdout, out); err != nil {
89+
return err
90+
}
91+
fmt.Println()
92+
}
93+
return nil
94+
}
95+
96+
// Render will convert the corpus to html.
97+
func Render(args []string) error {
98+
var root, out, static string
99+
100+
flags := flag.NewFlagSet("render", flag.ContinueOnError)
101+
flags.StringVar(&root, "root", "./content", "root input directory")
102+
flags.StringVar(&out, "out", "./public", "directory to render output to")
103+
flags.StringVar(&static, "static", "./static", "directory to prepopulate out with")
104+
if err := flags.Parse(args[1:]); err != nil {
105+
return err
106+
}
107+
108+
z, err := newZine()
109+
if err != nil {
110+
return err
111+
}
112+
z.root = root
113+
114+
metas := []article{}
115+
if err := z.load(&metas); err != nil {
116+
return err
117+
}
118+
119+
if err := os.RemoveAll(out); err != nil {
120+
return err
121+
}
122+
123+
if err := filepath.Walk(static, func(path string, info os.FileInfo, err error) error {
124+
if err != nil {
125+
return err
126+
}
127+
if info.IsDir() {
128+
return nil
129+
}
130+
131+
rel, err := filepath.Rel(static, path)
132+
if err != nil {
133+
return err
134+
}
135+
dir := filepath.Dir(rel)
136+
if err := os.MkdirAll(filepath.Join(out, dir), 0755); err != nil {
137+
return err
138+
}
139+
140+
from, err := os.Open(path)
141+
if err != nil {
142+
return err
143+
}
144+
defer from.Close()
145+
146+
to, err := os.Create(filepath.Join(out, rel))
147+
if err != nil {
148+
return err
149+
}
150+
defer to.Close()
151+
152+
if _, err := io.Copy(to, from); err != nil {
153+
return err
154+
}
155+
156+
return nil
157+
}); err != nil {
158+
return err
159+
}
160+
161+
for i := range metas {
162+
// don't be running on windows
163+
dir := filepath.Join(out, metas[i].URL)
164+
if err := os.MkdirAll(dir, 0755); err != nil {
165+
return fmt.Errorf("couldn't create dir for %s: %w", metas[i].Filename, err)
166+
}
167+
168+
b, err := z.render(metas[i])
169+
if err != nil {
170+
return fmt.Errorf("couldn't render %s: %w", metas[i].Filename, err)
171+
}
172+
173+
f, err := os.Create(filepath.Join(dir, "index.html"))
174+
if err != nil {
175+
return fmt.Errorf("couldn't create %s: %w", filepath.Join(dir, "index.html"), err)
176+
}
177+
178+
if _, err := io.Copy(f, bytes.NewReader(b)); err != nil {
179+
return fmt.Errorf("couldn't copy: %w", err)
180+
}
181+
}
182+
183+
return nil
184+
}
185+
186+
func Debug(args []string) error {
187+
var root, file string
188+
189+
flags := flag.NewFlagSet("debug", flag.ContinueOnError)
190+
flags.StringVar(&root, "root", "./content", "root input directory")
191+
flags.StringVar(&file, "file", "", "file to render to markdown")
192+
if err := flags.Parse(args[1:]); err != nil {
193+
return err
194+
}
195+
196+
if file == "" {
197+
return errors.New("-file argument is required")
198+
}
199+
200+
fileMatcher, err := regexp.Compile(file)
201+
if err != nil {
202+
return err
203+
}
204+
205+
z, err := newZine()
206+
if err != nil {
207+
return err
208+
}
209+
z.root = root
210+
211+
metas := []article{}
212+
if err := z.load(&metas); err != nil {
213+
return err
214+
}
215+
216+
for i := range metas {
217+
if !fileMatcher.MatchString(metas[i].Filename) {
218+
continue
219+
}
220+
221+
b, err := z.renderToMarkdown(metas[i])
222+
if err != nil {
223+
return fmt.Errorf("couldn't render %s: %w", metas[i].Filename, err)
224+
}
225+
226+
if _, err := io.Copy(os.Stdout, bytes.NewReader(b)); err != nil {
227+
return fmt.Errorf("couldn't copy: %w", err)
228+
}
229+
}
230+
231+
return nil
232+
}

0 commit comments

Comments
 (0)