我这人比较笨,老大让我看看Gogs,我看了半天才搞懂它的执行流程。又怕到时候忘了,只好边看边做点笔记。毕竟老话说得好,好记性不如烂笔头嘛。
Gogs从gogs.go
的main
函数开始执行,如果我们从浏览器访问,会进入cmd.web
模块。cmd.web
模块通过Macaron
注册了各种路由规则:
m := newMacaron()
...
m.Get("/", ignSignIn, routes.Home)
m.Group("/explore", func() {
m.Get("", func(c *context.Context) {
c.Redirect(setting.AppSubURL + "/explore/repos")
})
m.Get("/repos", routes.ExploreRepos)
m.Get("/users", routes.ExploreUsers)
m.Get("/organizations", routes.ExploreOrganizations)
}, ignSignIn)
m.Combo("/install", routes.InstallInit).Get(routes.Install).
Post(bindIgnErr(form.Install{}), routes.InstallPost)
m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues)
...
m.Group("/repo", func() {
m.Get("/create", repo.Create)
m.Post("/create", bindIgnErr(form.CreateRepo{}), repo.CreatePost)
m.Get("/migrate", repo.Migrate)
m.Post("/migrate", bindIgnErr(form.MigrateRepo{}), repo.MigratePost)
m.Combo("/fork/:repoid").Get(repo.Fork).
Post(bindIgnErr(form.CreateRepo{}), repo.ForkPost)
}, reqSignIn)
...
接下来我从创建仓库这一动作着手分析Gogs如何创建远端Git仓库以及如何在数据库里保存相关信息。
在浏览器里输入:
http://localhost:3000/repo/create
进入仓库创建页面,输入相关信息以后,点击创建仓库,接下来会进入repo.CreatePost
方法。
这个方法首先会将表格里的信息提取出来,然后通过调用models模块的 CreateRepository
方法完成仓库的创建以及数据库的记录:
func CreatePost(c *context.Context, f form.CreateRepo) {
...
c.Data["Gitignores"] = models.Gitignores
c.Data["Licenses"] = models.Licenses
c.Data["Readmes"] = models.Readmes
...
repo, err := models.CreateRepository(c.User, ctxUser, models.CreateRepoOptions{
Name: f.RepoName,
Description: f.Description,
Gitignores: f.Gitignores,
License: f.License,
Readme: f.Readme,
IsPrivate: f.Private || setting.Repository.ForcePrivate,
AutoInit: f.AutoInit,
})
...
}
这里的 CreateRepository
方法通过调用createRepository
向数据库里插入数据,调用initRepository
初始化远程仓库。并运用Transaction保证了数据库的内容与仓库的内容一致
// CreateRepository creates a repository for given user or organization.
func CreateRepository(doer, owner *User, opts CreateRepoOptions) (_ *Repository, err error) {
...
repo := &Repository{
OwnerID: owner.ID,
...
}
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return nil, err
}
if err = createRepository(sess, doer, owner, repo); err != nil {
return nil, err
}
// No need for init mirror.
if !opts.IsMirror {
repoPath := RepoPath(owner.Name, repo.Name)
if err = initRepository(sess, repoPath, doer, repo, opts); err != nil {
RemoveAllWithNotice("Delete repository for initialization failure", repoPath)
return nil, fmt.Errorf("initRepository: %v", err)
}
...
}
return repo, sess.Commit()
}
整个应用的大致流程就是这个样子。值得一提的是之前并不知道go怎么执行git命令,后来看了下源码,大概就是运用os.exec
传递需要执行的命令以及参数来执行git命令。