mirror of https://git.jolheiser.com/ugit.git
Compare commits
41 Commits
4f38e3db32
...
31714bf9af
Author | SHA1 | Date |
---|---|---|
|
31714bf9af | |
|
86aa09929f | |
|
b8ca3fc4b8 | |
|
ebe2dc4603 | |
|
ea40aa746e | |
|
68992f0807 | |
|
9f3ca2ae1e | |
|
070544ef18 | |
|
9d6aa43bd4 | |
|
27915049a8 | |
|
dc88be2777 | |
|
801198a1f7 | |
|
753d1f3d20 | |
|
f7bcb11792 | |
|
d502993daf | |
|
9358d37e07 | |
|
04f4bc04e9 | |
|
19b2f55a1a | |
|
3b4c4dcc06 | |
|
20a8451427 | |
|
d4b287ed08 | |
|
a9208d2fe2 | |
|
5809db19f5 | |
|
15c0850bab | |
|
53945f5a62 | |
|
d30862f6fd | |
|
b205fa2103 | |
|
4b90e77eed | |
|
0f4b6ec936 | |
|
3a4e09a218 | |
|
03fa43600d | |
|
39efc9d853 | |
|
9f70cc24cd | |
|
4fbb4cf289 | |
|
0ae76c9d74 | |
|
3faedb8236 | |
|
11d534f89f | |
|
00b0d91307 | |
|
590777dea0 | |
|
df7ace7fae | |
|
79c3e14082 |
|
@ -0,0 +1,24 @@
|
|||
root = "."
|
||||
testdata_dir = "testdata"
|
||||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
bin = "./ugitd"
|
||||
cmd = "go build ./cmd/ugitd"
|
||||
delay = 1000
|
||||
exclude_file = ["internal/html/tailwind.go"]
|
||||
exclude_regex = ["_test.go"]
|
||||
exclude_unchanged = true
|
||||
include_ext = ["go"]
|
||||
pre_cmd = ["go generate ./..."]
|
||||
|
||||
[misc]
|
||||
clean_on_exit = true
|
||||
|
||||
[proxy]
|
||||
app_port = 8449
|
||||
enabled = true
|
||||
proxy_port = 8450
|
||||
|
||||
[screen]
|
||||
clear_on_rebuild = true
|
|
@ -2,3 +2,4 @@
|
|||
.ssh/
|
||||
.ugit/
|
||||
.tsnet/
|
||||
*.qcow2
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[[language]]
|
||||
name = "templ"
|
||||
language-id = "html"
|
||||
language-servers = ["templ", "vscode-html-language-server", "tailwindcss-ls"]
|
||||
|
|
@ -2,17 +2,17 @@
|
|||
<picture>
|
||||
<img alt="ugit logo" width="250" src="./assets/ugit.svg" />
|
||||
</picture>
|
||||
<h3 align="center">ugit</h3>
|
||||
<h3 align="center">µgit</h3>
|
||||
</p>
|
||||
|
||||
Minimal git server
|
||||
|
||||
ugit allows cloning via HTTPS/SSH, but can only be pushed to via SSH.
|
||||
µgit allows cloning via HTTPS/SSH, but can only be pushed to via SSH.
|
||||
|
||||
There are no plans to directly support issues or PR workflows, although webhooks are planned and auxillary software may be created to facilitate these things.
|
||||
If you wish to collaborate, please send me patches via [git-pr](https://pr.jolheiser.com/repos/ugit).
|
||||
|
||||
Currently all HTML is allowed in markdown, ugit is intended to be run by/for a trusted user.
|
||||
Currently all HTML is allowed in markdown, µgit is intended to be run by/for a trusted user.
|
||||
|
||||
## Getting your public SSH keys from another forge
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg viewBox="0 0 24 24" stroke="#de4c36" fill="#de4c36" stroke-width="1" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>ugit icon</title>
|
||||
<title>µgit icon</title>
|
||||
<rect fill="none" x="1" y="1" rx="1" ry="1" width="22" height="22"></rect>
|
||||
<ellipse cx="6" cy="6" rx="2" ry="2"></ellipse>
|
||||
<ellipse cx="18" cy="6" rx="2" ry="2"></ellipse>
|
||||
|
|
Before Width: | Height: | Size: 543 B After Width: | Height: | Size: 544 B |
|
@ -3,9 +3,9 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/peterbourgon/ff/v3"
|
||||
"github.com/peterbourgon/ff/v3/ffyaml"
|
||||
)
|
||||
|
@ -17,7 +17,8 @@ type cliArgs struct {
|
|||
Meta metaArgs
|
||||
Profile profileArgs
|
||||
Log logArgs
|
||||
Tailscale tailscaleArgs
|
||||
ShowPrivate bool
|
||||
TUI bool
|
||||
}
|
||||
|
||||
type sshArgs struct {
|
||||
|
@ -51,16 +52,10 @@ type profileLink struct {
|
|||
}
|
||||
|
||||
type logArgs struct {
|
||||
Level log.Level
|
||||
Level slog.Level
|
||||
JSON bool
|
||||
}
|
||||
|
||||
type tailscaleArgs struct {
|
||||
Enable bool
|
||||
Hostname string
|
||||
DataDir string
|
||||
}
|
||||
|
||||
func parseArgs(args []string) (c cliArgs, e error) {
|
||||
fs := flag.NewFlagSet("ugitd", flag.ContinueOnError)
|
||||
fs.String("config", "ugit.yaml", "Path to config file")
|
||||
|
@ -84,25 +79,30 @@ func parseArgs(args []string) (c cliArgs, e error) {
|
|||
Description: "Minimal git server",
|
||||
},
|
||||
Log: logArgs{
|
||||
Level: log.InfoLevel,
|
||||
},
|
||||
Tailscale: tailscaleArgs{
|
||||
Enable: false,
|
||||
Hostname: "ugit",
|
||||
DataDir: ".tsnet",
|
||||
Level: slog.LevelError,
|
||||
},
|
||||
}
|
||||
|
||||
fs.Func("log.level", "Logging level", func(s string) error {
|
||||
lvl, err := log.ParseLevel(s)
|
||||
if err != nil {
|
||||
return err
|
||||
var lvl slog.Level
|
||||
switch strings.ToLower(s) {
|
||||
case "debug":
|
||||
lvl = slog.LevelDebug
|
||||
case "info":
|
||||
lvl = slog.LevelInfo
|
||||
case "warn", "warning":
|
||||
lvl = slog.LevelWarn
|
||||
case "error":
|
||||
lvl = slog.LevelError
|
||||
default:
|
||||
return fmt.Errorf("unknown log level %q: options are [debug, info, warn, error]", s)
|
||||
}
|
||||
c.Log.Level = lvl
|
||||
return nil
|
||||
})
|
||||
fs.BoolVar(&c.Log.JSON, "log.json", c.Log.JSON, "Print logs in JSON(L) format")
|
||||
fs.StringVar(&c.RepoDir, "repo-dir", c.RepoDir, "Path to directory containing repositories")
|
||||
fs.BoolVar(&c.ShowPrivate, "show-private", c.ShowPrivate, "Show private repos in web interface")
|
||||
fs.BoolVar(&c.SSH.Enable, "ssh.enable", c.SSH.Enable, "Enable SSH server")
|
||||
fs.StringVar(&c.SSH.AuthorizedKeys, "ssh.authorized-keys", c.SSH.AuthorizedKeys, "Path to authorized_keys")
|
||||
fs.StringVar(&c.SSH.CloneURL, "ssh.clone-url", c.SSH.CloneURL, "SSH clone URL base")
|
||||
|
@ -115,6 +115,7 @@ func parseArgs(args []string) (c cliArgs, e error) {
|
|||
fs.StringVar(&c.Meta.Description, "meta.description", c.Meta.Description, "App description")
|
||||
fs.StringVar(&c.Profile.Username, "profile.username", c.Profile.Username, "Username for index page")
|
||||
fs.StringVar(&c.Profile.Email, "profile.email", c.Profile.Email, "Email for index page")
|
||||
fs.BoolVar(&c.TUI, "tui", c.TUI, "Run the TUI interface directly")
|
||||
fs.Func("profile.links", "Link(s) for index page", func(s string) error {
|
||||
parts := strings.SplitN(s, ",", 2)
|
||||
if len(parts) != 2 {
|
||||
|
@ -126,9 +127,6 @@ func parseArgs(args []string) (c cliArgs, e error) {
|
|||
})
|
||||
return nil
|
||||
})
|
||||
fs.BoolVar(&c.Tailscale.Enable, "tailscale.enable", c.Tailscale.Enable, "Enable Tailscale")
|
||||
fs.StringVar(&c.Tailscale.Hostname, "tailscale.hostname", c.Tailscale.Hostname, "Tailscale host to show private repos on")
|
||||
fs.StringVar(&c.Tailscale.DataDir, "tailscale.data-dir", c.Tailscale.DataDir, "Tailscale data/state directory")
|
||||
|
||||
return c, ff.Parse(fs, args,
|
||||
ff.WithEnvVarPrefix("UGIT"),
|
||||
|
|
|
@ -4,22 +4,23 @@ import (
|
|||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/httplog/v2"
|
||||
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
|
||||
"github.com/go-git/go-git/v5/utils/trace"
|
||||
"go.jolheiser.com/tailroute"
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
"go.jolheiser.com/ugit/internal/http"
|
||||
"go.jolheiser.com/ugit/internal/ssh"
|
||||
"go.jolheiser.com/ugit/internal/tui"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -40,14 +41,22 @@ func main() {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
log.SetLevel(args.Log.Level)
|
||||
// Run TUI mode if requested
|
||||
if args.TUI {
|
||||
if err := tui.Run(args.RepoDir); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
slog.SetLogLoggerLevel(args.Log.Level)
|
||||
middleware.DefaultLogger = httplog.RequestLogger(httplog.NewLogger("ugit", httplog.Options{
|
||||
JSON: args.Log.JSON,
|
||||
LogLevel: slog.Level(args.Log.Level),
|
||||
Concise: args.Log.Level != log.DebugLevel,
|
||||
Concise: args.Log.Level != slog.LevelDebug,
|
||||
}))
|
||||
|
||||
if args.Log.Level == log.DebugLevel {
|
||||
if args.Log.Level == slog.LevelDebug {
|
||||
trace.SetTarget(trace.Packet)
|
||||
} else {
|
||||
middleware.DefaultLogger = http.NoopLogger
|
||||
|
@ -55,7 +64,8 @@ func main() {
|
|||
}
|
||||
|
||||
if args.Log.JSON {
|
||||
log.SetFormatter(log.JSONFormatter)
|
||||
logger := slog.New(slog.NewJSONHandler(os.Stderr, nil))
|
||||
slog.SetDefault(logger)
|
||||
}
|
||||
|
||||
if err := requiredFS(args.RepoDir); err != nil {
|
||||
|
@ -75,7 +85,7 @@ func main() {
|
|||
panic(err)
|
||||
}
|
||||
go func() {
|
||||
log.Debugf("SSH listening on ssh://localhost:%d\n", sshSettings.Port)
|
||||
log.Printf("SSH listening on ssh://localhost:%d\n", sshSettings.Port)
|
||||
if err := sshSrv.ListenAndServe(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -92,7 +102,7 @@ func main() {
|
|||
Username: args.Profile.Username,
|
||||
Email: args.Profile.Email,
|
||||
},
|
||||
ShowPrivate: false,
|
||||
ShowPrivate: args.ShowPrivate,
|
||||
}
|
||||
for _, link := range args.Profile.Links {
|
||||
httpSettings.Profile.Links = append(httpSettings.Profile.Links, http.Link{
|
||||
|
@ -103,30 +113,15 @@ func main() {
|
|||
if args.HTTP.Enable {
|
||||
httpSrv := http.New(httpSettings)
|
||||
go func() {
|
||||
log.Debugf("HTTP listening on http://localhost:%d\n", httpSettings.Port)
|
||||
log.Printf("HTTP listening on http://localhost:%d\n", httpSettings.Port)
|
||||
if err := httpSrv.ListenAndServe(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if args.Tailscale.Enable {
|
||||
tailnetSettings := httpSettings
|
||||
tailnetSettings.ShowPrivate = true
|
||||
tailnetSrv := http.New(tailnetSettings)
|
||||
tr := tailroute.Router{
|
||||
Tailnet: tailnetSrv.Mux,
|
||||
}
|
||||
go func() {
|
||||
log.Debugf("Tailnet listening on http://%s\n", args.Tailscale.Hostname)
|
||||
if err := tr.Serve(args.Tailscale.Hostname, args.Tailscale.DataDir); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, os.Kill, os.Interrupt)
|
||||
signal.Notify(ch, syscall.SIGTERM, os.Interrupt)
|
||||
<-ch
|
||||
}
|
||||
|
||||
|
@ -149,12 +144,20 @@ func requiredFS(repoDir string) error {
|
|||
}
|
||||
fp = filepath.Join(fp, "pre-receive")
|
||||
|
||||
if err := os.MkdirAll(fp+".d", os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fi, err := os.Create(fp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fi.WriteString("#!/usr/bin/env bash\n")
|
||||
fi.WriteString(fmt.Sprintf("%s pre-receive-hook\n", bin))
|
||||
fi.WriteString(fmt.Sprintf(`for hook in %s.d/*; do
|
||||
test -x "${hook}" && test -f "${hook}" || continue
|
||||
"${hook}"
|
||||
done`, fp))
|
||||
fi.Close()
|
||||
|
||||
return os.Chmod(fp, 0o755)
|
||||
|
|
|
@ -5,19 +5,13 @@ layout {
|
|||
command "nix"
|
||||
args "develop"
|
||||
size "90%"
|
||||
start_suspended true
|
||||
}
|
||||
pane split_direction="vertical" {
|
||||
pane {
|
||||
name "run"
|
||||
command "go"
|
||||
args "run" "./cmd/ugitd"
|
||||
start_suspended true
|
||||
}
|
||||
pane {
|
||||
name "watch"
|
||||
name "air"
|
||||
command "nix"
|
||||
args "develop" "--command" "nu" "-c" "watch --glob *.templ ./internal/html/ {|| go generate ./...}"
|
||||
args "develop" "--command" "air"
|
||||
start_suspended true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
61
flake.lock
61
flake.lock
|
@ -1,51 +1,12 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gomod2nix": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717050755,
|
||||
"narHash": "sha256-C9IEHABulv2zEDFA+Bf0E1nmfN4y6MIUe5eM2RCrDC0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "gomod2nix",
|
||||
"rev": "31b6d2e40b36456e792cd6cf50d5a8ddd2fa59a1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "gomod2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1719379843,
|
||||
"narHash": "sha256-u+D+IOAMMl70+CJ9NKB+RMrASjInuIWMHzjLWQjPZ6c=",
|
||||
"lastModified": 1736241350,
|
||||
"narHash": "sha256-CHd7yhaDigUuJyDeX0SADbTM9FXfiWaeNyY34FL1wQU=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b3f3c1b13fb08f3828442ee86630362e81136bbc",
|
||||
"rev": "8c9fd3e564728e90829ee7dbac6edc972971cd0f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -57,27 +18,11 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"gomod2nix": "gomod2nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"tailwind-ctp": "tailwind-ctp",
|
||||
"tailwind-ctp-lsp": "tailwind-ctp-lsp"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"tailwind-ctp": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
|
|
212
flake.nix
212
flake.nix
|
@ -3,10 +3,6 @@
|
|||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||
gomod2nix = {
|
||||
url = "github:nix-community/gomod2nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
tailwind-ctp = {
|
||||
url = "git+https://git.jolheiser.com/tailwind-ctp";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
@ -17,172 +13,76 @@
|
|||
};
|
||||
};
|
||||
|
||||
outputs = {
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
gomod2nix,
|
||||
tailwind-ctp,
|
||||
tailwind-ctp-lsp,
|
||||
} @ inputs: let
|
||||
system = "x86_64-linux";
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
tailwind-ctp = inputs.tailwind-ctp.packages.${system}.default;
|
||||
tailwind-ctp-lsp = inputs.tailwind-ctp-lsp.packages.${system}.default;
|
||||
ugit = gomod2nix.legacyPackages.${system}.buildGoApplication rec {
|
||||
name = "ugitd";
|
||||
src = pkgs.nix-gitignore.gitignoreSource [] (builtins.path {
|
||||
inherit name;
|
||||
path = ./.;
|
||||
});
|
||||
pwd = ./.;
|
||||
subPackages = ["cmd/ugitd"];
|
||||
CGO_ENABLED = 0;
|
||||
flags = [
|
||||
"-trimpath"
|
||||
}:
|
||||
let
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"i686-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-linux"
|
||||
"armv6l-linux"
|
||||
"armv7l-linux"
|
||||
];
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
"-extldflags -static"
|
||||
];
|
||||
meta = with pkgs.lib; {
|
||||
description = "Minimal git server";
|
||||
homepage = "https://git.jolheiser.com/ugit";
|
||||
maintainers = with maintainers; [jolheiser];
|
||||
mainProgram = "ugitd";
|
||||
};
|
||||
};
|
||||
in {
|
||||
packages.${system}.default = ugit;
|
||||
devShells.${system}.default = pkgs.mkShell {
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems f;
|
||||
tctp = forAllSystems (system: tailwind-ctp.packages.${system}.default);
|
||||
tctpl = forAllSystems (system: tailwind-ctp-lsp.packages.${system}.default);
|
||||
in
|
||||
{
|
||||
packages = forAllSystems (system: import ./nix { pkgs = import nixpkgs { inherit system; }; });
|
||||
devShells = forAllSystems (
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
in
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs; [
|
||||
go
|
||||
gopls
|
||||
gomod2nix.legacyPackages.${system}.gomod2nix
|
||||
templ
|
||||
tailwind-ctp
|
||||
tailwind-ctp-lsp
|
||||
air
|
||||
tctp.${system}
|
||||
tctpl.${system}
|
||||
vscode-langservers-extracted
|
||||
];
|
||||
};
|
||||
nixosModules.default = {
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
cfg = config.services.ugit;
|
||||
yamlFormat = pkgs.formats.yaml {};
|
||||
configFile = pkgs.writeText "ugit.yaml" (builtins.readFile (yamlFormat.generate "ugit-yaml" cfg.config));
|
||||
authorizedKeysFile = pkgs.writeText "ugit_keys" (builtins.concatStringsSep "\n" cfg.authorizedKeys);
|
||||
in {
|
||||
options = let
|
||||
inherit (lib) mkEnableOption mkOption types;
|
||||
in {
|
||||
services.ugit = {
|
||||
enable = mkEnableOption "Enable ugit";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
description = "ugit package to use";
|
||||
default = ugit;
|
||||
}
|
||||
);
|
||||
nixosModules.default = import ./nix/module.nix;
|
||||
nixosConfigurations.ugitVM = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
./nix/vm.nix
|
||||
{
|
||||
virtualisation.vmVariant.virtualisation = {
|
||||
cores = 2;
|
||||
memorySize = 2048;
|
||||
graphics = false;
|
||||
};
|
||||
|
||||
tsAuthKey = mkOption {
|
||||
type = types.str;
|
||||
description = "Tailscale one-time auth-key";
|
||||
default = "";
|
||||
};
|
||||
|
||||
repoDir = mkOption {
|
||||
type = types.str;
|
||||
description = "where ugit stores repositories";
|
||||
default = "/var/lib/ugit/repos";
|
||||
};
|
||||
|
||||
authorizedKeys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "list of keys to use for authorized_keys";
|
||||
default = [];
|
||||
};
|
||||
|
||||
authorizedKeysFile = mkOption {
|
||||
type = types.str;
|
||||
description = "path to authorized_keys file ugit uses for auth";
|
||||
default = "/var/lib/ugit/authorized_keys";
|
||||
};
|
||||
|
||||
hostKeyFile = mkOption {
|
||||
type = types.str;
|
||||
description = "path to host key file (will be created if it doesn't exist)";
|
||||
default = "/var/lib/ugit/ugit_ed25519";
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "config.yaml contents";
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "ugit";
|
||||
description = "User account under which ugit runs";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "ugit";
|
||||
description = "Group account under which ugit runs";
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
users.users."${cfg.user}" = {
|
||||
home = "/var/lib/ugit";
|
||||
createHome = true;
|
||||
group = "${cfg.group}";
|
||||
isSystemUser = true;
|
||||
isNormalUser = false;
|
||||
description = "user for ugit service";
|
||||
};
|
||||
users.groups."${cfg.group}" = {};
|
||||
networking.firewall = lib.mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [8448 8449];
|
||||
};
|
||||
|
||||
systemd.services.ugit = {
|
||||
enable = true;
|
||||
script = let
|
||||
authorizedKeysPath =
|
||||
if (builtins.length cfg.authorizedKeys) > 0
|
||||
then authorizedKeysFile
|
||||
else cfg.authorizedKeysFile;
|
||||
args = [
|
||||
"--config=${configFile}"
|
||||
"--repo-dir=${cfg.repoDir}"
|
||||
"--ssh.authorized-keys=${authorizedKeysPath}"
|
||||
"--ssh.host-key=${cfg.hostKeyFile}"
|
||||
system.stateVersion = "23.11";
|
||||
}
|
||||
];
|
||||
in "${cfg.package}/bin/ugitd ${builtins.concatStringsSep " " args}";
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network.target"];
|
||||
path = [cfg.package pkgs.git pkgs.bash];
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
Restart = "always";
|
||||
RestartSec = "15";
|
||||
WorkingDirectory = "/var/lib/ugit";
|
||||
Environment = ["TS_AUTHKEY=${cfg.tsAuthKey}"];
|
||||
};
|
||||
};
|
||||
};
|
||||
apps = forAllSystems (
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
in
|
||||
{
|
||||
vm = {
|
||||
type = "app";
|
||||
program = "${pkgs.writeShellScript "vm" ''
|
||||
nixos-rebuild build-vm --flake .#ugitVM
|
||||
./result/bin/run-nixos-vm
|
||||
rm nixos.qcow2
|
||||
''}";
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
171
go.mod
171
go.mod
|
@ -1,141 +1,84 @@
|
|||
module go.jolheiser.com/ugit
|
||||
|
||||
go 1.22.3
|
||||
go 1.23.1
|
||||
|
||||
toolchain go1.23.3
|
||||
|
||||
require (
|
||||
github.com/a-h/templ v0.2.543
|
||||
github.com/alecthomas/chroma/v2 v2.12.0
|
||||
github.com/charmbracelet/log v0.3.1
|
||||
github.com/charmbracelet/ssh v0.0.0-20240201134204-3f297de25560
|
||||
github.com/charmbracelet/wish v1.3.0
|
||||
github.com/alecthomas/assert/v2 v2.11.0
|
||||
github.com/alecthomas/chroma/v2 v2.15.0
|
||||
github.com/charmbracelet/bubbles v0.21.0
|
||||
github.com/charmbracelet/bubbletea v1.3.5
|
||||
github.com/charmbracelet/lipgloss v1.1.0
|
||||
github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c
|
||||
github.com/charmbracelet/wish v1.4.4
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/go-chi/chi/v5 v5.0.11
|
||||
github.com/go-chi/chi/v5 v5.2.0
|
||||
github.com/go-chi/httplog/v2 v2.1.1
|
||||
github.com/go-git/go-billy/v5 v5.5.0
|
||||
github.com/go-git/go-git/v5 v5.11.0
|
||||
github.com/go-git/go-billy/v5 v5.6.1
|
||||
github.com/go-git/go-git/v5 v5.13.1
|
||||
github.com/peterbourgon/ff/v3 v3.4.0
|
||||
github.com/yuin/goldmark v1.6.0
|
||||
github.com/yuin/goldmark-emoji v1.0.2
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
github.com/yuin/goldmark-emoji v1.0.4
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||
go.jolheiser.com/tailroute v0.0.0-20240726150858-67ef456b46b5
|
||||
golang.org/x/net v0.23.0
|
||||
golang.org/x/net v0.34.0
|
||||
maragu.dev/gomponents v1.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.0.0 // indirect
|
||||
github.com/akutz/memconn v0.1.0 // indirect
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.4 // indirect
|
||||
github.com/alecthomas/repr v0.4.0 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect
|
||||
github.com/aws/smithy-go v1.19.0 // indirect
|
||||
github.com/atotto/clipboard v0.1.4 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.13.0 // indirect
|
||||
github.com/charmbracelet/bubbletea v0.25.0 // indirect
|
||||
github.com/charmbracelet/keygen v0.5.0 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.9.1 // indirect
|
||||
github.com/charmbracelet/x/errors v0.0.0-20240130180102-bafe6fbaee60 // indirect
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240130180102-bafe6fbaee60 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 // indirect
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
|
||||
github.com/creack/pty v1.1.21 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
|
||||
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect
|
||||
github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||
github.com/charmbracelet/keygen v0.5.1 // indirect
|
||||
github.com/charmbracelet/log v0.4.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
|
||||
github.com/charmbracelet/x/conpty v0.1.0 // indirect
|
||||
github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5 // indirect
|
||||
github.com/charmbracelet/x/input v0.2.0 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/charmbracelet/x/termios v0.1.0 // indirect
|
||||
github.com/cloudflare/circl v1.5.0 // indirect
|
||||
github.com/creack/pty v1.1.24 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
|
||||
github.com/gaissmai/bart v0.4.1 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/csrf v1.7.2 // indirect
|
||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
|
||||
github.com/illarion/gonotify v1.0.1 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect
|
||||
github.com/jsimonetti/rtnetlink v1.4.0 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mdlayher/genetlink v1.3.2 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/sdnotify v1.0.0 // indirect
|
||||
github.com/mdlayher/socket v0.5.0 // indirect
|
||||
github.com/miekg/dns v1.1.58 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mmcloughlin/avo v0.6.0 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/prometheus-community/pro-bing v0.4.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.6 // indirect
|
||||
github.com/safchain/ethtool v0.3.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.1 // indirect
|
||||
github.com/skeema/knownhosts v1.2.1 // indirect
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
|
||||
github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 // indirect
|
||||
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect
|
||||
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect
|
||||
github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 // indirect
|
||||
github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 // indirect
|
||||
github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 // indirect
|
||||
github.com/tailscale/wireguard-go v0.0.0-20240429185444-03c5a0ccf754 // indirect
|
||||
github.com/tcnksm/go-httpstat v0.2.0 // indirect
|
||||
github.com/u-root/u-root v0.12.0 // indirect
|
||||
github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e // indirect
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sahilm/fuzzy v0.1.1 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
|
||||
golang.org/x/mod v0.16.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/term v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.19.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/tools v0.29.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20240306221502-ee1e1f6070e3 // indirect
|
||||
nhooyr.io/websocket v1.8.10 // indirect
|
||||
tailscale.com v1.68.2 // indirect
|
||||
)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
sha256-L87PnM43gHrDcsRr3wnkB4e1Th2S0LsSwkXuebAFH44=
|
458
go.sum
458
go.sum
|
@ -1,195 +1,108 @@
|
|||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc=
|
||||
filippo.io/mkcert v1.4.4/go.mod h1:VyvOchVuAye3BoUsPUOOofKygVwLV2KQMVFJNRq+1dA=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
||||
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/a-h/templ v0.2.543 h1:8YyLvyUtf0/IE2nIwZ62Z/m2o2NqwhnMynzOL78Lzbk=
|
||||
github.com/a-h/templ v0.2.543/go.mod h1:jP908DQCwI08IrnTalhzSEH9WJqG/Q94+EODQcJGFUA=
|
||||
github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
|
||||
github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw=
|
||||
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
|
||||
github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
|
||||
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 v1.1.4 h1:G5U5asvD5N/6/36oIw3k2bOfBn5XVcZrb7PBjzzKKoE=
|
||||
github.com/ProtonMail/go-crypto v1.1.4/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
|
||||
github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw=
|
||||
github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
|
||||
github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
|
||||
github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
|
||||
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
||||
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
|
||||
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
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/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.5 h1:lodGSevz7d+kkFJodfauThRxK9mdJbyutUxGq1NNhvw=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.26.5/go.mod h1:DxHrz6diQJOc9EwDslVRh84VjjrE17g+pVZXUeSxaDU=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 h1:a8HvP/+ew3tKwSXqL3BCSjiuicr+XTU2eFYeogV9GJE=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U=
|
||||
github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM=
|
||||
github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
||||
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
|
||||
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
|
||||
github.com/charmbracelet/keygen v0.5.0 h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc=
|
||||
github.com/charmbracelet/keygen v0.5.0/go.mod h1:DfvCgLHxZ9rJxdK0DGw3C/LkV4SgdGbnliHcObV3L+8=
|
||||
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
|
||||
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
|
||||
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
|
||||
github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
|
||||
github.com/charmbracelet/ssh v0.0.0-20240201134204-3f297de25560 h1:kUYiDRF04AsyJvWi4HrklXXSU7+S7qjExusfDnYbVGg=
|
||||
github.com/charmbracelet/ssh v0.0.0-20240201134204-3f297de25560/go.mod h1:IHy7o73i1MrQ5lmyJjjJ0g7y4+V+g69cm+Y7JCiZWPo=
|
||||
github.com/charmbracelet/wish v1.3.0 h1:SYV5TIlzDb6WaxjkkYXxv2WZsTu/QZGwfGVc0UB5M48=
|
||||
github.com/charmbracelet/wish v1.3.0/go.mod h1:1U/bI7zX+IE26ThD5gxtLgeRzctVhSrTpjucPqw4Pos=
|
||||
github.com/charmbracelet/x/errors v0.0.0-20240130180102-bafe6fbaee60 h1:u0XFhTN81zvoGwyQWOYjjkrimEQj5L2DPECCX5cBsRw=
|
||||
github.com/charmbracelet/x/errors v0.0.0-20240130180102-bafe6fbaee60/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240130180102-bafe6fbaee60 h1:IV19YKUZVf6ATrhiPSCirZ4Bs7EsenYwOWcUHngV+q0=
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240130180102-bafe6fbaee60/go.mod h1:kOOxxyxgAFQVcR5yQJWTuLjzt5dR2pcgwy3WaLEudjE=
|
||||
github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4=
|
||||
github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 h1:Ig+OPkE3XQrrl+SKsOqAjlkrBN/zrr+Qpw7rCuDjRCE=
|
||||
github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0=
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
||||
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||
github.com/charmbracelet/bubbletea v1.3.5 h1:JAMNLTbqMOhSwoELIr0qyP4VidFq72/6E9j7HHmRKQc=
|
||||
github.com/charmbracelet/bubbletea v1.3.5/go.mod h1:TkCnmH+aBd4LrXhXcqrKiYwRs7qyQx5rBgH5fVY3v54=
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
|
||||
github.com/charmbracelet/keygen v0.5.1 h1:zBkkYPtmKDVTw+cwUyY6ZwGDhRxXkEp0Oxs9sqMLqxI=
|
||||
github.com/charmbracelet/keygen v0.5.1/go.mod h1:zznJVmK/GWB6dAtjluqn2qsttiCBhA5MZSiwb80fcHw=
|
||||
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
|
||||
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
|
||||
github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c h1:treQxMBdI2PaD4eOYfFux8stfCkUxhuUxaqGcxKqVpI=
|
||||
github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c/go.mod h1:CY1xbl2z+ZeBmNWItKZyxx0zgDgnhmR57+DTsHOobJ4=
|
||||
github.com/charmbracelet/wish v1.4.4 h1:wtfoAMkf8Db9zi+9Lme2f7XKMxL6BqfgDWbqcTUHLaU=
|
||||
github.com/charmbracelet/wish v1.4.4/go.mod h1:XB8v51UxIFMRlUod9lLaAgOsj/wpe+qW9HjsoYIiNMo=
|
||||
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
|
||||
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||
github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U=
|
||||
github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ=
|
||||
github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5 h1:Hx72S6S4jAfrrWE3pv9IbudVdUV4htBgkOX800o17Bk=
|
||||
github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/charmbracelet/x/input v0.2.0 h1:1Sv+y/flcqUfUH2PXNIDKDIdT2G8smOnGOgawqhwy8A=
|
||||
github.com/charmbracelet/x/input v0.2.0/go.mod h1:KUSFIS6uQymtnr5lHVSOK9j8RvwTD4YHnWnzJUYnd/M=
|
||||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||
github.com/charmbracelet/x/termios v0.1.0 h1:y4rjAHeFksBAfGbkRDmVinMg7x7DELIGAFbdNvxg97k=
|
||||
github.com/charmbracelet/x/termios v0.1.0/go.mod h1:H/EVv/KRnrYjz+fCYa9bsKdqF3S8ouDK0AZEbG7r+/U=
|
||||
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
||||
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6/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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk=
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ=
|
||||
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q=
|
||||
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A=
|
||||
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
|
||||
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dsnet/try v0.0.3 h1:ptR59SsrcFUYbT/FhAbKTV6iLkeD6O18qfIWRml2fqI=
|
||||
github.com/dsnet/try v0.0.3/go.mod h1:WBM8tRpUmnXXhY1U6/S8dt6UWdHTQ7y8A5YSkRCkq40=
|
||||
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/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ=
|
||||
github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
|
||||
github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
|
||||
github.com/gaissmai/bart v0.4.1 h1:G1t58voWkNmT47lBDawH5QhtTDsdqRIO+ftq5x4P9Ls=
|
||||
github.com/gaissmai/bart v0.4.1/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg=
|
||||
github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I=
|
||||
github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo=
|
||||
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-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
|
||||
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
|
||||
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/httplog/v2 v2.1.1 h1:ojojiu4PIaoeJ/qAO4GWUxJqvYUTobeo7zmuHQJAxRk=
|
||||
github.com/go-chi/httplog/v2 v2.1.1/go.mod h1:/XXdxicJsp4BA5fapgIC3VuTD+z0Z/VzukoB3VDc1YE=
|
||||
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.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA=
|
||||
github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg=
|
||||
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA=
|
||||
github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
|
||||
github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg=
|
||||
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
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/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI=
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI=
|
||||
github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk=
|
||||
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
|
||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
|
||||
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
|
||||
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/hugelgupf/vmtest v0.0.0-20240102225328-693afabdd27f h1:ov45/OzrJG8EKbGjn7jJZQJTN7Z1t73sFYNIRd64YlI=
|
||||
github.com/hugelgupf/vmtest v0.0.0-20240102225328-693afabdd27f/go.mod h1:JoDrYMZpDPYo6uH9/f6Peqms3zNNWT2XiGgioMOIGuI=
|
||||
github.com/illarion/gonotify v1.0.1 h1:F1d+0Fgbq/sDWjj/r66ekjDG+IDeecQKUFH4wNwsoio=
|
||||
github.com/illarion/gonotify v1.0.1/go.mod h1:zt5pmDofZpU1f8aqlK0+95eQhoEAn/d4G4B/FjVW4jE=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI=
|
||||
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/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g=
|
||||
github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk=
|
||||
github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8=
|
||||
github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I=
|
||||
github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E=
|
||||
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/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ=
|
||||
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
|
@ -197,212 +110,96 @@ 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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c=
|
||||
github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE=
|
||||
github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
|
||||
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
|
||||
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc=
|
||||
github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||
github.com/pjbgf/sha1cd v0.3.1 h1:Dh2GYdpJnO84lIw0LJwTFXjcNbasP/bklicSznyAaPI=
|
||||
github.com/pjbgf/sha1cd v0.3.1/go.mod h1:Y8t7jSB/dEI/lQE04A1HVKteqjj9bX5O4+Cex0TCu8s=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
|
||||
github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4=
|
||||
github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
|
||||
github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0=
|
||||
github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
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/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
||||
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
|
||||
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
|
||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
||||
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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ=
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4=
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4=
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg=
|
||||
github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 h1:rXZGgEa+k2vJM8xT0PoSKfVXwFGPQ3z3CJfmnHJkZZw=
|
||||
github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ=
|
||||
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio=
|
||||
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8=
|
||||
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw=
|
||||
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8=
|
||||
github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85 h1:zrsUcqrG2uQSPhaUPjUQwozcRdDdSxxqhNgNZ3drZFk=
|
||||
github.com/tailscale/netlink v1.1.1-0.20211101221916-cabfb018fe85/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0=
|
||||
github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 h1:Gz0rz40FvFVLTBk/K8UNAenb36EbDSnh+q7Z9ldcC8w=
|
||||
github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4/go.mod h1:phI29ccmHQBc+wvroosENp1IF9195449VDnFDhJ4rJU=
|
||||
github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 h1:tdUdyPqJ0C97SJfjB9tW6EylTtreyee9C44de+UBG0g=
|
||||
github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ=
|
||||
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M=
|
||||
github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6/go.mod h1:ZXRML051h7o4OcI0d3AaILDIad/Xw0IkXaHM17dic1Y=
|
||||
github.com/tailscale/wireguard-go v0.0.0-20240429185444-03c5a0ccf754 h1:iazWjqVHE6CbNam7WXRhi33Qad5o7a8LVYgVoILpZdI=
|
||||
github.com/tailscale/wireguard-go v0.0.0-20240429185444-03c5a0ccf754/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4=
|
||||
github.com/tailscale/xnet v0.0.0-20240117122442-62b9a7c569f9 h1:81P7rjnikHKTJ75EkjppvbwUfKHDHYk6LJpO5PZy8pA=
|
||||
github.com/tailscale/xnet v0.0.0-20240117122442-62b9a7c569f9/go.mod h1:orPd6JZXXRyuDusYilywte7k094d7dycXXU5YnWsrwg=
|
||||
github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA=
|
||||
github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=
|
||||
github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0=
|
||||
github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8=
|
||||
github.com/u-root/gobusybox/src v0.0.0-20231228173702-b69f654846aa h1:unMPGGK/CRzfg923allsikmvk2l7beBeFPUNC4RVX/8=
|
||||
github.com/u-root/gobusybox/src v0.0.0-20231228173702-b69f654846aa/go.mod h1:Zj4Tt22fJVn/nz/y6Ergm1SahR9dio1Zm/D2/S0TmXM=
|
||||
github.com/u-root/u-root v0.12.0 h1:K0AuBFriwr0w/PGS3HawiAw89e3+MU7ks80GpghAsNs=
|
||||
github.com/u-root/u-root v0.12.0/go.mod h1:FYjTOh4IkIZHhjsd17lb8nYW6udgXdJhG1c0r6u0arI=
|
||||
github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e h1:BA9O3BmlTmpjbvajAwzWx4Wo2TRVdpPXZEeemGQcajw=
|
||||
github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264=
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs=
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
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.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
|
||||
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GAsO5s=
|
||||
github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY=
|
||||
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark-emoji v1.0.4 h1:vCwMkPZSNefSUnOW2ZKRUjBSD5Ok3W78IXhGxxAEF90=
|
||||
github.com/yuin/goldmark-emoji v1.0.4/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
|
||||
go.jolheiser.com/tailroute v0.0.0-20240726150858-67ef456b46b5 h1:SJ4Y1f52dpC7c9Svl7dfwd2upkhB66cr8/l1TDTAUY4=
|
||||
go.jolheiser.com/tailroute v0.0.0-20240726150858-67ef456b46b5/go.mod h1:CVL6F82hiqQ849aFeDZl1YolqiEKyY24oxxfjy8bZAc=
|
||||
go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8=
|
||||
go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
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-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||
golang.org/x/exp/typeparams v0.0.0-20240119083558-1b970713d09a h1:8qmSSA8Gz/1kTrCe0nqR0R3Gb/NDhykzWw2q2mWZydM=
|
||||
golang.org/x/exp/typeparams v0.0.0-20240119083558-1b970713d09a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
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/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
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.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/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-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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/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-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
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.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
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/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
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.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
|
@ -410,21 +207,10 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
|
|||
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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=
|
||||
gvisor.dev/gvisor v0.0.0-20240306221502-ee1e1f6070e3 h1:/8/t5pz/mgdRXhYOIeqqYhFAQLE4DDGegc0Y4ZjyFJM=
|
||||
gvisor.dev/gvisor v0.0.0-20240306221502-ee1e1f6070e3/go.mod h1:NQHVAzMwvZ+Qe3ElSiHmq9RUm1MdNHpUZ52fiEqvn+0=
|
||||
honnef.co/go/tools v0.4.6 h1:oFEHCKeID7to/3autwsWfnuv69j3NsfcXbvJKuIcep8=
|
||||
honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
|
||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q=
|
||||
nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
|
||||
tailscale.com v1.68.2 h1:nxy9HTAXPjuTbu/xzF05mS/v9ABMRGGJdPWEScTJxUo=
|
||||
tailscale.com v1.68.2/go.mod h1:uqtoDEA8tw5+S+HLGqQGfpQsqeVtBS/EVVv5mXIaAoQ=
|
||||
maragu.dev/gomponents v1.0.0 h1:eeLScjq4PqP1l+r5z/GC+xXZhLHXa6RWUWGW7gSfLh4=
|
||||
maragu.dev/gomponents v1.0.0/go.mod h1:oEDahza2gZoXDoDHhw8jBNgH+3UR5ni7Ur648HORydM=
|
||||
|
|
399
gomod2nix.toml
399
gomod2nix.toml
|
@ -1,399 +0,0 @@
|
|||
schema = 3
|
||||
|
||||
[mod]
|
||||
[mod."dario.cat/mergo"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-jlpc8dDj+DmiOU4gEawBu8poJJj9My0s9Mvuk9oS8ww="
|
||||
[mod."filippo.io/edwards25519"]
|
||||
version = "v1.1.0"
|
||||
hash = "sha256-9ACANrgWZSd5HYPfDZHY8DVbPSC9LOMgy8deq3rDOoc="
|
||||
[mod."github.com/Microsoft/go-winio"]
|
||||
version = "v0.6.1"
|
||||
hash = "sha256-BL0BVaHtmPKQts/711W59AbHXjGKqFS4ZTal0RYnR9I="
|
||||
[mod."github.com/ProtonMail/go-crypto"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-Gflazvyv+457FpUTtPafJ+SdolYSalpsU0tragTxNi8="
|
||||
[mod."github.com/a-h/templ"]
|
||||
version = "v0.2.543"
|
||||
hash = "sha256-1BvIj9UPZJp8SOXMPIGdHyZLIvjORHg2UY3pRZJM01s="
|
||||
[mod."github.com/akutz/memconn"]
|
||||
version = "v0.1.0"
|
||||
hash = "sha256-WOs/RQYjQbn41ui8ztHgWSd4jxydE+fvIrl/0dmHD9Y="
|
||||
[mod."github.com/alecthomas/chroma/v2"]
|
||||
version = "v2.12.0"
|
||||
hash = "sha256-w3gKGPwsoayknuU4ifPaF0JOMNqnKjIEutbIkR9c2Ag="
|
||||
[mod."github.com/alexbrainman/sspi"]
|
||||
version = "v0.0.0-20231016080023-1a75b4708caa"
|
||||
hash = "sha256-Joa/NfBofK7lRlknQ5LVYD4M/dpd9xaCqsvYUBhKW0I="
|
||||
[mod."github.com/anmitsu/go-shlex"]
|
||||
version = "v0.0.0-20200514113438-38f4b401e2be"
|
||||
hash = "sha256-L3Ak4X2z7WXq7vMKuiHCOJ29nlpajUQ08Sfb9T0yP54="
|
||||
[mod."github.com/aws/aws-sdk-go-v2"]
|
||||
version = "v1.24.1"
|
||||
hash = "sha256-qZDUrodVDWWtdQ6zYuNHxpXt2quK56pPoZsKdRGmYzk="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/config"]
|
||||
version = "v1.26.5"
|
||||
hash = "sha256-RAXQlnUAsxgi2BndS+Uh2Cw+TCbtUx9BB0Tqqz50rLE="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/credentials"]
|
||||
version = "v1.16.16"
|
||||
hash = "sha256-qjtE3/VxNAEtS68nLXULgjO+LO3EkayGkr2iU300xdA="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/feature/ec2/imds"]
|
||||
version = "v1.14.11"
|
||||
hash = "sha256-j8LHZYM+rBmWHV1PT/H6lDL/3vgBqvQxoY2bVuOi7zo="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/internal/configsources"]
|
||||
version = "v1.2.10"
|
||||
hash = "sha256-fhrws72g+ecgXnkiip0GQ206XfVdxDA7/Rz9X3nvgd8="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/internal/endpoints/v2"]
|
||||
version = "v2.5.10"
|
||||
hash = "sha256-Rbj+matn96a/3Nj8EpLgrTycSV+331+WWJd5Lpk1LlQ="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/internal/ini"]
|
||||
version = "v1.7.2"
|
||||
hash = "sha256-6ev22rRSz4TuoX1AoCDr67qA15kg+cHMuQeTXwp8AFg="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding"]
|
||||
version = "v1.10.4"
|
||||
hash = "sha256-Wvbil3pNKlCyn0SWNXCobxzJGeE+2Eb7GNP2OZATTfY="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/service/internal/presigned-url"]
|
||||
version = "v1.10.10"
|
||||
hash = "sha256-vUSnrZzo3mzfZsthjjZRmGNrXkQ4D2B7Glzu66N5MrQ="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/service/ssm"]
|
||||
version = "v1.44.7"
|
||||
hash = "sha256-U7XGN5O0Ksp6O3a2Nkb0WinTwuIHjCw5UNSwPjrMo8k="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/service/sso"]
|
||||
version = "v1.18.7"
|
||||
hash = "sha256-+1q43+9Cx/K3/T+LJJLV1h2PLHsG/YKHUSgwC5r3uNQ="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/service/ssooidc"]
|
||||
version = "v1.21.7"
|
||||
hash = "sha256-aoolSWOU3Sb3weV2yf2wACuh3fYaUmyGXCZ2dTvcg4A="
|
||||
[mod."github.com/aws/aws-sdk-go-v2/service/sts"]
|
||||
version = "v1.26.7"
|
||||
hash = "sha256-0LGfjSa65wNKuV/TH66XfN/uF4lZF9bSszbfTFWcLjY="
|
||||
[mod."github.com/aws/smithy-go"]
|
||||
version = "v1.19.0"
|
||||
hash = "sha256-KsQMOHJFIXRF+8c4WxiXA/u1Ok6hEF6eylvnfdRGivg="
|
||||
[mod."github.com/aymanbagabas/go-osc52/v2"]
|
||||
version = "v2.0.1"
|
||||
hash = "sha256-6Bp0jBZ6npvsYcKZGHHIUSVSTAMEyieweAX2YAKDjjg="
|
||||
[mod."github.com/bits-and-blooms/bitset"]
|
||||
version = "v1.13.0"
|
||||
hash = "sha256-1jccFEH9In72Jt3wSn4vi4/MJd/UDfDrC9DlmsGVc9o="
|
||||
[mod."github.com/charmbracelet/bubbletea"]
|
||||
version = "v0.25.0"
|
||||
hash = "sha256-A0WjFRFAUhwO3m7uvCOeefPPIM8ReU+xTtIRxG0aH+Y="
|
||||
[mod."github.com/charmbracelet/keygen"]
|
||||
version = "v0.5.0"
|
||||
hash = "sha256-JFD2SdFL7tq3oVhnBEgiBTrJvjqdUtIuodAJuSFcJoA="
|
||||
[mod."github.com/charmbracelet/lipgloss"]
|
||||
version = "v0.9.1"
|
||||
hash = "sha256-AHbabOymgDRIXsMBgJHS25/GgBWT54oGbd15EBWKeZc="
|
||||
[mod."github.com/charmbracelet/log"]
|
||||
version = "v0.3.1"
|
||||
hash = "sha256-Er60POPID2eNrRZnBHxoI4yHn0mIKnXYftGKSslbXx0="
|
||||
[mod."github.com/charmbracelet/ssh"]
|
||||
version = "v0.0.0-20240201134204-3f297de25560"
|
||||
hash = "sha256-r4h4bym47rs3C2us+sCgVfwAl4TCbm3bDCTsXKYREz8="
|
||||
[mod."github.com/charmbracelet/wish"]
|
||||
version = "v1.3.0"
|
||||
hash = "sha256-3Uq1PDu5DMoWgJykFx/roGk20x8jdb7o5JFPpmEtX/c="
|
||||
[mod."github.com/charmbracelet/x/errors"]
|
||||
version = "v0.0.0-20240130180102-bafe6fbaee60"
|
||||
hash = "sha256-GO8hf0lhVtl00C+xoTzvBtPU2cO0PymSLc2szBRUNtE="
|
||||
[mod."github.com/charmbracelet/x/exp/term"]
|
||||
version = "v0.0.0-20240130180102-bafe6fbaee60"
|
||||
hash = "sha256-hEj/Gj1U1ahk5EFVZVAL52yrdBNO47yXykpiehJICbc="
|
||||
[mod."github.com/cloudflare/circl"]
|
||||
version = "v1.3.7"
|
||||
hash = "sha256-AkOpcZ+evLxLJStvvr01+TLeWDqcLxY3e/AhGggzh40="
|
||||
[mod."github.com/containerd/console"]
|
||||
version = "v1.0.4-0.20230706203907-8f6c4e4faef5"
|
||||
hash = "sha256-mxRERsgS6TmI5I0UYblhzl2FZlbtkJhUkfF1x6mZINw="
|
||||
[mod."github.com/coreos/go-iptables"]
|
||||
version = "v0.7.1-0.20240112124308-65c67c9f46e6"
|
||||
hash = "sha256-kjnry8ld5Keew5q+tX7GSdGVZaXlehs2Lt+z8Rokhns="
|
||||
[mod."github.com/creack/pty"]
|
||||
version = "v1.1.21"
|
||||
hash = "sha256-pjGw6wQlrVhN65XaIxZueNJqnXThGu00u24rKOLzxS0="
|
||||
[mod."github.com/cyphar/filepath-securejoin"]
|
||||
version = "v0.2.4"
|
||||
hash = "sha256-heCD0xMxlwnHCHcRBgTjVexHOLyWI2zRW3E8NFKoLzk="
|
||||
[mod."github.com/dblohm7/wingoes"]
|
||||
version = "v0.0.0-20240119213807-a09d6be7affa"
|
||||
hash = "sha256-zUj7jSZQiX53+4OyRq7LaQXp8nx8+JRpyT6IFdktyw0="
|
||||
[mod."github.com/digitalocean/go-smbios"]
|
||||
version = "v0.0.0-20180907143718-390a4f403a8e"
|
||||
hash = "sha256-Hgx1ML3rigdYXx5ntnEYD5JEk6kJv1cL0+/GDbnPkbo="
|
||||
[mod."github.com/dlclark/regexp2"]
|
||||
version = "v1.10.0"
|
||||
hash = "sha256-Jxzj/O/Q9tIWBOOgCkCibhrgJBzzfVIxYDsabt7O8ow="
|
||||
[mod."github.com/dustin/go-humanize"]
|
||||
version = "v1.0.1"
|
||||
hash = "sha256-yuvxYYngpfVkUg9yAmG99IUVmADTQA0tMbBXe0Fq0Mc="
|
||||
[mod."github.com/emirpasic/gods"]
|
||||
version = "v1.18.1"
|
||||
hash = "sha256-hGDKddjLj+5dn2woHtXKUdd49/3xdsqnhx7VEdCu1m4="
|
||||
[mod."github.com/fxamacker/cbor/v2"]
|
||||
version = "v2.5.0"
|
||||
hash = "sha256-2rhvuNZjeidDP+Og6Q0u4ROiaPrEOjoI5wCb17XRnOQ="
|
||||
[mod."github.com/gaissmai/bart"]
|
||||
version = "v0.4.1"
|
||||
hash = "sha256-Zz+8yx+y6QtF2raJo01ldzKIlqfxLX3eqLr6ub+Byzw="
|
||||
[mod."github.com/go-chi/chi/v5"]
|
||||
version = "v5.0.11"
|
||||
hash = "sha256-95LKg/OVzhik2HUz6cirHH3eAT4qbHSg52bSvkc+XOY="
|
||||
[mod."github.com/go-chi/httplog/v2"]
|
||||
version = "v2.1.1"
|
||||
hash = "sha256-bMpoHUSNk3Uds9NfrStwhDsdCONR4pJso9sVUhqfidk="
|
||||
[mod."github.com/go-git/gcfg"]
|
||||
version = "v1.5.1-0.20230307220236-3a3c6141e376"
|
||||
hash = "sha256-f4k0gSYuo0/q3WOoTxl2eFaj7WZpdz29ih6CKc8Ude8="
|
||||
[mod."github.com/go-git/go-billy/v5"]
|
||||
version = "v5.5.0"
|
||||
hash = "sha256-4XUoD2bOCMCdu83egb/y8kY/Fm0s1rWgPMtiahh38OQ="
|
||||
[mod."github.com/go-git/go-git/v5"]
|
||||
version = "v5.11.0"
|
||||
hash = "sha256-2yUM/FlV+nYxacVynJCnDZeMub4Iu8JL2WBHmlnwOkE="
|
||||
[mod."github.com/go-json-experiment/json"]
|
||||
version = "v0.0.0-20231102232822-2e55bd4e08b0"
|
||||
hash = "sha256-ltOLec3r0dGA/k1TTrQjuMuHxdxBlALkfLbdKuUNvmg="
|
||||
[mod."github.com/go-logfmt/logfmt"]
|
||||
version = "v0.6.0"
|
||||
hash = "sha256-RtIG2qARd5sT10WQ7F3LR8YJhS8exs+KiuUiVf75bWg="
|
||||
[mod."github.com/go-ole/go-ole"]
|
||||
version = "v1.3.0"
|
||||
hash = "sha256-tF8t3VcV71jQ4jbPL91BwR59AKDpUAFV1waIKzkXJu8="
|
||||
[mod."github.com/godbus/dbus/v5"]
|
||||
version = "v5.1.1-0.20230522191255-76236955d466"
|
||||
hash = "sha256-OdcyeoGQ4xWUpl21WKXkbAm8yZHMDp8giY02arupjb4="
|
||||
[mod."github.com/golang/groupcache"]
|
||||
version = "v0.0.0-20210331224755-41bb18bfe9da"
|
||||
hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0="
|
||||
[mod."github.com/google/btree"]
|
||||
version = "v1.1.2"
|
||||
hash = "sha256-K7V2obq3pLM71Mg0vhhHtZ+gtaubwXPQx3xcIyZDCjM="
|
||||
[mod."github.com/google/go-cmp"]
|
||||
version = "v0.6.0"
|
||||
hash = "sha256-qgra5jze4iPGP0JSTVeY5qV5AvEnEu39LYAuUCIkMtg="
|
||||
[mod."github.com/google/nftables"]
|
||||
version = "v0.2.1-0.20240414091927-5e242ec57806"
|
||||
hash = "sha256-OXMzx4Exf++E4UzCUE1gw3TOrfyI187cFu3cDZ9ifKU="
|
||||
[mod."github.com/google/uuid"]
|
||||
version = "v1.6.0"
|
||||
hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw="
|
||||
[mod."github.com/gorilla/csrf"]
|
||||
version = "v1.7.2"
|
||||
hash = "sha256-pzOWbw8AOjhdRJYKlPBfh1j9a8TGNxgrlS4AmZpE1s8="
|
||||
[mod."github.com/gorilla/securecookie"]
|
||||
version = "v1.1.2"
|
||||
hash = "sha256-KeMHNM9emxX+N0WYiZsTii7n8sNsmjWwbnQ9SaJfTKE="
|
||||
[mod."github.com/hdevalence/ed25519consensus"]
|
||||
version = "v0.2.0"
|
||||
hash = "sha256-KTbeKMOT/HCJjDHqyciQjJPPgpNk6H0VyQCCbeGgs7Y="
|
||||
[mod."github.com/illarion/gonotify"]
|
||||
version = "v1.0.1"
|
||||
hash = "sha256-73KDUfk5iNo12u+nNN2H4UTfJ1FlLifahnFNPzV1P/k="
|
||||
[mod."github.com/insomniacslk/dhcp"]
|
||||
version = "v0.0.0-20231206064809-8c70d406f6d2"
|
||||
hash = "sha256-PHiso7HGNjCGbGdZ7TMGnSGzPDUTpvWpqAccoKPAaWM="
|
||||
[mod."github.com/jbenet/go-context"]
|
||||
version = "v0.0.0-20150711004518-d14ea06fba99"
|
||||
hash = "sha256-VANNCWNNpARH/ILQV9sCQsBWgyL2iFT+4AHZREpxIWE="
|
||||
[mod."github.com/jmespath/go-jmespath"]
|
||||
version = "v0.4.0"
|
||||
hash = "sha256-xpT9g2qIXmPq7eeHUXHiDqJeQoHCudh44G/KCSFbcuo="
|
||||
[mod."github.com/josharian/native"]
|
||||
version = "v1.1.1-0.20230202152459-5c7d0dd6ab86"
|
||||
hash = "sha256-dgyrLXuM55z8FAoUjyt5TDlzim6HfphWo5wx1/DHLwE="
|
||||
[mod."github.com/jsimonetti/rtnetlink"]
|
||||
version = "v1.4.0"
|
||||
hash = "sha256-GnrF2yxgm/h1JSTN1PwI4ysTl+oY0AyWzf3Ni7LZqRM="
|
||||
[mod."github.com/kevinburke/ssh_config"]
|
||||
version = "v1.2.0"
|
||||
hash = "sha256-Ta7ZOmyX8gG5tzWbY2oES70EJPfI90U7CIJS9EAce0s="
|
||||
[mod."github.com/klauspost/compress"]
|
||||
version = "v1.17.4"
|
||||
hash = "sha256-5E7dDtDKfL3jy7zJxHBMV57WlHZrP/OoEX5e6cOPba0="
|
||||
[mod."github.com/kortschak/wol"]
|
||||
version = "v0.0.0-20200729010619-da482cc4850a"
|
||||
hash = "sha256-lnr9r/KNv4EeeNohFImC3Vd5E9nJ0N+4ZZ0VHFjwHps="
|
||||
[mod."github.com/lucasb-eyer/go-colorful"]
|
||||
version = "v1.2.0"
|
||||
hash = "sha256-Gg9dDJFCTaHrKHRR1SrJgZ8fWieJkybljybkI9x0gyE="
|
||||
[mod."github.com/mattn/go-isatty"]
|
||||
version = "v0.0.20"
|
||||
hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ="
|
||||
[mod."github.com/mattn/go-localereader"]
|
||||
version = "v0.0.1"
|
||||
hash = "sha256-JlWckeGaWG+bXK8l8WEdZqmSiTwCA8b1qbmBKa/Fj3E="
|
||||
[mod."github.com/mattn/go-runewidth"]
|
||||
version = "v0.0.15"
|
||||
hash = "sha256-WP39EU2UrQbByYfnwrkBDoKN7xzXsBssDq3pNryBGm0="
|
||||
[mod."github.com/mdlayher/genetlink"]
|
||||
version = "v1.3.2"
|
||||
hash = "sha256-pgwXkyDY1dlB8tmV1lQ0Bz/2g0zmJOyXvQjacACy924="
|
||||
[mod."github.com/mdlayher/netlink"]
|
||||
version = "v1.7.2"
|
||||
hash = "sha256-08qlkKvG1+XFY3MDx7M1jdvaDMsmF9qv5/xMNaw3snc="
|
||||
[mod."github.com/mdlayher/sdnotify"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-O7MJt6Bam2bUoede07Z1T6EtW+kCJ+/4dJtYopZct1s="
|
||||
[mod."github.com/mdlayher/socket"]
|
||||
version = "v0.5.0"
|
||||
hash = "sha256-3zEbix66G+LQ2xAQW9XmkyubK9R+Vwnm09H5fqqLC7w="
|
||||
[mod."github.com/miekg/dns"]
|
||||
version = "v1.1.58"
|
||||
hash = "sha256-UGvyC1Abh2S5VaAUCV9AUuDMrCvpiWQy/UnYM9DfIB8="
|
||||
[mod."github.com/mitchellh/go-ps"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-HzxVHNLHZpnsBuPcub0G+9jjDcDOsxM/6wifbsxf7EY="
|
||||
[mod."github.com/muesli/ansi"]
|
||||
version = "v0.0.0-20230316100256-276c6243b2f6"
|
||||
hash = "sha256-qRKn0Bh2yvP0QxeEMeZe11Vz0BPFIkVcleKsPeybKMs="
|
||||
[mod."github.com/muesli/cancelreader"]
|
||||
version = "v0.2.2"
|
||||
hash = "sha256-uEPpzwRJBJsQWBw6M71FDfgJuR7n55d/7IV8MO+rpwQ="
|
||||
[mod."github.com/muesli/reflow"]
|
||||
version = "v0.3.0"
|
||||
hash = "sha256-Pou2ybE9SFSZG6YfZLVV1Eyfm+X4FuVpDPLxhpn47Cc="
|
||||
[mod."github.com/muesli/termenv"]
|
||||
version = "v0.15.2"
|
||||
hash = "sha256-Eum/SpyytcNIchANPkG4bYGBgcezLgej7j/+6IhqoMU="
|
||||
[mod."github.com/peterbourgon/ff/v3"]
|
||||
version = "v3.4.0"
|
||||
hash = "sha256-rmRl4GSmc2atnMbw6hTs6jwxW5lO4ivYuF2VN3jacZM="
|
||||
[mod."github.com/pierrec/lz4/v4"]
|
||||
version = "v4.1.21"
|
||||
hash = "sha256-u47Lm4tN2ChGDLGyR+Jpi/Mi0bOFBVT6PTpPFdu2rMU="
|
||||
[mod."github.com/pjbgf/sha1cd"]
|
||||
version = "v0.3.0"
|
||||
hash = "sha256-kX9BdLh2dxtGNaDvc24NORO+C0AZ7JzbrXrtecCdB7w="
|
||||
[mod."github.com/prometheus-community/pro-bing"]
|
||||
version = "v0.4.0"
|
||||
hash = "sha256-3TH0wB85OITw3uzTcEva2EcEF6jNf98sAoSOsnL2G9g="
|
||||
[mod."github.com/rivo/uniseg"]
|
||||
version = "v0.4.6"
|
||||
hash = "sha256-zGfzO8FWj03POzo47SzrK1B4yLMKJ7iic6ium76ZLzI="
|
||||
[mod."github.com/safchain/ethtool"]
|
||||
version = "v0.3.0"
|
||||
hash = "sha256-q5bQGHB7cyEejA9tQkrhpvzpfYRvXcmClbWBgfs3Ymc="
|
||||
[mod."github.com/sergi/go-diff"]
|
||||
version = "v1.3.1"
|
||||
hash = "sha256-XLA/BLIPuUU76yikXqIeRSXr7T7A3Uz6I27+mDxGj7w="
|
||||
[mod."github.com/skeema/knownhosts"]
|
||||
version = "v1.2.1"
|
||||
hash = "sha256-u0jB6ahTdGa+SvcIvPNRLnbSHvgmW9X/ThRq0nWQrJs="
|
||||
[mod."github.com/tailscale/certstore"]
|
||||
version = "v0.1.1-0.20231202035212-d3fa0460f47e"
|
||||
hash = "sha256-Q0HLTQPRsIizRqvdBBaLGoLascQiSpQm+X3NW3ytpDQ="
|
||||
[mod."github.com/tailscale/go-winio"]
|
||||
version = "v0.0.0-20231025203758-c4f33415bf55"
|
||||
hash = "sha256-WFW20c02gIk2MhafeVVNydmSfszPZegshDd2Y5abGgY="
|
||||
[mod."github.com/tailscale/golang-x-crypto"]
|
||||
version = "v0.0.0-20240604161659-3fde5e568aa4"
|
||||
hash = "sha256-vIrSd0emexe1lcjJqLbEtg7/TaZDnpGrDs96mxjANyE="
|
||||
[mod."github.com/tailscale/goupnp"]
|
||||
version = "v1.0.1-0.20210804011211-c64d0f06ea05"
|
||||
hash = "sha256-PRMJcYY+wjpbHkC9dQWTPErh2ID29UnFxehxmYR704I="
|
||||
[mod."github.com/tailscale/hujson"]
|
||||
version = "v0.0.0-20221223112325-20486734a56a"
|
||||
hash = "sha256-q9c2IjwbL0IgYPznVpQP1XT/8lrzH1niI3E+wjNcf5Y="
|
||||
[mod."github.com/tailscale/netlink"]
|
||||
version = "v1.1.1-0.20211101221916-cabfb018fe85"
|
||||
hash = "sha256-bMK5qqObMcxIbPy5XhOZP8TGDaXvDAHsE0FR68VMLi8="
|
||||
[mod."github.com/tailscale/peercred"]
|
||||
version = "v0.0.0-20240214030740-b535050b2aa4"
|
||||
hash = "sha256-82cdwvTUr47qMP2MHiMdY5O8vr/hA2aJ/KW2VTu97KI="
|
||||
[mod."github.com/tailscale/web-client-prebuilt"]
|
||||
version = "v0.0.0-20240226180453-5db17b287bf1"
|
||||
hash = "sha256-iE8PCr0At4P75cG7dDa6fwhARJUIUw9pwvgtQNMOjAA="
|
||||
[mod."github.com/tailscale/wireguard-go"]
|
||||
version = "v0.0.0-20240429185444-03c5a0ccf754"
|
||||
hash = "sha256-XhfEG8esndgZDoI2AeRvs95XRYiIrj/0NiVDBpOcacY="
|
||||
[mod."github.com/tcnksm/go-httpstat"]
|
||||
version = "v0.2.0"
|
||||
hash = "sha256-bCWn8E+DcZY6+yPu07AF3hCcDZx3CFdD74qfpDIgVqI="
|
||||
[mod."github.com/u-root/u-root"]
|
||||
version = "v0.12.0"
|
||||
hash = "sha256-B9Qoq1S0l0W6twET54uxiWjh2ulxN/zMLAeWJX4cXW0="
|
||||
[mod."github.com/u-root/uio"]
|
||||
version = "v0.0.0-20240118234441-a3c409a6018e"
|
||||
hash = "sha256-rUjQMG+HprbgHKzrIPFrQ6S3BCEyYQyUbA/D72mY8iU="
|
||||
[mod."github.com/vishvananda/netlink"]
|
||||
version = "v1.2.1-beta.2"
|
||||
hash = "sha256-ePReedgYT0KuAx/HOUgG76zDZ2XpW/u8bGlsWysxKzE="
|
||||
[mod."github.com/vishvananda/netns"]
|
||||
version = "v0.0.4"
|
||||
hash = "sha256-tEba2cxyk3GdCYvEIttQ8aZCzHcB0ZiUt6fUEARDkWU="
|
||||
[mod."github.com/x448/float16"]
|
||||
version = "v0.8.4"
|
||||
hash = "sha256-VKzMTMS9pIB/cwe17xPftCSK9Mf4Y6EuBEJlB4by5mE="
|
||||
[mod."github.com/xanzy/ssh-agent"]
|
||||
version = "v0.3.3"
|
||||
hash = "sha256-l3pGB6IdzcPA/HLk93sSN6NM2pKPy+bVOoacR5RC2+c="
|
||||
[mod."github.com/yuin/goldmark"]
|
||||
version = "v1.6.0"
|
||||
hash = "sha256-0PeGjGxxM7lUSx2dn8yPUBpilPQzEN9nkgf3s+5zGTY="
|
||||
[mod."github.com/yuin/goldmark-emoji"]
|
||||
version = "v1.0.2"
|
||||
hash = "sha256-RvzhNXlF98fu9SD/Rve9JMtR4bcRh7rN56Twhh/kmt4="
|
||||
[mod."github.com/yuin/goldmark-highlighting/v2"]
|
||||
version = "v2.0.0-20230729083705-37449abec8cc"
|
||||
hash = "sha256-HpiwU7jIeDUAg2zOpTIiviQir8dpRPuXYh2nqFFccpg="
|
||||
[mod."go.jolheiser.com/tailroute"]
|
||||
version = "v0.0.0-20240726150858-67ef456b46b5"
|
||||
hash = "sha256-NJBg8m3ukwBycuXj3lUtTclX1kmdw3xBW+YCKnPuU8g="
|
||||
[mod."go4.org/mem"]
|
||||
version = "v0.0.0-20220726221520-4f986261bf13"
|
||||
hash = "sha256-H2Fsuvzbqp/6JKzC03XPTQTSQBcGs+B5VGsBjrQDY3c="
|
||||
[mod."go4.org/netipx"]
|
||||
version = "v0.0.0-20231129151722-fdeea329fbba"
|
||||
hash = "sha256-qFrVlacz5R3Lpkzqeg1/1MYew3DJzY9hG0Uh/ua+SOU="
|
||||
[mod."golang.org/x/crypto"]
|
||||
version = "v0.21.0"
|
||||
hash = "sha256-Z4k1LvFh4Jai7HUe6TTuXSG3VnuiRpMwdARIdZZqSYk="
|
||||
[mod."golang.org/x/exp"]
|
||||
version = "v0.0.0-20240119083558-1b970713d09a"
|
||||
hash = "sha256-JQ3JLywTjgboNhs12blhOkS3ty7m8sUa/zaWv1k/X28="
|
||||
[mod."golang.org/x/mod"]
|
||||
version = "v0.16.0"
|
||||
hash = "sha256-aN1Cz5Wqd9YCjK8nFW6JWn+n1HfFoEcgYZmGO/FYtbw="
|
||||
[mod."golang.org/x/net"]
|
||||
version = "v0.23.0"
|
||||
hash = "sha256-ZB4504rtgsHbcRfijjlqt4/2ddb8tyQB5IBn126uVTQ="
|
||||
[mod."golang.org/x/sync"]
|
||||
version = "v0.6.0"
|
||||
hash = "sha256-LLims/wjDZtIqlYCVHREewcUOX4hwRwplEuZKPOJ/HI="
|
||||
[mod."golang.org/x/sys"]
|
||||
version = "v0.19.0"
|
||||
hash = "sha256-cmuL31TYLJmDm/fDnI2Sn0wB88cpdOHV1+urorsJWx4="
|
||||
[mod."golang.org/x/term"]
|
||||
version = "v0.18.0"
|
||||
hash = "sha256-lpze9arFZIhBV8Ht3VZyoiUwqPkeH2IwfXt8M3xljiM="
|
||||
[mod."golang.org/x/text"]
|
||||
version = "v0.14.0"
|
||||
hash = "sha256-yh3B0tom1RfzQBf1RNmfdNWF1PtiqxV41jW1GVS6JAg="
|
||||
[mod."golang.org/x/time"]
|
||||
version = "v0.5.0"
|
||||
hash = "sha256-W6RgwgdYTO3byIPOFxrP2IpAZdgaGowAaVfYby7AULU="
|
||||
[mod."golang.org/x/tools"]
|
||||
version = "v0.19.0"
|
||||
hash = "sha256-Xf05Ao398gBzxn5C8H6x+XsLjFLIm+UUfpDekQYA0cw="
|
||||
[mod."golang.zx2c4.com/wintun"]
|
||||
version = "v0.0.0-20230126152724-0fa3db229ce2"
|
||||
hash = "sha256-cjMLNjKnnupVROWmeASORVieAL9ieYdzX3cFzG8bCpo="
|
||||
[mod."golang.zx2c4.com/wireguard/windows"]
|
||||
version = "v0.5.3"
|
||||
hash = "sha256-wcJWS/4Fqbc+1RHSntex0zBdlHiZfzrea4QabYkNKvU="
|
||||
[mod."gopkg.in/warnings.v0"]
|
||||
version = "v0.1.2"
|
||||
hash = "sha256-ATVL9yEmgYbkJ1DkltDGRn/auGAjqGOfjQyBYyUo8s8="
|
||||
[mod."gopkg.in/yaml.v2"]
|
||||
version = "v2.4.0"
|
||||
hash = "sha256-uVEGglIedjOIGZzHW4YwN1VoRSTK8o0eGZqzd+TNdd0="
|
||||
[mod."gvisor.dev/gvisor"]
|
||||
version = "v0.0.0-20240306221502-ee1e1f6070e3"
|
||||
hash = "sha256-veCyTYMx5N/K7xU86GgQupjAjjiL3hlvIjz+jhBFM/0="
|
||||
[mod."nhooyr.io/websocket"]
|
||||
version = "v1.8.10"
|
||||
hash = "sha256-EsUWUFIA2uJTap1DfsYuSxlPMH3UHDpxEohJMalDOcI="
|
||||
[mod."tailscale.com"]
|
||||
version = "v1.68.2"
|
||||
hash = "sha256-GdYdZ/FA2m0dw5maZ9QFkiMo89UZtnzjUoWK+fLLV/c="
|
|
@ -98,7 +98,7 @@ func (r Repo) Dir(ref, path string) ([]FileInfo, error) {
|
|||
}
|
||||
}
|
||||
|
||||
fis := make([]FileInfo, 0)
|
||||
fis := make([]FileInfo, 0, len(t.Entries))
|
||||
for _, entry := range t.Entries {
|
||||
fm, err := entry.Mode.ToOSFileMode()
|
||||
if err != nil {
|
||||
|
@ -118,12 +118,30 @@ func (r Repo) Dir(ref, path string) ([]FileInfo, error) {
|
|||
sort.Slice(fis, func(i, j int) bool {
|
||||
fi1 := fis[i]
|
||||
fi2 := fis[j]
|
||||
return (fi1.IsDir && !fi2.IsDir) || fi1.Name() < fi2.Name()
|
||||
if fi1.IsDir != fi2.IsDir {
|
||||
return fi1.IsDir
|
||||
}
|
||||
return fi1.Name() < fi2.Name()
|
||||
})
|
||||
|
||||
return fis, nil
|
||||
}
|
||||
|
||||
// GetCommitFromRef returns the commit object for a given ref
|
||||
func (r Repo) GetCommitFromRef(ref string) (*object.Commit, error) {
|
||||
g, err := r.Git()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hash, err := g.ResolveRevision(plumbing.Revision(ref))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return g.CommitObject(*hash)
|
||||
}
|
||||
|
||||
// FileContent returns the content of a file in the git tree at a given ref/rev
|
||||
func (r Repo) FileContent(ref, file string) (string, error) {
|
||||
t, err := r.Tree(ref)
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
package git_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alecthomas/assert/v2"
|
||||
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
)
|
||||
|
||||
func TestEnsureRepo(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
|
||||
ok, err := git.PathExists(filepath.Join(tmp, "test"))
|
||||
assert.False(t, ok, "repo should not exist yet")
|
||||
assert.NoError(t, err, "PathExists should not error when repo doesn't exist")
|
||||
|
||||
err = git.EnsureRepo(tmp, "test")
|
||||
assert.NoError(t, err, "repo should be created")
|
||||
|
||||
ok, err = git.PathExists(filepath.Join(tmp, "test"))
|
||||
assert.True(t, ok, "repo should exist")
|
||||
assert.NoError(t, err, "EnsureRepo should not error when path exists")
|
||||
|
||||
err = git.EnsureRepo(tmp, "test")
|
||||
assert.NoError(t, err, "repo should already exist")
|
||||
}
|
||||
|
||||
func TestRepo(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
err := git.EnsureRepo(tmp, "test.git")
|
||||
assert.NoError(t, err, "should create repo")
|
||||
|
||||
repo, err := git.NewRepo(tmp, "test")
|
||||
assert.NoError(t, err, "should init new repo")
|
||||
assert.True(t, repo.Meta.Private, "repo should default to private")
|
||||
|
||||
repo.Meta.Private = false
|
||||
err = repo.SaveMeta()
|
||||
assert.NoError(t, err, "should save repo meta")
|
||||
|
||||
repo, err = git.NewRepo(tmp, "test")
|
||||
assert.NoError(t, err, "should not error when getting existing repo")
|
||||
assert.False(t, repo.Meta.Private, "repo should be public after saving meta")
|
||||
}
|
||||
|
||||
func TestPathExists(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
exists, err := git.PathExists(tmp)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, exists)
|
||||
|
||||
doesNotExist := filepath.Join(tmp, "does-not-exist")
|
||||
exists, err = git.PathExists(doesNotExist)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, exists)
|
||||
}
|
||||
|
||||
func TestRepoMetaUpdate(t *testing.T) {
|
||||
original := git.RepoMeta{
|
||||
Description: "Original description",
|
||||
Private: true,
|
||||
Tags: git.TagSet{"tag1": struct{}{}, "tag2": struct{}{}},
|
||||
}
|
||||
|
||||
update := git.RepoMeta{
|
||||
Description: "Updated description",
|
||||
Private: false,
|
||||
Tags: git.TagSet{"tag3": struct{}{}},
|
||||
}
|
||||
|
||||
err := original.Update(update)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "Updated description", original.Description)
|
||||
assert.False(t, original.Private)
|
||||
assert.Equal(t, []string{"tag1", "tag2", "tag3"}, original.Tags.Slice())
|
||||
}
|
||||
|
||||
func TestFileInfoName(t *testing.T) {
|
||||
testCases := []struct {
|
||||
path string
|
||||
expected string
|
||||
}{
|
||||
{path: "file.txt", expected: "file.txt"},
|
||||
{path: "dir/file.txt", expected: "file.txt"},
|
||||
{path: "nested/path/to/file.go", expected: "file.go"},
|
||||
{path: "README.md", expected: "README.md"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path, func(t *testing.T) {
|
||||
fi := git.FileInfo{Path: tc.path}
|
||||
assert.Equal(t, tc.expected, fi.Name())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitSummaryAndDetails(t *testing.T) {
|
||||
testCases := []struct {
|
||||
message string
|
||||
expectedSummary string
|
||||
expectedDetails string
|
||||
}{
|
||||
{
|
||||
message: "Simple commit message",
|
||||
expectedSummary: "Simple commit message",
|
||||
expectedDetails: "",
|
||||
},
|
||||
{
|
||||
message: "Add feature X\n\nThis commit adds feature X\nWith multiple details\nAcross multiple lines",
|
||||
expectedSummary: "Add feature X",
|
||||
expectedDetails: "\nThis commit adds feature X\nWith multiple details\nAcross multiple lines",
|
||||
},
|
||||
{
|
||||
message: "Fix bug\n\nDetailed explanation",
|
||||
expectedSummary: "Fix bug",
|
||||
expectedDetails: "\nDetailed explanation",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.message, func(t *testing.T) {
|
||||
commit := git.Commit{
|
||||
SHA: "abcdef1234567890",
|
||||
Message: tc.message,
|
||||
Signature: "",
|
||||
Author: "Test User",
|
||||
Email: "test@example.com",
|
||||
When: time.Now(),
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.expectedSummary, commit.Summary())
|
||||
assert.Equal(t, tc.expectedDetails, commit.Details())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitShort(t *testing.T) {
|
||||
commit := git.Commit{
|
||||
SHA: "abcdef1234567890abcdef1234567890",
|
||||
}
|
||||
|
||||
assert.Equal(t, "abcdef12", commit.Short())
|
||||
}
|
||||
|
||||
func TestCommitFilePath(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
fromPath string
|
||||
toPath string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "to path preferred",
|
||||
fromPath: "old/path.txt",
|
||||
toPath: "new/path.txt",
|
||||
expected: "new/path.txt",
|
||||
},
|
||||
{
|
||||
name: "fallback to from path",
|
||||
fromPath: "deleted/file.txt",
|
||||
toPath: "",
|
||||
expected: "deleted/file.txt",
|
||||
},
|
||||
{
|
||||
name: "both paths empty",
|
||||
fromPath: "",
|
||||
toPath: "",
|
||||
expected: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cf := git.CommitFile{
|
||||
From: git.CommitFileEntry{Path: tc.fromPath},
|
||||
To: git.CommitFileEntry{Path: tc.toPath},
|
||||
}
|
||||
assert.Equal(t, tc.expected, cf.Path())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoName(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
|
||||
repoName := "testrepo"
|
||||
err := git.EnsureRepo(tmp, repoName+".git")
|
||||
assert.NoError(t, err)
|
||||
|
||||
repo, err := git.NewRepo(tmp, repoName)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, repoName, repo.Name())
|
||||
|
||||
repoName2 := "test-repo-with-hyphens"
|
||||
err = git.EnsureRepo(tmp, repoName2+".git")
|
||||
assert.NoError(t, err)
|
||||
|
||||
repo2, err := git.NewRepo(tmp, repoName2)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, repoName2, repo2.Name())
|
||||
}
|
||||
|
||||
func TestHandlePushOptions(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
err := git.EnsureRepo(tmp, "test.git")
|
||||
assert.NoError(t, err)
|
||||
|
||||
repo, err := git.NewRepo(tmp, "test")
|
||||
assert.NoError(t, err)
|
||||
|
||||
opts := []*packp.Option{
|
||||
{Key: "description", Value: "New description"},
|
||||
}
|
||||
err = git.HandlePushOptions(repo, opts)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "New description", repo.Meta.Description)
|
||||
|
||||
opts = []*packp.Option{
|
||||
{Key: "private", Value: "false"},
|
||||
}
|
||||
err = git.HandlePushOptions(repo, opts)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, repo.Meta.Private)
|
||||
|
||||
repo.Meta.Private = true
|
||||
opts = []*packp.Option{
|
||||
{Key: "private", Value: "invalid"},
|
||||
}
|
||||
err = git.HandlePushOptions(repo, opts)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, repo.Meta.Private)
|
||||
|
||||
opts = []*packp.Option{
|
||||
{Key: "tags", Value: "tag1,tag2"},
|
||||
}
|
||||
err = git.HandlePushOptions(repo, opts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
opts = []*packp.Option{
|
||||
{Key: "description", Value: "Combined update"},
|
||||
{Key: "private", Value: "true"},
|
||||
}
|
||||
err = git.HandlePushOptions(repo, opts)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Combined update", repo.Meta.Description)
|
||||
assert.True(t, repo.Meta.Private)
|
||||
}
|
||||
|
||||
func TestRepoPath(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
err := git.EnsureRepo(tmp, "test.git")
|
||||
assert.NoError(t, err)
|
||||
|
||||
repo, err := git.NewRepo(tmp, "test")
|
||||
assert.NoError(t, err)
|
||||
|
||||
expected := filepath.Join(tmp, "test.git")
|
||||
assert.Equal(t, expected, repo.Path())
|
||||
}
|
||||
|
||||
func TestEnsureJSONFile(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
err := git.EnsureRepo(tmp, "test.git")
|
||||
assert.NoError(t, err)
|
||||
|
||||
repo, err := git.NewRepo(tmp, "test")
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.True(t, repo.Meta.Private, "default repo should be private")
|
||||
assert.Equal(t, "", repo.Meta.Description, "default description should be empty")
|
||||
assert.Equal(t, 0, len(repo.Meta.Tags), "default tags should be empty")
|
||||
}
|
|
@ -18,8 +18,10 @@ type GrepResult struct {
|
|||
|
||||
// Grep performs a naive "code search" via git grep
|
||||
func (r Repo) Grep(search string) ([]GrepResult, error) {
|
||||
// Plain-text search only
|
||||
re, err := regexp.Compile(regexp.QuoteMeta(search))
|
||||
if strings.HasPrefix(search, "=") {
|
||||
search = regexp.QuoteMeta(strings.TrimPrefix(search, "="))
|
||||
}
|
||||
re, err := regexp.Compile(search)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3,16 +3,67 @@ package git
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// RepoMeta is the meta information a Repo can have
|
||||
type RepoMeta struct {
|
||||
Description string `json:"description"`
|
||||
Private bool `json:"private"`
|
||||
Tags []string `json:"tags"`
|
||||
Tags TagSet `json:"tags"`
|
||||
}
|
||||
|
||||
// TagSet is a Set of tags
|
||||
type TagSet map[string]struct{}
|
||||
|
||||
// Add adds a tag to the set
|
||||
func (t TagSet) Add(tag string) {
|
||||
t[tag] = struct{}{}
|
||||
}
|
||||
|
||||
// Remove removes a tag from the set
|
||||
func (t TagSet) Remove(tag string) {
|
||||
delete(t, tag)
|
||||
}
|
||||
|
||||
// Contains checks if a tag is in the set
|
||||
func (t TagSet) Contains(tag string) bool {
|
||||
_, ok := t[tag]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Slice returns the set as a (sorted) slice
|
||||
func (t TagSet) Slice() []string {
|
||||
s := make([]string, 0, len(t))
|
||||
for k := range t {
|
||||
s = append(s, k)
|
||||
}
|
||||
slices.Sort(s)
|
||||
return s
|
||||
}
|
||||
|
||||
// MarshalJSON implements [json.Marshaler]
|
||||
func (t TagSet) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Slice())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements [json.Unmarshaler]
|
||||
func (t *TagSet) UnmarshalJSON(b []byte) error {
|
||||
var s []string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
if *t == nil {
|
||||
*t = make(TagSet)
|
||||
}
|
||||
for _, ss := range s {
|
||||
t.Add(ss)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update updates meta given another RepoMeta
|
||||
|
@ -46,6 +97,16 @@ func (r Repo) SaveMeta() error {
|
|||
return json.NewEncoder(fi).Encode(r.Meta)
|
||||
}
|
||||
|
||||
var defaultMeta = func() []byte {
|
||||
b, err := json.Marshal(RepoMeta{
|
||||
Private: true,
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("could not init default meta: %v", err))
|
||||
}
|
||||
return b
|
||||
}()
|
||||
|
||||
func ensureJSONFile(path string) error {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
|
@ -59,7 +120,7 @@ func ensureJSONFile(path string) error {
|
|||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
if _, err := fi.WriteString(`{"private":true}`); err != nil {
|
||||
if _, err := fi.Write(defaultMeta); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/alecthomas/assert/v2"
|
||||
)
|
||||
|
||||
func TestTagSet(t *testing.T) {
|
||||
set := make(TagSet)
|
||||
assert.Equal(t, 0, len(set))
|
||||
assert.Equal(t, 0, len(set.Slice()))
|
||||
|
||||
set.Add("foo")
|
||||
assert.Equal(t, 1, len(set))
|
||||
assert.Equal(t, 1, len(set.Slice()))
|
||||
assert.True(t, set.Contains("foo"))
|
||||
|
||||
set.Add("bar")
|
||||
assert.Equal(t, 2, len(set))
|
||||
assert.Equal(t, 2, len(set.Slice()))
|
||||
assert.True(t, set.Contains("foo"))
|
||||
assert.True(t, set.Contains("bar"))
|
||||
|
||||
set.Add("bar")
|
||||
assert.Equal(t, 2, len(set))
|
||||
assert.Equal(t, 2, len(set.Slice()))
|
||||
assert.True(t, set.Contains("foo"))
|
||||
assert.True(t, set.Contains("bar"))
|
||||
|
||||
set.Remove("foo")
|
||||
assert.Equal(t, 1, len(set))
|
||||
assert.Equal(t, 1, len(set.Slice()))
|
||||
assert.False(t, set.Contains("foo"))
|
||||
assert.True(t, set.Contains("bar"))
|
||||
|
||||
set.Add("foo")
|
||||
set.Add("baz")
|
||||
j, err := json.Marshal(set)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, `["bar","baz","foo"]`, string(j))
|
||||
|
||||
set = make(TagSet)
|
||||
b := []byte(`["foo","bar","baz"]`)
|
||||
err = json.Unmarshal(b, &set)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, len(set))
|
||||
assert.Equal(t, 3, len(set.Slice()))
|
||||
assert.True(t, set.Contains("foo"))
|
||||
assert.True(t, set.Contains("bar"))
|
||||
assert.True(t, set.Contains("baz"))
|
||||
}
|
|
@ -58,15 +58,11 @@ func HandlePushOptions(repo *Repo, opts []*packp.Option) error {
|
|||
remove = true
|
||||
tagValue = strings.TrimPrefix(tagValue, "-")
|
||||
}
|
||||
for idx, tag := range repo.Meta.Tags {
|
||||
if strings.EqualFold(tag, tagValue) {
|
||||
tagValue = strings.ToLower(tagValue)
|
||||
if remove {
|
||||
repo.Meta.Tags = append(repo.Meta.Tags[:idx], repo.Meta.Tags[idx+1:]...)
|
||||
repo.Meta.Tags.Remove(tagValue)
|
||||
} else {
|
||||
repo.Meta.Tags = append(repo.Meta.Tags, strings.ToLower(tagValue))
|
||||
}
|
||||
break
|
||||
}
|
||||
repo.Meta.Tags.Add(tagValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ func gitService(ctx ReadWriteContexter, command, repoDir string, args ...string)
|
|||
cmd.Env = append(os.Environ(), fmt.Sprintf("UGIT_REPODIR=%s", repoDir), "GIT_PROTOCOL=version=2")
|
||||
cmd.Stdin = ctx
|
||||
cmd.Stdout = ctx
|
||||
fmt.Println(cmd.Env, cmd.String())
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
|
|
|
@ -57,6 +57,9 @@ func NewRepo(dir, name string) (*Repo, error) {
|
|||
if err := json.NewDecoder(fi).Decode(&r.Meta); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Meta.Tags == nil {
|
||||
r.Meta.Tags = make(TagSet)
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
@ -134,6 +137,14 @@ type CommitFileEntry struct {
|
|||
Commit string
|
||||
}
|
||||
|
||||
// Path returns either the To or From path, in order of preference
|
||||
func (c CommitFile) Path() string {
|
||||
if c.To.Path != "" {
|
||||
return c.To.Path
|
||||
}
|
||||
return c.From.Path
|
||||
}
|
||||
|
||||
// Short returns the first eight characters of the SHA
|
||||
func (c Commit) Short() string {
|
||||
return c.SHA[:8]
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ListRepos returns all directory entries in the given directory
|
||||
func ListRepos(dir string) ([]fs.DirEntry, error) {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return []fs.DirEntry{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return entries, nil
|
||||
}
|
||||
|
||||
// DeleteRepo deletes a git repository from the filesystem
|
||||
func DeleteRepo(repoPath string) error {
|
||||
return os.RemoveAll(repoPath)
|
||||
}
|
||||
|
||||
// RenameRepo renames a git repository
|
||||
func RenameRepo(repoDir, oldName, newName string) error {
|
||||
if !filepath.IsAbs(repoDir) {
|
||||
return errors.New("repository directory must be an absolute path")
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(oldName) && !filepath.IsAbs(newName) {
|
||||
oldPath := filepath.Join(repoDir, oldName)
|
||||
if !strings.HasSuffix(oldPath, ".git") {
|
||||
oldPath += ".git"
|
||||
}
|
||||
|
||||
newPath := filepath.Join(repoDir, newName)
|
||||
if !strings.HasSuffix(newPath, ".git") {
|
||||
newPath += ".git"
|
||||
}
|
||||
|
||||
return os.Rename(oldPath, newPath)
|
||||
}
|
||||
|
||||
return errors.New("repository names should not be absolute paths")
|
||||
}
|
||||
|
||||
// RepoPathExists checks if a path exists
|
||||
func RepoPathExists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/components"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type BaseContext struct {
|
||||
Title string
|
||||
Description string
|
||||
}
|
||||
|
||||
func base(bc BaseContext, children ...Node) Node {
|
||||
return HTML5(HTML5Props{
|
||||
Title: bc.Title,
|
||||
Description: bc.Description,
|
||||
Head: []Node{
|
||||
Link(Rel("icon"), Href("/_/favicon.svg")),
|
||||
Link(Rel("stylesheet"), Href("/_/tailwind.css")),
|
||||
ogp("title", bc.Title),
|
||||
ogp("description", bc.Description),
|
||||
Meta(Name("forge"), Content("ugit")),
|
||||
Meta(Name("keywords"), Content("git,forge,ugit")),
|
||||
},
|
||||
Body: []Node{
|
||||
Class("latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10"),
|
||||
H2(Class("text-text text-xl mb-3"),
|
||||
A(Class("text-text text-xl mb-3"), Href("/"), Text("Home")),
|
||||
),
|
||||
Group(children),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func ogp(property, content string) Node {
|
||||
return El("meta", Attr("property", "og:"+property), Attr("content", content))
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package html
|
||||
|
||||
type BaseContext struct {
|
||||
Title string
|
||||
Description string
|
||||
}
|
||||
|
||||
templ base(bc BaseContext) {
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>{ bc.Title }</title>
|
||||
<link rel="icon" href="/_/favicon.svg"/>
|
||||
<link rel="stylesheet" href="/_/tailwind.css"/>
|
||||
<meta property="og:title" content={ bc.Title }/>
|
||||
<meta property="og:description" content={ bc.Description }/>
|
||||
</head>
|
||||
<body class="latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10">
|
||||
<h2 class="text-text text-xl mb-3"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href="/">Home</a></h2>
|
||||
{ children... }
|
||||
</body>
|
||||
</html>
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
type BaseContext struct {
|
||||
Title string
|
||||
Description string
|
||||
}
|
||||
|
||||
func base(bc BaseContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(bc.Title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 14, Col: 20}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</title><link rel=\"icon\" href=\"/_/favicon.svg\"><link rel=\"stylesheet\" href=\"/_/tailwind.css\"><meta property=\"og:title\" content=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(bc.Title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 17, Col: 47}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"><meta property=\"og:description\" content=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(bc.Description)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 18, Col: 59}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"></head><body class=\"latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10\"><h2 class=\"text-text text-xl mb-3\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"/\">Home</a></h2>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</body></html>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -47,7 +47,3 @@
|
|||
.code>.chroma {
|
||||
@apply text-sm p-3 rounded overflow-scroll;
|
||||
}
|
||||
|
||||
.chroma .line {
|
||||
@apply overflow-scroll
|
||||
}
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
"go.jolheiser.com/ugit/internal/html/markup"
|
||||
|
||||
"github.com/alecthomas/chroma/v2/formatters/html"
|
||||
"github.com/alecthomas/chroma/v2/styles"
|
||||
)
|
||||
|
||||
|
@ -25,7 +26,6 @@ var (
|
|||
otherCSS string
|
||||
)
|
||||
|
||||
//go:generate templ generate
|
||||
//go:generate go run generate.go
|
||||
func main() {
|
||||
if err := tailwind(); err != nil {
|
||||
|
@ -33,7 +33,7 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
// Generate tailwind code from templ templates and combine with other misc CSS
|
||||
// Generate tailwind code from templates and combine with other misc CSS
|
||||
func tailwind() error {
|
||||
fmt.Println("generating tailwind...")
|
||||
|
||||
|
@ -47,15 +47,16 @@ func tailwind() error {
|
|||
}
|
||||
|
||||
fmt.Println("generating chroma styles...")
|
||||
formatter := html.New(markup.Options("")...)
|
||||
|
||||
latte := styles.Get("catppuccin-latte")
|
||||
if err := markup.Formatter.WriteCSS(tmp, latte); err != nil {
|
||||
if err := formatter.WriteCSS(tmp, latte); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmp.WriteString("@media (prefers-color-scheme: dark) {")
|
||||
mocha := styles.Get("catppuccin-mocha")
|
||||
if err := markup.Formatter.WriteCSS(tmp, mocha); err != nil {
|
||||
if err := formatter.WriteCSS(tmp, mocha); err != nil {
|
||||
return err
|
||||
}
|
||||
tmp.WriteString("}")
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"go.jolheiser.com/ugit/assets"
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type IndexContext struct {
|
||||
BaseContext
|
||||
Profile IndexProfile
|
||||
Repos []*git.Repo
|
||||
}
|
||||
|
||||
type IndexProfile struct {
|
||||
Username string
|
||||
Email string
|
||||
Links []IndexLink
|
||||
}
|
||||
|
||||
type IndexLink struct {
|
||||
Name string
|
||||
URL string
|
||||
}
|
||||
|
||||
func lastCommitTime(repo *git.Repo, human bool) string {
|
||||
c, err := repo.LastCommit()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if human {
|
||||
return humanize.Time(c.When)
|
||||
}
|
||||
return c.When.Format("01/02/2006 03:04:05 PM")
|
||||
}
|
||||
|
||||
func lastCommit(repo *git.Repo) *git.Commit {
|
||||
c, err := repo.LastCommit()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &c
|
||||
}
|
||||
|
||||
func IndexTemplate(ic IndexContext) Node {
|
||||
return base(ic.BaseContext, []Node{
|
||||
Header(
|
||||
H1(Class("text-text text-xl font-bold"), Text(ic.Title)),
|
||||
H2(Class("text-subtext1 text-lg"), Text(ic.Description)),
|
||||
),
|
||||
Main(Class("mt-5"),
|
||||
Div(Class("grid grid-cols-1 sm:grid-cols-8"),
|
||||
If(ic.Profile.Username != "",
|
||||
Div(Class("text-mauve"), Text("@"+ic.Profile.Username)),
|
||||
),
|
||||
If(ic.Profile.Email != "", Group([]Node{
|
||||
Div(Class("text-mauve col-span-2"),
|
||||
Div(Class("w-5 h-5 stroke-mauve inline-block mr-1 align-middle"), Raw(string(assets.EmailIcon))),
|
||||
A(Class("underline decoration-mauve/50 decoration-dashed hover:decoration-solid"), Href("mailto:"+ic.Profile.Email), Text(ic.Profile.Email)),
|
||||
),
|
||||
}),
|
||||
),
|
||||
),
|
||||
Div(Class("grid grid-cols-1 sm:grid-cols-8"),
|
||||
Map(ic.Profile.Links, func(link IndexLink) Node {
|
||||
return Div(Class("text-mauve"),
|
||||
Div(Class("w-5 h-5 stroke-mauve inline-block mr-1 align-middle"),
|
||||
Raw(string(assets.LinkIcon)),
|
||||
),
|
||||
A(Class("underline decoration-mauve/50 decoration-dashed hover:decoration-solid"), Rel("me"), Href(link.URL), Text(link.Name)),
|
||||
)
|
||||
}),
|
||||
),
|
||||
Div(Class("grid sm:grid-cols-10 gap-2 mt-5"),
|
||||
Map(ic.Repos, func(repo *git.Repo) Node {
|
||||
commit := lastCommit(repo)
|
||||
return Group([]Node{
|
||||
Div(Class("sm:col-span-2 text-blue dark:text-lavender"),
|
||||
A(Class("underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid"), Href("/"+repo.Name()), Text(repo.Name())),
|
||||
),
|
||||
Div(Class("sm:col-span-3 text-subtext0"), Text(repo.Meta.Description)),
|
||||
Div(Class("sm:col-span-3 text-subtext0"),
|
||||
If(commit != nil,
|
||||
Div(Title(commit.Message),
|
||||
A(Class("underline text-blue dark:text-lavender decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/commit/%s", repo.Name(), commit.SHA)), Text(commit.Short())),
|
||||
Text(": "+commit.Summary()),
|
||||
),
|
||||
),
|
||||
),
|
||||
Div(Class("sm:col-span-1 text-subtext0"),
|
||||
Map(repo.Meta.Tags.Slice(), func(tag string) Node {
|
||||
return A(Class("rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block"), Href("?tag="+tag), Text(tag))
|
||||
}),
|
||||
),
|
||||
Div(Class("sm:col-span-1 text-text/80 mb-4 sm:mb-0"), Title(lastCommitTime(repo, false)), Text(lastCommitTime(repo, true))),
|
||||
})
|
||||
}),
|
||||
),
|
||||
),
|
||||
}...)
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
package html
|
||||
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
import "github.com/dustin/go-humanize"
|
||||
import "go.jolheiser.com/ugit/assets"
|
||||
|
||||
type IndexContext struct {
|
||||
BaseContext
|
||||
Profile IndexProfile
|
||||
Repos []*git.Repo
|
||||
}
|
||||
|
||||
type IndexProfile struct {
|
||||
Username string
|
||||
Email string
|
||||
Links []IndexLink
|
||||
}
|
||||
|
||||
type IndexLink struct {
|
||||
Name string
|
||||
URL string
|
||||
}
|
||||
|
||||
func lastCommit(repo *git.Repo, human bool) string {
|
||||
c, err := repo.LastCommit()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if human {
|
||||
return humanize.Time(c.When)
|
||||
}
|
||||
return c.When.Format("01/02/2006 03:04:05 PM")
|
||||
}
|
||||
|
||||
templ Index(ic IndexContext) {
|
||||
@base(ic.BaseContext) {
|
||||
<header>
|
||||
<h1 class="text-text text-xl font-bold">{ ic.Title }</h1>
|
||||
<h2 class="text-subtext1 text-lg">{ ic.Description }</h2>
|
||||
</header>
|
||||
<main class="mt-5">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-8">
|
||||
if ic.Profile.Username != "" {
|
||||
<div class="text-mauve">{ `@` + ic.Profile.Username }</div>
|
||||
}
|
||||
if ic.Profile.Email != "" {
|
||||
<div class="text-mauve col-span-2">
|
||||
<div class="w-5 h-5 stroke-mauve inline-block mr-1 align-middle">
|
||||
@templ.Raw(string(assets.EmailIcon))
|
||||
</div>
|
||||
<a class="underline decoration-mauve/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL("mailto:" + ic.Profile.Email) }>{ ic.Profile.Email }</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-8">
|
||||
for _, link := range ic.Profile.Links {
|
||||
<div class="text-mauve">
|
||||
<div class="w-5 h-5 stroke-mauve inline-block mr-1 align-middle">
|
||||
@templ.Raw(string(assets.LinkIcon))
|
||||
</div>
|
||||
<a class="underline decoration-mauve/50 decoration-dashed hover:decoration-solid" rel="me" href={ templ.SafeURL(link.URL) }>{ link.Name }</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="grid sm:grid-cols-8 gap-2 mt-5">
|
||||
for _, repo := range ic.Repos {
|
||||
<div class="sm:col-span-2 text-blue dark:text-lavender"><a class="underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid" href={ templ.URL("/" + repo.Name()) }>{ repo.Name() }</a></div>
|
||||
<div class="sm:col-span-4 text-subtext0">{ repo.Meta.Description }</div>
|
||||
<div class="sm:col-span-1 text-subtext0">
|
||||
for _, tag := range repo.Meta.Tags {
|
||||
<a href={ templ.SafeURL("?tag=" + tag) } class="rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block">{ tag }</a>
|
||||
}
|
||||
</div>
|
||||
<div class="sm:col-span-1 text-text/80 mb-4 sm:mb-0" title={ lastCommit(repo, false) }>{ lastCommit(repo, true) }</div>
|
||||
}
|
||||
</div>
|
||||
</main>
|
||||
}
|
||||
}
|
|
@ -1,310 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
import "github.com/dustin/go-humanize"
|
||||
import "go.jolheiser.com/ugit/assets"
|
||||
|
||||
type IndexContext struct {
|
||||
BaseContext
|
||||
Profile IndexProfile
|
||||
Repos []*git.Repo
|
||||
}
|
||||
|
||||
type IndexProfile struct {
|
||||
Username string
|
||||
Email string
|
||||
Links []IndexLink
|
||||
}
|
||||
|
||||
type IndexLink struct {
|
||||
Name string
|
||||
URL string
|
||||
}
|
||||
|
||||
func lastCommit(repo *git.Repo, human bool) string {
|
||||
c, err := repo.LastCommit()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if human {
|
||||
return humanize.Time(c.When)
|
||||
}
|
||||
return c.When.Format("01/02/2006 03:04:05 PM")
|
||||
}
|
||||
|
||||
func Index(ic IndexContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<header><h1 class=\"text-text text-xl font-bold\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Title)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 38, Col: 53}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1><h2 class=\"text-subtext1 text-lg\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Description)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 39, Col: 53}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h2></header><main class=\"mt-5\"><div class=\"grid grid-cols-1 sm:grid-cols-8\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if ic.Profile.Username != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-mauve\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(`@` + ic.Profile.Username)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 44, Col: 56}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if ic.Profile.Email != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-mauve col-span-2\"><div class=\"w-5 h-5 stroke-mauve inline-block mr-1 align-middle\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(string(assets.EmailIcon)).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 templ.SafeURL = templ.SafeURL("mailto:" + ic.Profile.Email)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var6)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Profile.Email)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 51, Col: 159}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"grid grid-cols-1 sm:grid-cols-8\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, link := range ic.Profile.Links {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-mauve\"><div class=\"w-5 h-5 stroke-mauve inline-block mr-1 align-middle\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(string(assets.LinkIcon)).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" rel=\"me\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 templ.SafeURL = templ.SafeURL(link.URL)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var8)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(link.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 61, Col: 141}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"grid sm:grid-cols-8 gap-2 mt-5\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, repo := range ic.Repos {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"sm:col-span-2 text-blue dark:text-lavender\"><a class=\"underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 templ.SafeURL = templ.URL("/" + repo.Name())
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Name())
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 67, Col: 221}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"sm:col-span-4 text-subtext0\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 string
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Meta.Description)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 68, Col: 69}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-1 text-subtext0\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, tag := range repo.Meta.Tags {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var13 templ.SafeURL = templ.SafeURL("?tag=" + tag)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var13)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var14 string
|
||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(tag)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 71, Col: 141}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-1 text-text/80 mb-4 sm:mb-0\" title=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var15 string
|
||||
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommit(repo, false))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 74, Col: 89}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var16 string
|
||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommit(repo, true))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 74, Col: 116}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></main>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = base(ic.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -2,6 +2,7 @@ package markup
|
|||
|
||||
import (
|
||||
"io"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/alecthomas/chroma/v2"
|
||||
"github.com/alecthomas/chroma/v2/formatters/html"
|
||||
|
@ -9,27 +10,27 @@ import (
|
|||
"github.com/alecthomas/chroma/v2/styles"
|
||||
)
|
||||
|
||||
var (
|
||||
// Formatter is the default formatter
|
||||
Formatter = html.New(
|
||||
var customReg = map[string]string{
|
||||
".hujson": "json",
|
||||
}
|
||||
|
||||
// Options are the default set of formatting options
|
||||
func Options(linePrefix string) []html.Option {
|
||||
return []html.Option{
|
||||
html.WithLineNumbers(true),
|
||||
html.WithLinkableLineNumbers(true, "L"),
|
||||
html.WithLinkableLineNumbers(true, linePrefix),
|
||||
html.WithClasses(true),
|
||||
html.LineNumbersInTable(true),
|
||||
)
|
||||
basicFormatter = html.New(
|
||||
html.WithClasses(true),
|
||||
)
|
||||
// Code is the entrypoint for formatting
|
||||
Code = code{}
|
||||
)
|
||||
|
||||
type code struct{}
|
||||
}
|
||||
}
|
||||
|
||||
func setup(source []byte, fileName string) (chroma.Iterator, *chroma.Style, error) {
|
||||
lexer := lexers.Match(fileName)
|
||||
if lexer == nil {
|
||||
lexer = lexers.Fallback
|
||||
if name, ok := customReg[filepath.Ext(fileName)]; ok {
|
||||
lexer = lexers.Get(name)
|
||||
}
|
||||
}
|
||||
lexer = chroma.Coalesce(lexer)
|
||||
|
||||
|
@ -46,22 +47,13 @@ func setup(source []byte, fileName string) (chroma.Iterator, *chroma.Style, erro
|
|||
return iter, style, nil
|
||||
}
|
||||
|
||||
// Basic formats code without any extras
|
||||
func (c code) Basic(source []byte, fileName string, writer io.Writer) error {
|
||||
iter, style, err := setup(source, fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return basicFormatter.Format(writer, style, iter)
|
||||
}
|
||||
|
||||
// Convert formats code with line numbers, links, etc.
|
||||
func (c code) Convert(source []byte, fileName string, writer io.Writer) error {
|
||||
func Convert(source []byte, fileName, linePrefix string, writer io.Writer) error {
|
||||
iter, style, err := setup(source, fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return Formatter.Format(writer, style, iter)
|
||||
return html.New(Options(linePrefix)...).Format(writer, style, iter)
|
||||
}
|
||||
|
||||
// Snippet formats code with line numbers starting at a specific line
|
||||
|
|
|
@ -112,6 +112,7 @@ func (a astTransformer) Transform(node *ast.Document, _ text.Reader, pc parser.C
|
|||
case *ast.Image:
|
||||
link := v.Destination
|
||||
if len(link) > 0 && !bytes.HasPrefix(link, []byte("http")) {
|
||||
v.SetAttributeString("style", []byte("max-width:100%;"))
|
||||
v.Destination = []byte(resolveLink(ctx.repo, ctx.ref, ctx.path, string(link)) + "?raw&pretty")
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type ReadmeComponentContext struct {
|
||||
Markdown string
|
||||
}
|
||||
|
||||
func readmeComponent(rcc ReadmeComponentContext) Node {
|
||||
if rcc.Markdown == "" {
|
||||
return nil
|
||||
}
|
||||
return Div(Class("bg-base dark:bg-base/50 p-5 mt-5 rounded markdown"), Raw(rcc.Markdown))
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package html
|
||||
|
||||
type ReadmeComponentContext struct {
|
||||
Markdown string
|
||||
}
|
||||
|
||||
templ readmeComponent(rcc ReadmeComponentContext) {
|
||||
if rcc.Markdown != "" {
|
||||
<div class="bg-base dark:bg-base/50 p-5 mt-5 rounded markdown">@templ.Raw(rcc.Markdown)</div>
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
type ReadmeComponentContext struct {
|
||||
Markdown string
|
||||
}
|
||||
|
||||
func readmeComponent(rcc ReadmeComponentContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
if rcc.Markdown != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"bg-base dark:bg-base/50 p-5 mt-5 rounded markdown\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(rcc.Markdown).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type RepoHeaderComponentContext struct {
|
||||
Name string
|
||||
Ref string
|
||||
Description string
|
||||
CloneURL string
|
||||
Tags []string
|
||||
}
|
||||
|
||||
func repoHeaderComponent(rhcc RepoHeaderComponentContext) Node {
|
||||
return Group([]Node{
|
||||
Div(Class("mb-1 text-text"),
|
||||
A(Class("text-lg underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href("/"+rhcc.Name), Text(rhcc.Name)),
|
||||
If(rhcc.Ref != "", Group([]Node{
|
||||
Text(" "),
|
||||
A(Class("text-text/80 text-sm underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/", rhcc.Name, rhcc.Ref)), Text("@"+rhcc.Ref)),
|
||||
})),
|
||||
Text(" - "),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/refs", rhcc.Name)), Text("refs")),
|
||||
Text(" - "),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref)), Text("log")),
|
||||
Text(" - "),
|
||||
Form(Class("inline-block"), Action(fmt.Sprintf("/%s/search", rhcc.Name)), Method("get"),
|
||||
Input(Class("rounded p-1 bg-mantle focus:border-lavender focus:outline-none focus:ring-0"), ID("search"), Type("text"), Name("q"), Placeholder("search")),
|
||||
),
|
||||
Text(" - "),
|
||||
Pre(Class("text-text inline select-all bg-base dark:bg-base/50 p-1 rounded"), Textf("%s/%s.git", rhcc.CloneURL, rhcc.Name)),
|
||||
),
|
||||
Div(Class("text-subtext0 mb-1"),
|
||||
Map(rhcc.Tags, func(tag string) Node {
|
||||
return Span(Class("rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block"), Text(tag))
|
||||
}),
|
||||
),
|
||||
Div(Class("text-text/80 mb-1"), Text(rhcc.Description)),
|
||||
})
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package html
|
||||
|
||||
import "fmt"
|
||||
|
||||
type RepoHeaderComponentContext struct {
|
||||
Name string
|
||||
Ref string
|
||||
Description string
|
||||
CloneURL string
|
||||
Tags []string
|
||||
}
|
||||
|
||||
templ repoHeaderComponent(rhcc RepoHeaderComponentContext) {
|
||||
<div class="mb-1 text-text">
|
||||
<a class="text-lg underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL("/" + rhcc.Name) }>{ rhcc.Name }</a>
|
||||
if rhcc.Ref != "" {
|
||||
{ " " }
|
||||
<a class="text-text/80 text-sm underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rhcc.Name, rhcc.Ref)) }>{ "@" + rhcc.Ref }</a>
|
||||
}
|
||||
{ " - " }
|
||||
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/refs", rhcc.Name)) }>refs</a>
|
||||
{ " - " }
|
||||
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref)) }>log</a>
|
||||
{ " - " }
|
||||
<form class="inline-block" action={ templ.SafeURL(fmt.Sprintf("/%s/search", rhcc.Name)) } method="get"><input class="rounded p-1 bg-mantle focus:border-lavender focus:outline-none focus:ring-0" id="search" type="text" name="q" placeholder="search"/></form>
|
||||
{ " - " }
|
||||
<pre class="text-text inline select-all bg-base dark:bg-base/50 p-1 rounded">{ fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name) }</pre>
|
||||
</div>
|
||||
<div class="text-subtext0 mb-1">
|
||||
for _, tag := range rhcc.Tags {
|
||||
<span class="rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block">{ tag }</span>
|
||||
}
|
||||
</div>
|
||||
<div class="text-text/80 mb-1">{ rhcc.Description }</div>
|
||||
}
|
|
@ -2,8 +2,11 @@ package html
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type RepoBreadcrumbComponentContext struct {
|
||||
|
@ -36,17 +39,19 @@ func (r RepoBreadcrumbComponentContext) crumbs() []breadcrumb {
|
|||
return breadcrumbs
|
||||
}
|
||||
|
||||
templ repoBreadcrumbComponent(rbcc RepoBreadcrumbComponentContext) {
|
||||
if rbcc.Path != "" {
|
||||
<div class="inline-block text-text">
|
||||
for _, crumb := range rbcc.crumbs() {
|
||||
func repoBreadcrumbComponent(rbcc RepoBreadcrumbComponentContext) Node {
|
||||
if rbcc.Path == "" {
|
||||
return nil
|
||||
}
|
||||
return Div(Class("inline-block text-text"),
|
||||
Map(rbcc.crumbs(), func(crumb breadcrumb) Node {
|
||||
if crumb.end {
|
||||
<span>{ crumb.label }</span>
|
||||
} else {
|
||||
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(crumb.href) }>{ crumb.label }</a>
|
||||
{ " / " }
|
||||
}
|
||||
}
|
||||
</div>
|
||||
return Span(Text(crumb.label))
|
||||
}
|
||||
return Group([]Node{
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(crumb.href), Text(crumb.label)),
|
||||
Text(" / "),
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RepoBreadcrumbComponentContext struct {
|
||||
Repo string
|
||||
Ref string
|
||||
Path string
|
||||
}
|
||||
|
||||
type breadcrumb struct {
|
||||
label string
|
||||
href string
|
||||
end bool
|
||||
}
|
||||
|
||||
func (r RepoBreadcrumbComponentContext) crumbs() []breadcrumb {
|
||||
parts := strings.Split(r.Path, "/")
|
||||
breadcrumbs := []breadcrumb{
|
||||
{
|
||||
label: r.Repo,
|
||||
href: fmt.Sprintf("/%s/tree/%s/", r.Repo, r.Ref),
|
||||
},
|
||||
}
|
||||
for idx, part := range parts {
|
||||
breadcrumbs = append(breadcrumbs, breadcrumb{
|
||||
label: part,
|
||||
href: path.Join(breadcrumbs[idx].href, part),
|
||||
})
|
||||
}
|
||||
breadcrumbs[len(breadcrumbs)-1].end = true
|
||||
return breadcrumbs
|
||||
}
|
||||
|
||||
func repoBreadcrumbComponent(rbcc RepoBreadcrumbComponentContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
if rbcc.Path != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"inline-block text-text\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, crumb := range rbcc.crumbs() {
|
||||
if crumb.end {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 string
|
||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(crumb.label)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 44, Col: 24}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 templ.SafeURL = templ.SafeURL(crumb.href)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(crumb.label)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 46, Col: 134}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(" / ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 47, Col: 12}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type RepoCommitContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Commit git.Commit
|
||||
}
|
||||
|
||||
func RepoCommitTemplate(rcc RepoCommitContext) Node {
|
||||
return base(rcc.BaseContext, []Node{
|
||||
repoHeaderComponent(rcc.RepoHeaderComponentContext),
|
||||
Div(Class("text-text mt-5"),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)), Text("tree")),
|
||||
Text(" "),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/log/%s", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)), Text("log")),
|
||||
Text(" "),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/commit/%s.patch", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)), Text("patch")),
|
||||
),
|
||||
Div(Class("text-text whitespace-pre mt-5 p-3 bg-base rounded"), Text(rcc.Commit.Message)),
|
||||
If(rcc.Commit.Signature != "",
|
||||
Details(Class("text-text whitespace-pre"),
|
||||
Summary(Class("cursor-pointer"), Text("Signature")),
|
||||
Div(Class("p-3 bg-base rounded"),
|
||||
Code(Text(rcc.Commit.Signature)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Div(Class("text-text mt-3"),
|
||||
Div(
|
||||
Text(rcc.Commit.Author),
|
||||
Text(" "),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("mailto:%s", rcc.Commit.Email)), Text(fmt.Sprintf("<%s>", rcc.Commit.Email))),
|
||||
),
|
||||
Div(Title(rcc.Commit.When.Format("01/02/2006 03:04:05 PM")), Text(humanize.Time(rcc.Commit.When))),
|
||||
),
|
||||
Details(Class("text-text mt-5"),
|
||||
Summary(Class("cursor-pointer"), Textf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions)),
|
||||
Div(Class("p-3 bg-base rounded"),
|
||||
Map(rcc.Commit.Files, func(file git.CommitFile) Node {
|
||||
return A(Class("block underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href("#"+file.Path()), Text(file.Path()))
|
||||
}),
|
||||
),
|
||||
),
|
||||
Map(rcc.Commit.Files, func(file git.CommitFile) Node {
|
||||
return Group([]Node{
|
||||
Div(Class("text-text mt-5"), ID(file.Path()),
|
||||
Span(Class("text-text/80"), Title(file.Action), Text(string(file.Action[0]))),
|
||||
Text(" "),
|
||||
If(file.From.Path != "",
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.From.Commit, file.From.Path)), Text(file.From.Path)),
|
||||
),
|
||||
If(file.From.Path != "" && file.To.Path != "", Text(" → ")),
|
||||
If(file.To.Path != "",
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path)), Text(file.To.Path)),
|
||||
),
|
||||
),
|
||||
Div(Class("code"),
|
||||
Raw(file.Patch),
|
||||
),
|
||||
})
|
||||
}),
|
||||
}...)
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package html
|
||||
|
||||
import "fmt"
|
||||
import "github.com/dustin/go-humanize"
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
|
||||
type RepoCommitContext struct{
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Commit git.Commit
|
||||
}
|
||||
|
||||
templ RepoCommit(rcc RepoCommitContext) {
|
||||
@base(rcc.BaseContext) {
|
||||
@repoHeaderComponent(rcc.RepoHeaderComponentContext)
|
||||
<div class="text-text mt-5"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)) }>tree</a>{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/log/%s", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)) }>log</a>{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/commit/%s.patch", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)) }>patch</a></div>
|
||||
<div class="text-text whitespace-pre mt-5 p-3 bg-base rounded">{ rcc.Commit.Message }</div>
|
||||
if rcc.Commit.Signature != "" {
|
||||
<details class="text-text whitespace-pre">
|
||||
<summary class="cursor-pointer">Signature</summary>
|
||||
<div class="p-3 bg-base rounded"><code>{ rcc.Commit.Signature }</code></div>
|
||||
</details>
|
||||
}
|
||||
<div class="text-text mt-3">
|
||||
<div>{ rcc.Commit.Author }{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("mailto:%s", rcc.Commit.Email)) }>{ fmt.Sprintf("<%s>", rcc.Commit.Email) }</a></div>
|
||||
<div title={ rcc.Commit.When.Format("01/02/2006 03:04:05 PM") }>{ humanize.Time(rcc.Commit.When) }</div>
|
||||
</div>
|
||||
<div class="text-text mt-5">{ fmt.Sprintf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions) }</div>
|
||||
for _, file := range rcc.Commit.Files {
|
||||
<div class="text-text mt-5">
|
||||
<span class="text-text/80" title={ file.Action }>{ string(file.Action[0]) }</span>
|
||||
{ " " }
|
||||
if file.From.Path != "" {
|
||||
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.From.Commit, file.From.Path)) }>{ file.From.Path }</a>
|
||||
}
|
||||
if file.From.Path != "" && file.To.Path != "" {
|
||||
{ " -> " }
|
||||
}
|
||||
if file.To.Path != "" {
|
||||
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path)) }>{ file.To.Path }</a>
|
||||
}
|
||||
</div>
|
||||
<div class="whitespace-pre code">@templ.Raw(file.Patch)</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,364 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import "fmt"
|
||||
import "github.com/dustin/go-humanize"
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
|
||||
type RepoCommitContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Commit git.Commit
|
||||
}
|
||||
|
||||
func RepoCommit(rcc RepoCommitContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
templ_7745c5c3_Err = repoHeaderComponent(rcc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"text-text mt-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">tree</a>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 229}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var5)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 427}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/commit/%s.patch", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var7)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">patch</a></div><div class=\"text-text whitespace-pre mt-5 p-3 bg-base rounded\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Message)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 17, Col: 85}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if rcc.Commit.Signature != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"text-text whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><div class=\"p-3 bg-base rounded\"><code>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Signature)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 21, Col: 65}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code></div></details>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"text-text mt-3\"><div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 string
|
||||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Author)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 27}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 34}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 templ.SafeURL = templ.SafeURL(fmt.Sprintf("mailto:%s", rcc.Commit.Email))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var12)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var13 string
|
||||
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("<%s>", rcc.Commit.Email))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 223}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div title=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var14 string
|
||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.When.Format("01/02/2006 03:04:05 PM"))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 26, Col: 64}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var15 string
|
||||
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(humanize.Time(rcc.Commit.When))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 26, Col: 99}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><div class=\"text-text mt-5\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var16 string
|
||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 28, Col: 179}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, file := range rcc.Commit.Files {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-text mt-5\"><span class=\"text-text/80\" title=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var17 string
|
||||
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(file.Action)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 31, Col: 50}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var18 string
|
||||
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(string(file.Action[0]))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 31, Col: 77}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var19 string
|
||||
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 9}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if file.From.Path != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var20 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.From.Commit, file.From.Path))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var20)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var21 string
|
||||
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(file.From.Path)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 34, Col: 227}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if file.From.Path != "" && file.To.Path != "" {
|
||||
var templ_7745c5c3_Var22 string
|
||||
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(" -> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 37, Col: 13}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if file.To.Path != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var23 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var23)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var24 string
|
||||
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(file.To.Path)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 40, Col: 221}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"whitespace-pre code\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(file.Patch).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = base(rcc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type RepoFileContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
RepoBreadcrumbComponentContext
|
||||
Code string
|
||||
Commit string
|
||||
Path string
|
||||
}
|
||||
|
||||
//go:embed repo_file.js
|
||||
var repoFileJS string
|
||||
|
||||
func RepoFileTemplate(rfc RepoFileContext) Node {
|
||||
permalink := fmt.Sprintf("/%s/tree/%s/%s", rfc.RepoBreadcrumbComponentContext.Repo, rfc.Commit, rfc.Path)
|
||||
return base(rfc.BaseContext, []Node{
|
||||
repoHeaderComponent(rfc.RepoHeaderComponentContext),
|
||||
Div(Class("mt-2 text-text"),
|
||||
repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext),
|
||||
Text(" - "),
|
||||
A(Class("text-text underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href("?raw"), Text("raw")),
|
||||
Text(" - "),
|
||||
A(Class("text-text underline decoration-text/50 decoration-dashed hover:decoration-solid"), ID("permalink"), Data("permalink", permalink), Href(permalink), Text("permalink")),
|
||||
Div(Class("code relative"),
|
||||
Raw(rfc.Code),
|
||||
Button(ID("copy"), Class("absolute top-0 right-0 rounded bg-base hover:bg-surface0")),
|
||||
),
|
||||
),
|
||||
Script(Raw(repoFileJS)),
|
||||
}...)
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
const lineRe = /#L(\d+)(?:-L(\d+))?/g
|
||||
const $lineLines = document.querySelectorAll(".chroma .lntable .lnt");
|
||||
const $codeLines = document.querySelectorAll(".chroma .lntable .line");
|
||||
const $copyButton = document.getElementById('copy');
|
||||
const $permalink = document.getElementById('permalink');
|
||||
const $copyIcon = "📋";
|
||||
const $copiedIcon = "✅";
|
||||
let $code = ""
|
||||
for (let codeLine of $codeLines) $code += codeLine.innerText;
|
||||
let start = 0;
|
||||
let end = 0;
|
||||
const results = [...location.hash.matchAll(lineRe)];
|
||||
if (0 in results) {
|
||||
start = results[0][1] !== undefined ? parseInt(results[0][1]) : 0;
|
||||
end = results[0][2] !== undefined ? parseInt(results[0][2]) : 0;
|
||||
}
|
||||
if (start !== 0) {
|
||||
deactivateLines();
|
||||
activateLines(start, end);
|
||||
let anchor = `#${start}`;
|
||||
if (end !== 0) anchor += `-${end}`;
|
||||
if (anchor !== "") $permalink.href = $permalink.dataset.permalink + anchor;
|
||||
$lineLines[start - 1].scrollIntoView(true);
|
||||
}
|
||||
for (let line of $lineLines) {
|
||||
line.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
deactivateLines();
|
||||
const n = parseInt(line.id.substring(1));
|
||||
let anchor = "";
|
||||
if (event.shiftKey) {
|
||||
end = n;
|
||||
anchor = `#L${start}-L${end}`;
|
||||
} else if (start === n) {
|
||||
start = 0;
|
||||
end = 0;
|
||||
} else {
|
||||
start = n;
|
||||
end = 0;
|
||||
anchor = `#L${start}`;
|
||||
}
|
||||
history.replaceState(null, null, window.location.pathname + anchor);
|
||||
$permalink.href = $permalink.dataset.permalink + anchor;
|
||||
if (start !== 0) activateLines(start, end);
|
||||
});
|
||||
}
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
$copyButton.innerText = $copyIcon;
|
||||
$copyButton.classList.remove("hidden");
|
||||
}
|
||||
$copyButton.addEventListener("click", () => {
|
||||
navigator.clipboard.writeText($code);
|
||||
$copyButton.innerText = $copiedIcon;
|
||||
setTimeout(() => {
|
||||
$copyButton.innerText = $copyIcon;
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
function activateLines(start, end) {
|
||||
if (end < start) end = start;
|
||||
for (let idx = start - 1; idx < end; idx++) {
|
||||
$codeLines[idx].classList.add("active");
|
||||
}
|
||||
}
|
||||
|
||||
function deactivateLines() {
|
||||
for (let code of $codeLines) {
|
||||
code.classList.remove("active");
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package html
|
||||
|
||||
type RepoFileContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
RepoBreadcrumbComponentContext
|
||||
Code string
|
||||
}
|
||||
|
||||
templ RepoFile(rfc RepoFileContext) {
|
||||
@base(rfc.BaseContext) {
|
||||
@repoHeaderComponent(rfc.RepoHeaderComponentContext)
|
||||
<div class="mt-2 text-text">
|
||||
@repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext)
|
||||
{ " - " }
|
||||
<a class="text-text underline decoration-text/50 decoration-dashed hover:decoration-solid" href="?raw">raw</a>
|
||||
<div class="code">
|
||||
@templ.Raw(rfc.Code)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<script>
|
||||
const lineRe = /#L(\d+)(?:-L(\d+))?/g
|
||||
const $lineLines = document.querySelectorAll(".chroma .lntable .lnt");
|
||||
const $codeLines = document.querySelectorAll(".chroma .lntable .line");
|
||||
let start = 0;
|
||||
let end = 0;
|
||||
|
||||
const results = [...location.hash.matchAll(lineRe)];
|
||||
if (0 in results) {
|
||||
start = results[0][1] !== undefined ? parseInt(results[0][1]) : 0;
|
||||
end = results[0][2] !== undefined ? parseInt(results[0][2]) : 0;
|
||||
}
|
||||
if (start != 0) {
|
||||
deactivateLines();
|
||||
activateLines(start, end);
|
||||
}
|
||||
|
||||
for (let line of $lineLines) {
|
||||
line.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
deactivateLines();
|
||||
const n = parseInt(line.id.substring(1));
|
||||
let anchor = "";
|
||||
if (event.shiftKey) {
|
||||
end = n;
|
||||
anchor = `#L${start}-L${end}`;
|
||||
} else {
|
||||
start = n;
|
||||
end = 0;
|
||||
anchor = `#L${start}`;
|
||||
}
|
||||
history.replaceState(null, null, anchor);
|
||||
activateLines(start, end);
|
||||
});
|
||||
}
|
||||
|
||||
function activateLines(start, end) {
|
||||
if (end < start) end = start;
|
||||
for (let idx = start - 1; idx < end; idx++) {
|
||||
$codeLines[idx].classList.add("active");
|
||||
}
|
||||
}
|
||||
|
||||
function deactivateLines() {
|
||||
for (let code of $codeLines) {
|
||||
code.classList.remove("active");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
type RepoFileContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
RepoBreadcrumbComponentContext
|
||||
Code string
|
||||
}
|
||||
|
||||
func RepoFile(rfc RepoFileContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
templ_7745c5c3_Err = repoHeaderComponent(rfc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"mt-2 text-text\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 15, Col: 10}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"text-text underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"?raw\">raw</a><div class=\"code\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(rfc.Code).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = base(rfc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script>\n\t\tconst lineRe = /#L(\\d+)(?:-L(\\d+))?/g\n\t\tconst $lineLines = document.querySelectorAll(\".chroma .lntable .lnt\");\n\t\tconst $codeLines = document.querySelectorAll(\".chroma .lntable .line\");\n\t\tlet start = 0;\n\t\tlet end = 0;\n\n\t\tconst results = [...location.hash.matchAll(lineRe)];\t\t\n\t\tif (0 in results) {\n\t\t\tstart = results[0][1] !== undefined ? parseInt(results[0][1]) : 0;\n\t\t\tend = results[0][2] !== undefined ? parseInt(results[0][2]) : 0;\n\t\t}\n\t\tif (start != 0) {\n\t\t\tdeactivateLines();\n\t\t\tactivateLines(start, end);\n\t\t}\n\n\t\tfor (let line of $lineLines) {\n\t\t\tline.addEventListener(\"click\", (event) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tdeactivateLines();\n\t\t\t\tconst n = parseInt(line.id.substring(1));\n\t\t\t\tlet anchor = \"\";\n\t\t\t\tif (event.shiftKey) {\n\t\t\t\t\tend = n;\n\t\t\t\t\tanchor = `#L${start}-L${end}`;\n\t\t\t\t} else {\n\t\t\t\t\tstart = n;\n\t\t\t\t\tend = 0;\n\t\t\t\t\tanchor = `#L${start}`;\n\t\t\t\t}\n\t\t\t\thistory.replaceState(null, null, anchor);\n\t\t\t\tactivateLines(start, end);\n\t\t\t});\n\t\t}\n\n\t\tfunction activateLines(start, end) {\n\t\t\tif (end < start) end = start;\n\t\t\tfor (let idx = start - 1; idx < end; idx++) {\n\t\t\t\t$codeLines[idx].classList.add(\"active\");\n\t\t\t}\n\t\t}\n\n\t\tfunction deactivateLines() {\n\t\t\tfor (let code of $codeLines) {\n\t\t\t\tcode.classList.remove(\"active\");\n\t\t\t}\n\t\t}\n\n\t\t\n\t\t\n\t</script>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type RepoLogContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Commits []git.Commit
|
||||
}
|
||||
|
||||
func RepoLogTemplate(rlc RepoLogContext) Node {
|
||||
return base(rlc.BaseContext, []Node{
|
||||
repoHeaderComponent(rlc.RepoHeaderComponentContext),
|
||||
Div(Class("grid sm:grid-cols-8 gap-1 text-text mt-5"),
|
||||
Map(rlc.Commits, func(commit git.Commit) Node {
|
||||
return Group([]Node{
|
||||
Div(Class("sm:col-span-5"),
|
||||
Div(
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/commit/%s", rlc.RepoHeaderComponentContext.Name, commit.SHA)), Text(commit.Short())),
|
||||
),
|
||||
Div(Class("whitespace-pre"),
|
||||
If(commit.Details() != "",
|
||||
Details(
|
||||
Summary(Class("cursor-pointer"), Text(commit.Summary())),
|
||||
Div(Class("p-3 bg-base rounded"), Text(commit.Details())),
|
||||
),
|
||||
),
|
||||
If(commit.Details() == "",
|
||||
Text(commit.Message),
|
||||
),
|
||||
),
|
||||
),
|
||||
Div(Class("sm:col-span-3 mb-4"),
|
||||
Div(
|
||||
Text(commit.Author),
|
||||
Text(" "),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("mailto:%s", commit.Email)), Textf("<%s>", commit.Email)),
|
||||
),
|
||||
Div(Title(commit.When.Format("01/02/2006 03:04:05 PM")), Text(humanize.Time(commit.When))),
|
||||
),
|
||||
})
|
||||
}),
|
||||
),
|
||||
}...)
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package html
|
||||
|
||||
import "fmt"
|
||||
import "github.com/dustin/go-humanize"
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
|
||||
type RepoLogContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Commits []git.Commit
|
||||
}
|
||||
|
||||
templ RepoLog(rlc RepoLogContext) {
|
||||
@base(rlc.BaseContext) {
|
||||
@repoHeaderComponent(rlc.RepoHeaderComponentContext)
|
||||
<div class="grid sm:grid-cols-8 gap-1 text-text mt-5">
|
||||
for _, commit := range rlc.Commits {
|
||||
<div class="sm:col-span-5">
|
||||
<div><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/commit/%s", rlc.RepoHeaderComponentContext.Name, commit.SHA)) }>{ commit.Short() }</a></div>
|
||||
<div class="whitespace-pre">
|
||||
if commit.Details() != "" {
|
||||
<details>
|
||||
<summary class="cursor-pointer">{ commit.Summary() }</summary>
|
||||
<div class="p-3 bg-base rounded">{ commit.Details() }</div>
|
||||
</details>
|
||||
} else {
|
||||
{ commit.Message }
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:col-span-3 mb-4">
|
||||
<div>{ commit.Author }{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("mailto:%s", commit.Email)) }>{ fmt.Sprintf("<%s>", commit.Email) }</a></div>
|
||||
<div title={ commit.When.Format("01/02/2006 03:04:05 PM") }>{ humanize.Time(commit.When) }</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
@ -1,212 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import "fmt"
|
||||
import "github.com/dustin/go-humanize"
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
|
||||
type RepoLogContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Commits []git.Commit
|
||||
}
|
||||
|
||||
func RepoLog(rlc RepoLogContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
templ_7745c5c3_Err = repoHeaderComponent(rlc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"grid sm:grid-cols-8 gap-1 text-text mt-5\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, commit := range rlc.Commits {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"sm:col-span-5\"><div><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/commit/%s", rlc.RepoHeaderComponentContext.Name, commit.SHA))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var3)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Short())
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 19, Col: 209}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"whitespace-pre\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if commit.Details() != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details><summary class=\"cursor-pointer\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Summary())
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 23, Col: 58}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</summary><div class=\"p-3 bg-base rounded\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Details())
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 24, Col: 59}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></details>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
} else {
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Message)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 27, Col: 23}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><div class=\"sm:col-span-3 mb-4\"><div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Author)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 25}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 32}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 templ.SafeURL = templ.SafeURL(fmt.Sprintf("mailto:%s", commit.Email))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("<%s>", commit.Email))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 213}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div title=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 string
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(commit.When.Format("01/02/2006 03:04:05 PM"))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 33, Col: 62}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var13 string
|
||||
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(humanize.Time(commit.When))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 33, Col: 93}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = base(rlc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type RepoRefsContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Branches []string
|
||||
Tags []git.Tag
|
||||
}
|
||||
|
||||
func RepoRefsTemplate(rrc RepoRefsContext) Node {
|
||||
return base(rrc.BaseContext, []Node{
|
||||
repoHeaderComponent(rrc.RepoHeaderComponentContext),
|
||||
If(len(rrc.Branches) > 0, Group([]Node{
|
||||
H3(Class("text-text text-lg mt-5"), Text("Branches")),
|
||||
Div(Class("text-text grid grid-cols-4 sm:grid-cols-8"),
|
||||
Map(rrc.Branches, func(branch string) Node {
|
||||
return Group([]Node{
|
||||
Div(Class("col-span-2 sm:col-span-1 font-bold"), Text(branch)),
|
||||
Div(Class("col-span-2 sm:col-span-7"),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, branch)), Text("tree")),
|
||||
Text(" "),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, branch)), Text("log")),
|
||||
),
|
||||
})
|
||||
}),
|
||||
),
|
||||
})),
|
||||
If(len(rrc.Tags) > 0, Group([]Node{
|
||||
H3(Class("text-text text-lg mt-5"), Text("Tags")),
|
||||
Div(Class("text-text grid grid-cols-8"),
|
||||
Map(rrc.Tags, func(tag git.Tag) Node {
|
||||
return Group([]Node{
|
||||
Div(Class("col-span-1 font-bold"), Text(tag.Name)),
|
||||
Div(Class("col-span-7"),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, tag.Name)), Text("tree")),
|
||||
Text(" "),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, tag.Name)), Text("log")),
|
||||
),
|
||||
If(tag.Signature != "",
|
||||
Details(Class("col-span-8 whitespace-pre"),
|
||||
Summary(Class("cursor-pointer"), Text("Signature")),
|
||||
Code(Text(tag.Signature)),
|
||||
),
|
||||
),
|
||||
If(tag.Annotation != "",
|
||||
Div(Class("col-span-8 mb-3"), Text(tag.Annotation)),
|
||||
),
|
||||
})
|
||||
}),
|
||||
),
|
||||
})),
|
||||
}...)
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package html
|
||||
|
||||
import "fmt"
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
|
||||
type RepoRefsContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Branches []string
|
||||
Tags []git.Tag
|
||||
}
|
||||
|
||||
templ RepoRefs(rrc RepoRefsContext) {
|
||||
@base(rrc.BaseContext) {
|
||||
@repoHeaderComponent(rrc.RepoHeaderComponentContext)
|
||||
if len(rrc.Branches) > 0 {
|
||||
<h3 class="text-text text-lg mt-5">Branches</h3>
|
||||
<div class="text-text grid grid-cols-4 sm:grid-cols-8">
|
||||
for _, branch := range rrc.Branches {
|
||||
<div class="col-span-2 sm:col-span-1 font-bold">{ branch }</div>
|
||||
<div class="col-span-2 sm:col-span-7"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, branch)) }>tree</a>{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, branch)) }>log</a></div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
if len(rrc.Tags) > 0 {
|
||||
<h3 class="text-text text-lg mt-5">Tags</h3>
|
||||
<div class="text-text grid grid-cols-8">
|
||||
for _, tag := range rrc.Tags {
|
||||
<div class="col-span-1 font-bold">{ tag.Name }</div>
|
||||
<div class="col-span-7"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, tag.Name)) }>tree</a>{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, tag.Name)) }>log</a></div>
|
||||
if tag.Signature != "" {
|
||||
<details class="col-span-8 whitespace-pre"><summary class="cursor-pointer">Signature</summary><code>{ tag.Signature }</code></details>
|
||||
}
|
||||
if tag.Annotation != "" {
|
||||
<div class="col-span-8 mb-3">{ tag.Annotation }</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import "fmt"
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
|
||||
type RepoRefsContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Branches []string
|
||||
Tags []git.Tag
|
||||
}
|
||||
|
||||
func RepoRefs(rrc RepoRefsContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
templ_7745c5c3_Err = repoHeaderComponent(rrc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if len(rrc.Branches) > 0 {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h3 class=\"text-text text-lg mt-5\">Branches</h3><div class=\"text-text grid grid-cols-4 sm:grid-cols-8\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, branch := range rrc.Branches {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-2 sm:col-span-1 font-bold\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(branch)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 20, Col: 61}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"col-span-2 sm:col-span-7\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, branch))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">tree</a>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 21, Col: 234}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, branch))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var6)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if len(rrc.Tags) > 0 {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h3 class=\"text-text text-lg mt-5\">Tags</h3><div class=\"text-text grid grid-cols-8\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, tag := range rrc.Tags {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-1 font-bold\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 29, Col: 49}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"col-span-7\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, tag.Name))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var8)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">tree</a>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 30, Col: 222}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, tag.Name))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if tag.Signature != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"col-span-8 whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><code>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Signature)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 32, Col: 121}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code></details>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if tag.Annotation != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-8 mb-3\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 string
|
||||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Annotation)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 35, Col: 51}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = base(rrc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type SearchContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Results []git.GrepResult
|
||||
}
|
||||
|
||||
func (s SearchContext) DedupeResults() [][]git.GrepResult {
|
||||
var (
|
||||
results [][]git.GrepResult
|
||||
currentFile string
|
||||
)
|
||||
var idx int
|
||||
for _, result := range s.Results {
|
||||
if result.File == currentFile {
|
||||
results[idx-1] = append(results[idx-1], result)
|
||||
continue
|
||||
}
|
||||
results = append(results, []git.GrepResult{result})
|
||||
currentFile = result.File
|
||||
idx++
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
//go:embed repo_search.js
|
||||
var repoSearchJS string
|
||||
|
||||
func repoSearchResult(repo, ref string, results []git.GrepResult) Node {
|
||||
return Group([]Node{
|
||||
Div(Class("text-text mt-5"),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line)), Text(results[0].File)),
|
||||
),
|
||||
Div(Class("code"),
|
||||
Raw(results[0].Content),
|
||||
),
|
||||
If(len(results) > 1,
|
||||
Details(Class("text-text cursor-pointer"),
|
||||
Summary(Textf("%d more", len(results[1:]))),
|
||||
Map(results[1:], func(result git.GrepResult) Node {
|
||||
return Group([]Node{
|
||||
Div(Class("text-text mt-5 ml-5"),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line)), Text(results[0].File)),
|
||||
),
|
||||
Div(Class("code ml-5"),
|
||||
Raw(result.Content),
|
||||
),
|
||||
})
|
||||
}),
|
||||
),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
func RepoSearchTemplate(sc SearchContext) Node {
|
||||
dedupeResults := sc.DedupeResults()
|
||||
return base(sc.BaseContext, []Node{
|
||||
repoHeaderComponent(sc.RepoHeaderComponentContext),
|
||||
Map(dedupeResults, func(results []git.GrepResult) Node {
|
||||
return repoSearchResult(sc.RepoHeaderComponentContext.Name, sc.RepoHeaderComponentContext.Ref, results)
|
||||
}),
|
||||
If(len(dedupeResults) == 0,
|
||||
P(Class("text-text mt-5 text-lg"), Text("No results")),
|
||||
),
|
||||
Script(Raw(repoSearchJS)),
|
||||
}...)
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
const search = new URLSearchParams(window.location.search).get("q");
|
||||
if (search !== "") document.querySelector("#search").value = search;
|
|
@ -1,65 +0,0 @@
|
|||
package html
|
||||
|
||||
import "fmt"
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
|
||||
type SearchContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Results []git.GrepResult
|
||||
}
|
||||
|
||||
func (s SearchContext) DedupeResults() [][]git.GrepResult {
|
||||
var (
|
||||
results [][]git.GrepResult
|
||||
currentFile string
|
||||
currentResults []git.GrepResult
|
||||
)
|
||||
for _, result := range s.Results {
|
||||
if result.File == currentFile {
|
||||
currentResults = append(currentResults, result)
|
||||
continue
|
||||
}
|
||||
if currentFile != "" {
|
||||
results = append(results, currentResults)
|
||||
}
|
||||
currentFile = result.File
|
||||
currentResults = []git.GrepResult{result}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
templ RepoSearch(sc SearchContext) {
|
||||
@base(sc.BaseContext) {
|
||||
@repoHeaderComponent(sc.RepoHeaderComponentContext)
|
||||
for _, results := range sc.DedupeResults() {
|
||||
@repoSearchResult(sc.RepoHeaderComponentContext.Name, sc.RepoHeaderComponentContext.Ref, results)
|
||||
}
|
||||
if len(sc.DedupeResults()) == 0 {
|
||||
<p class="text-text mt-5 text-lg">No results</p>
|
||||
}
|
||||
}
|
||||
<script>
|
||||
const search = new URLSearchParams(window.location.search).get("q");
|
||||
if (search !== "") document.querySelector("#search").value = search;
|
||||
</script>
|
||||
}
|
||||
|
||||
templ repoSearchResult(repo, ref string, results []git.GrepResult) {
|
||||
<div class="text-text mt-5"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line)) }>{ results[0].File }</a></div>
|
||||
<div class="code">
|
||||
@templ.Raw(results[0].Content)
|
||||
</div>
|
||||
if len(results) > 1 {
|
||||
<details class="text-text cursor-pointer">
|
||||
<summary>{ fmt.Sprintf("%d ", len(results[1:])) }more</summary>
|
||||
for _, result := range results[1:] {
|
||||
<div class="text-text mt-5 ml-5"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line)) }>{ results[0].File }</a></div>
|
||||
<div class="code ml-5">
|
||||
@templ.Raw(result.Content)
|
||||
</div>
|
||||
}
|
||||
</details>
|
||||
}
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import "fmt"
|
||||
import "go.jolheiser.com/ugit/internal/git"
|
||||
|
||||
type SearchContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
Results []git.GrepResult
|
||||
}
|
||||
|
||||
func (s SearchContext) DedupeResults() [][]git.GrepResult {
|
||||
var (
|
||||
results [][]git.GrepResult
|
||||
currentFile string
|
||||
currentResults []git.GrepResult
|
||||
)
|
||||
for _, result := range s.Results {
|
||||
if result.File == currentFile {
|
||||
currentResults = append(currentResults, result)
|
||||
continue
|
||||
}
|
||||
if currentFile != "" {
|
||||
results = append(results, currentResults)
|
||||
}
|
||||
currentFile = result.File
|
||||
currentResults = []git.GrepResult{result}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
func RepoSearch(sc SearchContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
templ_7745c5c3_Err = repoHeaderComponent(sc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, results := range sc.DedupeResults() {
|
||||
templ_7745c5c3_Err = repoSearchResult(sc.RepoHeaderComponentContext.Name, sc.RepoHeaderComponentContext.Ref, results).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if len(sc.DedupeResults()) == 0 {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"text-text mt-5 text-lg\">No results</p>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = base(sc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script>\n\t\tconst search = new URLSearchParams(window.location.search).get(\"q\");\n\t\tif (search !== \"\") document.querySelector(\"#search\").value = search;\n\t</script>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
func repoSearchResult(repo, ref string, results []git.GrepResult) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var3 == nil {
|
||||
templ_7745c5c3_Var3 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-text mt-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 50, Col: 230}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"code\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(results[0].Content).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if len(results) > 1 {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<details class=\"text-text cursor-pointer\"><summary>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d ", len(results[1:])))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 56, Col: 50}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("more</summary> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, result := range results[1:] {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"text-text mt-5 ml-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var7)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 58, Col: 230}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div><div class=\"code ml-5\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templ.Raw(result.Content).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</details>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import "fmt"
|
||||
|
||||
type RepoHeaderComponentContext struct {
|
||||
Name string
|
||||
Ref string
|
||||
Description string
|
||||
CloneURL string
|
||||
Tags []string
|
||||
}
|
||||
|
||||
func repoHeaderComponent(rhcc RepoHeaderComponentContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"mb-1 text-text\"><a class=\"text-lg underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var2 templ.SafeURL = templ.SafeURL("/" + rhcc.Name)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var2)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var3 string
|
||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(rhcc.Name)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 15, Col: 142}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if rhcc.Ref != "" {
|
||||
var templ_7745c5c3_Var4 string
|
||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 17, Col: 8}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"text-text/80 text-sm underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rhcc.Name, rhcc.Ref))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var5)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("@" + rhcc.Ref)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 18, Col: 194}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
var templ_7745c5c3_Var7 string
|
||||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 20, Col: 9}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/refs", rhcc.Name))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var8)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">refs</a> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var9 string
|
||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 22, Col: 9}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var10 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var10)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">log</a> ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var11 string
|
||||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 24, Col: 9}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<form class=\"inline-block\" action=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var12 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/search", rhcc.Name))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var12)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" method=\"get\"><input class=\"rounded p-1 bg-mantle focus:border-lavender focus:outline-none focus:ring-0\" id=\"search\" type=\"text\" name=\"q\" placeholder=\"search\"></form>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var13 string
|
||||
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 26, Col: 9}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<pre class=\"text-text inline select-all bg-base dark:bg-base/50 p-1 rounded\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var14 string
|
||||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 27, Col: 131}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</pre></div><div class=\"text-subtext0 mb-1\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
for _, tag := range rhcc.Tags {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<span class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var15 string
|
||||
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(tag)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 31, Col: 102}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"text-text/80 mb-1\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var16 string
|
||||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(rhcc.Description)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 34, Col: 50}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
type RepoTreeContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
RepoBreadcrumbComponentContext
|
||||
RepoTreeComponentContext
|
||||
ReadmeComponentContext
|
||||
Description string
|
||||
}
|
||||
|
||||
type RepoTreeComponentContext struct {
|
||||
Repo string
|
||||
Ref string
|
||||
Tree []git.FileInfo
|
||||
Back string
|
||||
}
|
||||
|
||||
func slashDir(name string, isDir bool) string {
|
||||
if isDir {
|
||||
return name + "/"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func repoTreeComponent(rtcc RepoTreeComponentContext) Node {
|
||||
return Div(Class("grid grid-cols-3 sm:grid-cols-8 text-text py-5 rounded px-5 gap-x-3 gap-y-1 bg-base dark:bg-base/50"),
|
||||
If(rtcc.Back != "", Group([]Node{
|
||||
Div(Class("col-span-2")),
|
||||
Div(Class("sm:col-span-6"),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back)), Text("..")),
|
||||
),
|
||||
})),
|
||||
Map(rtcc.Tree, func(fi git.FileInfo) Node {
|
||||
return Group([]Node{
|
||||
Div(Class("sm:col-span-1 break-keep"), Text(fi.Mode)),
|
||||
Div(Class("sm:col-span-1 text-right"), Text(fi.Size)),
|
||||
Div(Class("sm:col-span-6 overflow-hidden text-ellipsis"),
|
||||
A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path)), Text(slashDir(fi.Name(), fi.IsDir))),
|
||||
),
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func RepoTreeTemplate(rtc RepoTreeContext) Node {
|
||||
return base(rtc.BaseContext, []Node{
|
||||
repoHeaderComponent(rtc.RepoHeaderComponentContext),
|
||||
repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext),
|
||||
repoTreeComponent(rtc.RepoTreeComponentContext),
|
||||
readmeComponent(rtc.ReadmeComponentContext),
|
||||
}...)
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
)
|
||||
|
||||
type RepoTreeContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
RepoBreadcrumbComponentContext
|
||||
RepoTreeComponentContext
|
||||
ReadmeComponentContext
|
||||
Description string
|
||||
}
|
||||
|
||||
templ RepoTree(rtc RepoTreeContext) {
|
||||
@base(rtc.BaseContext) {
|
||||
@repoHeaderComponent(rtc.RepoHeaderComponentContext)
|
||||
@repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext)
|
||||
@repoTreeComponent(rtc.RepoTreeComponentContext)
|
||||
@readmeComponent(rtc.ReadmeComponentContext)
|
||||
}
|
||||
}
|
||||
|
||||
type RepoTreeComponentContext struct {
|
||||
Repo string
|
||||
Ref string
|
||||
Tree []git.FileInfo
|
||||
Back string
|
||||
}
|
||||
|
||||
func slashDir(name string, isDir bool) string {
|
||||
if isDir {
|
||||
return name + "/"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
templ repoTreeComponent(rtcc RepoTreeComponentContext) {
|
||||
<div class="grid grid-cols-3 sm:grid-cols-8 text-text py-5 rounded px-5 gap-x-3 gap-y-1 bg-base dark:bg-base/50">
|
||||
if rtcc.Back != "" {
|
||||
<div class="col-span-2"></div>
|
||||
<div class="sm:col-span-6"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back)) }>..</a></div>
|
||||
}
|
||||
for _, fi := range rtcc.Tree {
|
||||
<div class="sm:col-span-1 break-keep">{ fi.Mode }</div>
|
||||
<div class="sm:col-span-1 text-right">{ fi.Size }</div>
|
||||
<div class="sm:col-span-6 overflow-hidden text-ellipsis"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path)) }>{ slashDir(fi.Name(), fi.IsDir) }</a></div>
|
||||
}
|
||||
</div>
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
// Code generated by templ - DO NOT EDIT.
|
||||
|
||||
// templ: version: v0.2.707
|
||||
package html
|
||||
|
||||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
||||
|
||||
import "github.com/a-h/templ"
|
||||
import "context"
|
||||
import "io"
|
||||
import "bytes"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
)
|
||||
|
||||
type RepoTreeContext struct {
|
||||
BaseContext
|
||||
RepoHeaderComponentContext
|
||||
RepoBreadcrumbComponentContext
|
||||
RepoTreeComponentContext
|
||||
ReadmeComponentContext
|
||||
Description string
|
||||
}
|
||||
|
||||
func RepoTree(rtc RepoTreeContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var1 == nil {
|
||||
templ_7745c5c3_Var1 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
templ_7745c5c3_Var2 := templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
templ_7745c5c3_Err = repoHeaderComponent(rtc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = repoTreeComponent(rtc.RepoTreeComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = readmeComponent(rtc.ReadmeComponentContext).Render(ctx, templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
templ_7745c5c3_Err = base(rtc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
||||
|
||||
type RepoTreeComponentContext struct {
|
||||
Repo string
|
||||
Ref string
|
||||
Tree []git.FileInfo
|
||||
Back string
|
||||
}
|
||||
|
||||
func slashDir(name string, isDir bool) string {
|
||||
if isDir {
|
||||
return name + "/"
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func repoTreeComponent(rtcc RepoTreeComponentContext) templ.Component {
|
||||
return templ.ComponentFunc(func(ctx context.Context, templ_7745c5c3_W io.Writer) (templ_7745c5c3_Err error) {
|
||||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templ_7745c5c3_W.(*bytes.Buffer)
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
templ_7745c5c3_Buffer = templ.GetBuffer()
|
||||
defer templ.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||
}
|
||||
ctx = templ.InitializeContext(ctx)
|
||||
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
|
||||
if templ_7745c5c3_Var3 == nil {
|
||||
templ_7745c5c3_Var3 = templ.NopComponent
|
||||
}
|
||||
ctx = templ.ClearChildren(ctx)
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"grid grid-cols-3 sm:grid-cols-8 text-text py-5 rounded px-5 gap-x-3 gap-y-1 bg-base dark:bg-base/50\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if rtcc.Back != "" {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"col-span-2\"></div><div class=\"sm:col-span-6\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var4 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var4)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">..</a></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
for _, fi := range rtcc.Tree {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"sm:col-span-1 break-keep\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var5 string
|
||||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Mode)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 47, Col: 50}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-1 text-right\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var6 string
|
||||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Size)
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 48, Col: 50}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div class=\"sm:col-span-6 overflow-hidden text-ellipsis\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var7 templ.SafeURL = templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path))
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var7)))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
var templ_7745c5c3_Var8 string
|
||||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(slashDir(fi.Name(), fi.IsDir))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 49, Col: 256}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
if !templ_7745c5c3_IsBuffer {
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteTo(templ_7745c5c3_W)
|
||||
}
|
||||
return templ_7745c5c3_Err
|
||||
})
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./**/*.templ"],
|
||||
content: ["./*.go"],
|
||||
plugins: [require("@catppuccin/tailwindcss")],
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -126,7 +126,7 @@ func (rh repoHandler) repoHeaderContext(repo *git.Repo, r *http.Request) html.Re
|
|||
Name: chi.URLParam(r, "repo"),
|
||||
Ref: ref,
|
||||
CloneURL: rh.s.CloneURL,
|
||||
Tags: repo.Meta.Tags,
|
||||
Tags: repo.Meta.Tags.Slice(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,8 @@ package httperr
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
)
|
||||
|
||||
type httpError struct {
|
||||
|
@ -41,7 +40,7 @@ func Handler(fn func(w http.ResponseWriter, r *http.Request) error) http.Handler
|
|||
status = httpErr.status
|
||||
}
|
||||
|
||||
log.Error(err)
|
||||
slog.Error("httperr Handler error", "error", err)
|
||||
http.Error(w, http.StatusText(status), status)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
package httperr_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/alecthomas/assert/v2"
|
||||
"go.jolheiser.com/ugit/internal/http/httperr"
|
||||
)
|
||||
|
||||
func successHandler(w http.ResponseWriter, r *http.Request) error {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return nil
|
||||
}
|
||||
|
||||
func errorHandler(w http.ResponseWriter, r *http.Request) error {
|
||||
return errors.New("test error")
|
||||
}
|
||||
|
||||
func statusErrorHandler(status int) func(w http.ResponseWriter, r *http.Request) error {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
return httperr.Status(errors.New("test error"), status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandler_Success(t *testing.T) {
|
||||
handler := httperr.Handler(successHandler)
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, recorder.Code)
|
||||
}
|
||||
|
||||
func TestHandler_Error(t *testing.T) {
|
||||
handler := httperr.Handler(errorHandler)
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, http.StatusInternalServerError, recorder.Code)
|
||||
}
|
||||
|
||||
func TestHandler_StatusError(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
status int
|
||||
expectedStatus int
|
||||
}{
|
||||
{
|
||||
name: "not found",
|
||||
status: http.StatusNotFound,
|
||||
expectedStatus: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
name: "bad request",
|
||||
status: http.StatusBadRequest,
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "unauthorized",
|
||||
status: http.StatusUnauthorized,
|
||||
expectedStatus: http.StatusUnauthorized,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
handler := httperr.Handler(statusErrorHandler(tc.status))
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, tc.expectedStatus, recorder.Code)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type unwrapper interface {
|
||||
Unwrap() error
|
||||
}
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
originalErr := errors.New("original error")
|
||||
httpErr := httperr.Error(originalErr)
|
||||
|
||||
assert.Equal(t, originalErr.Error(), httpErr.Error())
|
||||
|
||||
unwrapper, ok := any(httpErr).(unwrapper)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, originalErr, unwrapper.Unwrap())
|
||||
}
|
||||
|
||||
func TestStatus(t *testing.T) {
|
||||
originalErr := errors.New("original error")
|
||||
httpErr := httperr.Status(originalErr, http.StatusNotFound)
|
||||
|
||||
assert.Equal(t, originalErr.Error(), httpErr.Error())
|
||||
|
||||
unwrapper, ok := any(httpErr).(unwrapper)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, originalErr, unwrapper.Unwrap())
|
||||
|
||||
handler := httperr.Handler(func(w http.ResponseWriter, r *http.Request) error {
|
||||
return httpErr
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
handler.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, recorder.Code)
|
||||
}
|
|
@ -3,7 +3,6 @@ package http
|
|||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -34,10 +33,10 @@ func (rh repoHandler) index(w http.ResponseWriter, r *http.Request) error {
|
|||
if !rh.s.ShowPrivate {
|
||||
continue
|
||||
}
|
||||
repo.Meta.Tags = append(repo.Meta.Tags, "private")
|
||||
repo.Meta.Tags.Add("private")
|
||||
}
|
||||
|
||||
if tagFilter != "" && !slices.Contains(repo.Meta.Tags, strings.ToLower(tagFilter)) {
|
||||
if tagFilter != "" && !repo.Meta.Tags.Contains(strings.ToLower(tagFilter)) {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, repo)
|
||||
|
@ -61,7 +60,7 @@ func (rh repoHandler) index(w http.ResponseWriter, r *http.Request) error {
|
|||
})
|
||||
}
|
||||
|
||||
if err := html.Index(html.IndexContext{
|
||||
if err := html.IndexTemplate(html.IndexContext{
|
||||
BaseContext: rh.baseContext(),
|
||||
Profile: html.IndexProfile{
|
||||
Username: rh.s.Profile.Username,
|
||||
|
@ -69,7 +68,7 @@ func (rh repoHandler) index(w http.ResponseWriter, r *http.Request) error {
|
|||
Links: links,
|
||||
},
|
||||
Repos: repos,
|
||||
}).Render(r.Context(), w); err != nil {
|
||||
}).Render(w); err != nil {
|
||||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ func (rh repoHandler) repoMiddleware(next http.Handler) http.Handler {
|
|||
if !rh.s.ShowPrivate {
|
||||
return httperr.Status(errors.New("could not get git repo"), http.StatusNotFound)
|
||||
}
|
||||
repo.Meta.Tags = append(repo.Meta.Tags, "private")
|
||||
repo.Meta.Tags.Add("private")
|
||||
}
|
||||
r = r.WithContext(context.WithValue(r.Context(), repoCtxKey, repo))
|
||||
next.ServeHTTP(w, r)
|
||||
|
|
|
@ -47,7 +47,7 @@ func (rh repoHandler) repoTree(ref, path string) http.HandlerFunc {
|
|||
if path != "" {
|
||||
back = filepath.Dir(path)
|
||||
}
|
||||
if err := html.RepoTree(html.RepoTreeContext{
|
||||
if err := html.RepoTreeTemplate(html.RepoTreeContext{
|
||||
Description: repo.Meta.Description,
|
||||
BaseContext: rh.baseContext(),
|
||||
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
|
||||
|
@ -61,7 +61,7 @@ func (rh repoHandler) repoTree(ref, path string) http.HandlerFunc {
|
|||
ReadmeComponentContext: html.ReadmeComponentContext{
|
||||
Markdown: readmeContent,
|
||||
},
|
||||
}).Render(r.Context(), w); err != nil {
|
||||
}).Render(w); err != nil {
|
||||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
|
@ -88,16 +88,26 @@ func (rh repoHandler) repoFile(w http.ResponseWriter, r *http.Request, repo *git
|
|||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := markup.Code.Convert([]byte(content), filepath.Base(path), &buf); err != nil {
|
||||
if err := markup.Convert([]byte(content), filepath.Base(path), "L", &buf); err != nil {
|
||||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
if err := html.RepoFile(html.RepoFileContext{
|
||||
commit := ref
|
||||
if len(ref) < 40 {
|
||||
commitObj, err := repo.GetCommitFromRef(ref)
|
||||
if err == nil {
|
||||
commit = commitObj.Hash.String()
|
||||
}
|
||||
}
|
||||
|
||||
if err := html.RepoFileTemplate(html.RepoFileContext{
|
||||
BaseContext: rh.baseContext(),
|
||||
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
|
||||
RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path),
|
||||
Code: buf.String(),
|
||||
}).Render(r.Context(), w); err != nil {
|
||||
Commit: commit,
|
||||
Path: path,
|
||||
}).Render(w); err != nil {
|
||||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
|
@ -117,12 +127,12 @@ func (rh repoHandler) repoRefs(w http.ResponseWriter, r *http.Request) error {
|
|||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
if err := html.RepoRefs(html.RepoRefsContext{
|
||||
if err := html.RepoRefsTemplate(html.RepoRefsContext{
|
||||
BaseContext: rh.baseContext(),
|
||||
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
|
||||
Branches: branches,
|
||||
Tags: tags,
|
||||
}).Render(r.Context(), w); err != nil {
|
||||
}).Render(w); err != nil {
|
||||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
|
@ -137,11 +147,11 @@ func (rh repoHandler) repoLog(w http.ResponseWriter, r *http.Request) error {
|
|||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
if err := html.RepoLog(html.RepoLogContext{
|
||||
if err := html.RepoLogTemplate(html.RepoLogContext{
|
||||
BaseContext: rh.baseContext(),
|
||||
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
|
||||
Commits: commits,
|
||||
}).Render(r.Context(), w); err != nil {
|
||||
}).Render(w); err != nil {
|
||||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
|
@ -158,17 +168,17 @@ func (rh repoHandler) repoCommit(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
for idx, p := range commit.Files {
|
||||
var patch bytes.Buffer
|
||||
if err := markup.Code.Basic([]byte(p.Patch), "commit.patch", &patch); err != nil {
|
||||
if err := markup.Convert([]byte(p.Patch), "commit.patch", p.Path()+"-L", &patch); err != nil {
|
||||
return httperr.Error(err)
|
||||
}
|
||||
commit.Files[idx].Patch = patch.String()
|
||||
}
|
||||
|
||||
if err := html.RepoCommit(html.RepoCommitContext{
|
||||
if err := html.RepoCommitTemplate(html.RepoCommitContext{
|
||||
BaseContext: rh.baseContext(),
|
||||
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
|
||||
Commit: commit,
|
||||
}).Render(r.Context(), w); err != nil {
|
||||
}).Render(w); err != nil {
|
||||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
|
@ -206,14 +216,13 @@ func (rh repoHandler) repoSearch(w http.ResponseWriter, r *http.Request) error {
|
|||
}
|
||||
results[idx].Content = buf.String()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if err := html.RepoSearch(html.SearchContext{
|
||||
if err := html.RepoSearchTemplate(html.SearchContext{
|
||||
BaseContext: rh.baseContext(),
|
||||
RepoHeaderComponentContext: rh.repoHeaderContext(repo, r),
|
||||
Results: results,
|
||||
}).Render(r.Context(), w); err != nil {
|
||||
}).Render(w); err != nil {
|
||||
return httperr.Error(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ package ssh
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/charmbracelet/ssh"
|
||||
"github.com/charmbracelet/wish"
|
||||
"github.com/charmbracelet/wish/logging"
|
||||
|
@ -42,7 +42,7 @@ func (a hooks) Push(_ string, _ ssh.PublicKey) {}
|
|||
func (a hooks) Fetch(_ string, _ ssh.PublicKey) {}
|
||||
|
||||
var (
|
||||
DefaultLogger logging.Logger = log.StandardLog()
|
||||
DefaultLogger logging.Logger = log.Default()
|
||||
NoopLogger logging.Logger = noopLogger{}
|
||||
)
|
||||
|
||||
|
|
|
@ -5,14 +5,15 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
"go.jolheiser.com/ugit/internal/tui"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/charmbracelet/ssh"
|
||||
"github.com/charmbracelet/wish"
|
||||
)
|
||||
|
@ -91,7 +92,7 @@ func Middleware(repoDir string, cloneURL string, port int, gh Hooks) wish.Middle
|
|||
if errors.Is(err, ErrInvalidRepo) {
|
||||
Fatal(s, ErrInvalidRepo)
|
||||
}
|
||||
log.Error("unknown git error", "error", err)
|
||||
slog.Error("unknown git error", "error", err)
|
||||
Fatal(s, ErrSystemMalfunction)
|
||||
}
|
||||
gh.Fetch(repo, pk)
|
||||
|
@ -99,11 +100,15 @@ func Middleware(repoDir string, cloneURL string, port int, gh Hooks) wish.Middle
|
|||
}
|
||||
}
|
||||
|
||||
// Repo list
|
||||
// No args, start TUI
|
||||
if len(cmd) == 0 {
|
||||
if err := tui.Start(s, repoDir); err != nil {
|
||||
slog.Error("failed to start TUI", "error", err)
|
||||
|
||||
// Fall back to simple list on TUI error
|
||||
des, err := os.ReadDir(repoDir)
|
||||
if err != nil && err != fs.ErrNotExist {
|
||||
log.Error("invalid repository", "error", err)
|
||||
slog.Error("invalid repository", "error", err)
|
||||
}
|
||||
tw := tabwriter.NewWriter(s, 0, 0, 1, ' ', 0)
|
||||
for _, de := range des {
|
||||
|
@ -122,6 +127,8 @@ func Middleware(repoDir string, cloneURL string, port int, gh Hooks) wish.Middle
|
|||
}
|
||||
tw.Flush()
|
||||
}
|
||||
return
|
||||
}
|
||||
sh(s)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
package tui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
)
|
||||
|
||||
type repoForm struct {
|
||||
inputs []textinput.Model
|
||||
isPrivate bool
|
||||
focusIndex int
|
||||
width int
|
||||
height int
|
||||
done bool
|
||||
save bool
|
||||
selectedRepo *git.Repo
|
||||
}
|
||||
|
||||
// newRepoForm creates a new repository editing form
|
||||
func newRepoForm() repoForm {
|
||||
var inputs []textinput.Model
|
||||
|
||||
nameInput := textinput.New()
|
||||
nameInput.Placeholder = "Repository name"
|
||||
nameInput.Focus()
|
||||
nameInput.Width = 50
|
||||
inputs = append(inputs, nameInput)
|
||||
|
||||
descInput := textinput.New()
|
||||
descInput.Placeholder = "Repository description"
|
||||
descInput.Width = 50
|
||||
inputs = append(inputs, descInput)
|
||||
|
||||
tagsInput := textinput.New()
|
||||
tagsInput.Placeholder = "Tags (comma separated)"
|
||||
tagsInput.Width = 50
|
||||
inputs = append(inputs, tagsInput)
|
||||
|
||||
return repoForm{
|
||||
inputs: inputs,
|
||||
focusIndex: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// setValues sets the form values from the selected repo
|
||||
func (f *repoForm) setValues(repo *git.Repo) {
|
||||
f.inputs[0].SetValue(repo.Name())
|
||||
f.inputs[1].SetValue(repo.Meta.Description)
|
||||
f.inputs[2].SetValue(strings.Join(repo.Meta.Tags.Slice(), ", "))
|
||||
f.isPrivate = repo.Meta.Private
|
||||
|
||||
f.inputs[0].Focus()
|
||||
f.focusIndex = 0
|
||||
}
|
||||
|
||||
// setSize sets the form dimensions
|
||||
func (f *repoForm) setSize(width, height int) {
|
||||
f.width = width
|
||||
f.height = height
|
||||
|
||||
for i := range f.inputs {
|
||||
f.inputs[i].Width = width - 10
|
||||
}
|
||||
}
|
||||
|
||||
// isPrivateToggleFocused returns true if the private toggle is focused
|
||||
func (f *repoForm) isPrivateToggleFocused() bool {
|
||||
return f.focusIndex == len(f.inputs)
|
||||
}
|
||||
|
||||
// isSaveButtonFocused returns true if the save button is focused
|
||||
func (f *repoForm) isSaveButtonFocused() bool {
|
||||
return f.focusIndex == len(f.inputs)+1
|
||||
}
|
||||
|
||||
// isCancelButtonFocused returns true if the cancel button is focused
|
||||
func (f *repoForm) isCancelButtonFocused() bool {
|
||||
return f.focusIndex == len(f.inputs)+2
|
||||
}
|
||||
|
||||
// Update handles form updates
|
||||
func (f repoForm) Update(msg tea.Msg) (repoForm, tea.Cmd) {
|
||||
var cmds []tea.Cmd
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "tab", "shift+tab", "up", "down":
|
||||
if msg.String() == "up" || msg.String() == "shift+tab" {
|
||||
f.focusIndex--
|
||||
if f.focusIndex < 0 {
|
||||
f.focusIndex = len(f.inputs) + 3 - 1
|
||||
}
|
||||
} else {
|
||||
f.focusIndex++
|
||||
if f.focusIndex >= len(f.inputs)+3 {
|
||||
f.focusIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
for i := range f.inputs {
|
||||
if i == f.focusIndex {
|
||||
cmds = append(cmds, f.inputs[i].Focus())
|
||||
} else {
|
||||
f.inputs[i].Blur()
|
||||
}
|
||||
}
|
||||
|
||||
case "enter":
|
||||
if f.isSaveButtonFocused() {
|
||||
f.done = true
|
||||
f.save = true
|
||||
return f, nil
|
||||
}
|
||||
|
||||
if f.isCancelButtonFocused() {
|
||||
f.done = true
|
||||
f.save = false
|
||||
return f, nil
|
||||
}
|
||||
|
||||
case "esc":
|
||||
f.done = true
|
||||
f.save = false
|
||||
return f, nil
|
||||
|
||||
case " ":
|
||||
if f.isPrivateToggleFocused() {
|
||||
f.isPrivate = !f.isPrivate
|
||||
}
|
||||
|
||||
if f.isSaveButtonFocused() {
|
||||
f.done = true
|
||||
f.save = true
|
||||
return f, nil
|
||||
}
|
||||
|
||||
if f.isCancelButtonFocused() {
|
||||
f.done = true
|
||||
f.save = false
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := range f.inputs {
|
||||
if i == f.focusIndex {
|
||||
var cmd tea.Cmd
|
||||
f.inputs[i], cmd = f.inputs[i].Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
}
|
||||
|
||||
return f, tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
// View renders the form
|
||||
func (f repoForm) View() string {
|
||||
var b strings.Builder
|
||||
|
||||
formStyle := lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("170")).
|
||||
Padding(1, 2)
|
||||
|
||||
titleStyle := lipgloss.NewStyle().
|
||||
Bold(true).
|
||||
Foreground(lipgloss.Color("170")).
|
||||
MarginBottom(1)
|
||||
|
||||
b.WriteString(titleStyle.Render("Edit Repository"))
|
||||
b.WriteString("\n\n")
|
||||
|
||||
b.WriteString("Repository Name:\n")
|
||||
b.WriteString(f.inputs[0].View())
|
||||
b.WriteString("\n\n")
|
||||
|
||||
b.WriteString("Description:\n")
|
||||
b.WriteString(f.inputs[1].View())
|
||||
b.WriteString("\n\n")
|
||||
|
||||
b.WriteString("Tags (comma separated):\n")
|
||||
b.WriteString(f.inputs[2].View())
|
||||
b.WriteString("\n\n")
|
||||
|
||||
toggleStyle := lipgloss.NewStyle()
|
||||
if f.isPrivateToggleFocused() {
|
||||
toggleStyle = toggleStyle.Foreground(lipgloss.Color("170")).Bold(true)
|
||||
}
|
||||
|
||||
visibility := "Public 🔓"
|
||||
if f.isPrivate {
|
||||
visibility = "Private 🔒"
|
||||
}
|
||||
|
||||
b.WriteString(toggleStyle.Render(fmt.Sprintf("[%s] %s", visibility, "Toggle with Space")))
|
||||
b.WriteString("\n\n")
|
||||
|
||||
buttonStyle := lipgloss.NewStyle().
|
||||
Padding(0, 3).
|
||||
MarginRight(1)
|
||||
|
||||
focusedButtonStyle := buttonStyle.Copy().
|
||||
Foreground(lipgloss.Color("0")).
|
||||
Background(lipgloss.Color("170")).
|
||||
Bold(true)
|
||||
|
||||
saveButton := buttonStyle.Render("[ Save ]")
|
||||
cancelButton := buttonStyle.Render("[ Cancel ]")
|
||||
|
||||
if f.isSaveButtonFocused() {
|
||||
saveButton = focusedButtonStyle.Render("[ Save ]")
|
||||
}
|
||||
|
||||
if f.isCancelButtonFocused() {
|
||||
cancelButton = focusedButtonStyle.Render("[ Cancel ]")
|
||||
}
|
||||
|
||||
b.WriteString(saveButton + cancelButton)
|
||||
b.WriteString("\n\n")
|
||||
|
||||
b.WriteString("\nTab: Next • Shift+Tab: Previous • Enter: Select • Esc: Cancel")
|
||||
|
||||
return formStyle.Width(f.width - 4).Render(b.String())
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package tui
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
)
|
||||
|
||||
// keyMap defines the keybindings for the TUI
|
||||
type keyMap struct {
|
||||
Up key.Binding
|
||||
Down key.Binding
|
||||
Edit key.Binding
|
||||
Delete key.Binding
|
||||
Help key.Binding
|
||||
Quit key.Binding
|
||||
Confirm key.Binding
|
||||
Cancel key.Binding
|
||||
}
|
||||
|
||||
// ShortHelp returns keybindings to be shown in the mini help view.
|
||||
func (k keyMap) ShortHelp() []key.Binding {
|
||||
return []key.Binding{k.Help, k.Edit, k.Delete, k.Quit}
|
||||
}
|
||||
|
||||
// FullHelp returns keybindings for the expanded help view.
|
||||
func (k keyMap) FullHelp() [][]key.Binding {
|
||||
return [][]key.Binding{
|
||||
{k.Up, k.Down, k.Edit},
|
||||
{k.Delete, k.Help, k.Quit},
|
||||
}
|
||||
}
|
||||
|
||||
var keys = keyMap{
|
||||
Up: key.NewBinding(
|
||||
key.WithKeys("up", "k"),
|
||||
key.WithHelp("↑/k", "up"),
|
||||
),
|
||||
Down: key.NewBinding(
|
||||
key.WithKeys("down", "j"),
|
||||
key.WithHelp("↓/j", "down"),
|
||||
),
|
||||
Edit: key.NewBinding(
|
||||
key.WithKeys("e"),
|
||||
key.WithHelp("e", "edit"),
|
||||
),
|
||||
Delete: key.NewBinding(
|
||||
key.WithKeys("d"),
|
||||
key.WithHelp("d", "delete"),
|
||||
),
|
||||
Help: key.NewBinding(
|
||||
key.WithKeys("?"),
|
||||
key.WithHelp("?", "help"),
|
||||
),
|
||||
Quit: key.NewBinding(
|
||||
key.WithKeys("q", "ctrl+c"),
|
||||
key.WithHelp("q", "quit"),
|
||||
),
|
||||
Confirm: key.NewBinding(
|
||||
key.WithKeys("y"),
|
||||
key.WithHelp("y", "confirm"),
|
||||
),
|
||||
Cancel: key.NewBinding(
|
||||
key.WithKeys("n", "esc"),
|
||||
key.WithHelp("n", "cancel"),
|
||||
),
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package tui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/charmbracelet/bubbles/help"
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
// Run runs the TUI standalone, useful for development or local usage
|
||||
func Run(repoDir string) error {
|
||||
model := Model{
|
||||
repoDir: repoDir,
|
||||
help: help.New(),
|
||||
keys: keys,
|
||||
activeView: ViewList,
|
||||
repoForm: newRepoForm(),
|
||||
}
|
||||
|
||||
repos, err := loadRepos(repoDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load repos: %w", err)
|
||||
}
|
||||
model.repos = repos
|
||||
|
||||
items := make([]list.Item, len(repos))
|
||||
for i, repo := range repos {
|
||||
items[i] = repoItem{repo: repo}
|
||||
}
|
||||
|
||||
delegate := list.NewDefaultDelegate()
|
||||
delegate.Styles.SelectedTitle = delegate.Styles.SelectedTitle.Foreground(lipgloss.Color("170"))
|
||||
delegate.Styles.SelectedDesc = delegate.Styles.SelectedDesc.Foreground(lipgloss.Color("244"))
|
||||
|
||||
repoList := list.New(items, delegate, 0, 0)
|
||||
repoList.Title = "Git Repositories"
|
||||
repoList.SetShowStatusBar(true)
|
||||
repoList.SetFilteringEnabled(true)
|
||||
repoList.Styles.Title = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("170")).Padding(0, 0, 0, 2)
|
||||
repoList.StatusMessageLifetime = 3
|
||||
|
||||
model.repoList = repoList
|
||||
|
||||
p := tea.NewProgram(model, tea.WithAltScreen(), tea.WithMouseCellMotion())
|
||||
|
||||
_, err = p.Run()
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package tui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
)
|
||||
|
||||
// repoItem represents a repository item in the list
|
||||
type repoItem struct {
|
||||
repo *git.Repo
|
||||
}
|
||||
|
||||
// Title returns the title for the list item
|
||||
func (r repoItem) Title() string {
|
||||
return r.repo.Name()
|
||||
}
|
||||
|
||||
// Description returns the description for the list item
|
||||
func (r repoItem) Description() string {
|
||||
var builder strings.Builder
|
||||
|
||||
if r.repo.Meta.Private {
|
||||
builder.WriteString("🔒")
|
||||
} else {
|
||||
builder.WriteString("🔓")
|
||||
}
|
||||
|
||||
builder.WriteString(" • ")
|
||||
|
||||
if r.repo.Meta.Description != "" {
|
||||
builder.WriteString(r.repo.Meta.Description)
|
||||
} else {
|
||||
builder.WriteString("No description")
|
||||
}
|
||||
|
||||
builder.WriteString(" • ")
|
||||
|
||||
builder.WriteString("[")
|
||||
if len(r.repo.Meta.Tags) > 0 {
|
||||
builder.WriteString(strings.Join(r.repo.Meta.Tags.Slice(), ", "))
|
||||
}
|
||||
builder.WriteString("]")
|
||||
|
||||
builder.WriteString(" • ")
|
||||
|
||||
lastCommit, err := r.repo.LastCommit()
|
||||
if err == nil {
|
||||
builder.WriteString(lastCommit.Short())
|
||||
} else {
|
||||
builder.WriteString("deadbeef")
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// FilterValue returns the value to use for filtering
|
||||
func (r repoItem) FilterValue() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString(r.repo.Name())
|
||||
builder.WriteString(" ")
|
||||
builder.WriteString(r.repo.Meta.Description)
|
||||
|
||||
if len(r.repo.Meta.Tags) > 0 {
|
||||
for _, tag := range r.repo.Meta.Tags.Slice() {
|
||||
builder.WriteString(" ")
|
||||
builder.WriteString(tag)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.ToLower(builder.String())
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
package tui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/help"
|
||||
"github.com/charmbracelet/bubbles/key"
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/ssh"
|
||||
"github.com/charmbracelet/wish/bubbletea"
|
||||
"go.jolheiser.com/ugit/internal/git"
|
||||
)
|
||||
|
||||
// Model is the main TUI model
|
||||
type Model struct {
|
||||
repoList list.Model
|
||||
repos []*git.Repo
|
||||
repoDir string
|
||||
width int
|
||||
height int
|
||||
help help.Model
|
||||
keys keyMap
|
||||
activeView View
|
||||
repoForm repoForm
|
||||
session ssh.Session
|
||||
}
|
||||
|
||||
// View represents the current active view in the TUI
|
||||
type View int
|
||||
|
||||
const (
|
||||
ViewList View = iota
|
||||
ViewForm
|
||||
ViewConfirmDelete
|
||||
)
|
||||
|
||||
// New creates a new TUI model
|
||||
func New(s ssh.Session, repoDir string) (*Model, error) {
|
||||
repos, err := loadRepos(repoDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load repos: %w", err)
|
||||
}
|
||||
r := bubbletea.MakeRenderer(s)
|
||||
|
||||
items := make([]list.Item, len(repos))
|
||||
for i, repo := range repos {
|
||||
items[i] = repoItem{repo: repo}
|
||||
}
|
||||
|
||||
delegate := list.NewDefaultDelegate()
|
||||
delegate.Styles.SelectedTitle = delegate.Styles.SelectedTitle.Foreground(lipgloss.Color("170"))
|
||||
delegate.Styles.SelectedDesc = delegate.Styles.SelectedDesc.Foreground(lipgloss.Color("244"))
|
||||
|
||||
repoList := list.New(items, delegate, 0, 0)
|
||||
repoList.Title = "Git Repositories"
|
||||
repoList.SetShowStatusBar(true)
|
||||
repoList.SetFilteringEnabled(true)
|
||||
repoList.Styles.Title = r.NewStyle().Bold(true).Foreground(lipgloss.Color("170")).Padding(0, 0, 0, 2)
|
||||
repoList.StatusMessageLifetime = 3
|
||||
repoList.Styles.Title.Renderer(r)
|
||||
|
||||
repoList.FilterInput.Placeholder = "Type to filter repositories..."
|
||||
repoList.FilterInput.PromptStyle = r.NewStyle().Foreground(lipgloss.Color("170"))
|
||||
repoList.FilterInput.TextStyle = r.NewStyle()
|
||||
|
||||
help := help.New()
|
||||
|
||||
repoForm := newRepoForm()
|
||||
|
||||
return &Model{
|
||||
repoList: repoList,
|
||||
repos: repos,
|
||||
repoDir: repoDir,
|
||||
help: help,
|
||||
keys: keys,
|
||||
activeView: ViewList,
|
||||
repoForm: repoForm,
|
||||
session: s,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// loadRepos loads all git repositories from the given directory
|
||||
func loadRepos(repoDir string) ([]*git.Repo, error) {
|
||||
entries, err := git.ListRepos(repoDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repos := make([]*git.Repo, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
if !strings.HasSuffix(entry.Name(), ".git") {
|
||||
continue
|
||||
}
|
||||
repo, err := git.NewRepo(repoDir, entry.Name())
|
||||
if err != nil {
|
||||
slog.Error("error loading repo", "name", entry.Name(), "error", err)
|
||||
continue
|
||||
}
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
// Init initializes the model
|
||||
func (m Model) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update handles all the messages and updates the model accordingly
|
||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmds []tea.Cmd
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch {
|
||||
case key.Matches(msg, m.keys.Quit):
|
||||
return m, tea.Quit
|
||||
case key.Matches(msg, m.keys.Help):
|
||||
m.help.ShowAll = !m.help.ShowAll
|
||||
}
|
||||
|
||||
switch m.activeView {
|
||||
case ViewList:
|
||||
var cmd tea.Cmd
|
||||
m.repoList, cmd = m.repoList.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
if m.repoList.FilterState() == list.Filtering {
|
||||
break
|
||||
}
|
||||
|
||||
switch {
|
||||
case key.Matches(msg, m.keys.Edit):
|
||||
if len(m.repos) == 0 {
|
||||
m.repoList.NewStatusMessage("No repositories to edit")
|
||||
break
|
||||
}
|
||||
|
||||
selectedItem := m.repoList.SelectedItem().(repoItem)
|
||||
m.repoForm.selectedRepo = selectedItem.repo
|
||||
|
||||
m.repoForm.setValues(selectedItem.repo)
|
||||
m.activeView = ViewForm
|
||||
return m, textinput.Blink
|
||||
|
||||
case key.Matches(msg, m.keys.Delete):
|
||||
if len(m.repos) == 0 {
|
||||
m.repoList.NewStatusMessage("No repositories to delete")
|
||||
break
|
||||
}
|
||||
|
||||
m.activeView = ViewConfirmDelete
|
||||
}
|
||||
|
||||
case ViewForm:
|
||||
var cmd tea.Cmd
|
||||
m.repoForm, cmd = m.repoForm.Update(msg)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
if m.repoForm.done {
|
||||
if m.repoForm.save {
|
||||
selectedRepo := m.repoForm.selectedRepo
|
||||
repoDir := filepath.Dir(selectedRepo.Path())
|
||||
oldName := selectedRepo.Name()
|
||||
newName := m.repoForm.inputs[0].Value()
|
||||
|
||||
var renamed bool
|
||||
if oldName != newName {
|
||||
if err := git.RenameRepo(repoDir, oldName, newName); err != nil {
|
||||
m.repoList.NewStatusMessage(fmt.Sprintf("Error renaming repo: %s", err))
|
||||
} else {
|
||||
m.repoList.NewStatusMessage(fmt.Sprintf("Repository renamed from %s to %s", oldName, newName))
|
||||
renamed = true
|
||||
}
|
||||
}
|
||||
|
||||
if renamed {
|
||||
if newRepo, err := git.NewRepo(repoDir, newName+".git"); err == nil {
|
||||
selectedRepo = newRepo
|
||||
} else {
|
||||
m.repoList.NewStatusMessage(fmt.Sprintf("Error loading renamed repo: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
selectedRepo.Meta.Description = m.repoForm.inputs[1].Value()
|
||||
selectedRepo.Meta.Private = m.repoForm.isPrivate
|
||||
|
||||
tags := make(git.TagSet)
|
||||
for _, tag := range strings.Split(m.repoForm.inputs[2].Value(), ",") {
|
||||
tag = strings.TrimSpace(tag)
|
||||
if tag != "" {
|
||||
tags.Add(tag)
|
||||
}
|
||||
}
|
||||
selectedRepo.Meta.Tags = tags
|
||||
|
||||
if err := selectedRepo.SaveMeta(); err != nil {
|
||||
m.repoList.NewStatusMessage(fmt.Sprintf("Error saving repo metadata: %s", err))
|
||||
} else if !renamed {
|
||||
m.repoList.NewStatusMessage("Repository updated successfully")
|
||||
}
|
||||
}
|
||||
|
||||
m.repoForm.done = false
|
||||
m.repoForm.save = false
|
||||
m.activeView = ViewList
|
||||
|
||||
if repos, err := loadRepos(m.repoDir); err == nil {
|
||||
m.repos = repos
|
||||
items := make([]list.Item, len(repos))
|
||||
for i, repo := range repos {
|
||||
items[i] = repoItem{repo: repo}
|
||||
}
|
||||
m.repoList.SetItems(items)
|
||||
}
|
||||
}
|
||||
|
||||
case ViewConfirmDelete:
|
||||
switch {
|
||||
case key.Matches(msg, m.keys.Confirm):
|
||||
selectedItem := m.repoList.SelectedItem().(repoItem)
|
||||
repo := selectedItem.repo
|
||||
|
||||
if err := git.DeleteRepo(repo.Path()); err != nil {
|
||||
m.repoList.NewStatusMessage(fmt.Sprintf("Error deleting repo: %s", err))
|
||||
} else {
|
||||
m.repoList.NewStatusMessage(fmt.Sprintf("Repository %s deleted", repo.Name()))
|
||||
|
||||
if repos, err := loadRepos(m.repoDir); err == nil {
|
||||
m.repos = repos
|
||||
items := make([]list.Item, len(repos))
|
||||
for i, repo := range repos {
|
||||
items[i] = repoItem{repo: repo}
|
||||
}
|
||||
m.repoList.SetItems(items)
|
||||
}
|
||||
}
|
||||
m.activeView = ViewList
|
||||
|
||||
case key.Matches(msg, m.keys.Cancel):
|
||||
m.activeView = ViewList
|
||||
}
|
||||
}
|
||||
|
||||
case tea.WindowSizeMsg:
|
||||
m.width = msg.Width
|
||||
m.height = msg.Height
|
||||
|
||||
headerHeight := 3
|
||||
footerHeight := 2
|
||||
|
||||
m.repoList.SetSize(msg.Width, msg.Height-headerHeight-footerHeight)
|
||||
m.repoForm.setSize(msg.Width, msg.Height)
|
||||
|
||||
m.help.Width = msg.Width
|
||||
}
|
||||
|
||||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
// View renders the current UI
|
||||
func (m Model) View() string {
|
||||
switch m.activeView {
|
||||
case ViewList:
|
||||
return fmt.Sprintf("%s\n%s", m.repoList.View(), m.help.View(m.keys))
|
||||
|
||||
case ViewForm:
|
||||
return m.repoForm.View()
|
||||
|
||||
case ViewConfirmDelete:
|
||||
selectedItem := m.repoList.SelectedItem().(repoItem)
|
||||
repo := selectedItem.repo
|
||||
|
||||
confirmStyle := lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.RoundedBorder()).
|
||||
BorderForeground(lipgloss.Color("170")).
|
||||
Padding(1, 2).
|
||||
Width(m.width - 4).
|
||||
Align(lipgloss.Center)
|
||||
|
||||
confirmText := fmt.Sprintf(
|
||||
"Are you sure you want to delete repository '%s'?\n\nThis action cannot be undone!\n\nPress y to confirm or n to cancel.",
|
||||
repo.Name(),
|
||||
)
|
||||
|
||||
return confirmStyle.Render(confirmText)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Start runs the TUI
|
||||
func Start(s ssh.Session, repoDir string) error {
|
||||
model, err := New(s, repoDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := tea.NewProgram(model, tea.WithAltScreen(), tea.WithMouseCellMotion(), tea.WithInput(s), tea.WithOutput(s))
|
||||
|
||||
_, err = p.Run()
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
pkgs ? import <nixpkgs> { },
|
||||
}:
|
||||
let
|
||||
pkg = pkgs.callPackage ./pkg.nix { inherit pkgs; };
|
||||
in
|
||||
{
|
||||
ugit = pkg;
|
||||
default = pkg;
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.ugit;
|
||||
pkg = pkgs.callPackage ./pkg.nix { inherit pkgs; };
|
||||
yamlFormat = pkgs.formats.yaml { };
|
||||
instanceOptions =
|
||||
{ name, config, ... }:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkOption types;
|
||||
baseDir = "/var/lib/ugit-${name}";
|
||||
in
|
||||
{
|
||||
options = {
|
||||
enable = mkEnableOption "Enable ugit";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
description = "ugit package to use";
|
||||
default = pkg;
|
||||
};
|
||||
|
||||
homeDir = mkOption {
|
||||
type = types.str;
|
||||
description = "ugit home directory";
|
||||
default = baseDir;
|
||||
};
|
||||
|
||||
repoDir = mkOption {
|
||||
type = types.str;
|
||||
description = "where ugit stores repositories";
|
||||
default = "${baseDir}/repos";
|
||||
};
|
||||
|
||||
authorizedKeys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "list of keys to use for authorized_keys";
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
authorizedKeysFile = mkOption {
|
||||
type = types.str;
|
||||
description = "path to authorized_keys file ugit uses for auth";
|
||||
default = "${baseDir}/authorized_keys";
|
||||
};
|
||||
|
||||
hostKeyFile = mkOption {
|
||||
type = types.str;
|
||||
description = "path to host key file (will be created if it doesn't exist)";
|
||||
default = "${baseDir}/ugit_ed25519";
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
type = types.attrs;
|
||||
default = { };
|
||||
description = "config.yaml contents";
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "ugit-${name}";
|
||||
description = "User account under which ugit runs";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "ugit-${name}";
|
||||
description = "Group account under which ugit runs";
|
||||
};
|
||||
|
||||
hooks = mkOption {
|
||||
type = types.listOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
description = "Hook name";
|
||||
};
|
||||
content = mkOption {
|
||||
type = types.str;
|
||||
description = "Hook contents";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
description = "A list of pre-receive hooks to run";
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.ugit = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule instanceOptions);
|
||||
default = { };
|
||||
description = "Attribute set of ugit instances";
|
||||
};
|
||||
};
|
||||
config = lib.mkIf (cfg != { }) {
|
||||
users.users = lib.mapAttrs' (
|
||||
name: instanceCfg:
|
||||
lib.nameValuePair instanceCfg.user {
|
||||
home = instanceCfg.homeDir;
|
||||
createHome = true;
|
||||
group = instanceCfg.group;
|
||||
isSystemUser = true;
|
||||
isNormalUser = false;
|
||||
description = "user for ugit ${name} service";
|
||||
}
|
||||
) (lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg);
|
||||
|
||||
users.groups = lib.mapAttrs' (name: instanceCfg: lib.nameValuePair instanceCfg.group { }) (
|
||||
lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg
|
||||
);
|
||||
|
||||
systemd.services = lib.foldl' (
|
||||
acc: name:
|
||||
let
|
||||
instanceCfg = cfg.${name};
|
||||
in
|
||||
lib.recursiveUpdate acc (
|
||||
lib.optionalAttrs instanceCfg.enable {
|
||||
"ugit-${name}" = {
|
||||
enable = true;
|
||||
description = "ugit instance ${name}";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
path = [
|
||||
instanceCfg.package
|
||||
pkgs.git
|
||||
pkgs.bash
|
||||
];
|
||||
serviceConfig = {
|
||||
User = instanceCfg.user;
|
||||
Group = instanceCfg.group;
|
||||
Restart = "always";
|
||||
RestartSec = "15";
|
||||
WorkingDirectory = instanceCfg.homeDir;
|
||||
ReadWritePaths = [ instanceCfg.homeDir ];
|
||||
CapabilityBoundingSet = "";
|
||||
NoNewPrivileges = true;
|
||||
ProtectSystem = "strict";
|
||||
ProtectHome = true;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
PrivateUsers = true;
|
||||
ProtectHostname = true;
|
||||
ProtectClock = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectControlGroups = true;
|
||||
RestrictAddressFamilies = [
|
||||
"AF_UNIX"
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
PrivateMounts = true;
|
||||
SystemCallArchitectures = "native";
|
||||
ExecStart =
|
||||
let
|
||||
configFile = pkgs.writeText "ugit-${name}.yaml" (
|
||||
builtins.readFile (yamlFormat.generate "ugit-${name}-yaml" instanceCfg.config)
|
||||
);
|
||||
authorizedKeysFile = pkgs.writeText "ugit_${name}_keys" (
|
||||
builtins.concatStringsSep "\n" instanceCfg.authorizedKeys
|
||||
);
|
||||
|
||||
authorizedKeysPath =
|
||||
if (builtins.length instanceCfg.authorizedKeys) > 0 then
|
||||
authorizedKeysFile
|
||||
else
|
||||
instanceCfg.authorizedKeysFile;
|
||||
args = [
|
||||
"--config=${configFile}"
|
||||
"--repo-dir=${instanceCfg.repoDir}"
|
||||
"--ssh.authorized-keys=${authorizedKeysPath}"
|
||||
"--ssh.host-key=${instanceCfg.hostKeyFile}"
|
||||
];
|
||||
in
|
||||
"${instanceCfg.package}/bin/ugitd ${builtins.concatStringsSep " " args}";
|
||||
};
|
||||
};
|
||||
|
||||
"ugit-${name}-hooks" = {
|
||||
description = "Setup hooks for ugit instance ${name}";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "ugit-${name}.service" ];
|
||||
requires = [ "ugit-${name}.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
User = instanceCfg.user;
|
||||
Group = instanceCfg.group;
|
||||
ExecStart =
|
||||
let
|
||||
hookDir = "${instanceCfg.repoDir}/hooks/pre-receive.d";
|
||||
mkHookScript =
|
||||
hook:
|
||||
let
|
||||
script = pkgs.writeShellScript "ugit-${name}-${hook.name}" hook.content;
|
||||
in
|
||||
''
|
||||
mkdir -p ${hookDir}
|
||||
ln -sf ${script} ${hookDir}/${hook.name}
|
||||
'';
|
||||
in
|
||||
pkgs.writeShellScript "ugit-${name}-hooks-setup" ''
|
||||
${builtins.concatStringsSep "\n" (map mkHookScript instanceCfg.hooks)}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
) { } (builtins.attrNames cfg);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
pkgs ? import <nixpkgs> { },
|
||||
}:
|
||||
let
|
||||
name = "ugitd";
|
||||
in
|
||||
pkgs.buildGoModule {
|
||||
pname = name;
|
||||
version = "main";
|
||||
src = pkgs.nix-gitignore.gitignoreSource [ ] (
|
||||
builtins.path {
|
||||
inherit name;
|
||||
path = ../.;
|
||||
}
|
||||
);
|
||||
subPackages = [
|
||||
"cmd/ugitd"
|
||||
];
|
||||
vendorHash = pkgs.lib.fileContents ../go.mod.sri;
|
||||
env.CGO_ENABLED = 0;
|
||||
flags = [ "-trimpath" ];
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
"-extldflags -static"
|
||||
];
|
||||
meta = {
|
||||
description = "Minimal git server";
|
||||
homepage = "https://git.jolheiser.com/ugit";
|
||||
mainProgram = "ugitd";
|
||||
};
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
{ pkgs, ... }:
|
||||
let
|
||||
privKey = ''
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACBIpmLtcHhECei1ls6s0kKUehjpRCP9yel/c5YCIb5DpQAAAIgAYtkzAGLZ
|
||||
MwAAAAtzc2gtZWQyNTUxOQAAACBIpmLtcHhECei1ls6s0kKUehjpRCP9yel/c5YCIb5DpQ
|
||||
AAAEDFY3M69VfnFbyE67r3l4lDcf5eht5qgNemE9xtMhRkBkimYu1weEQJ6LWWzqzSQpR6
|
||||
GOlEI/3J6X9zlgIhvkOlAAAAAAECAwQF
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
'';
|
||||
pubKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEimYu1weEQJ6LWWzqzSQpR6GOlEI/3J6X9zlgIhvkOl";
|
||||
sshConfig = ''
|
||||
Host ugit
|
||||
HostName localhost
|
||||
Port 8448
|
||||
User ugit
|
||||
IdentityFile ~/.ssh/vm
|
||||
IdentitiesOnly yes
|
||||
'';
|
||||
in
|
||||
{
|
||||
imports = [ ./module.nix ];
|
||||
environment.systemPackages = with pkgs; [ git ];
|
||||
services.getty.autologinUser = "root";
|
||||
services.openssh.enable = true;
|
||||
services.ugit.vm = {
|
||||
enable = true;
|
||||
authorizedKeys = [ pubKey ];
|
||||
hooks = [
|
||||
{
|
||||
name = "pre-receive";
|
||||
content = ''
|
||||
echo "Pre-receive hook executed"
|
||||
'';
|
||||
}
|
||||
];
|
||||
};
|
||||
systemd.services."setup-vm" = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "ugit-vm.service" ];
|
||||
path = with pkgs; [
|
||||
git
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
User = "root";
|
||||
Group = "root";
|
||||
ExecStart =
|
||||
let
|
||||
privSSH = pkgs.writeText "vm-privkey" privKey;
|
||||
sshConfigFile = pkgs.writeText "vm-sshconfig" sshConfig;
|
||||
in
|
||||
pkgs.writeShellScript "setup-vm-script" ''
|
||||
# Hack to let ugit start up and generate its SSH keypair
|
||||
sleep 3
|
||||
|
||||
# Set up git
|
||||
git config --global user.name "NixUser"
|
||||
git config --global user.email "nixuser@example.com"
|
||||
git config --global init.defaultBranch main
|
||||
git config --global push.autoSetupRemote true
|
||||
|
||||
# Set up SSH files
|
||||
mkdir ~/.ssh
|
||||
ln -sf ${sshConfigFile} ~/.ssh/config
|
||||
cp ${privSSH} ~/.ssh/vm
|
||||
chmod 600 ~/.ssh/vm
|
||||
echo "[localhost]:8448 $(cat /var/lib/ugit-vm/ugit_ed25519.pub)" > ~/.ssh/known_hosts
|
||||
|
||||
# Stage some git activity
|
||||
mkdir ~/repo
|
||||
cd ~/repo
|
||||
git init
|
||||
git remote add origin ugit:repo.git
|
||||
touch README.md
|
||||
git add README.md
|
||||
git commit -m "Test"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in New Issue