Skip to content

Commit 4b7ff49

Browse files
committed
Enable zipped sketch with embedded libraries
Works in conjunction with https://github.com/facchinm/arduino-builder/tree/inoz_experiment
1 parent 647a1b0 commit 4b7ff49

File tree

4 files changed

+202
-9
lines changed

4 files changed

+202
-9
lines changed

app/src/processing/app/Base.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,8 @@ public void handleOpenPrompt() throws Exception {
771771
fd.setFilenameFilter(new FilenameFilter() {
772772
public boolean accept(File dir, String name) {
773773
return name.toLowerCase().endsWith(".ino")
774-
|| name.toLowerCase().endsWith(".pde");
774+
|| name.toLowerCase().endsWith(".pde")
775+
|| name.toLowerCase().endsWith(".inz");
775776
}
776777
});
777778

app/src/processing/app/Editor.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public boolean test(SketchController sketch) {
157157

158158
static volatile AbstractMonitor serialMonitor;
159159
static AbstractMonitor serialPlotter;
160-
160+
161161
final EditorHeader header;
162162
EditorStatus status;
163163
EditorConsole console;
@@ -247,7 +247,7 @@ public void windowDeactivated(WindowEvent e) {
247247

248248
//PdeKeywords keywords = new PdeKeywords();
249249
//sketchbook = new Sketchbook(this);
250-
250+
251251
buildMenuBar();
252252

253253
// For rev 0120, placing things inside a JPanel
@@ -1862,7 +1862,9 @@ protected boolean handleOpenInternal(File sketchFile) {
18621862
File file = Sketch.checkSketchFile(sketchFile);
18631863

18641864
if (file == null) {
1865-
if (!fileName.endsWith(".ino") && !fileName.endsWith(".pde")) {
1865+
if (fileName.endsWith(".inz")) {
1866+
file = sketchFile;
1867+
} else if (!fileName.endsWith(".ino") && !fileName.endsWith(".pde")) {
18661868

18671869
Base.showWarning(tr("Bad file selected"), tr("Arduino can only open its own sketches\n" +
18681870
"and other files ending in .ino or .pde"), null);
@@ -2288,7 +2290,7 @@ public void handleSerial() {
22882290
return;
22892291
}
22902292
}
2291-
2293+
22922294
if (serialMonitor != null) {
22932295
// The serial monitor already exists
22942296

@@ -2385,7 +2387,7 @@ public void handleSerial() {
23852387
} while (serialMonitor.requiresAuthorization() && !success);
23862388

23872389
}
2388-
2390+
23892391
public void handlePlotter() {
23902392
if(serialMonitor != null) {
23912393
if(serialMonitor.isClosed()) {
@@ -2395,7 +2397,7 @@ public void handlePlotter() {
23952397
return;
23962398
}
23972399
}
2398-
2400+
23992401
if (serialPlotter != null) {
24002402
// The serial plotter already exists
24012403

arduino-core/src/processing/app/Sketch.java

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@
22

33
import java.io.File;
44
import java.io.IOException;
5+
import java.io.FileInputStream;
56
import java.nio.file.Files;
67
import java.util.*;
78
import java.util.stream.Collectors;
89
import java.util.stream.Stream;
10+
import java.util.zip.ZipEntry;
11+
import java.util.zip.ZipOutputStream;
12+
import java.io.FileOutputStream;
913

1014
import cc.arduino.files.DeleteFilesOnShutdown;
1115
import processing.app.helpers.FileUtils;
16+
import processing.app.tools.ZipDeflater;
17+
18+
import org.apache.commons.compress.utils.IOUtils;
1219

1320
import static processing.app.I18n.tr;
1421

@@ -17,8 +24,10 @@
1724
*/
1825
public class Sketch {
1926
public static final String DEFAULT_SKETCH_EXTENSION = "ino";
27+
public static final String DEFAULT_SKETCH_EXTENSION_COMPRESSED = "inoz";
2028
public static final List<String> OLD_SKETCH_EXTENSIONS = Arrays.asList("pde");
21-
public static final List<String> SKETCH_EXTENSIONS = Stream.concat(Stream.of(DEFAULT_SKETCH_EXTENSION), OLD_SKETCH_EXTENSIONS.stream()).collect(Collectors.toList());
29+
public static final List<String> DEFAULT_SKETCH_EXTENSIONS = Stream.concat(Stream.of(DEFAULT_SKETCH_EXTENSION), Stream.of(DEFAULT_SKETCH_EXTENSION_COMPRESSED)).collect(Collectors.toList());
30+
public static final List<String> SKETCH_EXTENSIONS = Stream.concat(DEFAULT_SKETCH_EXTENSIONS.stream(), OLD_SKETCH_EXTENSIONS.stream()).collect(Collectors.toList());
2231
public static final List<String> OTHER_ALLOWED_EXTENSIONS = Arrays.asList("c", "cpp", "h", "hh", "hpp", "s");
2332
public static final List<String> EXTENSIONS = Stream.concat(SKETCH_EXTENSIONS.stream(), OTHER_ALLOWED_EXTENSIONS.stream()).collect(Collectors.toList());
2433

@@ -27,6 +36,8 @@ public class Sketch {
2736
*/
2837
private File folder;
2938

39+
private File compressedSketch = null;
40+
3041
private List<SketchFile> files = new ArrayList<>();
3142

3243
private File buildPath;
@@ -50,10 +61,70 @@ public int compare(SketchFile x, SketchFile y) {
5061
* Any file inside the sketch directory.
5162
*/
5263
Sketch(File file) throws IOException {
53-
folder = file.getParentFile();
64+
if (file.getName().endsWith("inz")) {
65+
//extract it in a temp folder and assign the
66+
compressedSketch = file;
67+
File tmpFolder = FileUtils.createTempFolder();
68+
ZipDeflater zipDeflater = new ZipDeflater(file, tmpFolder);
69+
zipDeflater.deflate();
70+
String basename = FileUtils.splitFilename(file.getName()).basename;
71+
folder = new File(tmpFolder, basename);
72+
} else {
73+
folder = file.getParentFile();
74+
}
5475
files = listSketchFiles(true);
5576
}
5677

78+
public void buildZip(File dir, String sofar,
79+
ZipOutputStream zos) throws IOException {
80+
String files[] = dir.list();
81+
if (files == null) {
82+
throw new IOException("Unable to list files from " + dir);
83+
}
84+
for (int i = 0; i < files.length; i++) {
85+
if (files[i].equals(".") ||
86+
files[i].equals("..")) continue;
87+
88+
File sub = new File(dir, files[i]);
89+
String nowfar = (sofar == null) ?
90+
files[i] : (sofar + "/" + files[i]);
91+
92+
if (sub.isDirectory()) {
93+
// directories are empty entries and have / at the end
94+
ZipEntry entry = new ZipEntry(nowfar + "/");
95+
//System.out.println(entry);
96+
zos.putNextEntry(entry);
97+
zos.closeEntry();
98+
buildZip(sub, nowfar, zos);
99+
100+
} else {
101+
ZipEntry entry = new ZipEntry(nowfar);
102+
entry.setTime(sub.lastModified());
103+
zos.putNextEntry(entry);
104+
zos.write(loadBytesRaw(sub));
105+
zos.closeEntry();
106+
}
107+
}
108+
}
109+
110+
static public byte[] loadBytesRaw(File file) throws IOException {
111+
int size = (int) file.length();
112+
FileInputStream input = null;
113+
try {
114+
input = new FileInputStream(file);
115+
byte buffer[] = new byte[size];
116+
int offset = 0;
117+
int bytesRead;
118+
while ((bytesRead = input.read(buffer, offset, size - offset)) != -1) {
119+
offset += bytesRead;
120+
if (bytesRead == 0) break;
121+
}
122+
return buffer;
123+
} finally {
124+
IOUtils.closeQuietly(input);
125+
}
126+
}
127+
57128
static public File checkSketchFile(File file) {
58129
// check to make sure that this .pde file is
59130
// in a folder of the same name
@@ -137,6 +208,13 @@ public void save() throws IOException {
137208
if (file.isModified())
138209
file.save();
139210
}
211+
String basename = files.get(0).getPrettyName();
212+
if (compressedSketch != null) {
213+
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(compressedSketch));
214+
buildZip(folder, basename, zos);
215+
zos.flush();
216+
IOUtils.closeQuietly(zos);
217+
}
140218
}
141219

142220
public int getCodeCount() {
@@ -151,6 +229,9 @@ public SketchFile[] getFiles() {
151229
* Returns a file object for the primary .pde of this sketch.
152230
*/
153231
public SketchFile getPrimaryFile() {
232+
if (compressedSketch != null) {
233+
return new SketchFile(this, compressedSketch);
234+
}
154235
return files.get(0);
155236
}
156237

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package processing.app.tools;
2+
3+
import java.io.File;
4+
import java.io.FileOutputStream;
5+
import java.io.IOException;
6+
import java.io.InputStream;
7+
import java.util.Enumeration;
8+
import java.util.Random;
9+
import java.util.zip.ZipEntry;
10+
import java.util.zip.ZipException;
11+
import java.util.zip.ZipFile;
12+
13+
import org.apache.commons.compress.utils.IOUtils;
14+
import processing.app.helpers.FileUtils;
15+
16+
public class ZipDeflater {
17+
18+
private final ZipFile zipFile;
19+
private final File destFolder;
20+
private final Random random;
21+
private final File file;
22+
23+
public ZipDeflater(File file, File destFolder) throws ZipException, IOException {
24+
this.file = file;
25+
this.destFolder = destFolder;
26+
this.zipFile = new ZipFile(file);
27+
this.random = new Random();
28+
}
29+
30+
public void deflate() throws IOException {
31+
String tmpFolderName = folderNameFromZip() + random.nextInt(1000000);
32+
33+
File tmpFolder = new File(destFolder, tmpFolderName);
34+
35+
if (!tmpFolder.mkdir()) {
36+
throw new IOException("Unable to create folder " + tmpFolderName);
37+
}
38+
39+
Enumeration<? extends ZipEntry> entries = zipFile.entries();
40+
while (entries.hasMoreElements()) {
41+
ZipEntry entry = entries.nextElement();
42+
ensureFoldersOfEntryExist(tmpFolder, entry);
43+
File entryFile = new File(tmpFolder, entry.getName());
44+
if (entry.isDirectory()) {
45+
entryFile.mkdir();
46+
} else {
47+
FileOutputStream fos = null;
48+
InputStream zipInputStream = null;
49+
try {
50+
fos = new FileOutputStream(entryFile);
51+
zipInputStream = zipFile.getInputStream(entry);
52+
byte[] buffer = new byte[1024 * 4];
53+
int len = -1;
54+
while ((len = zipInputStream.read(buffer)) != -1) {
55+
fos.write(buffer, 0, len);
56+
}
57+
} finally {
58+
IOUtils.closeQuietly(fos);
59+
IOUtils.closeQuietly(zipInputStream);
60+
}
61+
}
62+
}
63+
64+
deleteUndesiredFoldersAndFiles(tmpFolder);
65+
66+
// Test.zip may or may not contain Test folder. If it does, we keep it. If not, we use zip name.
67+
ensureOneLevelFolder(tmpFolder);
68+
}
69+
70+
private void deleteUndesiredFoldersAndFiles(File folder) {
71+
for (File file : folder.listFiles()) {
72+
if (file.isDirectory() && "__MACOSX".equals(file.getName())) {
73+
FileUtils.recursiveDelete(file);
74+
} else if (file.getName().startsWith(".")) {
75+
FileUtils.recursiveDelete(file);
76+
}
77+
}
78+
}
79+
80+
private void ensureFoldersOfEntryExist(File folder, ZipEntry entry) {
81+
String[] parts = entry.getName().split("/");
82+
File current = folder;
83+
for (int i = 0; i < parts.length - 1; i++) {
84+
current = new File(current, parts[i]);
85+
current.mkdir();
86+
}
87+
}
88+
89+
private void ensureOneLevelFolder(File folder) {
90+
File[] files = folder.listFiles();
91+
92+
if (files.length != 1) {
93+
folder.renameTo(new File(folder.getParentFile(), folderNameFromZip()));
94+
return;
95+
}
96+
97+
files[0].renameTo(new File(folder.getParentFile(), files[0].getName()));
98+
FileUtils.recursiveDelete(folder);
99+
}
100+
101+
private String folderNameFromZip() {
102+
String filename = file.getName();
103+
if (filename.lastIndexOf(".") != -1) {
104+
filename = filename.substring(0, filename.lastIndexOf("."));
105+
}
106+
return filename;
107+
}
108+
109+
}

0 commit comments

Comments
 (0)