- commit
- 9a45dd6
- parent
- 69a42ed
- author
- Eric Bower
- date
- 2024-05-20 09:37:30 -0400 EDT
web view
M
cfg.go
+14,
-0
1@@ -2,13 +2,27 @@ package git
2
3 import "github.com/charmbracelet/ssh"
4
5+type Repo struct {
6+ ID string
7+ Desc string
8+ CloneAddr string
9+}
10+
11 type GitCfg struct {
12 DataPath string
13 Admins []ssh.PublicKey
14+ Repos []Repo
15 }
16
17 func NewGitCfg() *GitCfg {
18 return &GitCfg{
19 DataPath: "./ssh_data",
20+ Repos: []Repo{
21+ {
22+ ID: "test",
23+ Desc: "A test repo to play around with Patch Requests",
24+ CloneAddr: "git@github.com:picosh/test",
25+ },
26+ },
27 }
28 }
M
cli.go
+2,
-2
1@@ -81,8 +81,8 @@ Here's how it works:
2 fmt.Fprintf(
3 writer,
4 "%s\t%s\n",
5- utils.SanitizeRepo(repo),
6- filepath.Join(be.ReposDir(), repo),
7+ utils.SanitizeRepo(repo.ID),
8+ filepath.Join(be.ReposDir(), repo.ID),
9 )
10 }
11 writer.Flush()
M
go.mod
+7,
-12
1@@ -3,19 +3,21 @@ module github.com/picosh/pico-git
2 go 1.21.9
3
4 require (
5+ github.com/alecthomas/chroma/v2 v2.13.0
6+ github.com/bluekeyes/go-gitdiff v0.7.2
7 github.com/charmbracelet/soft-serve v0.7.4
8 github.com/charmbracelet/ssh v0.0.0-20240301204039-e79ff702f5b3
9 github.com/charmbracelet/wish v1.3.2
10- github.com/picosh/send v0.0.0-20240217194807-77b972121e63
11+ github.com/jmoiron/sqlx v1.3.5
12+ github.com/urfave/cli/v2 v2.27.2
13+ golang.org/x/crypto v0.21.0
14+ modernc.org/sqlite v1.27.0
15 )
16
17 require (
18- github.com/DavidGamba/go-getoptions v0.29.0 // indirect
19 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
20- github.com/antoniomika/go-rsync-receiver v0.0.0-20231110145728-c94949e1ab7d // indirect
21 github.com/aymanbagabas/git-module v1.8.4-0.20231101154130-8d27204ac6d2 // indirect
22 github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
23- github.com/bluekeyes/go-gitdiff v0.7.2 // indirect
24 github.com/caarlos0/env/v10 v10.0.0 // indirect
25 github.com/charmbracelet/bubbletea v0.25.0 // indirect
26 github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20231027181609-f7ff6baf2ed0 // indirect
27@@ -27,6 +29,7 @@ require (
28 github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
29 github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
30 github.com/creack/pty v1.1.21 // indirect
31+ github.com/dlclark/regexp2 v1.11.0 // indirect
32 github.com/dustin/go-humanize v1.0.1 // indirect
33 github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
34 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
35@@ -35,32 +38,25 @@ require (
36 github.com/go-logfmt/logfmt v0.6.0 // indirect
37 github.com/gobwas/glob v0.2.3 // indirect
38 github.com/golang-jwt/jwt/v5 v5.1.0 // indirect
39- github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
40 github.com/google/uuid v1.4.0 // indirect
41- github.com/jmoiron/sqlx v1.3.5 // indirect
42 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
43- github.com/kr/fs v0.1.0 // indirect
44 github.com/lib/pq v1.10.9 // indirect
45 github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
46 github.com/mattn/go-isatty v0.0.20 // indirect
47 github.com/mattn/go-localereader v0.0.1 // indirect
48 github.com/mattn/go-runewidth v0.0.15 // indirect
49 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 // indirect
50- github.com/mmcloughlin/md4 v0.1.2 // indirect
51 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
52 github.com/muesli/cancelreader v0.2.2 // indirect
53 github.com/muesli/reflow v0.3.0 // indirect
54 github.com/muesli/termenv v0.15.2 // indirect
55- github.com/pkg/sftp v1.13.6 // indirect
56 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
57 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
58 github.com/rivo/uniseg v0.4.7 // indirect
59 github.com/rubyist/tracerx v0.0.0-20170927163412-787959303086 // indirect
60 github.com/russross/blackfriday/v2 v2.1.0 // indirect
61 github.com/sergi/go-diff v1.1.0 // indirect
62- github.com/urfave/cli/v2 v2.27.2 // indirect
63 github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
64- golang.org/x/crypto v0.21.0 // indirect
65 golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect
66 golang.org/x/mod v0.14.0 // indirect
67 golang.org/x/sync v0.6.0 // indirect
68@@ -77,7 +73,6 @@ require (
69 modernc.org/mathutil v1.6.0 // indirect
70 modernc.org/memory v1.7.2 // indirect
71 modernc.org/opt v0.1.3 // indirect
72- modernc.org/sqlite v1.27.0 // indirect
73 modernc.org/strutil v1.1.3 // indirect
74 modernc.org/token v1.0.1 // indirect
75 )
M
go.sum
+10,
-38
1@@ -1,9 +1,11 @@
2-github.com/DavidGamba/go-getoptions v0.29.0 h1:cU8MjOyfAyPZke4hrgEuiGBJHS9PFYPAHve2fhDhdDk=
3-github.com/DavidGamba/go-getoptions v0.29.0/go.mod h1:zE97E3PR9P3BI/HKyNYgdMlYxodcuiC6W68KIgeYT84=
4+github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU=
5+github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
6+github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI=
7+github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk=
8+github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
9+github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
10 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
11 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
12-github.com/antoniomika/go-rsync-receiver v0.0.0-20231110145728-c94949e1ab7d h1:NyzUTxebDLLdtNu1gY5hn/amdAEnKG9DOawz82LwNTY=
13-github.com/antoniomika/go-rsync-receiver v0.0.0-20231110145728-c94949e1ab7d/go.mod h1:zmqePVIo1hp+WEKxERLLGHJBDOr8/z/T4eFqXgWIw1w=
14 github.com/aymanbagabas/git-module v1.8.4-0.20231101154130-8d27204ac6d2 h1:3w5KT+shE3hzWhORGiu2liVjEoaCEXm9uZP47+Gw4So=
15 github.com/aymanbagabas/git-module v1.8.4-0.20231101154130-8d27204ac6d2/go.mod h1:d4gQ7/3/S2sPq4NnKdtAgUOVr6XtLpWFtxyVV5/+76U=
16 github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
17@@ -41,6 +43,8 @@ github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr
18 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
19 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
20 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
21+github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
22+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
23 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
24 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
25 github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 h1:mtDjlmloH7ytdblogrMz1/8Hqua1y8B4ID+bh3rvod0=
26@@ -64,16 +68,14 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
27 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
28 github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
29 github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
30-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
31-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
32 github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
33 github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
34+github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
35+github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
36 github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
37 github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
38 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
39 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
40-github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
41-github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
42 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
43 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
44 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
45@@ -100,8 +102,6 @@ github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwp
46 github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
47 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 h1:Pijfgr7ZuvX7QIQiEwLdRVr3RoMG+i0SbBO1Qu+7yVk=
48 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
49-github.com/mmcloughlin/md4 v0.1.2 h1:kGYl+iNbxhyz4u76ka9a+0TXP9KWt/LmnM0QhZwhcBo=
50-github.com/mmcloughlin/md4 v0.1.2/go.mod h1:AAxFX59fddW0IguqNzWlf1lazh1+rXeIt/Bj49cqDTQ=
51 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
52 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
53 github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
54@@ -110,12 +110,8 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
55 github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
56 github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
57 github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
58-github.com/picosh/send v0.0.0-20240217194807-77b972121e63 h1:VSSbAejFzj2KBThfVnMcNXQwzHmwjPUridgi29LxihU=
59-github.com/picosh/send v0.0.0-20240217194807-77b972121e63/go.mod h1:1JCq0NVOdTDenQ0/Kd8e4rP80lu06UHJJ+6dQxhcpew=
60 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
61 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
62-github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
63-github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
64 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
65 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
66 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
67@@ -147,55 +143,31 @@ github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
68 github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
69 github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
70 github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
71-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
72 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
73 golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
74-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
75-golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
76 golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
77 golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
78 golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 h1:mchzmB1XO2pMaKFRqk/+MV3mgGG96aqaPXaMifQU47w=
79 golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
80-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
81 golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
82 golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
83 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
84-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
85-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
86-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
87-golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
88-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
89-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
90 golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
91 golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
92 golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
93 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
94 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
95-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
96-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
97-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
98-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
99 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
100 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
101 golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
102 golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
103-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
104-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
105-golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
106 golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
107 golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
108 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
109-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
110-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
111-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
112 golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
113 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
114-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
115-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
116-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
117 golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
118 golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
119-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
120 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
121 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
122 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
M
pr.go
+14,
-26
1@@ -4,20 +4,18 @@ import (
2 "bytes"
3 "fmt"
4 "io"
5- "os"
6- "path/filepath"
7 "time"
8
9 "github.com/bluekeyes/go-gitdiff/gitdiff"
10- "github.com/charmbracelet/soft-serve/pkg/git"
11 )
12
13 type GitPatchRequest interface {
14- GetRepos() ([]string, error)
15+ GetRepos() ([]Repo, error)
16 SubmitPatchRequest(pubkey string, repoID string, patches io.Reader) (*PatchRequest, error)
17 SubmitPatch(pubkey string, prID int64, review bool, patch io.Reader) (*Patch, error)
18 GetPatchRequestByID(prID int64) (*PatchRequest, error)
19 GetPatchRequests() ([]*PatchRequest, error)
20+ GetPatchRequestsByRepoID(repoID string) ([]*PatchRequest, error)
21 GetPatchesByPrID(prID int64) ([]*Patch, error)
22 UpdatePatchRequest(prID int64, status string) error
23 }
24@@ -29,18 +27,8 @@ type PrCmd struct {
25 var _ GitPatchRequest = PrCmd{}
26 var _ GitPatchRequest = (*PrCmd)(nil)
27
28-func (pr PrCmd) GetRepos() ([]string, error) {
29- repos := []string{}
30- entries, err := os.ReadDir(pr.Backend.ReposDir())
31- if err != nil {
32- return repos, err
33- }
34- for _, entry := range entries {
35- if entry.IsDir() {
36- repos = append(repos, entry.Name())
37- }
38- }
39- return repos, nil
40+func (pr PrCmd) GetRepos() ([]Repo, error) {
41+ return pr.Backend.Cfg.Repos, nil
42 }
43
44 func (pr PrCmd) GetPatchesByPrID(prID int64) ([]*Patch, error) {
45@@ -68,6 +56,16 @@ func (cmd PrCmd) GetPatchRequests() ([]*PatchRequest, error) {
46 return prs, err
47 }
48
49+func (cmd PrCmd) GetPatchRequestsByRepoID(repoID string) ([]*PatchRequest, error) {
50+ prs := []*PatchRequest{}
51+ err := cmd.Backend.DB.Select(
52+ &prs,
53+ "SELECT * FROM patch_requests WHERE repo_id=?",
54+ repoID,
55+ )
56+ return prs, err
57+}
58+
59 func (cmd PrCmd) GetPatchRequestByID(prID int64) (*PatchRequest, error) {
60 pr := PatchRequest{}
61 err := cmd.Backend.DB.Get(
62@@ -132,16 +130,6 @@ func (cmd PrCmd) SubmitPatch(pubkey string, prID int64, review bool, patch io.Re
63 }
64
65 func (cmd PrCmd) SubmitPatchRequest(pubkey string, repoID string, patches io.Reader) (*PatchRequest, error) {
66- err := git.EnsureWithin(cmd.Backend.ReposDir(), repoID)
67- if err != nil {
68- return nil, err
69- }
70- loc := filepath.Join(cmd.Backend.ReposDir(), repoID)
71- _, err = os.Stat(loc)
72- if os.IsNotExist(err) {
73- return nil, fmt.Errorf("repo does not exist: %s", loc)
74- }
75-
76 // need to read io.Reader from session twice
77 var buf bytes.Buffer
78 tee := io.TeeReader(patches, &buf)
M
web.go
+275,
-19
1@@ -1,25 +1,57 @@
2 package git
3
4 import (
5+ "bytes"
6 "context"
7 "fmt"
8+ "html/template"
9 "log/slog"
10 "net/http"
11 "os"
12 "path/filepath"
13+ "strconv"
14+ "time"
15+
16+ "github.com/alecthomas/chroma/v2"
17+ formatterHtml "github.com/alecthomas/chroma/v2/formatters/html"
18+ "github.com/alecthomas/chroma/v2/lexers"
19+ "github.com/alecthomas/chroma/v2/styles"
20 )
21
22-type ctxPr struct{}
23+type WebCtx struct {
24+ Pr *PrCmd
25+ Backend *Backend
26+ Formatter *formatterHtml.Formatter
27+ Logger *slog.Logger
28+ Theme *chroma.Style
29+}
30+
31+type ctxWeb struct{}
32
33-func getPrCtx(r *http.Request) (*PrCmd, error) {
34- pr, ok := r.Context().Value(ctxPr{}).(*PrCmd)
35- if pr == nil || !ok {
36- return pr, fmt.Errorf("pr not set on `r.Context()` for connection")
37+func getWebCtx(r *http.Request) (*WebCtx, error) {
38+ data, ok := r.Context().Value(ctxWeb{}).(*WebCtx)
39+ if data == nil || !ok {
40+ return data, fmt.Errorf("webCtx not set on `r.Context()` for connection")
41 }
42- return pr, nil
43+ return data, nil
44 }
45-func setPrCtx(ctx context.Context, pr *PrCmd) context.Context {
46- return context.WithValue(ctx, ctxPr{}, pr)
47+func setWebCtx(ctx context.Context, web *WebCtx) context.Context {
48+ return context.WithValue(ctx, ctxWeb{}, web)
49+}
50+
51+// converts contents of files in git tree to pretty formatted code
52+func parseText(formatter *formatterHtml.Formatter, theme *chroma.Style, text string) (string, error) {
53+ lexer := lexers.Get("diff")
54+ iterator, err := lexer.Tokenise(nil, text)
55+ if err != nil {
56+ return text, err
57+ }
58+ var buf bytes.Buffer
59+ err = formatter.Format(&buf, theme, iterator)
60+ if err != nil {
61+ return text, err
62+ }
63+ return buf.String(), nil
64 }
65
66 func ctxMdw(ctx context.Context, handler http.HandlerFunc) http.HandlerFunc {
67@@ -28,26 +60,232 @@ func ctxMdw(ctx context.Context, handler http.HandlerFunc) http.HandlerFunc {
68 }
69 }
70
71-func prHandler(w http.ResponseWriter, r *http.Request) {
72- pr, err := getPrCtx(r)
73+type TemplateData struct {
74+ Title string
75+ Body template.HTML
76+}
77+
78+func getTemplate() *template.Template {
79+ str := `<!doctype html>
80+<html lang="en">
81+ <head>
82+ <title>{{.Title}}</title>
83+ <link rel="stylesheet" href="https://pico.sh/smol.css" />
84+ <link rel="stylesheet" href="/syntax.css" />
85+ </head>
86+ <body class="container">
87+ {{.Body}}
88+ </body>
89+</html>`
90+ tmpl := template.Must(template.New("main").Parse(str))
91+ return tmpl
92+}
93+
94+func repoListHandler(w http.ResponseWriter, r *http.Request) {
95+ web, err := getWebCtx(r)
96 if err != nil {
97 fmt.Println(err)
98 w.WriteHeader(http.StatusInternalServerError)
99 return
100 }
101
102- str := "Patch Requests\n"
103- prs, err := pr.GetPatchRequests()
104+ str := `<h1 class="text-2xl">Repos</h1>`
105+ repos, err := web.Pr.GetRepos()
106 if err != nil {
107- pr.Backend.Logger.Error("cannot get prs", "err", err)
108+ web.Pr.Backend.Logger.Error("cannot get repos", "err", err)
109+ w.WriteHeader(http.StatusInternalServerError)
110+ return
111+ }
112+
113+ str += "<ul>"
114+ for _, repo := range repos {
115+ str += fmt.Sprintf(
116+ `<li><a href="%s">%s</a></li>`,
117+ template.URL("/repos/"+repo.ID),
118+ repo.ID,
119+ )
120+ }
121+ str += "</ul>"
122+
123+ w.Header().Set("content-type", "text/html")
124+ tmpl := getTemplate()
125+ err = tmpl.Execute(w, TemplateData{
126+ Title: "Repos",
127+ Body: template.HTML(str),
128+ })
129+ if err != nil {
130+ fmt.Println(err)
131+ }
132+}
133+
134+func prListHandler(w http.ResponseWriter, r *http.Request) {
135+ repoID := r.PathValue("id")
136+
137+ web, err := getWebCtx(r)
138+ if err != nil {
139+ fmt.Println(err)
140+ w.WriteHeader(http.StatusInternalServerError)
141+ return
142+ }
143+
144+ str := `<h1 class="text-2xl">Patch Requests</h1>`
145+ prs, err := web.Pr.GetPatchRequestsByRepoID(repoID)
146+ if err != nil {
147+ web.Pr.Backend.Logger.Error("cannot get prs", "err", err)
148 w.WriteHeader(http.StatusInternalServerError)
149 return
150 }
151
152 for _, curpr := range prs {
153- str += fmt.Sprintf("%d\t%s\t%s\t%s\n", curpr.ID, curpr.RepoID, curpr.Name, curpr.Pubkey)
154+ row := `
155+<div class="group-h">
156+ <div>%d</div>
157+ <div><a href="%s">%s</a></div>
158+ <div>%s</div>
159+</div>`
160+ str += fmt.Sprintf(
161+ row,
162+ curpr.ID,
163+ template.URL(fmt.Sprintf("/prs/%d", curpr.ID)),
164+ curpr.Name,
165+ curpr.Pubkey,
166+ )
167+ }
168+
169+ w.Header().Set("content-type", "text/html")
170+ tmpl := getTemplate()
171+ err = tmpl.Execute(w, TemplateData{
172+ Title: "Patch Requests",
173+ Body: template.HTML(str),
174+ })
175+ if err != nil {
176+ fmt.Println(err)
177+ }
178+}
179+
180+func header(pr *PatchRequest, page string) string {
181+ str := fmt.Sprintf(`<h1 class="text-2xl">%s</h1>`, pr.Name)
182+ str += fmt.Sprintf("<div>[%s] %s %s</div>", pr.Status, pr.CreatedAt.Format(time.DateTime), pr.Pubkey)
183+ if page == "pr" {
184+ str += fmt.Sprintf(`<div><strong>summary</strong> · <a href="/prs/%d/patches">patches</a></div>`, pr.ID)
185+ } else {
186+ str += fmt.Sprintf(`<div><a href="/prs/%d">summary</a> · <strong>patches</strong></div>`, pr.ID)
187+ }
188+ return str
189+}
190+
191+func prHandler(w http.ResponseWriter, r *http.Request) {
192+ id := r.PathValue("id")
193+ prID, err := strconv.Atoi(id)
194+ if err != nil {
195+ fmt.Println(err)
196+ w.WriteHeader(http.StatusUnprocessableEntity)
197+ return
198+ }
199+
200+ web, err := getWebCtx(r)
201+ if err != nil {
202+ fmt.Println(err)
203+ w.WriteHeader(http.StatusInternalServerError)
204+ return
205+ }
206+
207+ pr, err := web.Pr.GetPatchRequestByID(int64(prID))
208+ if err != nil {
209+ web.Pr.Backend.Logger.Error("cannot get prs", "err", err)
210+ w.WriteHeader(http.StatusInternalServerError)
211+ return
212+ }
213+
214+ str := header(pr, "pr")
215+ str += fmt.Sprintf("<p>%s</p>", pr.Text)
216+
217+ w.Header().Set("content-type", "text/html")
218+ tmpl := getTemplate()
219+ err = tmpl.Execute(w, TemplateData{
220+ Title: fmt.Sprintf("%s (%s)", pr.Name, pr.Status),
221+ Body: template.HTML(str),
222+ })
223+ if err != nil {
224+ fmt.Println(err)
225+ }
226+}
227+
228+func prPatchesHandler(w http.ResponseWriter, r *http.Request) {
229+ id := r.PathValue("id")
230+ prID, err := strconv.Atoi(id)
231+ if err != nil {
232+ fmt.Println(err)
233+ w.WriteHeader(http.StatusUnprocessableEntity)
234+ return
235+ }
236+
237+ web, err := getWebCtx(r)
238+ if err != nil {
239+ fmt.Println(err)
240+ w.WriteHeader(http.StatusInternalServerError)
241+ return
242+ }
243+
244+ pr, err := web.Pr.GetPatchRequestByID(int64(prID))
245+ if err != nil {
246+ web.Pr.Backend.Logger.Error("cannot get prs", "err", err)
247+ w.WriteHeader(http.StatusInternalServerError)
248+ return
249+ }
250+
251+ str := header(pr, "patches")
252+
253+ patches, err := web.Pr.GetPatchesByPrID(int64(prID))
254+ if err != nil {
255+ web.Pr.Backend.Logger.Error("cannot get patches", "err", err)
256+ w.WriteHeader(http.StatusInternalServerError)
257+ return
258+ }
259+
260+ for _, patch := range patches {
261+ rev := ""
262+ if patch.Review {
263+ rev = "[review]"
264+ }
265+ diffStr, err := parseText(web.Formatter, web.Theme, patch.RawText)
266+ if err != nil {
267+ w.WriteHeader(http.StatusUnprocessableEntity)
268+ return
269+ }
270+
271+ row := `
272+<h2 class="text-xl">%s %s</h2>
273+<div>%s</div>`
274+ str += fmt.Sprintf(
275+ row,
276+ patch.Title, rev,
277+ diffStr,
278+ )
279+ }
280+
281+ w.Header().Set("content-type", "text/html")
282+ tmpl := getTemplate()
283+ err = tmpl.Execute(w, TemplateData{
284+ Title: fmt.Sprintf("patches - %s", pr.Name),
285+ Body: template.HTML(str),
286+ })
287+ if err != nil {
288+ fmt.Println(err)
289+ }
290+}
291+
292+func chromaStyleHandler(w http.ResponseWriter, r *http.Request) {
293+ web, err := getWebCtx(r)
294+ if err != nil {
295+ w.WriteHeader(http.StatusUnprocessableEntity)
296+ return
297+ }
298+ w.Header().Add("content-type", "text/css")
299+ err = web.Formatter.WriteCSS(w, web.Theme)
300+ if err != nil {
301+ fmt.Println(err)
302 }
303- fmt.Fprintf(w, str)
304 }
305
306 func StartWebServer() {
307@@ -72,18 +310,36 @@ func StartWebServer() {
308 be := &Backend{
309 DB: dbh,
310 Logger: logger,
311+ Cfg: cfg,
312 }
313 prCmd := &PrCmd{
314 Backend: be,
315 }
316+ formatter := formatterHtml.New(
317+ formatterHtml.WithLineNumbers(true),
318+ formatterHtml.WithLinkableLineNumbers(true, ""),
319+ formatterHtml.WithClasses(true),
320+ )
321+ web := &WebCtx{
322+ Pr: prCmd,
323+ Backend: be,
324+ Logger: logger,
325+ Formatter: formatter,
326+ Theme: styles.Get("dracula"),
327+ }
328 ctx := context.Background()
329- ctx = setPrCtx(ctx, prCmd)
330+ ctx = setWebCtx(ctx, web)
331
332- mux := http.NewServeMux()
333- mux.HandleFunc("/", ctxMdw(ctx, prHandler))
334+ // ensure legacy router is disabled
335+ // GODEBUG=httpmuxgo121=0
336+ http.HandleFunc("GET /prs/{id}/patches", ctxMdw(ctx, prPatchesHandler))
337+ http.HandleFunc("GET /prs/{id}", ctxMdw(ctx, prHandler))
338+ http.HandleFunc("GET /repos/{id}", ctxMdw(ctx, prListHandler))
339+ http.HandleFunc("GET /", ctxMdw(ctx, repoListHandler))
340+ http.HandleFunc("GET /syntax.css", ctxMdw(ctx, chromaStyleHandler))
341
342 logger.Info("starting web server", "addr", addr)
343- err = http.ListenAndServe(addr, mux)
344+ err = http.ListenAndServe(addr, nil)
345 if err != nil {
346 logger.Error("listen", "err", err)
347 }