// runSync returns true if sync finished without error. func (m *Mirror) runSync() bool { repoPath := m.Repo.RepoPath() wikiPath := m.Repo.WikiPath() timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second gitArgs := []string{"remote", "update"} if m.EnablePrune { gitArgs = append(gitArgs, "--prune") } if _, stderr, err := process.ExecDir( timeout, repoPath, fmt.Sprintf("Mirror.runSync: %s", repoPath), "git", gitArgs...); err != nil { desc := fmt.Sprintf("Fail to update mirror repository '%s': %s", repoPath, stderr) log.Error(4, desc) if err = CreateRepositoryNotice(desc); err != nil { log.Error(4, "CreateRepositoryNotice: %v", err) } return false } if m.Repo.HasWiki() { if _, stderr, err := process.ExecDir( timeout, wikiPath, fmt.Sprintf("Mirror.runSync: %s", wikiPath), "git", "remote", "update", "--prune"); err != nil { desc := fmt.Sprintf("Fail to update mirror wiki repository '%s': %s", wikiPath, stderr) log.Error(4, desc) if err = CreateRepositoryNotice(desc); err != nil { log.Error(4, "CreateRepositoryNotice: %v", err) } return false } } return true }
// GitFsck calls 'git fsck' to check repository health. func GitFsck() { if isGitFscking { return } isGitFscking = true defer func() { isGitFscking = false }() args := append([]string{"fsck"}, setting.Git.Fsck.Args...) if err := x.Where("id > 0").Iterate(new(Repository), func(idx int, bean interface{}) error { repo := bean.(*Repository) if err := repo.GetOwner(); err != nil { return err } repoPath := RepoPath(repo.Owner.Name, repo.Name) _, _, err := process.ExecDir(-1, repoPath, "Repository health check", "git", args...) if err != nil { desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath) log.Warn(desc) if err = CreateRepositoryNotice(desc); err != nil { log.Error(4, "Fail to add notice: %v", err) } } return nil }); err != nil { log.Error(4, "repo.Fsck: %v", err) } }
// initRepoCommit temporarily changes with work directory. func initRepoCommit(tmpPath string, sig *git.Signature) (err error) { var stderr string if _, stderr, err = process.ExecDir(-1, tmpPath, fmt.Sprintf("initRepoCommit(git add): %s", tmpPath), "git", "add", "--all"); err != nil { return errors.New("git add: " + stderr) } if _, stderr, err = process.ExecDir(-1, tmpPath, fmt.Sprintf("initRepoCommit(git commit): %s", tmpPath), "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", "Init commit"); err != nil { return errors.New("git commit: " + stderr) } if _, stderr, err = process.ExecDir(-1, tmpPath, fmt.Sprintf("initRepoCommit(git push): %s", tmpPath), "git", "push", "origin", "master"); err != nil { return errors.New("git push: " + stderr) } os.RemoveAll(tmpPath) return nil }
func GitGcRepos() error { args := append([]string{"gc"}, setting.Git.GcArgs...) return x.Where("id > 0").Iterate(new(Repository), func(idx int, bean interface{}) error { repo := bean.(*Repository) if err := repo.GetOwner(); err != nil { return err } _, stderr, err := process.ExecDir(-1, RepoPath(repo.Owner.Name, repo.Name), "Repository garbage collection", "git", args...) if err != nil { return fmt.Errorf("%v: %v", err, stderr) } return nil }) }
// MirrorUpdate checks and updates mirror repositories. func MirrorUpdate() { if isMirrorUpdating { return } isMirrorUpdating = true defer func() { isMirrorUpdating = false }() mirrors := make([]*Mirror, 0, 10) if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error { m := bean.(*Mirror) if m.NextUpdate.After(time.Now()) { return nil } repoPath := filepath.Join(setting.RepoRootPath, m.RepoName+".git") if _, stderr, err := process.ExecDir(10*time.Minute, repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath), "git", "remote", "update", "--prune"); err != nil { desc := fmt.Sprintf("Fail to update mirror repository(%s): %s", repoPath, stderr) log.Error(4, desc) if err = CreateRepositoryNotice(desc); err != nil { log.Error(4, "Fail to add notice: %v", err) } return nil } m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour) mirrors = append(mirrors, m) return nil }); err != nil { log.Error(4, "MirrorUpdate: %v", err) } for i := range mirrors { if err := UpdateMirror(mirrors[i]); err != nil { log.Error(4, "UpdateMirror", fmt.Sprintf("%s: %v", mirrors[i].RepoName, err)) } } }
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID. func DeleteReleaseByID(id int64) error { rel, err := GetReleaseByID(id) if err != nil { return fmt.Errorf("GetReleaseByID: %v", err) } repo, err := GetRepositoryByID(rel.RepoID) if err != nil { return fmt.Errorf("GetRepositoryByID: %v", err) } _, stderr, err := process.ExecDir(-1, repo.RepoPath(), fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID), "git", "tag", "-d", rel.TagName) if err != nil && !strings.Contains(stderr, "not found") { return fmt.Errorf("git tag -d: %v - %s", err, stderr) } if _, err = x.Id(rel.ID).Delete(new(Release)); err != nil { return fmt.Errorf("Delete: %v", err) } return nil }
// CreateRepository creates a repository for given user or organization. func CreateRepository(u *User, name, desc, lang, license string, isPrivate, isMirror, initReadme bool) (_ *Repository, err error) { if !IsLegalName(name) { return nil, ErrRepoNameIllegal } if IsRepositoryExist(u, name) { return nil, ErrRepoAlreadyExist } repo := &Repository{ OwnerId: u.Id, Owner: u, Name: name, LowerName: strings.ToLower(name), Description: desc, IsPrivate: isPrivate, } sess := x.NewSession() defer sessionRelease(sess) if err = sess.Begin(); err != nil { return nil, err } if _, err = sess.Insert(repo); err != nil { return nil, err } else if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { return nil, err } // TODO fix code for mirrors? // Give access to all members in owner team. if u.IsOrganization() { t, err := u.getOwnerTeam(sess) if err != nil { return nil, fmt.Errorf("getOwnerTeam: %v", err) } else if err = t.addRepository(sess, repo); err != nil { return nil, fmt.Errorf("addRepository: %v", err) } } else { // Organization called this in addRepository method. if err = repo.recalculateAccesses(sess); err != nil { return nil, fmt.Errorf("recalculateAccesses: %v", err) } } if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { return nil, fmt.Errorf("watchRepo: %v", err) } else if err = newRepoAction(sess, u, repo); err != nil { return nil, fmt.Errorf("newRepoAction: %v", err) } // No need for init mirror. if !isMirror { repoPath := RepoPath(u.Name, repo.Name) if err = initRepository(sess, repoPath, u, repo, initReadme, lang, license); err != nil { if err2 := os.RemoveAll(repoPath); err2 != nil { log.Error(4, "initRepository: %v", err) return nil, fmt.Errorf( "delete repo directory %s/%s failed(2): %v", u.Name, repo.Name, err2) } return nil, fmt.Errorf("initRepository: %v", err) } _, stderr, err := process.ExecDir(-1, repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath), "git", "update-server-info") if err != nil { return nil, errors.New("CreateRepository(git update-server-info): " + stderr) } } return repo, sess.Commit() }
// InitRepository initializes README and .gitignore if needed. func initRepository(e Engine, repoPath string, u *User, repo *Repository, initReadme bool, repoLang, license string) error { // Init bare new repository. os.MkdirAll(repoPath, os.ModePerm) _, stderr, err := process.ExecDir(-1, repoPath, fmt.Sprintf("initRepository(git init --bare): %s", repoPath), "git", "init", "--bare") if err != nil { return errors.New("git init --bare: " + stderr) } if err := createUpdateHook(repoPath); err != nil { return err } // Initialize repository according to user's choice. fileName := map[string]string{} if initReadme { fileName["readme"] = "README.md" } if repoLang != "" { fileName["gitign"] = ".gitignore" } if license != "" { fileName["license"] = "LICENSE" } // Clone to temprory path and do the init commit. tmpDir := filepath.Join(os.TempDir(), com.ToStr(time.Now().Nanosecond())) os.MkdirAll(tmpDir, os.ModePerm) _, stderr, err = process.Exec( fmt.Sprintf("initRepository(git clone): %s", repoPath), "git", "clone", repoPath, tmpDir) if err != nil { return errors.New("git clone: " + stderr) } // README if initReadme { defaultReadme := repo.Name + "\n" + strings.Repeat("=", utf8.RuneCountInString(repo.Name)) + "\n\n" + repo.Description if err := ioutil.WriteFile(filepath.Join(tmpDir, fileName["readme"]), []byte(defaultReadme), 0644); err != nil { return err } } // FIXME: following two can be merged. // .gitignore // Copy custom file when available. customPath := path.Join(setting.CustomPath, "conf/gitignore", repoLang) targetPath := path.Join(tmpDir, fileName["gitign"]) if com.IsFile(customPath) { if err := com.Copy(customPath, targetPath); err != nil { return fmt.Errorf("copy gitignore: %v", err) } } else if com.IsSliceContainsStr(Gitignores, repoLang) { if err = ioutil.WriteFile(targetPath, bindata.MustAsset(path.Join("conf/gitignore", repoLang)), os.ModePerm); err != nil { return fmt.Errorf("generate gitignore: %v", err) } } else { delete(fileName, "gitign") } // LICENSE customPath = path.Join(setting.CustomPath, "conf/license", license) targetPath = path.Join(tmpDir, fileName["license"]) if com.IsFile(customPath) { if err = com.Copy(customPath, targetPath); err != nil { return fmt.Errorf("copy license: %v", err) } } else if com.IsSliceContainsStr(Licenses, license) { if err = ioutil.WriteFile(targetPath, bindata.MustAsset(path.Join("conf/license", license)), os.ModePerm); err != nil { return fmt.Errorf("generate license: %v", err) } } else { delete(fileName, "license") } if len(fileName) == 0 { // Re-fetch the repository from database before updating it (else it would // override changes that were done earlier with sql) if repo, err = getRepositoryById(e, repo.Id); err != nil { return err } repo.IsBare = true repo.DefaultBranch = "master" return updateRepository(e, repo, false) } // Apply changes and commit. return initRepoCommit(tmpDir, u.NewGitSig()) }
func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) { if IsRepositoryExist(u, name) { return nil, ErrRepoAlreadyExist } // In case the old repository is a fork. if oldRepo.IsFork { oldRepo, err = GetRepositoryById(oldRepo.ForkId) if err != nil { return nil, err } } repo := &Repository{ OwnerId: u.Id, Owner: u, Name: name, LowerName: strings.ToLower(name), Description: desc, IsPrivate: oldRepo.IsPrivate, IsFork: true, ForkId: oldRepo.Id, } sess := x.NewSession() defer sessionRelease(sess) if err = sess.Begin(); err != nil { return nil, err } if _, err = sess.Insert(repo); err != nil { return nil, err } if err = repo.recalculateAccesses(sess); err != nil { return nil, err } else if _, err = sess.Exec("UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?", u.Id); err != nil { return nil, err } if u.IsOrganization() { // Update owner team info and count. t, err := u.getOwnerTeam(sess) if err != nil { return nil, fmt.Errorf("getOwnerTeam: %v", err) } else if err = t.addRepository(sess, repo); err != nil { return nil, fmt.Errorf("addRepository: %v", err) } } else { if err = watchRepo(sess, u.Id, repo.Id, true); err != nil { return nil, fmt.Errorf("watchRepo: %v", err) } } if err = newRepoAction(sess, u, repo); err != nil { return nil, fmt.Errorf("newRepoAction: %v", err) } if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", oldRepo.Id); err != nil { return nil, err } oldRepoPath, err := oldRepo.RepoPath() if err != nil { return nil, fmt.Errorf("get old repository path: %v", err) } repoPath := RepoPath(u.Name, repo.Name) _, stderr, err := process.ExecTimeout(10*time.Minute, fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name), "git", "clone", "--bare", oldRepoPath, repoPath) if err != nil { return nil, fmt.Errorf("git clone: %v", stderr) } _, stderr, err = process.ExecDir(-1, repoPath, fmt.Sprintf("ForkRepository(git update-server-info): %s", repoPath), "git", "update-server-info") if err != nil { return nil, fmt.Errorf("git update-server-info: %v", err) } if err = createUpdateHook(repoPath); err != nil { return nil, fmt.Errorf("createUpdateHook: %v", err) } return repo, sess.Commit() }