use go:embed for static resources (#1107)

* feat: use go:embed to embed static files

* ci: fix broken test

* docs: update readme.md

* chore: remove statik

* feat: simplify code

Co-authored-by: AaronLiu <abslant@126.com>
pull/1198/head
Ink33 2 years ago committed by GitHub
parent ec776ac837
commit 84807be1ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,26 +9,22 @@ jobs:
name: Build
runs-on: ubuntu-18.04
steps:
- name: Set up Golang
uses: actions/setup-go@v1
- name: Set up Go 1.17
uses: actions/setup-go@v2
with:
go-version: 1.17
go-version: "1.17"
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
clean: false
submodules: 'recursive'
submodules: "recursive"
- run: |
git fetch --prune --unshallow --tags
- name: Get dependencies and build
run: |
go install github.com/rakyll/statik
export PATH=$PATH:~/go/bin/
statik -src=models -f
sudo apt-get update
sudo apt-get -y install gcc-mingw-w64-x86-64
sudo apt-get -y install gcc-arm-linux-gnueabihf libc6-dev-armhf-cross

@ -8,28 +8,25 @@ on:
branches: [master]
jobs:
test:
name: Test
runs-on: ubuntu-18.04
steps:
- name: Set up Golang
uses: actions/setup-go@v1
- name: Set up Go 1.17
uses: actions/setup-go@v2
with:
go-version: 1.17
go-version: "1.17"
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
submodules: 'recursive'
submodules: "recursive"
- name: Get dependencies
- name: Build static files
run: |
go get github.com/rakyll/statik
export PATH=$PATH:~/go/bin/
statik -src=models -f
mkdir assets/build
touch assets/build/test.html
- name: Test
run: go test -coverprofile=coverage.txt -covermode=atomic ./...

@ -4,10 +4,9 @@ go:
node_js: "12.16.3"
git:
depth: 1
install:
- go get github.com/rakyll/statik
before_script:
- statik -src=models -f
- mkdir assets/build
- touch assets/build/test.html
script:
- go test -coverprofile=coverage.txt -covermode=atomic ./...
after_success:

@ -28,8 +28,6 @@ RUN set -ex \
&& apk add gcc libc-dev git \
&& export COMMIT_SHA=$(git rev-parse --short HEAD) \
&& export VERSION=$(git describe --tags) \
&& (cd && go get github.com/rakyll/statik) \
&& statik -src=assets/build/ -include=*.html,*.js,*.json,*.css,*.png,*.svg,*.ico -f \
&& go install -ldflags "-X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.BackendVersion=${VERSION}' \
-X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.LastCommit=${COMMIT_SHA}'\
-w -s"

@ -68,7 +68,7 @@ chmod +x ./cloudreve
## :gear: 构建
自行构建前需要拥有 `Go >= 1.13`、`yarn`等必要依赖。
自行构建前需要拥有 `Go >= 1.17`、`yarn`等必要依赖。
#### 克隆代码
@ -85,19 +85,7 @@ cd assets
yarn install
# 开始构建
yarn run build
```
#### 嵌入静态资源
```shell
# 回到项目主目录
cd ../
# 安装 statik, 用于嵌入静态资源
go get github.com/rakyll/statik
# 开始嵌入
statik -src=assets/build/ -include=*.html,*.js,*.json,*.css,*.png,*.svg,*.ico -f
```
#### 编译项目
@ -108,7 +96,7 @@ export COMMIT_SHA=$(git rev-parse --short HEAD)
export VERSION=$(git describe --tags)
# 开始编译
go build -a -o cloudreve -ldflags " -X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.BackendVersion=$VERSION' -X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.LastCommit=$COMMIT_SHA'"
go build -a -o cloudreve -ldflags "-s -w -X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.BackendVersion=$VERSION' -X 'github.com/cloudreve/Cloudreve/v3/pkg/conf.LastCommit=$COMMIT_SHA'"
```
你也可以使用项目根目录下的`build.sh`快速开始构建:

@ -1,21 +1,26 @@
package bootstrap
import (
"bufio"
"embed"
"encoding/json"
"io"
"io/ioutil"
"io/fs"
"net/http"
"path"
"path/filepath"
"github.com/pkg/errors"
"github.com/cloudreve/Cloudreve/v3/pkg/conf"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
_ "github.com/cloudreve/Cloudreve/v3/statik"
"github.com/gin-contrib/static"
"github.com/rakyll/statik/fs"
)
const StaticFolder = "statics"
var StaticEmbed embed.FS
type GinFS struct {
FS http.FileSystem
}
@ -35,22 +40,28 @@ func (b *GinFS) Open(name string) (http.File, error) {
// Exists 文件是否存在
func (b *GinFS) Exists(prefix string, filepath string) bool {
if _, err := b.FS.Open(filepath); err != nil {
return false
}
return true
}
// InitStatic 初始化静态资源文件
func InitStatic() {
var err error
if util.Exists(util.RelativePath(StaticFolder)) {
util.Log().Info("检测到 statics 目录存在,将使用此目录下的静态资源文件")
StaticFS = static.LocalFile(util.RelativePath("statics"), false)
} else {
// 初始化静态资源
embedFS, err := fs.Sub(StaticEmbed, "assets/build")
if err != nil {
util.Log().Panic("无法初始化静态资源, %s", err)
}
StaticFS = &GinFS{
FS: http.FS(embedFS),
}
}
// 检查静态资源的版本
f, err := StaticFS.Open("version.json")
if err != nil {
@ -58,7 +69,7 @@ func InitStatic() {
return
}
b, err := ioutil.ReadAll(f)
b, err := io.ReadAll(f)
if err != nil {
util.Log().Warning("无法读取静态资源文件版本,请重新构建或删除 statics 目录")
return
@ -84,75 +95,45 @@ func InitStatic() {
util.Log().Warning("静态资源版本不匹配 [当前 %s, 需要: %s],请重新构建或删除 statics 目录", v.Version, conf.RequiredStaticVersion)
return
}
} else {
StaticFS = &GinFS{}
StaticFS.(*GinFS).FS, err = fs.New()
if err != nil {
util.Log().Panic("无法初始化静态资源, %s", err)
}
}
}
// Eject 抽离内置静态资源
func Eject() {
staticFS, err := fs.New()
// 初始化静态资源
embedFS, err := fs.Sub(StaticEmbed, "assets/build")
if err != nil {
util.Log().Panic("无法初始化静态资源, %s", err)
}
root, err := staticFS.Open("/")
var walk func(relPath string, d fs.DirEntry, err error) error
walk = func(relPath string, d fs.DirEntry, err error) error {
if err != nil {
util.Log().Panic("根目录不存在, %s", err)
}
var walk func(relPath string, object http.File)
walk = func(relPath string, object http.File) {
stat, err := object.Stat()
if err != nil {
util.Log().Error("无法获取[%s]的信息, %s, 跳过...", relPath, err)
return
return errors.Errorf("无法获取[%s]的信息, %s, 跳过...", relPath, err)
}
if !stat.IsDir() {
if !d.IsDir() {
// 写入文件
out, err := util.CreatNestedFile(util.RelativePath(StaticFolder + relPath))
out, err := util.CreatNestedFile(filepath.Join(util.RelativePath(""), StaticFolder, relPath))
defer out.Close()
if err != nil {
util.Log().Error("无法创建文件[%s], %s, 跳过...", relPath, err)
return
return errors.Errorf("无法创建文件[%s], %s, 跳过...", relPath, err)
}
util.Log().Info("导出 [%s]...", relPath)
if _, err := io.Copy(out, object); err != nil {
util.Log().Error("无法写入文件[%s], %s, 跳过...", relPath, err)
return
obj, _ := embedFS.Open(relPath)
if _, err := io.Copy(out, bufio.NewReader(obj)); err != nil {
return errors.Errorf("无法写入文件[%s], %s, 跳过...", relPath, err)
}
} else {
// 列出目录
objects, err := object.Readdir(0)
if err != nil {
util.Log().Error("无法步入子目录[%s], %s, 跳过...", relPath, err)
return
}
// 递归遍历子目录
for _, newObject := range objects {
newPath := path.Join(relPath, newObject.Name())
newRoot, err := staticFS.Open(newPath)
if err != nil {
util.Log().Error("无法打开对象[%s], %s, 跳过...", newPath, err)
continue
}
walk(newPath, newRoot)
return nil
}
// util.Log().Info("开始导出内置静态资源...")
err = fs.WalkDir(embedFS, ".", walk)
if err != nil {
util.Log().Error("导出内置静态资源遇到错误:%s", err)
return
}
}
util.Log().Info("开始导出内置静态资源...")
walk("/", root)
util.Log().Info("内置静态资源导出完成")
}

@ -1,6 +1,9 @@
#!/bin/bash
REPO=$(cd $(dirname $0); pwd)
REPO=$(
cd $(dirname $0)
pwd
)
COMMIT_SHA=$(git rev-parse --short HEAD)
VERSION=$(git describe --tags)
ASSETS="false"
@ -19,7 +22,6 @@ debugInfo () {
buildAssets() {
cd $REPO
rm -rf assets/build
rm -f statik/statik.go
export CI=false
@ -27,14 +29,8 @@ buildAssets () {
yarn install
yarn run build
if ! [ -x "$(command -v statik)" ]; then
export CGO_ENABLED=0
go get github.com/rakyll/statik
fi
cd $REPO
statik -src=assets/build/ -include=*.html,*.js,*.json,*.css,*.png,*.svg,*.ico,*.ttf -f
cd build
rm -rf *.map
}
buildBinary() {
@ -86,8 +82,8 @@ release(){
}
usage() {
echo "Usage: $0 [-a] [-c] [-b] [-r]" 1>&2;
exit 1;
echo "Usage: $0 [-a] [-c] [-b] [-r]" 1>&2
exit 1
}
while getopts "bacr:d" o; do

@ -1,6 +1,6 @@
module github.com/cloudreve/Cloudreve/v3
go 1.13
go 1.17
require (
github.com/DATA-DOG/go-sqlmock v1.3.3

@ -1,6 +1,7 @@
package main
import (
"embed"
"flag"
"github.com/cloudreve/Cloudreve/v3/bootstrap"
@ -15,6 +16,9 @@ var (
scriptName string
)
//go:embed assets/build
var StaticEmbed embed.FS
func init() {
flag.StringVar(&confPath, "c", util.RelativePath("conf.ini"), "配置文件路径")
flag.BoolVar(&isEject, "eject", false, "导出内置静态资源")

@ -56,3 +56,4 @@ func RelativePath(name string) string {
e, _ := os.Executable()
return filepath.Join(filepath.Dir(e), name)
}

Loading…
Cancel
Save