Go Back

0 package repo

1

2 import (

3 "errors"

4 "gemigit/config"

5 "gemigit/db"

6 io "gemigit/util"

7 "os"

8 "time"

9

10 "github.com/go-git/go-git/v5"

11 "github.com/go-git/go-git/v5/plumbing"

12 "github.com/go-git/go-git/v5/plumbing/object"

13 "github.com/go-git/go-git/v5/plumbing/storer"

14 "github.com/go-git/go-git/v5/storage"

15 "github.com/go-git/go-git/v5/storage/memory"

16 "github.com/go-git/go-git/v5/plumbing/transport/http"

17 )

18

19 var rootPath string

20 type repo struct {

21 memory storage.Storer

22 repository *git.Repository

23 update time.Time

24 }

25 var repositories = make(map[string]repo)

26

27 func Init(path string) error {

28 if config.Cfg.Git.Remote.Enabled {

29 return nil

30 }

31 rootPath = path

32 return os.MkdirAll(path, 0700)

33 }

34

35 func InitRepo(name string, username string) error {

36 if config.Cfg.Git.Remote.Enabled {

37 err := request("api/" + config.Cfg.Git.Remote.Key + "/init/" +

38 username + "/" + name)

39 return err

40 }

41 _, err := git.PlainInit(rootPath+"/"+username+"/"+name, true)

42 return err

43 }

44

45 func RemoveRepo(name string, username string) error {

46 if config.Cfg.Git.Remote.Enabled {

47 err := request("api/" + config.Cfg.Git.Remote.Key + "/rm/" +

48 username + "/" + name)

49 return err

50 }

51 return os.RemoveAll(rootPath + "/" + username + "/" + name)

52 }

53

54 func getRepo(name string, username string) (*git.Repository, error) {

55 var repository *git.Repository

56 var err error

57 url := username + "/" + name

58 if !config.Cfg.Git.Remote.Enabled {

59 repository, err = git.PlainOpen(rootPath + "/" + url)

60 return repository, err

61 }

62 var exist bool

63 r, exist := repositories[url]

64 if !exist {

65 r = repo{}

66 }

67 if exist && time.Now().Sub(r.update).Seconds() < 15 {

68 return r.repository, nil

69 }

70 r.update = time.Now()

71 repositories[url] = r

72 if r.repository == nil {

73 r.memory = memory.NewStorage()

74 r.repository, err = git.Clone(r.memory, nil,

75 &git.CloneOptions {

76 URL: config.Cfg.Git.Remote.Url + "/" + url,

77 Auth: &http.BasicAuth {

78 Username: "root#",

79 Password: config.Cfg.Git.Remote.Key,

80 },

81 })

82 if err != nil {

83 r.memory = nil

84 r.repository = nil

85 }

86 repositories[url] = r

87 return r.repository, err

88 }

89 err = r.repository.Fetch(&git.FetchOptions {

90 Auth: &http.BasicAuth {

91 Username: "root#",

92 Password: config.Cfg.Git.Remote.Key,

93 },

94 })

95 if err != nil {

96 return nil, err

97 }

98 repositories[url] = r

99 return r.repository, nil

100 }

101

102 func GetCommit(name string, username string,

103 hash plumbing.Hash) (*object.Commit, error) {

104 repo, err := getRepo(name, username)

105 if err != nil {

106 return nil, err

107 }

108 obj, err := repo.CommitObject(hash)

109 if err != nil {

110 return nil, err

111 }

112 return obj, nil

113 }

114

115 func GetCommits(name string, username string) (object.CommitIter, error) {

116 repo, err := getRepo(name, username)

117 if repo == nil || err != nil {

118 return nil, err

119 }

120 ref, err := repo.Head()

121 if err != nil {

122 return nil, nil // Empty repo

123 }

124 cIter, err := repo.Log(&git.LogOptions{From: ref.Hash()})

125 if err != nil {

126 return nil, err

127 }

128 return cIter, nil

129 }

130

131 func GetRefs(name string, username string) (storer.ReferenceIter, error) {

132 repo, err := getRepo(name, username)

133 if repo == nil || err != nil {

134 return nil, err

135 }

136 _, err = repo.Head()

137 if err != nil {

138 return nil, nil // Empty repo

139 }

140 refs, err := repo.References()

141 if err != nil {

142 return nil, err

143 }

144 return refs, nil

145 }

146

147 func getTree(name string, username string) (*object.Tree, error) {

148 repo, err := getRepo(name, username)

149 if repo == nil || err != nil {

150 return nil, err

151 }

152 ref, err := repo.Head()

153 if err != nil {

154 return nil, nil // Empty repo

155 }

156 last, err := repo.CommitObject(ref.Hash())

157 if err != nil {

158 return nil, err

159 }

160 tree, err := repo.TreeObject(last.TreeHash)

161 if err != nil {

162 return nil, err

163 }

164 return tree, nil

165 }

166

167 func GetFiles(name string, username string) (*object.FileIter, error) {

168 tree, err := getTree(name, username)

169 if err != nil {

170 return nil, err

171 }

172 if tree == nil {

173 return nil, nil

174 }

175 return tree.Files(), nil

176 }

177

178 func GetFile(name string, username string, file string) (*object.File, error) {

179 tree, err := getTree(name, username)

180 if err != nil {

181 return nil, err

182 }

183 if tree == nil {

184 return nil, nil

185 }

186 out, err := tree.File(file)

187 if err != nil {

188 return nil, err

189 }

190 return out, nil

191 }

192

193 func GetPublicFile(name string, username string, hash string) (string, error) {

194 public, err := db.IsRepoPublic(name, username)

195 if err != nil {

196 return "", err

197 }

198 if !public {

199 return "", errors.New("repository is private")

200 }

201 repo, err := git.PlainOpen(rootPath + "/" + username + "/" + name)

202 if err != nil {

203 return "", err

204 }

205 file, err := repo.BlobObject(plumbing.NewHash(hash))

206 if err != nil {

207 return "", err

208 }

209 reader, err := file.Reader()

210 if err != nil {

211 return "", err

212 }

213 buf, err := io.ReadAll(reader)

214 if err != nil {

215 return "", err

216 }

217 return string(buf), nil

218 }

219

220 func GetPrivateFile(name string, username string,

221 hash string, sig string) (string, error) {

222 user, b := db.GetUser(sig)

223 if !b || username != user.Name {

224 return "", errors.New("invalid signature")

225 }

226 repo, err := git.PlainOpen(rootPath + "/" + username + "/" + name)

227 if err != nil {

228 return "", err

229 }

230 file, err := repo.BlobObject(plumbing.NewHash(hash))

231 if err != nil {

232 return "", err

233 }

234 reader, err := file.Reader()

235 if err != nil {

236 return "", err

237 }

238 buf, err := io.ReadAll(reader)

239 if err != nil {

240 return "", err

241 }

242 return string(buf), nil

243 }

244

245 func ChangeRepoDir(name string, username string, newname string) error {

246 if config.Cfg.Git.Remote.Enabled {

247 err := request("api/" + config.Cfg.Git.Remote.Key + "/mv/" +

248 username + "/" + name + "/" + newname)

249 return err

250 }

251 return os.Rename(rootPath + "/" + username + "/" + name,

252 rootPath + "/" + username + "/" + newname)

253 }

254