repo.go

  1package config
  2
  3import (
  4	"log"
  5	"os"
  6	"path/filepath"
  7	"strings"
  8
  9	"github.com/charmbracelet/soft-serve/git"
 10	"github.com/charmbracelet/soft-serve/proto"
 11	"github.com/charmbracelet/soft-serve/server/db/types"
 12)
 13
 14var _ proto.Provider = &Config{}
 15var _ proto.MetadataProvider = &Config{}
 16
 17// Metadata returns the repository's metadata.
 18func (c *Config) Metadata(name string) (proto.Metadata, error) {
 19	i, err := c.db.GetRepo(name)
 20	if err != nil {
 21		return nil, err
 22	}
 23	return &repo{
 24		cfg:  c,
 25		info: i,
 26	}, nil
 27}
 28
 29// Open opens a repository.
 30func (c *Config) Open(name string) (proto.Repository, error) {
 31	if name == "" {
 32		return nil, os.ErrNotExist
 33	}
 34	name = strings.TrimSuffix(name, ".git")
 35	r, err := git.Open(filepath.Join(c.RepoPath(), name+".git"))
 36	if err != nil {
 37		log.Printf("error opening repository %q: %v", name, err)
 38		return nil, err
 39	}
 40	return &repo{
 41		cfg:  c,
 42		repo: r,
 43	}, nil
 44}
 45
 46// ListRepos lists all repositories metadata.
 47func (c *Config) ListRepos() ([]proto.Metadata, error) {
 48	md := make([]proto.Metadata, 0)
 49	ds, err := os.ReadDir(c.RepoPath())
 50	if err != nil {
 51		return nil, err
 52	}
 53	for _, d := range ds {
 54		name := strings.TrimSuffix(d.Name(), ".git")
 55		r, err := c.db.GetRepo(name)
 56		if err != nil || r == nil {
 57			md = append(md, &emptyMetadata{
 58				name: name,
 59				cfg:  c,
 60			})
 61		} else {
 62			md = append(md, &repo{
 63				cfg:  c,
 64				info: r,
 65			})
 66		}
 67	}
 68	return md, nil
 69}
 70
 71// Create creates a new repository.
 72func (c *Config) Create(name string, projectName string, description string, isPrivate bool) error {
 73	name = strings.TrimSuffix(name, ".git")
 74	name = strings.ToLower(name)
 75	if _, err := git.Init(filepath.Join(c.RepoPath(), name+".git"), true); err != nil {
 76		return err
 77	}
 78	if err := c.db.AddRepo(name, projectName, description, isPrivate); err != nil {
 79		return err
 80	}
 81	return nil
 82}
 83
 84// Delete deletes a repository.
 85func (c *Config) Delete(name string) error {
 86	name = strings.TrimSuffix(name, ".git")
 87	if err := os.RemoveAll(filepath.Join(c.RepoPath(), name+".git")); err != nil {
 88		return err
 89	}
 90	if err := c.db.DeleteRepo(name); err != nil {
 91		return err
 92	}
 93	return nil
 94}
 95
 96// Rename renames a repository.
 97func (c *Config) Rename(name string, newName string) error {
 98	name = strings.TrimSuffix(name, ".git")
 99	newName = strings.TrimSuffix(newName, ".git")
100	if err := os.Rename(filepath.Join(c.RepoPath(), name+".git"), filepath.Join(c.RepoPath(), newName+".git")); err != nil {
101		return err
102	}
103	if err := c.db.SetRepoName(name, newName); err != nil {
104		return err
105	}
106	return nil
107}
108
109// SetProjectName sets the repository's project name.
110func (c *Config) SetProjectName(name string, projectName string) error {
111	name = strings.TrimSuffix(name, ".git")
112	if err := c.db.SetRepoProjectName(name, projectName); err != nil {
113		return err
114	}
115	return nil
116}
117
118// SetDescription sets the repository's description.
119func (c *Config) SetDescription(name string, description string) error {
120	name = strings.TrimSuffix(name, ".git")
121	if err := c.db.SetRepoDescription(name, description); err != nil {
122		return err
123	}
124	return nil
125}
126
127// SetPrivate sets the repository's privacy.
128func (c *Config) SetPrivate(name string, isPrivate bool) error {
129	name = strings.TrimSuffix(name, ".git")
130	if err := c.db.SetRepoPrivate(name, isPrivate); err != nil {
131		return err
132	}
133	return nil
134}
135
136// SetDefaultBranch sets the repository's default branch.
137func (c *Config) SetDefaultBranch(name string, branch string) error {
138	re, err := c.Open(name)
139	if err != nil {
140		return err
141	}
142	if _, err = re.Repository().SymbolicRef("HEAD", "refs/heads/"+branch); err != nil {
143		return err
144	}
145	return nil
146}
147
148var _ proto.Metadata = emptyMetadata{}
149
150type emptyMetadata struct {
151	name string
152	cfg  *Config
153}
154
155// Collabs implements proto.Metadata.
156func (emptyMetadata) Collabs() []proto.User {
157	return []proto.User{}
158}
159
160// Description implements proto.Metadata.
161func (emptyMetadata) Description() string {
162	return ""
163}
164
165// IsPrivate implements proto.Metadata.
166func (emptyMetadata) IsPrivate() bool {
167	return false
168}
169
170// Name implements proto.Metadata.
171func (e emptyMetadata) Name() string {
172	return e.name
173}
174
175// Open implements proto.Metadata.
176func (e emptyMetadata) Open() (proto.Repository, error) {
177	return e.cfg.Open(e.Name())
178}
179
180// ProjectName implements proto.Metadata.
181func (emptyMetadata) ProjectName() string {
182	return ""
183}
184
185var _ proto.Metadata = &repo{}
186var _ proto.Repository = &repo{}
187
188// repo represents a Git repository.
189type repo struct {
190	cfg  *Config
191	repo *git.Repository
192	info *types.Repo
193}
194
195// Open opens the underlying Repository.
196func (r *repo) Open() (proto.Repository, error) {
197	return r.cfg.Open(r.Name())
198}
199
200// Name returns the name of the repository.
201func (r *repo) Name() string {
202	if r.repo != nil {
203		strings.TrimSuffix(filepath.Base(r.repo.Path), ".git")
204	}
205	return r.info.Name
206}
207
208// ProjectName returns the repository's project name.
209func (r *repo) ProjectName() string {
210	return r.info.ProjectName
211}
212
213// Description returns the repository's description.
214func (r *repo) Description() string {
215	return r.info.Description
216}
217
218// IsPrivate returns true if the repository is private.
219func (r *repo) IsPrivate() bool {
220	return r.info.Private
221}
222
223// Collabs returns the repository's collaborators.
224func (r *repo) Collabs() []proto.User {
225	collabs := make([]proto.User, 0)
226	cs, err := r.cfg.db.ListRepoCollabs(r.Name())
227	if err != nil {
228		return collabs
229	}
230	for i, c := range cs {
231		u := &user{
232			cfg:  r.cfg,
233			user: c,
234		}
235		collabs[i] = u
236	}
237	return collabs
238}
239
240// Repository returns the underlying git.Repository.
241func (r *repo) Repository() *git.Repository {
242	return r.repo
243}