|
| 1 | +/* |
| 2 | +Copyright © 2021 NAME HERE <EMAIL ADDRESS> |
| 3 | +
|
| 4 | +*/ |
| 5 | +package cmd |
| 6 | + |
| 7 | +import ( |
| 8 | + "encoding/json" |
| 9 | + "os" |
| 10 | + "os/exec" |
| 11 | + |
| 12 | + "github.com/arduino/go-paths-helper" |
| 13 | + "github.com/sirupsen/logrus" |
| 14 | + "github.com/spf13/cobra" |
| 15 | +) |
| 16 | + |
| 17 | +var fqbn string |
| 18 | + |
| 19 | +// compileOutput represents the json returned by the arduino-cli compile command |
| 20 | +type CompileOutput struct { |
| 21 | + CompilerErr string `json:"compiler_err"` |
| 22 | + BuilderResult *BuilderResult `json:"builder_result"` |
| 23 | + Success bool `json:"success"` |
| 24 | +} |
| 25 | + |
| 26 | +type BuilderResult struct { |
| 27 | + BuildPath string `json:"build_path"` |
| 28 | + UsedLibraries []*UsedLibrary `json:"used_libraries"` |
| 29 | + BuildPlatform *BuildPlatform `json:"build_platform"` |
| 30 | +} |
| 31 | + |
| 32 | +// UsedLibrary contains information regarding the library used during the compile process |
| 33 | +type UsedLibrary struct { |
| 34 | + Name string `json:"name"` |
| 35 | + Version string `json:"version"` |
| 36 | +} |
| 37 | + |
| 38 | +// BuildPlatform contains information regarding the platform used during the compile process |
| 39 | +type BuildPlatform struct { |
| 40 | + Id string `json:"id"` |
| 41 | + Version string `json:"version"` |
| 42 | +} |
| 43 | + |
| 44 | +// ResultJson contains information regarding the core and libraries used during the compile process |
| 45 | +type ResultJson struct { |
| 46 | + CoreInfo *BuildPlatform `json:"coreInfo"` |
| 47 | + LibsInfo []*UsedLibrary `json:"libsInfo"` |
| 48 | +} |
| 49 | + |
| 50 | +// compileCmd represents the compile command |
| 51 | +var compileCmd = &cobra.Command{ |
| 52 | + Use: "compile", |
| 53 | + Short: "Compiles Arduino sketches.", |
| 54 | + Long: `Compiles Arduino sketches outputting an object file and a json file in a build directory |
| 55 | + The json contains information regarding libraries and core to use in order to build the sketch`, |
| 56 | + Example: os.Args[0] + `compile -b arduino:avr:uno /home/umberto/Arduino/Blink`, |
| 57 | + Args: cobra.ExactArgs(1), // the path of the sketch to build |
| 58 | + Run: compileSketch, |
| 59 | +} |
| 60 | + |
| 61 | +func init() { |
| 62 | + rootCmd.AddCommand(compileCmd) |
| 63 | + compileCmd.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno") |
| 64 | + compileCmd.MarkFlagRequired("fqbn") |
| 65 | +} |
| 66 | + |
| 67 | +func compileSketch(cmd *cobra.Command, args []string) { |
| 68 | + logrus.Debug("compile called") |
| 69 | + |
| 70 | + // let's check the arduino-cli version |
| 71 | + cmdOutput, err := exec.Command("arduino-cli", "version", "--format", "json").Output() |
| 72 | + if err != nil { |
| 73 | + logrus.Warn("Before running this tool be sure to have arduino-cli installed in your $PATH") |
| 74 | + logrus.Fatal(err) |
| 75 | + } |
| 76 | + var unmarshalledOutput map[string]interface{} |
| 77 | + json.Unmarshal(cmdOutput, &unmarshalledOutput) |
| 78 | + logrus.Infof("arduino-cli version: %s", unmarshalledOutput["VersionString"]) |
| 79 | + |
| 80 | + // let's call arduino-cli compile and parse the verbose output |
| 81 | + logrus.Infof("running: arduino-cli compile -b %s %s -v --format json", fqbn, args[0]) |
| 82 | + cmdOutput, err = exec.Command("arduino-cli", "compile", "-b", fqbn, args[0], "-v", "--format", "json").Output() |
| 83 | + if err != nil { |
| 84 | + logrus.Fatal(err) |
| 85 | + } |
| 86 | + objFilesPaths, returnJson := parseOutput(cmdOutput) |
| 87 | + |
| 88 | + workingDir, err := paths.Getwd() |
| 89 | + if err != nil { |
| 90 | + logrus.Fatal(err) |
| 91 | + } |
| 92 | + buildDir := workingDir.Join("build") |
| 93 | + if !buildDir.Exist() { |
| 94 | + if err = buildDir.Mkdir(); err != nil { |
| 95 | + logrus.Fatal(err) |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + // Copy the object files from the `<tempdir>/arduino-sketch_stuff/sketch` folder |
| 100 | + for _, objFilePath := range objFilesPaths { |
| 101 | + destObjFilePath := buildDir.Join(objFilePath.Base()) |
| 102 | + if err = objFilePath.CopyTo(destObjFilePath); err != nil { |
| 103 | + logrus.Errorf("error copying object file: %s", err) |
| 104 | + } else { |
| 105 | + logrus.Infof("copied file to %s", destObjFilePath) |
| 106 | + } |
| 107 | + } |
| 108 | + |
| 109 | + // save the result.json in the build dir |
| 110 | + jsonFilePath := buildDir.Join("result.json") |
| 111 | + if jsonContents, err := json.MarshalIndent(returnJson, "", " "); err != nil { |
| 112 | + logrus.Errorf("error serializing json: %s", err) |
| 113 | + } else if err := jsonFilePath.WriteFile(jsonContents); err != nil { |
| 114 | + logrus.Errorf("error writing result.json: %s", err) |
| 115 | + } else { |
| 116 | + logrus.Infof("created new file in: %s", jsonFilePath) |
| 117 | + } |
| 118 | +} |
| 119 | + |
| 120 | +// parseOutput function takes cmdOutToParse as argument, |
| 121 | +// cmdOutToParse is the json output captured from the command run |
| 122 | +// the function extracts and returns the paths of the .o files |
| 123 | +// (generated during the compile phase) and a ReturnJson object |
| 124 | +func parseOutput(cmdOutToParse []byte) ([]*paths.Path, *ResultJson) { |
| 125 | + var compileOutput CompileOutput |
| 126 | + err := json.Unmarshal(cmdOutToParse, &compileOutput) |
| 127 | + if err != nil { |
| 128 | + logrus.Fatal(err) |
| 129 | + } else if !compileOutput.Success { |
| 130 | + logrus.Fatalf("sketch compile was not successful: %s", compileOutput.CompilerErr) |
| 131 | + } |
| 132 | + |
| 133 | + // this dir contains all the obj files we need (the sketch related ones and not the core or libs) |
| 134 | + sketchDir := paths.New(compileOutput.BuilderResult.BuildPath).Join("sketch") |
| 135 | + sketchFilesPaths, err := sketchDir.ReadDir() |
| 136 | + if err != nil { |
| 137 | + logrus.Fatal(err) |
| 138 | + } else if len(sketchFilesPaths) == 0 { |
| 139 | + logrus.Fatalf("empty directory: %s", sketchDir) |
| 140 | + } |
| 141 | + sketchFilesPaths.FilterSuffix(".o") |
| 142 | + |
| 143 | + returnJson := ResultJson{ |
| 144 | + CoreInfo: compileOutput.BuilderResult.BuildPlatform, |
| 145 | + LibsInfo: compileOutput.BuilderResult.UsedLibraries, |
| 146 | + } |
| 147 | + |
| 148 | + return sketchFilesPaths, &returnJson |
| 149 | +} |
0 commit comments