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 r, err := git.Open(filepath.Join(c.RepoPath(), name+".git"))
35 if err != nil {
36 log.Printf("error opening repository %q: %v", name, err)
37 return nil, err
38 }
39 return &repo{
40 cfg: c,
41 repo: r,
42 }, nil
43}
44
45// ListRepos lists all repositories metadata.
46func (c *Config) ListRepos() ([]proto.Metadata, error) {
47 md := make([]proto.Metadata, 0)
48 ds, err := os.ReadDir(c.RepoPath())
49 if err != nil {
50 return nil, err
51 }
52 for _, d := range ds {
53 name := strings.TrimSuffix(d.Name(), ".git")
54 r, err := c.db.GetRepo(name)
55 if err != nil || r == nil {
56 md = append(md, &emptyMetadata{
57 name: name,
58 cfg: c,
59 })
60 } else {
61 md = append(md, &repo{
62 cfg: c,
63 info: r,
64 })
65 }
66 }
67 return md, nil
68}
69
70var _ proto.Metadata = emptyMetadata{}
71
72type emptyMetadata struct {
73 name string
74 cfg *Config
75}
76
77// Collabs implements proto.Metadata.
78func (emptyMetadata) Collabs() []proto.User {
79 return []proto.User{}
80}
81
82// Description implements proto.Metadata.
83func (emptyMetadata) Description() string {
84 return ""
85}
86
87// IsPrivate implements proto.Metadata.
88func (emptyMetadata) IsPrivate() bool {
89 return false
90}
91
92// Name implements proto.Metadata.
93func (e emptyMetadata) Name() string {
94 return e.name
95}
96
97// Open implements proto.Metadata.
98func (e emptyMetadata) Open() (proto.Repository, error) {
99 return e.cfg.Open(e.Name())
100}
101
102// ProjectName implements proto.Metadata.
103func (emptyMetadata) ProjectName() string {
104 return ""
105}
106
107var _ proto.Metadata = &repo{}
108var _ proto.Repository = &repo{}
109
110// repo represents a Git repository.
111type repo struct {
112 cfg *Config
113 repo *git.Repository
114 info *types.Repo
115}
116
117// Open opens the underlying Repository.
118func (r *repo) Open() (proto.Repository, error) {
119 return r.cfg.Open(r.Name())
120}
121
122// Name returns the name of the repository.
123func (r *repo) Name() string {
124 if r.repo != nil {
125 strings.TrimSuffix(filepath.Base(r.repo.Path), ".git")
126 }
127 return r.info.Name
128}
129
130// ProjectName returns the repository's project name.
131func (r *repo) ProjectName() string {
132 return r.info.ProjectName
133}
134
135// Description returns the repository's description.
136func (r *repo) Description() string {
137 return r.info.Description
138}
139
140// IsPrivate returns true if the repository is private.
141func (r *repo) IsPrivate() bool {
142 return r.info.Private
143}
144
145// Collabs returns the repository's collaborators.
146func (r *repo) Collabs() []proto.User {
147 collabs := make([]proto.User, 0)
148 cs, err := r.cfg.db.ListRepoCollabs(r.Name())
149 if err != nil {
150 return collabs
151 }
152 for i, c := range cs {
153 u := &user{
154 cfg: r.cfg,
155 user: c,
156 }
157 collabs[i] = u
158 }
159 return collabs
160}
161
162// Repository returns the underlying git.Repository.
163func (r *repo) Repository() *git.Repository {
164 return r.repo
165}