Skip to content

Allow upload using binaries from build-path #675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions cli/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ var (
port string // Upload port, e.g.: COM10 or /dev/ttyACM0.
verify bool // Upload, verify uploaded binary after the upload.
exportFile string // The compiled binary is written to this file
dryRun bool // Use this flag to now write the output file
dryRun bool // Use this flag to not write the output file
libraries []string // List of custom libraries paths separated by commas. Or can be used multiple times for multiple libraries paths.
optimizeForDebug bool // Optimize compile output for debug, not for release
)
Expand Down Expand Up @@ -128,13 +128,15 @@ func run(cmd *cobra.Command, args []string) {

if uploadAfterCompile {
_, err := upload.Upload(context.Background(), &rpc.UploadReq{
Instance: inst,
Fqbn: fqbn,
SketchPath: sketchPath.String(),
Port: port,
Verbose: verbose,
Verify: verify,
ImportFile: exportFile,
Instance: inst,
Fqbn: fqbn,
SketchPath: sketchPath.String(),
Port: port,
Verbose: verbose,
Verify: verify,
ImportFile: exportFile,
BuildPath: buildPath,
ImportFromBuildPath: true,
}, os.Stdout, os.Stderr)

if err != nil {
Expand Down
30 changes: 18 additions & 12 deletions cli/upload/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ import (
)

var (
fqbn string
port string
verbose bool
verify bool
importFile string
fqbn string
port string
verbose bool
verify bool
importFile string
buildPath string
importFromBuildPath bool
)

// NewCommand created a new `upload` command
Expand All @@ -53,6 +55,8 @@ func NewCommand() *cobra.Command {
uploadCommand.Flags().StringVarP(&importFile, "input", "i", "", "Input file to be uploaded.")
uploadCommand.Flags().BoolVarP(&verify, "verify", "t", false, "Verify uploaded binary after the upload.")
uploadCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, "Optional, turns on verbose mode.")
uploadCommand.Flags().StringVarP(&buildPath, "build-path", "", "", "Optional, specify build path (can be used with --upload-from-build-path).")
uploadCommand.Flags().BoolVarP(&importFromBuildPath, "upload-from-build-path", "n", false, "Optional, use binaries produced in build path for uploading.")

return uploadCommand
}
Expand All @@ -71,13 +75,15 @@ func run(command *cobra.Command, args []string) {
sketchPath := initSketchPath(path)

if _, err := upload.Upload(context.Background(), &rpc.UploadReq{
Instance: instance,
Fqbn: fqbn,
SketchPath: sketchPath.String(),
Port: port,
Verbose: verbose,
Verify: verify,
ImportFile: importFile,
Instance: instance,
Fqbn: fqbn,
SketchPath: sketchPath.String(),
Port: port,
Verbose: verbose,
Verify: verify,
ImportFile: importFile,
ImportFromBuildPath: importFromBuildPath,
BuildPath: buildPath,
}, os.Stdout, os.Stderr); err != nil {
feedback.Errorf("Error during Upload: %v", err)
os.Exit(errorcodes.ErrGeneric)
Expand Down
2 changes: 2 additions & 0 deletions commands/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"strconv"
"strings"

bldr "github.com/arduino/arduino-cli/arduino/builder"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/arduino/sketches"
Expand Down Expand Up @@ -114,6 +115,7 @@ func Compile(ctx context.Context, req *rpc.CompileReq, outStream, errStream io.W
builderCtx.PackageManager = pm
builderCtx.FQBN = fqbn
builderCtx.SketchLocation = sketch.FullPath
builderCtx.BuildPath = bldr.GenBuildPath(sketch.FullPath)

// FIXME: This will be redundant when arduino-builder will be part of the cli
builderCtx.HardwareDirs = configuration.HardwareDirectories()
Expand Down
124 changes: 86 additions & 38 deletions commands/upload/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"strings"
"time"

"github.com/arduino/arduino-cli/arduino/builder"
"github.com/arduino/arduino-cli/arduino/cores"
"github.com/arduino/arduino-cli/arduino/sketches"
"github.com/arduino/arduino-cli/cli/feedback"
Expand All @@ -51,6 +52,7 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
if err != nil {
return nil, fmt.Errorf("opening sketch: %s", err)
}
logrus.WithField("sketchPath", sketchPath).Trace("Sketch to upload")

// FIXME: make a specification on how a port is specified via command line
port := req.GetPort()
Expand All @@ -66,6 +68,7 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
if port == "" {
return nil, fmt.Errorf("no upload port provided")
}
logrus.WithField("port", port).Trace("Port used for upload")

fqbnIn := req.GetFqbn()
if fqbnIn == "" && sketch != nil && sketch.Metadata != nil {
Expand All @@ -78,6 +81,7 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
if err != nil {
return nil, fmt.Errorf("incorrect FQBN: %s", err)
}
logrus.WithField("fqbn", fqbn).Trace("FQBN used for upload")

pm := commands.GetPackageManager(req.GetInstance().GetId())

Expand All @@ -88,17 +92,18 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
}

// Load programmer tool
uploadToolPattern, have := boardProperties.GetOk("upload.tool")
if !have || uploadToolPattern == "" {
uploadToolName, have := boardProperties.GetOk("upload.tool")
if !have || uploadToolName == "" {
return nil, fmt.Errorf("cannot get programmer tool: undefined 'upload.tool' property")
}
logrus.WithField("upload.tool", uploadToolName).Trace("Tool to use for upload")

var referencedPlatformRelease *cores.PlatformRelease
if split := strings.Split(uploadToolPattern, ":"); len(split) > 2 {
return nil, fmt.Errorf("invalid 'upload.tool' property: %s", uploadToolPattern)
if split := strings.Split(uploadToolName, ":"); len(split) > 2 {
return nil, fmt.Errorf("invalid 'upload.tool' property: %s", uploadToolName)
} else if len(split) == 2 {
referencedPackageName := split[0]
uploadToolPattern = split[1]
uploadToolName = split[1]
architecture := board.PlatformRelease.Platform.Architecture

if referencedPackage := pm.Packages[referencedPackageName]; referencedPackage == nil {
Expand All @@ -108,6 +113,10 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
} else {
referencedPlatformRelease = pm.GetInstalledPlatformRelease(referencedPlatform)
}
logrus.
WithField("upload.tool", uploadToolName).
WithField("referencedPlatform", referencedPlatformRelease).
Trace("Tool to use for upload")
}

// Build configuration for upload
Expand All @@ -119,7 +128,7 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
uploadProperties.Merge(board.PlatformRelease.RuntimeProperties())
uploadProperties.Merge(boardProperties)

uploadToolProperties := uploadProperties.SubTree("tools." + uploadToolPattern)
uploadToolProperties := uploadProperties.SubTree("tools." + uploadToolName)
uploadProperties.Merge(uploadToolProperties)

if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil {
Expand All @@ -130,62 +139,90 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
}

// Set properties for verbose upload
Verbose := req.GetVerbose()
if Verbose {
if req.GetVerbose() {
if v, ok := uploadProperties.GetOk("upload.params.verbose"); ok {
uploadProperties.Set("upload.verbose", v)
logrus.WithField("upload.verbose", v).Trace("Setting verbosity")
}
} else {
if v, ok := uploadProperties.GetOk("upload.params.quiet"); ok {
uploadProperties.Set("upload.verbose", v)
logrus.WithField("upload.verbose", v).Trace("Setting verbosity")
}
}

// Set properties for verify
Verify := req.GetVerify()
if Verify {
if req.GetVerify() {
uploadProperties.Set("upload.verify", uploadProperties.Get("upload.params.verify"))
} else {
uploadProperties.Set("upload.verify", uploadProperties.Get("upload.params.noverify"))
}
logrus.WithField("upload.verify", uploadProperties.Get("upload.verify")).Trace("Setting verify")

// Set path to compiled binary
// Make the filename without the FQBN configs part
fqbn.Configs = properties.NewMap()
fqbnSuffix := strings.Replace(fqbn.String(), ":", ".", -1)

var importPath *paths.Path
var importFile string
if req.GetImportFile() == "" {
importPath = sketch.FullPath
importFile = sketch.Name + "." + fqbnSuffix

// The upload recipes uses "{build.path}/{build.project_name}.hex" to
// obtain the path to the binary to upload. This works without well if
// the {build.path} directory used for the build is still available (for
// example if the upload is run straight after the compile)...
if req.GetImportFromBuildPath() {

if p := req.GetBuildPath(); p == "" {
uploadProperties.SetPath("build.path", builder.GenBuildPath(sketch.FullPath))
} else {
uploadProperties.Set("build.path", p)
}
uploadProperties.Set("build.project_name", sketch.Name+".ino")

} else {
importPath = paths.New(req.GetImportFile()).Parent()
importFile = paths.New(req.GetImportFile()).Base()
}
// ...otherwise {build.path} and {build.project_name} should be
// tweaked so the upload tool will point to the sketch folder or
// the import files specified by the user.

var importPath *paths.Path
var importFile string
if req.GetImportFile() == "" {
// Make the filename without the FQBN configs part
fqbn.Configs = properties.NewMap()
fqbnSuffix := strings.Replace(fqbn.String(), ":", ".", -1)
importPath = sketch.FullPath
importFile = sketch.Name + "." + fqbnSuffix
logrus.WithField("importPath", importPath).WithField("importFile", importFile).Trace("Import binary from sketch")
} else {
// Use the import file specified by the user
importPath = paths.New(req.GetImportFile()).Parent()
importFile = paths.New(req.GetImportFile()).Base()
logrus.WithField("importPath", importPath).WithField("importFile", importFile).Trace("Import binary from user provided path")
}

outputTmpFile, ok := uploadProperties.GetOk("recipe.output.tmp_file")
outputTmpFile = uploadProperties.ExpandPropsInString(outputTmpFile)
if !ok {
return nil, fmt.Errorf("property 'recipe.output.tmp_file' not defined")
}
ext := filepath.Ext(outputTmpFile)
if strings.HasSuffix(importFile, ext) {
importFile = importFile[:len(importFile)-len(ext)]
}
outputTmpFile, ok := uploadProperties.GetOk("recipe.output.tmp_file")
if !ok {
return nil, fmt.Errorf("property 'recipe.output.tmp_file' not defined")
}
outputTmpFile = uploadProperties.ExpandPropsInString(outputTmpFile)
logrus.WithField("recipe.output.tmp_file", outputTmpFile).Trace("Platform variable value")
ext := filepath.Ext(outputTmpFile)
if strings.HasSuffix(importFile, ext) {
importFile = importFile[:len(importFile)-len(ext)]
logrus.WithField("importPath", importPath).WithField("importFile", importFile).Trace("Adjusted importFile value (removed extension)")
}

uploadProperties.SetPath("build.path", importPath)
uploadProperties.Set("build.project_name", importFile)
uploadFile := importPath.Join(importFile + ext)
if _, err := uploadFile.Stat(); err != nil {
if os.IsNotExist(err) {
return nil, fmt.Errorf("compiled sketch %s not found", uploadFile.String())
uploadProperties.SetPath("build.path", importPath)
uploadProperties.Set("build.project_name", importFile)
logrus.WithField("build.path", importPath).Trace("Set build.path value")
logrus.WithField("build.project_name", importFile).Trace("Set build.project_name value")
uploadFile := importPath.Join(importFile + ext)
if _, err := uploadFile.Stat(); err != nil {
if os.IsNotExist(err) {
return nil, fmt.Errorf("compiled sketch %s not found", uploadFile.String())
}
return nil, fmt.Errorf("cannot open sketch: %s", err)
}
return nil, fmt.Errorf("cannot open sketch: %s", err)
}

// Perform reset via 1200bps touch if requested
if uploadProperties.GetBoolean("upload.use_1200bps_touch") {
logrus.WithField("upload.use_1200bps_touch", "true").Trace("Performing 1200 bps touch")
ports, err := serial.GetPortsList()
if err != nil {
return nil, fmt.Errorf("cannot get serial port list: %s", err)
Expand All @@ -209,13 +246,15 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
// Wait for upload port if requested
actualPort := port // default
if uploadProperties.GetBoolean("upload.wait_for_upload_port") {
logrus.WithField("upload.wait_for_upload_port", "true").Trace("Waiting for upload port...")
if p, err := waitForNewSerialPort(); err != nil {
return nil, fmt.Errorf("cannot detect serial ports: %s", err)
} else if p == "" {
feedback.Print("No new serial port detected.")
} else {
actualPort = p
}
logrus.WithField("port", actualPort).Trace("...new serial port found!")

// on OS X, if the port is opened too quickly after it is detected,
// a "Resource busy" error occurs, add a delay to workaround.
Expand All @@ -230,14 +269,23 @@ func Upload(ctx context.Context, req *rpc.UploadReq, outStream io.Writer, errStr
} else {
uploadProperties.Set("serial.port.file", actualPort)
}
logrus.
WithField("serial.port", actualPort). //
WithField("serial.port.file", uploadProperties.Get("serial.port.file")). //
Trace("Set property")

// Build recipe for upload
recipe := uploadProperties.Get("upload.pattern")
cmdLine := uploadProperties.ExpandPropsInString(recipe)
logrus.WithField("upload.pattern", recipe).Trace("Upload Recipe")
logrus.WithField("cmdline", cmdLine).Trace("Expanded command line")
cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false)
if err != nil {
return nil, fmt.Errorf("invalid recipe '%s': %s", recipe, err)
}
for i, arg := range cmdArgs {
logrus.WithField(fmt.Sprintf("arg %d", i), arg).Trace("Split command line arguments")
}

// Run Tool
cmd, err := executils.Command(cmdArgs)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
bou.ke/monkey v1.0.1
github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c
github.com/arduino/go-paths-helper v1.0.1
github.com/arduino/go-properties-orderedmap v1.0.0
github.com/arduino/go-properties-orderedmap v1.1.0
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b
github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b
github.com/cmaglie/pb v1.0.27
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c h1:agh2JT9
github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c/go.mod h1:HK7SpkEax/3P+0w78iRQx1sz1vCDYYw9RXwHjQTB5i8=
github.com/arduino/go-paths-helper v1.0.1 h1:utYXLM2RfFlc9qp/MJTIYp3t6ux/xM6mWjeEb/WLK4Q=
github.com/arduino/go-paths-helper v1.0.1/go.mod h1:HpxtKph+g238EJHq4geEPv9p+gl3v5YYu35Yb+w31Ck=
github.com/arduino/go-properties-orderedmap v1.0.0 h1:caaM25TQZKkytoKQUsgqtOVbrM5i8Gb427JmW0KL05s=
github.com/arduino/go-properties-orderedmap v1.0.0/go.mod h1:DKjD2VXY/NZmlingh4lSFMEYCVubfeArCsGPGDwb2yk=
github.com/arduino/go-properties-orderedmap v1.1.0 h1:g7Gzw6RS0V1TlOgVh5X7vWK1pJDjwWBLS45z1JUV7tI=
github.com/arduino/go-properties-orderedmap v1.1.0/go.mod h1:DKjD2VXY/NZmlingh4lSFMEYCVubfeArCsGPGDwb2yk=
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b h1:9hDi4F2st6dbLC3y4i02zFT5quS4X6iioWifGlVwfy4=
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b/go.mod h1:uwGy5PpN4lqW97FiLnbcx+xx8jly5YuPMJWfVwwjJiQ=
github.com/arduino/go-win32-utils v0.0.0-20180330194947-ed041402e83b h1:3PjgYG5gVPA7cipp7vIR2lF96KkEJIFBJ+ANnuv6J20=
Expand Down
Loading