mirror of https://github.com/gogs/gogs.git
Use go-bindata to embed `public` and `templates` files into binary (#5920)
* fixed private repositories are hidden in the organization's view * use go-bindata integrate public and templates files to gogs binary * optimize Dockerfile don't COPY public and templates files * use kevinburke's go-bindata to generate assets code * reset develepment as default run mode in configure file * optimize generated assets code relayout and help function * fixed code format * Update conf/app.ini * assets: add LICENSE headers * Some housekeeping * assets/public: simplify code logic * assets/templates: simplify code logic * cmd/web: more concise variable names * Minor changes * Add custom public and templates support back Co-authored-by: ᴜɴᴋɴᴡᴏɴ <u@gogs.io>pull/5927/head
parent
fd14ad6ce9
commit
4d83fd4238
|
@ -33,8 +33,6 @@ COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||||
|
|
||||||
WORKDIR /app/gogs
|
WORKDIR /app/gogs
|
||||||
COPY docker ./docker
|
COPY docker ./docker
|
||||||
COPY templates ./templates
|
|
||||||
COPY public ./public
|
|
||||||
COPY --from=binarybuilder /go/src/github.com/gogs/gogs/gogs .
|
COPY --from=binarybuilder /go/src/github.com/gogs/gogs/gogs .
|
||||||
|
|
||||||
RUN ./docker/finalize.sh
|
RUN ./docker/finalize.sh
|
||||||
|
|
|
@ -22,8 +22,6 @@ ENV GOGS_CUSTOM /data/gogs
|
||||||
# Configure LibC Name Service
|
# Configure LibC Name Service
|
||||||
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||||
COPY docker /app/gogs/docker
|
COPY docker /app/gogs/docker
|
||||||
COPY templates /app/gogs/templates
|
|
||||||
COPY public /app/gogs/public
|
|
||||||
|
|
||||||
WORKDIR /app/gogs/build
|
WORKDIR /app/gogs/build
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
|
@ -24,8 +24,6 @@ RUN chmod +x /usr/sbin/gosu \
|
||||||
|
|
||||||
|
|
||||||
COPY docker /app/gogs/docker
|
COPY docker /app/gogs/docker
|
||||||
COPY templates /app/gogs/templates
|
|
||||||
COPY public /app/gogs/public
|
|
||||||
WORKDIR /app/gogs/build
|
WORKDIR /app/gogs/build
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,6 @@ ENV GOGS_CUSTOM /data/gogs
|
||||||
# Configure LibC Name Service
|
# Configure LibC Name Service
|
||||||
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||||
COPY docker /app/gogs/docker
|
COPY docker /app/gogs/docker
|
||||||
COPY templates /app/gogs/templates
|
|
||||||
COPY public /app/gogs/public
|
|
||||||
|
|
||||||
WORKDIR /app/gogs/build
|
WORKDIR /app/gogs/build
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
|
@ -36,8 +36,6 @@ RUN chmod +x /usr/sbin/gosu \
|
||||||
# Configure LibC Name Service
|
# Configure LibC Name Service
|
||||||
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||||
COPY docker /app/gogs/docker
|
COPY docker /app/gogs/docker
|
||||||
COPY templates /app/gogs/templates
|
|
||||||
COPY public /app/gogs/public
|
|
||||||
|
|
||||||
WORKDIR /app/gogs/build
|
WORKDIR /app/gogs/build
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
32
Makefile
32
Makefile
|
@ -1,9 +1,12 @@
|
||||||
LDFLAGS += -X "gogs.io/gogs/internal/setting.BuildTime=$(shell date -u '+%Y-%m-%d %I:%M:%S %Z')"
|
LDFLAGS += -X "gogs.io/gogs/internal/setting.BuildTime=$(shell date -u '+%Y-%m-%d %I:%M:%S %Z')"
|
||||||
LDFLAGS += -X "gogs.io/gogs/internal/setting.BuildGitHash=$(shell git rev-parse HEAD)"
|
LDFLAGS += -X "gogs.io/gogs/internal/setting.BuildCommit=$(shell git rev-parse HEAD)"
|
||||||
|
|
||||||
DATA_FILES := $(shell find conf | sed 's/ /\\ /g')
|
CONF_FILES := $(shell find conf | sed 's/ /\\ /g')
|
||||||
|
TEMPLATES_FILES := $(shell find templates | sed 's/ /\\ /g')
|
||||||
|
PUBLIC_FILES := $(shell find public | sed 's/ /\\ /g')
|
||||||
LESS_FILES := $(wildcard public/less/gogs.less public/less/_*.less)
|
LESS_FILES := $(wildcard public/less/gogs.less public/less/_*.less)
|
||||||
GENERATED := internal/bindata/bindata.go public/css/gogs.css
|
ASSETS_GENERATED := internal/assets/conf/conf_gen.go internal/assets/templates/templates_gen.go internal/assets/public/public_gen.go
|
||||||
|
GENERATED := $(ASSETS_GENERATED) public/css/gogs.css
|
||||||
|
|
||||||
OS := $(shell uname)
|
OS := $(shell uname)
|
||||||
|
|
||||||
|
@ -15,7 +18,7 @@ RELEASE_GOGS = "release/gogs"
|
||||||
NOW = $(shell date -u '+%Y%m%d%I%M%S')
|
NOW = $(shell date -u '+%Y%m%d%I%M%S')
|
||||||
GOVET = go tool vet -composites=false -methods=false -structtags=false
|
GOVET = go tool vet -composites=false -methods=false -structtags=false
|
||||||
|
|
||||||
.PHONY: build pack release bindata clean
|
.PHONY: build pack release generate clean
|
||||||
|
|
||||||
.IGNORE: public/css/gogs.css
|
.IGNORE: public/css/gogs.css
|
||||||
|
|
||||||
|
@ -45,16 +48,27 @@ build-dev-race: $(GENERATED) govet
|
||||||
pack:
|
pack:
|
||||||
rm -rf $(RELEASE_GOGS)
|
rm -rf $(RELEASE_GOGS)
|
||||||
mkdir -p $(RELEASE_GOGS)
|
mkdir -p $(RELEASE_GOGS)
|
||||||
cp -r gogs LICENSE README.md README_ZH.md templates public scripts $(RELEASE_GOGS)
|
cp -r gogs LICENSE README.md README_ZH.md scripts $(RELEASE_GOGS)
|
||||||
rm -rf $(RELEASE_GOGS)/public/config.codekit $(RELEASE_GOGS)/public/less
|
|
||||||
cd $(RELEASE_ROOT) && zip -r gogs.$(NOW).zip "gogs"
|
cd $(RELEASE_ROOT) && zip -r gogs.$(NOW).zip "gogs"
|
||||||
|
|
||||||
release: build pack
|
release: build pack
|
||||||
|
|
||||||
bindata: internal/bindata/bindata.go
|
generate: $(ASSETS_GENERATED)
|
||||||
|
|
||||||
internal/bindata/bindata.go: $(DATA_FILES)
|
internal/assets/conf/conf_gen.go: $(CONF_FILES)
|
||||||
go-bindata -o=$@ -ignore="\\.DS_Store|README.md|TRANSLATORS|auth.d" -pkg=bindata conf/...
|
-rm -f $@
|
||||||
|
go generate internal/assets/conf/conf.go
|
||||||
|
gofmt -s -w $@
|
||||||
|
|
||||||
|
internal/assets/templates/templates_gen.go: $(TEMPLATES_FILES)
|
||||||
|
-rm -f $@
|
||||||
|
go generate internal/assets/templates/templates.go
|
||||||
|
gofmt -s -w $@
|
||||||
|
|
||||||
|
internal/assets/public/public_gen.go: $(PUBLIC_FILES)
|
||||||
|
-rm -f $@
|
||||||
|
go generate internal/assets/public/public.go
|
||||||
|
gofmt -s -w $@
|
||||||
|
|
||||||
less: public/css/gogs.css
|
less: public/css/gogs.css
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
After change anything (other than this file) in this directory, a re-run of the following command in the root directory of this repository is required:
|
After change anything (other than this file) in this directory, a re-run of the following command in the root directory of this repository is required:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ make bindata
|
$ make generate
|
||||||
```
|
```
|
||||||
|
|
||||||
To install the `go-bindata`, please see https://github.com/kevinburke/go-bindata#installation.
|
To install the `go-bindata`, please see https://github.com/kevinburke/go-bindata#installation.
|
||||||
|
|
|
@ -61,8 +61,9 @@ KEY_FILE = custom/https/key.pem
|
||||||
; Allowed TLS version values: SSL30, TLS10, TLS11, TLS12
|
; Allowed TLS version values: SSL30, TLS10, TLS11, TLS12
|
||||||
TLS_MIN_VERSION = TLS10
|
TLS_MIN_VERSION = TLS10
|
||||||
|
|
||||||
; Upper level of template and static file path
|
; Enable to load assets (i.e. "conf", "templates", "public") from disk instead of embedded bindata.
|
||||||
; default is the path where Gogs is executed
|
LOAD_ASSETS_FROM_DISK = false
|
||||||
|
; The directory that contains "templates" and "public". By default, it is the working directory.
|
||||||
STATIC_ROOT_PATH =
|
STATIC_ROOT_PATH =
|
||||||
; Default path for App data
|
; Default path for App data
|
||||||
APP_DATA_PATH = data
|
APP_DATA_PATH = data
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -80,8 +80,6 @@ github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQ
|
||||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk=
|
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk=
|
||||||
github.com/gogs/git-module v0.8.3 h1:9f8oxSs9OACWrGBYMVnnQNzyTcVN+zzcBM7CXnbmezw=
|
github.com/gogs/git-module v0.8.3 h1:9f8oxSs9OACWrGBYMVnnQNzyTcVN+zzcBM7CXnbmezw=
|
||||||
github.com/gogs/git-module v0.8.3/go.mod h1:aj4tcm7DxaszJWpZLZIRL6gfPXyguAHiE1PDfAAPrCw=
|
github.com/gogs/git-module v0.8.3/go.mod h1:aj4tcm7DxaszJWpZLZIRL6gfPXyguAHiE1PDfAAPrCw=
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20190710002546-4c3c18947c15 h1:tgEyCCe4+o8A2K/PEi9lF0QMA6XK+Y/j/WN01LnNbbo=
|
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20190710002546-4c3c18947c15/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4 h1:C7NryI/RQhsIWwC2bHN601P1wJKeuQ6U/UCOYTn3Cic=
|
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4 h1:C7NryI/RQhsIWwC2bHN601P1wJKeuQ6U/UCOYTn3Cic=
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
||||||
github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0 h1:K02vod+sn3M1OOkdqi2tPxN2+xESK4qyITVQ3JkGEv4=
|
github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0 h1:K02vod+sn3M1OOkdqi2tPxN2+xESK4qyITVQ3JkGEv4=
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package assets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsErrNotFound returns true if the error is asset not found.
|
||||||
|
func IsErrNotFound(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return strings.Contains(err.Error(), "not found")
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Copyright 2020 The Gogs 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 conf
|
||||||
|
|
||||||
|
//go:generate go-bindata -nomemcopy -pkg=conf -ignore="\\.DS_Store|README.md|TRANSLATORS|auth.d" -prefix=../../../ -debug=false -o=conf_gen.go ../../../conf/...
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,143 @@
|
||||||
|
// Copyright 2020 The Gogs 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 public
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gogs.io/gogs/internal/assets"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go-bindata -nomemcopy -pkg=public -ignore="\\.DS_Store|less" -prefix=../../../public -debug=false -o=public_gen.go ../../../public/...
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is a modified version of https://github.com/go-bindata/go-bindata/pull/18.
|
||||||
|
*/
|
||||||
|
|
||||||
|
type fileInfo struct {
|
||||||
|
name string
|
||||||
|
size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d fileInfo) Name() string {
|
||||||
|
return d.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d fileInfo) Size() int64 {
|
||||||
|
return d.size
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d fileInfo) Mode() os.FileMode {
|
||||||
|
return os.FileMode(0644) | os.ModeDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d fileInfo) ModTime() time.Time {
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDir return file whether a directory
|
||||||
|
func (d *fileInfo) IsDir() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d fileInfo) Sys() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// file implements the http.File interface.
|
||||||
|
type file struct {
|
||||||
|
name string
|
||||||
|
*bytes.Reader
|
||||||
|
|
||||||
|
children []os.FileInfo
|
||||||
|
childrenOffset int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *file) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⚠️ WARNING: This method is not concurrent-safe.
|
||||||
|
func (f *file) Readdir(count int) ([]os.FileInfo, error) {
|
||||||
|
if len(f.children) == 0 {
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
if count <= 0 {
|
||||||
|
return f.children, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.childrenOffset+count > len(f.children) {
|
||||||
|
count = len(f.children) - f.childrenOffset
|
||||||
|
}
|
||||||
|
offset := f.childrenOffset
|
||||||
|
f.childrenOffset += count
|
||||||
|
return f.children[offset : offset+count], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *file) Stat() (os.FileInfo, error) {
|
||||||
|
childCount := len(f.children)
|
||||||
|
if childCount != 0 {
|
||||||
|
return &fileInfo{
|
||||||
|
name: f.name,
|
||||||
|
size: int64(childCount),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return AssetInfo(f.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileSystem implements the http.FileSystem interface.
|
||||||
|
type fileSystem struct{}
|
||||||
|
|
||||||
|
func (f *fileSystem) Open(name string) (http.File, error) {
|
||||||
|
if len(name) > 0 && name[0] == '/' {
|
||||||
|
name = name[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to get it as a file
|
||||||
|
p, err := Asset(name)
|
||||||
|
if err != nil && !assets.IsErrNotFound(err) {
|
||||||
|
return nil, err
|
||||||
|
} else if err == nil {
|
||||||
|
return &file{
|
||||||
|
name: name,
|
||||||
|
Reader: bytes.NewReader(p),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to get it as a directory
|
||||||
|
paths, err := AssetDir(name)
|
||||||
|
if err != nil && !assets.IsErrNotFound(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
infos := make([]os.FileInfo, len(paths))
|
||||||
|
for i, path := range paths {
|
||||||
|
path = filepath.Join(name, path)
|
||||||
|
info, err := AssetInfo(path)
|
||||||
|
if err != nil {
|
||||||
|
if !assets.IsErrNotFound(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Not found as a file, assume it's a directory.
|
||||||
|
infos[i] = &fileInfo{name: path}
|
||||||
|
} else {
|
||||||
|
infos[i] = info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &file{
|
||||||
|
name: name,
|
||||||
|
children: infos,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFileSystem returns an http.FileSystem instance backed by embedded assets.
|
||||||
|
func NewFileSystem() http.FileSystem {
|
||||||
|
return &fileSystem{}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright 2020 The Gogs 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 (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/macaron.v1"
|
||||||
|
|
||||||
|
"gogs.io/gogs/internal/osutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go-bindata -nomemcopy -ignore="\\.DS_Store" -pkg=templates -prefix=../../../templates -debug=false -o=templates_gen.go ../../../templates/...
|
||||||
|
|
||||||
|
// fileSystem implements the macaron.TemplateFileSystem interface.
|
||||||
|
type fileSystem struct {
|
||||||
|
files []macaron.TemplateFile
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *fileSystem) ListFiles() []macaron.TemplateFile {
|
||||||
|
return fs.files
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *fileSystem) Get(name string) (io.Reader, error) {
|
||||||
|
for i := range fs.files {
|
||||||
|
if fs.files[i].Name()+fs.files[i].Ext() == name {
|
||||||
|
return bytes.NewReader(fs.files[i].Data()), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("file %q not found", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTemplateFileSystem returns a macaron.TemplateFileSystem instance for embedded assets.
|
||||||
|
// The argument "dir" can be used to serve subset of embedded assets. Template file
|
||||||
|
// found under the "customDir" on disk has higher precedence over embedded assets.
|
||||||
|
func NewTemplateFileSystem(dir, customDir string) macaron.TemplateFileSystem {
|
||||||
|
if dir != "" && !strings.HasSuffix(dir, "/") {
|
||||||
|
dir += "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
var files []macaron.TemplateFile
|
||||||
|
names := AssetNames()
|
||||||
|
for _, name := range names {
|
||||||
|
if !strings.HasPrefix(name, dir) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if corresponding custom file exists
|
||||||
|
var err error
|
||||||
|
var data []byte
|
||||||
|
fpath := path.Join(customDir, name)
|
||||||
|
if osutil.IsFile(fpath) {
|
||||||
|
data, err = ioutil.ReadFile(fpath)
|
||||||
|
} else {
|
||||||
|
data, err = Asset(name)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ext := path.Ext(name)
|
||||||
|
name = strings.TrimSuffix(name, ext)
|
||||||
|
files = append(files, macaron.NewTplFile(name, data, ext))
|
||||||
|
}
|
||||||
|
return &fileSystem{files: files}
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -11,7 +11,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -201,8 +200,6 @@ func runHookPostReceive(c *cli.Context) error {
|
||||||
// so we need to setup additional services for email notifications.
|
// so we need to setup additional services for email notifications.
|
||||||
setting.NewPostReceiveHookServices()
|
setting.NewPostReceiveHookServices()
|
||||||
mailer.NewContext()
|
mailer.NewContext()
|
||||||
mailer.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"),
|
|
||||||
path.Join(setting.CustomPath, "templates/mail"), template.NewFuncMap())
|
|
||||||
|
|
||||||
isWiki := strings.Contains(os.Getenv(db.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/")
|
isWiki := strings.Contains(os.Getenv(db.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/")
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/fcgi"
|
"net/http/fcgi"
|
||||||
|
@ -24,18 +23,18 @@ import (
|
||||||
"github.com/go-macaron/i18n"
|
"github.com/go-macaron/i18n"
|
||||||
"github.com/go-macaron/session"
|
"github.com/go-macaron/session"
|
||||||
"github.com/go-macaron/toolbox"
|
"github.com/go-macaron/toolbox"
|
||||||
"github.com/mcuadros/go-version"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
log "gopkg.in/clog.v1"
|
log "gopkg.in/clog.v1"
|
||||||
"gopkg.in/macaron.v1"
|
"gopkg.in/macaron.v1"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/bindata"
|
"gogs.io/gogs/internal/assets/conf"
|
||||||
|
"gogs.io/gogs/internal/assets/public"
|
||||||
|
"gogs.io/gogs/internal/assets/templates"
|
||||||
"gogs.io/gogs/internal/context"
|
"gogs.io/gogs/internal/context"
|
||||||
"gogs.io/gogs/internal/db"
|
"gogs.io/gogs/internal/db"
|
||||||
"gogs.io/gogs/internal/form"
|
"gogs.io/gogs/internal/form"
|
||||||
"gogs.io/gogs/internal/mailer"
|
|
||||||
"gogs.io/gogs/internal/route"
|
"gogs.io/gogs/internal/route"
|
||||||
"gogs.io/gogs/internal/route/admin"
|
"gogs.io/gogs/internal/route/admin"
|
||||||
apiv1 "gogs.io/gogs/internal/route/api/v1"
|
apiv1 "gogs.io/gogs/internal/route/api/v1"
|
||||||
|
@ -59,23 +58,6 @@ and it takes care of all the other things for you`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(2, "Fail to read 'templates/.VERSION': %v", err)
|
|
||||||
}
|
|
||||||
tplVer := strings.TrimSpace(string(data))
|
|
||||||
if tplVer != setting.AppVer {
|
|
||||||
if version.Compare(tplVer, setting.AppVer, ">") {
|
|
||||||
log.Fatal(2, "Binary version is lower than template file version, did you forget to recompile Gogs?")
|
|
||||||
} else {
|
|
||||||
log.Fatal(2, "Binary version is higher than template file version, did you forget to update template files?")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newMacaron initializes Macaron instance.
|
// newMacaron initializes Macaron instance.
|
||||||
func newMacaron() *macaron.Macaron {
|
func newMacaron() *macaron.Macaron {
|
||||||
m := macaron.New()
|
m := macaron.New()
|
||||||
|
@ -89,12 +71,26 @@ func newMacaron() *macaron.Macaron {
|
||||||
if setting.Protocol == setting.SCHEME_FCGI {
|
if setting.Protocol == setting.SCHEME_FCGI {
|
||||||
m.SetURLPrefix(setting.AppSubURL)
|
m.SetURLPrefix(setting.AppSubURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register custom middleware first to make it possible to override files under "public".
|
||||||
m.Use(macaron.Static(
|
m.Use(macaron.Static(
|
||||||
path.Join(setting.StaticRootPath, "public"),
|
path.Join(setting.CustomPath, "public"),
|
||||||
macaron.StaticOptions{
|
macaron.StaticOptions{
|
||||||
SkipLogging: setting.DisableRouterLog,
|
SkipLogging: setting.DisableRouterLog,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
var publicFs http.FileSystem
|
||||||
|
if !setting.LoadAssetsFromDisk {
|
||||||
|
publicFs = public.NewFileSystem()
|
||||||
|
}
|
||||||
|
m.Use(macaron.Static(
|
||||||
|
path.Join(setting.StaticRootPath, "public"),
|
||||||
|
macaron.StaticOptions{
|
||||||
|
SkipLogging: setting.DisableRouterLog,
|
||||||
|
FileSystem: publicFs,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
m.Use(macaron.Static(
|
m.Use(macaron.Static(
|
||||||
setting.AvatarUploadPath,
|
setting.AvatarUploadPath,
|
||||||
macaron.StaticOptions{
|
macaron.StaticOptions{
|
||||||
|
@ -110,23 +106,24 @@ func newMacaron() *macaron.Macaron {
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
|
||||||
funcMap := template.NewFuncMap()
|
renderOpt := macaron.RenderOptions{
|
||||||
m.Use(macaron.Renderer(macaron.RenderOptions{
|
|
||||||
Directory: path.Join(setting.StaticRootPath, "templates"),
|
Directory: path.Join(setting.StaticRootPath, "templates"),
|
||||||
AppendDirectories: []string{path.Join(setting.CustomPath, "templates")},
|
AppendDirectories: []string{path.Join(setting.CustomPath, "templates")},
|
||||||
Funcs: funcMap,
|
Funcs: template.FuncMap(),
|
||||||
IndentJSON: macaron.Env != macaron.PROD,
|
IndentJSON: macaron.Env != macaron.PROD,
|
||||||
}))
|
}
|
||||||
mailer.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"),
|
if !setting.LoadAssetsFromDisk {
|
||||||
path.Join(setting.CustomPath, "templates/mail"), funcMap)
|
renderOpt.TemplateFileSystem = templates.NewTemplateFileSystem("", renderOpt.AppendDirectories[0])
|
||||||
|
}
|
||||||
|
m.Use(macaron.Renderer(renderOpt))
|
||||||
|
|
||||||
localeNames, err := bindata.AssetDir("conf/locale")
|
localeNames, err := conf.AssetDir("conf/locale")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(4, "Fail to list locale files: %v", err)
|
log.Fatal(4, "Fail to list locale files: %v", err)
|
||||||
}
|
}
|
||||||
localFiles := make(map[string][]byte)
|
localFiles := make(map[string][]byte)
|
||||||
for _, name := range localeNames {
|
for _, name := range localeNames {
|
||||||
localFiles[name] = bindata.MustAsset("conf/locale/" + name)
|
localFiles[name] = conf.MustAsset("conf/locale/" + name)
|
||||||
}
|
}
|
||||||
m.Use(i18n.I18n(i18n.Options{
|
m.Use(i18n.I18n(i18n.Options{
|
||||||
SubURL: setting.AppSubURL,
|
SubURL: setting.AppSubURL,
|
||||||
|
@ -170,7 +167,6 @@ func runWeb(c *cli.Context) error {
|
||||||
setting.CustomConf = c.String("config")
|
setting.CustomConf = c.String("config")
|
||||||
}
|
}
|
||||||
route.GlobalInit()
|
route.GlobalInit()
|
||||||
checkVersion()
|
|
||||||
|
|
||||||
m := newMacaron()
|
m := newMacaron()
|
||||||
|
|
||||||
|
@ -697,7 +693,7 @@ func runWeb(c *cli.Context) error {
|
||||||
} else {
|
} else {
|
||||||
listenAddr = fmt.Sprintf("%s:%s", setting.HTTPAddr, setting.HTTPPort)
|
listenAddr = fmt.Sprintf("%s:%s", setting.HTTPAddr, setting.HTTPPort)
|
||||||
}
|
}
|
||||||
log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
|
log.Info("Listen on %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch setting.Protocol {
|
switch setting.Protocol {
|
||||||
|
|
|
@ -12,9 +12,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/unknwon/com"
|
"github.com/unknwon/com"
|
||||||
"xorm.io/xorm"
|
|
||||||
log "gopkg.in/clog.v1"
|
log "gopkg.in/clog.v1"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
|
||||||
|
"gogs.io/gogs/internal/osutil"
|
||||||
"gogs.io/gogs/internal/setting"
|
"gogs.io/gogs/internal/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ func generateAndMigrateGitHooks(x *xorm.Engine) (err error) {
|
||||||
// Gogs didn't allow user to set custom update hook thus no migration for it.
|
// Gogs didn't allow user to set custom update hook thus no migration for it.
|
||||||
// In case user runs this migration multiple times, and custom hook exists,
|
// In case user runs this migration multiple times, and custom hook exists,
|
||||||
// we assume it's been migrated already.
|
// we assume it's been migrated already.
|
||||||
if hookName != "update" && com.IsFile(oldHookPath) && !com.IsExist(customHookDir) {
|
if hookName != "update" && osutil.IsFile(oldHookPath) && !com.IsExist(customHookDir) {
|
||||||
os.MkdirAll(customHookDir, os.ModePerm)
|
os.MkdirAll(customHookDir, os.ModePerm)
|
||||||
if err = os.Rename(oldHookPath, newHookPath); err != nil {
|
if err = os.Rename(oldHookPath, newHookPath); err != nil {
|
||||||
return fmt.Errorf("move hook file to custom directory '%s' -> '%s': %v", oldHookPath, newHookPath, err)
|
return fmt.Errorf("move hook file to custom directory '%s' -> '%s': %v", oldHookPath, newHookPath, err)
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/db/errors"
|
"gogs.io/gogs/internal/db/errors"
|
||||||
|
"gogs.io/gogs/internal/osutil"
|
||||||
"gogs.io/gogs/internal/process"
|
"gogs.io/gogs/internal/process"
|
||||||
"gogs.io/gogs/internal/setting"
|
"gogs.io/gogs/internal/setting"
|
||||||
"gogs.io/gogs/internal/sync"
|
"gogs.io/gogs/internal/sync"
|
||||||
|
@ -406,7 +407,7 @@ func (pr *PullRequest) testPatch() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast fail if patch does not exist, this assumes data is cruppted.
|
// Fast fail if patch does not exist, this assumes data is cruppted.
|
||||||
if !com.IsFile(patchPath) {
|
if !osutil.IsFile(patchPath) {
|
||||||
log.Trace("PullRequest[%d].testPatch: ignored cruppted data", pr.ID)
|
log.Trace("PullRequest[%d].testPatch: ignored cruppted data", pr.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,11 @@ import (
|
||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
api "github.com/gogs/go-gogs-client"
|
api "github.com/gogs/go-gogs-client"
|
||||||
|
|
||||||
|
"gogs.io/gogs/internal/assets/conf"
|
||||||
"gogs.io/gogs/internal/avatar"
|
"gogs.io/gogs/internal/avatar"
|
||||||
"gogs.io/gogs/internal/bindata"
|
|
||||||
"gogs.io/gogs/internal/db/errors"
|
"gogs.io/gogs/internal/db/errors"
|
||||||
"gogs.io/gogs/internal/markup"
|
"gogs.io/gogs/internal/markup"
|
||||||
|
"gogs.io/gogs/internal/osutil"
|
||||||
"gogs.io/gogs/internal/process"
|
"gogs.io/gogs/internal/process"
|
||||||
"gogs.io/gogs/internal/setting"
|
"gogs.io/gogs/internal/setting"
|
||||||
"gogs.io/gogs/internal/sync"
|
"gogs.io/gogs/internal/sync"
|
||||||
|
@ -56,7 +57,7 @@ func LoadRepoConfig() {
|
||||||
types := []string{"gitignore", "license", "readme", "label"}
|
types := []string{"gitignore", "license", "readme", "label"}
|
||||||
typeFiles := make([][]string, 4)
|
typeFiles := make([][]string, 4)
|
||||||
for i, t := range types {
|
for i, t := range types {
|
||||||
files, err := bindata.AssetDir("conf/" + t)
|
files, err := conf.AssetDir("conf/" + t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(4, "Fail to get %s files: %v", t, err)
|
log.Fatal(4, "Fail to get %s files: %v", t, err)
|
||||||
}
|
}
|
||||||
|
@ -929,10 +930,10 @@ func getRepoInitFile(tp, name string) ([]byte, error) {
|
||||||
|
|
||||||
// Use custom file when available.
|
// Use custom file when available.
|
||||||
customPath := path.Join(setting.CustomPath, relPath)
|
customPath := path.Join(setting.CustomPath, relPath)
|
||||||
if com.IsFile(customPath) {
|
if osutil.IsFile(customPath) {
|
||||||
return ioutil.ReadFile(customPath)
|
return ioutil.ReadFile(customPath)
|
||||||
}
|
}
|
||||||
return bindata.Asset(relPath)
|
return conf.Asset(relPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {
|
func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/gogs/git-module"
|
"github.com/gogs/git-module"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/db/errors"
|
"gogs.io/gogs/internal/db/errors"
|
||||||
|
"gogs.io/gogs/internal/osutil"
|
||||||
"gogs.io/gogs/internal/process"
|
"gogs.io/gogs/internal/process"
|
||||||
"gogs.io/gogs/internal/setting"
|
"gogs.io/gogs/internal/setting"
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
|
@ -165,7 +166,7 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
|
||||||
|
|
||||||
// Ignore move step if it's a new file under a directory.
|
// Ignore move step if it's a new file under a directory.
|
||||||
// Otherwise, move the file when name changed.
|
// Otherwise, move the file when name changed.
|
||||||
if com.IsFile(oldFilePath) && opts.OldTreeName != opts.NewTreeName {
|
if osutil.IsFile(oldFilePath) && opts.OldTreeName != opts.NewTreeName {
|
||||||
if err = git.MoveFile(localPath, opts.OldTreeName, opts.NewTreeName); err != nil {
|
if err = git.MoveFile(localPath, opts.OldTreeName, opts.NewTreeName); err != nil {
|
||||||
return fmt.Errorf("git mv %q %q: %v", opts.OldTreeName, opts.NewTreeName, err)
|
return fmt.Errorf("git mv %q %q: %v", opts.OldTreeName, opts.NewTreeName, err)
|
||||||
}
|
}
|
||||||
|
@ -402,7 +403,7 @@ func DeleteUploads(uploads ...*Upload) (err error) {
|
||||||
|
|
||||||
for _, upload := range uploads {
|
for _, upload := range uploads {
|
||||||
localPath := upload.LocalPath()
|
localPath := upload.LocalPath()
|
||||||
if !com.IsFile(localPath) {
|
if !osutil.IsFile(localPath) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,7 +481,7 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
|
||||||
// Copy uploaded files into repository
|
// Copy uploaded files into repository
|
||||||
for _, upload := range uploads {
|
for _, upload := range uploads {
|
||||||
tmpPath := upload.LocalPath()
|
tmpPath := upload.LocalPath()
|
||||||
if !com.IsFile(tmpPath) {
|
if !osutil.IsFile(tmpPath) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,15 @@ package mailer
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"path"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
log "gopkg.in/clog.v1"
|
log "gopkg.in/clog.v1"
|
||||||
"gopkg.in/gomail.v2"
|
"gopkg.in/gomail.v2"
|
||||||
"gopkg.in/macaron.v1"
|
"gopkg.in/macaron.v1"
|
||||||
|
|
||||||
|
"gogs.io/gogs/internal/assets/templates"
|
||||||
"gogs.io/gogs/internal/markup"
|
"gogs.io/gogs/internal/markup"
|
||||||
"gogs.io/gogs/internal/setting"
|
"gogs.io/gogs/internal/setting"
|
||||||
)
|
)
|
||||||
|
@ -28,30 +32,49 @@ const (
|
||||||
MAIL_NOTIFY_COLLABORATOR = "notify/collaborator"
|
MAIL_NOTIFY_COLLABORATOR = "notify/collaborator"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MailRender interface {
|
var (
|
||||||
HTMLString(string, interface{}, ...macaron.HTMLOptions) (string, error)
|
tplRender *macaron.TplRender
|
||||||
}
|
tplRenderOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
var mailRender MailRender
|
// render renders a mail template with given data.
|
||||||
|
func render(tpl string, data map[string]interface{}) (string, error) {
|
||||||
|
tplRenderOnce.Do(func() {
|
||||||
|
opt := &macaron.RenderOptions{
|
||||||
|
Directory: path.Join(setting.StaticRootPath, "templates/mail"),
|
||||||
|
AppendDirectories: []string{path.Join(setting.CustomPath, "templates/mail")},
|
||||||
|
Funcs: []template.FuncMap{map[string]interface{}{
|
||||||
|
"AppName": func() string {
|
||||||
|
return setting.AppName
|
||||||
|
},
|
||||||
|
"AppURL": func() string {
|
||||||
|
return setting.AppURL
|
||||||
|
},
|
||||||
|
"Year": func() int {
|
||||||
|
return time.Now().Year()
|
||||||
|
},
|
||||||
|
"Str2HTML": func(raw string) template.HTML {
|
||||||
|
return template.HTML(markup.Sanitize(raw))
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
if !setting.LoadAssetsFromDisk {
|
||||||
|
opt.TemplateFileSystem = templates.NewTemplateFileSystem("mail", opt.AppendDirectories[0])
|
||||||
|
}
|
||||||
|
|
||||||
func InitMailRender(dir, appendDir string, funcMap []template.FuncMap) {
|
ts := macaron.NewTemplateSet()
|
||||||
opt := &macaron.RenderOptions{
|
ts.Set(macaron.DEFAULT_TPL_SET_NAME, opt)
|
||||||
Directory: dir,
|
tplRender = &macaron.TplRender{
|
||||||
AppendDirectories: []string{appendDir},
|
TemplateSet: ts,
|
||||||
Funcs: funcMap,
|
Opt: opt,
|
||||||
Extensions: []string{".tmpl", ".html"},
|
}
|
||||||
}
|
})
|
||||||
ts := macaron.NewTemplateSet()
|
|
||||||
ts.Set(macaron.DEFAULT_TPL_SET_NAME, opt)
|
|
||||||
|
|
||||||
mailRender = &macaron.TplRender{
|
return tplRender.HTMLString(tpl, data)
|
||||||
TemplateSet: ts,
|
|
||||||
Opt: opt,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendTestMail(email string) error {
|
func SendTestMail(email string) error {
|
||||||
return gomail.Send(&Sender{}, NewMessage([]string{email}, "Gogs Test Email!", "Gogs Test Email!").Message)
|
return gomail.Send(&Sender{}, NewMessage([]string{email}, "Gogs Test Email", "Hello 👋, greeting from Gogs!").Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -85,9 +108,9 @@ func SendUserMail(c *macaron.Context, u User, tpl, code, subject, info string) {
|
||||||
"ResetPwdCodeLives": setting.Service.ResetPwdCodeLives / 60,
|
"ResetPwdCodeLives": setting.Service.ResetPwdCodeLives / 60,
|
||||||
"Code": code,
|
"Code": code,
|
||||||
}
|
}
|
||||||
body, err := mailRender.HTMLString(string(tpl), data)
|
body, err := render(tpl, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(2, "HTMLString: %v", err)
|
log.Error(2, "render: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +136,7 @@ func SendActivateEmailMail(c *macaron.Context, u User, email string) {
|
||||||
"Code": u.GenerateEmailActivateCode(email),
|
"Code": u.GenerateEmailActivateCode(email),
|
||||||
"Email": email,
|
"Email": email,
|
||||||
}
|
}
|
||||||
body, err := mailRender.HTMLString(string(MAIL_AUTH_ACTIVATE_EMAIL), data)
|
body, err := render(MAIL_AUTH_ACTIVATE_EMAIL, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(3, "HTMLString: %v", err)
|
log.Error(3, "HTMLString: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -130,7 +153,7 @@ func SendRegisterNotifyMail(c *macaron.Context, u User) {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"Username": u.DisplayName(),
|
"Username": u.DisplayName(),
|
||||||
}
|
}
|
||||||
body, err := mailRender.HTMLString(string(MAIL_AUTH_REGISTER_NOTIFY), data)
|
body, err := render(MAIL_AUTH_REGISTER_NOTIFY, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(3, "HTMLString: %v", err)
|
log.Error(3, "HTMLString: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -151,7 +174,7 @@ func SendCollaboratorMail(u, doer User, repo Repository) {
|
||||||
"RepoName": repo.FullName(),
|
"RepoName": repo.FullName(),
|
||||||
"Link": repo.HTMLURL(),
|
"Link": repo.HTMLURL(),
|
||||||
}
|
}
|
||||||
body, err := mailRender.HTMLString(string(MAIL_NOTIFY_COLLABORATOR), data)
|
body, err := render(MAIL_NOTIFY_COLLABORATOR, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(3, "HTMLString: %v", err)
|
log.Error(3, "HTMLString: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -176,7 +199,7 @@ func composeIssueMessage(issue Issue, repo Repository, doer User, tplName string
|
||||||
body := string(markup.Markdown([]byte(issue.Content()), repo.HTMLURL(), repo.ComposeMetas()))
|
body := string(markup.Markdown([]byte(issue.Content()), repo.HTMLURL(), repo.ComposeMetas()))
|
||||||
data := composeTplData(subject, body, issue.HTMLURL())
|
data := composeTplData(subject, body, issue.HTMLURL())
|
||||||
data["Doer"] = doer
|
data["Doer"] = doer
|
||||||
content, err := mailRender.HTMLString(tplName, data)
|
content, err := render(tplName, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(3, "HTMLString (%s): %v", tplName, err)
|
log.Error(3, "HTMLString (%s): %v", tplName, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2020 The Gogs 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 osutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsFile returns true if given path exists as a file (i.e. not a directory).
|
||||||
|
func IsFile(path string) bool {
|
||||||
|
f, e := os.Stat(path)
|
||||||
|
if e != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return !f.IsDir()
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ func checkRunMode() {
|
||||||
} else {
|
} else {
|
||||||
git.Debug = true
|
git.Debug = true
|
||||||
}
|
}
|
||||||
log.Info("Run Mode: %s", strings.Title(macaron.Env))
|
log.Info("Run mode: %s", strings.Title(macaron.Env))
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServices() {
|
func NewServices() {
|
||||||
|
@ -78,10 +78,13 @@ func GlobalInit() {
|
||||||
db.InitTestPullRequests()
|
db.InitTestPullRequests()
|
||||||
}
|
}
|
||||||
if db.EnableSQLite3 {
|
if db.EnableSQLite3 {
|
||||||
log.Info("SQLite3 Supported")
|
log.Info("SQLite3 is supported")
|
||||||
}
|
}
|
||||||
if setting.SupportMiniWinService {
|
if setting.SupportMiniWinService {
|
||||||
log.Info("Builtin Windows Service Supported")
|
log.Info("Builtin Windows Service is supported")
|
||||||
|
}
|
||||||
|
if setting.LoadAssetsFromDisk {
|
||||||
|
log.Info("Assets are loaded from disk")
|
||||||
}
|
}
|
||||||
checkRunMode()
|
checkRunMode()
|
||||||
|
|
||||||
|
|
|
@ -16,18 +16,18 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/unknwon/com"
|
|
||||||
_ "github.com/go-macaron/cache/memcache"
|
_ "github.com/go-macaron/cache/memcache"
|
||||||
_ "github.com/go-macaron/cache/redis"
|
_ "github.com/go-macaron/cache/redis"
|
||||||
"github.com/go-macaron/session"
|
"github.com/go-macaron/session"
|
||||||
_ "github.com/go-macaron/session/redis"
|
_ "github.com/go-macaron/session/redis"
|
||||||
"github.com/mcuadros/go-version"
|
"github.com/mcuadros/go-version"
|
||||||
|
"github.com/unknwon/com"
|
||||||
log "gopkg.in/clog.v1"
|
log "gopkg.in/clog.v1"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
|
|
||||||
"github.com/gogs/go-libravatar"
|
"github.com/gogs/go-libravatar"
|
||||||
|
|
||||||
"gogs.io/gogs/internal/bindata"
|
"gogs.io/gogs/internal/assets/conf"
|
||||||
"gogs.io/gogs/internal/process"
|
"gogs.io/gogs/internal/process"
|
||||||
"gogs.io/gogs/internal/user"
|
"gogs.io/gogs/internal/user"
|
||||||
)
|
)
|
||||||
|
@ -50,8 +50,8 @@ const (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Build information should only be set by -ldflags.
|
// Build information should only be set by -ldflags.
|
||||||
BuildTime string
|
BuildTime string
|
||||||
BuildGitHash string
|
BuildCommit string
|
||||||
|
|
||||||
// App settings
|
// App settings
|
||||||
AppVer string
|
AppVer string
|
||||||
|
@ -74,6 +74,7 @@ var (
|
||||||
CertFile string
|
CertFile string
|
||||||
KeyFile string
|
KeyFile string
|
||||||
TLSMinVersion string
|
TLSMinVersion string
|
||||||
|
LoadAssetsFromDisk bool
|
||||||
StaticRootPath string
|
StaticRootPath string
|
||||||
EnableGzip bool
|
EnableGzip bool
|
||||||
LandingPageURL LandingPage
|
LandingPageURL LandingPage
|
||||||
|
@ -416,7 +417,7 @@ func NewContext() {
|
||||||
|
|
||||||
Cfg, err = ini.LoadSources(ini.LoadOptions{
|
Cfg, err = ini.LoadSources(ini.LoadOptions{
|
||||||
IgnoreInlineComment: true,
|
IgnoreInlineComment: true,
|
||||||
}, bindata.MustAsset("conf/app.ini"))
|
}, conf.MustAsset("conf/app.ini"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(2, "Fail to parse 'conf/app.ini': %v", err)
|
log.Fatal(2, "Fail to parse 'conf/app.ini': %v", err)
|
||||||
}
|
}
|
||||||
|
@ -489,6 +490,7 @@ func NewContext() {
|
||||||
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HTTPPort + "/")
|
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HTTPPort + "/")
|
||||||
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
|
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
|
||||||
DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
|
DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
|
||||||
|
LoadAssetsFromDisk = sec.Key("LOAD_ASSETS_FROM_DISK").MustBool()
|
||||||
StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)
|
StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir)
|
||||||
AppDataPath = sec.Key("APP_DATA_PATH").MustString("data")
|
AppDataPath = sec.Key("APP_DATA_PATH").MustString("data")
|
||||||
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
|
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
|
||||||
|
@ -729,8 +731,8 @@ func newService() {
|
||||||
|
|
||||||
func newLogService() {
|
func newLogService() {
|
||||||
if len(BuildTime) > 0 {
|
if len(BuildTime) > 0 {
|
||||||
log.Trace("Build Time: %s", BuildTime)
|
log.Trace("Build time: %s", BuildTime)
|
||||||
log.Trace("Build Git Hash: %s", BuildGitHash)
|
log.Trace("Build commit: %s", BuildCommit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because we always create a console logger as primary logger before all settings are loaded,
|
// Because we always create a console logger as primary logger before all settings are loaded,
|
||||||
|
@ -809,7 +811,7 @@ func newLogService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.New(log.MODE(mode), LogConfigs[i])
|
log.New(log.MODE(mode), LogConfigs[i])
|
||||||
log.Trace("Log Mode: %s (%s)", strings.Title(mode), strings.Title(name))
|
log.Trace("Log mode: %s (%s)", strings.Title(mode), strings.Title(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure everyone gets version info printed.
|
// Make sure everyone gets version info printed.
|
||||||
|
@ -830,7 +832,7 @@ func newCacheService() {
|
||||||
log.Fatal(2, "Unknown cache adapter: %s", CacheAdapter)
|
log.Fatal(2, "Unknown cache adapter: %s", CacheAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Cache Service Enabled")
|
log.Info("Cache service is enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSessionService() {
|
func newSessionService() {
|
||||||
|
@ -844,7 +846,7 @@ func newSessionService() {
|
||||||
SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
|
SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
|
||||||
CSRFCookieName = Cfg.Section("session").Key("CSRF_COOKIE_NAME").MustString("_csrf")
|
CSRFCookieName = Cfg.Section("session").Key("CSRF_COOKIE_NAME").MustString("_csrf")
|
||||||
|
|
||||||
log.Info("Session Service Enabled")
|
log.Info("Session service is enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mailer represents mail service.
|
// Mailer represents mail service.
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/editorconfig/editorconfig-core-go/v2"
|
"github.com/editorconfig/editorconfig-core-go/v2"
|
||||||
|
@ -27,103 +28,111 @@ import (
|
||||||
"gogs.io/gogs/internal/tool"
|
"gogs.io/gogs/internal/tool"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: only initialize map once and save to a local variable to reduce copies.
|
var (
|
||||||
func NewFuncMap() []template.FuncMap {
|
funcMap []template.FuncMap
|
||||||
return []template.FuncMap{map[string]interface{}{
|
funcMapOnce sync.Once
|
||||||
"GoVer": func() string {
|
)
|
||||||
return strings.Title(runtime.Version())
|
|
||||||
},
|
// FuncMap returns a list of user-defined template functions.
|
||||||
"Year": func() int {
|
func FuncMap() []template.FuncMap {
|
||||||
return time.Now().Year()
|
funcMapOnce.Do(func() {
|
||||||
},
|
funcMap = []template.FuncMap{map[string]interface{}{
|
||||||
"UseHTTPS": func() bool {
|
"GoVer": func() string {
|
||||||
return strings.HasPrefix(setting.AppURL, "https")
|
return strings.Title(runtime.Version())
|
||||||
},
|
},
|
||||||
"AppName": func() string {
|
"Year": func() int {
|
||||||
return setting.AppName
|
return time.Now().Year()
|
||||||
},
|
},
|
||||||
"AppSubURL": func() string {
|
"UseHTTPS": func() bool {
|
||||||
return setting.AppSubURL
|
return strings.HasPrefix(setting.AppURL, "https")
|
||||||
},
|
},
|
||||||
"AppURL": func() string {
|
"AppName": func() string {
|
||||||
return setting.AppURL
|
return setting.AppName
|
||||||
},
|
},
|
||||||
"AppVer": func() string {
|
"AppSubURL": func() string {
|
||||||
return setting.AppVer
|
return setting.AppSubURL
|
||||||
},
|
},
|
||||||
"AppDomain": func() string {
|
"AppURL": func() string {
|
||||||
return setting.Domain
|
return setting.AppURL
|
||||||
},
|
},
|
||||||
"DisableGravatar": func() bool {
|
"AppVer": func() string {
|
||||||
return setting.DisableGravatar
|
return setting.AppVer
|
||||||
},
|
},
|
||||||
"ShowFooterTemplateLoadTime": func() bool {
|
"AppDomain": func() string {
|
||||||
return setting.ShowFooterTemplateLoadTime
|
return setting.Domain
|
||||||
},
|
},
|
||||||
"LoadTimes": func(startTime time.Time) string {
|
"DisableGravatar": func() bool {
|
||||||
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
|
return setting.DisableGravatar
|
||||||
},
|
},
|
||||||
"AvatarLink": tool.AvatarLink,
|
"ShowFooterTemplateLoadTime": func() bool {
|
||||||
"AppendAvatarSize": tool.AppendAvatarSize,
|
return setting.ShowFooterTemplateLoadTime
|
||||||
"Safe": Safe,
|
},
|
||||||
"Sanitize": bluemonday.UGCPolicy().Sanitize,
|
"LoadTimes": func(startTime time.Time) string {
|
||||||
"Str2HTML": Str2HTML,
|
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
|
||||||
"NewLine2br": NewLine2br,
|
},
|
||||||
"TimeSince": tool.TimeSince,
|
"AvatarLink": tool.AvatarLink,
|
||||||
"RawTimeSince": tool.RawTimeSince,
|
"AppendAvatarSize": tool.AppendAvatarSize,
|
||||||
"FileSize": tool.FileSize,
|
"Safe": Safe,
|
||||||
"Subtract": tool.Subtract,
|
"Sanitize": bluemonday.UGCPolicy().Sanitize,
|
||||||
"Add": func(a, b int) int {
|
"Str2HTML": Str2HTML,
|
||||||
return a + b
|
"NewLine2br": NewLine2br,
|
||||||
},
|
"TimeSince": tool.TimeSince,
|
||||||
"ActionIcon": ActionIcon,
|
"RawTimeSince": tool.RawTimeSince,
|
||||||
"DateFmtLong": func(t time.Time) string {
|
"FileSize": tool.FileSize,
|
||||||
return t.Format(time.RFC1123Z)
|
"Subtract": tool.Subtract,
|
||||||
},
|
"Add": func(a, b int) int {
|
||||||
"DateFmtShort": func(t time.Time) string {
|
return a + b
|
||||||
return t.Format("Jan 02, 2006")
|
},
|
||||||
},
|
"ActionIcon": ActionIcon,
|
||||||
"List": List,
|
"DateFmtLong": func(t time.Time) string {
|
||||||
"SubStr": func(str string, start, length int) string {
|
return t.Format(time.RFC1123Z)
|
||||||
if len(str) == 0 {
|
},
|
||||||
return ""
|
"DateFmtShort": func(t time.Time) string {
|
||||||
}
|
return t.Format("Jan 02, 2006")
|
||||||
end := start + length
|
},
|
||||||
if length == -1 {
|
"List": List,
|
||||||
end = len(str)
|
"SubStr": func(str string, start, length int) string {
|
||||||
}
|
if len(str) == 0 {
|
||||||
if len(str) < end {
|
return ""
|
||||||
return str
|
|
||||||
}
|
|
||||||
return str[start:end]
|
|
||||||
},
|
|
||||||
"Join": strings.Join,
|
|
||||||
"EllipsisString": tool.EllipsisString,
|
|
||||||
"DiffTypeToStr": DiffTypeToStr,
|
|
||||||
"DiffLineTypeToStr": DiffLineTypeToStr,
|
|
||||||
"Sha1": Sha1,
|
|
||||||
"ShortSHA1": tool.ShortSHA1,
|
|
||||||
"MD5": tool.MD5,
|
|
||||||
"ActionContent2Commits": ActionContent2Commits,
|
|
||||||
"EscapePound": EscapePound,
|
|
||||||
"RenderCommitMessage": RenderCommitMessage,
|
|
||||||
"ThemeColorMetaTag": func() string {
|
|
||||||
return setting.UI.ThemeColorMetaTag
|
|
||||||
},
|
|
||||||
"FilenameIsImage": func(filename string) bool {
|
|
||||||
mimeType := mime.TypeByExtension(filepath.Ext(filename))
|
|
||||||
return strings.HasPrefix(mimeType, "image/")
|
|
||||||
},
|
|
||||||
"TabSizeClass": func(ec *editorconfig.Editorconfig, filename string) string {
|
|
||||||
if ec != nil {
|
|
||||||
def, err := ec.GetDefinitionForFilename(filename)
|
|
||||||
if err == nil && def.TabWidth > 0 {
|
|
||||||
return fmt.Sprintf("tab-size-%d", def.TabWidth)
|
|
||||||
}
|
}
|
||||||
}
|
end := start + length
|
||||||
return "tab-size-8"
|
if length == -1 {
|
||||||
},
|
end = len(str)
|
||||||
}}
|
}
|
||||||
|
if len(str) < end {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return str[start:end]
|
||||||
|
},
|
||||||
|
"Join": strings.Join,
|
||||||
|
"EllipsisString": tool.EllipsisString,
|
||||||
|
"DiffTypeToStr": DiffTypeToStr,
|
||||||
|
"DiffLineTypeToStr": DiffLineTypeToStr,
|
||||||
|
"Sha1": Sha1,
|
||||||
|
"ShortSHA1": tool.ShortSHA1,
|
||||||
|
"MD5": tool.MD5,
|
||||||
|
"ActionContent2Commits": ActionContent2Commits,
|
||||||
|
"EscapePound": EscapePound,
|
||||||
|
"RenderCommitMessage": RenderCommitMessage,
|
||||||
|
"ThemeColorMetaTag": func() string {
|
||||||
|
return setting.UI.ThemeColorMetaTag
|
||||||
|
},
|
||||||
|
"FilenameIsImage": func(filename string) bool {
|
||||||
|
mimeType := mime.TypeByExtension(filepath.Ext(filename))
|
||||||
|
return strings.HasPrefix(mimeType, "image/")
|
||||||
|
},
|
||||||
|
"TabSizeClass": func(ec *editorconfig.Editorconfig, filename string) string {
|
||||||
|
if ec != nil {
|
||||||
|
def, err := ec.GetDefinitionForFilename(filename)
|
||||||
|
if err == nil && def.TabWidth > 0 {
|
||||||
|
return fmt.Sprintf("tab-size-%d", def.TabWidth)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "tab-size-8"
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
})
|
||||||
|
return funcMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func Safe(raw string) template.HTML {
|
func Safe(raw string) template.HTML {
|
||||||
|
|
|
@ -40,7 +40,6 @@ function initEditPreviewTab($form) {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
$.post($this.data('url'), {
|
$.post($this.data('url'), {
|
||||||
"_csrf": csrf,
|
"_csrf": csrf,
|
||||||
"mode": "gfm",
|
|
||||||
"context": $this.data('context'),
|
"context": $this.data('context'),
|
||||||
"text": $form.find('.tab.segment[data-tab="' + $tabMenu.data('write') + '"] textarea').val()
|
"text": $form.find('.tab.segment[data-tab="' + $tabMenu.data('write') + '"] textarea').val()
|
||||||
},
|
},
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
0.11.97.1209
|
|
Loading…
Reference in New Issue