-
-
Notifications
You must be signed in to change notification settings - Fork 414
[breaking] Implementation of sketch profiles #1713
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
Merged
+1,793
−750
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
803782c
cosmetic: renamed import
cmaglie e82a46d
Simplify function pm.DownloadPlatformRelease
cmaglie 1b1867f
Implementation of the Profiles parser
cmaglie da64af5
Added methods to get profiles from sketch
cmaglie 670c9f1
Added gRPC parameters to support profiles
cmaglie 79eb7f4
Added function to load packages for profiles
cmaglie 183a8bb
Added support for profiles in compile command
cmaglie 1b53f59
Added progress callback and installMissing flag (stubs) in pm.Prepare…
cmaglie 4f8244a
Added auto-install procedures for profiles
cmaglie c21147b
Handle platform not found errors
cmaglie 8527015
Draft implementation of upload with profiles
cmaglie 10d95b2
Made packagemamager.loadToolsFromPackage public
cmaglie 6cc5d65
Simplified callbacks in commands.Init
cmaglie 18b0d34
cosmetic: added shortcut variable for library manager
cmaglie 4a26bd4
cosmetic: added shortcut variable for package manager; small readabil…
cmaglie 5449677
Wiring profiles into arduino-cli and gRPC implementation
cmaglie 5972501
Made gRPC Init return a full Profile structure
cmaglie efa8899
(tech debt) Disable profiles if compiling with --libraries/--library
cmaglie 61081f1
Fixed some linter warnings
cmaglie 6156a26
Apply suggestions from code review
cmaglie 9d1ec03
Added profiles specification docs
cmaglie d998f7f
Allow both sketch.yaml and .yml (with priority for .yaml)
cmaglie be8b325
Correctly handle nil return value
cmaglie 614d652
Apply suggestions from code review
cmaglie 8cdb8cb
Apply suggestions from code review
cmaglie bae72d0
Provide `core install` suggestions only when compiling without profiles
cmaglie 170382d
Remove stray comment
cmaglie 633022f
Fixed some comments in protoc files
cmaglie 1fdbce6
Apply suggestions from code review
cmaglie b206d47
Apply suggestions from code review
cmaglie 453f750
Implemented missing AsYaml methods and added tests
cmaglie 75f4117
Apply suggestions from code review
cmaglie 8203266
run of prettier formatter
cmaglie e20117f
Preserve profiles ordering in profiles.yaml
cmaglie 21e8e86
Apply suggestions from code review
cmaglie File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
// This file is part of arduino-cli. | ||
// | ||
// Copyright 2020-2022 ARDUINO SA (http://www.arduino.cc/) | ||
// | ||
// This software is released under the GNU General Public License version 3, | ||
// which covers the main part of arduino-cli. | ||
// The terms of this license can be found at: | ||
// https://www.gnu.org/licenses/gpl-3.0.en.html | ||
// | ||
// You can be released from the requirements of the above licenses by purchasing | ||
// a commercial license. Buying such a license is mandatory if you want to | ||
// modify or otherwise use the software for commercial activities involving the | ||
// Arduino software without disclosing the source code of your own applications. | ||
// To purchase a commercial license, send an email to [email protected]. | ||
|
||
package packagemanager | ||
|
||
import ( | ||
"fmt" | ||
"net/url" | ||
|
||
"github.com/arduino/arduino-cli/arduino" | ||
"github.com/arduino/arduino-cli/arduino/cores" | ||
"github.com/arduino/arduino-cli/arduino/resources" | ||
"github.com/arduino/arduino-cli/arduino/sketch" | ||
"github.com/arduino/arduino-cli/cli/globals" | ||
"github.com/arduino/arduino-cli/configuration" | ||
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" | ||
"github.com/arduino/go-paths-helper" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
// LoadHardwareForProfile load the hardware platforms for the given profile. | ||
// If installMissing is true then possibly missing tools and platforms will be downloaded and installed. | ||
func (pm *PackageManager) LoadHardwareForProfile(p *sketch.Profile, installMissing bool, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) []error { | ||
// Load required platforms | ||
var merr []error | ||
var platformReleases []*cores.PlatformRelease | ||
indexURLs := map[string]*url.URL{} | ||
for _, platformRef := range p.Platforms { | ||
if platformRelease, err := pm.loadProfilePlatform(platformRef, installMissing, downloadCB, taskCB); err != nil { | ||
merr = append(merr, fmt.Errorf("%s: %w", tr("loading required platform %s", platformRef), err)) | ||
logrus.WithField("platform", platformRef).WithError(err).Debugf("Error loading platform for profile") | ||
} else { | ||
platformReleases = append(platformReleases, platformRelease) | ||
indexURLs[platformRelease.Platform.Name] = platformRef.PlatformIndexURL | ||
logrus.WithField("platform", platformRef).Debugf("Loaded platform for profile") | ||
} | ||
} | ||
|
||
// Load tools dependencies for the platforms | ||
for _, platformRelease := range platformReleases { | ||
// TODO: pm.FindPlatformReleaseDependencies(platformRelease) | ||
|
||
for _, toolDep := range platformRelease.ToolDependencies { | ||
indexURL := indexURLs[toolDep.ToolPackager] | ||
if err := pm.loadProfileTool(toolDep, indexURL, installMissing, downloadCB, taskCB); err != nil { | ||
merr = append(merr, fmt.Errorf("%s: %w", tr("loading required tool %s", toolDep), err)) | ||
logrus.WithField("tool", toolDep).WithField("index_url", indexURL).WithError(err).Debugf("Error loading tool for profile") | ||
} else { | ||
logrus.WithField("tool", toolDep).WithField("index_url", indexURL).Debugf("Loaded tool for profile") | ||
} | ||
} | ||
} | ||
|
||
return merr | ||
} | ||
|
||
func (pm *PackageManager) loadProfilePlatform(platformRef *sketch.ProfilePlatformReference, installMissing bool, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) (*cores.PlatformRelease, error) { | ||
targetPackage := pm.Packages.GetOrCreatePackage(platformRef.Packager) | ||
platform := targetPackage.GetOrCreatePlatform(platformRef.Architecture) | ||
release := platform.GetOrCreateRelease(platformRef.Version) | ||
|
||
uid := platformRef.InternalUniqueIdentifier() | ||
destDir := configuration.ProfilesCacheDir(configuration.Settings).Join(uid) | ||
if !destDir.IsDir() && installMissing { | ||
// Try installing the missing platform | ||
if err := pm.installMissingProfilePlatform(platformRef, destDir, downloadCB, taskCB); err != nil { | ||
return nil, err | ||
} | ||
} | ||
return release, pm.loadPlatformRelease(release, destDir) | ||
} | ||
|
||
func (pm *PackageManager) installMissingProfilePlatform(platformRef *sketch.ProfilePlatformReference, destDir *paths.Path, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error { | ||
// Instantiate a temporary package manager only for platform installation | ||
_ = pm.TempDir.MkdirAll() | ||
tmp, err := paths.MkTempDir(pm.TempDir.String(), "") | ||
if err != nil { | ||
return fmt.Errorf("installing missing platform: could not create temp dir %s", err) | ||
} | ||
tmpPm := NewPackageManager(tmp, tmp, pm.DownloadDir, tmp, pm.userAgent) | ||
defer tmp.RemoveAll() | ||
|
||
// Download the main index and parse it | ||
taskCB(&rpc.TaskProgress{Name: tr("Downloading platform %s", platformRef)}) | ||
defaultIndexURL, _ := url.Parse(globals.DefaultIndexURL) | ||
indexesToDownload := []*url.URL{defaultIndexURL} | ||
if platformRef.PlatformIndexURL != nil { | ||
indexesToDownload = append(indexesToDownload, platformRef.PlatformIndexURL) | ||
} | ||
for _, indexURL := range indexesToDownload { | ||
if err != nil { | ||
taskCB(&rpc.TaskProgress{Name: tr("Error downloading %s", indexURL)}) | ||
return &arduino.FailedDownloadError{Message: tr("Error downloading %s", indexURL), Cause: err} | ||
} | ||
indexResource := resources.IndexResource{URL: indexURL} | ||
if err := indexResource.Download(tmpPm.IndexDir, downloadCB); err != nil { | ||
taskCB(&rpc.TaskProgress{Name: tr("Error downloading %s", indexURL)}) | ||
return &arduino.FailedDownloadError{Message: tr("Error downloading %s", indexURL), Cause: err} | ||
} | ||
if err := tmpPm.LoadPackageIndex(indexURL); err != nil { | ||
taskCB(&rpc.TaskProgress{Name: tr("Error loading index %s", indexURL)}) | ||
return &arduino.FailedInstallError{Message: tr("Error loading index %s", indexURL), Cause: err} | ||
} | ||
} | ||
|
||
// Download the platform | ||
tmpTargetPackage := tmpPm.Packages.GetOrCreatePackage(platformRef.Packager) | ||
tmpPlatform := tmpTargetPackage.GetOrCreatePlatform(platformRef.Architecture) | ||
tmpPlatformRelease := tmpPlatform.GetOrCreateRelease(platformRef.Version) | ||
if err := tmpPm.DownloadPlatformRelease(tmpPlatformRelease, nil, downloadCB); err != nil { | ||
taskCB(&rpc.TaskProgress{Name: tr("Error downloading platform %s", tmpPlatformRelease)}) | ||
return &arduino.FailedInstallError{Message: tr("Error downloading platform %s", tmpPlatformRelease), Cause: err} | ||
} | ||
taskCB(&rpc.TaskProgress{Completed: true}) | ||
|
||
// Perform install | ||
taskCB(&rpc.TaskProgress{Name: tr("Installing platform %s", tmpPlatformRelease)}) | ||
if err := tmpPm.InstallPlatformInDirectory(tmpPlatformRelease, destDir); err != nil { | ||
taskCB(&rpc.TaskProgress{Name: tr("Error installing platform %s", tmpPlatformRelease)}) | ||
return &arduino.FailedInstallError{Message: tr("Error installing platform %s", tmpPlatformRelease), Cause: err} | ||
} | ||
taskCB(&rpc.TaskProgress{Completed: true}) | ||
return nil | ||
} | ||
|
||
func (pm *PackageManager) loadProfileTool(toolRef *cores.ToolDependency, indexURL *url.URL, installMissing bool, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error { | ||
targetPackage := pm.Packages.GetOrCreatePackage(toolRef.ToolPackager) | ||
tool := targetPackage.GetOrCreateTool(toolRef.ToolName) | ||
|
||
uid := toolRef.InternalUniqueIdentifier(indexURL) | ||
destDir := configuration.ProfilesCacheDir(configuration.Settings).Join(uid) | ||
|
||
if !destDir.IsDir() && installMissing { | ||
// Try installing the missing tool | ||
toolRelease := tool.GetOrCreateRelease(toolRef.ToolVersion) | ||
if toolRelease == nil { | ||
return &arduino.InvalidVersionError{Cause: fmt.Errorf(tr("version %s not found", toolRef.ToolVersion))} | ||
} | ||
if err := pm.installMissingProfileTool(toolRelease, destDir, downloadCB, taskCB); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return pm.loadToolReleaseFromDirectory(tool, toolRef.ToolVersion, destDir) | ||
} | ||
|
||
func (pm *PackageManager) installMissingProfileTool(toolRelease *cores.ToolRelease, destDir *paths.Path, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB) error { | ||
// Instantiate a temporary package manager only for platform installation | ||
tmp, err := paths.MkTempDir(destDir.Parent().String(), "") | ||
if err != nil { | ||
return fmt.Errorf("installing missing platform: could not create temp dir %s", err) | ||
} | ||
defer tmp.RemoveAll() | ||
|
||
// Download the tool | ||
toolResource := toolRelease.GetCompatibleFlavour() | ||
if toolResource == nil { | ||
return &arduino.InvalidVersionError{Cause: fmt.Errorf(tr("version %s not available for this operating system", toolRelease))} | ||
} | ||
taskCB(&rpc.TaskProgress{Name: tr("Downloading tool %s", toolRelease)}) | ||
if err := toolResource.Download(pm.DownloadDir, nil, toolRelease.String(), downloadCB); err != nil { | ||
taskCB(&rpc.TaskProgress{Name: tr("Error downloading tool %s", toolRelease)}) | ||
return &arduino.FailedInstallError{Message: tr("Error installing tool %s", toolRelease), Cause: err} | ||
} | ||
taskCB(&rpc.TaskProgress{Completed: true}) | ||
|
||
// Install tool | ||
taskCB(&rpc.TaskProgress{Name: tr("Installing tool %s", toolRelease)}) | ||
if err := toolResource.Install(pm.DownloadDir, tmp, destDir); err != nil { | ||
taskCB(&rpc.TaskProgress{Name: tr("Error installing tool %s", toolRelease)}) | ||
return &arduino.FailedInstallError{Message: tr("Error installing tool %s", toolRelease), Cause: err} | ||
} | ||
taskCB(&rpc.TaskProgress{Completed: true}) | ||
return nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
// This file is part of arduino-cli. | ||
// | ||
// Copyright 2020-2022 ARDUINO SA (http://www.arduino.cc/) | ||
// | ||
// This software is released under the GNU General Public License version 3, | ||
// which covers the main part of arduino-cli. | ||
// The terms of this license can be found at: | ||
// https://www.gnu.org/licenses/gpl-3.0.en.html | ||
// | ||
// You can be released from the requirements of the above licenses by purchasing | ||
// a commercial license. Buying such a license is mandatory if you want to | ||
// modify or otherwise use the software for commercial activities involving the | ||
// Arduino software without disclosing the source code of your own applications. | ||
// To purchase a commercial license, send an email to license@arduino.cc. | ||
|
||
package sketch | ||
|
||
import ( | ||
"crypto/sha256" | ||
"encoding/hex" | ||
"fmt" | ||
"net/url" | ||
"regexp" | ||
"strings" | ||
|
||
"github.com/arduino/arduino-cli/arduino/utils" | ||
"github.com/arduino/go-paths-helper" | ||
semver "go.bug.st/relaxed-semver" | ||
"gopkg.in/yaml.v2" | ||
) | ||
|
||
// Project represents all the profiles defined for the sketch | ||
type Project struct { | ||
Profiles Profiles `yaml:"profiles"` | ||
DefaultProfile string `yaml:"default_profile"` | ||
} | ||
|
||
// AsYaml outputs the sketch project file as YAML | ||
func (p *Project) AsYaml() string { | ||
res := "profiles:\n" | ||
for _, profile := range p.Profiles { | ||
res += fmt.Sprintf(" %s:\n", profile.Name) | ||
res += profile.AsYaml() | ||
res += "\n" | ||
} | ||
if p.DefaultProfile != "" { | ||
res += fmt.Sprintf("default_profile: %s\n", p.DefaultProfile) | ||
} | ||
return res | ||
} | ||
|
||
// Profiles are a list of Profile | ||
type Profiles []*Profile | ||
|
||
// UnmarshalYAML decodes a Profiles section from YAML source. | ||
func (p *Profiles) UnmarshalYAML(unmarshal func(interface{}) error) error { | ||
unmarshaledProfiles := map[string]*Profile{} | ||
if err := unmarshal(&unmarshaledProfiles); err != nil { | ||
return err | ||
} | ||
|
||
var profilesData yaml.MapSlice | ||
if err := unmarshal(&profilesData); err != nil { | ||
return err | ||
} | ||
|
||
for _, profileData := range profilesData { | ||
profileName, ok := profileData.Key.(string) | ||
if !ok { | ||
return fmt.Errorf("invalid profile name: %v", profileData.Key) | ||
} | ||
profile := unmarshaledProfiles[profileName] | ||
profile.Name = profileName | ||
*p = append(*p, profile) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Profile is a sketch profile, it contains a reference to all the resources | ||
// needed to build and upload a sketch | ||
type Profile struct { | ||
Name string | ||
Notes string `yaml:"notes"` | ||
FQBN string `yaml:"fqbn"` | ||
Platforms ProfileRequiredPlatforms `yaml:"platforms"` | ||
Libraries ProfileRequiredLibraries `yaml:"libraries"` | ||
} | ||
|
||
// AsYaml outputs the profile as Yaml | ||
func (p *Profile) AsYaml() string { | ||
res := "" | ||
if p.Notes != "" { | ||
res += fmt.Sprintf(" notes: %s\n", p.Notes) | ||
} | ||
res += fmt.Sprintf(" fqbn: %s\n", p.FQBN) | ||
res += p.Platforms.AsYaml() | ||
res += p.Libraries.AsYaml() | ||
return res | ||
} | ||
|
||
// ProfileRequiredPlatforms is a list of ProfilePlatformReference (platforms | ||
// required to build the sketch using this profile) | ||
type ProfileRequiredPlatforms []*ProfilePlatformReference | ||
|
||
// AsYaml outputs the required platforms as Yaml | ||
func (p *ProfileRequiredPlatforms) AsYaml() string { | ||
res := " platforms:\n" | ||
for _, platform := range *p { | ||
res += platform.AsYaml() | ||
} | ||
return res | ||
} | ||
|
||
// ProfileRequiredLibraries is a list of ProfileLibraryReference (libraries | ||
// required to build the sketch using this profile) | ||
type ProfileRequiredLibraries []*ProfileLibraryReference | ||
|
||
// AsYaml outputs the required libraries as Yaml | ||
func (p *ProfileRequiredLibraries) AsYaml() string { | ||
res := " libraries:\n" | ||
for _, lib := range *p { | ||
res += lib.AsYaml() | ||
} | ||
return res | ||
} | ||
|
||
// ProfilePlatformReference is a reference to a platform | ||
type ProfilePlatformReference struct { | ||
Packager string | ||
Architecture string | ||
Version *semver.Version | ||
PlatformIndexURL *url.URL | ||
} | ||
|
||
// InternalUniqueIdentifier returns the unique identifier for this object | ||
func (p *ProfilePlatformReference) InternalUniqueIdentifier() string { | ||
id := p.String() | ||
h := sha256.Sum256([]byte(id)) | ||
res := fmt.Sprintf("%s:%s@%s_%s", p.Packager, p.Architecture, p.Version, hex.EncodeToString(h[:])[:16]) | ||
return utils.SanitizeName(res) | ||
} | ||
|
||
func (p *ProfilePlatformReference) String() string { | ||
res := fmt.Sprintf("%s:%s@%s", p.Packager, p.Architecture, p.Version) | ||
if p.PlatformIndexURL != nil { | ||
res += fmt.Sprintf(" (%s)", p.PlatformIndexURL) | ||
} | ||
return res | ||
} | ||
|
||
// AsYaml outputs the platform reference as Yaml | ||
func (p *ProfilePlatformReference) AsYaml() string { | ||
res := fmt.Sprintf(" - platform: %s:%s (%s)\n", p.Packager, p.Architecture, p.Version) | ||
if p.PlatformIndexURL != nil { | ||
res += fmt.Sprintf(" platform_index_url: %s\n", p.PlatformIndexURL) | ||
} | ||
return res | ||
} | ||
|
||
func parseNameAndVersion(in string) (string, string, bool) { | ||
re := regexp.MustCompile(`^([a-zA-Z0-9.\-_ :]+) \((.+)\)$`) | ||
split := re.FindAllStringSubmatch(in, -1) | ||
if len(split) != 1 || len(split[0]) != 3 { | ||
return "", "", false | ||
} | ||
return split[0][1], split[0][2], true | ||
} | ||
|
||
// UnmarshalYAML decodes a ProfilePlatformReference from YAML source. | ||
func (p *ProfilePlatformReference) UnmarshalYAML(unmarshal func(interface{}) error) error { | ||
var data map[string]string | ||
if err := unmarshal(&data); err != nil { | ||
return err | ||
} | ||
if platformID, ok := data["platform"]; !ok { | ||
return fmt.Errorf(tr("missing '%s' directive", "platform")) | ||
} else if platformID, platformVersion, ok := parseNameAndVersion(platformID); !ok { | ||
return fmt.Errorf(tr("invalid '%s' directive", "platform")) | ||
} else if c, err := semver.Parse(platformVersion); err != nil { | ||
return fmt.Errorf("%s: %w", tr("error parsing version constraints"), err) | ||
} else if split := strings.SplitN(platformID, ":", 2); len(split) != 2 { | ||
return fmt.Errorf("%s: %s", tr("invalid platform identifier"), platformID) | ||
} else { | ||
p.Packager = split[0] | ||
p.Architecture = split[1] | ||
p.Version = c | ||
} | ||
|
||
if rawIndexURL, ok := data["platform_index_url"]; ok { | ||
indexURL, err := url.Parse(rawIndexURL) | ||
if err != nil { | ||
return fmt.Errorf("%s: %w", tr("invalid platform index URL:"), err) | ||
} | ||
p.PlatformIndexURL = indexURL | ||
} | ||
return nil | ||
} | ||
|
||
// ProfileLibraryReference is a reference to a library | ||
type ProfileLibraryReference struct { | ||
Library string | ||
Version *semver.Version | ||
} | ||
|
||
// UnmarshalYAML decodes a ProfileLibraryReference from YAML source. | ||
func (l *ProfileLibraryReference) UnmarshalYAML(unmarshal func(interface{}) error) error { | ||
var data string | ||
if err := unmarshal(&data); err != nil { | ||
return err | ||
} | ||
if libName, libVersion, ok := parseNameAndVersion(data); !ok { | ||
return fmt.Errorf("%s %s", tr("invalid library directive:"), data) | ||
} else if v, err := semver.Parse(libVersion); err != nil { | ||
return fmt.Errorf("%s %w", tr("invalid version:"), err) | ||
} else { | ||
l.Library = libName | ||
l.Version = v | ||
} | ||
return nil | ||
} | ||
|
||
// AsYaml outputs the required library as Yaml | ||
func (l *ProfileLibraryReference) AsYaml() string { | ||
res := fmt.Sprintf(" - %s (%s)\n", l.Library, l.Version) | ||
return res | ||
} | ||
|
||
func (l *ProfileLibraryReference) String() string { | ||
return fmt.Sprintf("%s@%s", l.Library, l.Version) | ||
} | ||
|
||
// InternalUniqueIdentifier returns the unique identifier for this object | ||
func (l *ProfileLibraryReference) InternalUniqueIdentifier() string { | ||
id := l.String() | ||
h := sha256.Sum256([]byte(id)) | ||
res := fmt.Sprintf("%s_%s", id, hex.EncodeToString(h[:])[:16]) | ||
return utils.SanitizeName(res) | ||
} | ||
|
||
// LoadProjectFile reads a sketch project file | ||
func LoadProjectFile(file *paths.Path) (*Project, error) { | ||
data, err := file.ReadFile() | ||
if err != nil { | ||
return nil, err | ||
} | ||
res := &Project{} | ||
if err := yaml.Unmarshal(data, &res); err != nil { | ||
return nil, err | ||
} | ||
return res, nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// This file is part of arduino-cli. | ||
// | ||
// Copyright 2020-2022 ARDUINO SA (http://www.arduino.cc/) | ||
// | ||
// This software is released under the GNU General Public License version 3, | ||
// which covers the main part of arduino-cli. | ||
// The terms of this license can be found at: | ||
// https://www.gnu.org/licenses/gpl-3.0.en.html | ||
// | ||
// You can be released from the requirements of the above licenses by purchasing | ||
// a commercial license. Buying such a license is mandatory if you want to | ||
// modify or otherwise use the software for commercial activities involving the | ||
// Arduino software without disclosing the source code of your own applications. | ||
// To purchase a commercial license, send an email to license@arduino.cc. | ||
|
||
package sketch | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/arduino/go-paths-helper" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestProjectFileLoading(t *testing.T) { | ||
sketchProj := paths.New("testdata", "SketchWithProfiles", "sketch.yml") | ||
proj, err := LoadProjectFile(sketchProj) | ||
require.NoError(t, err) | ||
fmt.Println(proj) | ||
golden, err := sketchProj.ReadFile() | ||
require.NoError(t, err) | ||
require.Equal(t, proj.AsYaml(), string(golden)) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
profiles: | ||
nanorp: | ||
fqbn: arduino:mbed_nano:nanorp2040connect | ||
platforms: | ||
- platform: arduino:mbed_nano (2.1.0) | ||
libraries: | ||
- ArduinoIoTCloud (1.0.2) | ||
- Arduino_ConnectionHandler (0.6.4) | ||
- TinyDHT sensor library (1.1.0) | ||
|
||
another_profile_name: | ||
notes: testing the limit of the AVR platform, may be unstable | ||
fqbn: arduino:avr:uno | ||
platforms: | ||
- platform: arduino:avr (1.8.4) | ||
libraries: | ||
- VitconMQTT (1.0.1) | ||
- Arduino_ConnectionHandler (0.6.4) | ||
- TinyDHT sensor library (1.1.0) | ||
|
||
tiny: | ||
notes: testing the very limit of the AVR platform, it will be very unstable | ||
fqbn: attiny:avr:ATtinyX5:cpu=attiny85,clock=internal16 | ||
platforms: | ||
- platform: attiny:avr (1.0.2) | ||
platform_index_url: http://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json | ||
- platform: arduino:avr (1.8.3) | ||
libraries: | ||
- ArduinoIoTCloud (1.0.2) | ||
- Arduino_ConnectionHandler (0.6.4) | ||
- TinyDHT sensor library (1.1.0) | ||
|
||
feather: | ||
fqbn: adafruit:samd:adafruit_feather_m0 | ||
platforms: | ||
- platform: adafruit:samd (1.6.0) | ||
platform_index_url: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json | ||
libraries: | ||
- ArduinoIoTCloud (1.0.2) | ||
- Arduino_ConnectionHandler (0.6.4) | ||
- TinyDHT sensor library (1.1.0) | ||
|
||
default_profile: nanorp |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// This file is part of arduino-cli. | ||
// | ||
// Copyright 2020-2022 ARDUINO SA (http://www.arduino.cc/) | ||
// | ||
// This software is released under the GNU General Public License version 3, | ||
// which covers the main part of arduino-cli. | ||
// The terms of this license can be found at: | ||
// https://www.gnu.org/licenses/gpl-3.0.en.html | ||
// | ||
// You can be released from the requirements of the above licenses by purchasing | ||
// a commercial license. Buying such a license is mandatory if you want to | ||
// modify or otherwise use the software for commercial activities involving the | ||
// Arduino software without disclosing the source code of your own applications. | ||
// To purchase a commercial license, send an email to license@arduino.cc. | ||
|
||
package arguments | ||
|
||
import "github.com/spf13/cobra" | ||
|
||
// Profile contains the profile flag data. | ||
// This is useful so all flags used by commands that need | ||
// this information are consistent with each other. | ||
type Profile struct { | ||
profile string | ||
} | ||
|
||
// AddToCommand adds the flags used to set fqbn to the specified Command | ||
func (f *Profile) AddToCommand(cmd *cobra.Command) { | ||
cmd.Flags().StringVarP(&f.profile, "profile", "m", "", tr("Sketch profile to use")) | ||
// TODO: register autocompletion | ||
} | ||
|
||
// Get returns the profile name | ||
func (f *Profile) Get() string { | ||
return f.profile | ||
} | ||
|
||
// String returns the profile name | ||
func (f *Profile) String() string { | ||
return f.profile | ||
} | ||
|
||
// Set sets the profile | ||
func (f *Profile) Set(profile string) { | ||
f.profile = profile | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
Sketch metadata is defined in a file named `sketch.yaml`. This file is in YAML format. | ||
|
||
## Build profiles | ||
|
||
Arduino CLI provides support for reproducible builds through the use of build profiles. | ||
|
||
A profile is a complete description of all the resources needed to build a sketch. The sketch project file may contain | ||
multiple profiles. | ||
|
||
Each profile will define: | ||
|
||
- The board FQBN | ||
- The target core platform name and version (with the 3rd party platform index URL if needed) | ||
- A possible core platform name and version, that is a dependency of the target core platform (with the 3rd party | ||
platform index URL if needed) | ||
- The libraries used in the sketch (including their version) | ||
|
||
The format of the file is the following: | ||
|
||
``` | ||
profiles: | ||
<PROFILE_NAME>: | ||
notes: <USER_NOTES> | ||
fqbn: <FQBN> | ||
platforms: | ||
- platform: <PLATFORM> (<PLATFORM_VERSION>) | ||
platform_index_url: <3RD_PARTY_PLATFORM_URL> | ||
- platform: <PLATFORM_DEPENDENCY> (<PLATFORM_DEPENDENCY_VERSION>) | ||
platform_index_url: <3RD_PARTY_PLATFORM_DEPENDENCY_URL> | ||
libraries: | ||
- <LIB_NAME> (<LIB_VERSION>) | ||
- <LIB_NAME> (<LIB_VERSION>) | ||
- <LIB_NAME> (<LIB_VERSION>) | ||
...more profiles here... | ||
``` | ||
|
||
There is an optional `profiles:` section containing all the profiles. Each field in a profile is mandatory (unless noted | ||
otherwise below). The available fields are: | ||
|
||
- `<PROFILE_NAME>` is the profile identifier, it’s a user-defined field, and the allowed characters are alphanumerics, | ||
underscore `_`, dot `.`, and dash `-`. | ||
- `<PLATFORM>` is the target core platform identifier, for example, `arduino:avr` or `adafruit:samd`. | ||
- `<PLATFORM_VERSION>` is the target core platform version required. | ||
- `<3RD_PARTY_PLATFORM_URL>` is the index URL to download the target core platform (also known as “Additional Boards | ||
Manager URLs” in the Arduino IDE). This field can be omitted for the official `arduino:*` platforms. | ||
- `<PLATFORM_DEPENDENCY>`, `<PLATFORM_DEPENDENCY_VERSION>`, and `<3RD_PARTY_PLATFORM_DEPENDENCY_URL>` contains the same | ||
information as `<PLATFORM>`, `<PLATFORM_VERSION>`, and `<3RD_PARTY_PLATFORM_URL>` respectively but for the core | ||
platform dependency of the main core platform. These fields are optional. | ||
- `libraries:` is a section where the required libraries to build the project are defined. This section is optional. | ||
- `<LIB_VERSION>` is the version required for the library, for example, `1.0.0`. | ||
- `<USER_NOTES>` is a free text string available to the developer to add comments. This field is optional. | ||
|
||
A complete example of a sketch project file may be the following: | ||
|
||
``` | ||
profiles: | ||
nanorp: | ||
fqbn: arduino:mbed_nano:nanorp2040connect | ||
platforms: | ||
- platform: arduino:mbed_nano (2.1.0) | ||
libraries: | ||
- ArduinoIoTCloud (1.0.2) | ||
- Arduino_ConnectionHandler (0.6.4) | ||
- TinyDHT sensor library (1.1.0) | ||
cmaglie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
another_profile_name: | ||
notes: testing the limit of the AVR platform, may be unstable | ||
fqbn: arduino:avr:uno | ||
platforms: | ||
- platform: arduino:avr (1.8.4) | ||
libraries: | ||
- VitconMQTT (1.0.1) | ||
- Arduino_ConnectionHandler (0.6.4) | ||
- TinyDHT sensor library (1.1.0) | ||
tiny: | ||
notes: testing the very limit of the AVR platform, it will be very unstable | ||
fqbn: attiny:avr:ATtinyX5:cpu=attiny85,clock=internal16 | ||
platforms: | ||
- platform: attiny:avr@1.0.2 | ||
platform_index_url: https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json | ||
- platform: arduino:avr@1.8.3 | ||
libraries: | ||
- ArduinoIoTCloud (1.0.2) | ||
- Arduino_ConnectionHandler (0.6.4) | ||
- TinyDHT sensor library (1.1.0) | ||
feather: | ||
fqbn: adafruit:samd:adafruit_feather_m0 | ||
platforms: | ||
- platform: adafruit:samd (1.6.0) | ||
platform_index_url: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json | ||
libraries: | ||
- ArduinoIoTCloud (1.0.2) | ||
- Arduino_ConnectionHandler (0.6.4) | ||
- TinyDHT sensor library (1.1.0) | ||
``` | ||
|
||
### Building a sketch | ||
|
||
When a sketch project file is present, it can be leveraged to compile the sketch with the `--profile/-m` flag in the | ||
`compile` command: | ||
|
||
``` | ||
arduino-cli compile --profile nanorp | ||
``` | ||
|
||
In this case, the sketch will be compiled using the core platform and libraries specified in the nanorp profile. If a | ||
core platform or a library is missing it will be automatically downloaded and installed on the fly in an isolated | ||
directory inside the data folder. The dedicated storage is not accessible to the user and is meant as a "cache" of the | ||
resources used to build the sketch. | ||
|
||
When using the profile-based build, the globally installed platforms and libraries are excluded from the compile and can | ||
not be used in any way. In other words, the build is isolated from the system and will rely only on the resources | ||
specified in the profile: this will ensure that the build is portable and reproducible independently from the platforms | ||
and libraries installed in the system. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.