From 3cf02cd62ef4289587b0b145e002403cde1aca12 Mon Sep 17 00:00:00 2001 From: isubasinghe Date: Wed, 5 Jan 2022 11:09:02 +1100 Subject: [PATCH] feat: added cli for cwl transpiler Signed-off-by: isubasinghe --- cmd/cwl2argo/commands/root.go | 40 +++++++++++++++++ cmd/cwl2argo/commands/transpile.go | 65 +++++++++++++++++++++++++++ cmd/cwl2argo/main.go | 25 +++++++++++ cmd/cwl2argo/transpiler/transpiler.go | 46 +++++++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 cmd/cwl2argo/commands/root.go create mode 100644 cmd/cwl2argo/commands/transpile.go create mode 100644 cmd/cwl2argo/main.go create mode 100644 cmd/cwl2argo/transpiler/transpiler.go diff --git a/cmd/cwl2argo/commands/root.go b/cmd/cwl2argo/commands/root.go new file mode 100644 index 000000000000..95e58893eced --- /dev/null +++ b/cmd/cwl2argo/commands/root.go @@ -0,0 +1,40 @@ +package commands + +import ( + "github.com/argoproj/argo-workflows/v3/util/cmd" + "github.com/argoproj/pkg/cli" + "github.com/spf13/cobra" +) + +const ( + CLIName = "cwl2argo" +) + +var ( + logLevel string + logFormat string +) + +func init() { + cobra.OnInitialize(initConfig) +} + +func initConfig() { + cmd.SetLogFormatter(logFormat) + cli.SetLogLevel(logLevel) +} + +func NewRootCommand() *cobra.Command { + command := cobra.Command{ + Use: CLIName, + Short: "cwl2argo transpiles cwl to argo yaml", + Run: func(cmd *cobra.Command, args []string) { + cmd.HelpFunc()(cmd, args) + }, + } + command.AddCommand(NewTranspileCommand()) + command.PersistentFlags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error") + command.PersistentFlags().StringVar(&logFormat, "log-format", "text", "The formatter to use for logs. One of: text|json") + + return &command +} diff --git a/cmd/cwl2argo/commands/transpile.go b/cmd/cwl2argo/commands/transpile.go new file mode 100644 index 000000000000..93baab0f1f38 --- /dev/null +++ b/cmd/cwl2argo/commands/transpile.go @@ -0,0 +1,65 @@ +package commands + +import ( + "errors" + "fmt" + "path/filepath" + + "github.com/argoproj/argo-workflows/v3/cmd/cwl2argo/transpiler" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func lengthError() error { + return errors.New("length of filename should always be greater than the length of the extension") +} + +func invalidFileError(inputFileExt string) error { + return fmt.Errorf("invalid file extension %s, only common workflow language (.cwl) files are allowed", inputFileExt) +} +func extractNoExtFileName(filename string, ext string) (string, error) { + if len(filename) <= len(ext) { + return "", lengthError() + } + name := filename[0 : len(filename)-len(ext)] + return name, nil +} + +func processFile(inputFile string, inputsFile string) { + + ext := filepath.Ext(inputFile) + if ext != ".cwl" { + log.Fatalf("%+v", invalidFileError(ext)) + } + name, err := extractNoExtFileName(inputFile, ext) + if err != nil { + log.Fatalf("%+v", err) + } + newName := fmt.Sprintf("argo_%s.yaml", name) + log.Infof("Transpiling file %s with extension %s and ext free name %s to %s", inputFile, ext, name, newName) + err = transpiler.TranspileFile(inputFile, inputsFile, newName) + if err != nil { + log.Fatalf("%+v", err) + } + +} + +// Cobra command to transpile +func NewTranspileCommand() *cobra.Command { + + command := cobra.Command{ + Use: "transpile", + Short: "input common workflow language file", + Args: func(cmd *cobra.Command, args []string) error { + if len(args) != 2 { + return errors.New("transpile only accepts two arguments and ") + } + return nil + }, + Run: func(cmd *cobra.Command, args []string) { + processFile(args[0], args[1]) + }, + } + + return &command +} diff --git a/cmd/cwl2argo/main.go b/cmd/cwl2argo/main.go new file mode 100644 index 000000000000..1662d1e6a281 --- /dev/null +++ b/cmd/cwl2argo/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "os" + "os/exec" + + "github.com/argoproj/argo-workflows/v3/cmd/cwl2argo/commands" +) + +func main() { + + err := commands.NewRootCommand().Execute() + if err != nil { + if exitError, ok := err.(*exec.ExitError); ok { + if exitError.ExitCode() >= 0 { + os.Exit(exitError.ExitCode()) + } else { + os.Exit(137) // probably SIGTERM or SIGKILL + } + } else { + println(err.Error()) + os.Exit(64) + } + } +} diff --git a/cmd/cwl2argo/transpiler/transpiler.go b/cmd/cwl2argo/transpiler/transpiler.go new file mode 100644 index 000000000000..7e3dffe998a5 --- /dev/null +++ b/cmd/cwl2argo/transpiler/transpiler.go @@ -0,0 +1,46 @@ +package transpiler + +import ( + "errors" + "os" + + log "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" +) + +const ( + CWLVersion = "v1.2" +) + +func TranspileFile(inputFile string, inputsFile string, outputFile string) error { + + log.Warn("Currently the transpiler expects preprocessed CWL input, cwlpack is the recommended way of preprocessing, use cwlpack from here https://github.com/rabix/sbpack/tree/84bd7867a0630a826280a702db715377aa879f6a") + var cwl map[string]interface{} + var inputs map[string]interface{} + + def, err := os.ReadFile(inputFile) + if err != nil { + return err + } + + err = yaml.Unmarshal(def, &cwl) + if err != nil { + return err + } + + data, err := os.ReadFile(inputsFile) + if err != nil { + return err + } + + err = yaml.Unmarshal(data, &inputs) + if err != nil { + return err + } + + if _, ok := cwl["class"]; !ok { + return errors.New(" expected") + } + + return nil +}