@@ -26,6 +26,7 @@ import (
"io/fs"
"os"
"path/filepath"
+ "strconv"
"strings"
"github.com/charmbracelet/log"
@@ -38,15 +39,16 @@ import (
// sub file and directory names.
const (
- anonAccess = "anon-access"
- allowKeyless = "allow-keyless"
- admins = "admins"
- repos = "repos"
- collabs = "collaborators"
- description = "description"
- exportOk = "git-daemon-export-ok"
- private = "private"
- settings = "settings"
+ anonAccess = "anon-access"
+ defaultBranch = "default-branch"
+ allowKeyless = "allow-keyless"
+ admins = "admins"
+ repos = "repos"
+ collabs = "collaborators"
+ description = "description"
+ exportOk = "git-daemon-export-ok"
+ private = "private"
+ settings = "settings"
)
var (
@@ -86,7 +88,8 @@ func (fb *FileBackend) adminsPath() string {
}
func (fb *FileBackend) collabsPath(repo string) string {
- return filepath.Join(fb.path, collabs, repo, collabs)
+ repo = utils.SanitizeRepo(repo) + ".git"
+ return filepath.Join(fb.reposPath(), repo, collabs)
}
func readOneLine(path string) (string, error) {
@@ -125,7 +128,7 @@ func NewFileBackend(path string) (*FileBackend, error) {
}
}
- for _, file := range []string{admins, anonAccess, allowKeyless} {
+ for _, file := range []string{admins, anonAccess, allowKeyless, defaultBranch} {
fp := filepath.Join(fb.settingsPath(), file)
_, err := os.Stat(fp)
if errors.Is(err, fs.ErrNotExist) {
@@ -444,6 +447,26 @@ func (fb *FileBackend) AnonAccess() backend.AccessLevel {
}
}
+// DefaultBranch returns the default branch for new repositories.
+//
+// It implements backend.Backend.
+func (fb *FileBackend) DefaultBranch() string {
+ line, err := readOneLine(filepath.Join(fb.settingsPath(), defaultBranch))
+ if err != nil {
+ logger.Debug("failed to read default-branch file", "err", err)
+ return defaults[defaultBranch]
+ }
+
+ return line
+}
+
+// SetDefaultBranch sets the default branch for new repositories.
+//
+// It implements backend.Backend.
+func (fb *FileBackend) SetDefaultBranch(branch string) error {
+ return os.WriteFile(filepath.Join(fb.settingsPath(), defaultBranch), []byte(branch), 0600)
+}
+
// Description returns the description of the given repo.
//
// It implements backend.Backend.
@@ -531,28 +554,14 @@ func (fb *FileBackend) IsPrivate(repo string) bool {
//
// It implements backend.Backend.
func (fb *FileBackend) SetAllowKeyless(allow bool) error {
- f, err := os.OpenFile(filepath.Join(fb.settingsPath(), allowKeyless), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- return fmt.Errorf("failed to open allow-keyless file: %w", err)
- }
-
- defer f.Close() //nolint:errcheck
- _, err = fmt.Fprintln(f, allow)
- return err
+ return os.WriteFile(filepath.Join(fb.settingsPath(), allowKeyless), []byte(strconv.FormatBool(allow)), 0600)
}
// SetAnonAccess sets the anonymous access level.
//
// It implements backend.Backend.
func (fb *FileBackend) SetAnonAccess(level backend.AccessLevel) error {
- f, err := os.OpenFile(filepath.Join(fb.settingsPath(), anonAccess), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- return fmt.Errorf("failed to open anon-access file: %w", err)
- }
-
- defer f.Close() //nolint:errcheck
- _, err = fmt.Fprintln(f, level.String())
- return err
+ return os.WriteFile(filepath.Join(fb.settingsPath(), anonAccess), []byte(level.String()), 0600)
}
// SetDescription sets the description of the given repo.
@@ -560,14 +569,7 @@ func (fb *FileBackend) SetAnonAccess(level backend.AccessLevel) error {
// It implements backend.Backend.
func (fb *FileBackend) SetDescription(repo string, desc string) error {
repo = utils.SanitizeRepo(repo) + ".git"
- f, err := os.OpenFile(filepath.Join(fb.reposPath(), repo, description), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
- if err != nil {
- return fmt.Errorf("failed to open description file: %w", err)
- }
-
- defer f.Close() //nolint:errcheck
- _, err = fmt.Fprintln(f, desc)
- return err
+ return os.WriteFile(filepath.Join(fb.reposPath(), repo, description), []byte(desc), 0600)
}
// SetPrivate sets the private status of the given repo.
@@ -1,141 +0,0 @@
-package noop
-
-import (
- "fmt"
- "os"
- "path/filepath"
-
- "github.com/charmbracelet/soft-serve/git"
- "github.com/charmbracelet/soft-serve/server/backend"
- "golang.org/x/crypto/ssh"
-)
-
-var ErrNotImpl = fmt.Errorf("not implemented")
-
-var _ backend.Backend = (*Noop)(nil)
-
-// Noop is a backend that does nothing. It's used for testing.
-type Noop struct {
- Port string
-}
-
-// Admins implements backend.Backend
-func (*Noop) Admins() ([]string, error) {
- return nil, nil
-}
-
-// Collaborators implements backend.Backend
-func (*Noop) Collaborators(repo string) ([]string, error) {
- return nil, nil
-}
-
-// RemoveAdmin implements backend.Backend
-func (*Noop) RemoveAdmin(pk ssh.PublicKey) error {
- return nil
-}
-
-// RemoveCollaborator implements backend.Backend
-func (*Noop) RemoveCollaborator(pk ssh.PublicKey, repo string) error {
- return nil
-}
-
-// AccessLevel implements backend.AccessMethod
-func (*Noop) AccessLevel(repo string, pk ssh.PublicKey) backend.AccessLevel {
- return backend.AdminAccess
-}
-
-// AddAdmin implements backend.Backend
-func (*Noop) AddAdmin(pk ssh.PublicKey, memo string) error {
- return ErrNotImpl
-}
-
-// AddCollaborator implements backend.Backend
-func (*Noop) AddCollaborator(pk ssh.PublicKey, memo string, repo string) error {
- return ErrNotImpl
-}
-
-// AllowKeyless implements backend.Backend
-func (*Noop) AllowKeyless() bool {
- return true
-}
-
-// AnonAccess implements backend.Backend
-func (*Noop) AnonAccess() backend.AccessLevel {
- return backend.AdminAccess
-}
-
-// CreateRepository implements backend.Backend
-func (*Noop) CreateRepository(name string, private bool) (backend.Repository, error) {
- temp, err := os.MkdirTemp("", "soft-serve")
- if err != nil {
- return nil, err
- }
-
- rp := filepath.Join(temp, name)
- _, err = git.Init(rp, private)
- if err != nil {
- return nil, err
- }
-
- return &repo{path: rp}, nil
-}
-
-// DeleteRepository implements backend.Backend
-func (*Noop) DeleteRepository(name string) error {
- return ErrNotImpl
-}
-
-// Description implements backend.Backend
-func (*Noop) Description(repo string) string {
- return ""
-}
-
-// IsAdmin implements backend.Backend
-func (*Noop) IsAdmin(pk ssh.PublicKey) bool {
- return true
-}
-
-// IsCollaborator implements backend.Backend
-func (*Noop) IsCollaborator(pk ssh.PublicKey, repo string) bool {
- return true
-}
-
-// IsPrivate implements backend.Backend
-func (*Noop) IsPrivate(repo string) bool {
- return false
-}
-
-// RenameRepository implements backend.Backend
-func (*Noop) RenameRepository(oldName string, newName string) error {
- return ErrNotImpl
-}
-
-// Repositories implements backend.Backend
-func (*Noop) Repositories() ([]backend.Repository, error) {
- return nil, ErrNotImpl
-}
-
-// Repository implements backend.Backend
-func (*Noop) Repository(repo string) (backend.Repository, error) {
- return nil, ErrNotImpl
-}
-
-// SetAllowKeyless implements backend.Backend
-func (*Noop) SetAllowKeyless(allow bool) error {
- return ErrNotImpl
-}
-
-// SetAnonAccess implements backend.Backend
-func (*Noop) SetAnonAccess(level backend.AccessLevel) error {
- return ErrNotImpl
-}
-
-// SetDescription implements backend.Backend
-func (*Noop) SetDescription(repo string, desc string) error {
- return ErrNotImpl
-}
-
-// SetPrivate implements backend.Backend
-func (*Noop) SetPrivate(repo string, priv bool) error {
- return ErrNotImpl
-}