code.gitea.io/gitea@v1.21.7/models/migrations/v1_9/v82.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package v1_9 //nolint
     5  
     6  import (
     7  	"fmt"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"code.gitea.io/gitea/modules/git"
    12  	"code.gitea.io/gitea/modules/setting"
    13  
    14  	"xorm.io/xorm"
    15  )
    16  
    17  func FixReleaseSha1OnReleaseTable(x *xorm.Engine) error {
    18  	type Release struct {
    19  		ID      int64
    20  		RepoID  int64
    21  		Sha1    string
    22  		TagName string
    23  	}
    24  
    25  	type Repository struct {
    26  		ID      int64
    27  		OwnerID int64
    28  		Name    string
    29  	}
    30  
    31  	type User struct {
    32  		ID   int64
    33  		Name string
    34  	}
    35  
    36  	// UserPath returns the path absolute path of user repositories.
    37  	UserPath := func(userName string) string {
    38  		return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
    39  	}
    40  
    41  	// RepoPath returns repository path by given user and repository name.
    42  	RepoPath := func(userName, repoName string) string {
    43  		return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".git")
    44  	}
    45  
    46  	// Update release sha1
    47  	const batchSize = 100
    48  	sess := x.NewSession()
    49  	defer sess.Close()
    50  
    51  	var (
    52  		err          error
    53  		count        int
    54  		gitRepoCache = make(map[int64]*git.Repository)
    55  		repoCache    = make(map[int64]*Repository)
    56  		userCache    = make(map[int64]*User)
    57  	)
    58  
    59  	if err = sess.Begin(); err != nil {
    60  		return err
    61  	}
    62  
    63  	for start := 0; ; start += batchSize {
    64  		releases := make([]*Release, 0, batchSize)
    65  		if err = sess.Limit(batchSize, start).Asc("id").Where("is_tag=?", false).Find(&releases); err != nil {
    66  			return err
    67  		}
    68  		if len(releases) == 0 {
    69  			break
    70  		}
    71  
    72  		for _, release := range releases {
    73  			gitRepo, ok := gitRepoCache[release.RepoID]
    74  			if !ok {
    75  				repo, ok := repoCache[release.RepoID]
    76  				if !ok {
    77  					repo = new(Repository)
    78  					has, err := sess.ID(release.RepoID).Get(repo)
    79  					if err != nil {
    80  						return err
    81  					} else if !has {
    82  						return fmt.Errorf("Repository %d is not exist", release.RepoID)
    83  					}
    84  
    85  					repoCache[release.RepoID] = repo
    86  				}
    87  
    88  				user, ok := userCache[repo.OwnerID]
    89  				if !ok {
    90  					user = new(User)
    91  					has, err := sess.ID(repo.OwnerID).Get(user)
    92  					if err != nil {
    93  						return err
    94  					} else if !has {
    95  						return fmt.Errorf("User %d is not exist", repo.OwnerID)
    96  					}
    97  
    98  					userCache[repo.OwnerID] = user
    99  				}
   100  
   101  				gitRepo, err = git.OpenRepository(git.DefaultContext, RepoPath(user.Name, repo.Name))
   102  				if err != nil {
   103  					return err
   104  				}
   105  				defer gitRepo.Close()
   106  				gitRepoCache[release.RepoID] = gitRepo
   107  			}
   108  
   109  			release.Sha1, err = gitRepo.GetTagCommitID(release.TagName)
   110  			if err != nil && !git.IsErrNotExist(err) {
   111  				return err
   112  			}
   113  
   114  			if err == nil {
   115  				if _, err = sess.ID(release.ID).Cols("sha1").Update(release); err != nil {
   116  					return err
   117  				}
   118  			}
   119  
   120  			count++
   121  			if count >= 1000 {
   122  				if err = sess.Commit(); err != nil {
   123  					return err
   124  				}
   125  				if err = sess.Begin(); err != nil {
   126  					return err
   127  				}
   128  				count = 0
   129  			}
   130  		}
   131  	}
   132  	return sess.Commit()
   133  }