Skip to content

Commit 6a65d44

Browse files
committed
Allow zip sketches with embedded libraries
1 parent d2ff99c commit 6a65d44

File tree

6 files changed

+121
-1
lines changed

6 files changed

+121
-1
lines changed

src/arduino.cc/builder/container_setup.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ func (s *ContainerSetupHardwareToolsLibsSketchAndProps) Run(ctx *types.Context)
4646
&ToolsLoader{},
4747
&TargetBoardResolver{},
4848
&AddBuildBoardPropertyIfMissing{},
49-
&LibrariesLoader{},
5049
&SketchLoader{},
50+
&LibrariesLoader{},
5151
&SetupBuildProperties{},
5252
&LoadVIDPIDSpecificProperties{},
5353
&SetCustomBuildProperties{},

src/arduino.cc/builder/libraries_loader.go

+4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ func (s *LibrariesLoader) Run(ctx *types.Context) error {
6363

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

66+
if ctx.SketchZipped {
67+
sortedLibrariesFolders = appendPathToLibrariesFolders(sortedLibrariesFolders, filepath.Join(filepath.Dir(ctx.SketchLocation), constants.FOLDER_LIBRARIES))
68+
}
69+
6670
librariesFolders := ctx.OtherLibrariesFolders
6771
librariesFolders, err = utils.AbsolutizePaths(librariesFolders)
6872
if err != nil {

src/arduino.cc/builder/resolve_library.go

+14
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ func ResolveLibrary(ctx *types.Context, header string) *types.Library {
8484

8585
library = useAlreadyImportedLibraryWithSameNameIfExists(library, importedLibraries)
8686

87+
if ctx.SketchZipped {
88+
// select embedded library, in any case
89+
library = libraryContainedInSketchFolder(libraries, filepath.Dir(ctx.SketchLocation))
90+
}
91+
8792
libraryResolutionResults[header] = types.LibraryResolutionResult{
8893
Library: library,
8994
NotUsedLibraries: filterOutLibraryFrom(libraries, library),
@@ -119,6 +124,15 @@ func useAlreadyImportedLibraryWithSameNameIfExists(library *types.Library, impor
119124
return library
120125
}
121126

127+
func libraryContainedInSketchFolder(libraries []*types.Library, sketchFolder string) *types.Library {
128+
for _, lib := range libraries {
129+
if strings.Contains(lib.Folder, sketchFolder) {
130+
return lib
131+
}
132+
}
133+
return libraries[0]
134+
}
135+
122136
func filterOutLibraryFrom(libraries []*types.Library, libraryToRemove *types.Library) []*types.Library {
123137
filteredOutLibraries := []*types.Library{}
124138
for _, lib := range libraries {

src/arduino.cc/builder/sketch_loader.go

+29
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
package builder
3131

3232
import (
33+
"bufio"
3334
"io/ioutil"
35+
"net/http"
3436
"os"
3537
"path/filepath"
3638
"sort"
@@ -63,6 +65,17 @@ func (s *SketchLoader) Run(ctx *types.Context) error {
6365
sketchLocation = filepath.Join(sketchLocation, mainSketchStat.Name()+".ino")
6466
}
6567

68+
if mimeType(sketchLocation) == "application/zip" {
69+
dir, _ := ioutil.TempDir("", "arduino_sketch_zip_temp")
70+
sketchLocation, err = utils.ExtractZip(sketchLocation, dir)
71+
if err != nil {
72+
return nil
73+
}
74+
mainSketchFileName := filepath.Base(sketchLocation) + ".ino"
75+
sketchLocation = filepath.Join(sketchLocation, mainSketchFileName)
76+
ctx.SketchZipped = true
77+
}
78+
6679
ctx.SketchLocation = sketchLocation
6780

6881
allSketchFilePaths, err := collectAllSketchFiles(filepath.Dir(sketchLocation))
@@ -87,6 +100,22 @@ func (s *SketchLoader) Run(ctx *types.Context) error {
87100
return nil
88101
}
89102

103+
func mimeType(fileName string) string {
104+
fs, err := os.Open(fileName)
105+
106+
if err != nil {
107+
return ""
108+
}
109+
110+
defer fs.Close()
111+
112+
reader := bufio.NewReader(fs)
113+
114+
buf := make([]byte, 512)
115+
reader.Read(buf)
116+
return http.DetectContentType(buf)
117+
}
118+
90119
func collectAllSketchFiles(from string) ([]string, error) {
91120
filePaths := []string{}
92121
// Source files in the root are compiled, non-recursively. This

src/arduino.cc/builder/types/context.go

+3
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ type Context struct {
7777
Verbose bool
7878
DebugPreprocessor bool
7979

80+
// inoz handling
81+
SketchZipped bool
82+
8083
// Contents of a custom build properties file (line by line)
8184
CustomBuildProperties []string
8285

src/arduino.cc/builder/utils/utils.go

+70
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030
package utils
3131

3232
import (
33+
"archive/zip"
3334
"crypto/md5"
3435
"encoding/hex"
36+
"io"
3537
"io/ioutil"
3638
"os"
3739
"os/exec"
@@ -466,3 +468,71 @@ func ParseCppString(line string) (string, string, bool) {
466468
i += width
467469
}
468470
}
471+
472+
func ExtractZip(filePath string, location string) (string, error) {
473+
r, err := zip.OpenReader(filePath)
474+
if err != nil {
475+
return location, err
476+
}
477+
478+
var dirList []string
479+
480+
for _, f := range r.File {
481+
dirList = append(dirList, f.Name)
482+
}
483+
484+
basedir := findBaseDir(dirList)
485+
486+
for _, f := range r.File {
487+
fullname := filepath.Join(location, strings.Replace(f.Name, "", "", -1))
488+
if f.FileInfo().IsDir() {
489+
os.MkdirAll(fullname, f.FileInfo().Mode().Perm())
490+
} else {
491+
os.MkdirAll(filepath.Dir(fullname), 0755)
492+
perms := f.FileInfo().Mode().Perm()
493+
out, err := os.OpenFile(fullname, os.O_CREATE|os.O_RDWR, perms)
494+
if err != nil {
495+
return location, err
496+
}
497+
rc, err := f.Open()
498+
if err != nil {
499+
return location, err
500+
}
501+
_, err = io.CopyN(out, rc, f.FileInfo().Size())
502+
if err != nil {
503+
return location, err
504+
}
505+
rc.Close()
506+
out.Close()
507+
508+
mtime := f.FileInfo().ModTime()
509+
err = os.Chtimes(fullname, mtime, mtime)
510+
if err != nil {
511+
return location, err
512+
}
513+
}
514+
}
515+
return filepath.Join(location, basedir), nil
516+
}
517+
518+
func findBaseDir(dirList []string) string {
519+
baseDir := ""
520+
// https://github.com/backdrop-ops/contrib/issues/55#issuecomment-73814500
521+
dontdiff := []string{"pax_global_header"}
522+
for index := range dirList {
523+
if SliceContains(dontdiff, dirList[index]) {
524+
continue
525+
}
526+
candidateBaseDir := dirList[index]
527+
for i := index; i < len(dirList); i++ {
528+
if !strings.Contains(dirList[i], candidateBaseDir) {
529+
return baseDir
530+
}
531+
}
532+
// avoid setting the candidate if it is the last file
533+
if dirList[len(dirList)-1] != candidateBaseDir {
534+
baseDir = candidateBaseDir
535+
}
536+
}
537+
return baseDir
538+
}

0 commit comments

Comments
 (0)