コード例 #1
0
func (s *RecipeByPrefixSuffixRunner) Run(context map[string]interface{}) error {
	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	if utils.DebugLevel(context) >= 10 {
		logger.Fprintln(os.Stderr, constants.MSG_LOOKING_FOR_RECIPES, s.Prefix, s.Suffix)
	}

	buildProperties := utils.GetMapStringStringOrDefault(context, constants.CTX_BUILD_PROPERTIES)
	verbose := context[constants.CTX_VERBOSE].(bool)

	recipes := findRecipes(buildProperties, s.Prefix, s.Suffix)

	properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties)
	for _, recipe := range recipes {
		if utils.DebugLevel(context) >= 10 {
			logger.Fprintln(os.Stderr, constants.MSG_RUNNING_RECIPE, recipe)
		}
		_, err := builder_utils.ExecRecipe(properties, recipe, false, verbose, verbose, logger)
		if err != nil {
			return utils.WrapError(err)
		}
	}

	return nil

}
コード例 #2
0
func (s *RecipeByPrefixSuffixRunner) Run(context map[string]interface{}) error {
	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	if utils.DebugLevel(context) >= 10 {
		logger.Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_LOOKING_FOR_RECIPES, s.Prefix, s.Suffix)
	}

	buildProperties := make(props.PropertiesMap)
	if p, ok := context[constants.CTX_BUILD_PROPERTIES]; ok {
		buildProperties = p.(props.PropertiesMap).Clone()
	}
	verbose := context[constants.CTX_VERBOSE].(bool)

	recipes := findRecipes(buildProperties, s.Prefix, s.Suffix)

	properties := buildProperties.Clone()
	for _, recipe := range recipes {
		if utils.DebugLevel(context) >= 10 {
			logger.Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_RUNNING_RECIPE, recipe)
		}
		_, err := builder_utils.ExecRecipe(properties, recipe, false, verbose, verbose, logger)
		if err != nil {
			return utils.WrapError(err)
		}
	}

	return nil

}
コード例 #3
0
func (s *RewriteHardwareKeys) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_PLATFORM_KEYS_REWRITE) {
		return nil
	}

	hardware := context[constants.CTX_HARDWARE].(map[string]*types.Package)
	platformKeysRewrite := context[constants.CTX_PLATFORM_KEYS_REWRITE].(types.PlatforKeysRewrite)
	logger := context[constants.CTX_LOGGER].(i18n.Logger)

	warn := utils.DebugLevel(context) > 0

	for _, aPackage := range hardware {
		for _, platform := range aPackage.Platforms {
			if platform.Properties[constants.REWRITING] != constants.REWRITING_DISABLED {
				for _, rewrite := range platformKeysRewrite.Rewrites {
					if platform.Properties[rewrite.Key] != constants.EMPTY_STRING && platform.Properties[rewrite.Key] == rewrite.OldValue {
						platform.Properties[rewrite.Key] = rewrite.NewValue
						if warn {
							logger.Fprintln(os.Stderr, constants.MSG_WARNING_PLATFORM_OLD_VALUES, platform.Properties[constants.PLATFORM_NAME], rewrite.Key+"="+rewrite.OldValue, rewrite.Key+"="+rewrite.NewValue)
						}
					}
				}
			}
		}
	}

	return nil
}
コード例 #4
0
func (s *IncludesToIncludeFolders) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_LIBRARIES) {
		return nil
	}
	includes := context[constants.CTX_INCLUDES].([]string)
	headerToLibraries := context[constants.CTX_HEADER_TO_LIBRARIES].(map[string][]*types.Library)
	debugLevel := utils.DebugLevel(context)
	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	platform := context[constants.CTX_TARGET_PLATFORM].(*types.Platform)
	actualPlatform := context[constants.CTX_ACTUAL_PLATFORM].(*types.Platform)

	var previousImportedLibraries []*types.Library
	if utils.MapHas(context, constants.CTX_IMPORTED_LIBRARIES) {
		previousImportedLibraries = context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library)
	}
	importedLibraries, err := resolveLibraries(includes, headerToLibraries, previousImportedLibraries, []*types.Platform{actualPlatform, platform}, debugLevel, logger)
	if err != nil {
		return utils.WrapError(err)
	}
	context[constants.CTX_IMPORTED_LIBRARIES] = importedLibraries

	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(map[string]string)
	verbose := context[constants.CTX_VERBOSE].(bool)
	includeFolders := resolveIncludeFolders(importedLibraries, buildProperties, verbose)
	context[constants.CTX_INCLUDE_FOLDERS] = includeFolders

	return nil
}
func (s *WarnAboutArchIncompatibleLibraries) Run(context map[string]interface{}) error {
	if utils.DebugLevel(context) <= 0 {
		return nil
	}

	targetPlatform := context[constants.CTX_TARGET_PLATFORM].(*types.Platform)
	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(props.PropertiesMap)
	logger := context[constants.CTX_LOGGER].(i18n.Logger)

	archs := []string{}
	archs = append(archs, targetPlatform.PlatformId)

	if buildProperties[constants.BUILD_PROPERTIES_ARCH_OVERRIDE_CHECK] != constants.EMPTY_STRING {
		overrides := strings.Split(buildProperties[constants.BUILD_PROPERTIES_ARCH_OVERRIDE_CHECK], ",")
		for _, override := range overrides {
			archs = append(archs, override)
		}
	}

	importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library)
	for _, importedLibrary := range importedLibraries {
		if !importedLibrary.SupportsArchitectures(archs) {
			logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_LIBRARY_INCOMPATIBLE_ARCH, importedLibrary.Name, importedLibrary.Archs, archs)
		}
	}

	return nil
}
コード例 #6
0
func (s *WarnAboutPlatformRewrites) Run(context map[string]interface{}) error {
	warn := utils.DebugLevel(context) > 0
	if !warn {
		return nil
	}

	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	hardwareRewriteResults := context[constants.CTX_HARDWARE_REWRITE_RESULTS].(map[*types.Platform][]types.PlatforKeyRewrite)
	targetPlatform := context[constants.CTX_TARGET_PLATFORM].(*types.Platform)
	actualPlatform := context[constants.CTX_ACTUAL_PLATFORM].(*types.Platform)

	platforms := []*types.Platform{targetPlatform}
	if actualPlatform != targetPlatform {
		platforms = append(platforms, actualPlatform)
	}

	for _, platform := range platforms {
		if hardwareRewriteResults[platform] != nil {
			for _, rewrite := range hardwareRewriteResults[platform] {
				logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_WARNING_PLATFORM_OLD_VALUES, platform.Properties[constants.PLATFORM_NAME], rewrite.Key+"="+rewrite.OldValue, rewrite.Key+"="+rewrite.NewValue)
			}
		}
	}

	return nil
}
コード例 #7
0
func skipTagsWithField(tags []map[string]string, fields []string, context map[string]interface{}) {
	for _, tag := range tags {
		if field, skip := utils.TagHasAtLeastOneField(tag, fields); skip {
			if utils.DebugLevel(context) >= 10 {
				utils.Logger(context).Fprintln(os.Stderr, constants.MSG_SKIPPING_TAG_BECAUSE_HAS_FIELD, field)
			}
			tag[FIELD_SKIP] = TRUE
		}
	}
}
コード例 #8
0
func skipTagsWhere(tags []map[string]string, skipFunc skipFuncType, context map[string]interface{}) {
	for _, tag := range tags {
		if tag[FIELD_SKIP] != TRUE {
			skip := skipFunc(tag)
			if skip && utils.DebugLevel(context) >= 10 {
				utils.Logger(context).Fprintln(os.Stderr, constants.MSG_SKIPPING_TAG_WITH_REASON, tag[FIELD_FUNCTION_NAME], runtime.FuncForPC(reflect.ValueOf(skipFunc).Pointer()).Name())
			}
			tag[FIELD_SKIP] = strconv.FormatBool(skip)
		}
	}
}
コード例 #9
0
func skipTagsWhere(tags []*types.CTag, skipFunc skipFuncType, context map[string]interface{}) {
	for _, tag := range tags {
		if !tag.SkipMe {
			skip := skipFunc(tag)
			if skip && utils.DebugLevel(context) >= 10 {
				utils.Logger(context).Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_SKIPPING_TAG_WITH_REASON, tag.FunctionName, runtime.FuncForPC(reflect.ValueOf(skipFunc).Pointer()).Name())
			}
			tag.SkipMe = skip
		}
	}
}
コード例 #10
0
func removeDefinedProtypes(tags []map[string]string, context map[string]interface{}) {
	definedPrototypes := make(map[string]bool)
	for _, tag := range tags {
		if tag[FIELD_KIND] == KIND_PROTOTYPE {
			definedPrototypes[tag[KIND_PROTOTYPE]] = true
		}
	}

	for _, tag := range tags {
		if definedPrototypes[tag[KIND_PROTOTYPE]] {
			if utils.DebugLevel(context) >= 10 {
				utils.Logger(context).Fprintln(os.Stderr, constants.MSG_SKIPPING_TAG_ALREADY_DEFINED, tag[FIELD_FUNCTION_NAME])
			}
			tag[FIELD_SKIP] = TRUE
		}
	}
}
コード例 #11
0
func removeDefinedProtypes(tags []*types.CTag, context map[string]interface{}) {
	definedPrototypes := make(map[string]bool)
	for _, tag := range tags {
		if tag.Kind == KIND_PROTOTYPE {
			definedPrototypes[tag.Prototype] = true
		}
	}

	for _, tag := range tags {
		if definedPrototypes[tag.Prototype] {
			if utils.DebugLevel(context) >= 10 {
				utils.Logger(context).Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_SKIPPING_TAG_ALREADY_DEFINED, tag.FunctionName)
			}
			tag.SkipMe = true
		}
	}
}
コード例 #12
0
func (s *PrintUsedAndNotUsedLibraries) Run(context map[string]interface{}) error {
	if utils.DebugLevel(context) <= 0 {
		return nil
	}

	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	libraryResolutionResults := context[constants.CTX_LIBRARY_RESOLUTION_RESULTS].(map[string]types.LibraryResolutionResult)

	for header, libResResult := range libraryResolutionResults {
		if !libResResult.IsLibraryFromPlatform {
			logger.Fprintln(os.Stderr, constants.MSG_LIBRARIES_MULTIPLE_LIBS_FOUND_FOR, header)
			logger.Fprintln(os.Stderr, constants.MSG_LIBRARIES_USED, libResResult.Library.Folder)
			for _, notUsedLibrary := range libResResult.NotUsedLibraries {
				logger.Fprintln(os.Stderr, constants.MSG_LIBRARIES_NOT_USED, notUsedLibrary.Folder)
			}
		}
	}

	time.Sleep(100 * time.Millisecond)

	return nil
}
コード例 #13
0
func (s *GenerateBuildPathIfMissing) Run(context map[string]interface{}) error {
	if utils.MapHas(context, constants.CTX_BUILD_PATH) && context[constants.CTX_BUILD_PATH].(string) != constants.EMPTY_STRING {
		return nil
	}

	sketchLocation := context[constants.CTX_SKETCH_LOCATION].(string)
	md5sum := utils.MD5Sum([]byte(sketchLocation))

	buildPath := filepath.Join(os.TempDir(), "arduino-sketch-"+strings.ToUpper(md5sum))
	_, err := os.Stat(buildPath)
	if err != nil && !os.IsNotExist(err) {
		return utils.WrapError(err)
	}

	if utils.DebugLevel(context) > 5 {
		logger := context[constants.CTX_LOGGER].(i18n.Logger)
		logger.Fprintln(os.Stdout, constants.LOG_LEVEL_WARN, constants.MSG_SETTING_BUILD_PATH, buildPath)
	}

	context[constants.CTX_BUILD_PATH] = buildPath

	return nil
}
コード例 #14
0
func (s *LibrariesLoader) Run(context map[string]interface{}) error {
	sortedLibrariesFolders := []string{}

	builtInLibrariesFolders := []string{}
	if utils.MapHas(context, constants.CTX_BUILT_IN_LIBRARIES_FOLDERS) {
		builtInLibrariesFolders = context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS].([]string)
	}
	builtInLibrariesFolders, err := utils.AbsolutizePaths(builtInLibrariesFolders)
	if err != nil {
		return utils.WrapError(err)
	}
	sortedLibrariesFolders = utils.AppendIfNotPresent(sortedLibrariesFolders, builtInLibrariesFolders...)

	platform := context[constants.CTX_TARGET_PLATFORM].(*types.Platform)
	debugLevel := utils.DebugLevel(context)
	logger := context[constants.CTX_LOGGER].(i18n.Logger)

	actualPlatform := context[constants.CTX_ACTUAL_PLATFORM].(*types.Platform)
	if actualPlatform != platform {
		sortedLibrariesFolders = appendPathToLibrariesFolders(sortedLibrariesFolders, filepath.Join(actualPlatform.Folder, constants.FOLDER_LIBRARIES))
	}

	sortedLibrariesFolders = appendPathToLibrariesFolders(sortedLibrariesFolders, filepath.Join(platform.Folder, constants.FOLDER_LIBRARIES))

	librariesFolders := []string{}
	if utils.MapHas(context, constants.CTX_OTHER_LIBRARIES_FOLDERS) {
		librariesFolders = context[constants.CTX_OTHER_LIBRARIES_FOLDERS].([]string)
	}
	librariesFolders, err = utils.AbsolutizePaths(librariesFolders)
	if err != nil {
		return utils.WrapError(err)
	}
	sortedLibrariesFolders = utils.AppendIfNotPresent(sortedLibrariesFolders, librariesFolders...)

	context[constants.CTX_LIBRARIES_FOLDERS] = sortedLibrariesFolders

	var libraries []*types.Library
	for _, libraryFolder := range sortedLibrariesFolders {
		subFolders, err := utils.ReadDirFiltered(libraryFolder, utils.FilterDirs)
		if err != nil {
			return utils.WrapError(err)
		}
		for _, subFolder := range subFolders {
			library, err := makeLibrary(filepath.Join(libraryFolder, subFolder.Name()), debugLevel, logger)
			if err != nil {
				return utils.WrapError(err)
			}
			libraries = append(libraries, library)
		}
	}

	context[constants.CTX_LIBRARIES] = libraries

	headerToLibraries := make(map[string][]*types.Library)
	for _, library := range libraries {
		headers, err := utils.ReadDirFiltered(library.SrcFolder, utils.FilterFilesWithExtension(".h"))
		if err != nil {
			return utils.WrapError(err)
		}
		for _, header := range headers {
			headerFileName := header.Name()
			headerToLibraries[headerFileName] = append(headerToLibraries[headerFileName], library)
		}
	}

	context[constants.CTX_HEADER_TO_LIBRARIES] = headerToLibraries

	return nil
}
コード例 #15
0
ファイル: main.go プロジェクト: cmaglie/arduino-builder
func main() {
	flag.Parse()

	if *versionFlag {
		fmt.Println("Arduino Builder " + VERSION)
		fmt.Println("Copyright (C) 2015 Arduino LLC and contributors")
		fmt.Println("See https://www.arduino.cc/ and https://github.com/arduino/arduino-builder/graphs/contributors")
		fmt.Println("This is free software; see the source for copying conditions.  There is NO")
		fmt.Println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.")
		defer os.Exit(0)
		return
	}

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

	buildOptions := make(map[string]string)
	if *buildOptionsFileFlag != "" {
		if _, err := os.Stat(*buildOptionsFileFlag); err == nil {
			data, err := ioutil.ReadFile(*buildOptionsFileFlag)
			if err != nil {
				printCompleteError(err)
				defer os.Exit(1)
				return
			}
			err = json.Unmarshal(data, &buildOptions)
			if err != nil {
				printCompleteError(err)
				defer os.Exit(1)
				return
			}
		}
	}

	var err error
	printStackTrace := false
	err, printStackTrace = setContextSliceKeyOrLoadItFromOptions(context, hardwareFoldersFlag, buildOptions, constants.CTX_HARDWARE_FOLDERS, FLAG_HARDWARE, true)
	if err != nil {
		printError(err, printStackTrace)
		defer os.Exit(1)
		return
	}

	err, printStackTrace = setContextSliceKeyOrLoadItFromOptions(context, toolsFoldersFlag, buildOptions, constants.CTX_TOOLS_FOLDERS, FLAG_TOOLS, true)
	if err != nil {
		printError(err, printStackTrace)
		defer os.Exit(1)
		return
	}

	err, printStackTrace = setContextSliceKeyOrLoadItFromOptions(context, librariesFoldersFlag, buildOptions, constants.CTX_OTHER_LIBRARIES_FOLDERS, FLAG_LIBRARIES, false)
	if err != nil {
		printError(err, printStackTrace)
		defer os.Exit(1)
		return
	}

	err, printStackTrace = setContextSliceKeyOrLoadItFromOptions(context, librariesBuiltInFoldersFlag, buildOptions, constants.CTX_BUILT_IN_LIBRARIES_FOLDERS, FLAG_BUILT_IN_LIBRARIES, false)
	if err != nil {
		printError(err, printStackTrace)
		defer os.Exit(1)
		return
	}

	err, printStackTrace = setContextSliceKeyOrLoadItFromOptions(context, customBuildPropertiesFlag, buildOptions, constants.CTX_CUSTOM_BUILD_PROPERTIES, FLAG_PREFS, false)
	if err != nil {
		printError(err, printStackTrace)
		defer os.Exit(1)
		return
	}

	fqbn, err := gohasissues.Unquote(*fqbnFlag)
	if err != nil {
		printCompleteError(err)
		defer os.Exit(1)
		return
	}

	if fqbn == "" {
		fqbn = buildOptions[constants.CTX_FQBN]
	}

	if fqbn == "" {
		printErrorMessageAndFlagUsage(errors.New("Parameter '" + FLAG_FQBN + "' is mandatory"))
		defer os.Exit(1)
		return
	}
	context[constants.CTX_FQBN] = fqbn

	buildPath, err := gohasissues.Unquote(*buildPathFlag)
	if err != nil {
		printCompleteError(err)
		defer os.Exit(1)
		return
	}

	if buildPath != "" {
		_, err := os.Stat(buildPath)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			defer os.Exit(1)
			return
		}

		err = utils.EnsureFolderExists(buildPath)
		if err != nil {
			printCompleteError(err)
			defer os.Exit(1)
			return
		}
	}
	context[constants.CTX_BUILD_PATH] = buildPath

	if *vidPidFlag != "" {
		context[constants.CTX_VIDPID] = *vidPidFlag
	}

	if flag.NArg() > 0 {
		sketchLocation := flag.Arg(0)
		sketchLocation, err := gohasissues.Unquote(sketchLocation)
		if err != nil {
			printCompleteError(err)
			defer os.Exit(1)
			return
		}
		context[constants.CTX_SKETCH_LOCATION] = sketchLocation
	}

	if *verboseFlag && *quietFlag {
		*verboseFlag = false
		*quietFlag = false
	}

	context[constants.CTX_VERBOSE] = *verboseFlag

	ideVersion := ""
	if utils.MapStringStringHas(buildOptions, constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION) {
		ideVersion = buildOptions[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION]
	} else {
		ideVersion = *ideVersionFlag
	}
	context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = ideVersion

	if *warningsLevelFlag != "" {
		context[constants.CTX_WARNINGS_LEVEL] = *warningsLevelFlag
	}

	if *debugLevelFlag > -1 {
		context[constants.CTX_DEBUG_LEVEL] = *debugLevelFlag
	}

	if *libraryDiscoveryRecursionDepthFlag > 0 {
		context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH] = *libraryDiscoveryRecursionDepthFlag
	}

	if *quietFlag {
		context[constants.CTX_LOGGER] = i18n.NoopLogger{}
	} else if *loggerFlag == FLAG_LOGGER_MACHINE {
		context[constants.CTX_LOGGER] = i18n.MachineLogger{}
	} else {
		context[constants.CTX_LOGGER] = i18n.HumanLogger{}
	}

	if *dumpPrefsFlag {
		err = builder.RunParseHardwareAndDumpBuildProperties(context)
	} else if *preprocessFlag {
		err = builder.RunPreprocess(context)
	} else {
		if flag.NArg() == 0 {
			fmt.Fprintln(os.Stderr, "Last parameter must be the sketch to compile")
			flag.Usage()
			defer os.Exit(1)
			return
		}
		err = builder.RunBuilder(context)
	}

	exitCode := 0
	if err != nil {
		err = utils.WrapError(err)

		fmt.Fprintln(os.Stderr, err)

		if utils.DebugLevel(context) >= 10 {
			fmt.Fprintln(os.Stderr, err.(*errors.Error).ErrorStack())
		}

		exitCode = toExitCode(err)
	}

	defer os.Exit(exitCode)
}
コード例 #16
0
func PrintRingNameIfDebug(context map[string]interface{}, command types.Command) {
	if utils.DebugLevel(context) >= 10 {
		utils.Logger(context).Fprintln(os.Stderr, constants.MSG_RUNNING_COMMAND, reflect.Indirect(reflect.ValueOf(command)).Type().Name())
	}
}
コード例 #17
0
ファイル: builder.go プロジェクト: andy521/arduino-builder
func PrintRingNameIfDebug(context map[string]interface{}, command types.Command) {
	if utils.DebugLevel(context) >= 10 {
		utils.Logger(context).Fprintln(os.Stdout, constants.LOG_LEVEL_DEBUG, constants.MSG_RUNNING_COMMAND, strconv.FormatInt(time.Now().Unix(), 10), reflect.Indirect(reflect.ValueOf(command)).Type().Name())
	}
}
コード例 #18
0
ファイル: main.go プロジェクト: ricklon/arduino-builder
func main() {
	flag.Parse()

	if *versionFlag {
		fmt.Println("Arduino Builder " + VERSION)
		fmt.Println("Copyright (C) 2015 Arduino LLC and contributors")
		fmt.Println("See https://www.arduino.cc/ and https://github.com/arduino/arduino-builder/graphs/contributors")
		fmt.Println("This is free software; see the source for copying conditions.  There is NO")
		fmt.Println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.")
		defer os.Exit(0)
		return
	}

	compile := *compileFlag
	dumpPrefs := *dumpPrefsFlag

	if compile && dumpPrefs {
		fmt.Println("You can either specify --compile or --dump-prefs, not both")
		defer os.Exit(1)
		return
	}

	if !compile && !dumpPrefs {
		compile = true
	}

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

	hardware, err := toSliceOfUnquoted(hardwareFoldersFlag)
	if err != nil {
		printCompleteError(err)
		defer os.Exit(1)
		return
	}

	if len(hardware) == 0 {
		fmt.Println("Parameter 'hardware' is mandatory")
		flag.Usage()
		defer os.Exit(1)
		return
	}
	context[constants.CTX_HARDWARE_FOLDERS] = hardware

	tools, err := toSliceOfUnquoted(toolsFoldersFlag)
	if err != nil {
		printCompleteError(err)
		defer os.Exit(1)
		return
	}

	if len(tools) == 0 {
		fmt.Println("Parameter 'tools' is mandatory")
		flag.Usage()
		defer os.Exit(1)
		return
	}
	context[constants.CTX_TOOLS_FOLDERS] = tools

	libraries, err := toSliceOfUnquoted(librariesFoldersFlag)
	if err != nil {
		printCompleteError(err)
		defer os.Exit(1)
		return
	}
	context[constants.CTX_LIBRARIES_FOLDERS] = libraries

	customBuildProperties, err := toSliceOfUnquoted(customBuildPropertiesFlag)
	if err != nil {
		printCompleteError(err)
		defer os.Exit(1)
		return
	}
	context[constants.CTX_CUSTOM_BUILD_PROPERTIES] = customBuildProperties

	fqbn, err := gohasissues.Unquote(*fqbnFlag)
	if err != nil {
		printCompleteError(err)
		defer os.Exit(1)
		return
	}

	if fqbn == "" {
		fmt.Println("Parameter 'fqbn' is mandatory")
		flag.Usage()
		defer os.Exit(1)
		return
	}
	context[constants.CTX_FQBN] = fqbn

	buildPath, err := gohasissues.Unquote(*buildPathFlag)
	if err != nil {
		printCompleteError(err)
		defer os.Exit(1)
		return
	}

	if buildPath != "" {
		_, err := os.Stat(buildPath)
		if err != nil {
			fmt.Println(err)
			defer os.Exit(1)
			return
		}

		err = os.MkdirAll(buildPath, os.FileMode(0755))
		if err != nil {
			printCompleteError(err)
			defer os.Exit(1)
			return
		}
	}
	context[constants.CTX_BUILD_PATH] = buildPath

	if compile && flag.NArg() == 0 {
		fmt.Println("Last parameter must be the sketch to compile")
		flag.Usage()
		defer os.Exit(1)
		return
	}

	if flag.NArg() > 0 {
		sketchLocation := flag.Arg(0)
		sketchLocation, err := gohasissues.Unquote(sketchLocation)
		if err != nil {
			printCompleteError(err)
			defer os.Exit(1)
			return
		}
		context[constants.CTX_SKETCH_LOCATION] = sketchLocation
	}

	context[constants.CTX_VERBOSE] = *verboseFlag
	context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = *ideVersionFlag

	if *warningsLevelFlag != "" {
		context[constants.CTX_WARNINGS_LEVEL] = *warningsLevelFlag
	}

	if *debugLevelFlag > -1 {
		context[constants.CTX_DEBUG_LEVEL] = *debugLevelFlag
	}

	if *libraryDiscoveryRecursionDepthFlag > 0 {
		context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH] = *libraryDiscoveryRecursionDepthFlag
	}

	if *loggerFlag == "machine" {
		context[constants.CTX_LOGGER] = i18n.MachineLogger{}
	} else {
		context[constants.CTX_LOGGER] = i18n.HumanLogger{}
	}

	if compile {
		err = builder.RunBuilder(context)
	} else if dumpPrefs {
		err = builder.RunParseHardwareAndDumpBuildProperties(context)
	}

	exitCode := 0
	if err != nil {
		err = utils.WrapError(err)

		fmt.Println(err)

		if utils.DebugLevel(context) >= 10 {
			fmt.Println(err.(*errors.Error).ErrorStack())
		}

		exitCode = toExitCode(err)
	}

	defer os.Exit(exitCode)
}