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  }