From 080925324c4dbd37d141261f537bb2a5e6fadde3 Mon Sep 17 00:00:00 2001 From: Bert Frees Date: Tue, 18 Jun 2024 18:36:56 +0200 Subject: [PATCH] Include options for parameters defined in user agent stylesheets --- cli/cli.go | 2 +- cli/link.go | 55 ++++++++++++++++++++++- cli/mock_test.go | 4 ++ cli/scripts.go | 113 +++++++++++++++++++++++++++++++++++++++++++---- go.mod | 6 ++- go.sum | 2 + pom.xml | 2 +- 7 files changed, 169 insertions(+), 15 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index 044292d..1c04820 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -14,7 +14,7 @@ import ( ) const ( - VERSION = "2.1.9-SNAPSHOT" + VERSION = "2.2.0-SNAPSHOT" ) const ( diff --git a/cli/link.go b/cli/link.go index a3816ee..f8fc8e8 100644 --- a/cli/link.go +++ b/cli/link.go @@ -8,6 +8,7 @@ import ( "os" "time" "regexp" + "strings" "github.com/daisy/pipeline-clientlib-go" ) @@ -24,6 +25,7 @@ type PipelineApi interface { Scripts() (scripts pipeline.Scripts, err error) Script(id string) (script pipeline.Script, err error) JobRequest(newJob pipeline.JobRequest, data []byte) (job pipeline.Job, err error) + StylesheetParametersRequest(newReq pipeline.StylesheetParametersRequest, data []byte) (params pipeline.StylesheetParameters, err error) ScriptUrl(id string) string Job(string, int) (pipeline.Job, error) DeleteJob(id string) (bool, error) @@ -248,6 +250,16 @@ func (p PipelineLink) Execute(jobReq JobRequest) (job pipeline.Job, messages cha return } +func (p PipelineLink) StylesheetParameters(paramReq StylesheetParametersRequest) (params pipeline.StylesheetParameters, err error) { + req := pipeline.StylesheetParametersRequest{ + Media: pipeline.Media{Value: paramReq.Medium}, + UserAgentStylesheet: pipeline.UserAgentStylesheet{Mediatype: paramReq.ContentType}, + } + log.Printf("data len exec %v", len(paramReq.Data)) + params, err = p.pipeline.StylesheetParametersRequest(req, paramReq.Data) + return +} + //Feeds the channel with the messages describing the job's execution func getAsyncMessages(p PipelineLink, jobId string, messages chan Message) { msgNum := -1 @@ -306,6 +318,7 @@ func jobRequestToPipeline(req JobRequest, p PipelineLink) (pReq pipeline.JobRequ } pReq.Inputs = append(pReq.Inputs, input) } + var stylesheetParametersOption pipeline.Option for name, values := range req.Options { option := pipeline.Option{Name: name} if len(values) > 1 { @@ -315,8 +328,46 @@ func jobRequestToPipeline(req JobRequest, p PipelineLink) (pReq pipeline.JobRequ } else { option.Value = values[0] } - pReq.Options = append(pReq.Options, option) - + if name == "stylesheet-parameters" { + stylesheetParametersOption = option + } else { + pReq.Options = append(pReq.Options, option) + } + } + var params []string + for name, param := range req.StylesheetParameters { + switch param.Type.(type) { + case pipeline.XsBoolean, + pipeline.XsInteger, + pipeline.XsNonNegativeInteger: + params = append(params, fmt.Sprintf("%s: %s", name, param.Value)) + default: + params = append(params, + fmt.Sprintf("%s: '%s'", name, strings.NewReplacer( + "\n", "\\A ", + "'", "\\27 ", + ).Replace(param.Value))) + } + } + if (len(params) > 0) { + value := fmt.Sprintf("(%s)", strings.Join(params, ", ")) + if stylesheetParametersOption.Name == "" { + stylesheetParametersOption = pipeline.Option{Name: "stylesheet-parameters"} + stylesheetParametersOption.Value = value + } else { + if stylesheetParametersOption.Value != "" { + stylesheetParametersOption.Items = append( + stylesheetParametersOption.Items, + pipeline.Item{Value: stylesheetParametersOption.Value}) + stylesheetParametersOption.Value = "" + } + stylesheetParametersOption.Items = append( + stylesheetParametersOption.Items, + pipeline.Item{Value: value}) + } + } + if stylesheetParametersOption.Name != "" { + pReq.Options = append(pReq.Options, stylesheetParametersOption) } return } diff --git a/cli/mock_test.go b/cli/mock_test.go index 81c3ff8..d7721be 100644 --- a/cli/mock_test.go +++ b/cli/mock_test.go @@ -194,6 +194,10 @@ func (p *PipelineTest) JobRequest(newJob pipeline.JobRequest, data []byte) (job return } +func (p *PipelineTest) StylesheetParametersRequest(newReq pipeline.StylesheetParametersRequest, data []byte) (params pipeline.StylesheetParameters, err error) { + return +} + func (p *PipelineTest) DeleteJob(id string) (ok bool, err error) { if p.delete != nil { return p.delete(id) diff --git a/cli/scripts.go b/cli/scripts.go index 511094c..e6bcd86 100644 --- a/cli/scripts.go +++ b/cli/scripts.go @@ -24,23 +24,32 @@ var LastIdPath = getLastIdPath(runtime.GOOS) //Represents the job request type JobRequest struct { - Script string //Script id to call - Nicename string //Job's nicename - Priority string //Job's priority - Options map[string][]string //Options for the script - Inputs map[string][]url.URL //Input ports for the script - Data []byte //Data to send with the job request - Background bool //Send the request and return + Script string //Script id to call + Nicename string //Job's nicename + Priority string //Job's priority + Options map[string][]string //Options for the script + Inputs map[string][]url.URL //Input ports for the script + Data []byte //Data to send with the job request + Background bool //Send the request and return + StylesheetParameters map[string]pipeline.StylesheetParameter } //Creates a new JobRequest func newJobRequest() *JobRequest { return &JobRequest{ - Options: make(map[string][]string), - Inputs: make(map[string][]url.URL), + Options: make(map[string][]string), + Inputs: make(map[string][]url.URL), + StylesheetParameters: make(map[string]pipeline.StylesheetParameter), } } +//Represents the stylesheet-parameters request +type StylesheetParametersRequest struct { + Medium string + ContentType string + Data []byte +} + //Convinience method to add several scripts to a client func (c *Cli) AddScripts(scripts []pipeline.Script, link *PipelineLink) error { for _, s := range scripts { @@ -180,6 +189,28 @@ func flagsToString(flags []subcommand.Flag) []string { return res } +// FIXME: don't hard code +var mediumForScript = map[string]string { + "dtbook-to-daisy3": "speech", + "dtbook-to-epub3": "speech", + "dtbook-to-pef": "embossed", + "epub-to-daisy": "speech", + "epub3-to-epub3": "speech, embossed", + "epub3-to-pef": "embossed", + "html-to-pef": "embossed", + "zedai-to-epub3": "speech", +} +var contentTypeForScript = map[string]string { + "dtbook-to-daisy3": "application/x-dtbook+xml", + "dtbook-to-epub3": "application/x-dtbook+xml", + "dtbook-to-pef": "application/x-dtbook+xml", + "epub-to-daisy": "application/xhtml+xml", + "epub3-to-epub3": "application/xhtml+xml", + "epub3-to-pef": "application/xhtml+xml", + "html-to-pef": "application/xhtml+xml", + "zedai-to-epub3": "application/z3998-auth+xml", +} + //Adds the command and flags to be able to call the script to the cli func scriptToCommand(script pipeline.Script, cli *Cli, link *PipelineLink) (req *JobRequest, err error) { jobRequest := newJobRequest() @@ -224,6 +255,7 @@ func scriptToCommand(script pipeline.Script, cli *Cli, link *PipelineLink) (req command.AddOption(name, "", shortDesc, longDesc, italic("FILE"), inputFunc(jobRequest, link)).Must(input.Required) } + var hasStylesheetParametersOption bool for _, option := range script.Options { //desc:=option.Desc+ name := getFlagName(option.Name, "x-", command.Flags()) @@ -254,7 +286,53 @@ func scriptToCommand(script pipeline.Script, cli *Cli, link *PipelineLink) (req command.AddOption( name, "", shortDesc, longDesc, optionTypeToString(option.Type, name, option.Default), optionFunc(jobRequest, link, option.Type, option.Sequence)).Must(option.Required) + if option.Name == "stylesheet-parameters" { + hasStylesheetParametersOption = true + } + } + + if hasStylesheetParametersOption { + medium := mediumForScript[script.Id] + contentType := contentTypeForScript[script.Id] + if medium != "" && contentType != "" { + params, err := link.StylesheetParameters( + StylesheetParametersRequest{ + Medium: medium, + ContentType: contentType, + }) + if err != nil { + return jobRequest, err + } + for _, param := range params.Parameters { + name := getFlagName(param.Name, "x-", command.Flags()) + shortDesc := param.ShortDesc + longDesc := param.LongDesc + possibleValues := optionTypeToDetailedHelp(param.Type) + if (possibleValues != "") { + longDesc += ("\n\nPossible values: " + possibleValues) + } + longDesc += "\n\nDefault value: " + if param.Default == "" { + longDesc += "(empty)" + } else { + longDesc += "`" + param.Default + "`" + } + if (shortDesc != "" && strings.HasPrefix(longDesc, shortDesc + "\n\n")) { + // don't interpret first line as markdown + longDesc = shortDesc + "\n\n" + blackterm.MarkdownString(longDesc[len(shortDesc)+2:]) + } else { + longDesc = blackterm.MarkdownString(longDesc) + } + if (shortDesc == "") { + shortDesc = param.NiceName + } + command.AddOption( + name, "", shortDesc, longDesc, optionTypeToString(param.Type, name, param.Default), + paramFunc(jobRequest, link, param)).Must(false) + } + } } + command.AddOption("output", "o", "Path where to store the results. This option is mandatory when the job is not executed in the background", "", italic("DIRECTORY"), func(name, folder string) error { jExec.output = folder return nil @@ -495,6 +573,23 @@ func optionFunc(req *JobRequest, link *PipelineLink, optionType pipeline.DataTyp } } +//Returns a function that fills the stylesheet-parameters option with the subcommand option name +//and value +func paramFunc(req *JobRequest, link *PipelineLink, param pipeline.StylesheetParameter) func(string, string) error { + return func(name, value string) error { + if strings.HasPrefix("x-", name) { + name = name[2:] + } + value, err := validateOption(value, param.Type, link) + if err != nil { + return validationError(name, value, err) + } + param.Value = value; + req.StylesheetParameters[name] = param + return nil + } +} + func validationError(optionName, value string, cause error) error { msg := "'" + value + "' is not allowed as the value for option --" + optionName if cause != nil { diff --git a/go.mod b/go.mod index e70886e..75e7c0e 100644 --- a/go.mod +++ b/go.mod @@ -2,13 +2,15 @@ module github.com/daisy/pipeline-cli-go go 1.19 +// replace github.com/daisy/pipeline-clientlib-go => /Users/bert/src/github/daisy/pipeline/clientlib/go + require ( github.com/bertfrees/blackterm v0.0.0-20230119134958-9d34cff72a06 github.com/bertfrees/go-subcommand v0.0.0-20230119135135-b5e2f5321a24 github.com/capitancambio/chalk v0.0.0-20160127153406-9dc2af224a17 github.com/capitancambio/restclient v0.0.0-20150219172137-547c7b5e0857 - // go get github.com/daisy/pipeline-clientlib-go@be58359f0d - github.com/daisy/pipeline-clientlib-go v0.0.0-20231222112022-be58359f0dc7 + // go get github.com/daisy/pipeline-clientlib-go@3aeed200be + github.com/daisy/pipeline-clientlib-go v0.0.0-20240710161849-3aeed200be9b github.com/hashicorp/go-version v1.0.0 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 github.com/mattn/goveralls v0.0.11 diff --git a/go.sum b/go.sum index 3c3389c..0da50a3 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/daisy/pipeline-clientlib-go v0.0.0-20231222110436-b4071cde0d7f h1:RpH github.com/daisy/pipeline-clientlib-go v0.0.0-20231222110436-b4071cde0d7f/go.mod h1:EqAuNzs3I84oUiMMlo787kGYRaNKozEPMfThpfj+sW8= github.com/daisy/pipeline-clientlib-go v0.0.0-20231222112022-be58359f0dc7 h1:7UrPVu10K/PzN7YYmF7hYpzrqklTovHpLEWjQBK8U0s= github.com/daisy/pipeline-clientlib-go v0.0.0-20231222112022-be58359f0dc7/go.mod h1:EqAuNzs3I84oUiMMlo787kGYRaNKozEPMfThpfj+sW8= +github.com/daisy/pipeline-clientlib-go v0.0.0-20240710161849-3aeed200be9b h1:e06Z1gi/CD3FJgPOMpkXJzgooOwaGeTQLGG56FQzW/Q= +github.com/daisy/pipeline-clientlib-go v0.0.0-20240710161849-3aeed200be9b/go.mod h1:EqAuNzs3I84oUiMMlo787kGYRaNKozEPMfThpfj+sW8= github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8= github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= diff --git a/pom.xml b/pom.xml index df6b0bc..0bf7994 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ org.daisy.pipeline cli - 2.1.9-SNAPSHOT + 2.2.0-SNAPSHOT pom DAISY Pipeline 2 :: Command Line Interface Command Line Interface for the DAISY Pipeline 2.