Skip to content

Commit ebc28e1

Browse files
authored
Compile extract all artifacts in "sketch/build" folder (arduino#687)
* Deprecated exportFile/importFile in favor of exportDir/importDir * Updated compile/upload cli commands * Compile now saves artifacts in 'sketch/build/<FQBN>/...' folder * Upload now uses export folder * Test fix: use --output-dir option instead of deprecated --output * Text fix: no more need to check if "extension won't be added if already present" * Added Debug.ImportDir and deprecated Debug.ImportFile * Upload now uses export folder * Fixed GetCommandLine test * Fixed test_core_install_esp32
1 parent c387167 commit ebc28e1

File tree

20 files changed

+345
-237
lines changed

20 files changed

+345
-237
lines changed

cli/compile/compile.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ var (
4646
uploadAfterCompile bool // Upload the binary after the compilation.
4747
port string // Upload port, e.g.: COM10 or /dev/ttyACM0.
4848
verify bool // Upload, verify uploaded binary after the upload.
49-
exportFile string // The compiled binary is written to this file
49+
exportDir string // The compiled binary is written to this file
5050
dryRun bool // Use this flag to now write the output file
5151
libraries []string // List of custom libraries paths separated by commas. Or can be used multiple times for multiple libraries paths.
5252
optimizeForDebug bool // Optimize compile output for debug, not for release
@@ -67,7 +67,7 @@ func NewCommand() *cobra.Command {
6767
command.Flags().BoolVar(&showProperties, "show-properties", false, "Show all build properties used instead of compiling.")
6868
command.Flags().BoolVar(&preprocess, "preprocess", false, "Print preprocessed code to stdout instead of compiling.")
6969
command.Flags().StringVar(&buildCachePath, "build-cache-path", "", "Builds of 'core.a' are saved into this path to be cached and reused.")
70-
command.Flags().StringVarP(&exportFile, "output", "o", "", "Filename of the compile output.")
70+
command.Flags().StringVarP(&exportDir, "output-dir", "", "", "Save build artifacts in this directory.")
7171
command.Flags().BoolVarP(&dryRun, "dry-run", "n", false, "Perform the build but do not copy the compile output file.")
7272
command.Flags().StringVar(&buildPath, "build-path", "",
7373
"Path where to save compiled files. If omitted, a directory will be created in the default temporary path of your OS.")
@@ -115,7 +115,7 @@ func run(cmd *cobra.Command, args []string) {
115115
Verbose: verbose,
116116
Quiet: quiet,
117117
VidPid: vidPid,
118-
ExportFile: exportFile,
118+
ExportDir: exportDir,
119119
DryRun: dryRun,
120120
Libraries: libraries,
121121
OptimizeForDebug: optimizeForDebug,
@@ -134,7 +134,7 @@ func run(cmd *cobra.Command, args []string) {
134134
Port: port,
135135
Verbose: verbose,
136136
Verify: verify,
137-
ImportFile: exportFile,
137+
ImportDir: exportDir,
138138
}, os.Stdout, os.Stderr)
139139

140140
if err != nil {

cli/debug/debug.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ var (
3737
verbose bool
3838
verify bool
3939
interpreter string
40-
importFile string
40+
importDir string
4141
)
4242

4343
// NewCommand created a new `upload` command
@@ -54,7 +54,7 @@ func NewCommand() *cobra.Command {
5454
debugCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno")
5555
debugCommand.Flags().StringVarP(&port, "port", "p", "", "Debug port, e.g.: COM10 or /dev/ttyACM0")
5656
debugCommand.Flags().StringVar(&interpreter, "interpreter", "console", "Debug interpreter e.g.: console, mi, mi1, mi2, mi3")
57-
debugCommand.Flags().StringVarP(&importFile, "input", "i", "", "Input file to be uploaded for debug.")
57+
debugCommand.Flags().StringVarP(&importDir, "input-dir", "", "", "Direcory containing binaries for debug.")
5858

5959
return debugCommand
6060
}
@@ -82,7 +82,7 @@ func run(command *cobra.Command, args []string) {
8282
SketchPath: sketchPath.String(),
8383
Port: port,
8484
Interpreter: interpreter,
85-
ImportFile: importFile,
85+
ImportDir: importDir,
8686
}, os.Stdin, os.Stdout, ctrlc); err != nil {
8787
feedback.Errorf("Error during Debug: %v", err)
8888
os.Exit(errorcodes.ErrGeneric)

cli/upload/upload.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ import (
3030
)
3131

3232
var (
33-
fqbn string
34-
port string
35-
verbose bool
36-
verify bool
37-
importFile string
33+
fqbn string
34+
port string
35+
verbose bool
36+
verify bool
37+
importDir string
3838
)
3939

4040
// NewCommand created a new `upload` command
@@ -50,7 +50,7 @@ func NewCommand() *cobra.Command {
5050

5151
uploadCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno")
5252
uploadCommand.Flags().StringVarP(&port, "port", "p", "", "Upload port, e.g.: COM10 or /dev/ttyACM0")
53-
uploadCommand.Flags().StringVarP(&importFile, "input", "i", "", "Input file to be uploaded.")
53+
uploadCommand.Flags().StringVarP(&importDir, "input-dir", "", "", "Direcory containing binaries to upload.")
5454
uploadCommand.Flags().BoolVarP(&verify, "verify", "t", false, "Verify uploaded binary after the upload.")
5555
uploadCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, "Optional, turns on verbose mode.")
5656

@@ -77,7 +77,7 @@ func run(command *cobra.Command, args []string) {
7777
Port: port,
7878
Verbose: verbose,
7979
Verify: verify,
80-
ImportFile: importFile,
80+
ImportDir: importDir,
8181
}, os.Stdout, os.Stderr); err != nil {
8282
feedback.Errorf("Error during Upload: %v", err)
8383
os.Exit(errorcodes.ErrGeneric)

commands/compile/compile.go

Lines changed: 33 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package compile
1717

1818
import (
1919
"context"
20-
"errors"
2120
"fmt"
2221
"io"
2322
"path/filepath"
@@ -37,6 +36,7 @@ import (
3736
"github.com/arduino/arduino-cli/telemetry"
3837
paths "github.com/arduino/go-paths-helper"
3938
properties "github.com/arduino/go-properties-orderedmap"
39+
"github.com/pkg/errors"
4040
"github.com/segmentio/stats/v4"
4141
"github.com/sirupsen/logrus"
4242
"github.com/spf13/viper"
@@ -55,11 +55,16 @@ func Compile(ctx context.Context, req *rpc.CompileReq, outStream, errStream io.W
5555
"verbose": strconv.FormatBool(req.Verbose),
5656
"quiet": strconv.FormatBool(req.Quiet),
5757
"vidPid": req.VidPid,
58-
"exportFile": telemetry.Sanitize(req.ExportFile),
58+
"exportFile": telemetry.Sanitize(req.ExportFile), // deprecated
59+
"exportDir": telemetry.Sanitize(req.GetExportDir()),
5960
"jobs": strconv.FormatInt(int64(req.Jobs), 10),
6061
"libraries": strings.Join(req.Libraries, ","),
6162
}
6263

64+
if req.GetExportFile() != "" {
65+
outStream.Write([]byte(fmt.Sprintln("Compile.ExportFile has been deprecated. The ExportFile parameter will be ignored, use ExportDir instead.")))
66+
}
67+
6368
// Use defer func() to evaluate tags map when function returns
6469
// and set success flag inspecting the error named return parameter
6570
defer func() {
@@ -197,54 +202,38 @@ func Compile(ctx context.Context, req *rpc.CompileReq, outStream, errStream io.W
197202
}
198203

199204
if !req.GetDryRun() {
200-
// FIXME: Make a function to obtain these info...
201-
outputPath := paths.New(
202-
builderCtx.BuildProperties.ExpandPropsInString("{build.path}/{recipe.output.tmp_file}")) // "/build/path/sketch.ino.bin"
203-
ext := outputPath.Ext() // ".hex" | ".bin"
204-
base := outputPath.Base() // "sketch.ino.hex"
205-
base = base[:len(base)-len(ext)] // "sketch.ino"
206-
207-
// FIXME: Make a function to produce a better name...
208-
// Make the filename without the FQBN configs part
209-
fqbnSuffix := strings.Replace(fqbn.StringWithoutConfig(), ":", ".", -1)
210-
211205
var exportPath *paths.Path
212-
var exportFile string
213-
if req.GetExportFile() == "" {
214-
exportPath = sketch.FullPath
215-
exportFile = sketch.Name + "." + fqbnSuffix // "sketch.arduino.avr.uno"
206+
if exportDir := req.GetExportDir(); exportDir != "" {
207+
exportPath = paths.New(exportDir)
216208
} else {
217-
exportPath = paths.New(req.GetExportFile()).Parent()
218-
exportFile = paths.New(req.GetExportFile()).Base()
219-
if strings.HasSuffix(exportFile, ext) {
220-
exportFile = exportFile[:len(exportFile)-len(ext)]
221-
}
209+
exportPath = sketch.FullPath
210+
// Add FQBN (without configs part) to export path
211+
fqbnSuffix := strings.Replace(fqbn.StringWithoutConfig(), ":", ".", -1)
212+
exportPath = exportPath.Join("build").Join(fqbnSuffix)
213+
}
214+
logrus.WithField("path", exportPath).Trace("Saving sketch to export path.")
215+
if err := exportPath.MkdirAll(); err != nil {
216+
return nil, errors.Wrap(err, "creating output dir")
222217
}
223218

224-
// Copy "sketch.ino.*.hex" / "sketch.ino.*.bin" artifacts to sketch directory
225-
srcDir, err := outputPath.Parent().ReadDir() // read "/build/path/*"
226-
if err != nil {
227-
return nil, fmt.Errorf("reading build directory: %s", err)
219+
// Copy all "sketch.ino.*" artifacts to the export directory
220+
baseName, ok := builderCtx.BuildProperties.GetOk("build.project_name") // == "sketch.ino"
221+
if !ok {
222+
return nil, errors.New("missing 'build.project_name' build property")
228223
}
229-
srcDir.FilterPrefix(base + ".")
230-
srcDir.FilterSuffix(ext)
231-
for _, srcOutput := range srcDir {
232-
srcFilename := srcOutput.Base() // "sketch.ino.*.bin"
233-
srcFilename = srcFilename[len(base):] // ".*.bin"
234-
dstOutput := exportPath.Join(exportFile + srcFilename)
235-
logrus.WithField("from", srcOutput).WithField("to", dstOutput).Debug("copying sketch build output")
236-
if err = srcOutput.CopyTo(dstOutput); err != nil {
237-
return nil, fmt.Errorf("copying output file: %s", err)
238-
}
224+
buildFiles, err := builderCtx.BuildPath.ReadDir()
225+
if err != nil {
226+
return nil, errors.Errorf("reading build directory: %s", err)
239227
}
240-
241-
// Copy .elf file to sketch directory
242-
srcElf := outputPath.Parent().Join(base + ".elf")
243-
if srcElf.Exist() {
244-
dstElf := exportPath.Join(exportFile + ".elf")
245-
logrus.WithField("from", srcElf).WithField("to", dstElf).Debug("copying sketch build output")
246-
if err = srcElf.CopyTo(dstElf); err != nil {
247-
return nil, fmt.Errorf("copying elf file: %s", err)
228+
buildFiles.FilterPrefix(baseName)
229+
for _, buildFile := range buildFiles {
230+
exportedFile := exportPath.Join(buildFile.Base())
231+
logrus.
232+
WithField("src", buildFile).
233+
WithField("dest", exportedFile).
234+
Trace("Copying artifact.")
235+
if err = buildFile.CopyTo(exportedFile); err != nil {
236+
return nil, errors.Wrapf(err, "copying output file %s", buildFile)
248237
}
249238
}
250239
}

commands/debug/debug.go

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out
115115

116116
// getCommandLine compose a debug command represented by a core recipe
117117
func getCommandLine(req *dbg.DebugConfigReq, pm *packagemanager.PackageManager) ([]string, error) {
118+
if req.GetImportFile() != "" {
119+
return nil, errors.New("the ImportFile parameter has been deprecated, use ImportDir instead")
120+
}
121+
118122
// TODO: make a generic function to extract sketch from request
119123
// and remove duplication in commands/compile.go
120124
if req.GetSketchPath() == "" {
@@ -185,40 +189,24 @@ func getCommandLine(req *dbg.DebugConfigReq, pm *packagemanager.PackageManager)
185189
}
186190
}
187191

188-
// Set path to compiled binary
189-
// Make the filename without the FQBN configs part
190-
fqbn.Configs = properties.NewMap()
191-
fqbnSuffix := strings.Replace(fqbn.String(), ":", ".", -1)
192-
193192
var importPath *paths.Path
194-
var importFile string
195-
if req.GetImportFile() == "" {
196-
importPath = sketch.FullPath
197-
importFile = sketch.Name + "." + fqbnSuffix
193+
if importDir := req.GetImportDir(); importDir != "" {
194+
importPath = paths.New(importDir)
198195
} else {
199-
importPath = paths.New(req.GetImportFile()).Parent()
200-
importFile = paths.New(req.GetImportFile()).Base()
196+
// TODO: Create a function to obtain importPath from sketch
197+
importPath = sketch.FullPath
198+
// Add FQBN (without configs part) to export path
199+
fqbnSuffix := strings.Replace(fqbn.StringWithoutConfig(), ":", ".", -1)
200+
importPath = importPath.Join("build").Join(fqbnSuffix)
201201
}
202-
203-
outputTmpFile, ok := toolProperties.GetOk("recipe.output.tmp_file")
204-
outputTmpFile = toolProperties.ExpandPropsInString(outputTmpFile)
205-
if !ok {
206-
return nil, fmt.Errorf("property 'recipe.output.tmp_file' not defined")
202+
if !importPath.Exist() {
203+
return nil, fmt.Errorf("compiled sketch not found in %s", importPath)
207204
}
208-
ext := filepath.Ext(outputTmpFile)
209-
if strings.HasSuffix(importFile, ext) {
210-
importFile = importFile[:len(importFile)-len(ext)]
205+
if !importPath.IsDir() {
206+
return nil, fmt.Errorf("expected compiled sketch in directory %s, but is a file instead", importPath)
211207
}
212-
213208
toolProperties.SetPath("build.path", importPath)
214-
toolProperties.Set("build.project_name", importFile)
215-
uploadFile := importPath.Join(importFile + ext)
216-
if _, err := uploadFile.Stat(); err != nil {
217-
if os.IsNotExist(err) {
218-
return nil, fmt.Errorf("compiled sketch %s not found", uploadFile.String())
219-
}
220-
return nil, errors.Wrap(err, "cannot open sketch")
221-
}
209+
toolProperties.Set("build.project_name", sketch.Name+".ino")
222210

223211
// Set debug port property
224212
port := req.GetPort()

commands/debug/debug_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func TestGetCommandLine(t *testing.T) {
5656
fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s", dataDir, toolExtension) +
5757
fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) +
5858
fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg\"", customHardware) +
59-
fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.arduino_zero_edbg.elf", sketchPath)
59+
fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/build/arduino-test.samd.arduino_zero_edbg/hello.ino.elf", sketchPath)
6060

6161
command, err := getCommandLine(req, pm)
6262
assert.Nil(t, err)
@@ -77,7 +77,7 @@ func TestGetCommandLine(t *testing.T) {
7777
fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s", dataDir, toolExtension) +
7878
fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) +
7979
fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/mkr1000/openocd_scripts/arduino_zero.cfg\"", customHardware) +
80-
fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/hello.arduino-test.samd.mkr1000.elf", sketchPath)
80+
fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/build/arduino-test.samd.mkr1000/hello.ino.elf", sketchPath)
8181

8282
command2, err := getCommandLine(req2, pm)
8383
assert.Nil(t, err)

commands/upload/upload.go

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import (
2020
"fmt"
2121
"io"
2222
"net/url"
23-
"os"
24-
"path/filepath"
2523
"strings"
2624
"time"
2725

@@ -147,40 +145,25 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
147145
uploadProperties.Set("upload.verify", uploadProperties.Get("upload.params.noverify"))
148146
}
149147

150-
// Set path to compiled binary
151-
// Make the filename without the FQBN configs part
152-
fqbn.Configs = properties.NewMap()
153-
fqbnSuffix := strings.Replace(fqbn.String(), ":", ".", -1)
154-
155148
var importPath *paths.Path
156-
var importFile string
157-
if req.GetImportFile() == "" {
158-
importPath = sketch.FullPath
159-
importFile = sketch.Name + "." + fqbnSuffix
149+
if importDir := req.GetImportDir(); importDir != "" {
150+
importPath = paths.New(importDir)
160151
} else {
161-
importPath = paths.New(req.GetImportFile()).Parent()
162-
importFile = paths.New(req.GetImportFile()).Base()
152+
// TODO: Create a function to obtain importPath from sketch
153+
importPath = sketch.FullPath
154+
// Add FQBN (without configs part) to export path
155+
fqbnSuffix := strings.Replace(fqbn.StringWithoutConfig(), ":", ".", -1)
156+
importPath = importPath.Join("build").Join(fqbnSuffix)
163157
}
164158

165-
outputTmpFile, ok := uploadProperties.GetOk("recipe.output.tmp_file")
166-
outputTmpFile = uploadProperties.ExpandPropsInString(outputTmpFile)
167-
if !ok {
168-
return nil, fmt.Errorf("property 'recipe.output.tmp_file' not defined")
159+
if !importPath.Exist() {
160+
return nil, fmt.Errorf("compiled sketch not found in %s", importPath)
169161
}
170-
ext := filepath.Ext(outputTmpFile)
171-
if strings.HasSuffix(importFile, ext) {
172-
importFile = importFile[:len(importFile)-len(ext)]
162+
if !importPath.IsDir() {
163+
return nil, fmt.Errorf("expected compiled sketch in directory %s, but is a file instead", importPath)
173164
}
174-
175165
uploadProperties.SetPath("build.path", importPath)
176-
uploadProperties.Set("build.project_name", importFile)
177-
uploadFile := importPath.Join(importFile + ext)
178-
if _, err := uploadFile.Stat(); err != nil {
179-
if os.IsNotExist(err) {
180-
return nil, fmt.Errorf("compiled sketch %s not found", uploadFile.String())
181-
}
182-
return nil, fmt.Errorf("cannot open sketch: %s", err)
183-
}
166+
uploadProperties.Set("build.project_name", sketch.Name+".ino")
184167

185168
// Perform reset via 1200bps touch if requested
186169
if uploadProperties.GetBoolean("upload.use_1200bps_touch") {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy