Skip to content

Commit 324a9bc

Browse files
authored
Merge pull request #9023 from mattiabertorello/add-file-cache
Add file downloader cache to make faster the library/boards manager
2 parents ba34eb6 + 9ce5101 commit 324a9bc

28 files changed

+1167
-229
lines changed

Diff for: .classpath

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
<classpathentry kind="src" path="app/test"/>
55
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
66
<classpathentry kind="lib" path="app/lib/apple.jar"/>
7-
<classpathentry kind="lib" path="app/lib/ecj.jar"/>
87
<classpathentry kind="lib" path="app/test-lib/junit-4.11.jar"/>
98
<classpathentry kind="lib" path="app/test-lib/fest-assert-1.2.jar"/>
109
<classpathentry kind="lib" path="app/test-lib/fest-reflect-1.2.jar"/>
@@ -16,10 +15,10 @@
1615
<classpathentry kind="lib" path="app/lib/commons-httpclient-3.1.jar"/>
1716
<classpathentry kind="lib" path="app/lib/commons-logging-1.0.4.jar"/>
1817
<classpathentry kind="lib" path="app/lib/commons-net-3.3.jar"/>
19-
<classpathentry kind="lib" path="app/lib/jmdns-3.5.1.jar"/>
18+
<classpathentry kind="lib" path="app/lib/jmdns-3.5.3.jar"/>
2019
<classpathentry kind="lib" path="app/lib/slf4j-api-1.7.22.jar"/>
2120
<classpathentry kind="lib" path="app/lib/jsch-0.1.50.jar"/>
22-
<classpathentry kind="lib" path="app/lib/jssc-2.8.0.jar"/>
21+
<classpathentry kind="lib" path="app/lib/jssc-2.8.0-arduino3.jar"/>
2322
<classpathentry kind="lib" path="app/lib/bcpg-jdk15on-152.jar"/>
2423
<classpathentry kind="lib" path="app/lib/bcprov-jdk15on-152.jar"/>
2524
<classpathentry kind="lib" path="app/lib/jackson-core-2.9.5.jar"/>

Diff for: app/.classpath

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
<classpathentry kind="lib" path="lib/jmdns-3.5.3.jar"/>
4040
<classpathentry kind="lib" path="lib/slf4j-api-1.7.22.jar"/>
4141
<classpathentry kind="lib" path="lib/slf4j-simple-1.7.22.jar"/>
42+
<classpathentry kind="lib" path="lib/log4j-api-2.12.0.jar"/>
43+
<classpathentry kind="lib" path="lib/log4j-core-2.12.0.jar"/>
4244
<classpathentry kind="lib" path="lib/jsch-0.1.50.jar"/>
4345
<classpathentry kind="lib" path="lib/jssc-2.8.0-arduino3.jar"/>
4446
<classpathentry kind="lib" path="lib/rsyntaxtextarea-3.0.3-SNAPSHOT.jar"/>

Diff for: app/build.xml

+4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@
8080
includeAntRuntime="false"
8181
debug="true"
8282
classpathref="class.path" />
83+
<!-- If you want to add files in the jars -->
84+
<copy todir="bin" overwrite="true" verbose="true">
85+
<fileset dir="src" includes="log4j2.xml" />
86+
</copy>
8387
</target>
8488

8589
<target name="test" depends="compile" description="Runs the test">

Diff for: app/lib/commons-io-2.6.jar

210 KB
Binary file not shown.

Diff for: app/lib/log4j-api-2.12.0.jar

267 KB
Binary file not shown.

Diff for: app/lib/log4j-core-2.12.0.jar

1.59 MB
Binary file not shown.

Diff for: app/src/log4j2.xml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Configuration status="warn" name="Arduino" packages="cc.arduino">
3+
<Appenders>
4+
5+
<!-- Console Appender -->
6+
<Console name="Console" target="SYSTEM_ERR">
7+
<PatternLayout pattern="%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}{UTC} %p %c{1.} [%t] %m%n" />
8+
</Console>
9+
10+
<!-- Rolling File Appender -->
11+
<RollingFile name="RollingFile" fileName="${sys:log4j.saveDirectory}/logs/application.log"
12+
filePattern="${sys:log4j.saveDirectory}/logs/application-%d{MM-dd-yyyy}-%i.log.gz"
13+
ignoreExceptions="false">
14+
<PatternLayout>
15+
<Pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}{UTC} %p %c{1.} [%t] %m%n</Pattern>
16+
</PatternLayout>
17+
<Policies>
18+
<SizeBasedTriggeringPolicy size="50 MB"/>
19+
</Policies>
20+
<DefaultRolloverStrategy max="20"/>
21+
</RollingFile>
22+
</Appenders>
23+
<Loggers>
24+
<Root level="debug">
25+
<AppenderRef ref="Console" level="info" />
26+
<AppenderRef ref="RollingFile"/>
27+
</Root>
28+
</Loggers>
29+
</Configuration>

Diff for: app/src/processing/app/Base.java

+13-11
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,29 @@
2626
import cc.arduino.Constants;
2727
import cc.arduino.UpdatableBoardsLibsFakeURLsHandler;
2828
import cc.arduino.UploaderUtils;
29-
import cc.arduino.packages.Uploader;
3029
import cc.arduino.contributions.*;
31-
import cc.arduino.contributions.libraries.*;
30+
import cc.arduino.contributions.libraries.ContributedLibrary;
31+
import cc.arduino.contributions.libraries.LibrariesIndexer;
32+
import cc.arduino.contributions.libraries.LibraryInstaller;
33+
import cc.arduino.contributions.libraries.LibraryOfSameTypeComparator;
3234
import cc.arduino.contributions.libraries.ui.LibraryManagerUI;
3335
import cc.arduino.contributions.packages.ContributedPlatform;
3436
import cc.arduino.contributions.packages.ContributionInstaller;
3537
import cc.arduino.contributions.packages.ContributionsIndexer;
3638
import cc.arduino.contributions.packages.ui.ContributionManagerUI;
3739
import cc.arduino.files.DeleteFilesOnShutdown;
3840
import cc.arduino.packages.DiscoveryManager;
41+
import cc.arduino.packages.Uploader;
3942
import cc.arduino.view.Event;
4043
import cc.arduino.view.JMenuUtils;
4144
import cc.arduino.view.SplashScreenHelper;
42-
45+
import com.github.zafarkhaja.semver.Version;
4346
import org.apache.commons.compress.utils.IOUtils;
4447
import org.apache.commons.lang3.StringUtils;
45-
46-
import com.github.zafarkhaja.semver.Version;
47-
4848
import processing.app.debug.TargetBoard;
4949
import processing.app.debug.TargetPackage;
5050
import processing.app.debug.TargetPlatform;
5151
import processing.app.helpers.*;
52-
import processing.app.helpers.OSUtils;
5352
import processing.app.helpers.filefilters.OnlyDirs;
5453
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
5554
import processing.app.javax.swing.filechooser.FileNameExtensionFilter;
@@ -67,9 +66,9 @@
6766
import java.awt.*;
6867
import java.awt.event.*;
6968
import java.io.*;
70-
import java.util.*;
7169
import java.util.List;
7270
import java.util.Timer;
71+
import java.util.*;
7372
import java.util.logging.Handler;
7473
import java.util.logging.Level;
7574
import java.util.logging.Logger;
@@ -208,6 +207,8 @@ public Base(String[] args) throws Exception {
208207
BaseNoGui.getPlatform().init();
209208

210209
BaseNoGui.initPortableFolder();
210+
// This configure the logs root folder
211+
System.setProperty("log4j.saveDirectory", BaseNoGui.getSettingsFolder().getAbsolutePath());
211212

212213
// Look for a possible "--preferences-file" parameter and load preferences
213214
BaseNoGui.initParameters(args);
@@ -286,8 +287,9 @@ public Base(String[] args) throws Exception {
286287
pdeKeywords = new PdeKeywords();
287288
pdeKeywords.reload();
288289

289-
contributionInstaller = new ContributionInstaller(BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier());
290-
libraryInstaller = new LibraryInstaller(BaseNoGui.getPlatform());
290+
final GPGDetachedSignatureVerifier gpgDetachedSignatureVerifier = new GPGDetachedSignatureVerifier();
291+
contributionInstaller = new ContributionInstaller(BaseNoGui.getPlatform(), gpgDetachedSignatureVerifier);
292+
libraryInstaller = new LibraryInstaller(BaseNoGui.getPlatform(), gpgDetachedSignatureVerifier);
291293

292294
parser.parseArgumentsPhase2();
293295

@@ -301,7 +303,7 @@ public Base(String[] args) throws Exception {
301303
if (parser.isInstallBoard()) {
302304
ContributionsIndexer indexer = new ContributionsIndexer(
303305
BaseNoGui.getSettingsFolder(), BaseNoGui.getHardwareFolder(),
304-
BaseNoGui.getPlatform(), new GPGDetachedSignatureVerifier());
306+
BaseNoGui.getPlatform(), gpgDetachedSignatureVerifier);
305307
ProgressListener progressListener = new ConsoleProgressListener();
306308

307309
List<String> downloadedPackageIndexFiles = contributionInstaller.updateIndex(progressListener);

Diff for: arduino-core/.classpath

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
<classpathentry kind="lib" path="lib/jmdns-3.5.3.jar"/>
99
<classpathentry kind="lib" path="lib/slf4j-api-1.7.22.jar"/>
1010
<classpathentry kind="lib" path="lib/slf4j-simple-1.7.22.jar"/>
11+
<classpathentry kind="lib" path="lib/log4j-api-2.12.0.jar"/>
12+
<classpathentry kind="lib" path="lib/log4j-core-2.12.0.jar"/>
1113
<classpathentry kind="lib" path="lib/jssc-2.8.0-arduino3.jar"/>
1214
<classpathentry kind="lib" path="lib/jsch-0.1.50.jar"/>
1315
<classpathentry kind="lib" path="lib/commons-exec-1.1.jar"/>

Diff for: arduino-core/lib/commons-io-2.6.jar

210 KB
Binary file not shown.

Diff for: arduino-core/lib/log4j-api-2.12.0.jar

267 KB
Binary file not shown.

Diff for: arduino-core/lib/log4j-core-2.12.0.jar

1.59 MB
Binary file not shown.

Diff for: arduino-core/src/cc/arduino/contributions/DownloadableContributionsDownloader.java

+107-12
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,37 @@
3030
package cc.arduino.contributions;
3131

3232
import cc.arduino.utils.FileHash;
33+
import cc.arduino.utils.MultiStepProgress;
3334
import cc.arduino.utils.Progress;
3435
import cc.arduino.utils.network.FileDownloader;
36+
import org.apache.commons.io.FilenameUtils;
37+
import org.apache.logging.log4j.LogManager;
38+
import org.apache.logging.log4j.Logger;
39+
import processing.app.BaseNoGui;
40+
import processing.app.PreferencesData;
3541

3642
import java.io.File;
3743
import java.net.URL;
38-
import java.nio.file.Files;
39-
import java.nio.file.LinkOption;
40-
import java.nio.file.Path;
41-
import java.nio.file.Paths;
44+
import java.nio.file.*;
45+
import java.util.Collection;
4246

4347
import static processing.app.I18n.format;
4448
import static processing.app.I18n.tr;
4549

4650
public class DownloadableContributionsDownloader {
51+
private static Logger log = LogManager.getLogger(DownloadableContributionsDownloader.class);
4752

4853
private final File stagingFolder;
4954

5055
public DownloadableContributionsDownloader(File _stagingFolder) {
5156
stagingFolder = _stagingFolder;
5257
}
5358

54-
public File download(DownloadableContribution contribution, Progress progress, final String statusText, ProgressListener progressListener) throws Exception {
55-
return download(contribution, progress, statusText, progressListener, false);
59+
public File download(DownloadableContribution contribution, Progress progress, final String statusText, ProgressListener progressListener, boolean allowCache) throws Exception {
60+
return download(contribution, progress, statusText, progressListener, false, allowCache);
5661
}
5762

58-
public File download(DownloadableContribution contribution, Progress progress, final String statusText, ProgressListener progressListener, boolean noResume) throws Exception {
63+
public File download(DownloadableContribution contribution, Progress progress, final String statusText, ProgressListener progressListener, boolean noResume, boolean allowCache) throws Exception {
5964
URL url = new URL(contribution.getUrl());
6065
Path outputFile = Paths.get(stagingFolder.getAbsolutePath(), contribution.getArchiveFileName());
6166

@@ -70,7 +75,7 @@ public File download(DownloadableContribution contribution, Progress progress, f
7075
while (true) {
7176
// Need to download or resume downloading?
7277
if (!Files.isRegularFile(outputFile, LinkOption.NOFOLLOW_LINKS) || (Files.size(outputFile) < contribution.getSize())) {
73-
download(url, outputFile.toFile(), progress, statusText, progressListener, noResume);
78+
download(url, outputFile.toFile(), progress, statusText, progressListener, noResume, allowCache);
7479
downloaded = true;
7580
}
7681

@@ -116,12 +121,12 @@ private boolean hasChecksum(DownloadableContribution contribution) {
116121
return algo != null && !algo.isEmpty();
117122
}
118123

119-
public void download(URL url, File tmpFile, Progress progress, String statusText, ProgressListener progressListener) throws Exception {
120-
download(url, tmpFile, progress, statusText, progressListener, false);
124+
public void download(URL url, File tmpFile, Progress progress, String statusText, ProgressListener progressListener, boolean allowCache) throws Exception {
125+
download(url, tmpFile, progress, statusText, progressListener, false, allowCache);
121126
}
122127

123-
public void download(URL url, File tmpFile, Progress progress, String statusText, ProgressListener progressListener, boolean noResume) throws Exception {
124-
FileDownloader downloader = new FileDownloader(url, tmpFile);
128+
public void download(URL url, File tmpFile, Progress progress, String statusText, ProgressListener progressListener, boolean noResume, boolean allowCache) throws Exception {
129+
final FileDownloader downloader = new FileDownloader(url, tmpFile, allowCache);
125130
downloader.addObserver((o, arg) -> {
126131
FileDownloader me = (FileDownloader) o;
127132
String msg = "";
@@ -140,4 +145,94 @@ public void download(URL url, File tmpFile, Progress progress, String statusText
140145
}
141146
}
142147

148+
public void downloadIndexAndSignature(MultiStepProgress progress, URL packageIndexUrl, ProgressListener progressListener, SignatureVerifier signatureVerifier) throws Exception {
149+
150+
// Extract the file name from the url
151+
final String indexFileName = FilenameUtils.getName(packageIndexUrl.getPath());
152+
final File packageIndex = BaseNoGui.indexer.getIndexFile(indexFileName);
153+
154+
final String statusText = tr("Downloading platforms index...");
155+
156+
// Create temp files
157+
final File packageIndexTemp = File.createTempFile(indexFileName, ".tmp");
158+
try {
159+
// Download package index
160+
download(packageIndexUrl, packageIndexTemp, progress, statusText, progressListener, true, true);
161+
final URL signatureUrl = new URL(packageIndexUrl.toString() + ".sig");
162+
163+
if (verifyDomain(packageIndexUrl)) {
164+
if (checkSignature(progress, signatureUrl, progressListener, signatureVerifier, statusText, packageIndexTemp)) {
165+
Files.move(packageIndexTemp.toPath(), packageIndex.toPath(), StandardCopyOption.REPLACE_EXISTING);
166+
} else {
167+
log.info("The cached files have been removed. {} {}", packageIndexUrl, signatureUrl);
168+
FileDownloader.invalidateFiles(packageIndexUrl, signatureUrl);
169+
}
170+
} else {
171+
// Move the package index to the destination when the signature is not necessary
172+
Files.move(packageIndexTemp.toPath(), packageIndex.toPath(), StandardCopyOption.REPLACE_EXISTING);
173+
log.info("The domain is not selected to verify the signature. will be copied into this path {}, packageIndex url: {}", packageIndex, packageIndexUrl);
174+
}
175+
} catch (Exception e) {
176+
log.error("Cannot download the package index from {} the package will be discard", packageIndexUrl, e);
177+
throw e;
178+
} finally {
179+
// Delete useless temp file
180+
Files.deleteIfExists(packageIndexTemp.toPath());
181+
}
182+
}
183+
184+
public boolean verifyDomain(URL url) {
185+
final Collection<String> domain = PreferencesData.
186+
getCollection("http.signature_verify_domains");
187+
if (domain.size() == 0) {
188+
// Default domain
189+
domain.add("downloads.arduino.cc");
190+
}
191+
if (domain.contains(url.getHost())) {
192+
return true;
193+
} else {
194+
log.info("The domain is not selected to verify the signature. domain list: {}, url: {}", domain, url);
195+
return false;
196+
}
197+
}
198+
199+
public boolean checkSignature(MultiStepProgress progress, URL signatureUrl, ProgressListener progressListener, SignatureVerifier signatureVerifier, String statusText, File fileToVerify) throws Exception {
200+
201+
final boolean allowInsecurePackages =
202+
PreferencesData.getBoolean("allow_insecure_packages", false);
203+
if (allowInsecurePackages) {
204+
log.info("Allow insecure packages is true the signature will be skip and return always verified");
205+
return true;
206+
}
207+
208+
// Signature file name
209+
final String signatureFileName = FilenameUtils.getName(signatureUrl.getPath());
210+
final File packageIndexSignature = BaseNoGui.indexer.getIndexFile(signatureFileName);
211+
final File packageIndexSignatureTemp = File.createTempFile(signatureFileName, ".tmp");
212+
213+
214+
try {
215+
// Download signature
216+
download(signatureUrl, packageIndexSignatureTemp, progress, statusText, progressListener, true);
217+
218+
// Verify the signature before move the files
219+
final boolean signatureVerified = signatureVerifier.isSigned(fileToVerify, packageIndexSignatureTemp);
220+
if (signatureVerified) {
221+
log.info("Signature verified. url={}, signature url={}, file to verify={}, signature file={}", signatureUrl, signatureUrl, fileToVerify, packageIndexSignatureTemp);
222+
// Move if the signature is ok
223+
Files.move(packageIndexSignatureTemp.toPath(), packageIndexSignature.toPath(), StandardCopyOption.REPLACE_EXISTING);
224+
} else {
225+
log.error("{} file signature verification failed. File ignored.", signatureUrl);
226+
System.err.println(format(tr("{0} file signature verification failed. File ignored."), signatureUrl.toString()));
227+
}
228+
return signatureVerified;
229+
} catch (Exception e) {
230+
log.error("Cannot download the signature from {} the package will be discard", signatureUrl, e);
231+
throw e;
232+
} finally {
233+
Files.deleteIfExists(packageIndexSignatureTemp.toPath());
234+
}
235+
236+
}
237+
143238
}

Diff for: arduino-core/src/cc/arduino/contributions/GZippedJsonDownloader.java

+15-8
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@
2929

3030
package cc.arduino.contributions;
3131

32+
import cc.arduino.Constants;
3233
import cc.arduino.utils.Progress;
3334
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
3435
import org.apache.commons.compress.compressors.gzip.GzipUtils;
3536
import org.apache.commons.compress.utils.IOUtils;
37+
import org.apache.commons.io.FilenameUtils;
3638

3739
import java.io.*;
3840
import java.net.URL;
41+
import java.nio.file.Files;
3942

4043
public class GZippedJsonDownloader {
4144

@@ -49,18 +52,22 @@ public GZippedJsonDownloader(DownloadableContributionsDownloader downloader, URL
4952
this.gzippedUrl = gzippedUrl;
5053
}
5154

52-
public void download(File tmpFile, Progress progress, String statusText, ProgressListener progressListener) throws Exception {
55+
public void download(File tmpFile, Progress progress, String statusText, ProgressListener progressListener, boolean allowCache) throws Exception {
56+
File gzipTmpFile = null;
5357
try {
54-
File gzipTmpFile = new File(tmpFile.getParentFile(), GzipUtils.getCompressedFilename(tmpFile.getName()));
58+
String tmpFileName = FilenameUtils.getName(new URL(Constants.LIBRARY_INDEX_URL_GZ).getPath());
59+
gzipTmpFile = File.createTempFile(tmpFileName, GzipUtils.getCompressedFilename(tmpFile.getName()));
5560
// remove eventual leftovers from previous downloads
56-
if (gzipTmpFile.exists()) {
57-
gzipTmpFile.delete();
58-
}
59-
new JsonDownloader(downloader, gzippedUrl).download(gzipTmpFile, progress, statusText, progressListener);
61+
Files.deleteIfExists(gzipTmpFile.toPath());
62+
63+
new JsonDownloader(downloader, gzippedUrl).download(gzipTmpFile, progress, statusText, progressListener, allowCache);
6064
decompress(gzipTmpFile, tmpFile);
61-
gzipTmpFile.delete();
6265
} catch (Exception e) {
63-
new JsonDownloader(downloader, url).download(tmpFile, progress, statusText, progressListener);
66+
new JsonDownloader(downloader, url).download(tmpFile, progress, statusText, progressListener, allowCache);
67+
} finally {
68+
if (gzipTmpFile != null) {
69+
Files.deleteIfExists(gzipTmpFile.toPath());
70+
}
6471
}
6572
}
6673

Diff for: arduino-core/src/cc/arduino/contributions/JsonDownloader.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ public JsonDownloader(DownloadableContributionsDownloader downloader, URL url) {
4444
this.url = url;
4545
}
4646

47-
public void download(File tmpFile, Progress progress, String statusText, ProgressListener progressListener) throws Exception {
47+
public void download(File tmpFile, Progress progress, String statusText, ProgressListener progressListener, boolean allowCache) throws Exception {
4848
try {
49-
downloader.download(url, tmpFile, progress, statusText, progressListener);
49+
downloader.download(url, tmpFile, progress, statusText, progressListener, allowCache);
5050
} catch (InterruptedException e) {
5151
// Download interrupted... just exit
5252
}

Diff for: arduino-core/src/cc/arduino/contributions/SignatureVerifier.java

+9
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ public boolean isSigned(File indexFile) {
5050
}
5151
}
5252

53+
public boolean isSigned(File indexFile, File signature) {
54+
try {
55+
return verify(indexFile, signature, new File(BaseNoGui.getContentFile("lib"), "public.gpg.key"));
56+
} catch (Exception e) {
57+
BaseNoGui.showWarning(e.getMessage(), e.getMessage(), e);
58+
return false;
59+
}
60+
}
61+
5362
protected abstract boolean verify(File signedFile, File signature, File publicKey) throws IOException;
5463

5564
}

0 commit comments

Comments
 (0)