From 7d245fbe8e8b5efe30ac134788eb4a49e17a6276 Mon Sep 17 00:00:00 2001 From: mleku Date: Sun, 27 Apr 2025 15:11:46 -0106 Subject: [PATCH] add results in binary encoding for events endpoint --- cmd/legit/.github/workflows/docker.yaml | 52 --- cmd/legit/config.yaml | 20 - cmd/legit/config/config.go | 57 --- cmd/legit/contrib/Dockerfile | 22 -- cmd/legit/contrib/docker-compose.yml | 14 - cmd/legit/contrib/legit.service | 17 - cmd/legit/flake.lock | 26 -- cmd/legit/flake.nix | 62 --- cmd/legit/git/diff.go | 119 ------ cmd/legit/git/git.go | 344 ----------------- cmd/legit/git/service/service.go | 121 ------ cmd/legit/git/service/write_flusher.go | 25 -- cmd/legit/git/tree.go | 66 ---- cmd/legit/go.mod | 42 -- cmd/legit/go.sum | 187 --------- cmd/legit/license | 23 -- cmd/legit/main.go | 36 -- cmd/legit/readme | 88 ----- cmd/legit/routes/git.go | 81 ---- cmd/legit/routes/handler.go | 49 --- cmd/legit/routes/routes.go | 486 ------------------------ cmd/legit/routes/template.go | 151 -------- cmd/legit/routes/util.go | 118 ------ cmd/legit/static/legit.png | Bin 1321 -> 0 bytes cmd/legit/static/style.css | 332 ---------------- cmd/legit/templates/404.html | 13 - cmd/legit/templates/500.html | 13 - cmd/legit/templates/commit.html | 104 ----- cmd/legit/templates/file.html | 36 -- cmd/legit/templates/head.html | 32 -- cmd/legit/templates/index.html | 21 - cmd/legit/templates/log.html | 25 -- cmd/legit/templates/nav.html | 14 - cmd/legit/templates/refs.html | 40 -- cmd/legit/templates/repo-header.html | 12 - cmd/legit/templates/repo.html | 38 -- cmd/legit/templates/tree.html | 55 --- cmd/legit/unveil.go | 29 -- cmd/legit/unveil_stub.go | 18 - go.mod | 1 + go.sum | 2 + openapi/http-configuration.go | 5 +- openapi/http-event.go | 1 + openapi/http-events.go | 58 ++- ratel/fetch-ids.go | 27 +- store/store_interface.go | 2 +- version | 2 +- 47 files changed, 73 insertions(+), 3013 deletions(-) delete mode 100644 cmd/legit/.github/workflows/docker.yaml delete mode 100644 cmd/legit/config.yaml delete mode 100644 cmd/legit/config/config.go delete mode 100644 cmd/legit/contrib/Dockerfile delete mode 100644 cmd/legit/contrib/docker-compose.yml delete mode 100644 cmd/legit/contrib/legit.service delete mode 100644 cmd/legit/flake.lock delete mode 100644 cmd/legit/flake.nix delete mode 100644 cmd/legit/git/diff.go delete mode 100644 cmd/legit/git/git.go delete mode 100644 cmd/legit/git/service/service.go delete mode 100644 cmd/legit/git/service/write_flusher.go delete mode 100644 cmd/legit/git/tree.go delete mode 100644 cmd/legit/go.mod delete mode 100644 cmd/legit/go.sum delete mode 100644 cmd/legit/license delete mode 100644 cmd/legit/main.go delete mode 100644 cmd/legit/readme delete mode 100644 cmd/legit/routes/git.go delete mode 100644 cmd/legit/routes/handler.go delete mode 100644 cmd/legit/routes/routes.go delete mode 100644 cmd/legit/routes/template.go delete mode 100644 cmd/legit/routes/util.go delete mode 100644 cmd/legit/static/legit.png delete mode 100644 cmd/legit/static/style.css delete mode 100644 cmd/legit/templates/404.html delete mode 100644 cmd/legit/templates/500.html delete mode 100644 cmd/legit/templates/commit.html delete mode 100644 cmd/legit/templates/file.html delete mode 100644 cmd/legit/templates/head.html delete mode 100644 cmd/legit/templates/index.html delete mode 100644 cmd/legit/templates/log.html delete mode 100644 cmd/legit/templates/nav.html delete mode 100644 cmd/legit/templates/refs.html delete mode 100644 cmd/legit/templates/repo-header.html delete mode 100644 cmd/legit/templates/repo.html delete mode 100644 cmd/legit/templates/tree.html delete mode 100644 cmd/legit/unveil.go delete mode 100644 cmd/legit/unveil_stub.go diff --git a/cmd/legit/.github/workflows/docker.yaml b/cmd/legit/.github/workflows/docker.yaml deleted file mode 100644 index 708cc0f..0000000 --- a/cmd/legit/.github/workflows/docker.yaml +++ /dev/null @@ -1,52 +0,0 @@ -name: build and push docker image - -on: - push: - branches: [master] - tags: ["*"] - -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - attestations: write - id-token: write - - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Copy Dockerfile to . - run: cp ./contrib/Dockerfile ./Dockerfile - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - - name: Build and push Docker image - uses: docker/build-push-action@v6 - with: - context: . - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - push: true - build-args: | - BUILDKIT_INLINE_CACHE=1 diff --git a/cmd/legit/config.yaml b/cmd/legit/config.yaml deleted file mode 100644 index 7a6066f..0000000 --- a/cmd/legit/config.yaml +++ /dev/null @@ -1,20 +0,0 @@ -repo: - scanPath: /var/www/git - readme: - - readme - - README - - readme.md - - README.md - mainBranch: - - master - - main -dirs: - templates: ./templates - static: ./static -meta: - title: icy does git - description: come get your free software -server: - name: git.icyphox.sh - host: 0.0.0.0 - port: 5555 diff --git a/cmd/legit/config/config.go b/cmd/legit/config/config.go deleted file mode 100644 index 3bcf9de..0000000 --- a/cmd/legit/config/config.go +++ /dev/null @@ -1,57 +0,0 @@ -package config - -import ( - "fmt" - "os" - "path/filepath" - - "gopkg.in/yaml.v3" -) - -type Config struct { - Repo struct { - ScanPath string `yaml:"scanPath"` - Readme []string `yaml:"readme"` - MainBranch []string `yaml:"mainBranch"` - Ignore []string `yaml:"ignore,omitempty"` - Unlisted []string `yaml:"unlisted,omitempty"` - } `yaml:"repo"` - Dirs struct { - Templates string `yaml:"templates"` - Static string `yaml:"static"` - } `yaml:"dirs"` - Meta struct { - Title string `yaml:"title"` - Description string `yaml:"description"` - SyntaxHighlight string `yaml:"syntaxHighlight"` - } `yaml:"meta"` - Server struct { - Name string `yaml:"name,omitempty"` - Host string `yaml:"host"` - Port int `yaml:"port"` - } `yaml:"server"` -} - -func Read(f string) (*Config, error) { - b, err := os.ReadFile(f) - if err != nil { - return nil, fmt.Errorf("reading config: %w", err) - } - - c := Config{} - if err := yaml.Unmarshal(b, &c); err != nil { - return nil, fmt.Errorf("parsing config: %w", err) - } - - if c.Repo.ScanPath, err = filepath.Abs(c.Repo.ScanPath); err != nil { - return nil, err - } - if c.Dirs.Templates, err = filepath.Abs(c.Dirs.Templates); err != nil { - return nil, err - } - if c.Dirs.Static, err = filepath.Abs(c.Dirs.Static); err != nil { - return nil, err - } - - return &c, nil -} diff --git a/cmd/legit/contrib/Dockerfile b/cmd/legit/contrib/Dockerfile deleted file mode 100644 index c36cba0..0000000 --- a/cmd/legit/contrib/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM golang:1.22-alpine AS builder - -WORKDIR /app - -COPY . . -RUN go mod download -RUN go mod verify - -RUN go build -o legit - -FROM scratch AS build-release-stage - -WORKDIR /app - -COPY static ./static -COPY templates ./templates -COPY config.yaml ./ -COPY --from=builder /app/legit ./ - -EXPOSE 5555 - -CMD ["./legit"] diff --git a/cmd/legit/contrib/docker-compose.yml b/cmd/legit/contrib/docker-compose.yml deleted file mode 100644 index 366a732..0000000 --- a/cmd/legit/contrib/docker-compose.yml +++ /dev/null @@ -1,14 +0,0 @@ -services: - legit: - container_name: legit - build: - context: ../ - dockerfile: contrib/Dockerfile - restart: unless-stopped - ports: - - "5555:5555" - volumes: - - /var/www/git:/var/www/git - - ../config.yaml:/app/config.yaml - - ../static:/app/static - - ../templates:/app/templates diff --git a/cmd/legit/contrib/legit.service b/cmd/legit/contrib/legit.service deleted file mode 100644 index e0193ed..0000000 --- a/cmd/legit/contrib/legit.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=legit Server -After=network-online.target -Requires=network-online.target - -[Service] -User=git -Group=git -ExecStart=/usr/bin/legit -config /etc/legit/config.yaml -ProtectSystem=strict -ProtectHome=strict -NoNewPrivileges=true -PrivateTmp=true -PrivateDevices=true - -[Install] -WantedBy=multi-user.target diff --git a/cmd/legit/flake.lock b/cmd/legit/flake.lock deleted file mode 100644 index 9841a94..0000000 --- a/cmd/legit/flake.lock +++ /dev/null @@ -1,26 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1718558927, - "narHash": "sha256-PRqvkPqX5luuZ0WcUbz2zATGp4IzybDU0K33MxO9Sd0=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "f82fe275d98c521c051af4892cd8b3406cee67a3", - "type": "github" - }, - "original": { - "owner": "nixos", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/cmd/legit/flake.nix b/cmd/legit/flake.nix deleted file mode 100644 index 178cce8..0000000 --- a/cmd/legit/flake.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ - description = "web frontend for git"; - - inputs.nixpkgs.url = "github:nixos/nixpkgs"; - - outputs = - { self - , nixpkgs - , - }: - let - supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; - forAllSystems = nixpkgs.lib.genAttrs supportedSystems; - nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; }); - in - { - packages = forAllSystems (system: - let - pkgs = nixpkgsFor.${system}; - legit = self.packages.${system}.legit; - files = pkgs.lib.fileset.toSource { - root = ./.; - fileset = pkgs.lib.fileset.unions [ - ./config.yaml - ./static - ./templates - ]; - }; - in - { - legit = pkgs.buildGoModule { - name = "legit"; - rev = "master"; - src = ./.; - - vendorHash = "sha256-ynv0pBdVPIhTz7RvCwVWr0vUWwfw+PEjFXs9PdQMqm8="; - }; - docker = pkgs.dockerTools.buildLayeredImage { - name = "sini:5000/legit"; - tag = "latest"; - contents = [ files legit pkgs.git ]; - config = { - Entrypoint = [ "${legit}/bin/legit" ]; - ExposedPorts = { "5555/tcp" = { }; }; - }; - }; - }); - - defaultPackage = forAllSystems (system: self.packages.${system}.legit); - devShells = forAllSystems (system: - let - pkgs = nixpkgsFor.${system}; - in - { - default = pkgs.mkShell { - nativeBuildInputs = with pkgs; [ - go - ]; - }; - }); - }; -} diff --git a/cmd/legit/git/diff.go b/cmd/legit/git/diff.go deleted file mode 100644 index 93c823a..0000000 --- a/cmd/legit/git/diff.go +++ /dev/null @@ -1,119 +0,0 @@ -package git - -import ( - "fmt" - "log" - "strings" - - "github.com/bluekeyes/go-gitdiff/gitdiff" - "github.com/go-git/go-git/v5/plumbing/object" -) - -type TextFragment struct { - Header string - Lines []gitdiff.Line -} - -type Diff struct { - Name struct { - Old string - New string - } - TextFragments []TextFragment - IsBinary bool - IsNew bool - IsDelete bool -} - -// A nicer git diff representation. -type NiceDiff struct { - Commit struct { - Message string - Author object.Signature - This string - Parent string - } - Stat struct { - FilesChanged int - Insertions int - Deletions int - } - Diff []Diff -} - -func (g *GitRepo) Diff() (*NiceDiff, error) { - c, err := g.r.CommitObject(g.h) - if err != nil { - return nil, fmt.Errorf("commit object: %w", err) - } - - patch := &object.Patch{} - commitTree, err := c.Tree() - parent := &object.Commit{} - if err == nil { - parentTree := &object.Tree{} - if c.NumParents() != 0 { - parent, err = c.Parents().Next() - if err == nil { - parentTree, err = parent.Tree() - if err == nil { - patch, err = parentTree.Patch(commitTree) - if err != nil { - return nil, fmt.Errorf("patch: %w", err) - } - } - } - } else { - patch, err = parentTree.Patch(commitTree) - if err != nil { - return nil, fmt.Errorf("patch: %w", err) - } - } - } - - diffs, _, err := gitdiff.Parse(strings.NewReader(patch.String())) - if err != nil { - log.Println(err) - } - - nd := NiceDiff{} - nd.Commit.This = c.Hash.String() - - if parent.Hash.IsZero() { - nd.Commit.Parent = "" - } else { - nd.Commit.Parent = parent.Hash.String() - } - nd.Commit.Author = c.Author - nd.Commit.Message = c.Message - - for _, d := range diffs { - ndiff := Diff{} - ndiff.Name.New = d.NewName - ndiff.Name.Old = d.OldName - ndiff.IsBinary = d.IsBinary - ndiff.IsNew = d.IsNew - ndiff.IsDelete = d.IsDelete - - for _, tf := range d.TextFragments { - ndiff.TextFragments = append(ndiff.TextFragments, TextFragment{ - Header: tf.Header(), - Lines: tf.Lines, - }) - for _, l := range tf.Lines { - switch l.Op { - case gitdiff.OpAdd: - nd.Stat.Insertions += 1 - case gitdiff.OpDelete: - nd.Stat.Deletions += 1 - } - } - } - - nd.Diff = append(nd.Diff, ndiff) - } - - nd.Stat.FilesChanged = len(diffs) - - return &nd, nil -} diff --git a/cmd/legit/git/git.go b/cmd/legit/git/git.go deleted file mode 100644 index d55460f..0000000 --- a/cmd/legit/git/git.go +++ /dev/null @@ -1,344 +0,0 @@ -package git - -import ( - "archive/tar" - "fmt" - "io" - "io/fs" - "path" - "sort" - "time" - - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" -) - -type GitRepo struct { - r *git.Repository - h plumbing.Hash -} - -type TagList struct { - refs []*TagReference - r *git.Repository -} - -// TagReference is used to list both tag and non-annotated tags. -// Non-annotated tags should only contains a reference. -// Annotated tags should contain its reference and its tag information. -type TagReference struct { - ref *plumbing.Reference - tag *object.Tag -} - -// infoWrapper wraps the property of a TreeEntry so it can export fs.FileInfo -// to tar WriteHeader -type infoWrapper struct { - name string - size int64 - mode fs.FileMode - modTime time.Time - isDir bool -} - -func (self *TagList) Len() int { - return len(self.refs) -} - -func (self *TagList) Swap(i, j int) { - self.refs[i], self.refs[j] = self.refs[j], self.refs[i] -} - -// sorting tags in reverse chronological order -func (self *TagList) Less(i, j int) bool { - var dateI time.Time - var dateJ time.Time - - if self.refs[i].tag != nil { - dateI = self.refs[i].tag.Tagger.When - } else { - c, err := self.r.CommitObject(self.refs[i].ref.Hash()) - if err != nil { - dateI = time.Now() - } else { - dateI = c.Committer.When - } - } - - if self.refs[j].tag != nil { - dateJ = self.refs[j].tag.Tagger.When - } else { - c, err := self.r.CommitObject(self.refs[j].ref.Hash()) - if err != nil { - dateJ = time.Now() - } else { - dateJ = c.Committer.When - } - } - - return dateI.After(dateJ) -} - -func Open(path string, ref string) (*GitRepo, error) { - var err error - g := GitRepo{} - g.r, err = git.PlainOpen(path) - if err != nil { - return nil, fmt.Errorf("opening %s: %w", path, err) - } - - if ref == "" { - head, err := g.r.Head() - if err != nil { - return nil, fmt.Errorf("getting head of %s: %w", path, err) - } - g.h = head.Hash() - } else { - hash, err := g.r.ResolveRevision(plumbing.Revision(ref)) - if err != nil { - return nil, fmt.Errorf("resolving rev %s for %s: %w", ref, path, err) - } - g.h = *hash - } - return &g, nil -} - -func (g *GitRepo) Commits() ([]*object.Commit, error) { - ci, err := g.r.Log(&git.LogOptions{From: g.h}) - if err != nil { - return nil, fmt.Errorf("commits from ref: %w", err) - } - - commits := []*object.Commit{} - ci.ForEach(func(c *object.Commit) error { - commits = append(commits, c) - return nil - }) - - return commits, nil -} - -func (g *GitRepo) LastCommit() (*object.Commit, error) { - c, err := g.r.CommitObject(g.h) - if err != nil { - return nil, fmt.Errorf("last commit: %w", err) - } - return c, nil -} - -func (g *GitRepo) FileContent(path string) (string, error) { - c, err := g.r.CommitObject(g.h) - if err != nil { - return "", fmt.Errorf("commit object: %w", err) - } - - tree, err := c.Tree() - if err != nil { - return "", fmt.Errorf("file tree: %w", err) - } - - file, err := tree.File(path) - if err != nil { - return "", err - } - - isbin, _ := file.IsBinary() - - if !isbin { - return file.Contents() - } else { - return "Not displaying binary file", nil - } -} - -func (g *GitRepo) Tags() ([]*TagReference, error) { - iter, err := g.r.Tags() - if err != nil { - return nil, fmt.Errorf("tag objects: %w", err) - } - - tags := make([]*TagReference, 0) - - if err := iter.ForEach(func(ref *plumbing.Reference) error { - obj, err := g.r.TagObject(ref.Hash()) - switch err { - case nil: - tags = append(tags, &TagReference{ - ref: ref, - tag: obj, - }) - case plumbing.ErrObjectNotFound: - tags = append(tags, &TagReference{ - ref: ref, - }) - default: - return err - } - return nil - }); err != nil { - return nil, err - } - - tagList := &TagList{r: g.r, refs: tags} - sort.Sort(tagList) - return tags, nil -} - -func (g *GitRepo) Branches() ([]*plumbing.Reference, error) { - bi, err := g.r.Branches() - if err != nil { - return nil, fmt.Errorf("branchs: %w", err) - } - - branches := []*plumbing.Reference{} - - _ = bi.ForEach(func(ref *plumbing.Reference) error { - branches = append(branches, ref) - return nil - }) - - return branches, nil -} - -func (g *GitRepo) FindMainBranch(branches []string) (string, error) { - for _, b := range branches { - _, err := g.r.ResolveRevision(plumbing.Revision(b)) - if err == nil { - return b, nil - } - } - return "", fmt.Errorf("unable to find main branch") -} - -// WriteTar writes itself from a tree into a binary tar file format. -// prefix is root folder to be appended. -func (g *GitRepo) WriteTar(w io.Writer, prefix string) error { - tw := tar.NewWriter(w) - defer tw.Close() - - c, err := g.r.CommitObject(g.h) - if err != nil { - return fmt.Errorf("commit object: %w", err) - } - - tree, err := c.Tree() - if err != nil { - return err - } - - walker := object.NewTreeWalker(tree, true, nil) - defer walker.Close() - - name, entry, err := walker.Next() - for ; err == nil; name, entry, err = walker.Next() { - info, err := newInfoWrapper(name, prefix, &entry, tree) - if err != nil { - return err - } - - header, err := tar.FileInfoHeader(info, "") - if err != nil { - return err - } - - err = tw.WriteHeader(header) - if err != nil { - return err - } - - if !info.IsDir() { - file, err := tree.File(name) - if err != nil { - return err - } - - reader, err := file.Blob.Reader() - if err != nil { - return err - } - - _, err = io.Copy(tw, reader) - if err != nil { - reader.Close() - return err - } - reader.Close() - } - } - - return nil -} - -func newInfoWrapper( - name string, - prefix string, - entry *object.TreeEntry, - tree *object.Tree, -) (*infoWrapper, error) { - var ( - size int64 - mode fs.FileMode - isDir bool - ) - - if entry.Mode.IsFile() { - file, err := tree.TreeEntryFile(entry) - if err != nil { - return nil, err - } - mode = fs.FileMode(file.Mode) - - size, err = tree.Size(name) - if err != nil { - return nil, err - } - } else { - isDir = true - mode = fs.ModeDir | fs.ModePerm - } - - fullname := path.Join(prefix, name) - return &infoWrapper{ - name: fullname, - size: size, - mode: mode, - modTime: time.Unix(0, 0), - isDir: isDir, - }, nil -} - -func (i *infoWrapper) Name() string { - return i.name -} - -func (i *infoWrapper) Size() int64 { - return i.size -} - -func (i *infoWrapper) Mode() fs.FileMode { - return i.mode -} - -func (i *infoWrapper) ModTime() time.Time { - return i.modTime -} - -func (i *infoWrapper) IsDir() bool { - return i.isDir -} - -func (i *infoWrapper) Sys() any { - return nil -} - -func (t *TagReference) Name() string { - return t.ref.Name().Short() -} - -func (t *TagReference) Message() string { - if t.tag != nil { - return t.tag.Message - } - return "" -} diff --git a/cmd/legit/git/service/service.go b/cmd/legit/git/service/service.go deleted file mode 100644 index d2c7fdd..0000000 --- a/cmd/legit/git/service/service.go +++ /dev/null @@ -1,121 +0,0 @@ -package service - -import ( - "bytes" - "fmt" - "io" - "log" - "net/http" - "os/exec" - "strings" - "syscall" -) - -// Mostly from charmbracelet/soft-serve and sosedoff/gitkit. - -type ServiceCommand struct { - Dir string - Stdin io.Reader - Stdout http.ResponseWriter -} - -func (c *ServiceCommand) InfoRefs() error { - cmd := exec.Command("git", []string{ - "upload-pack", - "--stateless-rpc", - "--advertise-refs", - ".", - }...) - - cmd.Dir = c.Dir - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - stdoutPipe, _ := cmd.StdoutPipe() - cmd.Stderr = cmd.Stdout - - if err := cmd.Start(); err != nil { - log.Printf("git: failed to start git-upload-pack (info/refs): %s", err) - return err - } - - if err := packLine(c.Stdout, "# service=git-upload-pack\n"); err != nil { - log.Printf("git: failed to write pack line: %s", err) - return err - } - - if err := packFlush(c.Stdout); err != nil { - log.Printf("git: failed to flush pack: %s", err) - return err - } - - buf := bytes.Buffer{} - if _, err := io.Copy(&buf, stdoutPipe); err != nil { - log.Printf("git: failed to copy stdout to tmp buffer: %s", err) - return err - } - - if err := cmd.Wait(); err != nil { - out := strings.Builder{} - _, _ = io.Copy(&out, &buf) - log.Printf("git: failed to run git-upload-pack; err: %s; output: %s", err, out.String()) - return err - } - - if _, err := io.Copy(c.Stdout, &buf); err != nil { - log.Printf("git: failed to copy stdout: %s", err) - } - - return nil -} - -func (c *ServiceCommand) UploadPack() error { - cmd := exec.Command("git", []string{ - "-c", "uploadpack.allowFilter=true", - "upload-pack", - "--stateless-rpc", - ".", - }...) - cmd.Dir = c.Dir - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} - - stdoutPipe, _ := cmd.StdoutPipe() - cmd.Stderr = cmd.Stdout - defer stdoutPipe.Close() - - stdinPipe, err := cmd.StdinPipe() - if err != nil { - return err - } - defer stdinPipe.Close() - - if err := cmd.Start(); err != nil { - log.Printf("git: failed to start git-upload-pack: %s", err) - return err - } - - if _, err := io.Copy(stdinPipe, c.Stdin); err != nil { - log.Printf("git: failed to copy stdin: %s", err) - return err - } - stdinPipe.Close() - - if _, err := io.Copy(newWriteFlusher(c.Stdout), stdoutPipe); err != nil { - log.Printf("git: failed to copy stdout: %s", err) - return err - } - if err := cmd.Wait(); err != nil { - log.Printf("git: failed to wait for git-upload-pack: %s", err) - return err - } - - return nil -} - -func packLine(w io.Writer, s string) error { - _, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s) - return err -} - -func packFlush(w io.Writer) error { - _, err := fmt.Fprint(w, "0000") - return err -} diff --git a/cmd/legit/git/service/write_flusher.go b/cmd/legit/git/service/write_flusher.go deleted file mode 100644 index f25a5ae..0000000 --- a/cmd/legit/git/service/write_flusher.go +++ /dev/null @@ -1,25 +0,0 @@ -package service - -import ( - "io" - "net/http" -) - -func newWriteFlusher(w http.ResponseWriter) io.Writer { - return writeFlusher{w.(interface { - io.Writer - http.Flusher - })} -} - -type writeFlusher struct { - wf interface { - io.Writer - http.Flusher - } -} - -func (w writeFlusher) Write(p []byte) (int, error) { - defer w.wf.Flush() - return w.wf.Write(p) -} diff --git a/cmd/legit/git/tree.go b/cmd/legit/git/tree.go deleted file mode 100644 index 88ad1c1..0000000 --- a/cmd/legit/git/tree.go +++ /dev/null @@ -1,66 +0,0 @@ -package git - -import ( - "fmt" - - "github.com/go-git/go-git/v5/plumbing/object" -) - -func (g *GitRepo) FileTree(path string) ([]NiceTree, error) { - c, err := g.r.CommitObject(g.h) - if err != nil { - return nil, fmt.Errorf("commit object: %w", err) - } - - files := []NiceTree{} - tree, err := c.Tree() - if err != nil { - return nil, fmt.Errorf("file tree: %w", err) - } - - if path == "" { - files = makeNiceTree(tree) - } else { - o, err := tree.FindEntry(path) - if err != nil { - return nil, err - } - - if !o.Mode.IsFile() { - subtree, err := tree.Tree(path) - if err != nil { - return nil, err - } - - files = makeNiceTree(subtree) - } - } - - return files, nil -} - -// A nicer git tree representation. -type NiceTree struct { - Name string - Mode string - Size int64 - IsFile bool - IsSubtree bool -} - -func makeNiceTree(t *object.Tree) []NiceTree { - nts := []NiceTree{} - - for _, e := range t.Entries { - mode, _ := e.Mode.ToOSFileMode() - sz, _ := t.Size(e.Name) - nts = append(nts, NiceTree{ - Name: e.Name, - Mode: mode.String(), - IsFile: e.Mode.IsFile(), - Size: sz, - }) - } - - return nts -} diff --git a/cmd/legit/go.mod b/cmd/legit/go.mod deleted file mode 100644 index 516d7ef..0000000 --- a/cmd/legit/go.mod +++ /dev/null @@ -1,42 +0,0 @@ -module realy.lol/cmd/legit - -go 1.22.0 - -require ( - github.com/alecthomas/chroma/v2 v2.14.0 - github.com/bluekeyes/go-gitdiff v0.8.0 - github.com/cyphar/filepath-securejoin v0.4.1 - github.com/dustin/go-humanize v1.0.1 - github.com/go-git/go-git/v5 v5.13.2 - github.com/microcosm-cc/bluemonday v1.0.27 - github.com/russross/blackfriday/v2 v2.1.0 - golang.org/x/sys v0.30.0 - gopkg.in/yaml.v3 v3.0.1 -) - -require ( - github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/ProtonMail/go-crypto v1.1.5 // indirect - github.com/acomagu/bufpipe v1.0.4 // indirect - github.com/aymerick/douceur v0.2.0 // indirect - github.com/cloudflare/circl v1.6.0 // indirect - github.com/dlclark/regexp2 v1.11.4 // indirect - github.com/emirpasic/gods v1.18.1 // indirect - github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.6.2 // indirect - github.com/gorilla/css v1.0.1 // indirect - github.com/imdario/mergo v0.3.16 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/pjbgf/sha1cd v0.3.2 // indirect - github.com/sergi/go-diff v1.3.1 // indirect - github.com/skeema/knownhosts v1.3.1 // indirect - github.com/xanzy/ssh-agent v0.3.3 // indirect - golang.org/x/crypto v0.33.0 // indirect - golang.org/x/net v0.35.0 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect -) - -replace github.com/sergi/go-diff => github.com/sergi/go-diff v1.1.0 - -replace github.com/go-git/go-git/v5 => github.com/go-git/go-git/v5 v5.6.1 diff --git a/cmd/legit/go.sum b/cmd/legit/go.sum deleted file mode 100644 index f8ba6ba..0000000 --- a/cmd/legit/go.sum +++ /dev/null @@ -1,187 +0,0 @@ -github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= -github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4= -github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= -github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= -github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= -github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= -github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= -github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= -github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= -github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/bluekeyes/go-gitdiff v0.8.0 h1:Nn1wfw3/XeKoc3lWk+2bEXGUHIx36kj80FM1gVcBk+o= -github.com/bluekeyes/go-gitdiff v0.8.0/go.mod h1:WWAk1Mc6EgWarCrPFO+xeYlujPu98VuLW3Tu+B/85AE= -github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= -github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= -github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= -github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= -github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= -github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= -github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= -github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= -github.com/go-git/go-git-fixtures/v4 v4.3.1 h1:y5z6dd3qi8Hl+stezc8p3JxDkoTRqMAlKnXHuzrfjTQ= -github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= -github.com/go-git/go-git/v5 v5.6.1 h1:q4ZRqQl4pR/ZJHc1L5CFjGA1a10u76aV1iC+nh+bHsk= -github.com/go-git/go-git/v5 v5.6.1/go.mod h1:mvyoL6Unz0PiTQrGQfSfiLFhBH1c1e84ylC2MDs4ee8= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= -github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= -github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= -github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= -github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= -github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= -github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= -github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= -github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= -github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= -github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag= -github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= -github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= -github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -golang.org/x/arch v0.1.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/cmd/legit/license b/cmd/legit/license deleted file mode 100644 index fc9152a..0000000 --- a/cmd/legit/license +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) Anirudh Oppiliappan - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/cmd/legit/main.go b/cmd/legit/main.go deleted file mode 100644 index 2f716d5..0000000 --- a/cmd/legit/main.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "log" - "net/http" - - "realy.lol/cmd/legit/config" - "realy.lol/cmd/legit/routes" -) - -func main() { - var cfg string - flag.StringVar(&cfg, "config", "./config.yaml", "path to config file") - flag.Parse() - - c, err := config.Read(cfg) - if err != nil { - log.Fatal(err) - } - - if err := UnveilPaths([]string{ - c.Dirs.Static, - c.Repo.ScanPath, - c.Dirs.Templates, - }, - "r"); err != nil { - log.Fatalf("unveil: %s", err) - } - - mux := routes.Handlers(c) - addr := fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port) - log.Println("starting server on", addr) - log.Fatal(http.ListenAndServe(addr, mux)) -} diff --git a/cmd/legit/readme b/cmd/legit/readme deleted file mode 100644 index bc0ef0b..0000000 --- a/cmd/legit/readme +++ /dev/null @@ -1,88 +0,0 @@ -legit ------ - -A git web frontend written in Go. - -Pronounced however you like; I prefer channeling my inner beret-wearing -Frenchman, and saying "Oui, il est le git!" - -But yeah it's pretty legit, no cap on god fr fr. - - -FEATURES - -• Fully customizable templates and stylesheets. -• Cloning over http(s). -• Less archaic HTML. -• Not CGI. - - -INSTALLING - -Clone it, 'go build' it. - - -CONFIG - -Uses yaml for configuration. Looks for a 'config.yaml' in the current -directory by default; pass the '--config' flag to point it elsewhere. - -Example config.yaml: - - repo: - scanPath: /var/www/git - readme: - - readme - - README - - readme.md - - README.md - mainBranch: - - master - - main - ignore: - - foo - - bar - dirs: - templates: ./templates - static: ./static - meta: - title: git good - description: i think it's a skill issue - syntaxHighlight: monokailight - server: - name: git.icyphox.sh - host: 127.0.0.1 - port: 5555 - -These options are fairly self-explanatory, but of note are: - -• repo.scanPath: where all your git repos live (or die). legit doesn't - traverse subdirs yet. -• dirs: use this to override the default templates and static assets. -• repo.readme: readme files to look for. -• repo.mainBranch: main branch names to look for. -• repo.ignore: repos to ignore, relative to scanPath. -• repo.unlisted: repos to hide, relative to scanPath. -• server.name: used for go-import meta tags and clone URLs. -• meta.syntaxHighlight: this is used to select the syntax theme to render. If left - blank or removed, the native theme will be used. If an invalid theme is set in this field, - it will default to "monokailight". For more information - about themes, please refer to chroma's gallery [1]. - - -NOTES - -• Run legit behind a TLS terminating proxy like relayd(8) or nginx. -• Cloning only works in bare repos -- this is a limitation inherent to git. You - can still view non-bare repos just fine in legit. -• Pushing over https, while supported, is disabled because auth is a - pain. Use ssh. -• Paths are unveil(2)'d on OpenBSD. -• Docker images are available ghcr.io/icyphox/legit:{master,latest,vX.Y.Z}. [2] - -LICENSE - -legit is licensed under MIT. - -[1]: https://swapoff.org/chroma/playground/ -[2]: https://github.com/icyphox/legit/pkgs/container/legit diff --git a/cmd/legit/routes/git.go b/cmd/legit/routes/git.go deleted file mode 100644 index 05a35a2..0000000 --- a/cmd/legit/routes/git.go +++ /dev/null @@ -1,81 +0,0 @@ -package routes - -import ( - "compress/gzip" - "io" - "log" - "net/http" - "path/filepath" - - securejoin "github.com/cyphar/filepath-securejoin" - - "realy.lol/cmd/legit/git/service" -) - -func (d *deps) InfoRefs(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - name = filepath.Clean(name) - - repo, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - - w.Header().Set("content-type", "application/x-git-upload-pack-advertisement") - w.WriteHeader(http.StatusOK) - - cmd := service.ServiceCommand{ - Dir: repo, - Stdout: w, - } - - if err := cmd.InfoRefs(); err != nil { - http.Error(w, err.Error(), 500) - log.Printf("git: failed to execute git-upload-pack (info/refs) %s", err) - return - } -} - -func (d *deps) UploadPack(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - name = filepath.Clean(name) - - repo, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - - w.Header().Set("content-type", "application/x-git-upload-pack-result") - w.Header().Set("Connection", "Keep-Alive") - w.Header().Set("Transfer-Encoding", "chunked") - w.WriteHeader(http.StatusOK) - - cmd := service.ServiceCommand{ - Dir: repo, - Stdout: w, - } - - var reader io.ReadCloser - reader = r.Body - - if r.Header.Get("Content-Encoding") == "gzip" { - reader, err := gzip.NewReader(r.Body) - if err != nil { - http.Error(w, err.Error(), 500) - log.Printf("git: failed to create gzip reader: %s", err) - return - } - defer reader.Close() - } - - cmd.Stdin = reader - if err := cmd.UploadPack(); err != nil { - http.Error(w, err.Error(), 500) - log.Printf("git: failed to execute git-upload-pack %s", err) - return - } -} diff --git a/cmd/legit/routes/handler.go b/cmd/legit/routes/handler.go deleted file mode 100644 index 160ec31..0000000 --- a/cmd/legit/routes/handler.go +++ /dev/null @@ -1,49 +0,0 @@ -package routes - -import ( - "net/http" - - "realy.lol/cmd/legit/config" -) - -// Checks for gitprotocol-http(5) specific smells; if found, passes -// the request on to the git http service, else render the web frontend. -func (d *deps) Multiplex(w http.ResponseWriter, r *http.Request) { - path := r.PathValue("rest") - - if r.URL.RawQuery == "service=git-receive-pack" { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("no pushing allowed!")) - return - } - - if path == "info/refs" && - r.URL.RawQuery == "service=git-upload-pack" && - r.Method == "GET" { - d.InfoRefs(w, r) - } else if path == "git-upload-pack" && r.Method == "POST" { - d.UploadPack(w, r) - } else if r.Method == "GET" { - d.RepoIndex(w, r) - } -} - -func Handlers(c *config.Config) *http.ServeMux { - mux := http.NewServeMux() - d := deps{c} - - mux.HandleFunc("GET /", d.Index) - mux.HandleFunc("GET /static/{file}", d.ServeStatic) - mux.HandleFunc("GET /{name}", d.Multiplex) - mux.HandleFunc("POST /{name}", d.Multiplex) - mux.HandleFunc("GET /{name}/tree/{ref}/{rest...}", d.RepoTree) - mux.HandleFunc("GET /{name}/blob/{ref}/{rest...}", d.FileContent) - mux.HandleFunc("GET /{name}/log/{ref}", d.Log) - mux.HandleFunc("GET /{name}/archive/{file}", d.Archive) - mux.HandleFunc("GET /{name}/commit/{ref}", d.Diff) - mux.HandleFunc("GET /{name}/refs/{$}", d.Refs) - mux.HandleFunc("GET /{name}/{rest...}", d.Multiplex) - mux.HandleFunc("POST /{name}/{rest...}", d.Multiplex) - - return mux -} diff --git a/cmd/legit/routes/routes.go b/cmd/legit/routes/routes.go deleted file mode 100644 index 694e9a2..0000000 --- a/cmd/legit/routes/routes.go +++ /dev/null @@ -1,486 +0,0 @@ -package routes - -import ( - "compress/gzip" - "fmt" - "html/template" - "log" - "net/http" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - "time" - - securejoin "github.com/cyphar/filepath-securejoin" - "github.com/dustin/go-humanize" - "github.com/microcosm-cc/bluemonday" - "github.com/russross/blackfriday/v2" - - "realy.lol/cmd/legit/config" - "realy.lol/cmd/legit/git" -) - -type deps struct { - c *config.Config -} - -func (d *deps) Index(w http.ResponseWriter, r *http.Request) { - dirs, err := os.ReadDir(d.c.Repo.ScanPath) - if err != nil { - d.Write500(w) - log.Printf("reading scan path: %s", err) - return - } - - type info struct { - DisplayName, Name, Desc, Idle string - d time.Time - } - - infos := []info{} - - for _, dir := range dirs { - name := dir.Name() - if !dir.IsDir() || d.isIgnored(name) || d.isUnlisted(name) { - continue - } - - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - - gr, err := git.Open(path, "") - if err != nil { - log.Println(err) - continue - } - - c, err := gr.LastCommit() - if err != nil { - d.Write500(w) - log.Println(err) - return - } - - infos = append(infos, info{ - DisplayName: getDisplayName(name), - Name: name, - Desc: getDescription(path), - Idle: humanize.Time(c.Author.When), - d: c.Author.When, - }) - } - - sort.Slice(infos, func(i, j int) bool { - return infos[j].d.Before(infos[i].d) - }) - - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - - data := make(map[string]interface{}) - data["meta"] = d.c.Meta - data["info"] = infos - - if err := t.ExecuteTemplate(w, "index", data); err != nil { - log.Println(err) - return - } -} - -func (d *deps) RepoIndex(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { - d.Write404(w) - return - } - name = filepath.Clean(name) - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - - gr, err := git.Open(path, "") - if err != nil { - d.Write404(w) - return - } - - commits, err := gr.Commits() - if err != nil { - d.Write500(w) - log.Println(err) - return - } - - var readmeContent template.HTML - for _, readme := range d.c.Repo.Readme { - ext := filepath.Ext(readme) - content, _ := gr.FileContent(readme) - if len(content) > 0 { - switch ext { - case ".md", ".mkd", ".markdown": - unsafe := blackfriday.Run( - []byte(content), - blackfriday.WithExtensions(blackfriday.CommonExtensions), - ) - html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) - readmeContent = template.HTML(html) - default: - safe := bluemonday.UGCPolicy().SanitizeBytes([]byte(content)) - readmeContent = template.HTML( - fmt.Sprintf(`
%s
`, safe), - ) - } - break - } - } - - if readmeContent == "" { - log.Printf("no readme found for %s", name) - } - - mainBranch, err := gr.FindMainBranch(d.c.Repo.MainBranch) - if err != nil { - d.Write500(w) - log.Println(err) - return - } - - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - - if len(commits) >= 3 { - commits = commits[:3] - } - - data := make(map[string]any) - data["name"] = name - data["displayname"] = getDisplayName(name) - data["ref"] = mainBranch - data["readme"] = readmeContent - data["commits"] = commits - data["desc"] = getDescription(path) - data["servername"] = d.c.Server.Name - data["meta"] = d.c.Meta - data["gomod"] = isGoModule(gr) - - if err := t.ExecuteTemplate(w, "repo", data); err != nil { - log.Println(err) - return - } - - return -} - -func (d *deps) RepoTree(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { - d.Write404(w) - return - } - treePath := r.PathValue("rest") - ref := r.PathValue("ref") - - name = filepath.Clean(name) - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - gr, err := git.Open(path, ref) - if err != nil { - d.Write404(w) - return - } - - files, err := gr.FileTree(treePath) - if err != nil { - d.Write500(w) - log.Println(err) - return - } - - data := make(map[string]any) - data["name"] = name - data["displayname"] = getDisplayName(name) - data["ref"] = ref - data["parent"] = treePath - data["desc"] = getDescription(path) - data["dotdot"] = filepath.Dir(treePath) - - d.listFiles(files, data, w) - return -} - -func (d *deps) FileContent(w http.ResponseWriter, r *http.Request) { - var raw bool - if rawParam, err := strconv.ParseBool(r.URL.Query().Get("raw")); err == nil { - raw = rawParam - } - - name := r.PathValue("name") - if d.isIgnored(name) { - d.Write404(w) - return - } - treePath := r.PathValue("rest") - ref := r.PathValue("ref") - - name = filepath.Clean(name) - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - - gr, err := git.Open(path, ref) - if err != nil { - d.Write404(w) - return - } - - contents, err := gr.FileContent(treePath) - if err != nil { - d.Write500(w) - return - } - data := make(map[string]any) - data["name"] = name - data["displayname"] = getDisplayName(name) - data["ref"] = ref - data["desc"] = getDescription(path) - data["path"] = treePath - - if raw { - d.showRaw(contents, w) - } else { - if d.c.Meta.SyntaxHighlight == "" { - d.showFile(contents, data, w) - } else { - d.showFileWithHighlight(treePath, contents, data, w) - } - } -} - -func (d *deps) Archive(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { - d.Write404(w) - return - } - - file := r.PathValue("file") - - // TODO: extend this to add more files compression (e.g.: xz) - if !strings.HasSuffix(file, ".tar.gz") { - d.Write404(w) - return - } - - ref := strings.TrimSuffix(file, ".tar.gz") - - // This allows the browser to use a proper name for the file when - // downloading - filename := fmt.Sprintf("%s-%s.tar.gz", name, ref) - setContentDisposition(w, filename) - setGZipMIME(w) - - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - - gr, err := git.Open(path, ref) - if err != nil { - d.Write404(w) - return - } - - gw := gzip.NewWriter(w) - defer gw.Close() - - prefix := fmt.Sprintf("%s-%s", name, ref) - err = gr.WriteTar(gw, prefix) - if err != nil { - // once we start writing to the body we can't report error anymore - // so we are only left with printing the error. - log.Println(err) - return - } - - err = gw.Flush() - if err != nil { - // once we start writing to the body we can't report error anymore - // so we are only left with printing the error. - log.Println(err) - return - } -} - -func (d *deps) Log(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { - d.Write404(w) - return - } - ref := r.PathValue("ref") - - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - - gr, err := git.Open(path, ref) - if err != nil { - d.Write404(w) - return - } - - commits, err := gr.Commits() - if err != nil { - d.Write500(w) - log.Println(err) - return - } - - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - - data := make(map[string]interface{}) - data["commits"] = commits - data["meta"] = d.c.Meta - data["name"] = name - data["displayname"] = getDisplayName(name) - data["ref"] = ref - data["desc"] = getDescription(path) - data["log"] = true - - if err := t.ExecuteTemplate(w, "log", data); err != nil { - log.Println(err) - return - } -} - -func (d *deps) Diff(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { - d.Write404(w) - return - } - ref := r.PathValue("ref") - - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - gr, err := git.Open(path, ref) - if err != nil { - d.Write404(w) - return - } - - diff, err := gr.Diff() - if err != nil { - d.Write500(w) - log.Println(err) - return - } - - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - - data := make(map[string]interface{}) - - data["commit"] = diff.Commit - data["stat"] = diff.Stat - data["diff"] = diff.Diff - data["meta"] = d.c.Meta - data["name"] = name - data["displayname"] = getDisplayName(name) - data["ref"] = ref - data["desc"] = getDescription(path) - - if err := t.ExecuteTemplate(w, "commit", data); err != nil { - log.Println(err) - return - } -} - -func (d *deps) Refs(w http.ResponseWriter, r *http.Request) { - name := r.PathValue("name") - if d.isIgnored(name) { - d.Write404(w) - return - } - - path, err := securejoin.SecureJoin(d.c.Repo.ScanPath, name) - if err != nil { - log.Printf("securejoin error: %v", err) - d.Write404(w) - return - } - - gr, err := git.Open(path, "") - if err != nil { - d.Write404(w) - return - } - - tags, err := gr.Tags() - if err != nil { - // Non-fatal, we *should* have at least one branch to show. - log.Println(err) - } - - branches, err := gr.Branches() - if err != nil { - log.Println(err) - d.Write500(w) - return - } - - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - - data := make(map[string]interface{}) - - data["meta"] = d.c.Meta - data["name"] = name - data["displayname"] = getDisplayName(name) - data["branches"] = branches - data["tags"] = tags - data["desc"] = getDescription(path) - - if err := t.ExecuteTemplate(w, "refs", data); err != nil { - log.Println(err) - return - } -} - -func (d *deps) ServeStatic(w http.ResponseWriter, r *http.Request) { - f := r.PathValue("file") - f = filepath.Clean(f) - f, err := securejoin.SecureJoin(d.c.Dirs.Static, f) - if err != nil { - d.Write404(w) - return - } - - http.ServeFile(w, r, f) -} diff --git a/cmd/legit/routes/template.go b/cmd/legit/routes/template.go deleted file mode 100644 index 46b9bd3..0000000 --- a/cmd/legit/routes/template.go +++ /dev/null @@ -1,151 +0,0 @@ -package routes - -import ( - "bytes" - "html/template" - "io" - "log" - "net/http" - "path/filepath" - "strings" - - "github.com/alecthomas/chroma/v2/formatters/html" - "github.com/alecthomas/chroma/v2/lexers" - "github.com/alecthomas/chroma/v2/styles" - - "realy.lol/cmd/legit/git" -) - -func (d *deps) Write404(w http.ResponseWriter) { - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - w.WriteHeader(404) - if err := t.ExecuteTemplate(w, "404", nil); err != nil { - log.Printf("404 template: %s", err) - } -} - -func (d *deps) Write500(w http.ResponseWriter) { - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - w.WriteHeader(500) - if err := t.ExecuteTemplate(w, "500", nil); err != nil { - log.Printf("500 template: %s", err) - } -} - -func (d *deps) listFiles(files []git.NiceTree, data map[string]any, w http.ResponseWriter) { - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - - data["files"] = files - data["meta"] = d.c.Meta - - if err := t.ExecuteTemplate(w, "tree", data); err != nil { - log.Println(err) - return - } -} - -func countLines(r io.Reader) (int, error) { - buf := make([]byte, 32*1024) - bufLen := 0 - count := 0 - nl := []byte{'\n'} - - for { - c, err := r.Read(buf) - if c > 0 { - bufLen += c - } - count += bytes.Count(buf[:c], nl) - - switch { - case err == io.EOF: - /* handle last line not having a newline at the end */ - if bufLen >= 1 && buf[(bufLen-1)%(32*1024)] != '\n' { - count++ - } - return count, nil - case err != nil: - return 0, err - } - } -} - -func (d *deps) showFileWithHighlight(name, content string, data map[string]any, w http.ResponseWriter) { - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - - lexer := lexers.Get(name) - if lexer == nil { - lexer = lexers.Get(".txt") - } - - style := styles.Get(d.c.Meta.SyntaxHighlight) - if style == nil { - style = styles.Get("monokailight") - } - - formatter := html.New( - html.WithLineNumbers(true), - html.WithLinkableLineNumbers(true, "L"), - ) - - iterator, err := lexer.Tokenise(nil, content) - if err != nil { - d.Write500(w) - return - } - - var code bytes.Buffer - err = formatter.Format(&code, style, iterator) - if err != nil { - d.Write500(w) - return - } - - data["content"] = template.HTML(code.String()) - data["meta"] = d.c.Meta - data["chroma"] = true - - if err := t.ExecuteTemplate(w, "file", data); err != nil { - log.Println(err) - return - } -} - -func (d *deps) showFile(content string, data map[string]any, w http.ResponseWriter) { - tpath := filepath.Join(d.c.Dirs.Templates, "*") - t := template.Must(template.ParseGlob(tpath)) - - lc, err := countLines(strings.NewReader(content)) - if err != nil { - // Non-fatal, we'll just skip showing line numbers in the template. - log.Printf("counting lines: %s", err) - } - - lines := make([]int, lc) - if lc > 0 { - for i := range lines { - lines[i] = i + 1 - } - } - - data["linecount"] = lines - data["content"] = content - data["meta"] = d.c.Meta - data["chroma"] = false - - if err := t.ExecuteTemplate(w, "file", data); err != nil { - log.Println(err) - return - } -} - -func (d *deps) showRaw(content string, w http.ResponseWriter) { - w.WriteHeader(http.StatusOK) - w.Header().Set("Content-Type", "text/plain") - w.Write([]byte(content)) - return -} diff --git a/cmd/legit/routes/util.go b/cmd/legit/routes/util.go deleted file mode 100644 index c5b4655..0000000 --- a/cmd/legit/routes/util.go +++ /dev/null @@ -1,118 +0,0 @@ -package routes - -import ( - "io/fs" - "log" - "net/http" - "os" - "path/filepath" - "strings" - - "realy.lol/cmd/legit/git" -) - -func isGoModule(gr *git.GitRepo) bool { - _, err := gr.FileContent("go.mod") - return err == nil -} - -func getDisplayName(name string) string { - return strings.TrimSuffix(name, ".git") -} - -func getDescription(path string) (desc string) { - db, err := os.ReadFile(filepath.Join(path, "description")) - if err == nil { - desc = string(db) - } else { - desc = "" - } - return -} - -func (d *deps) isUnlisted(name string) bool { - for _, i := range d.c.Repo.Unlisted { - if name == i { - return true - } - } - - return false -} - -func (d *deps) isIgnored(name string) bool { - for _, i := range d.c.Repo.Ignore { - if name == i { - return true - } - } - - return false -} - -type repoInfo struct { - Git *git.GitRepo - Path string - Category string -} - -func (d *deps) getAllRepos() ([]repoInfo, error) { - repos := []repoInfo{} - max := strings.Count(d.c.Repo.ScanPath, string(os.PathSeparator)) + 2 - - err := filepath.WalkDir(d.c.Repo.ScanPath, func(path string, de fs.DirEntry, err error) error { - if err != nil { - return err - } - - if de.IsDir() { - // Check if we've exceeded our recursion depth - if strings.Count(path, string(os.PathSeparator)) > max { - return fs.SkipDir - } - - if d.isIgnored(path) { - return fs.SkipDir - } - - // A bare repo should always have at least a HEAD file, if it - // doesn't we can continue recursing - if _, err := os.Lstat(filepath.Join(path, "HEAD")); err == nil { - repo, err := git.Open(path, "") - if err != nil { - log.Println(err) - } else { - relpath, _ := filepath.Rel(d.c.Repo.ScanPath, path) - repos = append(repos, repoInfo{ - Git: repo, - Path: relpath, - Category: d.category(path), - }) - // Since we found a Git repo, we don't want to recurse - // further - return fs.SkipDir - } - } - } - return nil - }) - - return repos, err -} - -func (d *deps) category(path string) string { - return strings.TrimPrefix(filepath.Dir(strings.TrimPrefix(path, d.c.Repo.ScanPath)), string(os.PathSeparator)) -} - -func setContentDisposition(w http.ResponseWriter, name string) { - h := "inline; filename=\"" + name + "\"" - w.Header().Add("Content-Disposition", h) -} - -func setGZipMIME(w http.ResponseWriter) { - setMIME(w, "application/gzip") -} - -func setMIME(w http.ResponseWriter, mime string) { - w.Header().Add("Content-Type", mime) -} diff --git a/cmd/legit/static/legit.png b/cmd/legit/static/legit.png deleted file mode 100644 index be2368ac2e6704b39be360d1b970b04e7e6e2250..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1321 zcmV+^1=jkBP)EX>4Tx04R}tkv&MmKpe$iTT4YM4(%Y~kfAzRlq%w=RVYG*P%E_RU~=gfG-*gu zTpR`0f`cE6RRjWHa-`QDULg#c~(3vY`@B5yuo&qkMnP zWrgz=XSG^q?R)YUh6~!tGS_JiBZWmQL4*JqbyQG=g*dGmDJC+spY-q#Iew8`GPx>X zeSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00RL@L_t(o!|j*5OFMZK#Xm8>5KN*`M5`#;2^Nwel^|kc zp%x;dHnH%5ouK#^3<_dlp*A8|2nvFQO@b1{!4y75f=a|HC@6#wUwO?W6OwFYV1KY1 zH5*;nz2#-@+`~Ed-osZH2n2HcV3hI0@jrk(fLt!e^Yb&YSnOv2Xqv|G@GyIOd;cv7 zeii!Q;o*Usn;T-W7)?!0*zI=odj0n>;Pd$y9UVoMW#aKT^Yim8FE5kLW=qdNGMQv) zX^Gz6UZ$p|(CKtI91dn?X6WkbqNSy!v;ab(5TQ^Av)PQ->jgkn)x0bv2armo0EkAT z1cSkRetdkK>gwv!OYq*rZnx9f*$F@gwu>_X5A)&+hIn2L}fzih|qi=J@y+fOI;IBuQLdT>)@?ea-p#IRN|n z`^d6f8~~5U!}Rntk|g2x`&nCCV{>zpv$Hb*ve_)FtE=4J-U1Mh$9a2u10Wm@|H<-y zeYSZbkzi$I1wjxHMG>RXh%C#v-R{4vX=`gEkw|cPd5P2MEKY)_rzccZrK6(*qtOUZ z)LMQTKsucUz-%_>a~6w*^78WU0q}mJeLi147YqjTMpY<&xAITVKut{zLqkLC?Celg zRfWxFsv4~GQ#ZaEa7mN*Vk7jCnpO!WNT|H-QC@6 zY;53ixr#ePnx>(uDpspCKNo#{ef0PDGd4E%x3#HM3WLEwSy|cFB*^7*%+1Yle}B)! z!~|BWm6MYbG)=?da1^Y6-<+Zth(sc|TrLg|4|#ccK@bFbdU_B9p)_t-h>?$)R7u_i f#Wep{JWT!o<26YYzoRQ-00000NkvXXu0mjf;N(t6 diff --git a/cmd/legit/static/style.css b/cmd/legit/static/style.css deleted file mode 100644 index 53ab7dd..0000000 --- a/cmd/legit/static/style.css +++ /dev/null @@ -1,332 +0,0 @@ -:root { - --white: #fff; - --light: #f4f4f4; - --cyan: #509c93; - --light-gray: #eee; - --medium-gray: #ddd; - --gray: #6a6a6a; - --dark: #444; - --darker: #222; - - --sans-font: -apple-system, BlinkMacSystemFont, "Inter", "Roboto", "Segoe UI", sans-serif; - --display-font: -apple-system, BlinkMacSystemFont, "Inter", "Roboto", "Segoe UI", sans-serif; - --mono-font: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', 'Roboto Mono', Menlo, Consolas, monospace; -} - -@media (prefers-color-scheme: dark) { - :root { - color-scheme: dark light; - --light: #181818; - --cyan: #76c7c0; - --light-gray: #333; - --medium-gray: #444; - --gray: #aaa; - --dark: #ddd; - --darker: #f4f4f4; - --white: #000; - } -} - -html { - background: var(--white); - -webkit-text-size-adjust: none; - font-family: var(--sans-font); - font-weight: 380; -} - -pre { - font-family: var(--mono-font); -} - -::selection { - background: var(--medium-gray); - opacity: 0.3; -} - -* { - box-sizing: border-box; - padding: 0; - margin: 0; -} - -body { - max-width: 1000px; - padding: 0 13px; - margin: 40px auto; -} - -main, footer { - font-size: 1rem; - padding: 0; - line-height: 160%; -} - -header h1, h2, h3 { - font-family: var(--display-font); -} - -h2 { - font-weight: 400; -} - -strong { - font-weight: 500; -} - -main h1 { - padding: 10px 0 10px 0; -} - -main h2 { - font-size: 18px; -} - -main h2, h3 { - padding: 20px 0 15px 0; -} - -nav { - padding: 0.4rem 0 1.5rem 0; -} - -nav ul { - padding: 0; - margin: 0; - list-style: none; - padding-bottom: 20px; -} - -nav ul li { - padding-right: 10px; - display: inline-block; -} - -a { - margin: 0; - padding: 0; - box-sizing: border-box; - text-decoration: none; - word-wrap: break-word; -} - -a { - color: var(--darker); - border-bottom: 1.5px solid var(--medium-gray); -} - -a:hover { - border-bottom: 1.5px solid var(--gray); -} - -.index { - padding-top: 2em; - display: grid; - grid-template-columns: 6em 1fr minmax(0, 7em); - grid-row-gap: 0.5em; - min-width: 0; -} - -.clone-url { - padding-top: 2rem; -} - -.clone-url pre { - color: var(--dark); - white-space: pre-wrap; -} - -.desc { - font-weight: normal; - color: var(--gray); - font-style: italic; -} - -.tree { - display: grid; - grid-template-columns: 10ch auto 1fr; - grid-row-gap: 0.5em; - grid-column-gap: 1em; - min-width: 0; -} - -.log { - display: grid; - grid-template-columns: 20rem minmax(0, 1fr); - grid-row-gap: 0.8em; - grid-column-gap: 8rem; - margin-bottom: 2em; - padding-bottom: 1em; - border-bottom: 1.5px solid var(--medium-gray); -} - -.log pre { - white-space: pre-wrap; -} - -.mode, .size { - font-family: var(--mono-font); -} -.size { - text-align: right; -} - -.readme pre { - white-space: pre-wrap; - overflow-x: auto; -} - -.readme { - background: var(--light-gray); - padding: 0.5rem; -} - -.readme ul { - padding: revert; -} - -.readme img { - max-width: 100%; -} - -.diff { - margin: 1rem 0 1rem 0; - padding: 1rem 0 1rem 0; - border-bottom: 1.5px solid var(--medium-gray); -} - -.diff pre { - overflow: scroll; -} - -.diff-stat { - padding: 1rem 0 1rem 0; -} - -.commit-hash, .commit-email { - font-family: var(--mono-font); -} - -.commit-email:before { - content: '<'; -} - -.commit-email:after { - content: '>'; -} - -.commit { - margin-bottom: 1rem; -} - -.commit pre { - padding-bottom: 1rem; - white-space: pre-wrap; -} - -.diff-stat ul li { - list-style: none; - padding-left: 0.5em; -} - -.diff-add { - color: green; -} - -.diff-del { - color: red; -} - -.diff-noop { - color: var(--gray); -} - -.ref { - font-family: var(--sans-font); - font-size: 14px; - color: var(--gray); - display: inline-block; - padding-top: 0.7em; -} - -.refs pre { - white-space: pre-wrap; - padding-bottom: 0.5rem; -} - -.refs strong { - padding-right: 1em; -} - -.line-numbers { - white-space: pre-line; - -moz-user-select: -moz-none; - -khtml-user-select: none; - -webkit-user-select: none; - -o-user-select: none; - user-select: none; - display: flex; - float: left; - flex-direction: column; - margin-right: 1ch; -} - -.file-wrapper { - display: flex; - flex-direction: row; - grid-template-columns: 1rem minmax(0, 1fr); - gap: 1rem; - padding: 0.5rem; - background: var(--light-gray); - overflow-x: auto; -} - -.chroma-file-wrapper { - display: flex; - flex-direction: row; - grid-template-columns: 1rem minmax(0, 1fr); - overflow-x: auto; -} - -.file-content { - background: var(--light-gray); - overflow-y: hidden; - overflow-x: auto; -} - -.diff-type { - color: var(--gray); -} - -.commit-info { - color: var(--gray); - padding-bottom: 1.5rem; - font-size: 0.85rem; -} - -@media (max-width: 600px) { - .index { - grid-row-gap: 0.8em; - } - - .log { - grid-template-columns: 1fr; - grid-row-gap: 0em; - } - - .index { - grid-template-columns: 1fr; - grid-row-gap: 0em; - } - - .index-name:not(:first-child) { - padding-top: 1.5rem; - } - - .commit-info:not(:last-child) { - padding-bottom: 1.5rem; - } - - pre { - font-size: 0.8rem; - } -} diff --git a/cmd/legit/templates/404.html b/cmd/legit/templates/404.html deleted file mode 100644 index 8c40cd1..0000000 --- a/cmd/legit/templates/404.html +++ /dev/null @@ -1,13 +0,0 @@ -{{ define "404" }} - - 404 -{{ template "head" . }} - - {{ template "nav" . }} -
-

404 — nothing like that here.

-
- - - -{{ end }} diff --git a/cmd/legit/templates/500.html b/cmd/legit/templates/500.html deleted file mode 100644 index 53c605f..0000000 --- a/cmd/legit/templates/500.html +++ /dev/null @@ -1,13 +0,0 @@ -{{ define "500" }} - - 500 -{{ template "head" . }} - - {{ template "nav" . }} -
-

500 — something broke!

-
- - - -{{ end }} diff --git a/cmd/legit/templates/commit.html b/cmd/legit/templates/commit.html deleted file mode 100644 index c1def17..0000000 --- a/cmd/legit/templates/commit.html +++ /dev/null @@ -1,104 +0,0 @@ -{{ define "commit" }} - -{{ template "head" . }} - - {{ template "repoheader" . }} - - {{ template "nav" . }} -
-
-
-          {{- .commit.Message -}}
-        
-
- {{ .commit.Author.Name }} {{ .commit.Author.Email}} -
{{ .commit.Author.When.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}
-
- - - - {{ if .commit.Parent }} - - - {{ end }} -
-
- {{ .stat.FilesChanged }} files changed, - {{ .stat.Insertions }} insertions(+), - {{ .stat.Deletions }} deletions(-) -
-
-
- jump to - {{ range .diff }} - - {{ end }} -
-
-
-
- {{ $repo := .name }} - {{ $this := .commit.This }} - {{ $parent := .commit.Parent }} - {{ range .diff }} -
-
- {{ if .IsNew }} - A - {{ end }} - {{ if .IsDelete }} - D - {{ end }} - {{ if not (or .IsNew .IsDelete) }} - M - {{ end }} - {{ if .Name.Old }} - {{ .Name.Old }} - {{ if .Name.New }} - → - {{ .Name.New }} - {{ end }} - {{ else }} - {{ .Name.New }} - {{- end -}} - {{ if .IsBinary }} -

Not showing binary file.

- {{ else }} -
-            {{- range .TextFragments -}}
-            

{{- .Header -}}

- {{- range .Lines -}} - {{- if eq .Op.String "+" -}} - {{ .String }} - {{- end -}} - {{- if eq .Op.String "-" -}} - {{ .String }} - {{- end -}} - {{- if eq .Op.String " " -}} - {{ .String }} - {{- end -}} - {{- end -}} - {{- end -}} - {{- end -}} -
-
-
- {{ end }} -
-
- - -{{ end }} diff --git a/cmd/legit/templates/file.html b/cmd/legit/templates/file.html deleted file mode 100644 index 1a09e87..0000000 --- a/cmd/legit/templates/file.html +++ /dev/null @@ -1,36 +0,0 @@ -{{ define "file" }} - - {{ template "head" . }} - {{ template "repoheader" . }} - - {{ template "nav" . }} -
-

{{ .path }} (view raw)

- {{if .chroma }} -
- {{ .content }} -
- {{else}} -
- - - - - -
-
-            {{- range .linecount }}
- {{ . }}
-            {{- end -}}
-              
-
-
-             {{- .content -}}
-              
-
-
- {{end}} -
- - -{{ end }} diff --git a/cmd/legit/templates/head.html b/cmd/legit/templates/head.html deleted file mode 100644 index b3f71c9..0000000 --- a/cmd/legit/templates/head.html +++ /dev/null @@ -1,32 +0,0 @@ -{{ define "head" }} - - - - - - {{ if .parent }} - {{ .meta.Title }} — {{ .name }} ({{ .ref }}): {{ .parent }}/ - - {{ else if .path }} - {{ .meta.Title }} — {{ .name }} ({{ .ref }}): {{ .path }} - {{ else if .files }} - {{ .meta.Title }} — {{ .name }} ({{ .ref }}) - {{ else if .commit }} - {{ .meta.Title }} — {{ .name }}: {{ .commit.This }} - {{ else if .branches }} - {{ .meta.Title }} — {{ .name }}: refs - {{ else if .commits }} - {{ if .log }} - {{ .meta.Title }} — {{ .name }}: log - {{ else }} - {{ .meta.Title }} — {{ .name }} - {{ end }} - {{ else }} - {{ .meta.Title }} - {{ end }} - {{ if and .servername .gomod }} - - {{ end }} - - -{{ end }} diff --git a/cmd/legit/templates/index.html b/cmd/legit/templates/index.html deleted file mode 100644 index 7a77aec..0000000 --- a/cmd/legit/templates/index.html +++ /dev/null @@ -1,21 +0,0 @@ -{{ define "index" }} - -{{ template "head" . }} - -
-

{{ .meta.Title }}

-

{{ .meta.Description }}

-
- -
-
- {{ range .info }} - -
{{ .Desc }}
-
{{ .Idle }}
- {{ end }} -
-
- - -{{ end }} diff --git a/cmd/legit/templates/log.html b/cmd/legit/templates/log.html deleted file mode 100644 index 7d74cb3..0000000 --- a/cmd/legit/templates/log.html +++ /dev/null @@ -1,25 +0,0 @@ -{{ define "log" }} - -{{ template "head" . }} - - {{ template "repoheader" . }} - - {{ template "nav" . }} -
- {{ $repo := .name }} -
- {{ range .commits }} -
- -
{{ .Message }}
-
-
- {{ .Author.Name }} {{ .Author.Email }} -
{{ .Author.When.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}
-
- {{ end }} -
-
- - -{{ end }} diff --git a/cmd/legit/templates/nav.html b/cmd/legit/templates/nav.html deleted file mode 100644 index 51c9a34..0000000 --- a/cmd/legit/templates/nav.html +++ /dev/null @@ -1,14 +0,0 @@ -{{ define "nav" }} - -{{ end }} diff --git a/cmd/legit/templates/refs.html b/cmd/legit/templates/refs.html deleted file mode 100644 index 00058d5..0000000 --- a/cmd/legit/templates/refs.html +++ /dev/null @@ -1,40 +0,0 @@ -{{ define "refs" }} - -{{ template "head" . }} - - {{ template "repoheader" . }} - - {{ template "nav" . }} -
- {{ $name := .name }} -

branches

-
- {{ range .branches }} -
- {{ .Name.Short }} - browse - log - tar.gz -
- {{ end }} -
- {{ if .tags }} -

tags

-
- {{ range .tags }} -
- {{ .Name }} - browse - log - tar.gz - {{ if .Message }} -
{{ .Message }}
-
- {{ end }} - {{ end }} -
- {{ end }} -
- - -{{ end }} diff --git a/cmd/legit/templates/repo-header.html b/cmd/legit/templates/repo-header.html deleted file mode 100644 index 0420da7..0000000 --- a/cmd/legit/templates/repo-header.html +++ /dev/null @@ -1,12 +0,0 @@ -{{ define "repoheader" }} -
-

- all repos - — {{ .displayname }} - {{ if .ref }} - @ {{ .ref }} - {{ end }} -

-

{{ .desc }}

-
-{{ end }} diff --git a/cmd/legit/templates/repo.html b/cmd/legit/templates/repo.html deleted file mode 100644 index 1cd9b5c..0000000 --- a/cmd/legit/templates/repo.html +++ /dev/null @@ -1,38 +0,0 @@ -{{ define "repo" }} - -{{ template "head" . }} - -{{ template "repoheader" . }} - - - {{ template "nav" . }} -
- {{ $repo := .name }} -
- {{ range .commits }} -
- -
{{ .Message }}
-
-
- {{ .Author.Name }} {{ .Author.Email }} -
{{ .Author.When.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}
-
- {{ end }} -
-{{- if .readme }} -
- {{- .readme -}} -
-{{- end -}} - -
- clone -
-git clone https://{{ .servername }}/{{ .name }}
-        
-
-
- - -{{ end }} diff --git a/cmd/legit/templates/tree.html b/cmd/legit/templates/tree.html deleted file mode 100644 index c4b7e4f..0000000 --- a/cmd/legit/templates/tree.html +++ /dev/null @@ -1,55 +0,0 @@ -{{ define "tree" }} - - -{{ template "head" . }} - - {{ template "repoheader" . }} - - {{ template "nav" . }} -
- {{ $repo := .name }} - {{ $ref := .ref }} - {{ $parent := .parent }} - -
- {{ if $parent }} -
-
- - {{ end }} - {{ range .files }} - {{ if not .IsFile }} -
{{ .Mode }}
-
{{ .Size }}
-
- {{ if $parent }} - {{ .Name }}/ - {{ else }} - {{ .Name }}/ - {{ end }} -
- {{ end }} - {{ end }} - {{ range .files }} - {{ if .IsFile }} -
{{ .Mode }}
-
{{ .Size }}
-
- {{ if $parent }} - {{ .Name }} - {{ else }} - {{ .Name }} - {{ end }} -
- {{ end }} - {{ end }} -
-
-
-          {{- if .readme }}{{ .readme }}{{- end -}}
-        
-
-
- - -{{ end }} diff --git a/cmd/legit/unveil.go b/cmd/legit/unveil.go deleted file mode 100644 index 39353a8..0000000 --- a/cmd/legit/unveil.go +++ /dev/null @@ -1,29 +0,0 @@ -//go:build openbsd -// +build openbsd - -package main - -import ( - "log" - - "golang.org/x/sys/unix" -) - -func Unveil(path string, perms string) error { - log.Printf("unveil: \"%s\", %s", path, perms) - return unix.Unveil(path, perms) -} - -func UnveilBlock() error { - log.Printf("unveil: block") - return unix.UnveilBlock() -} - -func UnveilPaths(paths []string, perms string) error { - for _, path := range paths { - if err := Unveil(path, perms); err != nil { - return err - } - } - return UnveilBlock() -} diff --git a/cmd/legit/unveil_stub.go b/cmd/legit/unveil_stub.go deleted file mode 100644 index dc72a7d..0000000 --- a/cmd/legit/unveil_stub.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build !openbsd -// +build !openbsd - -// Stub functions for GOOS that don't support unix.Unveil() - -package main - -func Unveil(path string, perms string) error { - return nil -} - -func UnveilBlock() error { - return nil -} - -func UnveilPaths(paths []string, perms string) error { - return nil -} diff --git a/go.mod b/go.mod index 57b44f1..1c5cfce 100644 --- a/go.mod +++ b/go.mod @@ -46,6 +46,7 @@ require ( github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rickb777/acceptable v0.46.0 // indirect github.com/savsgio/gotils v0.0.0-20250408102913-196191ec6287 // indirect github.com/templexxx/cpu v0.1.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect diff --git a/go.sum b/go.sum index f67671d..8bf0924 100644 --- a/go.sum +++ b/go.sum @@ -87,6 +87,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/rickb777/acceptable v0.46.0 h1:G/GoAKyQlDKKmEl9kbp9mgkf4vHvcxB6Vx/l2MHEdJ8= +github.com/rickb777/acceptable v0.46.0/go.mod h1:MHPJml//8ogaImxiVu6qmOlpoFiKtuLOaTEGSl+Mmos= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= diff --git a/openapi/http-configuration.go b/openapi/http-configuration.go index a558b9a..9dac78d 100644 --- a/openapi/http-configuration.go +++ b/openapi/http-configuration.go @@ -16,8 +16,9 @@ import ( // ConfigurationSetInput is the parameters for HTTP API method to set Configuration. type ConfigurationSetInput struct { - Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"true"` - Body config.C `doc:"the new configuration"` + Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"true"` + Body config.C `doc:"the new configuration"` + Accept string `header:"Accept" default:"application/json" required:"false"` } // ConfigurationGetInput is the parameters for HTTP API method to get Configuration. diff --git a/openapi/http-event.go b/openapi/http-event.go index 55d3187..e969df7 100644 --- a/openapi/http-event.go +++ b/openapi/http-event.go @@ -25,6 +25,7 @@ import ( // EventInput is the parameters for the Event HTTP API method. type EventInput struct { Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"` + Accept string `header:"Accept" default:"application/nostr+json;q=0.9,application/x-realy-event:q=0.1"` RawBody []byte } diff --git a/openapi/http-events.go b/openapi/http-events.go index 6b8a997..d47a530 100644 --- a/openapi/http-events.go +++ b/openapi/http-events.go @@ -6,6 +6,7 @@ import ( "net/http" "github.com/danielgtaylor/huma/v2" + "github.com/rickb777/acceptable/header" "realy.lol/chk" "realy.lol/context" @@ -20,8 +21,13 @@ import ( // EventsInput is the parameters for an Events HTTP API method. Basically an array of eventid.T. type EventsInput struct { - Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"` - Body []string `doc:"list of event Ids"` + Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"` + Accept string `header:"Accept" default:"application/nostr+json;q=0.9,application/x-realy-event;q=0.1" doc:"event encoding format that is expected, priority using mimetype;q=0.x will indicate preference when multiple are available"` + Body []string `doc:"list of event Ids"` +} + +type EventsOutput struct { + Limit int `header:"X-Limit" default:"1000" doc:"informs client maximum number of events that they can request"` } // RegisterEvents is the implementation of the HTTP API for Events. @@ -32,15 +38,14 @@ func (x *Operations) RegisterEvents(api huma.API) { scopes := []string{"user", "read"} method := http.MethodPost huma.Register(api, huma.Operation{ - OperationID: name, - Summary: name, - Path: path, - Method: method, - Tags: []string{"events"}, - Description: helpers.GenerateDescription(description, scopes), - Security: []map[string][]string{{"auth": scopes}}, - DefaultStatus: 204, - }, func(ctx context.T, input *EventsInput) (output *huma.StreamResponse, err error) { + OperationID: name, + Summary: name, + Path: path, + Method: method, + Tags: []string{"events"}, + Description: helpers.GenerateDescription(description, scopes), + Security: []map[string][]string{{"auth": scopes}}, + }, func(ctx context.T, input *EventsInput) (output *struct{}, err error) { // log.I.S(input) if len(input.Body) == 10000 { err = huma.Error400BadRequest( @@ -52,6 +57,10 @@ func (x *Operations) RegisterEvents(api huma.API) { if len(input.Body) > 1000 || x.Server.AuthRequired() { authrequired = true } + limit := 1000 + if !authrequired { + limit = 10000 + } r := ctx.Value("http-request").(*http.Request) var valid bool var pubkey []byte @@ -97,14 +106,27 @@ func (x *Operations) RegisterEvents(api huma.API) { } evIds = append(evIds, idb) } + if idsWriter, ok := sto.(store.GetIdsWriter); ok { - output = &huma.StreamResponse{ - func(ctx huma.Context) { - if err = idsWriter.FetchIds(x.Context(), tag.New(evIds...), - ctx.BodyWriter()); chk.E(err) { - return - } - }, + w := ctx.Value("http-response").(http.ResponseWriter) + var binary bool + precedence := header.ParsePrecedenceValues(r.Header.Get("Accept")) + done: + for _, v := range precedence { + switch v.Value { + case "application/x-realy-event": + binary = true + break done + case "application/nostr+json": + break done + default: + break done + } + } + w.WriteHeader(200) + w.Header().Set("X-Limit", fmt.Sprint(limit)) + if err = idsWriter.FetchIds(w, x.Context(), tag.New(evIds...), binary); chk.E(err) { + return } } return diff --git a/ratel/fetch-ids.go b/ratel/fetch-ids.go index 263621c..ad7e615 100644 --- a/ratel/fetch-ids.go +++ b/ratel/fetch-ids.go @@ -1,12 +1,14 @@ package ratel import ( + "bytes" "io" "github.com/dgraph-io/badger/v4" "realy.lol/chk" "realy.lol/context" + "realy.lol/event" "realy.lol/ratel/keys/id" "realy.lol/ratel/keys/serial" "realy.lol/ratel/prefixes" @@ -14,7 +16,7 @@ import ( ) // FetchIds retrieves events based on a list of event Ids that have been provided. -func (r *T) FetchIds(c context.T, evIds *tag.T, out io.Writer) (err error) { +func (r *T) FetchIds(w io.Writer, c context.T, evIds *tag.T, binary bool) (err error) { b := make([]byte, 0, 100000) err = r.View(func(txn *badger.Txn) (err error) { for _, v := range evIds.ToSliceOfBytes() { @@ -38,11 +40,30 @@ func (r *T) FetchIds(c context.T, evIds *tag.T, out io.Writer) (err error) { if b, err = item.ValueCopy(nil); chk.E(err) { return } - if _, err = out.Write(b); chk.E(err) { + if binary { + if !r.Binary { + ev := event.New() + if b, err = ev.Unmarshal(b); chk.E(err) { + return + } + ev.MarshalBinary(w) + continue + } + } else { + if r.Binary { + ev := event.New() + buf := bytes.NewBuffer(b) + if err = ev.UnmarshalBinary(buf); chk.E(err) { + return + } + b = ev.Marshal(nil) + } + } + if _, err = w.Write(b); chk.E(err) { return } // add the new line after entries - if _, err = out.Write([]byte{'\n'}); chk.E(err) { + if _, err = w.Write([]byte{'\n'}); chk.E(err) { return } } diff --git a/store/store_interface.go b/store/store_interface.go index 6350333..553312a 100644 --- a/store/store_interface.go +++ b/store/store_interface.go @@ -72,7 +72,7 @@ type Querier interface { } type GetIdsWriter interface { - FetchIds(c context.T, evIds *tag.T, out io.Writer) (err error) + FetchIds(w io.Writer, c context.T, evIds *tag.T, binary bool) (err error) } type Deleter interface { diff --git a/version b/version index b72cf1c..13e94ce 100644 --- a/version +++ b/version @@ -1 +1 @@ -v1.17.0 \ No newline at end of file +v1.18.0 \ No newline at end of file