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