func (s *ToolsLoader) Run(ctx *types.Context) error { folders := ctx.ToolsFolders tools := []*types.Tool{} for _, folder := range folders { builtinToolsVersionsFile, err := findBuiltinToolsVersionsFile(folder) if err != nil { return i18n.WrapError(err) } if builtinToolsVersionsFile != constants.EMPTY_STRING { err = loadToolsFrom(&tools, builtinToolsVersionsFile) if err != nil { return i18n.WrapError(err) } } else { subfolders, err := collectAllToolsFolders(folder) if err != nil { return i18n.WrapError(err) } for _, subfolder := range subfolders { err = loadToolsFromFolderStructure(&tools, subfolder) if err != nil { return i18n.WrapError(err) } } } } ctx.Tools = tools return nil }
func loadToolsFrom(tools *[]*types.Tool, builtinToolsVersionsFilePath string) error { rows, err := utils.ReadFileToRows(builtinToolsVersionsFilePath) if err != nil { return i18n.WrapError(err) } folder, err := filepath.Abs(filepath.Dir(builtinToolsVersionsFilePath)) if err != nil { return i18n.WrapError(err) } for _, row := range rows { row = strings.TrimSpace(row) if row != constants.EMPTY_STRING { rowParts := strings.Split(row, "=") toolName := strings.Split(rowParts[0], ".")[1] toolVersion := rowParts[1] if !toolsSliceContains(tools, toolName, toolVersion) { *tools = append(*tools, &types.Tool{Name: toolName, Version: toolVersion, Folder: folder}) } } } return nil }
func collectAllToolsFolders(from string) ([]string, error) { folders := []string{} walkFunc := func(currentPath string, info os.FileInfo, err error) error { if err != nil { return nil } if !info.IsDir() { return nil } rel, err := filepath.Rel(from, currentPath) if err != nil { return i18n.WrapError(err) } depth := len(strings.Split(rel, string(os.PathSeparator))) if info.Name() == constants.FOLDER_TOOLS && depth == 2 { folders = append(folders, currentPath) } else if depth > 2 { return filepath.SkipDir } return nil } err := gohasissues.Walk(from, walkFunc) if len(folders) == 0 { folders = append(folders, from) } return folders, i18n.WrapError(err) }
func (s *SketchBuilder) Run(ctx *types.Context) error { sketchBuildPath := ctx.SketchBuildPath buildProperties := ctx.BuildProperties includes := ctx.IncludeFolders includes = utils.Map(includes, utils.WrapWithHyphenI) verbose := ctx.Verbose warningsLevel := ctx.WarningsLevel logger := ctx.GetLogger() err := utils.EnsureFolderExists(sketchBuildPath) if err != nil { return i18n.WrapError(err) } var objectFiles []string objectFiles, err = builder_utils.CompileFiles(objectFiles, sketchBuildPath, false, sketchBuildPath, buildProperties, includes, verbose, warningsLevel, logger) if err != nil { return i18n.WrapError(err) } // The "src/" subdirectory of a sketch is compiled recursively sketchSrcPath := filepath.Join(sketchBuildPath, constants.SKETCH_FOLDER_SRC) if info, err := os.Stat(sketchSrcPath); err == nil && info.IsDir() { objectFiles, err = builder_utils.CompileFiles(objectFiles, sketchSrcPath, true, sketchSrcPath, buildProperties, includes, verbose, warningsLevel, logger) if err != nil { return i18n.WrapError(err) } } ctx.SketchObjectFiles = objectFiles return nil }
func findFilesInFolder(sourcePath string, extension string, recurse bool) ([]string, error) { files, err := utils.ReadDirFiltered(sourcePath, utils.FilterFilesWithExtension(extension)) if err != nil { return nil, i18n.WrapError(err) } var sources []string for _, file := range files { sources = append(sources, filepath.Join(sourcePath, file.Name())) } if recurse { folders, err := utils.ReadDirFiltered(sourcePath, utils.FilterDirs) if err != nil { return nil, i18n.WrapError(err) } for _, folder := range folders { otherSources, err := findFilesInFolder(filepath.Join(sourcePath, folder.Name()), extension, recurse) if err != nil { return nil, i18n.WrapError(err) } sources = append(sources, otherSources...) } } return sources, nil }
func findIncludesUntilDone(ctx *types.Context, sourceFilePath string) error { targetFilePath := utils.NULLFile() importedLibraries := ctx.ImportedLibraries done := false for !done { commands := []types.Command{ &GCCPreprocRunnerForDiscoveringIncludes{SourceFilePath: sourceFilePath, TargetFilePath: targetFilePath}, &IncludesFinderWithRegExp{Source: &ctx.SourceGccMinusE}, &IncludesToIncludeFolders{}, } for _, command := range commands { err := runCommand(ctx, command) if err != nil { return i18n.WrapError(err) } } if len(ctx.IncludesJustFound) == 0 { done = true } else if len(ctx.ImportedLibraries) == len(importedLibraries) { err := runCommand(ctx, &GCCPreprocRunner{TargetFileName: constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E}) return i18n.WrapError(err) } importedLibraries = ctx.ImportedLibraries ctx.IncludesJustFound = []string{} } return nil }
func (s *Linker) Run(ctx *types.Context) error { objectFilesSketch := ctx.SketchObjectFiles objectFilesLibraries := ctx.LibrariesObjectFiles objectFilesCore := ctx.CoreObjectsFiles var objectFiles []string objectFiles = append(objectFiles, objectFilesSketch...) objectFiles = append(objectFiles, objectFilesLibraries...) objectFiles = append(objectFiles, objectFilesCore...) coreArchiveFilePath := ctx.CoreArchiveFilePath buildPath := ctx.BuildPath coreDotARelPath, err := filepath.Rel(buildPath, coreArchiveFilePath) if err != nil { return i18n.WrapError(err) } buildProperties := ctx.BuildProperties verbose := ctx.Verbose warningsLevel := ctx.WarningsLevel logger := ctx.GetLogger() err = link(objectFiles, coreDotARelPath, coreArchiveFilePath, buildProperties, verbose, warningsLevel, logger) if err != nil { return i18n.WrapError(err) } return nil }
func (s *UnusedCompiledLibrariesRemover) Run(ctx *types.Context) error { librariesBuildPath := ctx.LibrariesBuildPath _, err := os.Stat(librariesBuildPath) if err != nil && os.IsNotExist(err) { return nil } libraryNames := toLibraryNames(ctx.ImportedLibraries) files, err := ioutil.ReadDir(librariesBuildPath) if err != nil { return i18n.WrapError(err) } for _, file := range files { if file.IsDir() { if !utils.SliceContains(libraryNames, file.Name()) { err := os.RemoveAll(filepath.Join(librariesBuildPath, file.Name())) if err != nil { return i18n.WrapError(err) } } } } return nil }
func (s *CTagsRunner) Run(ctx *types.Context) error { buildProperties := ctx.BuildProperties ctagsTargetFilePath := ctx.CTagsTargetFile logger := ctx.GetLogger() properties := buildProperties.Clone() properties.Merge(buildProperties.SubTree(constants.BUILD_PROPERTIES_TOOLS_KEY).SubTree(constants.CTAGS)) properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = ctagsTargetFilePath pattern := properties[constants.BUILD_PROPERTIES_PATTERN] if pattern == constants.EMPTY_STRING { return i18n.ErrorfWithLogger(logger, constants.MSG_PATTERN_MISSING, constants.CTAGS) } commandLine := properties.ExpandPropsInString(pattern) command, err := utils.PrepareCommand(commandLine, logger) if err != nil { return i18n.WrapError(err) } verbose := ctx.Verbose if verbose { fmt.Println(commandLine) } sourceBytes, err := command.Output() if err != nil { return i18n.WrapError(err) } ctx.CTagsOutput = string(sourceBytes) return nil }
func compileCore(buildPath string, buildProperties props.PropertiesMap, verbose bool, warningsLevel string, logger i18n.Logger) (string, []string, error) { coreFolder := buildProperties[constants.BUILD_PROPERTIES_BUILD_CORE_PATH] variantFolder := buildProperties[constants.BUILD_PROPERTIES_BUILD_VARIANT_PATH] includes := []string{} includes = append(includes, coreFolder) if variantFolder != constants.EMPTY_STRING { includes = append(includes, variantFolder) } includes = utils.Map(includes, utils.WrapWithHyphenI) var err error variantObjectFiles := []string{} if variantFolder != constants.EMPTY_STRING { variantObjectFiles, err = builder_utils.CompileFiles(variantObjectFiles, variantFolder, true, buildPath, buildProperties, includes, verbose, warningsLevel, logger) if err != nil { return "", nil, i18n.WrapError(err) } } coreObjectFiles, err := builder_utils.CompileFiles([]string{}, coreFolder, true, buildPath, buildProperties, includes, verbose, warningsLevel, logger) if err != nil { return "", nil, i18n.WrapError(err) } archiveFile, err := builder_utils.ArchiveCompiledFiles(buildPath, "core.a", coreObjectFiles, buildProperties, verbose, logger) if err != nil { return "", nil, i18n.WrapError(err) } return archiveFile, variantObjectFiles, nil }
func loadBoards(boards map[string]*types.Board, packageId string, platformId string, folder string, logger i18n.Logger) error { properties, err := props.Load(filepath.Join(folder, constants.FILE_BOARDS_TXT), logger) if err != nil { return i18n.WrapError(err) } localProperties, err := props.SafeLoad(filepath.Join(folder, constants.FILE_BOARDS_LOCAL_TXT), logger) if err != nil { return i18n.WrapError(err) } properties = properties.Merge(localProperties) propertiesByBoardId := properties.FirstLevelOf() delete(propertiesByBoardId, constants.BOARD_PROPERTIES_MENU) for boardId, properties := range propertiesByBoardId { properties[constants.ID] = boardId board := getOrCreateBoard(boards, boardId) board.Properties.Merge(properties) boards[boardId] = board } return nil }
func compileFileWithRecipe(sourcePath string, source string, buildPath string, buildProperties props.PropertiesMap, includes []string, recipe string, verbose bool, warningsLevel string, logger i18n.Logger) (string, error) { properties := buildProperties.Clone() properties[constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS] = properties[constants.BUILD_PROPERTIES_COMPILER_WARNING_FLAGS+"."+warningsLevel] properties[constants.BUILD_PROPERTIES_INCLUDES] = strings.Join(includes, constants.SPACE) properties[constants.BUILD_PROPERTIES_SOURCE_FILE] = source relativeSource, err := filepath.Rel(sourcePath, source) if err != nil { return "", i18n.WrapError(err) } properties[constants.BUILD_PROPERTIES_OBJECT_FILE] = filepath.Join(buildPath, relativeSource+".o") err = utils.EnsureFolderExists(filepath.Dir(properties[constants.BUILD_PROPERTIES_OBJECT_FILE])) if err != nil { return "", i18n.WrapError(err) } objIsUpToDate, err := ObjFileIsUpToDate(properties[constants.BUILD_PROPERTIES_SOURCE_FILE], properties[constants.BUILD_PROPERTIES_OBJECT_FILE], filepath.Join(buildPath, relativeSource+".d")) if err != nil { return "", i18n.WrapError(err) } if !objIsUpToDate { _, err = ExecRecipe(properties, recipe, false, verbose, verbose, logger) if err != nil { return "", i18n.WrapError(err) } } else if verbose { logger.Println(constants.LOG_LEVEL_INFO, constants.MSG_USING_PREVIOUS_COMPILED_FILE, properties[constants.BUILD_PROPERTIES_OBJECT_FILE]) } return properties[constants.BUILD_PROPERTIES_OBJECT_FILE], nil }
func PrepareCommandForRecipe(properties props.PropertiesMap, recipe string, removeUnsetProperties bool, echoCommandLine bool, echoOutput bool, logger i18n.Logger) (*exec.Cmd, error) { pattern := properties[recipe] if pattern == constants.EMPTY_STRING { return nil, i18n.ErrorfWithLogger(logger, constants.MSG_PATTERN_MISSING, recipe) } var err error commandLine := properties.ExpandPropsInString(pattern) if removeUnsetProperties { commandLine, err = props.DeleteUnexpandedPropsFromString(commandLine) if err != nil { return nil, i18n.WrapError(err) } } command, err := utils.PrepareCommand(commandLine, logger) if err != nil { return nil, i18n.WrapError(err) } if echoCommandLine { fmt.Println(commandLine) } return command, nil }
func downloadAndUnpackLibrary(library Library, url string, targetPath string) error { if libraryAlreadyDownloadedAndUnpacked(targetPath, library) { return nil } targetPath, err := filepath.Abs(targetPath) if err != nil { return i18n.WrapError(err) } unpackFolder, files, err := downloadAndUnpack(url) if err != nil { return i18n.WrapError(err) } defer os.RemoveAll(unpackFolder) _, err = os.Stat(filepath.Join(targetPath, strings.Replace(library.Name, " ", "_", -1))) if err == nil { err = os.RemoveAll(filepath.Join(targetPath, strings.Replace(library.Name, " ", "_", -1))) if err != nil { return i18n.WrapError(err) } } err = copyRecursive(filepath.Join(unpackFolder, files[0].Name()), filepath.Join(targetPath, strings.Replace(library.Name, " ", "_", -1))) if err != nil { return i18n.WrapError(err) } return nil }
func downloadToolsMultipleVersions(tools []Tool, index map[string]interface{}) error { host := translateGOOSGOARCHToPackageIndexValue() for _, tool := range tools { if !toolAlreadyDownloadedAndUnpacked(TOOLS_FOLDER, tool) { _, err := os.Stat(filepath.Join(TOOLS_FOLDER, tool.Name)) if err == nil { err = os.RemoveAll(filepath.Join(TOOLS_FOLDER, tool.Name)) if err != nil { return i18n.WrapError(err) } } } } for _, tool := range tools { url, err := findToolUrl(index, tool, host) if err != nil { return i18n.WrapError(err) } err = downloadAndUnpackTool(tool, url, TOOLS_FOLDER, false) if err != nil { return i18n.WrapError(err) } } return nil }
func (s *GCCPreprocSourceSaver) Run(ctx *types.Context) error { preprocPath := ctx.PreprocPath err := utils.EnsureFolderExists(preprocPath) if err != nil { return i18n.WrapError(err) } err = utils.WriteFile(filepath.Join(preprocPath, constants.FILE_GCC_PREPROC_TARGET), ctx.Source) return i18n.WrapError(err) }
func (s *HardwareLoader) Run(ctx *types.Context) error { logger := ctx.GetLogger() packages := &types.Packages{} packages.Packages = make(map[string]*types.Package) packages.Properties = make(map[string]string) folders := ctx.HardwareFolders folders, err := utils.AbsolutizePaths(folders) if err != nil { return i18n.WrapError(err) } for _, folder := range folders { stat, err := os.Stat(folder) if err != nil { return i18n.WrapError(err) } if !stat.IsDir() { return i18n.ErrorfWithLogger(logger, constants.MSG_MUST_BE_A_FOLDER, folder) } hardwarePlatformTxt, err := props.SafeLoad(filepath.Join(folder, constants.FILE_PLATFORM_TXT), logger) if err != nil { return i18n.WrapError(err) } packages.Properties.Merge(hardwarePlatformTxt) subfolders, err := utils.ReadDirFiltered(folder, utils.FilterDirs) if err != nil { return i18n.WrapError(err) } subfolders = utils.FilterOutFoldersByNames(subfolders, constants.FOLDER_TOOLS) for _, subfolder := range subfolders { subfolderPath := filepath.Join(folder, subfolder.Name()) packageId := subfolder.Name() if _, err := os.Stat(filepath.Join(subfolderPath, constants.FOLDER_HARDWARE)); err == nil { subfolderPath = filepath.Join(subfolderPath, constants.FOLDER_HARDWARE) } targetPackage := getOrCreatePackage(packages, packageId) err = loadPackage(targetPackage, subfolderPath, logger) if err != nil { return i18n.WrapError(err) } packages.Packages[packageId] = targetPackage } } ctx.Hardware = packages return nil }
func collectAllSketchFiles(from string) ([]string, error) { filePaths := []string{} // Source files in the root are compiled, non-recursively. This // is the only place where .ino files can be present. rootExtensions := func(ext string) bool { return MAIN_FILE_VALID_EXTENSIONS[ext] || ADDITIONAL_FILE_VALID_EXTENSIONS[ext] } err := utils.FindFilesInFolder(&filePaths, from, rootExtensions, true /* recurse */) if err != nil { return nil, i18n.WrapError(err) } return filePaths, i18n.WrapError(err) }
func (s *SketchSaver) Run(ctx *types.Context) error { sketch := ctx.Sketch sketchBuildPath := ctx.SketchBuildPath err := utils.EnsureFolderExists(sketchBuildPath) if err != nil { return i18n.WrapError(err) } err = utils.WriteFile(filepath.Join(sketchBuildPath, filepath.Base(sketch.MainFile.Name)+".cpp"), ctx.Source) return i18n.WrapError(err) }
func downloadBoardManagerCores(cores []Core, index map[string]interface{}) error { for _, core := range cores { url, err := findCoreUrl(index, core) if err != nil { return i18n.WrapError(err) } err = downloadAndUnpackBoardManagerCore(core, url, BOARD_MANAGER_FOLDER) if err != nil { return i18n.WrapError(err) } } return nil }
func downloadCores(cores []Core, index map[string]interface{}) error { for _, core := range cores { url, err := findCoreUrl(index, core) if err != nil { return i18n.WrapError(err) } err = downloadAndUnpackCore(core, url, HARDWARE_FOLDER) if err != nil { return i18n.WrapError(err) } } return nil }
func downloadLibraries(libraries []Library, index map[string]interface{}) error { for _, library := range libraries { url, err := findLibraryUrl(index, library) if err != nil { return i18n.WrapError(err) } err = downloadAndUnpackLibrary(library, url, LIBRARIES_FOLDER) if err != nil { return i18n.WrapError(err) } } return nil }
func copyRecursive(from, to string) error { copyFunc := func(currentPath string, info os.FileInfo, err error) error { if err != nil { return err } rel, err := filepath.Rel(from, currentPath) if err != nil { return i18n.WrapError(err) } targetPath := filepath.Join(to, rel) if info.IsDir() { err := os.MkdirAll(targetPath, info.Mode()) if err != nil { return i18n.WrapError(err) } } else if info.Mode().IsRegular() { fromFile, err := os.Open(currentPath) if err != nil { return i18n.WrapError(err) } defer fromFile.Close() targetFile, err := os.Create(targetPath) if err != nil { return i18n.WrapError(err) } defer targetFile.Close() _, err = io.Copy(targetFile, fromFile) if err != nil { return i18n.WrapError(err) } err = os.Chmod(targetPath, info.Mode()) if err != nil { return i18n.WrapError(err) } } else if info.Mode()&os.ModeSymlink == os.ModeSymlink { linkedFile, err := os.Readlink(currentPath) if err != nil { return i18n.WrapError(err) } fromFile := filepath.Join(filepath.Dir(targetPath), linkedFile) err = os.Symlink(fromFile, targetPath) if err != nil { return i18n.WrapError(err) } } else { return errors.Errorf("unable to copy file " + currentPath) } return nil } err := gohasissues.Walk(from, copyFunc) return i18n.WrapError(err) }
func CompileFiles(objectFiles []string, sourcePath string, recurse bool, buildPath string, buildProperties props.PropertiesMap, includes []string, verbose bool, warningsLevel string, logger i18n.Logger) ([]string, error) { objectFiles, err := compileFilesWithExtensionWithRecipe(objectFiles, sourcePath, recurse, buildPath, buildProperties, includes, ".S", constants.RECIPE_S_PATTERN, verbose, warningsLevel, logger) if err != nil { return nil, i18n.WrapError(err) } objectFiles, err = compileFilesWithExtensionWithRecipe(objectFiles, sourcePath, recurse, buildPath, buildProperties, includes, ".c", constants.RECIPE_C_PATTERN, verbose, warningsLevel, logger) if err != nil { return nil, i18n.WrapError(err) } objectFiles, err = compileFilesWithExtensionWithRecipe(objectFiles, sourcePath, recurse, buildPath, buildProperties, includes, ".cpp", constants.RECIPE_CPP_PATTERN, verbose, warningsLevel, logger) if err != nil { return nil, i18n.WrapError(err) } return objectFiles, nil }
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 compileFilesWithExtensionWithRecipe(objectFiles []string, sourcePath string, recurse bool, buildPath string, buildProperties props.PropertiesMap, includes []string, extension string, recipe string, verbose bool, warningsLevel string, logger i18n.Logger) ([]string, error) { sources, err := findFilesInFolder(sourcePath, extension, recurse) if err != nil { return nil, i18n.WrapError(err) } return compileFilesWithRecipe(objectFiles, sourcePath, sources, buildPath, buildProperties, includes, recipe, verbose, warningsLevel, logger) }
func (s *LoadVIDPIDSpecificProperties) Run(ctx *types.Context) error { if ctx.USBVidPid == "" { return nil } vidPid := ctx.USBVidPid vidPid = strings.ToLower(vidPid) vidPidParts := strings.Split(vidPid, "_") vid := vidPidParts[0] pid := vidPidParts[1] buildProperties := ctx.BuildProperties VIDPIDIndex, err := findVIDPIDIndex(buildProperties, vid, pid) if err != nil { return i18n.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 *ContainerSetupHardwareToolsLibsSketchAndProps) Run(ctx *types.Context) error { commands := []types.Command{ &AddAdditionalEntriesToContext{}, &FailIfBuildPathEqualsSketchPath{}, &HardwareLoader{}, &PlatformKeysRewriteLoader{}, &RewriteHardwareKeys{}, &ToolsLoader{}, &TargetBoardResolver{}, &AddBuildBoardPropertyIfMissing{}, &LibrariesLoader{}, &SketchLoader{}, &SetupBuildProperties{}, &LoadVIDPIDSpecificProperties{}, &SetCustomBuildProperties{}, &AddMissingBuildPropertiesFromParentPlatformTxtFiles{}, } for _, command := range commands { PrintRingNameIfDebug(ctx, command) err := command.Run(ctx) if err != nil { return i18n.WrapError(err) } } return nil }
func downloadBoardsManagerTools(tools []Tool, index map[string]interface{}) error { host := translateGOOSGOARCHToPackageIndexValue() for _, tool := range tools { url, err := findToolUrl(index, tool, host) if err != nil { return i18n.WrapError(err) } err = downloadAndUnpackBoardsManagerTool(tool, url, BOARD_MANAGER_FOLDER) if err != nil { return i18n.WrapError(err) } } return nil }
func makeSketch(sketchLocation string, allSketchFilePaths []string, logger i18n.Logger) (*types.Sketch, error) { sketchFilesMap := make(map[string]types.SketchFile) for _, sketchFilePath := range allSketchFilePaths { source, err := ioutil.ReadFile(sketchFilePath) if err != nil { return nil, i18n.WrapError(err) } sketchFilesMap[sketchFilePath] = types.SketchFile{Name: sketchFilePath, Source: string(source)} } mainFile := sketchFilesMap[sketchLocation] delete(sketchFilesMap, sketchLocation) additionalFiles := []types.SketchFile{} otherSketchFiles := []types.SketchFile{} mainFileDir := filepath.Dir(mainFile.Name) for _, sketchFile := range sketchFilesMap { ext := strings.ToLower(filepath.Ext(sketchFile.Name)) if MAIN_FILE_VALID_EXTENSIONS[ext] { if filepath.Dir(sketchFile.Name) == mainFileDir { otherSketchFiles = append(otherSketchFiles, sketchFile) } } else if ADDITIONAL_FILE_VALID_EXTENSIONS[ext] { additionalFiles = append(additionalFiles, sketchFile) } else { return nil, i18n.ErrorfWithLogger(logger, constants.MSG_UNKNOWN_SKETCH_EXT, sketchFile.Name) } } sort.Sort(types.SketchFileSortByName(additionalFiles)) sort.Sort(types.SketchFileSortByName(otherSketchFiles)) return &types.Sketch{MainFile: mainFile, OtherSketchFiles: otherSketchFiles, AdditionalFiles: additionalFiles}, nil }