-progress cli param for bars

This commit is contained in:
Sebastian Frank 2019-03-25 14:01:28 +01:00
parent 740fb94556
commit 267d1010bb
Signed by: apairon
GPG Key ID: 7270D06DDA7FE8C3
12 changed files with 166 additions and 38 deletions

12
.gitmodules vendored
View File

@ -79,3 +79,15 @@
[submodule "vendor/github.com/itchio/go-brotli"]
path = vendor/github.com/itchio/go-brotli
url = https://github.com/itchio/go-brotli
[submodule "vendor/github.com/gosuri/uiprogress"]
path = vendor/github.com/gosuri/uiprogress
url = https://github.com/gosuri/uiprogress
[submodule "vendor/github.com/gosuri/uilive"]
path = vendor/github.com/gosuri/uilive
url = https://github.com/gosuri/uilive
[submodule "vendor/github.com/mattn/go-tty"]
path = vendor/github.com/mattn/go-tty
url = https://github.com/mattn/go-tty
[submodule "vendor/golang.org/x/sys"]
path = vendor/golang.org/x/sys
url = https://go.googlesource.com/sys

View File

@ -9,6 +9,7 @@ import (
"gitbase.de/apairon/mark2web/pkg/filter"
"gitbase.de/apairon/mark2web/pkg/logger"
"gitbase.de/apairon/mark2web/pkg/mark2web"
"gitbase.de/apairon/mark2web/pkg/progress"
)
var (
@ -26,6 +27,7 @@ func main() {
createOutDir := flag.Bool("create", false, "create output directory if not existing")
//clearOutDir := flag.Bool("clear", false, "clear output directory before generating website")
logLevel := flag.String("logLevel", "notice", "log level: debug, info, notice, warning, error")
progressBars := flag.Bool("progress", false, "show progress bars for jobs")
version := flag.Bool("version", false, "print version of this executable")
flag.Parse()
@ -43,6 +45,10 @@ func main() {
}
logger.SetLogLevel(level)
if progressBars != nil && *progressBars {
progress.Init()
}
if inDir == nil || *inDir == "" {
logger.Log.Panic("input directory not specified")
}

View File

@ -5,6 +5,9 @@ import (
"errors"
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"net/http"
"net/url"
"os"
@ -107,27 +110,18 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *
p.Quality,
)
if strings.HasPrefix(imgSource, "http://") || strings.HasPrefix(imgSource, "https://") {
// remote file
img, p.Format, err = getImageFromURL(imgSource)
if err != nil {
return nil, &pongo2.Error{
Sender: "filter:image_resize",
OrigError: fmt.Errorf("could not open image '%s': %s", imgSource, err),
}
}
// build filename
if p.Filename == "" {
var fBase string
if u, _ := url.Parse(imgSource); u != nil {
fBase = strings.Split(path.Base(u.Path), ".")[0]
fBase = path.Base(u.Path)
}
p.Filename = fmt.Sprintf(
"%s_%x_%s.%s",
"%s_%x_%s",
filePrefix,
md5.Sum([]byte(imgSource)),
fBase,
p.Format,
)
}
} else {
@ -173,13 +167,12 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *
Function: func() {
logger.Log.Noticef("processing image from %s to %s", imgSource, imgTarget)
if strings.HasPrefix(imgSource, "http://") || strings.HasPrefix(imgSource, "https://") {
// webrequest before finding target filename, because of file format in filename
// remote file
img, p.Format, err = getImageFromURL(imgSource)
} else {
img, err = imaging.Open(imgSource, imaging.AutoOrientation(true))
if err != nil {
logger.Log.Panicf("filter:image_resize, could not open image '%s': %s", imgSource, err)
}
}
logger.Eexit(err, "filter:image_resize, could not open image '%s'", imgSource)
switch p.Process {
case "resize":
@ -217,18 +210,47 @@ func ImageProcessFilter(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *
logger.Log.Panicf("filter:image_resize, invalid p parameter '%s'", p.Process)
}
var encodeOptions = make([]imaging.EncodeOption, 0)
if p.Quality > 0 {
encodeOptions = append(encodeOptions, imaging.JPEGQuality(p.Quality))
if p.Format == "" {
switch strings.ToLower(path.Ext(imgTarget)) {
case ".jpg", ".jpeg", ".gif", ".png":
var encodeOptions = make([]imaging.EncodeOption, 0)
if p.Quality > 0 {
encodeOptions = append(encodeOptions, imaging.JPEGQuality(p.Quality))
}
err = imaging.Save(img, imgTarget, encodeOptions...)
logger.Eerr(err, "filter:image_resize, could save image '%s'", imgTarget)
default:
logger.E("filter:image_resize, invalid filename extension for image: %s", imgTarget)
os.Exit(1)
}
} else {
out, err := os.Create(imgTarget)
defer out.Close()
logger.Eerr(err, "filter:image_resize, could not create image file '%s'", imgTarget)
switch p.Format {
case "jpeg", "jpg":
var jpegOpt *jpeg.Options
if p.Quality > 0 {
jpegOpt = &jpeg.Options{
Quality: p.Quality,
}
}
err = jpeg.Encode(out, img, jpegOpt)
case "png":
err = png.Encode(out, img)
case "gif":
err = gif.Encode(out, img, nil)
default:
logger.E("filter:image_resize, unknown format '%s' for '%s'", p.Format, imgSource)
}
logger.Eerr(err, "filter:image_resize, could not encode image file '%s'", imgTarget)
}
err = imaging.Save(img, imgTarget, encodeOptions...)
if err != nil {
logger.Log.Panicf("filter:image_resize, could save image '%s': %s", imgTarget, err)
}
logger.Log.Noticef("finished image: %s", imgTarget)
},
Description: "process image " + imgSource,
Description: imgSource,
Category: "image process",
})
}

View File

@ -4,6 +4,7 @@ import (
"os"
"testing"
"gitbase.de/apairon/mark2web/pkg/jobm"
"gitbase.de/apairon/mark2web/pkg/mark2web"
"github.com/flosch/pongo2"
@ -19,7 +20,7 @@ func TestImageProcessFilter(t *testing.T) {
}
// we want to check files after function calls, so no multithreading
mark2web.SetNumCPU(1)
jobm.SetNumCPU(1)
mark2web.Config.Directories.Input = "../../test/in"
mark2web.Config.Directories.Output = "../../test/out"

13
pkg/helper/string.go Normal file
View File

@ -0,0 +1,13 @@
package helper
// ShortenStringLeft shortens a string
func ShortenStringLeft(str string, num int) string {
tstr := str
if len(str) > num {
if num > 3 {
num -= 3
}
tstr = "..." + str[len(str)-num:len(str)]
}
return tstr
}

View File

@ -3,8 +3,9 @@ package jobm
import (
"runtime"
"sync"
"time"
"gitbase.de/apairon/mark2web/pkg/logger"
"gitbase.de/apairon/mark2web/pkg/progress"
)
var wg sync.WaitGroup
@ -17,37 +18,40 @@ type Job struct {
Category string
}
var jobChan = make(chan Job)
var jobChan = make(chan []Job)
func worker(jobChan <-chan Job) {
func worker(jobChan <-chan []Job) {
defer wg.Done()
for job := range jobChan {
job.Function()
for jobs := range jobChan {
for _, job := range jobs {
progress.DescribeCurrent(job.Category, job.Description)
job.Function()
progress.IncrDone(job.Category)
}
}
}
func init() {
logger.Log.Infof("number of CPU core: %d", numCPU)
//logger.Log.Infof("number of CPU core: %d", numCPU)
// one core for main thread
for i := 0; i < (numCPU - 1); i++ {
for i := 0; i < numCPU; i++ {
wg.Add(1)
go worker(jobChan)
}
}
// Enqueue enqueues a job to the job queue
func Enqueue(job Job) {
if numCPU <= 1 {
// no threading
job.Function()
return
func Enqueue(jobs ...Job) {
for _, job := range jobs {
progress.IncrTotal(job.Category)
}
jobChan <- job
jobChan <- jobs
}
// Wait will wait for all jobs to finish
func Wait() {
time.Sleep(time.Millisecond * 300)
close(jobChan)
wg.Wait()
}

View File

@ -61,7 +61,7 @@ func handleCompression(filename string, content []byte) {
}
}
},
Description: "compress " + filename,
Description: filename,
Category: "compress",
})
}

66
pkg/progress/bar.go Normal file
View File

@ -0,0 +1,66 @@
package progress
import (
"fmt"
"gitbase.de/apairon/mark2web/pkg/helper"
"github.com/gosuri/uiprogress"
"github.com/mattn/go-tty"
)
type bar struct {
Bar *uiprogress.Bar
Description string
}
var bars = make(map[string]*bar)
var initialized = false
var terminalWidth = 80
// Init initializes the bar drawing
func Init() {
if t, err := tty.Open(); err == nil && t != nil {
terminalWidth, _, _ = t.Size()
t.Close()
}
uiprogress.Start() // start rendering
initialized = true
}
// IncrTotal increases the total jobs for the bar
func IncrTotal(barname string) {
if initialized {
_bar := bars[barname]
if _bar == nil {
_bar = new(bar)
_bar.Bar = uiprogress.AddBar(1)
_bar.Bar.Width = 25
_bar.Bar.PrependFunc(func(b *uiprogress.Bar) string {
return fmt.Sprintf("%15s: %3d/%3d", helper.ShortenStringLeft(barname, 15), b.Current(), b.Total)
})
_bar.Bar.AppendFunc(func(b *uiprogress.Bar) string {
return fmt.Sprintf("%s", helper.ShortenStringLeft(_bar.Description, terminalWidth-80))
})
bars[barname] = _bar
} else {
_bar.Bar.Total++
}
}
}
// IncrDone increases to done jobs counter
func IncrDone(barname string) {
if initialized {
bars[barname].Bar.Incr()
bars[barname].Description = ""
}
}
// DescribeCurrent describes the current job
func DescribeCurrent(barname, description string) {
if initialized {
bars[barname].Description = description
}
}

1
vendor/github.com/gosuri/uilive generated vendored Submodule

@ -0,0 +1 @@
Subproject commit ac356e6e42cd31fcef8e6aec13ae9ed6fe87713e

1
vendor/github.com/gosuri/uiprogress generated vendored Submodule

@ -0,0 +1 @@
Subproject commit d0567a9d84a1c40dd7568115ea66f4887bf57b33

1
vendor/github.com/mattn/go-tty generated vendored Submodule

@ -0,0 +1 @@
Subproject commit 5518497423d1a71429a4bea2a4536ef5939c3c27

1
vendor/golang.org/x/sys generated vendored Submodule

@ -0,0 +1 @@
Subproject commit f49334f85ddcf0f08d7fb6dd7363e9e6d6b777eb