web frontend for git (tangled's grandpa)
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

all: init

+462
+1
.gitignore
··· 1 + legit
+7
config.yaml
··· 1 + git: 2 + scanPath: /home/icy/code/tmp 3 + template: 4 + dir: ./templates 5 + meta: 6 + title: git good 7 + description: i think it's a skill issue
+35
config/config.go
··· 1 + package config 2 + 3 + import ( 4 + "fmt" 5 + "os" 6 + 7 + "gopkg.in/yaml.v3" 8 + ) 9 + 10 + type Config struct { 11 + Git struct { 12 + ScanPath string `yaml:"scanPath"` 13 + } `yaml:"git"` 14 + Template struct { 15 + Dir string `yaml:"dir"` 16 + } `yaml:"template"` 17 + Meta struct { 18 + Title string `yaml:"title"` 19 + Description string `yaml:"description"` 20 + } `yaml:"meta"` 21 + } 22 + 23 + func Read(f string) (*Config, error) { 24 + b, err := os.ReadFile(f) 25 + if err != nil { 26 + return nil, fmt.Errorf("reading config: %w", err) 27 + } 28 + 29 + c := Config{} 30 + if err := yaml.Unmarshal(b, &c); err != nil { 31 + return nil, fmt.Errorf("parsing config: %w", err) 32 + } 33 + 34 + return &c, nil 35 + }
+88
git/git.go
··· 1 + package git 2 + 3 + import ( 4 + "fmt" 5 + 6 + "github.com/go-git/go-git/v5" 7 + "github.com/go-git/go-git/v5/plumbing" 8 + "github.com/go-git/go-git/v5/plumbing/object" 9 + ) 10 + 11 + func AllCommits(r *git.Repository) ([]*object.Commit, error) { 12 + ci, err := r.Log(&git.LogOptions{All: true}) 13 + if err != nil { 14 + return nil, fmt.Errorf("all commits: %w", err) 15 + } 16 + 17 + commits := []*object.Commit{} 18 + ci.ForEach(func(c *object.Commit) error { 19 + commits = append(commits, c) 20 + return nil 21 + }) 22 + 23 + return commits, nil 24 + } 25 + 26 + // A nicer git tree representation. 27 + type NiceTree struct { 28 + Name string 29 + Mode string 30 + Size int64 31 + IsFile bool 32 + } 33 + 34 + func FilesAtHead(r *git.Repository, path string) ([]NiceTree, error) { 35 + head, err := r.Head() 36 + if err != nil { 37 + return nil, fmt.Errorf("getting head: %w", err) 38 + } 39 + 40 + return FilesAtRef(r, head, path) 41 + } 42 + 43 + func FilesAtRef(r *git.Repository, ref *plumbing.Reference, path string) ([]NiceTree, error) { 44 + c, err := r.CommitObject(ref.Hash()) 45 + if err != nil { 46 + return nil, fmt.Errorf("commit object: %w", err) 47 + } 48 + 49 + files := []NiceTree{} 50 + tree, err := c.Tree() 51 + if err != nil { 52 + return nil, fmt.Errorf("file tree: %w", err) 53 + } 54 + 55 + if path == "" { 56 + files = makeNiceTree(tree.Entries) 57 + } else { 58 + o, err := tree.FindEntry(path) 59 + if err != nil { 60 + return nil, err 61 + } 62 + 63 + if !o.Mode.IsFile() { 64 + subtree, err := tree.Tree(path) 65 + if err != nil { 66 + return nil, err 67 + } 68 + 69 + files = makeNiceTree(subtree.Entries) 70 + } 71 + } 72 + 73 + return files, nil 74 + } 75 + 76 + func makeNiceTree(es []object.TreeEntry) []NiceTree { 77 + nts := []NiceTree{} 78 + for _, e := range es { 79 + mode, _ := e.Mode.ToOSFileMode() 80 + nts = append(nts, NiceTree{ 81 + Name: e.Name, 82 + Mode: mode.String(), 83 + IsFile: e.Mode.IsFile(), 84 + }) 85 + } 86 + 87 + return nts 88 + }
+30
go.mod
··· 1 + module icyphox.sh/legit 2 + 3 + go 1.19 4 + 5 + require ( 6 + github.com/alexedwards/flow v0.0.0-20220806114457-cf11be9e0e03 7 + github.com/go-git/go-git/v5 v5.5.0 8 + gopkg.in/yaml.v3 v3.0.0 9 + ) 10 + 11 + require ( 12 + github.com/Microsoft/go-winio v0.5.2 // indirect 13 + github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect 14 + github.com/acomagu/bufpipe v1.0.3 // indirect 15 + github.com/cloudflare/circl v1.1.0 // indirect 16 + github.com/emirpasic/gods v1.18.1 // indirect 17 + github.com/go-git/gcfg v1.5.0 // indirect 18 + github.com/go-git/go-billy/v5 v5.3.1 // indirect 19 + github.com/imdario/mergo v0.3.13 // indirect 20 + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 21 + github.com/kevinburke/ssh_config v1.2.0 // indirect 22 + github.com/pjbgf/sha1cd v0.2.0 // indirect 23 + github.com/sergi/go-diff v1.1.0 // indirect 24 + github.com/skeema/knownhosts v1.1.0 // indirect 25 + github.com/xanzy/ssh-agent v0.3.2 // indirect 26 + golang.org/x/crypto v0.3.0 // indirect 27 + golang.org/x/net v0.2.0 // indirect 28 + golang.org/x/sys v0.2.0 // indirect 29 + gopkg.in/warnings.v0 v0.1.2 // indirect 30 + )
+129
go.sum
··· 1 + github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= 2 + github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= 3 + github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I= 4 + github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= 5 + github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= 6 + github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= 7 + github.com/alexedwards/flow v0.0.0-20220806114457-cf11be9e0e03 h1:r07xZN3ENBWdxGuU/feCsnpsgHJ7+3uLm7cq9S0sqoI= 8 + github.com/alexedwards/flow v0.0.0-20220806114457-cf11be9e0e03/go.mod h1:1rjOQiOqQlmMdUMuvlJFjldqTnE/tQULE7qPIu4aq3U= 9 + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= 10 + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= 11 + github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 12 + github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 13 + github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= 14 + github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY= 15 + github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= 16 + github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 17 + github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 + github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 19 + github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 + github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= 21 + github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 22 + github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= 23 + github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= 24 + github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= 25 + github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= 26 + github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= 27 + github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= 28 + github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ= 29 + github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= 30 + github.com/go-git/go-git/v5 v5.5.0 h1:StO/ASRvk1Pp74tr7XQ0pQwKlCFignzzTF/NLKdQzUE= 31 + github.com/go-git/go-git/v5 v5.5.0/go.mod h1:g456XI30HAdt7GQtIf8JR6GDAdULGaR4KtfFtQa0uTg= 32 + github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 33 + github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 34 + github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= 35 + github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= 36 + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= 37 + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= 38 + github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= 39 + github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= 40 + github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 41 + github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 42 + github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 43 + github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 44 + github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 45 + github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 46 + github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 47 + github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 48 + github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= 49 + github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= 50 + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 51 + github.com/pjbgf/sha1cd v0.2.0 h1:gIsJVwjbRviE4gydidGztxH1IlJQoYBcCrwG4Dz8wvM= 52 + github.com/pjbgf/sha1cd v0.2.0/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M= 53 + github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 54 + github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 55 + github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 56 + github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 57 + github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= 58 + github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 59 + github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 60 + github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0= 61 + github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag= 62 + github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 63 + github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 64 + github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 65 + github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 66 + github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 67 + github.com/xanzy/ssh-agent v0.3.2 h1:eKj4SX2Fe7mui28ZgnFW5fmTz1EIr7ugo5s6wDxdHBM= 68 + github.com/xanzy/ssh-agent v0.3.2/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= 69 + github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 70 + golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 71 + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 72 + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 73 + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 74 + golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 75 + golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= 76 + golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= 77 + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 78 + golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 79 + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 80 + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 81 + golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 82 + golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 83 + golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= 84 + golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= 85 + golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 86 + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 87 + golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 88 + golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 89 + golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 90 + golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 91 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 92 + golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 93 + golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 94 + golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 95 + golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 96 + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 97 + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 100 + golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 101 + golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= 102 + golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 106 + golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= 107 + golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= 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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 111 + golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 112 + golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= 113 + golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 118 + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 119 + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 120 + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 121 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 122 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 123 + gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= 124 + gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 125 + gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 126 + gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 127 + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 128 + gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= 129 + gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+24
main.go
··· 1 + package main 2 + 3 + import ( 4 + "flag" 5 + "log" 6 + "net/http" 7 + 8 + "icyphox.sh/legit/config" 9 + "icyphox.sh/legit/routes" 10 + ) 11 + 12 + func main() { 13 + var cfg string 14 + flag.StringVar(&cfg, "config", "./config.yaml", "path to config file") 15 + flag.Parse() 16 + 17 + c, err := config.Read(cfg) 18 + if err != nil { 19 + log.Fatal(err) 20 + } 21 + 22 + mux := routes.Handlers(c) 23 + log.Fatal(http.ListenAndServe(":5555", mux)) 24 + }
+14
routes/handler.go
··· 1 + package routes 2 + 3 + import ( 4 + "github.com/alexedwards/flow" 5 + "icyphox.sh/legit/config" 6 + ) 7 + 8 + func Handlers(c *config.Config) *flow.Mux { 9 + mux := flow.New() 10 + d := deps{c} 11 + mux.HandleFunc("/:name", d.Repo, "GET") 12 + mux.HandleFunc("/:name/tree/...", d.Repo, "GET") 13 + return mux 14 + }
+50
routes/routes.go
··· 1 + package routes 2 + 3 + import ( 4 + "html/template" 5 + "log" 6 + "net/http" 7 + "path/filepath" 8 + 9 + "github.com/alexedwards/flow" 10 + gogit "github.com/go-git/go-git/v5" 11 + "icyphox.sh/legit/config" 12 + "icyphox.sh/legit/git" 13 + ) 14 + 15 + type deps struct { 16 + c *config.Config 17 + } 18 + 19 + func (d *deps) Repo(w http.ResponseWriter, r *http.Request) { 20 + name := flow.Param(r.Context(), "name") 21 + treePath := flow.Param(r.Context(), "...") 22 + 23 + name = filepath.Clean(name) 24 + // TODO: remove .git 25 + path := filepath.Join(d.c.Git.ScanPath, name+".git") 26 + repo, err := gogit.PlainOpen(path) 27 + if err != nil { 28 + Write404(w, *d.c) 29 + return 30 + } 31 + 32 + files, err := git.FilesAtHead(repo, treePath) 33 + if err != nil { 34 + Write500(w, *d.c) 35 + log.Println(err) 36 + } 37 + 38 + tpath := filepath.Join(d.c.Template.Dir, "*") 39 + t := template.Must(template.ParseGlob(tpath)) 40 + 41 + data := make(map[string]interface{}) 42 + data["files"] = files 43 + data["meta"] = d.c.Meta 44 + 45 + if err := t.ExecuteTemplate(w, "repo", data); err != nil { 46 + Write500(w, *d.c) 47 + log.Println(err) 48 + return 49 + } 50 + }
+32
routes/template.go
··· 1 + package routes 2 + 3 + import ( 4 + "html/template" 5 + "net/http" 6 + "os" 7 + "path/filepath" 8 + 9 + "icyphox.sh/legit/config" 10 + ) 11 + 12 + func Write404(w http.ResponseWriter, c config.Config) { 13 + w.WriteHeader(404) 14 + tpath := filepath.Join(c.Template.Dir, "404.html") 15 + t := template.Must(template.ParseFiles(tpath)) 16 + t.Execute(w, nil) 17 + } 18 + 19 + func Write500(w http.ResponseWriter, c config.Config) { 20 + w.WriteHeader(500) 21 + tpath := filepath.Join(c.Template.Dir, "500.html") 22 + t := template.Must(template.ParseFiles(tpath)) 23 + t.Execute(w, nil) 24 + } 25 + 26 + func funcMap() template.FuncMap { 27 + return template.FuncMap{ 28 + "prettyMode": func(mode uint32) string { 29 + return os.FileMode(mode).String() 30 + }, 31 + } 32 + }
+7
templates/404.html
··· 1 + <html> 2 + <title>404</title> 3 + {{ template "header" . }} 4 + <body> 5 + 404 &mdash; nothing like that here 6 + </body> 7 + </html>
+7
templates/500.html
··· 1 + <html> 2 + <title>500</title> 3 + {{ template "header" . }} 4 + <body> 5 + 500 &mdash; something broke! 6 + </body> 7 + </html>
+7
templates/head.html
··· 1 + {{ define "head" }} 2 + <head> 3 + <meta charset="utf-8"> 4 + <meta name="viewport" content="width=device-width, initial-scale=1"> 5 + <!-- other meta tags here --> 6 + </head> 7 + {{ end }}
+9
templates/nav.html
··· 1 + {{ define "nav" }} 2 + <nav> 3 + <ul> 4 + <li>some 5 + <li>thing 6 + <li>here 7 + </ul> 8 + </nav> 9 + {{ end }}
+22
templates/repo.html
··· 1 + {{ define "repo" }} 2 + <html> 3 + {{ template "head" . }} 4 + 5 + <header> 6 + <h1>{{ .meta.Title }}</h1> 7 + <h2>{{ .meta.Description }}</h2> 8 + </header> 9 + <body> 10 + {{ template "nav" . }} 11 + <main> 12 + {{ range .files }} 13 + {{ if .IsFile }} 14 + <p>{{ .Mode }} {{ .Name }} {{ .Size }} </p> 15 + {{ else }} 16 + <p>d-------- {{ .Name}}/</p> 17 + {{ end }} 18 + {{ end }} 19 + </main> 20 + </body> 21 + </html> 22 + {{ end }}