diff --git a/container_setup.go b/container_setup.go index 57749aa2..b5b3857d 100644 --- a/container_setup.go +++ b/container_setup.go @@ -47,8 +47,8 @@ func (s *ContainerSetupHardwareToolsLibsSketchAndProps) Run(ctx *types.Context) &ToolsLoader{}, &TargetBoardResolver{}, &AddBuildBoardPropertyIfMissing{}, - &LibrariesLoader{}, &SketchLoader{}, + &LibrariesLoader{}, &SetupBuildProperties{}, &LoadVIDPIDSpecificProperties{}, &SetCustomBuildProperties{}, diff --git a/libraries_loader.go b/libraries_loader.go index 1730bf44..6c8aca8d 100644 --- a/libraries_loader.go +++ b/libraries_loader.go @@ -63,6 +63,10 @@ func (s *LibrariesLoader) Run(ctx *types.Context) error { sortedLibrariesFolders = appendPathToLibrariesFolders(sortedLibrariesFolders, filepath.Join(platform.Folder, constants.FOLDER_LIBRARIES)) + if ctx.SketchZipped { + sortedLibrariesFolders = appendPathToLibrariesFolders(sortedLibrariesFolders, filepath.Join(filepath.Dir(ctx.SketchLocation), constants.FOLDER_LIBRARIES)) + } + librariesFolders := ctx.OtherLibrariesFolders librariesFolders, err = utils.AbsolutizePaths(librariesFolders) if err != nil { diff --git a/resolve_library.go b/resolve_library.go index dd96ab75..c69fd845 100644 --- a/resolve_library.go +++ b/resolve_library.go @@ -84,6 +84,11 @@ func ResolveLibrary(ctx *types.Context, header string) *types.Library { library = useAlreadyImportedLibraryWithSameNameIfExists(library, importedLibraries) + if ctx.SketchZipped { + // select embedded library, in any case + library = libraryContainedInSketchFolder(libraries, filepath.Dir(ctx.SketchLocation)) + } + libraryResolutionResults[header] = types.LibraryResolutionResult{ Library: library, NotUsedLibraries: filterOutLibraryFrom(libraries, library), @@ -119,6 +124,15 @@ func useAlreadyImportedLibraryWithSameNameIfExists(library *types.Library, impor return library } +func libraryContainedInSketchFolder(libraries []*types.Library, sketchFolder string) *types.Library { + for _, lib := range libraries { + if strings.Contains(lib.Folder, sketchFolder) { + return lib + } + } + return libraries[0] +} + func filterOutLibraryFrom(libraries []*types.Library, libraryToRemove *types.Library) []*types.Library { filteredOutLibraries := []*types.Library{} for _, lib := range libraries { diff --git a/sketch_loader.go b/sketch_loader.go index 3ba588fa..0b6a5910 100644 --- a/sketch_loader.go +++ b/sketch_loader.go @@ -30,7 +30,9 @@ package builder import ( + "bufio" "io/ioutil" + "net/http" "os" "path/filepath" "sort" @@ -63,6 +65,17 @@ func (s *SketchLoader) Run(ctx *types.Context) error { sketchLocation = filepath.Join(sketchLocation, mainSketchStat.Name()+".ino") } + if mimeType(sketchLocation) == "application/zip" { + dir, _ := ioutil.TempDir("", "arduino_sketch_zip_temp") + sketchLocation, err = utils.ExtractZip(sketchLocation, dir) + if err != nil { + panic(err) + } + mainSketchFileName := filepath.Base(sketchLocation) + ".ino" + sketchLocation = filepath.Join(sketchLocation, mainSketchFileName) + ctx.SketchZipped = true + } + ctx.SketchLocation = sketchLocation allSketchFilePaths, err := collectAllSketchFiles(filepath.Dir(sketchLocation)) @@ -72,7 +85,7 @@ func (s *SketchLoader) Run(ctx *types.Context) error { logger := ctx.GetLogger() - if !utils.SliceContains(allSketchFilePaths, sketchLocation) { + if !utils.SliceContains(allSketchFilePaths, sketchLocation) && !ctx.SketchZipped { return i18n.ErrorfWithLogger(logger, constants.MSG_CANT_FIND_SKETCH_IN_PATH, sketchLocation, filepath.Dir(sketchLocation)) } @@ -87,6 +100,22 @@ func (s *SketchLoader) Run(ctx *types.Context) error { return nil } +func mimeType(fileName string) string { + fs, err := os.Open(fileName) + + if err != nil { + return "" + } + + defer fs.Close() + + reader := bufio.NewReader(fs) + + buf := make([]byte, 512) + reader.Read(buf) + return http.DetectContentType(buf) +} + func collectAllSketchFiles(from string) ([]string, error) { filePaths := []string{} // Source files in the root are compiled, non-recursively. This diff --git a/types/context.go b/types/context.go index e9368c08..f9bb8af6 100644 --- a/types/context.go +++ b/types/context.go @@ -88,6 +88,9 @@ type Context struct { Verbose bool DebugPreprocessor bool + // inoz handling + SketchZipped bool + // Dry run, only create progress map Progress ProgressStruct diff --git a/utils/utils.go b/utils/utils.go index 8cadb80c..adec3320 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -30,6 +30,7 @@ package utils import ( + "archive/zip" "bytes" "crypto/md5" "encoding/hex" @@ -585,6 +586,70 @@ func ParseCppString(line string) (string, string, bool) { } } +func ExtractZip(filePath string, location string) (string, error) { + r, err := zip.OpenReader(filePath) + if err != nil { + return location, err + } + + var dirList []string + + for _, f := range r.File { + fullname := filepath.Join(location, strings.Replace(f.Name, "", "", -1)) + if f.FileInfo().IsDir() { + dirList = append(dirList, fullname) + os.MkdirAll(fullname, 0755) + } else { + _, err := os.Stat(filepath.Dir(fullname)) + if err != nil { + dirList = append(dirList, filepath.Dir(fullname)) + os.MkdirAll(filepath.Dir(fullname), 0755) + } + perms := f.FileInfo().Mode().Perm() + out, err := os.OpenFile(fullname, os.O_CREATE|os.O_RDWR, perms) + if err != nil { + return location, err + } + rc, err := f.Open() + if err != nil { + return location, err + } + _, err = io.CopyN(out, rc, f.FileInfo().Size()) + if err != nil { + return location, err + } + rc.Close() + out.Close() + + mtime := f.FileInfo().ModTime() + err = os.Chtimes(fullname, mtime, mtime) + if err != nil { + return location, err + } + } + } + basedir := filepath.Base(findBaseDir(dirList)) + return filepath.Join(location, basedir), nil +} + +func findBaseDir(dirList []string) string { + baseDir := "" + minLen := 256 + // https://github.com/backdrop-ops/contrib/issues/55#issuecomment-73814500 + dontdiff := []string{"pax_global_header"} + for _, dir := range dirList { + if SliceContains(dontdiff, dir) { + continue + } + //get the shortest string + if len(dir) < minLen { + baseDir = dir + minLen = len(dir) + } + } + return baseDir +} + func isMn(r rune) bool { return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks }