Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement git-lfs support #344

Merged
merged 20 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions cmd/soft/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,51 @@ import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/charmbracelet/log"
"github.com/charmbracelet/soft-serve/server/backend"
"github.com/charmbracelet/soft-serve/server/config"
"github.com/charmbracelet/soft-serve/server/hooks"
"github.com/spf13/cobra"
)

var (
// ErrInternalServerError indicates that an internal server error occurred.
ErrInternalServerError = errors.New("internal server error")

// Deprecated: this flag is ignored.
configPath string

hookCmd = &cobra.Command{
Use: "hook",
Short: "Run git server hooks",
Long: "Handles Soft Serve git server hooks.",
Hidden: true,
PersistentPreRunE: initBackendContext,
PersistentPostRunE: closeDBContext,
Use: "hook",
Short: "Run git server hooks",
Long: "Handles Soft Serve git server hooks.",
Hidden: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
logger := log.FromContext(cmd.Context())
if err := initBackendContext(cmd, args); err != nil {
logger.Error("failed to initialize backend context", "err", err)
return ErrInternalServerError
}

return nil
},
PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
logger := log.FromContext(cmd.Context())
if err := closeDBContext(cmd, args); err != nil {
logger.Error("failed to close backend", "err", err)
return ErrInternalServerError
}

return nil
},
}

// Git hooks read the config from the environment, based on
Expand Down
8 changes: 4 additions & 4 deletions cmd/soft/migrate_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ var migrateConfig = &cobra.Command{
return fmt.Errorf("failed to copy repo: %w", err)
}

if _, err := sb.CreateRepository(ctx, dir.Name(), proto.RepositoryOptions{}); err != nil {
if _, err := sb.CreateRepository(ctx, dir.Name(), nil, proto.RepositoryOptions{}); err != nil {
fmt.Fprintf(os.Stderr, "failed to create repository: %s\n", err)
}
}
Expand Down Expand Up @@ -239,7 +239,7 @@ var migrateConfig = &cobra.Command{
}

// Create `.soft-serve` repository and add readme
if _, err := sb.CreateRepository(ctx, ".soft-serve", proto.RepositoryOptions{
if _, err := sb.CreateRepository(ctx, ".soft-serve", nil, proto.RepositoryOptions{
ProjectName: "Home",
Description: "Soft Serve home repository",
Hidden: true,
Expand Down Expand Up @@ -273,7 +273,7 @@ var migrateConfig = &cobra.Command{
}

for _, collab := range r.Collabs {
if err := sb.AddCollaborator(ctx, repo, collab); err != nil {
if err := sb.AddCollaborator(ctx, repo, collab, access.ReadWriteAccess); err != nil {
logger.Errorf("failed to add repo collab to %s: %s", repo, err)
}
}
Expand Down Expand Up @@ -308,7 +308,7 @@ var migrateConfig = &cobra.Command{
}

for _, repo := range user.CollabRepos {
if err := sb.AddCollaborator(ctx, repo, username); err != nil {
if err := sb.AddCollaborator(ctx, repo, username, access.ReadWriteAccess); err != nil {
logger.Errorf("failed to add user collab to %s: %s\n", repo, err)
}
}
Expand Down
54 changes: 13 additions & 41 deletions cmd/soft/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ package main

import (
"context"
"errors"
"fmt"
"io/fs"
"os"
"runtime/debug"
"strings"
"time"

"github.com/charmbracelet/log"
"github.com/charmbracelet/soft-serve/server/backend"
"github.com/charmbracelet/soft-serve/server/config"
"github.com/charmbracelet/soft-serve/server/db"
logr "github.com/charmbracelet/soft-serve/server/log"
"github.com/charmbracelet/soft-serve/server/store"
"github.com/charmbracelet/soft-serve/server/store/database"
_ "github.com/lib/pq" // postgres driver
"github.com/spf13/cobra"
"go.uber.org/automaxprocs/maxprocs"
Expand Down Expand Up @@ -74,7 +77,7 @@ func main() {
}

ctx = config.WithContext(ctx, cfg)
logger, f, err := newDefaultLogger(cfg)
logger, f, err := logr.NewLogger(cfg)
if err != nil {
log.Errorf("failed to create logger: %v", err)
}
Expand Down Expand Up @@ -103,53 +106,22 @@ func main() {
}
}

// newDefaultLogger returns a new logger with default settings.
func newDefaultLogger(cfg *config.Config) (*log.Logger, *os.File, error) {
logger := log.NewWithOptions(os.Stderr, log.Options{
ReportTimestamp: true,
TimeFormat: time.DateOnly,
})

switch {
case config.IsVerbose():
logger.SetReportCaller(true)
fallthrough
case config.IsDebug():
logger.SetLevel(log.DebugLevel)
}

logger.SetTimeFormat(cfg.Log.TimeFormat)

switch strings.ToLower(cfg.Log.Format) {
case "json":
logger.SetFormatter(log.JSONFormatter)
case "logfmt":
logger.SetFormatter(log.LogfmtFormatter)
case "text":
logger.SetFormatter(log.TextFormatter)
}

var f *os.File
if cfg.Log.Path != "" {
f, err := os.OpenFile(cfg.Log.Path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return nil, nil, err
}
logger.SetOutput(f)
}

return logger, f, nil
}

func initBackendContext(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
cfg := config.FromContext(ctx)
if _, err := os.Stat(cfg.DataPath); errors.Is(err, fs.ErrNotExist) {
if err := os.MkdirAll(cfg.DataPath, os.ModePerm); err != nil {
return fmt.Errorf("create data directory: %w", err)
}
}
dbx, err := db.Open(ctx, cfg.DB.Driver, cfg.DB.DataSource)
if err != nil {
return fmt.Errorf("open database: %w", err)
}

ctx = db.WithContext(ctx, dbx)
dbstore := database.New(ctx, dbx)
ctx = store.WithContext(ctx, dbstore)
be := backend.New(ctx, cfg, dbx)
ctx = backend.WithContext(ctx, be)

Expand Down
72 changes: 30 additions & 42 deletions git/config.go
Original file line number Diff line number Diff line change
@@ -1,51 +1,39 @@
package git

// ConfigOptions are options for Config.
type ConfigOptions struct {
File string
All bool
Add bool
CommandOptions
}
import (
"os"
"path/filepath"

// Config gets a git configuration.
func Config(key string, opts ...ConfigOptions) (string, error) {
var opt ConfigOptions
if len(opts) > 0 {
opt = opts[0]
}
cmd := NewCommand("config")
if opt.File != "" {
cmd.AddArgs("--file", opt.File)
}
if opt.All {
cmd.AddArgs("--get-all")
}
for _, a := range opt.Args {
cmd.AddArgs(a)
}
cmd.AddArgs(key)
bts, err := cmd.Run()
gcfg "github.com/go-git/go-git/v5/plumbing/format/config"
)

// Config returns the repository Git configuration.
func (r *Repository) Config() (*gcfg.Config, error) {
cp := filepath.Join(r.Path, "config")
f, err := os.Open(cp)
if err != nil {
return "", err
return nil, err
}
return string(bts), nil
}

// SetConfig sets a git configuration.
func SetConfig(key string, value string, opts ...ConfigOptions) error {
var opt ConfigOptions
if len(opts) > 0 {
opt = opts[0]
defer f.Close() // nolint: errcheck
d := gcfg.NewDecoder(f)
cfg := gcfg.New()
if err := d.Decode(cfg); err != nil {
return nil, err
}
cmd := NewCommand("config")
if opt.File != "" {
cmd.AddArgs("--file", opt.File)
}
for _, a := range opt.Args {
cmd.AddArgs(a)

return cfg, nil
}

// SetConfig sets the repository Git configuration.
func (r *Repository) SetConfig(cfg *gcfg.Config) error {
cp := filepath.Join(r.Path, "config")
f, err := os.Create(cp)
if err != nil {
return err
}
cmd.AddArgs(key, value)
_, err := cmd.Run()
return err

defer f.Close() // nolint: errcheck
e := gcfg.NewEncoder(f)
return e.Encode(cfg)
}
28 changes: 0 additions & 28 deletions git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,34 +200,6 @@ func (r *Repository) CommitsByPage(ref *Reference, page, size int) (Commits, err
return commits, nil
}

// Config returns the config value for the given key.
func (r *Repository) Config(key string, opts ...ConfigOptions) (string, error) {
dir, err := gitDir(r.Repository)
if err != nil {
return "", err
}
var opt ConfigOptions
if len(opts) > 0 {
opt = opts[0]
}
opt.File = filepath.Join(dir, "config")
return Config(key, opt)
}

// SetConfig sets the config value for the given key.
func (r *Repository) SetConfig(key, value string, opts ...ConfigOptions) error {
dir, err := gitDir(r.Repository)
if err != nil {
return err
}
var opt ConfigOptions
if len(opts) > 0 {
opt = opts[0]
}
opt.File = filepath.Join(dir, "config")
return SetConfig(key, value, opt)
}

// SymbolicRef returns or updates the symbolic reference for the given name.
// Both name and ref can be empty.
func (r *Repository) SymbolicRef(name string, ref string, opts ...git.SymbolicRefOptions) (string, error) {
Expand Down
25 changes: 18 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@ require (
)

require (
github.com/caarlos0/duration v0.0.0-20220103233809-8df7c22fe305
github.com/caarlos0/env/v8 v8.0.0
github.com/caarlos0/tablewriter v0.1.0
github.com/charmbracelet/git-lfs-transfer v0.1.1-0.20230725143853-5dd0632f9245
github.com/charmbracelet/keygen v0.4.3
github.com/charmbracelet/log v0.2.3-0.20230713155356-557335e40e35
github.com/charmbracelet/ssh v0.0.0-20230712221603-7e03c5063afc
github.com/charmbracelet/log v0.2.3-0.20230725142510-280c4e3f1ef2
github.com/charmbracelet/ssh v0.0.0-20230720143903-5bdd92839155
github.com/go-jose/go-jose/v3 v3.0.0
github.com/gobwas/glob v0.2.3
github.com/gogs/git-module v1.8.2
github.com/golang-jwt/jwt/v5 v5.0.0
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/hashicorp/golang-lru/v2 v2.0.4
github.com/jmoiron/sqlx v1.3.5
github.com/lib/pq v1.10.9
Expand All @@ -33,9 +40,9 @@ require (
github.com/prometheus/client_golang v1.16.0
github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/go-internal v1.11.0
github.com/rubyist/tracerx v0.0.0-20170927163412-787959303086
github.com/spf13/cobra v1.7.0
go.uber.org/automaxprocs v1.5.3
goji.io v2.0.2+incompatible
golang.org/x/crypto v0.11.0
golang.org/x/sync v0.3.0
gopkg.in/yaml.v3 v3.0.1
Expand All @@ -52,6 +59,9 @@ require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.3.0 // indirect
Expand All @@ -74,18 +84,19 @@ require (
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/yuin/goldmark v1.5.2 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.13.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/tools v0.6.0 // indirect
golang.org/x/tools v0.9.1 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect
Expand Down
Loading