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 *AddAdditionalEntriesToContext) Run(context map[string]interface{}) error {
	if utils.MapHas(context, constants.CTX_BUILD_PATH) {
		buildPath := context[constants.CTX_BUILD_PATH].(string)
		preprocPath, err := filepath.Abs(filepath.Join(buildPath, constants.FOLDER_PREPROC))
		if err != nil {
			return utils.WrapError(err)
		}
		sketchBuildPath, err := filepath.Abs(filepath.Join(buildPath, constants.FOLDER_SKETCH))
		if err != nil {
			return utils.WrapError(err)
		}
		librariesBuildPath, err := filepath.Abs(filepath.Join(buildPath, constants.FOLDER_LIBRARIES))
		if err != nil {
			return utils.WrapError(err)
		}
		coreBuildPath, err := filepath.Abs(filepath.Join(buildPath, constants.FOLDER_CORE))
		if err != nil {
			return utils.WrapError(err)
		}

		context[constants.CTX_PREPROC_PATH] = preprocPath
		context[constants.CTX_SKETCH_BUILD_PATH] = sketchBuildPath
		context[constants.CTX_LIBRARIES_BUILD_PATH] = librariesBuildPath
		context[constants.CTX_CORE_BUILD_PATH] = coreBuildPath
	}

	if !utils.MapHas(context, constants.CTX_WARNINGS_LEVEL) {
		context[constants.CTX_WARNINGS_LEVEL] = DEFAULT_WARNINGS_LEVEL
	}

	if !utils.MapHas(context, constants.CTX_VERBOSE) {
		context[constants.CTX_VERBOSE] = false
	}

	if !utils.MapHas(context, constants.CTX_DEBUG_LEVEL) {
		context[constants.CTX_DEBUG_LEVEL] = DEFAULT_DEBUG_LEVEL
	}

	if !utils.MapHas(context, constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH) {
		context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH] = DEFAULT_LIBRARY_DISCOVERY_RECURSION_DEPTH
	}

	sourceFiles := &types.UniqueStringQueue{}
	context[constants.CTX_COLLECTED_SOURCE_FILES_QUEUE] = sourceFiles
	foldersWithSources := &types.UniqueSourceFolderQueue{}
	context[constants.CTX_FOLDERS_WITH_SOURCES_QUEUE] = foldersWithSources

	context[constants.CTX_LIBRARY_RESOLUTION_RESULTS] = make(map[string]types.LibraryResolutionResult)

	return nil
}
func (s *ContainerFindIncludes) Run(context map[string]interface{}) error {
	err := runCommand(context, &IncludesToIncludeFolders{})
	if err != nil {
		return utils.WrapError(err)
	}

	sketch := context[constants.CTX_SKETCH].(*types.Sketch)
	sketchBuildPath := context[constants.CTX_SKETCH_BUILD_PATH].(string)
	wheelSpins := context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH].(int)
	for i := 0; i < wheelSpins; i++ {
		commands := []types.Command{
			&IncludesFinderWithGCC{SourceFile: filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp")},
			&GCCMinusMOutputParser{},
			&IncludesToIncludeFolders{},
		}

		for _, command := range commands {
			err := runCommand(context, command)
			if err != nil {
				return utils.WrapError(err)
			}
		}
	}

	foldersWithSources := context[constants.CTX_FOLDERS_WITH_SOURCES_QUEUE].(*types.UniqueSourceFolderQueue)
	foldersWithSources.Push(types.SourceFolder{Folder: context[constants.CTX_SKETCH_BUILD_PATH].(string), Recurse: true})
	if utils.MapHas(context, constants.CTX_IMPORTED_LIBRARIES) {
		for _, library := range context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) {
			sourceFolders := utils.LibraryToSourceFolder(library)
			for _, sourceFolder := range sourceFolders {
				foldersWithSources.Push(sourceFolder)
			}
		}
	}

	err = runCommand(context, &CollectAllSourceFilesFromFoldersWithSources{})
	if err != nil {
		return utils.WrapError(err)
	}

	sourceFiles := context[constants.CTX_COLLECTED_SOURCE_FILES_QUEUE].(*types.UniqueStringQueue)

	for !sourceFiles.Empty() {
		commands := []types.Command{
			&IncludesFinderWithGCC{SourceFile: sourceFiles.Pop().(string)},
			&GCCMinusMOutputParser{},
			&IncludesToIncludeFolders{},
			&CollectAllSourceFilesFromFoldersWithSources{},
		}

		for _, command := range commands {
			err := runCommand(context, command)
			if err != nil {
				return utils.WrapError(err)
			}
		}
	}

	return nil
}
func (s *PrototypesAdder) Run(context map[string]interface{}) error {
	source := context[constants.CTX_SOURCE].(string)
	sourceRows := strings.Split(source, "\n")

	if !utils.MapHas(context, constants.CTX_FIRST_FUNCTION_AT_LINE) {
		return nil
	}

	firstFunctionLine := context[constants.CTX_FIRST_FUNCTION_AT_LINE].(int)
	if firstFunctionOutsideOfSource(firstFunctionLine, sourceRows) {
		return nil
	}

	firstFunctionChar := len(strings.Join(sourceRows[:firstFunctionLine-1], "\n")) + 1
	if firstFunctionLine > 1 {
		firstFunctionLine -= context[constants.CTX_LINE_OFFSET].(int)
	}
	prototypeSection := composePrototypeSection(firstFunctionLine, context[constants.CTX_PROTOTYPES].([]string))
	context[constants.CTX_PROTOTYPE_SECTION] = prototypeSection
	source = source[:firstFunctionChar] + prototypeSection + source[firstFunctionChar:]

	includeSection := composeIncludeArduinoSection()
	context[constants.CTX_INCLUDE_SECTION] = includeSection
	source = includeSection + source

	context[constants.CTX_SOURCE] = source

	return nil
}
func (s *SetupHumanLoggerIfMissing) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_LOGGER) {
		context[constants.CTX_LOGGER] = i18n.HumanLogger{}
	}

	return nil
}
func (s *RewriteHardwareKeys) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_PLATFORM_KEYS_REWRITE) {
		return nil
	}

	packages := context[constants.CTX_HARDWARE].(*types.Packages)
	platformKeysRewrite := context[constants.CTX_PLATFORM_KEYS_REWRITE].(types.PlatforKeysRewrite)
	hardwareRewriteResults := context[constants.CTX_HARDWARE_REWRITE_RESULTS].(map[*types.Platform][]types.PlatforKeyRewrite)

	for _, aPackage := range packages.Packages {
		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
						appliedRewrites := rewritesAppliedToPlatform(platform, hardwareRewriteResults)
						appliedRewrites = append(appliedRewrites, rewrite)
						hardwareRewriteResults[platform] = appliedRewrites
					}
				}
			}
		}
	}

	return nil
}
func (s *PrintUsedLibrariesIfVerbose) Run(context map[string]interface{}) error {
	verbose := context[constants.CTX_VERBOSE].(bool)
	logger := context[constants.CTX_LOGGER].(i18n.Logger)

	if !verbose || !utils.MapHas(context, constants.CTX_IMPORTED_LIBRARIES) {
		return nil
	}

	importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library)

	for _, library := range importedLibraries {
		legacy := constants.EMPTY_STRING
		if library.IsLegacy {
			legacy = constants.MSG_LIB_LEGACY
		}
		if library.Version == constants.EMPTY_STRING {
			logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_USING_LIBRARY, library.Name, library.Folder, legacy)
		} else {
			logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_USING_LIBRARY_AT_VERSION, library.Name, library.Version, library.Folder, legacy)
		}
	}

	time.Sleep(100 * time.Millisecond)

	return nil
}
func (s *WipeoutBuildPathIfBuildOptionsChanged) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_BUILD_OPTIONS_PREVIOUS_JSON) {
		return nil
	}

	buildOptionsJson := context[constants.CTX_BUILD_OPTIONS_JSON].(string)
	previousBuildOptionsJson := context[constants.CTX_BUILD_OPTIONS_PREVIOUS_JSON].(string)
	logger := context[constants.CTX_LOGGER].(i18n.Logger)

	if buildOptionsJson == previousBuildOptionsJson {
		return nil
	}

	logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_BUILD_OPTIONS_CHANGED)

	buildPath := context[constants.CTX_BUILD_PATH].(string)
	files, err := gohasissues.ReadDir(buildPath)
	if err != nil {
		return utils.WrapError(err)
	}
	for _, file := range files {
		os.RemoveAll(filepath.Join(buildPath, file.Name()))
	}

	return nil
}
func (s *IncludesFinderWithRegExp) Run(context map[string]interface{}) error {
	source := context[s.ContextField].(string)

	matches := INCLUDE_REGEXP.FindAllStringSubmatch(source, -1)
	includes := []string{}
	for _, match := range matches {
		includes = append(includes, strings.TrimSpace(match[1]))
	}

	if len(includes) == 0 {
		include := findIncludesForOldCompilers(source)
		if include != "" {
			includes = append(includes, include)
		}
	}

	context[constants.CTX_INCLUDES_JUST_FOUND] = includes

	if !utils.MapHas(context, constants.CTX_INCLUDES) {
		context[constants.CTX_INCLUDES] = includes
		return nil
	}

	context[constants.CTX_INCLUDES] = utils.AddStringsToStringsSet(context[constants.CTX_INCLUDES].([]string), includes)

	return nil
}
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
}
func (s *IncludesFinderWithGCC) Run(context map[string]interface{}) error {
	buildProperties := make(props.PropertiesMap)
	if p, ok := context[constants.CTX_BUILD_PROPERTIES]; ok {
		buildProperties = p.(props.PropertiesMap).Clone()
	}
	verbose := context[constants.CTX_VERBOSE].(bool)
	logger := context[constants.CTX_LOGGER].(i18n.Logger)

	includesParams := constants.EMPTY_STRING
	if utils.MapHas(context, constants.CTX_INCLUDE_FOLDERS) {
		includes := context[constants.CTX_INCLUDE_FOLDERS].([]string)
		includes = utils.Map(includes, utils.WrapWithHyphenI)
		includesParams = strings.Join(includes, " ")
	}

	properties := buildProperties.Clone()
	properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = s.SourceFile
	properties[constants.BUILD_PROPERTIES_INCLUDES] = includesParams
	builder_utils.RemoveHyphenMDDFlagFromGCCCommandLine(properties)

	output, err := builder_utils.ExecRecipe(properties, constants.RECIPE_PREPROC_INCLUDES, true, verbose, false, logger)
	if err != nil {
		return utils.WrapError(err)
	}

	context[constants.CTX_GCC_MINUS_M_OUTPUT] = string(output)

	return nil
}
func (s *GCCMinusMOutputParser) Run(context map[string]interface{}) error {
	output := context[constants.CTX_GCC_MINUS_M_OUTPUT].(string)

	rows := strings.Split(output, "\n")
	includes := make([]string, 0)
	if len(rows) > 2 {
		for _, row := range rows[2:] {
			if !strings.HasPrefix(row, constants.SPACE) {
				row = strings.TrimSpace(row)
				if row != constants.EMPTY_STRING {
					row = strings.TrimSuffix(row, ":")
					row = strings.Replace(row, "\\ ", " ", -1)
					includes = append(includes, row)
				}
			}
		}
	}

	if !utils.MapHas(context, constants.CTX_INCLUDES) {
		context[constants.CTX_INCLUDES] = includes
		return nil
	}

	previousIncludes := utils.SliceToMapStringBool(context[constants.CTX_INCLUDES].([]string), true)
	currentIncludes := utils.SliceToMapStringBool(includes, true)

	mergedIncludes := utils.MergeMapsOfStringBool(previousIncludes, currentIncludes)

	context[constants.CTX_INCLUDES] = utils.KeysOfMapOfStringBool(mergedIncludes)

	return nil
}
func (s *FailIfImportedLibraryIsWrong) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_IMPORTED_LIBRARIES) {
		return nil
	}

	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	importedLibraries := context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library)

	for _, library := range importedLibraries {
		if !library.IsLegacy {
			if stat, err := os.Stat(filepath.Join(library.Folder, constants.LIBRARY_FOLDER_ARCH)); err == nil && stat.IsDir() {
				return utils.ErrorfWithLogger(logger, constants.MSG_ARCH_FOLDER_NOT_SUPPORTED)
			}
			for _, propName := range LIBRARY_MANDATORY_PROPERTIES {
				if _, ok := library.Properties[propName]; !ok {
					return utils.ErrorfWithLogger(logger, constants.MSG_PROP_IN_LIBRARY, propName, library.Folder)
				}
			}
			if library.Layout == types.LIBRARY_RECURSIVE {
				if stat, err := os.Stat(filepath.Join(library.Folder, constants.LIBRARY_FOLDER_UTILITY)); err == nil && stat.IsDir() {
					return utils.ErrorfWithLogger(logger, constants.MSG_LIBRARY_CAN_USE_SRC_AND_UTILITY_FOLDERS, library.Folder)
				}
			}
		}
	}

	return nil
}
func (s *GCCMinusMOutputParser) Run(context map[string]interface{}) error {
	output := context[constants.CTX_GCC_MINUS_M_OUTPUT].(string)

	rows := strings.Split(output, "\n")
	includes := make([]string, 0)
	if len(rows) > 2 {
		for _, row := range rows[2:] {
			if !strings.HasPrefix(row, constants.SPACE) {
				row = strings.TrimSpace(row)
				if row != constants.EMPTY_STRING {
					row = strings.TrimSuffix(row, ":")
					row = strings.Replace(row, "\\ ", " ", -1)
					includes = append(includes, row)
				}
			}
		}
	}

	if !utils.MapHas(context, constants.CTX_INCLUDES) {
		context[constants.CTX_INCLUDES] = includes
		return nil
	}

	context[constants.CTX_INCLUDES] = utils.AddStringsToStringsSet(context[constants.CTX_INCLUDES].([]string), includes)

	return nil
}
func (s *LoadVIDPIDSpecificProperties) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_VIDPID) {
		return nil
	}

	vidPid := context[constants.CTX_VIDPID].(string)
	vidPid = strings.ToLower(vidPid)
	vidPidParts := strings.Split(vidPid, "_")
	vid := vidPidParts[0]
	pid := vidPidParts[1]

	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(props.PropertiesMap)
	VIDPIDIndex, err := findVIDPIDIndex(buildProperties, vid, pid)
	if err != nil {
		return utils.WrapError(err)
	}
	if VIDPIDIndex < 0 {
		return nil
	}

	vidPidSpecificProperties := buildProperties.SubTree(constants.BUILD_PROPERTIES_VID).SubTree(strconv.Itoa(VIDPIDIndex))
	buildProperties.Merge(vidPidSpecificProperties)

	return nil
}
func (s *IncludesFinderWithGCC) Run(context map[string]interface{}) error {
	buildProperties := utils.GetMapStringStringOrDefault(context, constants.CTX_BUILD_PROPERTIES)
	sketch := context[constants.CTX_SKETCH].(*types.Sketch)
	sketchBuildPath := context[constants.CTX_SKETCH_BUILD_PATH].(string)
	verbose := context[constants.CTX_VERBOSE].(bool)
	logger := context[constants.CTX_LOGGER].(i18n.Logger)

	includesParams := ""
	if utils.MapHas(context, constants.CTX_INCLUDE_FOLDERS) {
		includes := context[constants.CTX_INCLUDE_FOLDERS].([]string)
		includes = utils.Map(includes, utils.WrapWithHyphenI)
		includesParams = strings.Join(includes, " ")
	}

	properties := utils.MergeMapsOfStrings(make(map[string]string), buildProperties)
	properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp")
	properties[constants.BUILD_PROPERTIES_INCLUDES] = includesParams
	builder_utils.RemoveHyphenMDDFlagFromGCCCommandLine(properties)

	output, err := builder_utils.ExecRecipe(properties, constants.RECIPE_PREPROC_INCLUDES, true, verbose, false, logger)
	if err != nil {
		return utils.WrapError(err)
	}

	context[constants.CTX_GCC_MINUS_M_OUTPUT] = string(output)

	return nil
}
func (s *AddAdditionalEntriesToContext) Run(context map[string]interface{}) error {
	if utils.MapHas(context, constants.CTX_BUILD_PATH) {
		buildPath := context[constants.CTX_BUILD_PATH].(string)
		preprocPath, err := filepath.Abs(filepath.Join(buildPath, constants.FOLDER_PREPROC))
		if err != nil {
			return utils.WrapError(err)
		}
		sketchBuildPath, err := filepath.Abs(filepath.Join(buildPath, constants.FOLDER_SKETCH))
		if err != nil {
			return utils.WrapError(err)
		}
		librariesBuildPath, err := filepath.Abs(filepath.Join(buildPath, constants.FOLDER_LIBRARIES))
		if err != nil {
			return utils.WrapError(err)
		}
		coreBuildPath, err := filepath.Abs(filepath.Join(buildPath, constants.FOLDER_CORE))
		if err != nil {
			return utils.WrapError(err)
		}

		context[constants.CTX_PREPROC_PATH] = preprocPath
		context[constants.CTX_SKETCH_BUILD_PATH] = sketchBuildPath
		context[constants.CTX_LIBRARIES_BUILD_PATH] = librariesBuildPath
		context[constants.CTX_CORE_BUILD_PATH] = coreBuildPath
	}

	if !utils.MapHas(context, constants.CTX_WARNINGS_LEVEL) {
		context[constants.CTX_WARNINGS_LEVEL] = DEFAULT_WARNINGS_LEVEL
	}

	if !utils.MapHas(context, constants.CTX_VERBOSE) {
		context[constants.CTX_VERBOSE] = false
	}

	if !utils.MapHas(context, constants.CTX_DEBUG_LEVEL) {
		context[constants.CTX_DEBUG_LEVEL] = DEFAULT_DEBUG_LEVEL
	}

	if !utils.MapHas(context, constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH) {
		context[constants.CTX_LIBRARY_DISCOVERY_RECURSION_DEPTH] = DEFAULT_LIBRARY_DISCOVERY_RECURSION_DEPTH
	}

	return nil
}
func (s *IncludesToIncludeFolders) Run(context map[string]interface{}) error {
	includes := []string{}
	if utils.MapHas(context, constants.CTX_INCLUDES) {
		includes = context[constants.CTX_INCLUDES].([]string)
	}
	headerToLibraries := make(map[string][]*types.Library)
	if utils.MapHas(context, constants.CTX_HEADER_TO_LIBRARIES) {
		headerToLibraries = context[constants.CTX_HEADER_TO_LIBRARIES].(map[string][]*types.Library)
	}

	platform := context[constants.CTX_TARGET_PLATFORM].(*types.Platform)
	actualPlatform := context[constants.CTX_ACTUAL_PLATFORM].(*types.Platform)
	libraryResolutionResults := context[constants.CTX_LIBRARY_RESOLUTION_RESULTS].(map[string]types.LibraryResolutionResult)

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

	foldersWithSources := context[constants.CTX_FOLDERS_WITH_SOURCES_QUEUE].(*types.UniqueSourceFolderQueue)

	for _, newlyImportedLibrary := range newlyImportedLibraries {
		if !sliceContainsLibrary(importedLibraries, newlyImportedLibrary) {
			importedLibraries = append(importedLibraries, newlyImportedLibrary)
			sourceFolders := types.LibraryToSourceFolder(newlyImportedLibrary)
			for _, sourceFolder := range sourceFolders {
				foldersWithSources.Push(sourceFolder)
			}
		}
	}

	context[constants.CTX_IMPORTED_LIBRARIES] = importedLibraries

	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(props.PropertiesMap)
	verbose := context[constants.CTX_VERBOSE].(bool)
	includeFolders := resolveIncludeFolders(newlyImportedLibraries, buildProperties, verbose)
	context[constants.CTX_INCLUDE_FOLDERS] = includeFolders

	return nil
}
func TestLoadPreviousBuildOptionsMapMissingFile(t *testing.T) {
	context := make(map[string]interface{})

	buildPath := SetupBuildPath(t, context)
	defer os.RemoveAll(buildPath)

	command := builder.LoadPreviousBuildOptionsMap{}
	err := command.Run(context)
	NoError(t, err)

	require.False(t, utils.MapHas(context, constants.CTX_BUILD_OPTIONS_PREVIOUS_JSON))
}
func (s *FailIfBuildPathEqualsSketchPath) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_BUILD_PATH) || !utils.MapHas(context, constants.CTX_SKETCH_LOCATION) {
		return nil
	}

	buildPath, err := filepath.Abs(context[constants.CTX_BUILD_PATH].(string))
	if err != nil {
		return utils.WrapError(err)
	}

	sketchPath, err := filepath.Abs(context[constants.CTX_SKETCH_LOCATION].(string))
	if err != nil {
		return utils.WrapError(err)
	}
	sketchPath = filepath.Dir(sketchPath)

	if buildPath == sketchPath {
		return utils.Errorf(context, constants.MSG_SKETCH_CANT_BE_IN_BUILDPATH)
	}

	return nil
}
func (s *SetCustomBuildProperties) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_CUSTOM_BUILD_PROPERTIES) {
		return nil
	}

	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(map[string]string)
	customBuildProperties := props.LoadFromSlice(context[constants.CTX_CUSTOM_BUILD_PROPERTIES].([]string))

	for key, value := range customBuildProperties {
		buildProperties[key] = value
	}

	return nil
}
func (s *ContainerFindIncludes) Run(context map[string]interface{}) error {
	err := runCommand(context, &IncludesToIncludeFolders{})
	if err != nil {
		return utils.WrapError(err)
	}

	sketchBuildPath := context[constants.CTX_SKETCH_BUILD_PATH].(string)
	sketch := context[constants.CTX_SKETCH].(*types.Sketch)
	err = findIncludesUntilDone(context, filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp"))
	if err != nil {
		return utils.WrapError(err)
	}

	foldersWithSources := context[constants.CTX_FOLDERS_WITH_SOURCES_QUEUE].(*types.UniqueSourceFolderQueue)
	foldersWithSources.Push(types.SourceFolder{Folder: context[constants.CTX_SKETCH_BUILD_PATH].(string), Recurse: true})
	if utils.MapHas(context, constants.CTX_IMPORTED_LIBRARIES) {
		for _, library := range context[constants.CTX_IMPORTED_LIBRARIES].([]*types.Library) {
			sourceFolders := types.LibraryToSourceFolder(library)
			for _, sourceFolder := range sourceFolders {
				foldersWithSources.Push(sourceFolder)
			}
		}
	}

	err = runCommand(context, &CollectAllSourceFilesFromFoldersWithSources{})
	if err != nil {
		return utils.WrapError(err)
	}

	sourceFilePaths := context[constants.CTX_COLLECTED_SOURCE_FILES_QUEUE].(*types.UniqueStringQueue)

	for !sourceFilePaths.Empty() {
		err = findIncludesUntilDone(context, sourceFilePaths.Pop().(string))
		if err != nil {
			return utils.WrapError(err)
		}
		err := runCommand(context, &CollectAllSourceFilesFromFoldersWithSources{})
		if err != nil {
			return utils.WrapError(err)
		}
	}

	err = runCommand(context, &FailIfImportedLibraryIsWrong{})
	if err != nil {
		return utils.WrapError(err)
	}

	return nil
}
func (s *SetCustomBuildProperties) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_CUSTOM_BUILD_PROPERTIES) {
		return nil
	}

	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	buildProperties := context[constants.CTX_BUILD_PROPERTIES].(props.PropertiesMap)
	customBuildProperties, err := props.LoadFromSlice(context[constants.CTX_CUSTOM_BUILD_PROPERTIES].([]string), logger)
	if err != nil {
		return utils.WrapError(err)
	}

	for key, value := range customBuildProperties {
		buildProperties[key] = value
	}

	return nil
}
Esempio n. 24
0
func (s *PrototypesAdder) Run(context map[string]interface{}) error {
	debugOutput := context[constants.CTX_DEBUG_PREPROCESSOR] != nil
	source := context[constants.CTX_SOURCE].(string)

	source = strings.Replace(source, "\r\n", "\n", -1)
	source = strings.Replace(source, "\r", "\n", -1)

	sourceRows := strings.Split(source, "\n")

	if !utils.MapHas(context, constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES) {
		return nil
	}

	firstFunctionLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int)
	if isFirstFunctionOutsideOfSource(firstFunctionLine, sourceRows) {
		return nil
	}

	insertionLine := firstFunctionLine + context[constants.CTX_LINE_OFFSET].(int) - 1
	firstFunctionChar := len(strings.Join(sourceRows[:insertionLine], "\n")) + 1
	prototypeSection := composePrototypeSection(firstFunctionLine, context[constants.CTX_PROTOTYPES].([]*types.Prototype))
	context[constants.CTX_PROTOTYPE_SECTION] = prototypeSection
	source = source[:firstFunctionChar] + prototypeSection + source[firstFunctionChar:]

	if debugOutput {
		fmt.Println("#PREPROCESSED SOURCE")
		prototypesRows := strings.Split(prototypeSection, "\n")
		prototypesRows = prototypesRows[:len(prototypesRows)-1]
		for i := 0; i < len(sourceRows)+len(prototypesRows); i++ {
			if i < insertionLine {
				fmt.Printf("   |%s\n", sourceRows[i])
			} else if i < insertionLine+len(prototypesRows) {
				fmt.Printf("PRO|%s\n", prototypesRows[i-insertionLine])
			} else {
				fmt.Printf("   |%s\n", sourceRows[i-len(prototypesRows)])
			}
		}
		fmt.Println("#END OF PREPROCESSED SOURCE")
	}
	context[constants.CTX_SOURCE] = source

	return nil
}
func (s *CreateBuildOptionsMap) Run(context map[string]interface{}) error {
	buildOptions := make(map[string]string)

	buildOptionsMapKeys := []string{
		constants.CTX_HARDWARE_FOLDERS,
		constants.CTX_TOOLS_FOLDERS,
		constants.CTX_BUILT_IN_LIBRARIES_FOLDERS,
		constants.CTX_OTHER_LIBRARIES_FOLDERS,
		constants.CTX_FQBN,
		constants.CTX_SKETCH_LOCATION,
		constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION,
		constants.CTX_CUSTOM_BUILD_PROPERTIES,
	}

	for _, key := range buildOptionsMapKeys {
		if utils.MapHas(context, key) {
			originalValue := context[key]
			value := constants.EMPTY_STRING
			kindOfValue := reflect.TypeOf(originalValue).Kind()
			if kindOfValue == reflect.Slice {
				value = strings.Join(originalValue.([]string), ",")
			} else if kindOfValue == reflect.String {
				value = originalValue.(string)
			} else {
				return utils.Errorf(context, constants.MSG_UNHANDLED_TYPE_IN_CONTEXT, kindOfValue.String(), key)
			}

			buildOptions[key] = value
		}
	}

	context[constants.CTX_BUILD_OPTIONS] = buildOptions

	bytes, err := json.MarshalIndent(buildOptions, "", "  ")
	if err != nil {
		return utils.WrapError(err)
	}

	context[constants.CTX_BUILD_OPTIONS_JSON] = string(bytes)

	return nil
}
Esempio n. 26
0
func (s *SketchLoader) Run(context map[string]interface{}) error {
	if !utils.MapHas(context, constants.CTX_SKETCH_LOCATION) {
		return nil
	}

	sketchLocation := context[constants.CTX_SKETCH_LOCATION].(string)

	sketchLocation, err := filepath.Abs(sketchLocation)
	if err != nil {
		return utils.WrapError(err)
	}
	mainSketchStat, err := os.Stat(sketchLocation)
	if err != nil {
		return utils.WrapError(err)
	}
	if mainSketchStat.IsDir() {
		sketchLocation = filepath.Join(sketchLocation, mainSketchStat.Name()+".ino")
	}
	context[constants.CTX_SKETCH_LOCATION] = sketchLocation

	allSketchFilePaths, err := collectAllSketchFiles(filepath.Dir(sketchLocation))
	if err != nil {
		return utils.WrapError(err)
	}

	if !utils.SliceContains(allSketchFilePaths, sketchLocation) {
		return utils.Errorf(context, constants.MSG_CANT_FIND_SKETCH_IN_PATH, sketchLocation, filepath.Dir(sketchLocation))
	}

	logger := context[constants.CTX_LOGGER].(i18n.Logger)
	sketch, err := makeSketch(sketchLocation, allSketchFilePaths, logger)
	if err != nil {
		return utils.WrapError(err)
	}

	context[constants.CTX_SKETCH_LOCATION] = sketchLocation
	context[constants.CTX_SKETCH] = sketch

	return nil
}
Esempio n. 27
0
func (s *PrototypesAdder) Run(context map[string]interface{}) error {
	source := context[constants.CTX_SOURCE].(string)
	sourceRows := strings.Split(source, "\n")

	if !utils.MapHas(context, constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES) {
		return nil
	}

	firstFunctionLine := context[constants.CTX_LINE_WHERE_TO_INSERT_PROTOTYPES].(int)
	if firstFunctionOutsideOfSource(firstFunctionLine, sourceRows) {
		return nil
	}

	firstFunctionChar := len(strings.Join(sourceRows[:firstFunctionLine+context[constants.CTX_LINE_OFFSET].(int)-1], "\n")) + 1
	prototypeSection := composePrototypeSection(firstFunctionLine, context[constants.CTX_PROTOTYPES].([]*types.Prototype))
	context[constants.CTX_PROTOTYPE_SECTION] = prototypeSection
	source = source[:firstFunctionChar] + prototypeSection + source[firstFunctionChar:]

	context[constants.CTX_SOURCE] = source

	return nil
}
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
}
Esempio n. 29
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
}
func (s *SetupBuildProperties) Run(context map[string]interface{}) error {
	packages := context[constants.CTX_HARDWARE].(map[string]*types.Package)

	targetPlatform := context[constants.CTX_TARGET_PLATFORM].(*types.Platform)
	actualPlatform := context[constants.CTX_ACTUAL_PLATFORM].(*types.Platform)
	targetBoard := context[constants.CTX_TARGET_BOARD].(*types.Board)

	buildProperties := make(map[string]string)
	utils.MergeMapsOfStrings(buildProperties, actualPlatform.Properties)
	utils.MergeMapsOfStrings(buildProperties, targetPlatform.Properties)
	utils.MergeMapsOfStrings(buildProperties, targetBoard.Properties)

	if utils.MapHas(context, constants.CTX_BUILD_PATH) {
		buildProperties[constants.BUILD_PROPERTIES_BUILD_PATH] = context[constants.CTX_BUILD_PATH].(string)
	}
	if utils.MapHas(context, constants.CTX_SKETCH) {
		buildProperties[constants.BUILD_PROPERTIES_BUILD_PROJECT_NAME] = filepath.Base(context[constants.CTX_SKETCH].(*types.Sketch).MainFile.Name)
	}
	buildProperties[constants.BUILD_PROPERTIES_BUILD_ARCH] = strings.ToUpper(targetPlatform.PlatformId)

	if buildProperties[constants.BUILD_PROPERTIES_COMPILER_PATH] == constants.EMPTY_STRING {
		return utils.Errorf(context, constants.MSG_MISSING_COMPILER_PATH)
	}

	buildProperties[constants.BUILD_PROPERTIES_BUILD_CORE] = context[constants.CTX_BUILD_CORE].(string)
	buildProperties[constants.BUILD_PROPERTIES_BUILD_CORE_PATH] = filepath.Join(actualPlatform.Folder, constants.FOLDER_CORES, buildProperties[constants.BUILD_PROPERTIES_BUILD_CORE])
	buildProperties[constants.BUILD_PROPERTIES_BUILD_SYSTEM_PATH] = filepath.Join(actualPlatform.Folder, constants.FOLDER_SYSTEM)
	buildProperties[constants.BUILD_PROPERTIES_RUNTIME_PLATFORM_PATH] = actualPlatform.Folder
	buildProperties[constants.BUILD_PROPERTIES_RUNTIME_HARDWARE_PATH] = filepath.Join(actualPlatform.Folder, "..")
	buildProperties[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION].(string)
	buildProperties[constants.IDE_VERSION] = context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION].(string)
	buildProperties[constants.BUILD_PROPERTIES_RUNTIME_OS] = utils.PrettyOSName()

	variant := buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT]
	if variant == constants.EMPTY_STRING {
		buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT_PATH] = constants.EMPTY_STRING
	} else {
		var variantPlatform *types.Platform
		variantParts := strings.Split(variant, ":")
		if len(variantParts) > 1 {
			variantPlatform = packages[variantParts[0]].Platforms[targetPlatform.PlatformId]
			variant = variantParts[1]
		} else {
			variantPlatform = targetPlatform
		}
		buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT_PATH] = filepath.Join(variantPlatform.Folder, constants.FOLDER_VARIANTS, variant)
	}

	tools := context[constants.CTX_TOOLS].([]*types.Tool)
	for _, tool := range tools {
		buildProperties[constants.BUILD_PROPERTIES_RUNTIME_TOOLS_PREFIX+tool.Name+constants.BUILD_PROPERTIES_RUNTIME_TOOLS_SUFFIX] = tool.Folder
		buildProperties[constants.BUILD_PROPERTIES_RUNTIME_TOOLS_PREFIX+tool.Name+"-"+tool.Version+constants.BUILD_PROPERTIES_RUNTIME_TOOLS_SUFFIX] = tool.Folder
	}

	if !utils.MapStringStringHas(buildProperties, constants.BUILD_PROPERTIES_SOFTWARE) {
		buildProperties[constants.BUILD_PROPERTIES_SOFTWARE] = DEFAULT_SOFTWARE
	}

	if utils.MapHas(context, constants.CTX_SKETCH_LOCATION) {
		sourcePath, err := filepath.Abs(context[constants.CTX_SKETCH_LOCATION].(string))
		if err != nil {
			return err
		}
		buildProperties[constants.BUILD_PROPERTIES_SOURCE_PATH] = sourcePath
	}

	context[constants.CTX_BUILD_PROPERTIES] = buildProperties

	return nil
}