func (s *IncludesToIncludeFolders) Run(ctx *types.Context) error {
	includes := ctx.Includes
	headerToLibraries := ctx.HeaderToLibraries

	platform := ctx.TargetPlatform
	actualPlatform := ctx.ActualPlatform
	libraryResolutionResults := ctx.LibrariesResolutionResults
	importedLibraries := ctx.ImportedLibraries

	newlyImportedLibraries, err := resolveLibraries(includes, headerToLibraries, importedLibraries, []*types.Platform{actualPlatform, platform}, libraryResolutionResults)
	if err != nil {
		return i18n.WrapError(err)
	}

	foldersWithSources := ctx.FoldersWithSourceFiles

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

	ctx.ImportedLibraries = importedLibraries
	ctx.IncludeFolders = resolveIncludeFolders(newlyImportedLibraries, ctx.BuildProperties, ctx.Verbose)

	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 *ContainerFindIncludes) Run(ctx *types.Context) error {
	err := runCommand(ctx, &IncludesToIncludeFolders{})
	if err != nil {
		return i18n.WrapError(err)
	}

	sketchBuildPath := ctx.SketchBuildPath
	sketch := ctx.Sketch
	err = findIncludesUntilDone(ctx, filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp"))
	if err != nil {
		return i18n.WrapError(err)
	}

	foldersWithSources := ctx.FoldersWithSourceFiles
	foldersWithSources.Push(types.SourceFolder{Folder: ctx.SketchBuildPath, Recurse: true})
	if len(ctx.ImportedLibraries) > 0 {
		for _, library := range ctx.ImportedLibraries {
			sourceFolders := types.LibraryToSourceFolder(library)
			for _, sourceFolder := range sourceFolders {
				foldersWithSources.Push(sourceFolder)
			}
		}
	}

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

	sourceFilePaths := ctx.CollectedSourceFiles

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

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

	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 findIncludesUntilDone(ctx *types.Context, cache *includeCache, sourceFile types.SourceFile) error {
	sourcePath := sourceFile.SourcePath(ctx)
	targetFilePath := utils.NULLFile()

	// TODO: This should perhaps also compare against the
	// include.cache file timestamp. Now, it only checks if the file
	// changed after the object file was generated, but if it
	// changed between generating the cache and the object file,
	// this could show the file as unchanged when it really is
	// changed. Changing files during a build isn't really
	// supported, but any problems from it should at least be
	// resolved when doing another build, which is not currently the
	// case.
	// TODO: This reads the dependency file, but the actual building
	// does it again. Should the result be somehow cached? Perhaps
	// remove the object file if it is found to be stale?
	unchanged, err := builder_utils.ObjFileIsUpToDate(sourcePath, sourceFile.ObjectPath(ctx), sourceFile.DepfilePath(ctx))
	if err != nil {
		return i18n.WrapError(err)
	}

	first := true
	for {
		var include string
		cache.ExpectFile(sourcePath)

		includes := ctx.IncludeFolders
		if library, ok := sourceFile.Origin.(*types.Library); ok && library.UtilityFolder != "" {
			includes = append(includes, library.UtilityFolder)
		}
		if unchanged && cache.valid {
			include = cache.Next().Include
			if first && ctx.Verbose {
				ctx.GetLogger().Println(constants.LOG_LEVEL_INFO, constants.MSG_USING_CACHED_INCLUDES, sourcePath)
			}
		} else {
			commands := []types.Command{
				&GCCPreprocRunnerForDiscoveringIncludes{SourceFilePath: sourcePath, TargetFilePath: targetFilePath, Includes: includes},
				&IncludesFinderWithRegExp{Source: &ctx.SourceGccMinusE},
			}
			for _, command := range commands {
				err := runCommand(ctx, command)
				if err != nil {
					return i18n.WrapError(err)
				}
			}
			include = ctx.IncludeJustFound
		}

		if include == "" {
			// No missing includes found, we're done
			cache.ExpectEntry(sourcePath, "", "")
			return nil
		}

		library := ResolveLibrary(ctx, include)
		if library == nil {
			// Library could not be resolved, show error
			err := runCommand(ctx, &GCCPreprocRunner{SourceFilePath: sourcePath, TargetFileName: constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E, Includes: includes})
			return i18n.WrapError(err)
		}

		// Add this library to the list of libraries, the
		// include path and queue its source files for further
		// include scanning
		ctx.ImportedLibraries = append(ctx.ImportedLibraries, library)
		appendIncludeFolder(ctx, cache, sourcePath, include, library.SrcFolder)
		sourceFolders := types.LibraryToSourceFolder(library)
		for _, sourceFolder := range sourceFolders {
			queueSourceFilesFromFolder(ctx, ctx.CollectedSourceFiles, library, sourceFolder.Folder, sourceFolder.Recurse)
		}
		first = false
	}
}