From e8ea12c629e3a07c09dcc54d683760370dde13f4 Mon Sep 17 00:00:00 2001 From: Federico Fissore Date: Wed, 17 Oct 2012 15:25:29 +0200 Subject: [PATCH] Add library from ZIP --- app/src/processing/app/Base.java | 22 ++++ app/src/processing/app/Editor.java | 14 ++- app/src/processing/app/tools/ZipDeflater.java | 97 ++++++++++++++++++ app/test/Test.zip | Bin 0 -> 3109 bytes app/test/Test2.zip | Bin 0 -> 3013 bytes .../processing/app/tools/ZipDeflaterTest.java | 81 +++++++++++++++ 6 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 app/src/processing/app/tools/ZipDeflater.java create mode 100644 app/test/Test.zip create mode 100644 app/test/Test2.zip create mode 100644 app/test/processing/app/tools/ZipDeflaterTest.java diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 55e34985a..59966ffc0 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -36,6 +36,7 @@ import processing.app.helpers.FileUtils; import processing.app.helpers.PreferencesMap; import processing.app.helpers.filefilters.OnlyDirs; import processing.app.helpers.filefilters.OnlyFilesWithExtension; +import processing.app.tools.ZipDeflater; import processing.core.*; import static processing.app.I18n._; @@ -2594,4 +2595,25 @@ public class Base { } } } + + + public void handleAddZipLibrary(Editor editor) { + String prompt = _("Select a zip file containing the library you'd like to add"); + FileDialog fd = new FileDialog(editor, prompt, FileDialog.LOAD); + fd.setDirectory(System.getProperty("user.home")); + fd.setVisible(true); + + String directory = fd.getDirectory(); + String filename = fd.getFile(); + if (filename == null) return; + + File sourceFile = new File(directory, filename); + try { + ZipDeflater zipDeflater = new ZipDeflater(sourceFile, getSketchbookLibrariesFolder()); + zipDeflater.deflate(); + editor.statusNotice(_("Library added to your libraries. Check \"Import library\" menu")); + } catch (IOException e) { + editor.statusError(e); + } + } } diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 7b15b8ba5..54c7e61d4 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -178,7 +178,7 @@ public class Editor extends JFrame implements RunnerListener { // re-add the sub-menus that are shared by all windows fileMenu.insert(sketchbookMenu, 2); fileMenu.insert(examplesMenu, 3); - sketchMenu.insert(importMenu, 4); + //sketchMenu.insert(importMenu, 4); toolsMenu.insert(boardsMenu, numTools); toolsMenu.insert(cpuTypeMenu, numTools + 1); toolsMenu.insert(serialMenu, numTools + 2); @@ -190,7 +190,7 @@ public class Editor extends JFrame implements RunnerListener { // System.err.println("deactivate"); // not coming through fileMenu.remove(sketchbookMenu); fileMenu.remove(examplesMenu); - sketchMenu.remove(importMenu); + //sketchMenu.remove(importMenu); toolsMenu.remove(boardsMenu); toolsMenu.remove(cpuTypeMenu); toolsMenu.remove(serialMenu); @@ -634,6 +634,16 @@ public class Editor extends JFrame implements RunnerListener { } sketchMenu.add(importMenu); + item = new JMenuItem(_("Add Library from ZIP")); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + base.handleAddZipLibrary(Editor.this); + base.onBoardOrPortChange(); + base.rebuildImportMenu(Editor.importMenu); + } + }); + sketchMenu.add(item); + item = newJMenuItem(_("Show Sketch Folder"), 'K'); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { diff --git a/app/src/processing/app/tools/ZipDeflater.java b/app/src/processing/app/tools/ZipDeflater.java new file mode 100644 index 000000000..651ff37ba --- /dev/null +++ b/app/src/processing/app/tools/ZipDeflater.java @@ -0,0 +1,97 @@ +package processing.app.tools; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.Random; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +public class ZipDeflater { + + private final ZipFile zipFile; + private final File destFolder; + + public ZipDeflater(File file, File destFolder) throws ZipException, IOException { + this.destFolder = destFolder; + this.zipFile = new ZipFile(file); + } + + public void deflate() throws IOException { + String folderName = tempFolderNameFromZip(); + + File folder = new File(destFolder, folderName); + + if (!folder.mkdir()) { + throw new IOException("Unable to create folder " + folderName); + } + + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + ensureFoldersOfEntryExist(folder, entry); + File entryFile = new File(folder, entry.getName()); + if (entry.isDirectory()) { + entryFile.mkdir(); + } else { + FileOutputStream fos = null; + InputStream zipInputStream = null; + try { + fos = new FileOutputStream(entryFile); + zipInputStream = zipFile.getInputStream(entry); + byte[] buffer = new byte[1024 * 4]; + int len = -1; + while ((len = zipInputStream.read(buffer)) != -1) { + fos.write(buffer, 0, len); + } + } finally { + if (fos != null) { + fos.close(); + } + if (zipInputStream != null) { + zipInputStream.close(); + } + } + } + } + + // Test.zip may or may not contain Test folder. We use zip name to create libraries folder. Therefore, a contained Test folder is useless and must be removed + ensureOneLevelFolder(folder); + } + + private void ensureFoldersOfEntryExist(File folder, ZipEntry entry) { + String[] parts = entry.getName().split("/"); + File current = folder; + for (int i = 0; i < parts.length - 1; i++) { + current = new File(current, parts[i]); + current.mkdir(); + } + } + + private void ensureOneLevelFolder(File folder) { + File[] files = folder.listFiles(); + if (files.length == 1 && files[0].isDirectory()) { + File tempFile = new File(files[0].getPath() + new Random().nextInt(1000)); + files[0].renameTo(tempFile); + for (File file : tempFile.listFiles()) { + file.renameTo(new File(folder, file.getName())); + } + tempFile.delete(); + } + } + + private String tempFolderNameFromZip() { + String folderName = zipFile.getName(); + if (folderName.lastIndexOf(".") != -1) { + folderName = folderName.substring(0, folderName.lastIndexOf(".")); + } + if (folderName.lastIndexOf(File.separator) != -1) { + folderName = folderName.substring(folderName.lastIndexOf(File.separator) + 1); + } + return folderName; + } + +} diff --git a/app/test/Test.zip b/app/test/Test.zip new file mode 100644 index 0000000000000000000000000000000000000000..f4b4c354d66f6ef78129cc46a1ec9ffd3d39b3bd GIT binary patch literal 3109 zcmai$cT`i`62=1|gc8_!o?sUCG;YKbkJ+4 zVg#uo7K(t<5rkMkxd{jcTyMQ(t+V#|W4^s-&Ns7vNCc3I20;2LTa?T0EPg#e049J5 zDj-nef;k-kY~Z9dfppT^pxB^5?uQ_Kk`9D0?1iAv_Flf8sDS<0*>R0Sv9+@C2V!~u zh;{OD^LDWf@bN+gx)N9WT4~ZM`&z63DDls8=;%`aSL=}WNna-vDa~)h6ia@ksg_jb z-6lz=6>_lmdZzzs7FG9#~e@i(i9j0C~Lz<61wmWLepQgp)8^?^Egf$(Q;7W#e~IRyfj!98r0jcBWH zq@*nD=ge^nDJD(x#MaT{>&Gjng^;*5loOOc}hLtx{Zwq zkp3Cj9xz`j@!F9`W}S}Iv z_gbY-lr3^SA5DFeB+OYqg|9R_quP*KP%F)~(vH8n1+Ch!D}*L1RVgLNg>xB2+ZD9V z0h>GpSWcHoQTnANM?2eaLa=;!m?Ps%&xG*}ZJF{%@^G@_71z;=eLQV>HWC7w^ILXu z<||)n>bq1{!(R2U#m&8MREM-EgC92ninfNtqF@X^r%??kYmeKlSyY2d>2RDE#H`{a0w3R* z*3$A1jfW^coi%^WYkXT}AZE))TB$6z#{c4LSKY6))Lm-TUFA)3i>i4Rcl#2M#aQ=7*F5u;w+0@AR&Tb}Jd8_yo zYfwb=eFN>fF^|E-8DT#7RES}lhq0qtN`48Ff(K)IG3X&%I)p=$;92=n>-!^4>vKQd z$}&^E5sR2n%@=1IPXD?UAspZUl(L8VX06w(M}d9 z)zQ=I|qAp80V;5>SXX0Q!+10zw9&KqF|A!4X_Hla<47J7oZ&`?nz%# z^#F!Yo?_skxegh!K}+A2QYb7wfohCVOmF?>A4*}Xe}58-Q+iTs)E9h0x#sAz(7?Lb zybelTkIJ6%6|rK6oKTh>RIu80M(uzt5j zKfRuofP4v!>#$R!O_}Js1Hz=n1lY_{U1XJ$v9*yO$JE5!6dM|k67%Ey@xCSU$h3v( zkHzvu+#;%DFkbDS4uvu>6(5++%n-p(uUdVw{FQX4)t2FH)ITj80gl-$Z8QTRIu2We zcXZ2qbqg^|>o@RONny`*yH+I95ckzV1|u^zhLj<*0kC(pUOboPHB2H+WQ6fcW-l(E z&7Pih#%|mNWf-KvZis2JSYiuCF+dNe#0L1O=I6_6v)_wf2;h}$ zfB;G{b*y}2ZDY$n5m=A@lv89RafwB2UDQo_j-kE#w$m}T)n=76V z4PzgUrFM*|Gg;6pDW#kq(uuM*{{CU>2G|WkP-Eg6x2!SZFroGL?5Cf4H0*xd#~~As zSe}k~tALpR>rbT0xx@v0W)X&lepwUrOKDbIcCocMrrD>;>eo42gDdMv7=hDUZya}F zx++fVT_c5I$!gJ(U+PYQU!iPQAS}RSOjj9V0b6A_CP3Bi`NgJGUDJ3uH*BE&LQ9;!rZPd3FdZn zf1?~Zx<~*il00nJW&`{z5Xd+2=^?4bK#N4^z_g~%C#`M_2)#M(vctEO)_z8EU$Pr{$h=d^ILZo3%-evS;LQB^gh<&#sM0)Iw_FWm$XeXB; mwIsQLXb;FJLCIx^4Z15rYEUEsM7&%8J5=pXJaz#!>Fr-)eX%$I literal 0 HcmV?d00001 diff --git a/app/test/Test2.zip b/app/test/Test2.zip new file mode 100644 index 0000000000000000000000000000000000000000..466e7488261f91a66eb7d0cf61afdb1232a8a107 GIT binary patch literal 3013 zcmb7`cT^Mk9>oVj5_%Jn4iZ{ml@@vtrHFu!7U|MM?==W2vPcmr3X4HNO6Wxd>7Z+< zVg#uot5O7%jvxdTlpS#2%3D~@d1ua<^P4~B^P9PI?|iR;E`)*w002rr!#feB8;;*^0Zj!!UW}<}d@*p;2*lC=WE3+H0N6cwCh6-!BpKV6zp%8j z=A8(r!+y*zG!nnWEV?G*Dm6>r)^*$Q80$)t(%VyR?UqiX#LaHK8WW%b=V#vPgbgn= z9;}2PjaAQ-fNOR>oi7Z{2{o!bvKOoMRT%M(k)BKaW1T$wxzO$Gz<{h`LKt(Qo8%<1oGP z6dC7O|4+<9lp!0d0=~&j@=MM(=Eu}~m05f{W~vFL-SNXnI;-{L&Wu;ZXuPT=am<;` z8nTOB$;d0@ZE~cgX_?VW$aiygB28+n9`cdFDfo{eA+9m91^NS45dJ{LN#2%MTul6G zg_q;D5%ezn@7dRoWzZ_Y!ogz(e@onGR)$*jB^;Fn<<)}ji2j$v4n97+A}{MZ9wc(P zF~MsV=G^MvZ?UKn_hOPvb0P#_r-lk zW@`B`bt$ldTRR{&KerEpL~=<~L*n}ihcB}Ae&+H#t79d`trLTU=FHEA`wEtYv9QXy zoGZGw+2QiRGY#ux(Y!XycttdjndPe$_UZN1c!QUevF)}hG|A(=cc8eGXn*S&ii<2V z(l*wzW4P+*o1%kbk)pmF-`+Jx9GNm#{ET5X_w*d4Ac5P{c|R~T-&yFssIWRbNLVpnWGaF#ugzZY^UF{deuqC%RJK&s-t%zb~lVc0|wK-N*wPT2|t!q75f74{0PkOXU zHVJRk?~uPuSu_xK^PG{Eby23^nAiI`(kD@@uwksCD#PaIJE1nq!B?#uc&|Wy`cBcj z47JF2eKimCT^egaL^k&U?`0c5WkFzKpTI zg{(ZX-oOTCkk=Y zO%f|i&nVZYuu8MEb$>bg#)mC#q+tg*B2 z8dTxUim=BGK;hP)Xe5IE`xK^rP^HU2hpfC3t6(2&A9Q9Ahek~-kCWti!Ul_bUW7#G zB785wrpv`U8ra-wy%i-l8`PoGfzyyiYLWQ~evQ@IrAh-O6FYmvC|!q}{RZzZVPj5J z<1OlMa)d)~$p|Y2ug1Pvxc0csidi|RgqFZ@LDVu%JmB%2DGd$3kT|&f(;2frc#Ll= z^+#`cODUA*RQp~0!$tcu4OOQ~RcBeF%z`rfeNq;YJ}f#~6`Q-_tJ=dqV9>{(qxoCT zXP7N939kMPStF!2?a;>3>>z_oZAJKy$igf+eCb1lt=S3}vYAHpWWy|rgj5v;U}mz9 z3VPE9l0qW9@XIflkV6bHq5nzHx?n@mlrHuJavEt=#O=YPC7p=@s1l|e^}~}@;t3@m zSBEm}DMj#n(b|~a?Wp@e!n6=C zax&Pk)!o=ZB{{FyfQ%bwaxw5BYZ{zgo#avRQse6*4y$wD-C_rCCO0O}V0AKP{e?u# z?nBEv9<0CW8a*H0X6&(C6-$ zkYH~=NB_T_?kS;kkkd1hh}10-jGDvm#b8y%x|{HRIE!UuE#F1@^Su#0DNYod8(KN_ z=QGwbL+MTDvyC|#f1|KTTFJZ%b{JlLf0WRR`pVudS z95K5QFFrWpDv6a|trD~v!I#^~%oo~&$g9#s%T3w`2Zrt71Y zkt1>H-@`{*i?sMeNT3kkr;nRUGOC*;w2T~IJ6P?KR= zq&RpspT|Rnzf1W-%~zwb^mn+cP!9wAm+iEY@Nl8w4|B!y&(IHecLbsaB>{jMR2*t| z@z;s{FoAZ}NR?93fPv%oAARO0(g5s3dy!Ook-LZ)uo4}JAS362{9CDF+hu~^5Lmpn zv;1$xg8ryj`yS^fYkzy#%W?pbyR6+V0n&E5#38i(GvOyK@7imy-|d|cAa7?v9Kze5 zy}i6vaO(VT5<%il5)UEnH~n5>1|0Z5BLMEW6M+MF{5Kc<*bx92fyL90C=c230vg2c mc~nR;9&*+;f%qX0N_vVR*p#k literal 0 HcmV?d00001 diff --git a/app/test/processing/app/tools/ZipDeflaterTest.java b/app/test/processing/app/tools/ZipDeflaterTest.java new file mode 100644 index 000000000..6a147dd5c --- /dev/null +++ b/app/test/processing/app/tools/ZipDeflaterTest.java @@ -0,0 +1,81 @@ +package processing.app.tools; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.util.Arrays; +import java.util.Random; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import processing.app.tools.ZipDeflater; + +public class ZipDeflaterTest { + + private File destFolder; + + @Before + public void makeTempFolder() { + destFolder = new File(System.getProperty("java.io.tmpdir") + File.separator + "arduino_zip_test_" + new Random().nextInt(100000)); + destFolder.mkdir(); + } + + @Test + public void shouldDeflateZip() throws Exception { + File file = new File(ZipDeflater.class.getResource("/Test2.zip").getFile()); + new ZipDeflater(file, destFolder).deflate(); + + String[] files = destFolder.list(); + assertEquals(1, files.length); + assertEquals("Test2", files[0]); + + file = destFolder.listFiles()[0]; + files = file.list(); + assertEquals(5, files.length); + Arrays.sort(files); + assertEquals("Test.cpp", files[0]); + assertEquals("Test.h", files[1]); + assertEquals("examples", files[2]); + assertEquals("keywords.txt", files[3]); + assertEquals("readme.txt", files[4]); + } + + @Test + public void shouldDeflateZipAndMoveContentsToParentFolder() throws Exception { + File file = new File(ZipDeflater.class.getResource("/Test.zip").getFile()); + new ZipDeflater(file, destFolder).deflate(); + + String[] files = destFolder.list(); + assertEquals(1, files.length); + assertEquals("Test", files[0]); + + file = destFolder.listFiles()[0]; + files = file.list(); + assertEquals(5, files.length); + Arrays.sort(files); + assertEquals("Test.cpp", files[0]); + assertEquals("Test.h", files[1]); + assertEquals("examples", files[2]); + assertEquals("keywords.txt", files[3]); + assertEquals("readme.txt", files[4]); + } + + @After + public void deleteTempFolder() { + recursiveDelete(destFolder); + } + + private void recursiveDelete(File folder) { + for (File file : folder.listFiles()) { + if (file.isDirectory()) { + recursiveDelete(file); + } else { + file.delete(); + } + } + folder.delete(); + } + +}