Skip to content

feat: option to expand properties with flag --show-properties #2074

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
merged 6 commits into from
Feb 17, 2023
Merged
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
63 changes: 55 additions & 8 deletions internal/cli/compile/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,36 @@ import (
"github.com/arduino/arduino-cli/table"
"github.com/arduino/arduino-cli/version"
"github.com/arduino/go-paths-helper"
"github.com/arduino/go-properties-orderedmap"
"github.com/fatih/color"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

type showPropertiesMode int

const (
showPropertiesModeDisabled showPropertiesMode = iota
showPropertiesModeUnexpanded
showPropertiesModeExpanded
)

func parseShowPropertiesMode(showProperties string) (showPropertiesMode, error) {
val, ok := map[string]showPropertiesMode{
"disabled": showPropertiesModeDisabled,
"unexpanded": showPropertiesModeUnexpanded,
"expanded": showPropertiesModeExpanded,
}[showProperties]
if !ok {
return showPropertiesModeDisabled, fmt.Errorf(tr("invalid option '%s'.", showProperties))
}
return val, nil
}

var (
fqbnArg arguments.Fqbn // Fully Qualified Board Name, e.g.: arduino:avr:uno.
profileArg arguments.Profile // Profile to use
showProperties bool // Show all build preferences used instead of compiling.
showProperties string // Show all build preferences used instead of compiling.
preprocess bool // Print preprocessed code to stdout.
buildCachePath string // Builds of 'core.a' are saved into this path to be cached and reused.
buildPath string // Path where to save compiled files.
Expand Down Expand Up @@ -95,7 +116,13 @@ func NewCommand() *cobra.Command {
fqbnArg.AddToCommand(compileCommand)
profileArg.AddToCommand(compileCommand)
compileCommand.Flags().BoolVar(&dumpProfile, "dump-profile", false, tr("Create and print a profile configuration from the build."))
compileCommand.Flags().BoolVar(&showProperties, "show-properties", false, tr("Show all build properties used instead of compiling."))
compileCommand.Flags().StringVar(
&showProperties,
"show-properties",
"disabled",
tr(`Show build properties instead of compiling. The properties are returned exactly as they are defined. Use "--show-properties=expanded" to replace placeholders with compilation context values.`),
)
compileCommand.Flags().Lookup("show-properties").NoOptDefVal = "unexpanded" // default if the flag is present with no value
compileCommand.Flags().BoolVar(&preprocess, "preprocess", false, tr("Print preprocessed code to stdout instead of compiling."))
compileCommand.Flags().StringVar(&buildCachePath, "build-cache-path", "", tr("Builds of 'core.a' are saved into this path to be cached and reused."))
compileCommand.Flags().StringVarP(&exportDir, "output-dir", "", "", tr("Save build artifacts in this directory."))
Expand Down Expand Up @@ -188,9 +215,14 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
overrides = o.Overrides
}

showPropertiesM, err := parseShowPropertiesMode(showProperties)
if err != nil {
feedback.Fatal(tr("Error parsing --show-properties flag: %v", err), feedback.ErrGeneric)
}

var stdOut, stdErr io.Writer
var stdIORes func() *feedback.OutputStreamsResult
if showProperties {
if showPropertiesM != showPropertiesModeDisabled {
stdOut, stdErr, stdIORes = feedback.NewBufferedStreams()
} else {
stdOut, stdErr, stdIORes = feedback.OutputStreams()
Expand All @@ -200,7 +232,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
Instance: inst,
Fqbn: fqbn,
SketchPath: sketchPath.String(),
ShowProperties: showProperties,
ShowProperties: showPropertiesM != showPropertiesModeDisabled,
Preprocess: preprocess,
BuildCachePath: buildCachePath,
BuildPath: buildPath,
Expand Down Expand Up @@ -318,7 +350,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
BuilderResult: compileRes,
ProfileOut: profileOut,
Success: compileError == nil,
showOnlyProperties: showProperties,
showPropertiesMode: showPropertiesM,
}

if compileError != nil {
Expand Down Expand Up @@ -353,9 +385,24 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
}
feedback.FatalResult(res, feedback.ErrGeneric)
}
if showPropertiesM == showPropertiesModeExpanded {
expandPropertiesInResult(res)
}
feedback.PrintResult(res)
}

func expandPropertiesInResult(res *compileResult) {
expanded, err := properties.LoadFromSlice(res.BuilderResult.GetBuildProperties())
if err != nil {
res.Error = tr(err.Error())
}
expandedSlice := make([]string, expanded.Size())
for i, k := range expanded.Keys() {
expandedSlice[i] = strings.Join([]string{k, expanded.ExpandPropsInString(expanded.Get(k))}, "=")
}
res.BuilderResult.BuildProperties = expandedSlice
}

type compileResult struct {
CompilerOut string `json:"compiler_out"`
CompilerErr string `json:"compiler_err"`
Expand All @@ -364,16 +411,16 @@ type compileResult struct {
ProfileOut string `json:"profile_out,omitempty"`
Error string `json:"error,omitempty"`

showOnlyProperties bool
showPropertiesMode showPropertiesMode
}

func (r *compileResult) Data() interface{} {
return r
}

func (r *compileResult) String() string {
if r.showOnlyProperties {
return strings.Join(r.BuilderResult.BuildProperties, fmt.Sprintln())
if r.showPropertiesMode != showPropertiesModeDisabled {
return strings.Join(r.BuilderResult.GetBuildProperties(), fmt.Sprintln())
}

titleColor := color.New(color.FgHiGreen)
Expand Down
69 changes: 65 additions & 4 deletions internal/integrationtest/compile_3/compile_show_properties_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@
package compile_test

import (
"encoding/json"
"testing"

"github.com/arduino/arduino-cli/internal/integrationtest"
"github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
"github.com/arduino/go-properties-orderedmap"
"github.com/stretchr/testify/require"
"go.bug.st/testifyjson/requirejson"
)

type cliCompileResponse struct {
BuilderResult *commands.CompileResponse `json:"builder_result"`
}

func TestCompileShowProperties(t *testing.T) {
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
defer env.CleanUp()
Expand All @@ -36,17 +41,25 @@ func TestCompileShowProperties(t *testing.T) {
bareMinimum := cli.CopySketch("bare_minimum")

// Test --show-properties output is clean
// properties are not expanded
stdout, stderr, err := cli.Run("compile", "--fqbn", "arduino:avr:uno", "-v", "--show-properties", bareMinimum.String())
require.NoError(t, err)
_, err = properties.LoadFromBytes(stdout)
props, err := properties.LoadFromBytes(stdout)
require.NoError(t, err, "Output must be a clean property list")
require.Empty(t, stderr)
require.True(t, props.ContainsKey("archive_file_path"))
require.Contains(t, props.Get("archive_file_path"), "{build.path}")

// Test --show-properties --format JSON output is clean
// properties are not expanded
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:uno", "-v", "--show-properties", "--format", "json", bareMinimum.String())
require.NoError(t, err)
requirejson.Parse(t, stdout, "Output must be a valid JSON")
require.Empty(t, stderr)
props, err = properties.LoadFromSlice(
requireCompileResponseJson(t, stdout).BuilderResult.GetBuildProperties())
require.NoError(t, err)
require.True(t, props.ContainsKey("archive_file_path"))
require.Contains(t, props.Get("archive_file_path"), "{build.path}")

// Test --show-properties output is clean, with a wrong FQBN
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:unoa", "-v", "--show-properties", bareMinimum.String())
Expand All @@ -58,6 +71,54 @@ func TestCompileShowProperties(t *testing.T) {
// Test --show-properties --format JSON output is clean, with a wrong FQBN
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:unoa", "-v", "--show-properties", "--format", "json", bareMinimum.String())
require.Error(t, err)
requirejson.Parse(t, stdout, "Output must be a valid JSON")
require.Empty(t, stderr)
requireCompileResponseJson(t, stdout)

// Test --show-properties=unexpanded output is clean
// properties are not expanded
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:uno", "-v", "--show-properties=unexpanded", bareMinimum.String())
require.NoError(t, err)
props, err = properties.LoadFromBytes(stdout)
require.NoError(t, err, "Output must be a clean property list")
require.Empty(t, stderr)
require.True(t, props.ContainsKey("archive_file_path"))
require.Contains(t, props.Get("archive_file_path"), "{build.path}")

// Test --show-properties=unexpanded output is clean
// properties are not expanded
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:uno", "-v", "--show-properties=unexpanded", "--format", "json", bareMinimum.String())
require.NoError(t, err)
require.Empty(t, stderr)
props, err = properties.LoadFromSlice(
requireCompileResponseJson(t, stdout).BuilderResult.GetBuildProperties())
require.NoError(t, err)
require.True(t, props.ContainsKey("archive_file_path"))
require.Contains(t, props.Get("archive_file_path"), "{build.path}")

// Test --show-properties=expanded output is clean
// properties are expanded
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:uno", "-v", "--show-properties=expanded", bareMinimum.String())
require.NoError(t, err)
props, err = properties.LoadFromBytes(stdout)
require.NoError(t, err, "Output must be a clean property list")
require.Empty(t, stderr)
require.True(t, props.ContainsKey("archive_file_path"))
require.NotContains(t, props.Get("archive_file_path"), "{build.path}")

// Test --show-properties=expanded --format JSON output is clean
// properties are expanded
stdout, stderr, err = cli.Run("compile", "--fqbn", "arduino:avr:uno", "-v", "--show-properties=expanded", "--format", "json", bareMinimum.String())
require.NoError(t, err)
require.Empty(t, stderr)
props, err = properties.LoadFromSlice(
requireCompileResponseJson(t, stdout).BuilderResult.GetBuildProperties())
require.NoError(t, err)
require.True(t, props.ContainsKey("archive_file_path"))
require.NotContains(t, props.Get("archive_file_path"), "{build.path}")
}

func requireCompileResponseJson(t *testing.T, stdout []byte) *cliCompileResponse {
var compileResponse cliCompileResponse
require.NoError(t, json.Unmarshal(stdout, &compileResponse))
return &compileResponse
}