diff --git a/.gitmodules b/.gitmodules index 8f90ec8..e159477 100644 --- a/.gitmodules +++ b/.gitmodules @@ -76,3 +76,6 @@ [submodule "vendor/github.com/smartystreets/assertions"] path = vendor/github.com/smartystreets/assertions url = https://github.com/smartystreets/assertions +[submodule "vendor/github.com/itchio/go-brotli"] + path = vendor/github.com/itchio/go-brotli + url = https://github.com/itchio/go-brotli diff --git a/build/ci/.drone.yml b/build/ci/.drone.yml index 21db4b7..aec9979 100644 --- a/build/ci/.drone.yml +++ b/build/ci/.drone.yml @@ -17,7 +17,7 @@ steps: - name: test image: golang:latest environment: - CGO_ENABLED: 0 + CGO_ENABLED: 1 GOOS: linux GOARCH: amd64 commands: @@ -29,7 +29,7 @@ steps: - name: build for linux image: golang:latest environment: - CGO_ENABLED: 0 + CGO_ENABLED: 1 GOOS: linux GOARCH: amd64 commands: @@ -48,7 +48,7 @@ steps: - name: build for freebsd image: golang:latest environment: - CGO_ENABLED: 0 + CGO_ENABLED: 1 GOOS: freebsd GOARCH: amd64 commands: @@ -59,7 +59,7 @@ steps: - name: build for macos image: golang:latest environment: - CGO_ENABLED: 0 + CGO_ENABLED: 1 GOOS: darwin GOARCH: amd64 commands: @@ -70,7 +70,7 @@ steps: - name: build for windows image: golang:latest environment: - CGO_ENABLED: 0 + CGO_ENABLED: 1 GOOS: windows GOARCH: amd64 FILEEXT: .exe diff --git a/example/content/de/config.yml b/example/content/de/config.yml index 4360ebc..65413df 100644 --- a/example/content/de/config.yml +++ b/example/content/de/config.yml @@ -1,2 +1,2 @@ This: - GoTo: main/home \ No newline at end of file + GoTo: main/home/ \ No newline at end of file diff --git a/example/content/en/config.yml b/example/content/en/config.yml index 4360ebc..65413df 100644 --- a/example/content/en/config.yml +++ b/example/content/en/config.yml @@ -1,2 +1,2 @@ This: - GoTo: main/home \ No newline at end of file + GoTo: main/home/ \ No newline at end of file diff --git a/pkg/mark2web/brotli.go b/pkg/mark2web/brotli.go new file mode 100644 index 0000000..0d640b5 --- /dev/null +++ b/pkg/mark2web/brotli.go @@ -0,0 +1,48 @@ +// +build cgo + +package mark2web + +import ( + "io" + "os" + + "gitbase.de/apairon/mark2web/pkg/helper" + "github.com/itchio/go-brotli/enc" +) + +var brotliSupported = true + +func handleBrotliCompression(filename string, content []byte) { + brFilename := filename + ".br" + + helper.Log.Infof("writing to compressed output file: %s", brFilename) + + f, err := os.Create(brFilename) + if err != nil { + helper.Log.Panicf("could not create file '%s': %s", brFilename, err) + } + defer f.Close() + + bw := enc.NewBrotliWriter(f, nil) + defer bw.Close() + + if content != nil { + // content given + _, err = bw.Write(content) + if err != nil { + helper.Log.Panicf("could not write brotli content for '%s': %s", filename, err) + } + } else { + // read file + r, err := os.Open(filename) + if err != nil { + helper.Log.Panicf("could not open file '%s': %s", filename, err) + } + defer r.Close() + + _, err = io.Copy(bw, r) + if err != nil { + helper.Log.Panicf("could not write brotli file for '%s': %s", filename, err) + } + } +} diff --git a/pkg/mark2web/compress.go b/pkg/mark2web/compress.go index 6b97007..9fa39f8 100644 --- a/pkg/mark2web/compress.go +++ b/pkg/mark2web/compress.go @@ -1,7 +1,6 @@ package mark2web import ( - "bytes" "compress/gzip" "io" "io/ioutil" @@ -15,16 +14,26 @@ func handleCompression(filename string, content []byte) { ThreadStart(func() { if _, ok := Config.Compress.Extensions[path.Ext(filename)]; ok { + if Config.Compress.Brotli { + handleBrotliCompression(filename, content) + } + if Config.Compress.GZIP { gzFilename := filename + ".gz" helper.Log.Infof("writing to compressed output file: %s", gzFilename) - var buf bytes.Buffer - zw, err := gzip.NewWriterLevel(&buf, gzip.BestCompression) + f, err := os.Create(gzFilename) + if err != nil { + helper.Log.Panicf("could not create file '%s': %s", gzFilename, err) + } + defer f.Close() + + zw, err := gzip.NewWriterLevel(f, gzip.BestCompression) if err != nil { helper.Log.Panicf("could not initialize gzip writer for '%s': %s", filename, err) } + defer zw.Close() if content != nil { // content given @@ -34,32 +43,18 @@ func handleCompression(filename string, content []byte) { } } else { // read file - f, err := os.Open(filename) + r, err := os.Open(filename) if err != nil { helper.Log.Panicf("could not open file '%s': %s", filename, err) } - defer f.Close() - _, err = io.Copy(zw, f) + defer r.Close() + + _, err = io.Copy(zw, r) if err != nil { helper.Log.Panicf("could not gzip file '%s': %s", filename, err) } } - err = zw.Close() - if err != nil { - helper.Log.Panicf("could not close gziped content for '%s': %s", filename, err) - } - - f, err := os.Create(gzFilename) - if err != nil { - helper.Log.Panicf("could not create file '%s': %s", gzFilename, err) - } - defer f.Close() - - _, err = buf.WriteTo(f) - if err != nil { - helper.Log.Panicf("could not write to file '%s': %s", gzFilename, err) - } } } }) diff --git a/pkg/mark2web/config_global.go b/pkg/mark2web/config_global.go index 9f53a15..0ddb8e4 100644 --- a/pkg/mark2web/config_global.go +++ b/pkg/mark2web/config_global.go @@ -28,6 +28,7 @@ type GlobalConfig struct { } `yaml:"OtherFiles"` Compress struct { + Brotli bool `yaml:"Brotli"` GZIP bool `yaml:"GZIP"` Extensions map[string]string `yaml:"Extensions"` } `yaml:"Compress"` diff --git a/pkg/mark2web/htaccess.go b/pkg/mark2web/htaccess.go index 95117ea..637c2eb 100644 --- a/pkg/mark2web/htaccess.go +++ b/pkg/mark2web/htaccess.go @@ -26,35 +26,52 @@ func WriteWebserverConfig() { switch Config.Webserver.Type { case "apache": configStr := ` - AddCharset UTF-8 .html - AddCharset UTF-8 .json - AddCharset UTF-8 .js - AddCharset UTF-8 .css +AddCharset UTF-8 .html +AddCharset UTF-8 .json +AddCharset UTF-8 .js +AddCharset UTF-8 .css + +RemoveLanguage .br + + RewriteEngine on ` - if Config.Compress.GZIP { - for ext, contentType := range Config.Compress.Extensions { - rExt := regexp.QuoteMeta(ext) + rewriteMacro := func(e, c, x, xx string) string { + return ` - configStr += ` - RewriteCond "%{HTTP:Accept-encoding}" "gzip" - RewriteCond "%{REQUEST_FILENAME}\.gz" -s - RewriteRule "^(.*)` + rExt + `" "$1` + rExt + `\.gz" [QSA] + ######` + e + `.` + x + ` - RewriteRule "` + rExt + `\.gz$" "-" [E=no-gzip:1] + RewriteCond "%{HTTP:Accept-encoding}" "` + xx + `" + RewriteCond "%{REQUEST_FILENAME}\.` + x + `" -s + RewriteRule "^(.*)` + e + `" "$1` + e + `\.` + x + `" [QSA] - - ForceType '` + contentType + `; charset=UTF-8' - Header append Content-Encoding gzip + RewriteRule "` + e + `\.` + x + `$" "-" [E=no-gzip:1,E=no-brotli] + + + ForceType '` + c + `; charset=UTF-8' + Header append Content-Encoding ` + xx + ` Header append Vary Accept-Encoding ` + } + + for ext, contentType := range Config.Compress.Extensions { + rExt := regexp.QuoteMeta(ext) + if brotliSupported && Config.Compress.Brotli { + configStr += rewriteMacro(rExt, contentType, "br", "br") + } + if Config.Compress.GZIP { + configStr += rewriteMacro(rExt, contentType, "gz", "gzip") } } + configStr += ` + +` + if configStr != "" { htaccessFile := Config.Directories.Output + "/.htaccess" helper.Log.Noticef("writing webserver config to: %s", htaccessFile) diff --git a/pkg/mark2web/no_cgo.go b/pkg/mark2web/no_cgo.go new file mode 100644 index 0000000..123bc0d --- /dev/null +++ b/pkg/mark2web/no_cgo.go @@ -0,0 +1,14 @@ +// +build !cgo + +package mark2web + +import "gitbase.de/apairon/mark2web/pkg/helper" + +var brotliSupported = false + +func init() { + helper.Log.Warning("cgo is disabled, so brotli compression is not supported") +} + +func handleBrotliCompression(filename string, content []byte) { +} diff --git a/vendor/github.com/itchio/go-brotli b/vendor/github.com/itchio/go-brotli new file mode 160000 index 0000000..29899a4 --- /dev/null +++ b/vendor/github.com/itchio/go-brotli @@ -0,0 +1 @@ +Subproject commit 29899a447037af0c68028d70df58ac2faebf280c diff --git a/website/config.yml b/website/config.yml index 4ccce57..50972af 100644 --- a/website/config.yml +++ b/website/config.yml @@ -14,6 +14,7 @@ OtherFiles: Action: "copy" Compress: + Brotli: True GZIP: True Extensions: .html: text/html