+13
-13
cmd/knotserver/main.go
+13
-13
cmd/knotserver/main.go
···
1
1
package main
2
2
3
3
import (
4
-
"flag"
4
+
"context"
5
5
"fmt"
6
6
"log"
7
7
"log/slog"
8
8
"net/http"
9
9
"os"
10
+
"os/signal"
11
+
"syscall"
10
12
11
-
"github.com/icyphox/bild/config"
12
-
"github.com/icyphox/bild/db"
13
13
"github.com/icyphox/bild/knotserver"
14
+
"github.com/icyphox/bild/knotserver/config"
14
15
)
15
16
16
17
func main() {
17
-
var cfg string
18
-
flag.StringVar(&cfg, "config", "./config.yaml", "path to config file")
19
-
flag.Parse()
18
+
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
19
+
defer stop()
20
20
21
21
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, nil)))
22
22
23
-
c, err := config.Read(cfg)
23
+
c, err := config.Load(ctx)
24
24
if err != nil {
25
25
log.Fatal(err)
26
26
}
27
-
db, err := db.Setup(c.Server.DBPath)
28
-
if err != nil {
29
-
log.Fatalf("failed to setup db: %s", err)
30
-
}
27
+
// db, err := db.Setup(c.Server.DBPath)
28
+
// if err != nil {
29
+
// log.Fatalf("failed to setup db: %s", err)
30
+
// }
31
31
32
-
mux, err := knotserver.Setup(c, db)
32
+
mux, err := knotserver.Setup(c, nil)
33
33
if err != nil {
34
34
log.Fatal(err)
35
35
}
36
36
37
-
addr := fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port)
37
+
addr := fmt.Sprintf("%s:%d", c.Host, c.Port)
38
38
39
39
log.Println("starting main server on", addr)
40
40
log.Fatal(http.ListenAndServe(addr, mux))
+5
git/git.go
+5
git/git.go
···
202
202
}
203
203
204
204
func (g *GitRepo) FindMainBranch(branches []string) (string, error) {
205
+
branches = append(branches, []string{
206
+
"main",
207
+
"master",
208
+
"trunk",
209
+
}...)
205
210
for _, b := range branches {
206
211
_, err := g.r.ResolveRevision(plumbing.Revision(b))
207
212
if err == nil {
+1
go.mod
+1
go.mod
···
17
17
github.com/mattn/go-sqlite3 v1.14.24
18
18
github.com/microcosm-cc/bluemonday v1.0.27
19
19
github.com/russross/blackfriday/v2 v2.1.0
20
+
github.com/sethvargo/go-envconfig v1.1.0
20
21
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e
21
22
golang.org/x/crypto v0.31.0
22
23
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
+2
go.sum
+2
go.sum
···
210
210
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
211
211
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
212
212
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
213
+
github.com/sethvargo/go-envconfig v1.1.0 h1:cWZiJxeTm7AlCvzGXrEXaSTCNgip5oJepekh/BOQuog=
214
+
github.com/sethvargo/go-envconfig v1.1.0/go.mod h1:JLd0KFWQYzyENqnEPWWZ49i4vzZo/6nRidxI8YvGiHw=
213
215
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
214
216
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
215
217
github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag=
+49
knotserver/config/config.go
+49
knotserver/config/config.go
···
1
+
package config
2
+
3
+
import (
4
+
"context"
5
+
6
+
"github.com/sethvargo/go-envconfig"
7
+
)
8
+
9
+
type Repo struct {
10
+
ScanPath string `env:"SCAN_PATH, default=/home/git"`
11
+
Readme []string `env:"README"`
12
+
MainBranch []string `env:"MAIN_BRANCH"`
13
+
}
14
+
15
+
type Config struct {
16
+
Host string `env:"KNOTSERVER_HOST, default=0.0.0.0"`
17
+
Port int `env:"KNOTSERVER_PORT, default=5555"`
18
+
Secret string `env:"KNOTSERVER_SECRET, required"`
19
+
20
+
Repo Repo `env:",prefix=KNOTSERVER_REPO_"`
21
+
}
22
+
23
+
func Load(ctx context.Context) (*Config, error) {
24
+
var cfg Config
25
+
err := envconfig.Process(ctx, &cfg)
26
+
if err != nil {
27
+
return nil, err
28
+
}
29
+
30
+
if cfg.Repo.Readme == nil {
31
+
cfg.Repo.Readme = []string{
32
+
"README.md", "readme.md",
33
+
"README",
34
+
"readme",
35
+
"README.markdown",
36
+
"readme.markdown",
37
+
"README.txt",
38
+
"readme.txt",
39
+
"README.rst",
40
+
"readme.rst",
41
+
"README.org",
42
+
"readme.org",
43
+
"README.asciidoc",
44
+
"readme.asciidoc",
45
+
}
46
+
}
47
+
48
+
return &cfg, nil
49
+
}
+1
-3
knotserver/file.go
+1
-3
knotserver/file.go
···
7
7
"net/http"
8
8
"strings"
9
9
10
-
"github.com/icyphox/bild/git"
10
+
"github.com/icyphox/bild/knotserver/git"
11
11
)
12
12
13
13
func (h *Handle) listFiles(files []git.NiceTree, data map[string]any, w http.ResponseWriter) {
14
14
data["files"] = files
15
-
data["meta"] = h.c.Meta
16
15
17
16
writeJSON(w, data)
18
17
return
···
60
59
61
60
data["linecount"] = lines
62
61
data["content"] = content
63
-
data["meta"] = h.c.Meta
64
62
65
63
writeJSON(w, data)
66
64
return
+5
knotserver/git/git.go
+5
knotserver/git/git.go
···
202
202
}
203
203
204
204
func (g *GitRepo) FindMainBranch(branches []string) (string, error) {
205
+
branches = append(branches, []string{
206
+
"main",
207
+
"master",
208
+
"trunk",
209
+
}...)
205
210
for _, b := range branches {
206
211
_, err := g.r.ResolveRevision(plumbing.Revision(b))
207
212
if err == nil {
+5
-7
knotserver/handler.go
+5
-7
knotserver/handler.go
···
5
5
"net/http"
6
6
7
7
"github.com/go-chi/chi/v5"
8
-
"github.com/icyphox/bild/config"
9
8
"github.com/icyphox/bild/db"
9
+
"github.com/icyphox/bild/knotserver/config"
10
10
)
11
11
12
12
func Setup(c *config.Config, db *db.DB) (http.Handler, error) {
···
16
16
c: c,
17
17
db: db,
18
18
}
19
-
20
-
// r.Route("/repo", func(r chi.Router) {
21
-
// r.Use(h.AuthMiddleware)
22
-
// r.Get("/new", h.NewRepo)
23
-
// r.Put("/new", h.NewRepo)
24
-
// })
25
19
26
20
r.Get("/", h.Index)
27
21
r.Route("/{did}", func(r chi.Router) {
···
44
38
r.Get("/commit/{ref}", h.Diff)
45
39
r.Get("/refs/", h.Refs)
46
40
})
41
+
})
42
+
43
+
r.Route("/repo", func(r chi.Router) {
44
+
r.Put("/new", h.NewRepo)
47
45
})
48
46
49
47
return r, nil
+55
-41
knotserver/routes.go
+55
-41
knotserver/routes.go
···
2
2
3
3
import (
4
4
"compress/gzip"
5
+
"encoding/json"
5
6
"errors"
6
7
"fmt"
7
8
"html/template"
···
13
14
14
15
"github.com/go-chi/chi/v5"
15
16
"github.com/go-git/go-git/v5/plumbing"
16
-
"github.com/icyphox/bild/git"
17
+
"github.com/go-git/go-git/v5/plumbing/object"
18
+
"github.com/icyphox/bild/knotserver/git"
17
19
"github.com/russross/blackfriday/v2"
18
20
)
19
21
···
84
86
data["readme"] = readmeContent
85
87
data["commits"] = commits
86
88
data["desc"] = getDescription(path)
87
-
data["servername"] = h.c.Server.Name
88
-
data["meta"] = h.c.Meta
89
89
90
90
writeJSON(w, data)
91
91
return
···
218
218
return
219
219
}
220
220
221
+
// Get page parameters
222
+
page := 1
223
+
pageSize := 30
224
+
225
+
if pageParam := r.URL.Query().Get("page"); pageParam != "" {
226
+
if p, err := strconv.Atoi(pageParam); err == nil && p > 0 {
227
+
page = p
228
+
}
229
+
}
230
+
231
+
if pageSizeParam := r.URL.Query().Get("per_page"); pageSizeParam != "" {
232
+
if ps, err := strconv.Atoi(pageSizeParam); err == nil && ps > 0 {
233
+
pageSize = ps
234
+
}
235
+
}
236
+
237
+
// Calculate pagination
238
+
start := (page - 1) * pageSize
239
+
end := start + pageSize
240
+
total := len(commits)
241
+
242
+
if start >= total {
243
+
commits = []*object.Commit{}
244
+
} else {
245
+
if end > total {
246
+
end = total
247
+
}
248
+
commits = commits[start:end]
249
+
}
250
+
221
251
data := make(map[string]interface{})
222
252
data["commits"] = commits
223
-
data["meta"] = h.c.Meta
224
253
data["ref"] = ref
225
254
data["desc"] = getDescription(path)
226
255
data["log"] = true
256
+
data["total"] = total
257
+
data["page"] = page
258
+
data["per_page"] = pageSize
227
259
228
260
writeJSON(w, data)
229
261
return
···
251
283
data["commit"] = diff.Commit
252
284
data["stat"] = diff.Stat
253
285
data["diff"] = diff.Diff
254
-
data["meta"] = h.c.Meta
255
286
data["ref"] = ref
256
287
data["desc"] = getDescription(path)
257
288
···
282
313
283
314
data := make(map[string]interface{})
284
315
285
-
data["meta"] = h.c.Meta
286
316
data["branches"] = branches
287
317
data["tags"] = tags
288
318
data["desc"] = getDescription(path)
···
291
321
return
292
322
}
293
323
294
-
func (h *Handle) ServeStatic(w http.ResponseWriter, r *http.Request) {
295
-
f := chi.URLParam(r, "file")
296
-
f = filepath.Clean(filepath.Join(h.c.Dirs.Static, f))
297
-
298
-
http.ServeFile(w, r, f)
299
-
}
300
-
301
324
// func (h *Handle) Keys(w http.ResponseWriter, r *http.Request) {
302
325
// session, _ := h.s.Get(r, "bild-session")
303
326
// did := session.Values["did"].(string)
···
361
384
// }
362
385
// }
363
386
364
-
// func (h *Handle) NewRepo(w http.ResponseWriter, r *http.Request) {
365
-
// session, _ := h.s.Get(r, "bild-session")
366
-
// did := session.Values["did"].(string)
367
-
// handle := session.Values["handle"].(string)
387
+
func (h *Handle) NewRepo(w http.ResponseWriter, r *http.Request) {
388
+
data := struct {
389
+
DID string `json:"did"`
390
+
Name string `json:"name"`
391
+
}{}
368
392
369
-
// switch r.Method {
370
-
// case http.MethodGet:
371
-
// if err := h.t.ExecuteTemplate(w, "repo/new", nil); err != nil {
372
-
// log.Println(err)
373
-
// return
374
-
// }
375
-
// case http.MethodPut:
376
-
// name := r.FormValue("name")
377
-
// description := r.FormValue("description")
393
+
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
394
+
writeError(w, "invalid request body", http.StatusBadRequest)
395
+
return
396
+
}
378
397
379
-
// repoPath := filepath.Join(h.c.Repo.ScanPath, did, name)
380
-
// err := git.InitBare(repoPath)
381
-
// if err != nil {
382
-
// h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.")
383
-
// return
384
-
// }
398
+
did := data.DID
399
+
name := data.Name
385
400
386
-
// err = h.db.AddRepo(did, name, description)
387
-
// if err != nil {
388
-
// h.WriteOOBNotice(w, "repo", "Error creating repo. Try again later.")
389
-
// return
390
-
// }
401
+
repoPath := filepath.Join(h.c.Repo.ScanPath, did, name)
402
+
err := git.InitBare(repoPath)
403
+
if err != nil {
404
+
writeError(w, err.Error(), http.StatusInternalServerError)
405
+
return
406
+
}
391
407
392
-
// w.Header().Set("HX-Redirect", fmt.Sprintf("/@%s/%s", handle, name))
393
-
// w.WriteHeader(http.StatusOK)
394
-
// }
395
-
// }
408
+
w.WriteHeader(http.StatusNoContent)
409
+
}
396
410
397
411
// func (h *Handle) Timeline(w http.ResponseWriter, r *http.Request) {
398
412
// session, err := h.s.Get(r, "bild-session")