code.gitea.io/gitea@v1.22.3/services/migrations/restore.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package migrations 5 6 import ( 7 "context" 8 "fmt" 9 "os" 10 "path/filepath" 11 "strconv" 12 13 base "code.gitea.io/gitea/modules/migration" 14 15 "gopkg.in/yaml.v3" 16 ) 17 18 // RepositoryRestorer implements an Downloader from the local directory 19 type RepositoryRestorer struct { 20 base.NullDownloader 21 ctx context.Context 22 baseDir string 23 repoOwner string 24 repoName string 25 validation bool 26 } 27 28 // NewRepositoryRestorer creates a repository restorer which could restore repository from a dumped folder 29 func NewRepositoryRestorer(ctx context.Context, baseDir, owner, repoName string, validation bool) (*RepositoryRestorer, error) { 30 baseDir, err := filepath.Abs(baseDir) 31 if err != nil { 32 return nil, err 33 } 34 return &RepositoryRestorer{ 35 ctx: ctx, 36 baseDir: baseDir, 37 repoOwner: owner, 38 repoName: repoName, 39 validation: validation, 40 }, nil 41 } 42 43 func (r *RepositoryRestorer) commentDir() string { 44 return filepath.Join(r.baseDir, "comments") 45 } 46 47 func (r *RepositoryRestorer) reviewDir() string { 48 return filepath.Join(r.baseDir, "reviews") 49 } 50 51 // SetContext set context 52 func (r *RepositoryRestorer) SetContext(ctx context.Context) { 53 r.ctx = ctx 54 } 55 56 func (r *RepositoryRestorer) getRepoOptions() (map[string]string, error) { 57 p := filepath.Join(r.baseDir, "repo.yml") 58 bs, err := os.ReadFile(p) 59 if err != nil { 60 return nil, err 61 } 62 63 opts := make(map[string]string) 64 err = yaml.Unmarshal(bs, &opts) 65 if err != nil { 66 return nil, err 67 } 68 return opts, nil 69 } 70 71 // GetRepoInfo returns a repository information 72 func (r *RepositoryRestorer) GetRepoInfo() (*base.Repository, error) { 73 opts, err := r.getRepoOptions() 74 if err != nil { 75 return nil, err 76 } 77 78 isPrivate, _ := strconv.ParseBool(opts["is_private"]) 79 80 return &base.Repository{ 81 Owner: r.repoOwner, 82 Name: r.repoName, 83 IsPrivate: isPrivate, 84 Description: opts["description"], 85 OriginalURL: opts["original_url"], 86 CloneURL: filepath.Join(r.baseDir, "git"), 87 DefaultBranch: opts["default_branch"], 88 }, nil 89 } 90 91 // GetTopics return github topics 92 func (r *RepositoryRestorer) GetTopics() ([]string, error) { 93 p := filepath.Join(r.baseDir, "topic.yml") 94 95 topics := struct { 96 Topics []string `yaml:"topics"` 97 }{} 98 99 bs, err := os.ReadFile(p) 100 if err != nil { 101 if os.IsNotExist(err) { 102 return nil, nil 103 } 104 return nil, err 105 } 106 107 err = yaml.Unmarshal(bs, &topics) 108 if err != nil { 109 return nil, err 110 } 111 return topics.Topics, nil 112 } 113 114 // GetMilestones returns milestones 115 func (r *RepositoryRestorer) GetMilestones() ([]*base.Milestone, error) { 116 milestones := make([]*base.Milestone, 0, 10) 117 p := filepath.Join(r.baseDir, "milestone.yml") 118 err := base.Load(p, &milestones, r.validation) 119 if err != nil { 120 if os.IsNotExist(err) { 121 return nil, nil 122 } 123 return nil, err 124 } 125 126 return milestones, nil 127 } 128 129 // GetReleases returns releases 130 func (r *RepositoryRestorer) GetReleases() ([]*base.Release, error) { 131 releases := make([]*base.Release, 0, 10) 132 p := filepath.Join(r.baseDir, "release.yml") 133 _, err := os.Stat(p) 134 if err != nil { 135 if os.IsNotExist(err) { 136 return nil, nil 137 } 138 return nil, err 139 } 140 141 bs, err := os.ReadFile(p) 142 if err != nil { 143 return nil, err 144 } 145 146 err = yaml.Unmarshal(bs, &releases) 147 if err != nil { 148 return nil, err 149 } 150 for _, rel := range releases { 151 for _, asset := range rel.Assets { 152 if asset.DownloadURL != nil { 153 *asset.DownloadURL = "file://" + filepath.Join(r.baseDir, *asset.DownloadURL) 154 } 155 } 156 } 157 return releases, nil 158 } 159 160 // GetLabels returns labels 161 func (r *RepositoryRestorer) GetLabels() ([]*base.Label, error) { 162 labels := make([]*base.Label, 0, 10) 163 p := filepath.Join(r.baseDir, "label.yml") 164 _, err := os.Stat(p) 165 if err != nil { 166 if os.IsNotExist(err) { 167 return nil, nil 168 } 169 return nil, err 170 } 171 172 bs, err := os.ReadFile(p) 173 if err != nil { 174 return nil, err 175 } 176 177 err = yaml.Unmarshal(bs, &labels) 178 if err != nil { 179 return nil, err 180 } 181 return labels, nil 182 } 183 184 // GetIssues returns issues according start and limit 185 func (r *RepositoryRestorer) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { 186 issues := make([]*base.Issue, 0, 10) 187 p := filepath.Join(r.baseDir, "issue.yml") 188 err := base.Load(p, &issues, r.validation) 189 if err != nil { 190 if os.IsNotExist(err) { 191 return nil, true, nil 192 } 193 return nil, false, err 194 } 195 return issues, true, nil 196 } 197 198 // GetComments returns comments according issueNumber 199 func (r *RepositoryRestorer) GetComments(commentable base.Commentable) ([]*base.Comment, bool, error) { 200 comments := make([]*base.Comment, 0, 10) 201 p := filepath.Join(r.commentDir(), fmt.Sprintf("%d.yml", commentable.GetForeignIndex())) 202 _, err := os.Stat(p) 203 if err != nil { 204 if os.IsNotExist(err) { 205 return nil, false, nil 206 } 207 return nil, false, err 208 } 209 210 bs, err := os.ReadFile(p) 211 if err != nil { 212 return nil, false, err 213 } 214 215 err = yaml.Unmarshal(bs, &comments) 216 if err != nil { 217 return nil, false, err 218 } 219 return comments, false, nil 220 } 221 222 // GetPullRequests returns pull requests according page and perPage 223 func (r *RepositoryRestorer) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) { 224 pulls := make([]*base.PullRequest, 0, 10) 225 p := filepath.Join(r.baseDir, "pull_request.yml") 226 _, err := os.Stat(p) 227 if err != nil { 228 if os.IsNotExist(err) { 229 return nil, true, nil 230 } 231 return nil, false, err 232 } 233 234 bs, err := os.ReadFile(p) 235 if err != nil { 236 return nil, false, err 237 } 238 239 err = yaml.Unmarshal(bs, &pulls) 240 if err != nil { 241 return nil, false, err 242 } 243 for _, pr := range pulls { 244 pr.PatchURL = "file://" + filepath.Join(r.baseDir, pr.PatchURL) 245 CheckAndEnsureSafePR(pr, "", r) 246 } 247 return pulls, true, nil 248 } 249 250 // GetReviews returns pull requests review 251 func (r *RepositoryRestorer) GetReviews(reviewable base.Reviewable) ([]*base.Review, error) { 252 reviews := make([]*base.Review, 0, 10) 253 p := filepath.Join(r.reviewDir(), fmt.Sprintf("%d.yml", reviewable.GetForeignIndex())) 254 _, err := os.Stat(p) 255 if err != nil { 256 if os.IsNotExist(err) { 257 return nil, nil 258 } 259 return nil, err 260 } 261 262 bs, err := os.ReadFile(p) 263 if err != nil { 264 return nil, err 265 } 266 267 err = yaml.Unmarshal(bs, &reviews) 268 if err != nil { 269 return nil, err 270 } 271 return reviews, nil 272 }