Refactor for ff, zerolog, and re-integrate SDK
Signed-off-by: jolheiser <john.olheiser@gmail.com>pull/14/head
parent
2d644e2711
commit
10b01b48e3
43
.drone.yml
43
.drone.yml
|
@ -1,43 +0,0 @@
|
|||
---
|
||||
kind: pipeline
|
||||
name: compliance
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
steps:
|
||||
- name: build
|
||||
pull: always
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- make test
|
||||
- make build
|
||||
- name: check
|
||||
pull: always
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- make vet
|
||||
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
name: release
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
branch:
|
||||
- main
|
||||
steps:
|
||||
- name: build
|
||||
pull: always
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- make build
|
||||
- name: gitea-release
|
||||
pull: always
|
||||
image: jolheiser/drone-gitea-main:latest
|
||||
settings:
|
||||
token:
|
||||
from_secret: gitea_token
|
||||
base: https://git.jojodev.com
|
||||
files:
|
||||
- "vanity"
|
|
@ -1,7 +1,5 @@
|
|||
# GoLand
|
||||
.idea
|
||||
.idea/
|
||||
|
||||
# Vanity
|
||||
/vanity
|
||||
/vanity.exe
|
||||
/vanity.db
|
||||
/vanity*
|
|
@ -0,0 +1,37 @@
|
|||
clone:
|
||||
git:
|
||||
image: woodpeckerci/plugin-git:next
|
||||
|
||||
pipeline:
|
||||
compliance:
|
||||
image: golang:1.17
|
||||
commands:
|
||||
- go test -race ./...
|
||||
- go run github.com/rs/zerolog/cmd/lint ./cmd/vanity-cli
|
||||
- go run github.com/rs/zerolog/cmd/lint ./cmd/vanity-server
|
||||
- go vet ./...
|
||||
when:
|
||||
event: pull_request
|
||||
|
||||
build:
|
||||
image: golang:1.17
|
||||
commands:
|
||||
- GOOS="linux" go build ./cmd/vanity-cli
|
||||
- GOOS="windows" go build ./cmd/vanity-cli
|
||||
- GOOS="linux" go build ./cmd/vanity-server
|
||||
- GOOS="windows" go build ./cmd/vanity-server
|
||||
|
||||
release-main:
|
||||
image: jolheiser/drone-gitea-main:latest
|
||||
settings:
|
||||
base: https://git.jojodev.com
|
||||
token:
|
||||
from_secret: gitea_token
|
||||
files:
|
||||
- "vanity-cli"
|
||||
- "vanity-cli.exe"
|
||||
- "vanity-server"
|
||||
- "vanity-server.exe"
|
||||
when:
|
||||
event: push
|
||||
branch: main
|
41
Makefile
41
Makefile
|
@ -1,41 +0,0 @@
|
|||
GO ?= go
|
||||
|
||||
VERSION ?= $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
$(GO) build -ldflags '-s -w -X "go.jolheiser.com/vanity/router.Version=$(VERSION)"'
|
||||
|
||||
.PHONY: fmt
|
||||
fmt: fmt-cli fmt-lib
|
||||
|
||||
.PHONY: test
|
||||
test: test-cli test-lib
|
||||
|
||||
.PHONY: fmt-cli
|
||||
fmt-cli:
|
||||
$(GO) fmt ./...
|
||||
|
||||
.PHONY: test-cli
|
||||
test-cli:
|
||||
$(GO) test -race ./...
|
||||
|
||||
.PHONY: fmt-lib
|
||||
fmt-lib:
|
||||
@cd go-vanity && $(GO) fmt ./...
|
||||
|
||||
.PHONY: test-lib
|
||||
test-lib:
|
||||
@cd go-vanity && $(GO) test -race ./...
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
$(GO) vet ./...
|
||||
|
||||
.PHONY: docker-build
|
||||
docker-build:
|
||||
docker build -f docker/Dockerfile -t jolheiser/vanity .
|
||||
|
||||
.PHONY: docker-push
|
||||
docker-push:
|
||||
docker push jolheiser/vanity
|
69
cmd/add.go
69
cmd/add.go
|
@ -1,69 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
|
||||
"go.jolheiser.com/vanity/cmd/flags"
|
||||
"go.jolheiser.com/vanity/database"
|
||||
"go.jolheiser.com/vanity/go-vanity"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.jolheiser.com/beaver"
|
||||
)
|
||||
|
||||
var Add = cli.Command{
|
||||
Name: "add",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "Add a package",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "force",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "Overwrite existing package without prompt",
|
||||
Destination: &flags.Force,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "local",
|
||||
Aliases: []string{"l"},
|
||||
Usage: "local mode",
|
||||
Destination: &flags.Local,
|
||||
},
|
||||
},
|
||||
Before: localOrToken,
|
||||
Action: doAdd,
|
||||
}
|
||||
|
||||
func doAdd(_ *cli.Context) error {
|
||||
pkg, err := pkgPrompt(vanity.Package{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if flags.Local {
|
||||
db, err := database.Load(flags.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := db.PutPackage(pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
client := vanity.New(flags.Token, vanity.WithServer(flags.Server))
|
||||
if err := client.Add(context.Background(), pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
beaver.Infof("Added %s", yellow.Format(pkg.Name))
|
||||
return nil
|
||||
}
|
||||
|
||||
func validURL(ans interface{}) error {
|
||||
if err := survey.Required(ans); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := url.Parse(ans.(string))
|
||||
return err
|
||||
}
|
181
cmd/cmd.go
181
cmd/cmd.go
|
@ -1,181 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"go.jolheiser.com/vanity/cmd/flags"
|
||||
"go.jolheiser.com/vanity/contrib"
|
||||
"go.jolheiser.com/vanity/database"
|
||||
"go.jolheiser.com/vanity/go-vanity"
|
||||
"go.jolheiser.com/vanity/router"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.jolheiser.com/beaver/color"
|
||||
)
|
||||
|
||||
var yellow = color.FgYellow
|
||||
|
||||
func New() *cli.App {
|
||||
app := cli.NewApp()
|
||||
app.Name = "vanity"
|
||||
app.Usage = "Vanity Import URLs"
|
||||
app.Version = router.Version
|
||||
app.Commands = []*cli.Command{
|
||||
&Add,
|
||||
&Remove,
|
||||
&Server,
|
||||
&Update,
|
||||
}
|
||||
app.Flags = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "server",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "vanity server to use",
|
||||
Value: vanity.DefaultServer,
|
||||
EnvVars: []string{"VANITY_SERVER"},
|
||||
Destination: &flags.Server,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "token",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "vanity auth token to use",
|
||||
DefaultText: "${VANITY_TOKEN}",
|
||||
EnvVars: []string{"VANITY_TOKEN"},
|
||||
Destination: &flags.Token,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "database",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "path to vanity database for server",
|
||||
Value: dbPath(),
|
||||
DefaultText: "`${HOME}/vanity.db` or `${BINPATH}/vanity.db`",
|
||||
EnvVars: []string{"VANITY_DATABASE"},
|
||||
Destination: &flags.Database,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "systemd-service",
|
||||
Usage: "Output example systemd service",
|
||||
Destination: &flags.SystemdService,
|
||||
Hidden: true,
|
||||
},
|
||||
}
|
||||
app.Action = action
|
||||
return app
|
||||
}
|
||||
|
||||
func action(ctx *cli.Context) error {
|
||||
if flags.SystemdService {
|
||||
fmt.Println(contrib.SystemdService)
|
||||
return nil
|
||||
}
|
||||
return cli.ShowAppHelp(ctx)
|
||||
}
|
||||
|
||||
func dbPath() string {
|
||||
fn := "vanity.db"
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
bin, err := os.Executable()
|
||||
if err != nil {
|
||||
return fn
|
||||
}
|
||||
return filepath.Join(filepath.Dir(bin), fn)
|
||||
}
|
||||
return filepath.Join(home, fn)
|
||||
}
|
||||
|
||||
func localOrToken(_ *cli.Context) error {
|
||||
if flags.Local && flags.Token == "" {
|
||||
return errors.New("server interaction requires --token")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func listPackages() ([]vanity.Package, error) {
|
||||
var pkgs []vanity.Package
|
||||
if flags.Local {
|
||||
db, err := database.Load(flags.Database)
|
||||
if err != nil {
|
||||
return pkgs, err
|
||||
}
|
||||
pkgs, err = db.Packages()
|
||||
if err != nil {
|
||||
return pkgs, err
|
||||
}
|
||||
} else {
|
||||
client := vanity.New(flags.Token, vanity.WithServer(flags.Server))
|
||||
info, err := client.Info(context.Background())
|
||||
if err != nil {
|
||||
return pkgs, err
|
||||
}
|
||||
pkgs = info.Packages
|
||||
}
|
||||
return pkgs, nil
|
||||
}
|
||||
|
||||
func pkgPrompt(def vanity.Package) (vanity.Package, error) {
|
||||
if def.Branch == "" {
|
||||
def.Branch = "main"
|
||||
}
|
||||
var pkg vanity.Package
|
||||
questions := []*survey.Question{
|
||||
{
|
||||
Name: "name",
|
||||
Prompt: &survey.Input{Message: "Name", Default: def.Name},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "description",
|
||||
Prompt: &survey.Multiline{Message: "Description", Default: def.Description},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "branch",
|
||||
Prompt: &survey.Input{Message: "Branch", Default: def.Branch},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "weburl",
|
||||
Prompt: &survey.Input{Message: "Web URL", Default: def.WebURL},
|
||||
Validate: validURL,
|
||||
},
|
||||
}
|
||||
if err := survey.Ask(questions, &pkg); err != nil {
|
||||
return pkg, err
|
||||
}
|
||||
|
||||
defHTTP, defSSH := def.CloneHTTP, def.CloneSSH
|
||||
if def.WebURL != pkg.WebURL {
|
||||
u, err := url.Parse(pkg.WebURL)
|
||||
if err != nil {
|
||||
return pkg, err
|
||||
}
|
||||
defHTTP = pkg.WebURL + ".git"
|
||||
defSSH = fmt.Sprintf("git@%s:%s.git", u.Host, strings.TrimPrefix(u.Path, "/"))
|
||||
}
|
||||
|
||||
questions = []*survey.Question{
|
||||
{
|
||||
Name: "clonehttp",
|
||||
Prompt: &survey.Input{Message: "HTTP(S) CLone URL", Default: defHTTP},
|
||||
Validate: validURL,
|
||||
},
|
||||
{
|
||||
Name: "clonessh",
|
||||
Prompt: &survey.Input{Message: "SSH CLone URL", Default: defSSH},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
}
|
||||
if err := survey.Ask(questions, &pkg); err != nil {
|
||||
return pkg, err
|
||||
}
|
||||
|
||||
return pkg, nil
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package flags
|
||||
|
||||
var (
|
||||
Server string
|
||||
Domain string
|
||||
Token string
|
||||
Database string
|
||||
|
||||
Local bool
|
||||
Force bool
|
||||
Port int
|
||||
|
||||
SystemdService bool
|
||||
)
|
|
@ -1,67 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.jolheiser.com/vanity/cmd/flags"
|
||||
"go.jolheiser.com/vanity/database"
|
||||
"go.jolheiser.com/vanity/go-vanity"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.jolheiser.com/beaver"
|
||||
)
|
||||
|
||||
var Remove = cli.Command{
|
||||
Name: "remove",
|
||||
Aliases: []string{"rm"},
|
||||
Usage: "Remove package(s)",
|
||||
Before: localOrToken,
|
||||
Action: doRemove,
|
||||
}
|
||||
|
||||
func doRemove(_ *cli.Context) error {
|
||||
pkgs, err := listPackages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkgSlice := make([]string, len(pkgs))
|
||||
pkgMap := make(map[string]vanity.Package)
|
||||
for idx, pkg := range pkgs {
|
||||
pkgSlice[idx] = pkg.Name
|
||||
pkgMap[pkg.Name] = pkg
|
||||
}
|
||||
|
||||
pkgQuestion := &survey.Select{
|
||||
Message: "Select package to remove",
|
||||
Options: pkgSlice,
|
||||
}
|
||||
|
||||
var pkgName string
|
||||
if err := survey.AskOne(pkgQuestion, &pkgName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkg := vanity.Package{
|
||||
Name: pkgName,
|
||||
}
|
||||
|
||||
if flags.Local {
|
||||
db, err := database.Load(flags.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := db.RemovePackage(pkg.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
client := vanity.New(flags.Token, vanity.WithServer(flags.Server))
|
||||
if err := client.Remove(context.Background(), pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
beaver.Infof("Removed %s", yellow.Format(pkgName))
|
||||
return nil
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"go.jolheiser.com/vanity/cmd/flags"
|
||||
"go.jolheiser.com/vanity/database"
|
||||
"go.jolheiser.com/vanity/router"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.jolheiser.com/beaver"
|
||||
)
|
||||
|
||||
var Server = cli.Command{
|
||||
Name: "server",
|
||||
Aliases: []string{"web"},
|
||||
Usage: "Start the vanity server",
|
||||
Flags: []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "port",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Port to run the vanity server on",
|
||||
Value: 3333,
|
||||
EnvVars: []string{"VANITY_PORT"},
|
||||
Destination: &flags.Port,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "domain",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "The Go module domain (e.g. go.jolheiser.com)",
|
||||
EnvVars: []string{"VANITY_DOMAIN"},
|
||||
Destination: &flags.Domain,
|
||||
},
|
||||
},
|
||||
Action: doServer,
|
||||
}
|
||||
|
||||
func doServer(_ *cli.Context) error {
|
||||
if flags.Token == "" || flags.Domain == "" {
|
||||
return errors.New("vanity server requires --token and --domain")
|
||||
}
|
||||
|
||||
db, err := database.Load(flags.Database)
|
||||
if err != nil {
|
||||
beaver.Fatalf("could not load database at %s: %v", flags.Database, err)
|
||||
}
|
||||
|
||||
beaver.Infof("Running vanity server at http://localhost:%d", flags.Port)
|
||||
if err := http.ListenAndServe(fmt.Sprintf(":%d", flags.Port), router.New(flags.Token, db)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.jolheiser.com/vanity/cmd/flags"
|
||||
"go.jolheiser.com/vanity/database"
|
||||
"go.jolheiser.com/vanity/go-vanity"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go.jolheiser.com/beaver"
|
||||
)
|
||||
|
||||
var Update = cli.Command{
|
||||
Name: "update",
|
||||
Aliases: []string{"u"},
|
||||
Usage: "Update a package",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "local",
|
||||
Aliases: []string{"l"},
|
||||
Usage: "local mode",
|
||||
Destination: &flags.Local,
|
||||
},
|
||||
},
|
||||
Before: localOrToken,
|
||||
Action: doUpdate,
|
||||
}
|
||||
|
||||
func doUpdate(_ *cli.Context) error {
|
||||
pkgs, err := listPackages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkgSlice := make([]string, len(pkgs))
|
||||
pkgMap := make(map[string]vanity.Package)
|
||||
for idx, pkg := range pkgs {
|
||||
pkgSlice[idx] = pkg.Name
|
||||
pkgMap[pkg.Name] = pkg
|
||||
}
|
||||
|
||||
pkgQuestion := &survey.Select{
|
||||
Message: "Select package to update",
|
||||
Options: pkgSlice,
|
||||
}
|
||||
|
||||
var pkgName string
|
||||
if err := survey.AskOne(pkgQuestion, &pkgName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkg, err := pkgPrompt(pkgMap[pkgName])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if flags.Local {
|
||||
db, err := database.Load(flags.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := db.PutPackage(pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
client := vanity.New(flags.Token, vanity.WithServer(flags.Server))
|
||||
if err := client.Update(context.Background(), pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
beaver.Infof("Updated %s", yellow.Format(pkgName))
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
|
||||
"go.jolheiser.com/vanity/sdk"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func add(token, server *string) func(context.Context, []string) error {
|
||||
return func(ctx context.Context, args []string) error {
|
||||
pkg, err := pkgPrompt(sdk.Package{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := sdk.New(*token, sdk.WithServer(*server))
|
||||
if err := client.Add(context.Background(), pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msgf("Added %q", pkg.Name)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func validURL(ans interface{}) error {
|
||||
if err := survey.Required(ans); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := url.Parse(ans.(string))
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"go.jolheiser.com/vanity/sdk"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/peterbourgon/ff/v3"
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"github.com/peterbourgon/ff/v3/fftoml"
|
||||
)
|
||||
|
||||
func New() *ffcli.Command {
|
||||
fs := flag.NewFlagSet("vanity", flag.ExitOnError)
|
||||
serverFlag := fs.String("server", sdk.DefaultServer, "vanity server to use")
|
||||
tokenFlag := fs.String("token", "", "vanity auth token to use")
|
||||
|
||||
cmd := &ffcli.Command{
|
||||
Name: "vanity",
|
||||
ShortUsage: "vanity [add|update|remove]",
|
||||
ShortHelp: "Vanity CLI",
|
||||
LongHelp: "Vanity CLI to work with a remote Vanity server",
|
||||
FlagSet: fs,
|
||||
Options: []ff.Option{
|
||||
ff.WithEnvVarPrefix("VANITY"),
|
||||
ff.WithAllowMissingConfigFile(true),
|
||||
ff.WithConfigFileFlag("config"),
|
||||
ff.WithConfigFileParser(fftoml.New().Parse),
|
||||
},
|
||||
Subcommands: []*ffcli.Command{
|
||||
{
|
||||
Name: "add",
|
||||
ShortHelp: "add package",
|
||||
LongHelp: "add a package to the vanity server",
|
||||
Exec: add(tokenFlag, serverFlag),
|
||||
},
|
||||
{
|
||||
Name: "remove",
|
||||
ShortHelp: "remove package",
|
||||
LongHelp: "remove a package from the vanity server",
|
||||
Exec: remove(tokenFlag, serverFlag),
|
||||
},
|
||||
{
|
||||
Name: "update",
|
||||
ShortHelp: "update package",
|
||||
LongHelp: "update a package on the vanity server",
|
||||
Exec: update(tokenFlag, serverFlag),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func listPackages(token, server string) ([]sdk.Package, error) {
|
||||
client := sdk.New(token, sdk.WithServer(server))
|
||||
info, err := client.Info(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return info.Packages, nil
|
||||
}
|
||||
|
||||
func pkgPrompt(def sdk.Package) (sdk.Package, error) {
|
||||
if def.Branch == "" {
|
||||
def.Branch = "main"
|
||||
}
|
||||
var pkg sdk.Package
|
||||
questions := []*survey.Question{
|
||||
{
|
||||
Name: "name",
|
||||
Prompt: &survey.Input{Message: "Name", Default: def.Name},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "description",
|
||||
Prompt: &survey.Multiline{Message: "Description", Default: def.Description},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "branch",
|
||||
Prompt: &survey.Input{Message: "Branch", Default: def.Branch},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
{
|
||||
Name: "weburl",
|
||||
Prompt: &survey.Input{Message: "Web URL", Default: def.WebURL},
|
||||
Validate: validURL,
|
||||
},
|
||||
}
|
||||
if err := survey.Ask(questions, &pkg); err != nil {
|
||||
return pkg, err
|
||||
}
|
||||
|
||||
defHTTP, defSSH := def.CloneHTTP, def.CloneSSH
|
||||
if def.WebURL != pkg.WebURL {
|
||||
u, err := url.Parse(pkg.WebURL)
|
||||
if err != nil {
|
||||
return pkg, err
|
||||
}
|
||||
defHTTP = pkg.WebURL + ".git"
|
||||
defSSH = fmt.Sprintf("git@%s:%s.git", u.Host, strings.TrimPrefix(u.Path, "/"))
|
||||
}
|
||||
|
||||
questions = []*survey.Question{
|
||||
{
|
||||
Name: "clonehttp",
|
||||
Prompt: &survey.Input{Message: "HTTP(S) CLone URL", Default: defHTTP},
|
||||
Validate: validURL,
|
||||
},
|
||||
{
|
||||
Name: "clonessh",
|
||||
Prompt: &survey.Input{Message: "SSH CLone URL", Default: defSSH},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
}
|
||||
if err := survey.Ask(questions, &pkg); err != nil {
|
||||
return pkg, err
|
||||
}
|
||||
|
||||
return pkg, nil
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
cmd := New()
|
||||
if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.jolheiser.com/vanity/sdk"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func remove(token, server *string) func(context.Context, []string) error {
|
||||
return func(ctx context.Context, args []string) error {
|
||||
pkgs, err := listPackages(*token, *server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkgSlice := make([]string, len(pkgs))
|
||||
pkgMap := make(map[string]sdk.Package)
|
||||
for idx, pkg := range pkgs {
|
||||
pkgSlice[idx] = pkg.Name
|
||||
pkgMap[pkg.Name] = pkg
|
||||
}
|
||||
|
||||
pkgQuestion := &survey.Select{
|
||||
Message: "Select package to remove",
|
||||
Options: pkgSlice,
|
||||
}
|
||||
|
||||
var pkgName string
|
||||
if err := survey.AskOne(pkgQuestion, &pkgName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkg := sdk.Package{
|
||||
Name: pkgName,
|
||||
}
|
||||
|
||||
client := sdk.New(*token, sdk.WithServer(*server))
|
||||
if err := client.Remove(context.Background(), pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msgf("Removed %q", pkgName)
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.jolheiser.com/vanity/sdk"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func update(token, server *string) func(context.Context, []string) error {
|
||||
return func(ctx context.Context, args []string) error {
|
||||
pkgs, err := listPackages(*token, *server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkgSlice := make([]string, len(pkgs))
|
||||
pkgMap := make(map[string]sdk.Package)
|
||||
for idx, pkg := range pkgs {
|
||||
pkgSlice[idx] = pkg.Name
|
||||
pkgMap[pkg.Name] = pkg
|
||||
}
|
||||
|
||||
pkgQuestion := &survey.Select{
|
||||
Message: "Select package to update",
|
||||
Options: pkgSlice,
|
||||
}
|
||||
|
||||
var pkgName string
|
||||
if err := survey.AskOne(pkgQuestion, &pkgName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkg, err := pkgPrompt(pkgMap[pkgName])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := sdk.New(*token, sdk.WithServer(*server))
|
||||
if err := client.Update(context.Background(), pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().Msgf("Updated %q", pkgName)
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
cmd := New()
|
||||
if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"go.jolheiser.com/vanity/server/database"
|
||||
"go.jolheiser.com/vanity/server/router"
|
||||
|
||||
"github.com/peterbourgon/ff/v3"
|
||||
"github.com/peterbourgon/ff/v3/ffcli"
|
||||
"github.com/peterbourgon/ff/v3/fftoml"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func New() *ffcli.Command {
|
||||
fs := flag.NewFlagSet("vanity", flag.ExitOnError)
|
||||
portFlag := fs.Int("port", 3333, "Port to run the vanity server on")
|
||||
domainFlag := fs.String("domain", "", "The Go module domain (e.g. go.jolheiser.com)")
|
||||
tokenFlag := fs.String("token", "", "vanity auth token to use")
|
||||
dbFlag := fs.String("database", dbPath(), "The path to the database")
|
||||
|
||||
cmd := &ffcli.Command{
|
||||
Name: "vanity",
|
||||
ShortUsage: "vanity",
|
||||
ShortHelp: "Vanity Server",
|
||||
LongHelp: "Vanity Server to serve the Go module vanity domain",
|
||||
FlagSet: fs,
|
||||
Options: []ff.Option{
|
||||
ff.WithEnvVarPrefix("VANITY"),
|
||||
ff.WithAllowMissingConfigFile(true),
|
||||
ff.WithConfigFileFlag("config"),
|
||||
ff.WithConfigFileParser(fftoml.New().Parse),
|
||||
},
|
||||
Exec: server(portFlag, domainFlag, tokenFlag, dbFlag),
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func server(port *int, domain, token, dbPath *string) func(context.Context, []string) error {
|
||||
return func(ctx context.Context, args []string) error {
|
||||
if *token == "" || *domain == "" {
|
||||
return errors.New("vanity server requires --token and --domain")
|
||||
}
|
||||
|
||||
db, err := database.Load(*dbPath)
|
||||
if err != nil {
|
||||
log.Fatal().Msgf("could not load database at %s: %v", *dbPath, err)
|
||||
}
|
||||
|
||||
log.Info().Msgf("Running vanity server at http://localhost:%d", *port)
|
||||
if err := http.ListenAndServe(fmt.Sprintf(":%d", *port), router.New(*token, *domain, db)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func dbPath() string {
|
||||
fn := "vanity.db"
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
bin, err := os.Executable()
|
||||
if err != nil {
|
||||
return fn
|
||||
}
|
||||
return filepath.Join(filepath.Dir(bin), fn)
|
||||
}
|
||||
return filepath.Join(home, fn)
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package contrib
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed vanity.service
|
||||
var SystemdService string
|
||||
|
||||
func init() {
|
||||
bin, err := os.Executable()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
SystemdService = os.Expand(SystemdService, func(s string) string {
|
||||
switch strings.ToUpper(s) {
|
||||
case "BIN":
|
||||
return bin
|
||||
case "VANITY_TOKEN":
|
||||
return os.Getenv("VANITY_TOKEN")
|
||||
case "VANITY_DOMAIN":
|
||||
return os.Getenv("VANITY_DOMAIN")
|
||||
}
|
||||
return ""
|
||||
})
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
module go.jolheiser.com/vanity/go-vanity
|
||||
|
||||
go 1.16
|
11
go.mod
11
go.mod
|
@ -2,18 +2,11 @@ module go.jolheiser.com/vanity
|
|||
|
||||
go 1.16
|
||||
|
||||
replace go.jolheiser.com/vanity/go-vanity => ./go-vanity
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.2.8
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.3
|
||||
github.com/urfave/cli/v2 v2.2.0
|
||||
github.com/peterbourgon/ff/v3 v3.1.2
|
||||
github.com/rs/zerolog v1.26.1
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
go.jolheiser.com/beaver v1.0.2
|
||||
go.jolheiser.com/overlay v0.0.3
|
||||
go.jolheiser.com/vanity/go-vanity v0.0.0-00010101000000-000000000000
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
|
||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect
|
||||
golang.org/x/text v0.3.3 // indirect
|
||||
)
|
||||
|
|
57
go.sum
57
go.sum
|
@ -1,15 +1,15 @@
|
|||
github.com/AlecAivazis/survey/v2 v2.2.8 h1:TgxCwybKdBckmC+/P9/5h49rw/nAHe/itZL0dgHs+Q0=
|
||||
github.com/AlecAivazis/survey/v2 v2.2.8/go.mod h1:9DYvHgXtiXm6nCn+jXnOXLKbH+Yo9u8fAS/SduGdoPk=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-chi/chi/v5 v5.0.3 h1:khYQBdPivkYG1s1TAzDQG1f6eX4kD2TItYVZexL5rS4=
|
||||
github.com/go-chi/chi/v5 v5.0.3/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
|
@ -22,38 +22,59 @@ github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE
|
|||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
|
||||
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
|
||||
github.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM=
|
||||
github.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
|
||||
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
|
||||
github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
|
||||
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.jolheiser.com/beaver v1.0.2 h1:KA2D6iO8MQhZi1nZYi/Chak/f1Cxfrs6b1XO623+Khk=
|
||||
go.jolheiser.com/beaver v1.0.2/go.mod h1:7X4F5+XOGSC3LejTShoBdqtRCnPWcnRgmYGmG3EKW8g=
|
||||
go.jolheiser.com/overlay v0.0.3 h1:5WoXtnRi1w5KkU9xq+si/wV0GINOMJphfSOvgG2l53I=
|
||||
go.jolheiser.com/overlay v0.0.3/go.mod h1:xNbssakJ3HjK4RnjuP38q9yQNS4wxXKsyprYIWWr2bg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e h1:1SzTfNOXwIS2oWiMF+6qu0OUDKb0dauo6MoDUQyu+yU=
|
||||
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
|
||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
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.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
24
main.go
24
main.go
|
@ -1,24 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"go.jolheiser.com/vanity/cmd"
|
||||
|
||||
"go.jolheiser.com/beaver"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
beaver.Console.Format = beaver.FormatOptions{
|
||||
TimePrefix: true,
|
||||
StackPrefix: true,
|
||||
StackLimit: 15,
|
||||
LevelPrefix: true,
|
||||
LevelColor: true,
|
||||
}
|
||||
|
||||
if err := cmd.New().Run(os.Args); err != nil {
|
||||
beaver.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package vanity
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"context"
|
|
@ -1,4 +1,4 @@
|
|||
package vanity
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"bytes"
|
|
@ -1,4 +1,4 @@
|
|||
package vanity
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"errors"
|
|
@ -1,4 +1,4 @@
|
|||
package vanity
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"context"
|
|
@ -6,7 +6,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"go.jolheiser.com/vanity/go-vanity"
|
||||
"go.jolheiser.com/vanity/sdk"
|
||||
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
@ -33,8 +33,8 @@ func Load(dbPath string) (*Database, error) {
|
|||
})
|
||||
}
|
||||
|
||||
func (d *Database) Package(name string) (vanity.Package, error) {
|
||||
var pkg vanity.Package
|
||||
func (d *Database) Package(name string) (sdk.Package, error) {
|
||||
var pkg sdk.Package
|
||||
data, err := d.PackageJSON(name)
|
||||
if err != nil {
|
||||
return pkg, err
|
||||
|
@ -54,10 +54,10 @@ func (d *Database) PackageJSON(name string) (pkg []byte, err error) {
|
|||
})
|
||||
}
|
||||
|
||||
func (d *Database) Packages() (pkgs []vanity.Package, err error) {
|
||||
func (d *Database) Packages() (pkgs []sdk.Package, err error) {
|
||||
return pkgs, d.db.View(func(tx *bbolt.Tx) error {
|
||||
return tx.Bucket(packageBucket).ForEach(func(key, val []byte) error {
|
||||
var pkg vanity.Package
|
||||
var pkg sdk.Package
|
||||
if err := json.NewDecoder(bytes.NewReader(val)).Decode(&pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ func (d *Database) Packages() (pkgs []vanity.Package, err error) {
|
|||
})
|
||||
}
|
||||
|
||||
func (d *Database) PutPackage(pkg vanity.Package) error {
|
||||
func (d *Database) PutPackage(pkg sdk.Package) error {
|
||||
return d.db.Update(func(tx *bbolt.Tx) error {
|
||||
data, err := json.Marshal(pkg)
|
||||
if err != nil {
|
|
@ -8,56 +8,55 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"go.jolheiser.com/vanity/cmd/flags"
|
||||
"go.jolheiser.com/vanity/database"
|
||||
"go.jolheiser.com/vanity/go-vanity"
|
||||
"go.jolheiser.com/vanity/sdk"
|
||||
"go.jolheiser.com/vanity/server/database"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"go.jolheiser.com/beaver"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func New(token string, db *database.Database) *chi.Mux {
|
||||
func New(token, domain string, db *database.Database) *chi.Mux {
|
||||
r := chi.NewRouter()
|
||||
r.Use(middleware.Recoverer)
|
||||
r.Use(middleware.Timeout(60 * time.Second))
|
||||
|
||||
r.Mount("/_/", http.StripPrefix("/_/", static()))
|
||||
|
||||
r.Get("/", indexGET(db))
|
||||
r.Get("/", indexGET(domain, db))
|
||||
r.Options("/", infoPackages(db))
|
||||
r.Post("/", addUpdatePackage(db, token))
|
||||
r.Patch("/", addUpdatePackage(db, token))
|
||||
r.Delete("/", removePackage(db, token))
|
||||
r.Get("/*", vanityGET(db))
|
||||
r.Get("/*", vanityGET(domain, db))
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func indexGET(db *database.Database) http.HandlerFunc {
|
||||
func indexGET(domain string, db *database.Database) http.HandlerFunc {
|
||||
return func(res http.ResponseWriter, req *http.Request) {
|
||||
packages, err := db.Packages()
|
||||
if err != nil {
|
||||
beaver.Errorf("could not load packages: %v", err)
|
||||
log.Error().Msgf("could not load packages: %v", err)
|
||||
http.Error(res, "could not load packages", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
tpl, err := tmpl("index.tmpl")
|
||||
tpl, err := tmpl(domain, "index.tmpl")
|
||||
if err != nil {
|
||||
beaver.Warnf("could not load index template: %v", err)
|
||||
log.Warn().Msgf("could not load index template: %v", err)
|
||||
}
|
||||
|
||||
if err := tpl.Execute(res, map[string]interface{}{
|
||||
"Packages": packages,
|
||||
"Index": true,
|
||||
}); err != nil {
|
||||
beaver.Errorf("could not write response: %v", err)
|
||||
log.Error().Msgf("could not write response: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func vanityGET(db *database.Database) http.HandlerFunc {
|
||||
func vanityGET(domain string, db *database.Database) http.HandlerFunc {
|
||||
return func(res http.ResponseWriter, req *http.Request) {
|
||||
key := chi.URLParam(req, "*")
|
||||
key = strings.Split(key, "/")[0]
|
||||
|
@ -72,36 +71,36 @@ func vanityGET(db *database.Database) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
sdf, err := vanity.AnalyzeSDF(pkg)
|
||||
sdf, err := sdk.AnalyzeSDF(pkg)
|
||||
if err != nil {
|
||||
beaver.Warnf("could not get SDF for %s: %v", key, err)
|
||||
log.Warn().Msgf("could not get SDF for %s: %v", key, err)
|
||||
}
|
||||
|
||||
ctx := map[string]interface{}{
|
||||
"Package": pkg,
|
||||
"Module": pkg.Module(flags.Domain),
|
||||
"GoSource": fmt.Sprintf("%s %s %s %s", pkg.Module(flags.Domain), pkg.CloneHTTP, sdf.Dir, sdf.File),
|
||||
"Module": pkg.Module(domain),
|
||||
"GoSource": fmt.Sprintf("%s %s %s %s", pkg.Module(domain), pkg.CloneHTTP, sdf.Dir, sdf.File),
|
||||
"Index": false,
|
||||
}
|
||||
|
||||
q := req.URL.Query()
|
||||
if q.Get("go-get") != "" || q.Get("git-import") != "" {
|
||||
tpl, err := tmpl("import.tmpl")
|
||||
tpl, err := tmpl(domain, "import.tmpl")
|
||||
if err != nil {
|
||||
beaver.Warnf("could not load import template: %v", err)
|
||||
log.Warn().Msgf("could not load import template: %v", err)
|
||||
}
|
||||
if err := tpl.Execute(res, ctx); err != nil {
|
||||
beaver.Errorf("could not write response: %v", err)
|
||||
log.Error().Msgf("could not write response: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
tpl, err := tmpl("vanity.tmpl")
|
||||
tpl, err := tmpl(domain, "vanity.tmpl")
|
||||
if err != nil {
|
||||
beaver.Warnf("could not load vanity template: %v", err)
|
||||
log.Warn().Msgf("could not load vanity template: %v", err)
|
||||
}
|
||||
if err := tpl.Execute(res, ctx); err != nil {
|
||||
beaver.Errorf("could not write response: %v", err)
|
||||
log.Error().Msgf("could not write response: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +113,7 @@ func infoPackages(db *database.Database) func(http.ResponseWriter, *http.Request
|
|||
return
|
||||
}
|
||||
|
||||
info := vanity.Info{
|
||||
info := sdk.Info{
|
||||
Version: Version,
|
||||
NumPackages: len(packages),
|
||||
Packages: packages,
|
||||
|
@ -128,7 +127,7 @@ func infoPackages(db *database.Database) func(http.ResponseWriter, *http.Request
|
|||
|
||||
func addUpdatePackage(db *database.Database, token string) func(http.ResponseWriter, *http.Request) {
|
||||
return func(res http.ResponseWriter, req *http.Request) {
|
||||
if req.Header.Get(vanity.TokenHeader) != token {
|
||||
if req.Header.Get(sdk.TokenHeader) != token {
|
||||
res.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
@ -140,7 +139,7 @@ func addUpdatePackage(db *database.Database, token string) func(http.ResponseWri
|
|||
}
|
||||
defer req.Body.Close()
|
||||
|
||||
var pkg vanity.Package
|
||||
var pkg sdk.Package
|
||||
if err := json.Unmarshal(data, &pkg); err != nil {
|
||||
res.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
|
@ -181,7 +180,7 @@ func addUpdatePackage(db *database.Database, token string) func(http.ResponseWri
|
|||
|
||||
func removePackage(db *database.Database, token string) func(http.ResponseWriter, *http.Request) {
|
||||
return func(res http.ResponseWriter, req *http.Request) {
|
||||
if req.Header.Get(vanity.TokenHeader) != token {
|
||||
if req.Header.Get(sdk.TokenHeader) != token {
|
||||
res.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
@ -193,7 +192,7 @@ func removePackage(db *database.Database, token string) func(http.ResponseWriter
|
|||
}
|
||||
defer req.Body.Close()
|
||||
|
||||
var pkg vanity.Package
|
||||
var pkg sdk.Package
|
||||
if err := json.Unmarshal(data, &pkg); err != nil {
|
||||
res.WriteHeader(http.StatusBadRequest)
|
||||
return
|
|
@ -9,10 +9,10 @@ import (
|
|||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"go.jolheiser.com/vanity/database"
|
||||
"go.jolheiser.com/vanity/go-vanity"
|
||||
"go.jolheiser.com/vanity/sdk"
|
||||
"go.jolheiser.com/vanity/server/database"
|
||||
|
||||
"go.jolheiser.com/beaver"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -31,10 +31,10 @@ func TestMain(m *testing.M) {
|
|||
|
||||
db, err := database.Load(dbPath)
|
||||
if err != nil {
|
||||
beaver.Fatalf("could not load database at %s: %v", dbPath, err)
|
||||
log.Fatal().Msgf("could not load database at %s: %v", dbPath, err)
|
||||
}
|
||||
|
||||
server = httptest.NewServer(New(token, db))
|
||||
server = httptest.NewServer(New(token, "", db))
|
||||
|
||||
code := m.Run()
|
||||
|
||||
|
@ -48,12 +48,12 @@ func TestMain(m *testing.M) {
|
|||
|
||||
func TestRouter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := vanity.New("", vanity.WithServer(server.URL))
|
||||
client := sdk.New("", sdk.WithServer(server.URL))
|
||||
|
||||
// Info
|
||||
checkInfo(t, client, 0)
|
||||
|
||||
pkg1 := vanity.Package{
|
||||
pkg1 := sdk.Package{
|
||||
Name: "test1",
|
||||
Description: "test1",
|
||||
Branch: "main",
|
||||
|
@ -61,7 +61,7 @@ func TestRouter(t *testing.T) {
|
|||
CloneHTTP: "https://gitea.com/jolheiser/test1.git",
|
||||
CloneSSH: "https://gitea.com/jolheiser/test1",
|
||||
}
|
||||
pkg2 := vanity.Package{
|
||||
pkg2 := sdk.Package{
|
||||
Name: "test2",
|
||||
Description: "test2",
|
||||
Branch: "main",
|
||||
|
@ -77,7 +77,7 @@ func TestRouter(t *testing.T) {
|
|||
}
|
||||
|
||||
// Add (with token)
|
||||
client = vanity.New(token, vanity.WithServer(server.URL))
|
||||
client = sdk.New(token, sdk.WithServer(server.URL))
|
||||
checkAdd(t, client, pkg1, pkg2)
|
||||
|
||||
// Info (after second package)
|
||||
|
@ -102,7 +102,7 @@ func TestRouter(t *testing.T) {
|
|||
checkInfo(t, client, 1)
|
||||
}
|
||||
|
||||
func checkInfo(t *testing.T, client *vanity.Client, numPackages int) {
|
||||
func checkInfo(t *testing.T, client *sdk.Client, numPackages int) {
|
||||
info, err := client.Info(context.Background())
|
||||
if err != nil {
|
||||
t.Logf("info should not return error: %v\n", err)
|
||||
|
@ -114,7 +114,7 @@ func checkInfo(t *testing.T, client *vanity.Client, numPackages int) {
|
|||
}
|
||||
}
|
||||
|
||||
func checkAdd(t *testing.T, client *vanity.Client, pkg1, pkg2 vanity.Package) {
|
||||
func checkAdd(t *testing.T, client *sdk.Client, pkg1, pkg2 sdk.Package) {
|
||||
ctx := context.Background()
|
||||
if err := client.Add(ctx, pkg1); err != nil {
|
||||
t.Logf("pkg1 should be added: %v\n", err)
|
||||
|
@ -131,10 +131,10 @@ func checkAdd(t *testing.T, client *vanity.Client, pkg1, pkg2 vanity.Package) {
|
|||
}
|
||||
}
|
||||
|
||||
func checkUpdate(t *testing.T, client *vanity.Client, pkg vanity.Package) {
|
||||
func checkUpdate(t *testing.T, client *sdk.Client, pkg sdk.Package) {
|
||||
ctx := context.Background()
|
||||
// Update invalid package
|
||||
if err := client.Update(ctx, vanity.Package{Name: "test4"}); err == nil {
|
||||
if err := client.Update(ctx, sdk.Package{Name: "test4"}); err == nil {
|
||||
t.Log("should not be able to update invalid package")
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ func checkUpdate(t *testing.T, client *vanity.Client, pkg vanity.Package) {
|
|||
}
|
||||
}
|
||||
|
||||
func checkRemove(t *testing.T, client *vanity.Client, pkg vanity.Package) {
|
||||
func checkRemove(t *testing.T, client *sdk.Client, pkg sdk.Package) {
|
||||
ctx := context.Background()
|
||||
if err := client.Remove(ctx, pkg); err != nil {
|
||||
t.Logf("should be able to remove package: %v\n", err)
|
|
@ -11,8 +11,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"go.jolheiser.com/overlay"
|
||||
|
||||
"go.jolheiser.com/vanity/cmd/flags"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -34,8 +32,8 @@ func customRoot() string {
|
|||
return customPath
|
||||
}
|
||||
|
||||
func tmpl(name string) (*template.Template, error) {
|
||||
return template.New(name).Funcs(funcMap).ParseFS(ofs, "templates/base.tmpl", "templates/"+name)
|
||||
func tmpl(domain, name string) (*template.Template, error) {
|
||||
return template.New(name).Funcs(funcMap(domain)).ParseFS(ofs, "templates/base.tmpl", "templates/"+name)
|
||||
}
|
||||
|
||||
func static() http.Handler {
|
||||
|
@ -46,14 +44,16 @@ func static() http.Handler {
|
|||
return http.FileServer(http.FS(sub))
|
||||
}
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"AppVer": func() string {
|
||||
return Version
|
||||
},
|
||||
"GoVer": func() string {
|
||||
return runtime.Version()
|
||||
},
|
||||
"Domain": func() string {
|
||||
return strings.TrimSuffix(flags.Domain, "/")
|
||||
},
|
||||
func funcMap(domain string) template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"AppVer": func() string {
|
||||
return Version
|
||||
},
|
||||
"GoVer": func() string {
|
||||
return runtime.Version()
|
||||
},
|
||||
"Domain": func() string {
|
||||
return strings.TrimSuffix(domain, "/")
|
||||
},
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue