From 35d34ddd1195e97277002c581c406990b744071f Mon Sep 17 00:00:00 2001 From: Tigor Hutasuhut Date: Wed, 3 Jul 2024 21:57:45 +0700 Subject: [PATCH] update implementation --- go.mod | 16 +++++++++---- go.sum | 23 ++++++++++++++++-- lib/workflow/context.go | 24 +++++++++++++++++++ lib/workflow/open.go | 48 +++++++++++++------------------------ lib/workflow/steps.go | 52 ++++++++++++++++++++++++++++++++++++++++ lib/workflow/workflow.go | 9 ++++--- 6 files changed, 130 insertions(+), 42 deletions(-) create mode 100644 lib/workflow/context.go create mode 100644 lib/workflow/steps.go diff --git a/go.mod b/go.mod index 5a904d9..c40e8fa 100644 --- a/go.mod +++ b/go.mod @@ -2,13 +2,21 @@ module github.com/tigorlazuardi/qbitrun go 1.22.3 +require ( + github.com/samber/lo v1.44.0 + github.com/spf13/cobra v1.8.1 + github.com/stretchr/testify v1.9.0 + gopkg.in/yaml.v3 v3.0.1 +) + require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/kr/pretty v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect + github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/testify v1.9.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect ) diff --git a/go.sum b/go.sum index 78a8e26..1ba8cb7 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,38 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/samber/lo v1.44.0 h1:5il56KxRE+GHsm1IR+sZ/6J42NODigFiqCWpSc2dybA= +github.com/samber/lo v1.44.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/lib/workflow/context.go b/lib/workflow/context.go new file mode 100644 index 0000000..2a957e4 --- /dev/null +++ b/lib/workflow/context.go @@ -0,0 +1,24 @@ +package workflow + +type Context struct { + TorrentName string + Category string + Tags []string + ContentPath string + RootPath string + SavePath string + NumberOfFiles int + TorrentSize uint64 + CurrentTracker string + InfoHashV1 string + InfoHashV2 string + TorrentID string + AddEvent bool +} + +func (c Context) AsMap() map[string]any { + return map[string]any{ + "torrent_name": c.TorrentName, + "category": c.Category, + } +} diff --git a/lib/workflow/open.go b/lib/workflow/open.go index b13f52d..1bb60d2 100644 --- a/lib/workflow/open.go +++ b/lib/workflow/open.go @@ -7,17 +7,17 @@ import ( "os" "path/filepath" - "github.com/sourcegraph/conc/iter" + lop "github.com/samber/lo/parallel" "gopkg.in/yaml.v3" ) -type WorkflowFiles []io.ReadCloser +type WorkflowFiles []io.Reader func (wo WorkflowFiles) Close() error { var errs []error - for _, rc := range wo { - if err := rc.Close(); err != nil { - errs = append(errs, err) + for _, reader := range wo { + if reader, ok := reader.(io.ReadCloser); ok { + errs = append(errs, reader.Close()) } } return errors.Join(errs...) @@ -25,19 +25,21 @@ func (wo WorkflowFiles) Close() error { func (wo WorkflowFiles) Workflows() ([]Workflow, error) { var ( - errs = make([]error, len(wo)) - workflows = make([]Workflow, len(wo)) + errs = []error{} + workflows = make([]Workflow, 0, len(wo)) ) - iter.ForEachIdx(wo, func(i int, rc *io.ReadCloser) { + lop.ForEach(wo, func(reader io.Reader, _ int) { var w Workflow - if err := yaml.NewDecoder(*rc).Decode(&w); err != nil { - errs[i] = err + if err := yaml.NewDecoder(reader).Decode(&w); err != nil { + errs = append(errs, err) } else { - workflows[i] = w + workflows = append(workflows, w) } - if err := (*rc).Close(); err != nil && errs[i] == nil { - errs[i] = err + if rc, ok := reader.(io.ReadCloser); ok { + if err := rc.Close(); err != nil { + errs = append(errs, err) + } } }) @@ -50,7 +52,7 @@ type DirFilter = func(path string, d fs.FileInfo) bool // // Set filter to filter out unwanted files. func OpenDir(dir string, filters ...DirFilter) (WorkflowFiles, error) { - var files []io.ReadCloser + var files []io.Reader err := filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { if err != nil { return err @@ -81,14 +83,6 @@ func OpenDir(dir string, filters ...DirFilter) (WorkflowFiles, error) { return WorkflowFiles(files), nil } -// WorkflowFromReadClosers creates a WorkflowInput from a list of io.ReadCloser. -// -// WorkflowFromReadClosers assumes ownership of the ReadClosers and will close -// all of them after the WorkflowInput is consumed (whether successfully or not). -func WorkflowFromReadClosers(rcs ...io.ReadCloser) WorkflowFiles { - return WorkflowFiles(rcs) -} - // WorkflowFromReaders creates a WorkflowInput from a list of io.Reader. // // If the Reader implements io.ReadCloser, it will be used as is. @@ -97,13 +91,5 @@ func WorkflowFromReadClosers(rcs ...io.ReadCloser) WorkflowFiles { // WorkflowFromReaders assumes ownership of the Readers and will close (if implements io.ReadCloser) // all of them after the WorkflowInput is consumed (whether successfully or not). func WorkflowFromReaders(readers ...io.Reader) WorkflowFiles { - var rcs []io.ReadCloser - for _, r := range readers { - if rc, ok := r.(io.ReadCloser); ok { - rcs = append(rcs, rc) - } else { - rcs = append(rcs, io.NopCloser(r)) - } - } - return WorkflowFiles(rcs) + return WorkflowFiles(readers) } diff --git a/lib/workflow/steps.go b/lib/workflow/steps.go new file mode 100644 index 0000000..f8f7ed3 --- /dev/null +++ b/lib/workflow/steps.go @@ -0,0 +1,52 @@ +package workflow + +import ( + "fmt" + "io" + "strings" + + "github.com/valyala/fasttemplate" +) + +type Step struct { + Name string `yaml:"name"` + Run string `yaml:"run"` + Shell string `yaml:"shell"` +} + +func (s Step) RenderCommand(c Context) string { + return fasttemplate.ExecuteFuncString(s.Run, "{{", "}}", func(w io.Writer, tag string) (int, error) { + switch tag { + case "torrent_name": + return fmt.Fprintf(w, "%q", c.TorrentName) + case "!torrent_name": + return io.WriteString(w, c.TorrentName) + case "category": + return fmt.Fprintf(w, "%q", c.Category) + case "!category": + return io.WriteString(w, c.Category) + case "tags": + return fmt.Fprintf(w, "%q", strings.Join(c.Tags, ",")) + case "!tags": + return io.WriteString(w, strings.Join(c.Tags, ",")) + default: + if strings.HasPrefix(tag, "tags[") { + var index int + if n, _ := fmt.Sscanf(tag, "tags[%d]", &index); n > 0 { + if len(c.Tags) > index { + return fmt.Fprintf(w, "%q", c.Tags[index]) + } + } + } + if strings.HasPrefix(tag, "!tags[") { + var index int + if n, _ := fmt.Sscanf(tag, "!tags[%d]", &index); n > 0 { + if len(c.Tags) > index { + return io.WriteString(w, c.Tags[index]) + } + } + } + return 0, nil + } + }) +} diff --git a/lib/workflow/workflow.go b/lib/workflow/workflow.go index 4602e10..806db87 100644 --- a/lib/workflow/workflow.go +++ b/lib/workflow/workflow.go @@ -1,6 +1,10 @@ package workflow type WorkflowInput interface { + // Workflows returns a slice of Workflows. + // It returns an error if any of the workflows are invalid. + // + // Implementor must clean up any resources (e.g. closing files) after transformation. Workflows() ([]Workflow, error) } @@ -12,8 +16,3 @@ type Workflow struct { } type Jobs map[string]Job - -type Step struct { - Name string `yaml:"name"` - Run string `yaml:"run"` -}