From b4ade07ba6c306e21b0154cb92b418efa42d838e Mon Sep 17 00:00:00 2001 From: Jacob Jonsson Date: Mon, 12 Aug 2024 17:52:03 +0200 Subject: [PATCH] feat: allow `generate` command to generate a single DBC file This commit allows a user to run cantool generate INPUT OUTPUT-DIRECTORY where INPUT is either a path to a DBC file. Previously it was only possible to provide INPUT as a directory containing DBC files. N.B. When INPUT is a directory containing DBC files the generated files are created in OUTPUT-DIRECTORY relative to where they are found in INPUT. As an example, given the following directory structure: dbc/ powertrain/pt.dbc steering/steer.dbc brake/brake.dbc A `cantool generate dbc/ gen/go` call will generate the following structure: gen/go/ powertrain/pt.dbc.go steering/steer.dbc.go brake/brake.dbc.go However, when INPUT is a single DBC file it is generated directly in OUTPUT-DIRECTORY with its basename as the stem. `cantool generate dbc/steering/steer.dbc gen/go/steering` will therefore generate the gen/go/steering/steer.dbc.go. --- README.md | 41 ++++++++++++++++++++++++++++++++++++++++- cmd/cantool/main.go | 14 +++++++++----- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e3a330c..2daf760 100644 --- a/README.md +++ b/README.md @@ -75,13 +75,52 @@ func main() { It is possible to generate Go code from a `.dbc` file. ``` -$ go run go.einride.tech/can/cmd/cantool generate +$ go run go.einride.tech/can/cmd/cantool generate ``` +The INPUT argument can be either a directory containing DBC files, or the path +to a single DBC file. + +#### Placement of generated code + +OUTPUT FOLDER is treated slightly different dependeing on whether INPUT is a +file or a directory. + +When INPUT is a directory containing DBC files the generated files are created +in OUTPUT-DIRECTORY relative to where they are found in INPUT. + +As an example, given the following directory structure: + +``` +dbc/ + powertrain/pt.dbc + steering/steer.dbc + brake/brake.dbc +``` + +A `cantool generate dbc/ gen/go` call will generate the following structure: + +``` +gen/go/ + powertrain/pt.dbc.go + steering/steer.dbc.go + brake/brake.dbc.go +``` + +When INPUT is a single DBC file it is generated directly in OUTPUT-DIRECTORY +with its basename as the stem. + +`cantool generate dbc/steering/steer.dbc gen/go/steering` will therefore +generate the gen/go/steering/steer.dbc.go. + +#### Linting + In order to generate Go code that makes sense, we currently perform some validations when parsing the DBC file so there may need to be some changes on the DBC file to make it work +#### Using generated code + After generating Go code we can marshal a message to a frame: ```go diff --git a/cmd/cantool/main.go b/cmd/cantool/main.go index 885186f..a005fc5 100644 --- a/cmd/cantool/main.go +++ b/cmd/cantool/main.go @@ -44,26 +44,30 @@ func main() { func generateCommand(app *kingpin.Application) { command := app.Command("generate", "generate CAN messages") - inputDir := command. - Arg("input-dir", "input directory"). + fileOrDir := command. + Arg("input", "input DBC file, if is a directory all contained DBC files will be generated"). Required(). - ExistingDir() + ExistingFileOrDir() outputDir := command. Arg("output-dir", "output directory"). Required(). String() command.Action(func(_ *kingpin.ParseContext) error { - return filepath.Walk(*inputDir, func(p string, i os.FileInfo, err error) error { + return filepath.Walk(*fileOrDir, func(p string, i os.FileInfo, err error) error { if err != nil { return err } if i.IsDir() || filepath.Ext(p) != ".dbc" { return nil } - relPath, err := filepath.Rel(*inputDir, p) + relPath, err := filepath.Rel(*fileOrDir, p) if err != nil { return err } + if relPath == "." { + // happens if fileOrDir points directly to the DBC file + relPath = filepath.Base(*fileOrDir) + } outputFile := relPath + ".go" outputPath := filepath.Join(*outputDir, outputFile) return genGo(p, outputPath)