Verified Commit f7c1894e authored by Loïc Dachary's avatar Loïc Dachary
Browse files

repo: add a .projectbase repository to each project



Same as .wiki
Signed-off-by: Loïc Dachary's avatarLoïc Dachary <loic@dachary.org>
parent 8c1a9a51
......@@ -926,6 +926,11 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository wiki", repo.WikiPath())
}
// Remove projectbase files
if repo.HasProjectBase() {
admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository projectbase", repo.ProjectBasePath())
}
// Remove archives
for i := range archivePaths {
admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.RepoArchives, "Delete repo archive file", archivePaths[i])
......
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"path/filepath"
"strings"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
)
// ProjectBaseCloneLink function
func (repo *Repository) ProjectBaseCloneLink() *CloneLink {
return repo.cloneLink(".projectbase")
}
// ProjectBasePath function
func ProjectBasePath(userName, repoName string) string {
return filepath.Join(user_model.UserPath(userName), strings.ToLower(repoName)+".projectbase.git")
}
// ProjectBasePath function
func (repo *Repository) ProjectBasePath() string {
return ProjectBasePath(repo.OwnerName, repo.Name)
}
// HasProjectBase function
func (repo *Repository) HasProjectBase() bool {
isDir, err := util.IsDir(repo.ProjectBasePath())
if err != nil {
log.Error("Unable to check if %s is a directory: %v", repo.ProjectBasePath(), err)
}
return isDir
}
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"os"
"path/filepath"
"testing"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
func TestRepository_ProjectBaseCloneLink(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
cloneLink := repo.ProjectBaseCloneLink()
assert.Equal(t, "ssh://runuser@try.gitea.io:3000/user2/repo1.projectbase.git", cloneLink.SSH)
assert.Equal(t, "https://try.gitea.io/user2/repo1.projectbase.git", cloneLink.HTTPS)
}
func TestProjectBasePath(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
expected := filepath.Join(setting.RepoRootPath, "user2/repo1.projectbase.git")
assert.Equal(t, expected, ProjectBasePath("user2", "repo1"))
}
func TestRepository_ProjectBasePath(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
expected := filepath.Join(setting.RepoRootPath, "user2/repo1.projectbase.git")
assert.Equal(t, expected, repo.ProjectBasePath())
}
func TestRepository_HasProjectBase(t *testing.T) {
unittest.PrepareTestEnv(t)
repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
assert.False(t, repo1.HasProjectBase())
os.MkdirAll(ProjectBasePath("user2", "repo1"), os.ModePerm)
assert.True(t, repo1.HasProjectBase())
}
......@@ -27,7 +27,7 @@ import (
var (
reservedRepoNames = []string{".", ".."}
reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"}
reservedRepoPatterns = []string{"*.git", "*.wiki", "*.projectbase", "*.rss", "*.atom"}
)
// IsUsableRepoName returns true when repository is usable
......
......@@ -165,6 +165,18 @@ func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName s
}
}
projectBasePath := repo.ProjectBasePath()
isExist, err = util.IsExist(projectBasePath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", projectBasePath, err)
return err
}
if isExist {
if err = util.Rename(projectBasePath, ProjectBasePath(repo.Owner.Name, newRepoName)); err != nil {
return fmt.Errorf("rename repository projectbase: %v", err)
}
}
ctx, committer, err := db.TxContext()
if err != nil {
return err
......
......@@ -208,10 +208,11 @@ func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int
func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_model.Repository) (err error) {
repoRenamed := false
wikiRenamed := false
projectBaseRenamed := false
oldOwnerName := doer.Name
defer func() {
if !repoRenamed && !wikiRenamed {
if !repoRenamed && !wikiRenamed && !projectBaseRenamed {
return
}
......@@ -234,6 +235,12 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
}
}
if projectBaseRenamed {
if err := util.Rename(repo_model.ProjectBasePath(newOwnerName, repo.Name), repo_model.ProjectBasePath(oldOwnerName, repo.Name)); err != nil {
log.Critical("Unable to move projectbase for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name, repo_model.ProjectBasePath(newOwnerName, repo.Name), repo_model.ProjectBasePath(oldOwnerName, repo.Name), err)
}
}
if recoverErr != nil {
log.Error("Panic within TransferOwnership: %v\n%s", recoverErr, log.Stack(2))
panic(recoverErr)
......@@ -404,6 +411,19 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
wikiRenamed = true
}
// Rename remote projectbase repository to new path and delete local copy.
projectBasePath := repo_model.ProjectBasePath(oldOwner.Name, repo.Name)
if isExist, err := util.IsExist(projectBasePath); err != nil {
log.Error("Unable to check if %s exists. Error: %v", projectBasePath, err)
return err
} else if isExist {
if err := util.Rename(projectBasePath, repo_model.ProjectBasePath(newOwner.Name, repo.Name)); err != nil {
return fmt.Errorf("rename repository projectbase: %v", err)
}
projectBaseRenamed = true
}
if err := deleteRepositoryTransfer(ctx, repo.ID); err != nil {
return fmt.Errorf("deleteRepositoryTransfer: %v", err)
}
......
......@@ -525,6 +525,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
ctx.Data["RepoSearchEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["CloneLink"] = repo.CloneLink()
ctx.Data["WikiCloneLink"] = repo.WikiCloneLink()
ctx.Data["ProjectBaseCloneLink"] = repo.ProjectBaseCloneLink()
if ctx.IsSigned {
ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx.User.ID, repo.ID)
......
......@@ -172,6 +172,11 @@ func newDownloader(ctx context.Context, ownerName string, opts base.MigrateOptio
return downloader, nil
}
// InternalMigrateRepository function
func InternalMigrateRepository(downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions) error {
return migrateRepository(downloader, uploader, opts, nil)
}
// migrateRepository will download information and then upload it to Uploader, this is a simple
// process for small repository. For a big repository, save all the data to disk
// before upload is better
......
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package projectbase
import (
"fmt"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
)
// InitProjectBase function
func InitProjectBase(repo *repo_model.Repository) error {
if repo.HasProjectBase() {
return nil
}
if err := git.InitRepository(repo.ProjectBasePath(), true); err != nil {
return fmt.Errorf("InitRepository: %v", err)
} else if _, err = git.NewCommand("symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(repo.ProjectBasePath()); err != nil {
return fmt.Errorf("unable to set default branch to master: %v", err)
}
return nil
}
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package projectbase
import (
"path/filepath"
"testing"
_ "code.gitea.io/gitea/models"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
unittest.MainTest(m, filepath.Join("..", ".."))
}
func TestRepository_InitProjectBase(t *testing.T) {
unittest.PrepareTestEnv(t)
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
assert.False(t, repo1.HasProjectBase())
assert.NoError(t, InitProjectBase(repo1))
assert.True(t, repo1.HasProjectBase())
}
......@@ -41,6 +41,11 @@ func NewTemporaryUploadRepository(repo *repo_model.Repository) (*TemporaryUpload
return t, nil
}
// BasePath function
func (t *TemporaryUploadRepository) BasePath() string {
return t.basePath
}
// Close the repository cleaning up all files
func (t *TemporaryUploadRepository) Close() {
defer t.gitRepo.Close()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment