repos / pgit

static site generator for git
git clone https://github.com/picosh/pgit.git

commit
d8a9ea1
parent
7415be1
author
Eric Bower
date
2023-08-08 19:04:57 +0000 UTC
refactor: rework all structs
12 files changed,  +362, -520
M go.mod
M go.sum
D config.yaml
+0, -16
 1@@ -1,16 +0,0 @@
 2-url: git.erock.io
 3-repos:
 4-  - path: /home/erock/dev/pico/pico
 5-    refs:
 6-      - main
 7-      - v1.0.0
 8-    desc: pico services - prose.sh, lists.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
 9-  - path: /home/erock/dev/pico/pico-ops
10-    refs:
11-      - main
12-    desc: infra for pico services
13-  - path: /home/erock/dev/app-ui
14-    refs:
15-      - main
16-      - v50
17-    desc: aptible's paas web application
M go.mod
+5, -47
 1@@ -3,74 +3,32 @@ module sr.ht/~erock/gemgit
 2 go 1.18
 3 
 4 require (
 5+	github.com/alecthomas/chroma v0.10.0
 6+	github.com/dustin/go-humanize v1.0.0
 7 	github.com/gogs/git-module v1.6.0
 8 	github.com/mergestat/timediff v0.0.3
 9-	github.com/picosh/pico v1.1.6
10 	github.com/spf13/viper v1.12.0
11 )
12 
13 require (
14-	github.com/alecthomas/chroma v0.10.0 // indirect
15-	github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
16-	github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect
17-	github.com/aymerick/douceur v0.2.0 // indirect
18-	github.com/disintegration/imaging v1.6.2 // indirect
19 	github.com/dlclark/regexp2 v1.7.0 // indirect
20-	github.com/dsoprea/go-exif v0.0.0-20221012082141-d21ac8e2de85 // indirect
21-	github.com/dsoprea/go-exif/v2 v2.0.0-20221012082141-d21ac8e2de85 // indirect
22-	github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 // indirect
23-	github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
24-	github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d // indirect
25-	github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d // indirect
26-	github.com/dsoprea/go-utility v0.0.0-20221003172846-a3e1774ef349 // indirect
27-	github.com/dustin/go-humanize v1.0.0 // indirect
28 	github.com/fsnotify/fsnotify v1.5.4 // indirect
29-	github.com/gliderlabs/ssh v0.3.5 // indirect
30-	github.com/go-errors/errors v1.4.2 // indirect
31-	github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
32-	github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
33-	github.com/google/uuid v1.3.0 // indirect
34-	github.com/gorilla/css v1.0.0 // indirect
35-	github.com/gorilla/feeds v1.1.1 // indirect
36 	github.com/hashicorp/hcl v1.0.0 // indirect
37-	github.com/json-iterator/go v1.1.12 // indirect
38-	github.com/klauspost/compress v1.15.13 // indirect
39-	github.com/klauspost/cpuid/v2 v2.2.2 // indirect
40-	github.com/kolesa-team/go-webp v1.0.2 // indirect
41-	github.com/lib/pq v1.10.7 // indirect
42 	github.com/magiconair/properties v1.8.6 // indirect
43 	github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 // indirect
44-	github.com/microcosm-cc/bluemonday v1.0.21 // indirect
45-	github.com/minio/md5-simd v1.1.2 // indirect
46-	github.com/minio/minio-go/v7 v7.0.45 // indirect
47-	github.com/minio/sha256-simd v1.0.0 // indirect
48 	github.com/mitchellh/mapstructure v1.5.0 // indirect
49-	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
50-	github.com/modern-go/reflect2 v1.0.2 // indirect
51-	github.com/neurosnap/go-exif-remove v0.0.0-20221010134343-50d1e3c35577 // indirect
52-	github.com/neurosnap/go-jpeg-image-structure v0.0.0-20221010133817-70b1c1ff679e // indirect
53-	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
54 	github.com/pelletier/go-toml v1.9.5 // indirect
55 	github.com/pelletier/go-toml/v2 v2.0.1 // indirect
56-	github.com/rs/xid v1.4.0 // indirect
57-	github.com/sirupsen/logrus v1.9.0 // indirect
58 	github.com/spf13/afero v1.8.2 // indirect
59 	github.com/spf13/cast v1.5.0 // indirect
60 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
61 	github.com/spf13/pflag v1.0.5 // indirect
62+	github.com/stretchr/testify v1.8.0 // indirect
63 	github.com/subosito/gotenv v1.3.0 // indirect
64-	github.com/yuin/goldmark v1.5.3 // indirect
65-	github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 // indirect
66-	github.com/yuin/goldmark-meta v1.1.0 // indirect
67-	go.uber.org/atomic v1.10.0 // indirect
68-	go.uber.org/multierr v1.8.0 // indirect
69-	go.uber.org/zap v1.24.0 // indirect
70-	golang.org/x/crypto v0.4.0 // indirect
71-	golang.org/x/exp v0.0.0-20221211140036-ad323defaf05 // indirect
72-	golang.org/x/image v0.2.0 // indirect
73-	golang.org/x/net v0.4.0 // indirect
74+	golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
75 	golang.org/x/sys v0.3.0 // indirect
76 	golang.org/x/text v0.5.0 // indirect
77+	gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
78 	gopkg.in/ini.v1 v1.67.0 // indirect
79 	gopkg.in/yaml.v2 v2.4.0 // indirect
80 	gopkg.in/yaml.v3 v3.0.1 // indirect
M go.sum
+3, -147
  1@@ -40,13 +40,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
  2 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
  3 github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
  4 github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
  5-github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
  6-github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
  7-github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
  8-github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
  9-github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
 10-github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
 11-github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 12 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 13 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 14 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 15@@ -58,35 +51,9 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht
 16 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 17 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 18 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 19-github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
 20-github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
 21 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 22 github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
 23 github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
 24-github.com/dsoprea/go-exif v0.0.0-20221012082141-d21ac8e2de85 h1:+wKSjK8wh5Ybb63Fx1QvTSIfWU/n1nmqEzZy+82pqbQ=
 25-github.com/dsoprea/go-exif v0.0.0-20221012082141-d21ac8e2de85/go.mod h1:lOaOt7+UEppOgyvRy749v3do836U/hw0YVJNjoyPaEs=
 26-github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
 27-github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4/go.mod h1:9EXlPeHfblFFnwu5UOqmP2eoZfJyAZ2Ri/Vki33ajO0=
 28-github.com/dsoprea/go-exif/v2 v2.0.0-20221012082141-d21ac8e2de85 h1:sgMOHQHMiddteUitH9QYgaRTwAcqqr5X9z5j4yNXDuY=
 29-github.com/dsoprea/go-exif/v2 v2.0.0-20221012082141-d21ac8e2de85/go.mod h1:oKrjk2kb3rAR5NbtSTLUMvMSbc+k8ZosI3MaVH47noc=
 30-github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
 31-github.com/dsoprea/go-exif/v3 v3.0.0-20210512043655-120bcdb2a55e/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
 32-github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
 33-github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 h1:YDRiMEm32T60Kpm35YzOK9ZHgjsS1Qrid+XskNcsdp8=
 34-github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413/go.mod h1:kYIdx9N9NaOyD7U6D+YtExN7QhRm+5kq7//yOsRXQtM=
 35-github.com/dsoprea/go-logging v0.0.0-20190624164917-c4f10aab7696/go.mod h1:Nm/x2ZUNRW6Fe5C3LxdY1PyZY5wmDv/s5dkPJ/VB3iA=
 36-github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
 37-github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd h1:l+vLbuxptsC6VQyQsfD7NnEC8BZuFpz45PgY+pH8YTg=
 38-github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3Pe2o/YSU88W0hWlm9S22W7XI1JFNJ86U0zPKMf8=
 39-github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
 40-github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d h1:dg6UMHa50VI01WuPWXPbNJpO8QSyvIF5T5n2IZiqX3A=
 41-github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d/go.mod h1:pqKB+ijp27cEcrHxhXVgUUMlSDRuGJJp1E+20Lj5H0E=
 42-github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d h1:8+qI8ant/vZkNSsbwSjIR6XJfWcDVTg/qx/3pRUUZNA=
 43-github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d/go.mod h1:yTR3tKgyk20phAFg6IE9ulMA5NjEDD2wyx+okRFLVtw=
 44-github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
 45-github.com/dsoprea/go-utility v0.0.0-20221003172846-a3e1774ef349 h1:/py11NlxDaOxkT9OKN+gXgT+QOH5xj1ZRoyusfRIlo4=
 46-github.com/dsoprea/go-utility v0.0.0-20221003172846-a3e1774ef349/go.mod h1:KVK+/Hul09ujXAGq+42UBgCTnXkiJZRnLYdURGjQUwo=
 47-github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
 48 github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
 49 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 50 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 51@@ -98,25 +65,11 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 52 github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
 53 github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
 54 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
 55-github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
 56-github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
 57-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
 58-github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
 59-github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
 60-github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
 61-github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
 62 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 63 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 64 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 65-github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
 66-github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
 67-github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
 68 github.com/gogs/git-module v1.6.0 h1:71GdRM9/pFxGgSUz8t2DKmm3RYuHUnTjsOuFInJXnkM=
 69 github.com/gogs/git-module v1.6.0/go.mod h1:8jFYhDxLUwEOhM2709l2CJXmoIIslobU1xszpT0NcAI=
 70-github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
 71-github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
 72-github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
 73-github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
 74 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 75 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 76 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 77@@ -154,7 +107,6 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 78 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 79 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 80 github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
 81-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 82 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 83 github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 84 github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 85@@ -170,92 +122,43 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
 86 github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 87 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 88 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 89-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 90-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 91 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 92 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 93 github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 94-github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
 95-github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
 96-github.com/gorilla/feeds v1.1.1 h1:HwKXxqzcRNg9to+BbvJog4+f3s/xzvtZXICcQGutYfY=
 97-github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA=
 98 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 99 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
100 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
101 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
102 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
103 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
104-github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
105-github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
106-github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
107 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
108 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
109 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
110-github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0=
111-github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
112-github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
113-github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
114-github.com/klauspost/cpuid/v2 v2.2.2 h1:xPMwiykqNK9VK0NYC3+jTMYv9I6Vl3YdjZgPZKG3zO0=
115-github.com/klauspost/cpuid/v2 v2.2.2/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
116-github.com/kolesa-team/go-webp v1.0.2 h1:XCrWqxI7tNOI3dr0YufD9TUb+54vBDogg9KsHH7q5Lc=
117-github.com/kolesa-team/go-webp v1.0.2/go.mod h1:oMvdivD6K+Q5qIIkVC2w4k2ZUnI1H+MyP7inwgWq9aA=
118 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
119 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
120 github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
121 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
122 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
123 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
124-github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
125-github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
126 github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
127 github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
128-github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
129-github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
130 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 h1:Pijfgr7ZuvX7QIQiEwLdRVr3RoMG+i0SbBO1Qu+7yVk=
131 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
132 github.com/mergestat/timediff v0.0.3 h1:ucCNh4/ZrTPjFZ081PccNbhx9spymCJkFxSzgVuPU+Y=
133 github.com/mergestat/timediff v0.0.3/go.mod h1:yvMUaRu2oetc+9IbPLYBJviz6sA7xz8OXMDfhBl7YSI=
134-github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg=
135-github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
136-github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
137-github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
138-github.com/minio/minio-go/v7 v7.0.45 h1:g4IeM9M9pW/Lo8AGGNOjBZYlvmtlE1N5TQEYWXRWzIs=
139-github.com/minio/minio-go/v7 v7.0.45/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw=
140-github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
141-github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
142 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
143 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
144-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
145-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
146-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
147-github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
148-github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
149-github.com/neurosnap/go-exif-remove v0.0.0-20221010134343-50d1e3c35577 h1:hVmVNttSLNloGsbFKVXAUHonXTd8KKrv30U/8UkloKI=
150-github.com/neurosnap/go-exif-remove v0.0.0-20221010134343-50d1e3c35577/go.mod h1:G3Cu1AW+dmRLDFpOi8eUAfc3cGoRHUjTkGjeRcndgl4=
151-github.com/neurosnap/go-jpeg-image-structure v0.0.0-20221010133817-70b1c1ff679e h1:76Dng5ms0fR+26doKZAvNqhi2UPfnLxGfPIDEr+BBlM=
152-github.com/neurosnap/go-jpeg-image-structure v0.0.0-20221010133817-70b1c1ff679e/go.mod h1:nZBDA7+RD63GDJwjZmxhxac65MJqiCIHUUUvdYOsFkk=
153-github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
154-github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
155 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
156 github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
157 github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
158 github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
159-github.com/picosh/pico v1.1.6 h1:Kw0gP/WVOwD9DkvEfTFt84pXJSv4yKI4n9ncIJHpOnQ=
160-github.com/picosh/pico v1.1.6/go.mod h1:dbiKZsgsm/4KWzN6g4hCkqPj4itd9KzplPYZqs1JWLg=
161-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
162 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
163 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
164 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
165 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
166 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
167-github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
168 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
169 github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
170-github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
171-github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
172-github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
173-github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
174-github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
175 github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
176 github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
177 github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
178@@ -267,52 +170,33 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
179 github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
180 github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
181 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
182+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
183 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
184-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
185 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
186 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
187 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
188 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
189 github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
190+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
191 github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI=
192 github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs=
193 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
194 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
195 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
196 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
197-github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
198-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
199-github.com/yuin/goldmark v1.5.3 h1:3HUJmBFbQW9fhQOzMgseU134xfi6hU+mjWywx5Ty+/M=
200-github.com/yuin/goldmark v1.5.3/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
201-github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg=
202-github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU=
203-github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
204-github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
205 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
206 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
207 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
208 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
209 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
210 go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
211-go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
212-go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
213-go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
214-go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
215-go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
216-go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
217-go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
218-go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
219 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
220 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
221 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
222 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
223 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
224 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
225-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
226 golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
227-golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
228-golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
229-golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
230 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
231 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
232 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
233@@ -323,14 +207,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
234 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
235 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
236 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
237-golang.org/x/exp v0.0.0-20221211140036-ad323defaf05 h1:T8EldfGCcveFMewH5xAYxxoX3PSQMrsechlUGVFlQBU=
238-golang.org/x/exp v0.0.0-20221211140036-ad323defaf05/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
239 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
240 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
241-golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
242-golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
243-golang.org/x/image v0.2.0 h1:/DcQ0w3VHKCC5p0/P2B0JpAZ9Z++V2KOo2fyU89CXBQ=
244-golang.org/x/image v0.2.0/go.mod h1:la7oBXb9w3YFjBqaAwtynVioc1ZvOnNteUNrifGNmAI=
245 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
246 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
247 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
248@@ -352,7 +230,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
249 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
250 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
251 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
252-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
253 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
254 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
255 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
256@@ -371,7 +248,6 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
257 golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
258 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
259 golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
260-golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
261 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
262 golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
263 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
264@@ -385,11 +261,6 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
265 golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
266 golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
267 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
268-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
269-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
270-golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
271-golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
272-golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
273 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
274 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
275 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
276@@ -443,30 +314,18 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
277 golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
278 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
279 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
280-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
281 golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
282 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
283 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
284-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
285-golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
286-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
287-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
288-golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
289-golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
290 golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
291 golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
292 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
293-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
294-golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
295-golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
296 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
297 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
298 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
299 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
300 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
301 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
302-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
303-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
304 golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
305 golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
306 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
307@@ -519,7 +378,6 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
308 golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
309 golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
310 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
311-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
312 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
313 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
314 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
315@@ -615,16 +473,14 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
316 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
317 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
318 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
319+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
320 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
321 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
322 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
323 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
324-gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
325-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
326 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
327 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
328 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
329-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
330 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
331 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
332 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
M html/commit.page.tmpl
+10, -10
 1@@ -6,29 +6,29 @@
 2 
 3   <dl>
 4     <dt>commit</dt>
 5-    <dd><a href="{{.Data.CommitURL}}">{{.Data.CommitID}}</a></dd>
 6+    <dd><a href="{{.CommitURL}}">{{.CommitID}}</a></dd>
 7 
 8     <dt>parent</dt>
 9-    <dd><a href="{{.Data.ParentURL}}">{{.Data.Parent}}</a></dd>
10+    <dd><a href="{{.ParentURL}}">{{.Parent}}</a></dd>
11 
12     <dt>author</dt>
13-    <dd>{{.Data.Commit.Author.Name}}</dd>
14+    <dd>{{.Commit.Author.Name}}</dd>
15 
16     <dt>date</dt>
17-    <dd>{{.Data.Commit.Author.When}}</dd>
18+    <dd>{{.Commit.Author.When}}</dd>
19   </dl>
20 
21-  <pre>{{.Data.Commit.Message}}</pre>
22+  <pre>{{.Commit.Message}}</pre>
23 
24   <div class="box mono">
25     <div>
26-      <strong>{{.Data.Diff.NumFiles}}</strong> files changed,&nbsp;
27-      <span class="color-green">+{{.Data.Diff.TotalAdditions}}</span>,
28-      <span class="color-red">-{{.Data.Diff.TotalDeletions}}</span>
29+      <strong>{{.Diff.NumFiles}}</strong> files changed,&nbsp;
30+      <span class="color-green">+{{.Diff.TotalAdditions}}</span>,
31+      <span class="color-red">-{{.Diff.TotalDeletions}}</span>
32     </div>
33 
34     <div>
35-    {{range .Data.Diff.Files}}
36+    {{range .Diff.Files}}
37       <div class="my-sm">
38         <span>{{.FileType}}</span>
39         <a href="#diff-{{.Name}}">{{.Name}}</a>
40@@ -37,7 +37,7 @@
41     </div>
42   </div>
43 
44-  {{range .Data.Diff.Files}}
45+  {{range .Diff.Files}}
46     <div id="diff-{{.Name}}" class="flex justify-between mono">
47       <span>{{.FileType}} {{if eq .FileType "R"}}{{.OldName}} => {{end}}{{.Name}}</span>
48       <div>
M html/file.page.tmpl
+2, -2
1@@ -4,6 +4,6 @@
2 {{define "content"}}
3   {{template "header" .}}
4 
5-  <h1 class="text-lg">{{.Data.Path}}</h1>
6-  {{.Data.Contents}}
7+  <h1 class="text-lg">{{.Path}}</h1>
8+  {{.Contents}}
9 {{end }}
M html/header.partial.tmpl
+7, -7
 1@@ -1,20 +1,20 @@
 2 {{define "header"}}
 3 <h1 class="text-xl">
 4   <a href="/">repos</a>
 5-  <span>&nbsp;/&nbsp;{{.RepoName}}</span>
 6+  <span>&nbsp;/&nbsp;{{.Repo.RepoName}}</span>
 7 </h1>
 8 
 9 <div class="text-lg">
10-  <a href="{{.Repo.SummaryURL}}">summary</a> |
11-  <a href="{{.Repo.RefsURL}}">refs</a> |
12-  <span class="font-bold">{{.Repo.RevName}}</span> |
13-  <a href="{{.Repo.TreeURL}}">tree</a> |
14-  <a href="{{.Repo.LogURL}}">log</a>
15+  <a href="{{.SiteURLs.SummaryURL}}">summary</a> |
16+  <a href="{{.SiteURLs.RefsURL}}">refs</a> |
17+  <span class="font-bold">{{.RevData.RevName}}</span> |
18+  <a href="{{.RevData.TreeURL}}">tree</a> |
19+  <a href="{{.RevData.LogURL}}">log</a>
20 </div>
21 
22 <div class="mt-lg">
23   <div class="text-lg">{{.Repo.Desc}}</div>
24-  <pre style="margin: 0;">git clone {{.Repo.CloneURL}}</pre>
25+  <pre style="margin: 0;">git clone {{.SiteURLs.CloneURL}}</pre>
26 </div>
27 
28 <hr />
D html/index.page.tmpl
+0, -19
 1@@ -1,19 +0,0 @@
 2-{{template "base" .}}
 3-
 4-{{define "title"}}index{{end}}
 5-
 6-{{define "content"}}
 7-  <h1 class="text-xl">repos</h1>
 8-  <div>
 9-    {{range .RepoList}}
10-      <div class="my box">
11-        <div class="flex justify-between items-center">
12-          <div><a class="text-lg" href="{{.URL}}">{{.Name}}</a></div>
13-          <div class="text-sm">{{.CommitDate}}</div>
14-        </div>
15-
16-        <div class="my">{{.Desc}}</div>
17-      </div>
18-    {{end}}
19-  </div>
20-{{end}}
M html/log.page.tmpl
+1, -1
1@@ -6,7 +6,7 @@
2   {{template "header" .}}
3 
4   <div>
5-  {{range .Data.Log}}
6+  {{range .Logs}}
7     <div class="box">
8       <div class="flex justify-between items-center">
9         <div>
M html/refs.page.tmpl
+1, -1
1@@ -7,7 +7,7 @@
2 
3   <h2 class="text-md font-bold">refs</h2>
4   <ul>
5-  {{range .Data.Refs}}
6+  {{range .Refs}}
7     {{if .URL}}
8       <li><a href="{{.URL}}">{{.Refspec}}</a></li>
9     {{else}}
M html/summary.page.tmpl
+1, -1
1@@ -5,5 +5,5 @@
2 {{define "content"}}
3   {{template "header" .}}
4 
5-  {{.Data.Readme}}
6+  {{.Readme}}
7 {{end}}
M html/tree.page.tmpl
+1, -1
1@@ -6,7 +6,7 @@
2   {{template "header" .}}
3 
4   <div>
5-  {{range .Data.Tree}}
6+  {{range .Tree}}
7     <div class="flex justify-between items-center gap my-sm border-b">
8       <div class="flex-1">
9         <a href="{{.URL}}">{{.Path}}</a>
M main.go
+331, -268
  1@@ -1,53 +1,74 @@
  2 package main
  3 
  4 import (
  5+	"bytes"
  6+	"embed"
  7+	_ "embed"
  8+	"flag"
  9 	"fmt"
 10 	"html/template"
 11 	html "html/template"
 12+	"math"
 13 	"os"
 14 	"path/filepath"
 15 	"sort"
 16 	"strings"
 17+	"unicode/utf8"
 18 
 19+	formatterHtml "github.com/alecthomas/chroma/formatters/html"
 20+	"github.com/alecthomas/chroma/lexers"
 21+	"github.com/alecthomas/chroma/styles"
 22 	"github.com/dustin/go-humanize"
 23 	git "github.com/gogs/git-module"
 24 	"github.com/mergestat/timediff"
 25-	"github.com/picosh/pico/pastes"
 26-	"github.com/picosh/pico/shared"
 27-	"github.com/spf13/viper"
 28 )
 29 
 30+//go:embed html/*.tmpl
 31+var efs embed.FS
 32 var defaultBranches = []string{"main", "master"}
 33 
 34-type RepoItemData struct {
 35-	URL        string
 36-	Name       string
 37-	Desc       string
 38-	CommitDate string
 39-	LastCommit *git.Commit
 40-}
 41+type Config struct {
 42+	// required params
 43+	Outdir string
 44+	// abs path to git repo
 45+	RepoPath string
 46+
 47+	// optional params
 48+	// generate logs and trees based on the refs provided
 49+	Refs []string
 50+	// description of repo used in the header of site
 51+	Desc string
 52+	// maximum number of commits that we will process in descending order
 53+	MaxCommits int
 54+	// name of the readme file
 55+	Readme string
 56+	// In order to get the latest commit per file we do a `git rev-list {ref} {file}`
 57+	// which is n+1 where n is a file in the tree.
 58+	// We offer a way to disable showing the latest commit in the output
 59+	// for those who want a faster build time
 60+	HideTreeLastCommit bool
 61 
 62-type IndexPage struct {
 63-	RepoList []*RepoItemData
 64+	// user-defined urls
 65+	HomeUrl  template.URL
 66+	CloneURL template.URL
 67+
 68+	// computed
 69+	// cache for skipping commits, trees, etc.
 70+	Cache map[string]bool
 71+	// pretty name for the repo
 72+	RepoName string
 73 }
 74 
 75-type RepoData struct {
 76-	Name               string
 77-	Desc               string
 78-	SummaryURL         string
 79-	TreeURL            string
 80-	LogURL             string
 81-	RefsURL            string
 82-	CloneURL           string
 83-	MaxCommits         int
 84-	RevName            string
 85-	Readme             string
 86-	HideTreeLastCommit bool
 87+type RevData struct {
 88+	RevName string
 89+	TreeURL template.URL
 90+	LogURL  template.URL
 91+	Ref     *git.Reference
 92 }
 93 
 94 type CommitData struct {
 95 	SummaryStr string
 96-	URL        string
 97+	URL        template.URL
 98 	WhenStr    string
 99 	AuthorStr  string
100 	ShortID    string
101@@ -61,41 +82,11 @@ type TreeItem struct {
102 	URL        string
103 	Path       string
104 	Entry      *git.TreeEntry
105-	CommitURL  string
106+	CommitURL  template.URL
107 	Summary    string
108 	When       string
109 }
110 
111-type PageData struct {
112-	Repo    *RepoData
113-	Log     []*CommitData
114-	Tree    []*TreeItem
115-	Readme  template.HTML
116-	Rev     *git.Reference
117-	RevName string
118-	Refs    []*RefInfo
119-}
120-
121-type CommitPageData struct {
122-	CommitMsg template.HTML
123-	CommitID  string
124-	Commit    *CommitData
125-	Diff      *DiffRender
126-	Repo      *RepoData
127-	Parent    string
128-	ParentURL string
129-	CommitURL string
130-}
131-
132-type WriteData struct {
133-	Name     string
134-	Template string
135-	Data     interface{}
136-	RepoName string
137-	Subdir   string
138-	Repo     *RepoData
139-}
140-
141 type DiffRender struct {
142 	NumFiles       int
143 	TotalAdditions int
144@@ -114,11 +105,6 @@ type DiffRenderFile struct {
145 	NumDeletions int
146 }
147 
148-type FileData struct {
149-	Contents template.HTML
150-	Path     string
151-}
152-
153 type RefInfo struct {
154 	Refspec string
155 	URL     template.URL
156@@ -129,19 +115,54 @@ type BranchOutput struct {
157 	LastCommit *git.Commit
158 }
159 
160-type RepoConfig struct {
161-	Path               string   `mapstructure:"path"`
162-	Refs               []string `mapstructure:"refs"`
163-	Desc               string   `mapstructure:"desc"`
164-	MaxCommits         int      `mapstructure:"max_commits"`
165-	Readme             string   `mapstructure:"readme"`
166-	HideTreeLastCommit bool     `mapstructure:"hide_tree_last_commit"`
167+type PageData struct {
168+	Repo     *Config
169+	SiteURLs *SiteURLs
170+	RevData  *RevData
171 }
172 
173-type Config struct {
174-	Repos []*RepoConfig `mapstructure:"repos"`
175-	URL   string        `mapstructure:"url"`
176-	Cache map[string]bool
177+type SummaryPageData struct {
178+	*PageData
179+	Readme template.HTML
180+}
181+
182+type TreePageData struct {
183+	*PageData
184+	Tree []*TreeItem
185+}
186+
187+type LogPageData struct {
188+	*PageData
189+	Logs []*CommitData
190+}
191+
192+type FilePageData struct {
193+	*PageData
194+	Contents template.HTML
195+	Path     string
196+}
197+
198+type CommitPageData struct {
199+	*PageData
200+	CommitMsg template.HTML
201+	CommitID  string
202+	Commit    *CommitData
203+	Diff      *DiffRender
204+	Parent    string
205+	ParentURL template.URL
206+	CommitURL template.URL
207+}
208+
209+type RefPageData struct {
210+	*PageData
211+	Refs []*RefInfo
212+}
213+
214+type WriteData struct {
215+	Template string
216+	Filename string
217+	Subdir   string
218+	Data     interface{}
219 }
220 
221 func diffFileType(_type git.DiffFileType) string {
222@@ -164,12 +185,62 @@ func bail(err error) {
223 	}
224 }
225 
226-func toPretty(b int64) string {
227-	return humanize.Bytes(uint64(b))
228+func parseText(filename string, text string) (string, error) {
229+	formatter := formatterHtml.New(
230+		formatterHtml.WithLineNumbers(true),
231+		formatterHtml.LinkableLineNumbers(true, ""),
232+		formatterHtml.WithClasses(true),
233+	)
234+	lexer := lexers.Match(filename)
235+	if lexer == nil {
236+		lexer = lexers.Analyse(text)
237+	}
238+	if lexer == nil {
239+		lexer = lexers.Get("plaintext")
240+	}
241+	iterator, err := lexer.Tokenise(nil, text)
242+	if err != nil {
243+		return text, err
244+	}
245+	var buf bytes.Buffer
246+	err = formatter.Format(&buf, styles.Dracula, iterator)
247+	if err != nil {
248+		return text, err
249+	}
250+	return buf.String(), nil
251 }
252 
253-func commitURL(repo string, commitID string) string {
254-	return fmt.Sprintf("/%s/commits/%s.html", repo, commitID)
255+// isText reports whether a significant prefix of s looks like correct UTF-8;
256+// that is, if it is likely that s is human-readable text.
257+func isText(s string) bool {
258+	const max = 1024 // at least utf8.UTFMax
259+	if len(s) > max {
260+		s = s[0:max]
261+	}
262+	for i, c := range s {
263+		if i+utf8.UTFMax > len(s) {
264+			// last char may be incomplete - ignore
265+			break
266+		}
267+		if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' && c != '\f' && c != '\r' {
268+			// decoding error or control character - not a text file
269+			return false
270+		}
271+	}
272+	return true
273+}
274+
275+// isTextFile reports whether the file has a known extension indicating
276+// a text file, or if a significant chunk of the specified file looks like
277+// correct UTF-8; that is, if it is likely that the file contains human-
278+// readable text.
279+func isTextFile(text string) bool {
280+	num := math.Min(float64(len(text)), 1024)
281+	return isText(text[0:int(num)])
282+}
283+
284+func toPretty(b int64) string {
285+	return humanize.Bytes(uint64(b))
286 }
287 
288 func repoName(root string) string {
289@@ -177,7 +248,7 @@ func repoName(root string) string {
290 	return file
291 }
292 
293-func readmeFile(repo *RepoData) string {
294+func readmeFile(repo *Config) string {
295 	if repo.Readme == "" {
296 		return "readme.md"
297 	}
298@@ -185,8 +256,8 @@ func readmeFile(repo *RepoData) string {
299 	return strings.ToLower(repo.Readme)
300 }
301 
302-func findDefaultBranch(config *RepoConfig, refs []*git.Reference) *git.Reference {
303-	branches := config.Refs
304+func (c *Config) findDefaultBranch(refs []*git.Reference) *git.Reference {
305+	branches := c.Refs
306 	if len(branches) == 0 {
307 		branches = defaultBranches
308 	}
309@@ -207,13 +278,14 @@ func walkTree(tree *git.Tree, branch string, curpath string, aggregate []*TreeIt
310 	bail(err)
311 
312 	for _, entry := range entries {
313-		fname := curpath + "/" + entry.Name()
314-		if entry.IsTree() {
315+		fname := filepath.Join(curpath, entry.Name())
316+		typ := entry.Type()
317+		if typ == git.ObjectTree {
318 			re, _ := tree.Subtree(entry.Name())
319 			aggregate = walkTree(re, branch, fname, aggregate)
320 		}
321 
322-		if entry.IsBlob() {
323+		if entry.Type() == git.ObjectBlob {
324 			aggregate = append(aggregate, &TreeItem{
325 				Size:  toPretty(entry.Size()),
326 				Path:  fname,
327@@ -226,140 +298,115 @@ func walkTree(tree *git.Tree, branch string, curpath string, aggregate []*TreeIt
328 	return aggregate
329 }
330 
331-func writeHtml(data *WriteData) {
332-	files := []string{data.Template}
333-	files = append(
334-		files,
335-		"./html/header.partial.tmpl",
336-		"./html/base.layout.tmpl",
337+func (c *Config) writeHtml(writeData *WriteData) {
338+	ts, err := html.ParseFS(
339+		efs,
340+		writeData.Template,
341+		"html/header.partial.tmpl",
342+		"html/base.layout.tmpl",
343 	)
344-
345-	ts, err := html.ParseFiles(files...)
346 	bail(err)
347 
348-	outdir := viper.GetString("outdir")
349-	dir := filepath.Join(outdir, data.RepoName, data.Subdir)
350+	dir := filepath.Join(c.Outdir, c.RepoName, writeData.Subdir)
351 	err = os.MkdirAll(dir, os.ModePerm)
352 	bail(err)
353 
354-	fp := filepath.Join(dir, data.Name)
355+	fp := filepath.Join(dir, writeData.Filename)
356 	fmt.Printf("writing (%s)\n", fp)
357 
358 	w, err := os.OpenFile(fp, os.O_WRONLY|os.O_CREATE, 0755)
359 	bail(err)
360 
361-	err = ts.Execute(w, data)
362+	err = ts.Execute(w, writeData.Data)
363 	bail(err)
364 }
365 
366-func writeIndex(data *IndexPage) {
367-	files := []string{"./html/index.page.tmpl"}
368-	files = append(
369-		files,
370-		"./html/header.partial.tmpl",
371-		"./html/base.layout.tmpl",
372-	)
373-
374-	ts, err := html.ParseFiles(files...)
375-	bail(err)
376-
377-	outdir := viper.GetString("outdir")
378-	dir := filepath.Join(outdir)
379-	err = os.MkdirAll(dir, os.ModePerm)
380-	bail(err)
381-
382-	fp := filepath.Join(dir, "index.html")
383-	fmt.Printf("writing (%s)\n", fp)
384-
385-	w, err := os.OpenFile(fp, os.O_WRONLY|os.O_CREATE, 0755)
386-	bail(err)
387-
388-	err = ts.Execute(w, data)
389-	bail(err)
390-}
391-
392-func writeRootSummary(data *PageData) {
393-	writeHtml(&WriteData{
394-		Name:     "index.html",
395-		Template: "./html/summary.page.tmpl",
396-		Data:     data,
397-		RepoName: data.Repo.Name,
398-		Repo:     data.Repo,
399+func (c *Config) writeRootSummary(data *PageData, readme template.HTML) {
400+	c.writeHtml(&WriteData{
401+		Filename: "index.html",
402+		Template: "html/summary.page.tmpl",
403+		Data: &SummaryPageData{
404+			PageData: data,
405+			Readme:   readme,
406+		},
407 	})
408 }
409 
410-func writeTree(data *PageData) {
411-	writeHtml(&WriteData{
412-		Name:     "index.html",
413-		Subdir:   filepath.Join("tree", data.RevName),
414-		Template: "./html/tree.page.tmpl",
415-		Data:     data,
416-		RepoName: data.Repo.Name,
417-		Repo:     data.Repo,
418+func (c *Config) writeTree(data *PageData, tree []*TreeItem) {
419+	c.writeHtml(&WriteData{
420+		Filename: "index.html",
421+		Subdir:   filepath.Join("tree", data.RevData.RevName),
422+		Template: "html/tree.page.tmpl",
423+		Data: &TreePageData{
424+			PageData: data,
425+			Tree:     tree,
426+		},
427 	})
428 }
429-func writeLog(data *PageData) {
430-	writeHtml(&WriteData{
431-		Name:     "index.html",
432-		Subdir:   filepath.Join("logs", data.RevName),
433-		Template: "./html/log.page.tmpl",
434-		Data:     data,
435-		RepoName: data.Repo.Name,
436-		Repo:     data.Repo,
437+
438+func (c *Config) writeLog(data *PageData, logs []*CommitData) {
439+	c.writeHtml(&WriteData{
440+		Filename: "index.html",
441+		Subdir:   filepath.Join("logs", data.RevData.RevName),
442+		Template: "html/log.page.tmpl",
443+		Data: &LogPageData{
444+			PageData: data,
445+			Logs:     logs,
446+		},
447 	})
448 }
449-func writeRefs(data *PageData) {
450-	writeHtml(&WriteData{
451-		Name:     "refs.html",
452-		Template: "./html/refs.page.tmpl",
453-		Data:     data,
454-		RepoName: data.Repo.Name,
455-		Repo:     data.Repo,
456+
457+func (c *Config) writeRefs(data *PageData, refs []*RefInfo) {
458+	c.writeHtml(&WriteData{
459+		Filename: "refs.html",
460+		Template: "html/refs.page.tmpl",
461+		Data: &RefPageData{
462+			PageData: data,
463+			Refs:     refs,
464+		},
465 	})
466 }
467 
468-func writeHTMLTreeFiles(data *PageData) string {
469+func (c *Config) writeHTMLTreeFiles(pageData *PageData, tree []*TreeItem) string {
470 	readme := ""
471-	for _, file := range data.Tree {
472+	for _, file := range tree {
473 		b, err := file.Entry.Blob().Bytes()
474 		bail(err)
475 		str := string(b)
476 
477-		file.IsTextFile = shared.IsTextFile(str)
478+		file.IsTextFile = isTextFile(str)
479 
480 		contents := "binary file, cannot display"
481 		if file.IsTextFile {
482 			file.NumLines = len(strings.Split(str, "\n"))
483-			contents, err = pastes.ParseText(file.Entry.Name(), string(b))
484+			contents, err = parseText(file.Entry.Name(), string(b))
485 			bail(err)
486 		}
487 
488 		d := filepath.Dir(file.Path)
489 
490 		nameLower := strings.ToLower(file.Entry.Name())
491-		summary := readmeFile(data.Repo)
492+		summary := readmeFile(pageData.Repo)
493 		if nameLower == summary {
494 			readme = contents
495 		}
496 
497-		writeHtml(&WriteData{
498-			Name:     fmt.Sprintf("%s.html", file.Entry.Name()),
499-			Template: "./html/file.page.tmpl",
500-			Data: &FileData{
501+		c.writeHtml(&WriteData{
502+			Filename: fmt.Sprintf("%s.html", file.Entry.Name()),
503+			Template: "html/file.page.tmpl",
504+			Data: &FilePageData{
505+				PageData: pageData,
506 				Contents: template.HTML(contents),
507 				Path:     file.Path,
508 			},
509-			RepoName: data.Repo.Name,
510-			Subdir:   filepath.Join("tree", data.RevName, "item", d),
511-			Repo:     data.Repo,
512+			Subdir: filepath.Join("tree", pageData.RevData.RevName, "item", d),
513 		})
514 	}
515 	return readme
516 }
517 
518-func (c *Config) writeLogDiffs(repo *git.Repository, pageData *PageData) {
519-	project := pageData.Repo.Name
520-	for _, commit := range pageData.Log {
521+func (c *Config) writeLogDiffs(repo *git.Repository, pageData *PageData, logs []*CommitData) {
522+	for _, commit := range logs {
523 		commitID := commit.ID.String()
524 
525 		if c.Cache[commitID] {
526@@ -377,7 +424,7 @@ func (c *Config) writeLogDiffs(repo *git.Repository, pageData *PageData) {
527 			pt := ancestors[0]
528 			parent = &CommitData{
529 				Commit: pt,
530-				URL:    commitURL(project, pt.ID.String()),
531+				URL:    c.getCommitURL(pt.ID.String()),
532 			}
533 		}
534 		parentID := parent.ID.String()
535@@ -413,7 +460,7 @@ func (c *Config) writeLogDiffs(repo *git.Repository, pageData *PageData) {
536 				}
537 			}
538 			// set filename to something our `ParseText` recognizes (e.g. `.diff`)
539-			finContent, err := pastes.ParseText("commit.diff", content)
540+			finContent, err := parseText("commit.diff", content)
541 			bail(err)
542 
543 			fl.Content = template.HTML(finContent)
544@@ -422,73 +469,110 @@ func (c *Config) writeLogDiffs(repo *git.Repository, pageData *PageData) {
545 		rnd.Files = fls
546 
547 		commitData := &CommitPageData{
548+			PageData:  pageData,
549 			Commit:    commit,
550 			CommitID:  commit.ID.String()[:7],
551 			Diff:      rnd,
552-			Repo:      pageData.Repo,
553 			Parent:    parentID[:7],
554-			CommitURL: commitURL(project, commitID),
555-			ParentURL: commitURL(project, parentID),
556+			CommitURL: c.getCommitURL(commitID),
557+			ParentURL: c.getCommitURL(parentID),
558 		}
559 
560-		writeHtml(&WriteData{
561-			Name:     fmt.Sprintf("%s.html", commitID),
562-			Template: "./html/commit.page.tmpl",
563-			Data:     commitData,
564-			RepoName: pageData.Repo.Name,
565+		c.writeHtml(&WriteData{
566+			Filename: fmt.Sprintf("%s.html", commitID),
567+			Template: "html/commit.page.tmpl",
568 			Subdir:   "commits",
569-			Repo:     pageData.Repo,
570+			Data:     commitData,
571 		})
572 	}
573 }
574 
575-func (c *Config) writeRepo(config *RepoConfig) *BranchOutput {
576-	repo, err := git.Open(config.Path)
577+type SiteURLs struct {
578+	RootURL    template.URL
579+	CloneURL   template.URL
580+	SummaryURL template.URL
581+	RefsURL    template.URL
582+}
583+
584+func (c *Config) getCloneURL() template.URL {
585+	url := fmt.Sprintf("https://%s/%s.git", c.CloneURL, c.RepoName)
586+	return template.URL(url)
587+}
588+
589+func (c *Config) getSummaryUrl() template.URL {
590+	url := fmt.Sprintf("/%s/index.html", c.RepoName)
591+	return template.URL(url)
592+}
593+
594+func (c *Config) getRefsUrl() template.URL {
595+	url := fmt.Sprintf("/%s/refs.html", c.RepoName)
596+	return template.URL(url)
597+}
598+
599+func (c *Config) getTreeUrl(revn string) template.URL {
600+	url := fmt.Sprintf("/%s/tree/%s/index.html", c.RepoName, revn)
601+	return template.URL(url)
602+}
603+
604+func (c *Config) getLogsUrl(revn string) template.URL {
605+	url := fmt.Sprintf("/%s/logs/%s/index.html", c.RepoName, revn)
606+	return template.URL(url)
607+}
608+
609+func (c *Config) getCommitURL(commitID string) template.URL {
610+	url := fmt.Sprintf("/%s/commits/%s.html", c.RepoName, commitID)
611+	return template.URL(url)
612+}
613+
614+func (c *Config) getURLs() *SiteURLs {
615+	return &SiteURLs{
616+		RootURL:    c.HomeUrl,
617+		CloneURL:   c.CloneURL,
618+		RefsURL:    c.getRefsUrl(),
619+		SummaryURL: c.getSummaryUrl(),
620+	}
621+}
622+
623+func (c *Config) writeRepo() *BranchOutput {
624+	repo, err := git.Open(c.RepoPath)
625 	bail(err)
626 
627-	name := repoName(config.Path)
628+	name := repoName(c.RepoPath)
629 
630 	refs, err := repo.ShowRef(git.ShowRefOptions{Heads: true, Tags: true})
631 	bail(err)
632 
633-	rev := findDefaultBranch(config, refs)
634+	rev := c.findDefaultBranch(refs)
635 	if rev == nil {
636 		bail(fmt.Errorf("no default branch found"))
637 	}
638 	_, revName := filepath.Split(rev.Refspec)
639 
640 	refInfoMap := map[string]*RefInfo{}
641-	var mainOutput *BranchOutput
642+	mainOutput := &BranchOutput{}
643 	claimed := false
644-	for _, revn := range config.Refs {
645-		for _, head := range refs {
646-			_, headName := filepath.Split(head.Refspec)
647+	for _, revn := range c.Refs {
648+		for _, ref := range refs {
649+			_, headName := filepath.Split(ref.Refspec)
650 			if revn != headName {
651 				continue
652 			}
653-			refInfoMap[head.ID] = &RefInfo{
654-				Refspec: strings.TrimPrefix(head.Refspec, "refs/"),
655+			refInfoMap[ref.ID] = &RefInfo{
656+				Refspec: strings.TrimPrefix(ref.Refspec, "refs/"),
657 				URL:     template.URL(fmt.Sprintf("/%s/tree/%s/index.html", name, revn)),
658 			}
659 
660-			branchRepo := &RepoData{
661-				Name:               name,
662-				Desc:               config.Desc,
663-				MaxCommits:         config.MaxCommits,
664-				Readme:             config.Readme,
665-				HideTreeLastCommit: config.HideTreeLastCommit,
666-				SummaryURL:         fmt.Sprintf("/%s/index.html", name),
667-				TreeURL:            fmt.Sprintf("/%s/tree/%s/index.html", name, revn),
668-				LogURL:             fmt.Sprintf("/%s/logs/%s/index.html", name, revn),
669-				RefsURL:            fmt.Sprintf("/%s/refs.html", name),
670-				CloneURL:           fmt.Sprintf("https://%s/%s.git", c.URL, name),
671-				RevName:            revn,
672+			branchRepo := &RevData{
673+				TreeURL: c.getTreeUrl(revn),
674+				LogURL:  c.getLogsUrl(revn),
675+				RevName: revn,
676+				Ref: ref,
677 			}
678 
679 			data := &PageData{
680-				Rev:     head,
681-				RevName: headName,
682-				Repo:    branchRepo,
683+				Repo:     c,
684+				RevData:  branchRepo,
685+				SiteURLs: c.getURLs(),
686 			}
687 
688 			branchOutput := c.writeBranch(repo, data)
689@@ -524,31 +608,24 @@ func (c *Config) writeRepo(config *RepoConfig) *BranchOutput {
690 		return urlI > urlJ
691 	})
692 
693-	repoData := &RepoData{
694-		Name:       name,
695-		Desc:       config.Desc,
696-		SummaryURL: fmt.Sprintf("/%s/index.html", name),
697-		TreeURL:    fmt.Sprintf("/%s/tree/%s/index.html", name, revName),
698-		LogURL:     fmt.Sprintf("/%s/logs/%s/index.html", name, revName),
699-		RefsURL:    fmt.Sprintf("/%s/refs.html", name),
700-		CloneURL:   fmt.Sprintf("https://%s/%s.git", c.URL, name),
701-		RevName:    revName,
702+	revData := &RevData{
703+		TreeURL: c.getTreeUrl(revName),
704+		LogURL:  c.getLogsUrl(revName),
705+		RevName: revName,
706 	}
707 
708 	data := &PageData{
709-		Rev:     rev,
710-		RevName: revName,
711-		Repo:    repoData,
712-		Readme:  template.HTML(mainOutput.Readme),
713-		Refs:    refInfoList,
714+		RevData:  revData,
715+		Repo:     c,
716+		SiteURLs: c.getURLs(),
717 	}
718-	writeRefs(data)
719-	writeRootSummary(data)
720+	c.writeRefs(data, refInfoList)
721+	c.writeRootSummary(data, template.HTML(mainOutput.Readme))
722 	return mainOutput
723 }
724 
725 func (c *Config) writeBranch(repo *git.Repository, pageData *PageData) *BranchOutput {
726-	fmt.Printf("compiling (%s) branch (%s)\n", pageData.Repo.Name, pageData.Repo.RevName)
727+	fmt.Printf("compiling (%s) branch (%s)\n", c.RepoName, pageData.RevData.RevName)
728 
729 	output := &BranchOutput{}
730 	pageSize := pageData.Repo.MaxCommits
731@@ -556,7 +633,7 @@ func (c *Config) writeBranch(repo *git.Repository, pageData *PageData) *BranchOu
732 		pageSize = 5000
733 	}
734 
735-	commits, err := repo.CommitsByPage(pageData.Rev.ID, 0, pageSize)
736+	commits, err := repo.CommitsByPage(pageData.RevData.Ref.ID, 0, pageSize)
737 	bail(err)
738 
739 	logs := []*CommitData{}
740@@ -566,7 +643,7 @@ func (c *Config) writeBranch(repo *git.Repository, pageData *PageData) *BranchOu
741 		}
742 
743 		logs = append(logs, &CommitData{
744-			URL:        commitURL(pageData.Repo.Name, commit.ID.String()),
745+			URL:        c.getCommitURL(commit.ID.String()),
746 			ShortID:    commit.ID.String()[:7],
747 			SummaryStr: commit.Summary(),
748 			AuthorStr:  commit.Author.Name,
749@@ -575,10 +652,11 @@ func (c *Config) writeBranch(repo *git.Repository, pageData *PageData) *BranchOu
750 		})
751 	}
752 
753-	tree, err := repo.LsTree(pageData.Rev.ID)
754+	tree, err := repo.LsTree(pageData.RevData.Ref.ID)
755 	bail(err)
756+
757 	entries := []*TreeItem{}
758-	treeEntries := walkTree(tree, pageData.RevName, "", entries)
759+	treeEntries := walkTree(tree, pageData.RevData.RevName, "", entries)
760 	for _, entry := range treeEntries {
761 		entry.Path = strings.TrimPrefix(entry.Path, "/")
762 
763@@ -587,7 +665,7 @@ func (c *Config) writeBranch(repo *git.Repository, pageData *PageData) *BranchOu
764 		if pageData.Repo.HideTreeLastCommit {
765 			fmt.Println("skipping finding last commit for each file")
766 		} else {
767-			lastCommits, err = repo.RevList([]string{pageData.Rev.Refspec}, git.RevListOptions{
768+			lastCommits, err = repo.RevList([]string{pageData.RevData.Ref.Refspec}, git.RevListOptions{
769 				Path:           entry.Path,
770 				CommandOptions: git.CommandOptions{Args: []string{"-1"}},
771 			})
772@@ -597,69 +675,54 @@ func (c *Config) writeBranch(repo *git.Repository, pageData *PageData) *BranchOu
773 			if len(lastCommits) > 0 {
774 				lc = lastCommits[0]
775 			}
776-			entry.CommitURL = commitURL(pageData.Repo.Name, lc.ID.String())
777+			entry.CommitURL = c.getCommitURL(lc.ID.String())
778 			entry.Summary = lc.Summary()
779 			entry.When = timediff.TimeDiff(lc.Author.When)
780 		}
781 		entry.URL = filepath.Join(
782 			"/",
783-			pageData.Repo.Name,
784+			c.RepoName,
785 			"tree",
786-			pageData.RevName,
787+			pageData.RevData.RevName,
788 			"item",
789 			fmt.Sprintf("%s.html", entry.Path),
790 		)
791 	}
792 
793-	pageData.Log = logs
794-	pageData.Tree = treeEntries
795-
796-	fmt.Printf("compilation complete (%s) branch (%s)", pageData.Repo.Name, pageData.Repo.RevName)
797-
798-	writeLog(pageData)
799-	readme := writeHTMLTreeFiles(pageData)
800-	c.writeLogDiffs(repo, pageData)
801+	fmt.Printf("compilation complete (%s) branch (%s)\n", c.RepoName, pageData.RevData.RevName)
802 
803-	writeTree(pageData)
804+	c.writeLog(pageData, logs)
805+	c.writeLogDiffs(repo, pageData, logs)
806+	c.writeTree(pageData, treeEntries)
807+	readme := c.writeHTMLTreeFiles(pageData, treeEntries)
808 
809 	output.Readme = readme
810 	return output
811 }
812 
813 func main() {
814-	viper.SetDefault("outdir", "./public")
815-	viper.SetConfigName("config")
816-	viper.SetConfigType("yaml")
817-	viper.AddConfigPath(".")
818-	err := viper.ReadInConfig()
819-	bail(err)
820-
821-	var config Config
822-	err = viper.Unmarshal(&config)
823-	bail(err)
824-
825-	config.Cache = make(map[string]bool)
826-
827-	repoList := []*RepoItemData{}
828-	for _, r := range config.Repos {
829-		mainOutput := config.writeRepo(r)
830-		name := repoName(r.Path)
831-		url := filepath.Join("/", name, "index.html")
832-		repoList = append(repoList, &RepoItemData{
833-			URL:        url,
834-			Name:       name,
835-			Desc:       r.Desc,
836-			CommitDate: timediff.TimeDiff(mainOutput.LastCommit.Author.When),
837-			LastCommit: mainOutput.LastCommit,
838-		})
839+	var outdir = flag.String("out", "./public", "output directory (default: ./public)")
840+	var rpath = flag.String("repo", ".", "path to git repo")
841+	var refs = flag.String("refs", "HEAD", "path to git repo")
842+
843+	flag.Parse()
844+
845+	repoPath := *rpath
846+	// outdir
847+	config := &Config{
848+		Outdir:   *outdir,
849+		RepoPath: repoPath,
850+		RepoName: repoName(repoPath),
851+		Cache:    make(map[string]bool),
852+		Refs:     strings.Split(*refs, ","),
853 	}
854-	sort.Slice(repoList, func(i, j int) bool {
855-		first := repoList[i].LastCommit.Author.When
856-		second := repoList[j].LastCommit.Author.When
857-		return first.After(second)
858-	})
859 
860-	writeIndex(&IndexPage{
861-		RepoList: repoList,
862-	})
863+	fmt.Println(config.Outdir)
864+	fmt.Println(config.RepoPath)
865+	fmt.Println(config.RepoName)
866+	fmt.Println(config.Refs)
867+
868+	config.writeRepo()
869+	url := filepath.Join("/", config.RepoName, "index.html")
870+	fmt.Println(url)
871 }