Skip to content

Commit 6ffb6af

Browse files
author
Federico Fissore
committedSep 22, 2015
Added -build-options-file param, which allows to specify a local
build.options.json file. Fixes #6 Signed-off-by: Federico Fissore <[email protected]>
1 parent 8e42048 commit 6ffb6af

File tree

2 files changed

+124
-45
lines changed

2 files changed

+124
-45
lines changed
 

‎README.md

+8
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ This tool generates function prototypes and gathers library paths, providing `gc
3737

3838
* `-version`: if specified, prints version and exits.
3939

40+
* `-build-options-file`: it specifies path to a local `build.options.json` file (see paragraph below), which allows you to omit specifying params such as `-hardware`, `-tools`, `-libraries`, `-fqbn`, `-pref` and `-ide-version`.
41+
4042
Final mandatory parameter is the sketch to compile (of course).
43+
44+
### What is and how to use build.options.json file
45+
46+
Every time you run this tool, it will create a `build.options.json` file in build path. It's used to understand if build options (such as hardware folders, fqbn and so on) were changed when compiling the same sketch.
47+
If they changed, the whole build path is wiped out. If they didn't change, previous compiled files will be reused if the corresponding source files didn't change as well.
48+
You can save this file locally and use it instead of specifying `-hardware`, `-tools`, `-libraries`, `-fqbn`, `-pref` and `-ide-version`.
4149

4250
### Using it for continuously verify your libraries or cores
4351

‎main.go

+116-45
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ import (
3535
"arduino.cc/builder/gohasissues"
3636
"arduino.cc/builder/i18n"
3737
"arduino.cc/builder/utils"
38+
"encoding/json"
3839
"flag"
3940
"fmt"
4041
"github.com/go-errors/errors"
42+
"io/ioutil"
4143
"os"
4244
"os/exec"
4345
"strings"
@@ -46,6 +48,29 @@ import (
4648

4749
const VERSION = "1.0.0-beta9"
4850

51+
const FLAG_COMPILE = "compile"
52+
const FLAG_DUMP_PREFS = "dump-prefs"
53+
const FLAG_BUILD_OPTIONS_FILE = "build-options-file"
54+
const FLAG_HARDWARE = "hardware"
55+
const FLAG_TOOLS = "tools"
56+
const FLAG_LIBRARIES = "libraries"
57+
const FLAG_PREFS = "prefs"
58+
const FLAG_FQBN = "fqbn"
59+
const FLAG_IDE_VERSION = "ide-version"
60+
const FLAG_BUILD_PATH = "build-path"
61+
const FLAG_VERBOSE = "verbose"
62+
const FLAG_DEBUG_LEVEL = "debug-level"
63+
const FLAG_WARNINGS = "warnings"
64+
const FLAG_WARNINGS_NONE = "none"
65+
const FLAG_WARNINGS_DEFAULT = "default"
66+
const FLAG_WARNINGS_MORE = "more"
67+
const FLAG_WARNINGS_ALL = "all"
68+
const FLAG_LOGGER = "logger"
69+
const FLAG_LOGGER_HUMAN = "human"
70+
const FLAG_LOGGER_MACHINE = "machine"
71+
const FLAG_LIB_DISCOVERY_RECURSION_PATH = "lib-discovery-recursion-depth"
72+
const FLAG_VERSION = "version"
73+
4974
type slice []string
5075

5176
func (h *slice) String() string {
@@ -70,6 +95,7 @@ func (h *slice) Set(csv string) error {
7095

7196
var compileFlag *bool
7297
var dumpPrefsFlag *bool
98+
var buildOptionsFileFlag *string
7399
var hardwareFoldersFlag slice
74100
var toolsFoldersFlag slice
75101
var librariesFoldersFlag slice
@@ -85,21 +111,22 @@ var loggerFlag *string
85111
var versionFlag *bool
86112

87113
func init() {
88-
compileFlag = flag.Bool("compile", false, "compiles the given sketch")
89-
dumpPrefsFlag = flag.Bool("dump-prefs", false, "dumps build properties used when compiling")
90-
flag.Var(&hardwareFoldersFlag, "hardware", "Specify a 'hardware' folder. Can be added multiple times for specifying multiple 'hardware' folders")
91-
flag.Var(&toolsFoldersFlag, "tools", "Specify a 'tools' folder. Can be added multiple times for specifying multiple 'tools' folders")
92-
flag.Var(&librariesFoldersFlag, "libraries", "Specify a 'libraries' folder. Can be added multiple times for specifying multiple 'libraries' folders")
93-
flag.Var(&customBuildPropertiesFlag, "prefs", "Specify a custom preference. Can be added multiple times for specifying multiple custom preferences")
94-
fqbnFlag = flag.String("fqbn", "", "fully qualified board name")
95-
ideVersionFlag = flag.String("ide-version", "10600", "fake IDE version")
96-
buildPathFlag = flag.String("build-path", "", "build path")
97-
verboseFlag = flag.Bool("verbose", false, "if 'true' prints lots of stuff")
98-
debugLevelFlag = flag.Int("debug-level", builder.DEFAULT_DEBUG_LEVEL, "Turns on debugging messages. The higher, the chattier")
99-
warningsLevelFlag = flag.String("warnings", "", "Sets warnings level. Available values are 'none', 'default', 'more' and 'all'")
100-
loggerFlag = flag.String("logger", "human", "Sets type of logger. Available values are 'human', 'machine'")
101-
libraryDiscoveryRecursionDepthFlag = flag.Int("lib-discovery-recursion-depth", builder.DEFAULT_LIBRARY_DISCOVERY_RECURSION_DEPTH, "How deep should library discovery go down looking for included libraries")
102-
versionFlag = flag.Bool("version", false, "prints version and exits")
114+
compileFlag = flag.Bool(FLAG_COMPILE, false, "compiles the given sketch")
115+
dumpPrefsFlag = flag.Bool(FLAG_DUMP_PREFS, false, "dumps build properties used when compiling")
116+
buildOptionsFileFlag = flag.String(FLAG_BUILD_OPTIONS_FILE, "", "Instead of specifying --"+FLAG_HARDWARE+", --"+FLAG_TOOLS+" etc every time, you can load all such options from a file")
117+
flag.Var(&hardwareFoldersFlag, FLAG_HARDWARE, "Specify a 'hardware' folder. Can be added multiple times for specifying multiple 'hardware' folders")
118+
flag.Var(&toolsFoldersFlag, FLAG_TOOLS, "Specify a 'tools' folder. Can be added multiple times for specifying multiple 'tools' folders")
119+
flag.Var(&librariesFoldersFlag, FLAG_LIBRARIES, "Specify a 'libraries' folder. Can be added multiple times for specifying multiple 'libraries' folders")
120+
flag.Var(&customBuildPropertiesFlag, FLAG_PREFS, "Specify a custom preference. Can be added multiple times for specifying multiple custom preferences")
121+
fqbnFlag = flag.String(FLAG_FQBN, "", "fully qualified board name")
122+
ideVersionFlag = flag.String(FLAG_IDE_VERSION, "10600", "fake IDE version")
123+
buildPathFlag = flag.String(FLAG_BUILD_PATH, "", "build path")
124+
verboseFlag = flag.Bool(FLAG_VERBOSE, false, "if 'true' prints lots of stuff")
125+
debugLevelFlag = flag.Int(FLAG_DEBUG_LEVEL, builder.DEFAULT_DEBUG_LEVEL, "Turns on debugging messages. The higher, the chattier")
126+
warningsLevelFlag = flag.String(FLAG_WARNINGS, "", "Sets warnings level. Available values are '"+FLAG_WARNINGS_NONE+"', '"+FLAG_WARNINGS_DEFAULT+"', '"+FLAG_WARNINGS_MORE+"' and '"+FLAG_WARNINGS_ALL+"'")
127+
loggerFlag = flag.String(FLAG_LOGGER, FLAG_LOGGER_HUMAN, "Sets type of logger. Available values are '"+FLAG_LOGGER_HUMAN+"', '"+FLAG_LOGGER_MACHINE+"'")
128+
libraryDiscoveryRecursionDepthFlag = flag.Int(FLAG_LIB_DISCOVERY_RECURSION_PATH, builder.DEFAULT_LIBRARY_DISCOVERY_RECURSION_DEPTH, "How deep should library discovery go down looking for included libraries")
129+
versionFlag = flag.Bool(FLAG_VERSION, false, "prints version and exits")
103130
}
104131

105132
func main() {
@@ -119,7 +146,7 @@ func main() {
119146
dumpPrefs := *dumpPrefsFlag
120147

121148
if compile && dumpPrefs {
122-
fmt.Fprintln(os.Stderr, "You can either specify --compile or --dump-prefs, not both")
149+
fmt.Fprintln(os.Stderr, "You can either specify --"+FLAG_COMPILE+" or --"+FLAG_DUMP_PREFS+", not both")
123150
defer os.Exit(1)
124151
return
125152
}
@@ -130,51 +157,53 @@ func main() {
130157

131158
context := make(map[string]interface{})
132159

133-
hardware, err := toSliceOfUnquoted(hardwareFoldersFlag)
134-
if err != nil {
135-
printCompleteError(err)
136-
defer os.Exit(1)
137-
return
138-
}
139-
140-
if len(hardware) == 0 {
141-
fmt.Fprintln(os.Stderr, "Parameter 'hardware' is mandatory")
142-
flag.Usage()
143-
defer os.Exit(1)
144-
return
160+
buildOptions := make(map[string]string)
161+
if *buildOptionsFileFlag != "" {
162+
if _, err := os.Stat(*buildOptionsFileFlag); err == nil {
163+
data, err := ioutil.ReadFile(*buildOptionsFileFlag)
164+
if err != nil {
165+
printCompleteError(err)
166+
defer os.Exit(1)
167+
return
168+
}
169+
err = json.Unmarshal(data, &buildOptions)
170+
if err != nil {
171+
printCompleteError(err)
172+
defer os.Exit(1)
173+
return
174+
}
175+
}
145176
}
146-
context[constants.CTX_HARDWARE_FOLDERS] = hardware
147177

148-
tools, err := toSliceOfUnquoted(toolsFoldersFlag)
178+
var err error
179+
printStackTrace := false
180+
err, printStackTrace = setContextSliceKeyOrLoadItFromOptions(context, hardwareFoldersFlag, buildOptions, constants.CTX_HARDWARE_FOLDERS, FLAG_HARDWARE, true)
149181
if err != nil {
150-
printCompleteError(err)
182+
printError(err, printStackTrace)
151183
defer os.Exit(1)
152184
return
153185
}
154186

155-
if len(tools) == 0 {
156-
fmt.Fprintln(os.Stderr, "Parameter 'tools' is mandatory")
157-
flag.Usage()
187+
err, printStackTrace = setContextSliceKeyOrLoadItFromOptions(context, toolsFoldersFlag, buildOptions, constants.CTX_TOOLS_FOLDERS, FLAG_TOOLS, true)
188+
if err != nil {
189+
printError(err, printStackTrace)
158190
defer os.Exit(1)
159191
return
160192
}
161-
context[constants.CTX_TOOLS_FOLDERS] = tools
162193

163-
libraries, err := toSliceOfUnquoted(librariesFoldersFlag)
194+
err, printStackTrace = setContextSliceKeyOrLoadItFromOptions(context, librariesFoldersFlag, buildOptions, constants.CTX_LIBRARIES_FOLDERS, FLAG_LIBRARIES, false)
164195
if err != nil {
165-
printCompleteError(err)
196+
printError(err, printStackTrace)
166197
defer os.Exit(1)
167198
return
168199
}
169-
context[constants.CTX_LIBRARIES_FOLDERS] = libraries
170200

171-
customBuildProperties, err := toSliceOfUnquoted(customBuildPropertiesFlag)
201+
err, printStackTrace = setContextSliceKeyOrLoadItFromOptions(context, customBuildPropertiesFlag, buildOptions, constants.CTX_CUSTOM_BUILD_PROPERTIES, FLAG_PREFS, false)
172202
if err != nil {
173-
printCompleteError(err)
203+
printError(err, printStackTrace)
174204
defer os.Exit(1)
175205
return
176206
}
177-
context[constants.CTX_CUSTOM_BUILD_PROPERTIES] = customBuildProperties
178207

179208
fqbn, err := gohasissues.Unquote(*fqbnFlag)
180209
if err != nil {
@@ -184,8 +213,11 @@ func main() {
184213
}
185214

186215
if fqbn == "" {
187-
fmt.Fprintln(os.Stderr, "Parameter 'fqbn' is mandatory")
188-
flag.Usage()
216+
fqbn = buildOptions[constants.CTX_FQBN]
217+
}
218+
219+
if fqbn == "" {
220+
printErrorMessageAndFlagUsage(errors.New("Parameter '" + FLAG_FQBN + "' is mandatory"))
189221
defer os.Exit(1)
190222
return
191223
}
@@ -234,7 +266,14 @@ func main() {
234266
}
235267

236268
context[constants.CTX_VERBOSE] = *verboseFlag
237-
context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = *ideVersionFlag
269+
270+
ideVersion := ""
271+
if utils.MapStringStringHas(buildOptions, constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION) {
272+
ideVersion = buildOptions[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION]
273+
} else {
274+
ideVersion = *ideVersionFlag
275+
}
276+
context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = ideVersion
238277

239278
if *warningsLevelFlag != "" {
240279
context[constants.CTX_WARNINGS_LEVEL] = *warningsLevelFlag
@@ -248,7 +287,7 @@ func main() {
248287
context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH] = *libraryDiscoveryRecursionDepthFlag
249288
}
250289

251-
if *loggerFlag == "machine" {
290+
if *loggerFlag == FLAG_LOGGER_MACHINE {
252291
context[constants.CTX_LOGGER] = i18n.MachineLogger{}
253292
} else {
254293
context[constants.CTX_LOGGER] = i18n.HumanLogger{}
@@ -276,6 +315,25 @@ func main() {
276315
defer os.Exit(exitCode)
277316
}
278317

318+
func setContextSliceKeyOrLoadItFromOptions(context map[string]interface{}, cliFlag slice, buildOptions map[string]string, contextKey string, paramName string, mandatory bool) (error, bool) {
319+
values, err := toSliceOfUnquoted(cliFlag)
320+
if err != nil {
321+
return err, true
322+
}
323+
324+
if len(values) == 0 && len(buildOptions[contextKey]) > 0 {
325+
values = strings.Split(buildOptions[contextKey], ",")
326+
}
327+
328+
if mandatory && len(values) == 0 {
329+
return errors.New("Parameter '" + paramName + "' is mandatory"), false
330+
}
331+
332+
context[contextKey] = values
333+
334+
return nil, false
335+
}
336+
279337
func toExitCode(err error) int {
280338
if exiterr, ok := err.(*exec.ExitError); ok {
281339
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
@@ -297,7 +355,20 @@ func toSliceOfUnquoted(value slice) ([]string, error) {
297355
return values, nil
298356
}
299357

358+
func printError(err error, printStackTrace bool) {
359+
if printStackTrace {
360+
printCompleteError(err)
361+
} else {
362+
printErrorMessageAndFlagUsage(err)
363+
}
364+
}
365+
300366
func printCompleteError(err error) {
301367
err = utils.WrapError(err)
302368
fmt.Fprintln(os.Stderr, err.(*errors.Error).ErrorStack())
303369
}
370+
371+
func printErrorMessageAndFlagUsage(err error) {
372+
fmt.Fprintln(os.Stderr, err)
373+
flag.Usage()
374+
}

0 commit comments

Comments
 (0)
Please sign in to comment.