diff --git a/.gitignore b/.gitignore index 9825b96ee..0bca5df1d 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ _testmain.go coverage.out /modules/public/bindata.go +/modules/templates/bindata.go *.db *.log diff --git a/cmd/web.go b/cmd/web.go index 544285056..dfb3ac238 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -7,7 +7,6 @@ package cmd import ( "crypto/tls" "fmt" - "io/ioutil" "net" "net/http" "net/http/fcgi" @@ -15,7 +14,6 @@ import ( "path" "strings" - "code.gitea.io/git" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/bindata" @@ -23,7 +21,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/public" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/template" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers/admin" apiv1 "code.gitea.io/gitea/routers/api/v1" @@ -39,10 +37,7 @@ import ( "github.com/go-macaron/i18n" "github.com/go-macaron/session" "github.com/go-macaron/toolbox" - "github.com/go-xorm/xorm" - version "github.com/mcuadros/go-version" "github.com/urfave/cli" - ini "gopkg.in/ini.v1" macaron "gopkg.in/macaron.v1" ) @@ -74,45 +69,6 @@ type VerChecker struct { Expected string } -// checkVersion checks if binary matches the version of templates files. -func checkVersion() { - // Templates. - data, err := ioutil.ReadFile(setting.StaticRootPath + "/templates/.VERSION") - if err != nil { - log.Fatal(4, "Fail to read 'templates/.VERSION': %v", err) - } - tplVer := string(data) - if tplVer != setting.AppVer { - if version.Compare(tplVer, setting.AppVer, ">") { - log.Fatal(4, "Binary version is lower than template file version, did you forget to recompile Gogs?") - } else { - log.Fatal(4, "Binary version is higher than template file version, did you forget to update template files?") - } - } - - // Check dependency version. - checkers := []VerChecker{ - {"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.5.5"}, - {"github.com/go-macaron/binding", binding.Version, "0.3.2"}, - {"github.com/go-macaron/cache", cache.Version, "0.1.2"}, - {"github.com/go-macaron/csrf", csrf.Version, "0.1.0"}, - {"github.com/go-macaron/i18n", i18n.Version, "0.3.0"}, - {"github.com/go-macaron/session", session.Version, "0.1.6"}, - {"github.com/go-macaron/toolbox", toolbox.Version, "0.1.0"}, - {"gopkg.in/ini.v1", ini.Version, "1.8.4"}, - {"gopkg.in/macaron.v1", macaron.Version, "1.1.7"}, - {"code.gitea.io/git", git.Version, "0.4.1"}, - } - for _, c := range checkers { - if !version.Compare(c.Version(), c.Expected, ">=") { - log.Fatal(4, `Dependency outdated! -Package '%s' current version (%s) is below requirement (%s), -please use following command to update this package and recompile Gogs: -go get -u %[1]s`, c.ImportPath, c.Version(), c.Expected) - } - } -} - // newMacaron initializes Macaron instance. func newMacaron() *macaron.Macaron { m := macaron.New() @@ -140,15 +96,8 @@ func newMacaron() *macaron.Macaron { }, )) - funcMap := template.NewFuncMap() - m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: path.Join(setting.StaticRootPath, "templates"), - AppendDirectories: []string{path.Join(setting.CustomPath, "templates")}, - Funcs: funcMap, - IndentJSON: macaron.Env != macaron.PROD, - })) - models.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"), - path.Join(setting.CustomPath, "templates/mail"), funcMap) + m.Use(templates.Renderer()) + models.InitMailRender(templates.Mailer()) localeNames, err := bindata.AssetDir("conf/locale") if err != nil { @@ -200,7 +149,6 @@ func runWeb(ctx *cli.Context) error { setting.CustomConf = ctx.String("config") } routers.GlobalInit() - checkVersion() m := newMacaron() diff --git a/models/git_diff.go b/models/git_diff.go index b8f9cacec..fe99f61bf 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -18,10 +18,10 @@ import ( "code.gitea.io/git" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/template/highlight" "github.com/Unknwon/com" "github.com/sergi/go-diff/diffmatchpatch" "golang.org/x/net/html/charset" diff --git a/models/mail.go b/models/mail.go index f89e38e62..a5e9bd551 100644 --- a/models/mail.go +++ b/models/mail.go @@ -5,18 +5,18 @@ package models import ( + "bytes" "fmt" "html/template" "path" - "gopkg.in/gomail.v2" - "gopkg.in/macaron.v1" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/mailer" "code.gitea.io/gitea/modules/markdown" "code.gitea.io/gitea/modules/setting" + "gopkg.in/gomail.v2" + "gopkg.in/macaron.v1" ) const ( @@ -31,27 +31,11 @@ const ( mailNotifyCollaborator base.TplName = "notify/collaborator" ) -type mailRenderInterface interface { - HTMLString(string, interface{}, ...macaron.HTMLOptions) (string, error) -} - -var mailRender mailRenderInterface +var templates *template.Template // InitMailRender initializes the macaron mail renderer -func InitMailRender(dir, appendDir string, funcMap []template.FuncMap) { - opt := &macaron.RenderOptions{ - Directory: dir, - AppendDirectories: []string{appendDir}, - Funcs: funcMap, - Extensions: []string{".tmpl", ".html"}, - } - ts := macaron.NewTemplateSet() - ts.Set(macaron.DEFAULT_TPL_SET_NAME, opt) - - mailRender = &macaron.TplRender{ - TemplateSet: ts, - Opt: opt, - } +func InitMailRender(tmpls *template.Template) { + templates = tmpls } // SendTestMail sends a test mail @@ -67,13 +51,15 @@ func SendUserMail(c *macaron.Context, u *User, tpl base.TplName, code, subject, "ResetPwdCodeLives": setting.Service.ResetPwdCodeLives / 60, "Code": code, } - body, err := mailRender.HTMLString(string(tpl), data) - if err != nil { - log.Error(3, "HTMLString: %v", err) + + var content bytes.Buffer + + if err := templates.ExecuteTemplate(&content, string(tpl), data); err != nil { + log.Error(3, "Template: %v", err) return } - msg := mailer.NewMessage([]string{u.Email}, subject, body) + msg := mailer.NewMessage([]string{u.Email}, subject, content.String()) msg.Info = fmt.Sprintf("UID: %d, %s", u.ID, info) mailer.SendAsync(msg) @@ -97,13 +83,15 @@ func SendActivateEmailMail(c *macaron.Context, u *User, email *EmailAddress) { "Code": u.GenerateEmailActivateCode(email.Email), "Email": email.Email, } - body, err := mailRender.HTMLString(string(mailAuthActivateEmail), data) - if err != nil { - log.Error(3, "HTMLString: %v", err) + + var content bytes.Buffer + + if err := templates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil { + log.Error(3, "Template: %v", err) return } - msg := mailer.NewMessage([]string{email.Email}, c.Tr("mail.activate_email"), body) + msg := mailer.NewMessage([]string{email.Email}, c.Tr("mail.activate_email"), content.String()) msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID) mailer.SendAsync(msg) @@ -114,13 +102,15 @@ func SendRegisterNotifyMail(c *macaron.Context, u *User) { data := map[string]interface{}{ "Username": u.DisplayName(), } - body, err := mailRender.HTMLString(string(mailAuthRegisterNotify), data) - if err != nil { - log.Error(3, "HTMLString: %v", err) + + var content bytes.Buffer + + if err := templates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil { + log.Error(3, "Template: %v", err) return } - msg := mailer.NewMessage([]string{u.Email}, c.Tr("mail.register_notify"), body) + msg := mailer.NewMessage([]string{u.Email}, c.Tr("mail.register_notify"), content.String()) msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID) mailer.SendAsync(msg) @@ -136,13 +126,15 @@ func SendCollaboratorMail(u, doer *User, repo *Repository) { "RepoName": repoName, "Link": repo.HTMLURL(), } - body, err := mailRender.HTMLString(string(mailNotifyCollaborator), data) - if err != nil { - log.Error(3, "HTMLString: %v", err) + + var content bytes.Buffer + + if err := templates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil { + log.Error(3, "Template: %v", err) return } - msg := mailer.NewMessage([]string{u.Email}, subject, body) + msg := mailer.NewMessage([]string{u.Email}, subject, content.String()) msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID) mailer.SendAsync(msg) @@ -161,11 +153,14 @@ func composeIssueMessage(issue *Issue, doer *User, tplName base.TplName, tos []s body := string(markdown.RenderSpecialLink([]byte(issue.Content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas())) data := composeTplData(subject, body, issue.HTMLURL()) data["Doer"] = doer - content, err := mailRender.HTMLString(string(tplName), data) - if err != nil { - log.Error(3, "HTMLString (%s): %v", tplName, err) + + var content bytes.Buffer + + if err := templates.ExecuteTemplate(&content, string(tplName), data); err != nil { + log.Error(3, "Template: %v", err) } - msg := mailer.NewMessageFrom(tos, fmt.Sprintf(`"%s" <%s>`, doer.DisplayName(), setting.MailService.FromEmail), subject, content) + + msg := mailer.NewMessageFrom(tos, fmt.Sprintf(`"%s" <%s>`, doer.DisplayName(), setting.MailService.FromEmail), subject, content.String()) msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info) return msg } diff --git a/modules/template/highlight/highlight.go b/modules/highlight/highlight.go similarity index 100% rename from modules/template/highlight/highlight.go rename to modules/highlight/highlight.go diff --git a/modules/public/public.go b/modules/public/public.go index 261ed8887..9c9e9d533 100644 --- a/modules/public/public.go +++ b/modules/public/public.go @@ -6,6 +6,8 @@ package public //go:generate go-bindata -tags "bindata" -ignore "\\.go|\\.less" -pkg "public" -o "bindata.go" ../../public/... //go:generate go fmt bindata.go +//go:generate sed -i.bak s/..\/..\/public\/// bindata.go +//go:generate rm -f bindata.go.bak // Options represents the available options to configure the macaron handler. type Options struct { diff --git a/modules/public/static.go b/modules/public/static.go index 8184bc214..f68400d32 100644 --- a/modules/public/static.go +++ b/modules/public/static.go @@ -22,7 +22,7 @@ func Static(opts *Options) macaron.Handler { AssetDir: AssetDir, AssetInfo: AssetInfo, AssetNames: AssetNames, - Prefix: "../../public", + Prefix: "", }), }, ) diff --git a/modules/templates/dynamic.go b/modules/templates/dynamic.go new file mode 100644 index 000000000..c127b6947 --- /dev/null +++ b/modules/templates/dynamic.go @@ -0,0 +1,103 @@ +// +build !bindata + +// Copyright 2016 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 templates + +import ( + "html/template" + "io/ioutil" + "path" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "github.com/Unknwon/com" + "gopkg.in/macaron.v1" +) + +var ( + templates = template.New("") +) + +// Renderer implements the macaron handler for serving the templates. +func Renderer() macaron.Handler { + return macaron.Renderer(macaron.RenderOptions{ + Funcs: NewFuncMap(), + Directory: path.Join(setting.StaticRootPath, "templates"), + AppendDirectories: []string{ + path.Join(setting.CustomPath, "templates"), + }, + }) +} + +// Mailer provides the templates required for sending notification mails. +func Mailer() *template.Template { + for _, funcs := range NewFuncMap() { + templates.Funcs(funcs) + } + + staticDir := path.Join(setting.StaticRootPath, "templates", "mail") + + if com.IsDir(staticDir) { + files, err := com.StatDir(staticDir) + + if err != nil { + log.Warn("Failed to read %s templates dir. %v", staticDir, err) + } else { + for _, filePath := range files { + if !strings.HasSuffix(filePath, ".tmpl") { + continue + } + + content, err := ioutil.ReadFile(path.Join(staticDir, filePath)) + + if err != nil { + log.Warn("Failed to read static %s template. %v", filePath, err) + continue + } + + templates.New( + strings.TrimSuffix( + filePath, + ".tmpl", + ), + ).Parse(string(content)) + } + } + } + + customDir := path.Join(setting.CustomPath, "templates", "mail") + + if com.IsDir(customDir) { + files, err := com.StatDir(customDir) + + if err != nil { + log.Warn("Failed to read %s templates dir. %v", customDir, err) + } else { + for _, filePath := range files { + if !strings.HasSuffix(filePath, ".tmpl") { + continue + } + + content, err := ioutil.ReadFile(path.Join(customDir, filePath)) + + if err != nil { + log.Warn("Failed to read custom %s template. %v", filePath, err) + continue + } + + templates.New( + strings.TrimSuffix( + filePath, + ".tmpl", + ), + ).Parse(string(content)) + } + } + } + + return templates +} diff --git a/modules/template/template.go b/modules/templates/helper.go similarity index 99% rename from modules/template/template.go rename to modules/templates/helper.go index 65d78c2f6..c25645539 100644 --- a/modules/template/template.go +++ b/modules/templates/helper.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package template +package templates import ( "container/list" diff --git a/modules/templates/static.go b/modules/templates/static.go new file mode 100644 index 000000000..5c9903cde --- /dev/null +++ b/modules/templates/static.go @@ -0,0 +1,109 @@ +// +build bindata + +// Copyright 2016 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 templates + +import ( + "html/template" + "io/ioutil" + "path" + "strings" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "github.com/Unknwon/com" + "github.com/go-macaron/bindata" + "gopkg.in/macaron.v1" +) + +var ( + templates = template.New("") +) + +// Renderer implements the macaron handler for serving the templates. +func Renderer() macaron.Handler { + return macaron.Renderer(macaron.RenderOptions{ + Funcs: NewFuncMap(), + AppendDirectories: []string{ + path.Join(setting.CustomPath, "templates"), + }, + TemplateFileSystem: bindata.Templates( + bindata.Options{ + Asset: Asset, + AssetDir: AssetDir, + AssetInfo: AssetInfo, + AssetNames: AssetNames, + Prefix: "", + }, + ), + }) +} + +// Mailer provides the templates required for sending notification mails. +func Mailer() *template.Template { + for _, funcs := range NewFuncMap() { + templates.Funcs(funcs) + } + + for _, assetPath := range AssetNames() { + if !strings.HasPrefix(assetPath, "mail/") { + continue + } + + if !strings.HasSuffix(assetPath, ".tmpl") { + continue + } + + content, err := Asset(assetPath) + + if err != nil { + log.Warn("Failed to read embedded %s template. %v", assetPath, err) + continue + } + + templates.New( + strings.TrimPrefix( + strings.TrimSuffix( + assetPath, + ".tmpl", + ), + "mail/", + ), + ).Parse(string(content)) + } + + customDir := path.Join(setting.CustomPath, "templates", "mail") + + if com.IsDir(customDir) { + files, err := com.StatDir(customDir) + + if err != nil { + log.Warn("Failed to read %s templates dir. %v", customDir, err) + } else { + for _, filePath := range files { + if !strings.HasSuffix(filePath, ".tmpl") { + continue + } + + content, err := ioutil.ReadFile(path.Join(customDir, filePath)) + + if err != nil { + log.Warn("Failed to read custom %s template. %v", filePath, err) + continue + } + + templates.New( + strings.TrimSuffix( + filePath, + ".tmpl", + ), + ).Parse(string(content)) + } + } + } + + return templates +} diff --git a/modules/templates/templates.go b/modules/templates/templates.go new file mode 100644 index 000000000..91c8db522 --- /dev/null +++ b/modules/templates/templates.go @@ -0,0 +1,10 @@ +// Copyright 2016 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 templates + +//go:generate go-bindata -tags "bindata" -ignore "\\.go" -pkg "templates" -o "bindata.go" ../../templates/... +//go:generate go fmt bindata.go +//go:generate sed -i.bak s/..\/..\/templates\/// bindata.go +//go:generate rm -f bindata.go.bak diff --git a/routers/init.go b/routers/init.go index b6b9911c8..3d5235d79 100644 --- a/routers/init.go +++ b/routers/init.go @@ -11,12 +11,12 @@ import ( "code.gitea.io/git" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/cron" + "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/mailer" "code.gitea.io/gitea/modules/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/ssh" - "code.gitea.io/gitea/modules/template/highlight" macaron "gopkg.in/macaron.v1" ) diff --git a/routers/repo/editor.go b/routers/repo/editor.go index f037b39b2..8d45521a2 100644 --- a/routers/repo/editor.go +++ b/routers/repo/editor.go @@ -18,7 +18,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/template" + "code.gitea.io/gitea/modules/templates" ) const ( @@ -74,7 +74,7 @@ func editFile(ctx *context.Context, isNewFile bool) { d, _ := ioutil.ReadAll(dataRc) buf = append(buf, d...) - if content, err := template.ToUTF8WithErr(buf); err != nil { + if content, err := templates.ToUTF8WithErr(buf); err != nil { if err != nil { log.Error(4, "ToUTF8WithErr: %v", err) } diff --git a/routers/repo/view.go b/routers/repo/view.go index 3ef3716f2..4417383bd 100644 --- a/routers/repo/view.go +++ b/routers/repo/view.go @@ -16,11 +16,11 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/highlight" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markdown" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/template" - "code.gitea.io/gitea/modules/template/highlight" + "code.gitea.io/gitea/modules/templates" "github.com/Unknwon/paginater" ) @@ -164,7 +164,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } else { // Building code view blocks with line number on server side. var fileContent string - if content, err := template.ToUTF8WithErr(buf); err != nil { + if content, err := templates.ToUTF8WithErr(buf); err != nil { if err != nil { log.Error(4, "ToUTF8WithErr: %s", err) } diff --git a/templates/.VERSION b/templates/.VERSION deleted file mode 100644 index 927f673c5..000000000 --- a/templates/.VERSION +++ /dev/null @@ -1 +0,0 @@ -0.9.99.0915 \ No newline at end of file