Skip to content

Commit 6ac0e71

Browse files
authored
Local JAR Support (#20)
2 parents b0bdb96 + 573f940 commit 6ac0e71

File tree

8 files changed

+125
-26
lines changed

8 files changed

+125
-26
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ build/
1111
.classpath
1212
.settings/
1313
bin/
14+
15+
# IntelliJ
16+
.idea/
17+
out/

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- Support for local JAR file ([#20](https://github.com/diffplug/blowdryer/pull/20))
810

911
## [1.1.1] - 2021-02-12
1012
### Fixed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ plugins {
44
id 'com.diffplug.spotless-changelog'
55
id 'com.gradle.plugin-publish'
66
id 'com.jfrog.bintray'
7+
id "com.palantir.idea-test-fix" version "0.1.0" // Added to run tests successfully in IntelliJ
78
}
89

910
apply from: 干.file('base/changelog.gradle')

src/main/java/com/diffplug/blowdryer/Blowdryer.java

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
import com.diffplug.common.hash.Hashing;
2222
import com.diffplug.common.io.Files;
2323
import java.io.File;
24+
import java.io.FileNotFoundException;
2425
import java.io.IOException;
2526
import java.io.InputStream;
2627
import java.io.OutputStream;
2728
import java.net.MalformedURLException;
29+
import java.net.URI;
30+
import java.net.URISyntaxException;
2831
import java.nio.charset.StandardCharsets;
2932
import java.nio.file.Path;
3033
import java.util.Base64;
@@ -34,6 +37,8 @@
3437
import java.util.Map;
3538
import java.util.Objects;
3639
import java.util.Properties;
40+
import java.util.zip.ZipEntry;
41+
import java.util.zip.ZipFile;
3742
import okhttp3.OkHttpClient;
3843
import okhttp3.Request;
3944
import okhttp3.Response;
@@ -47,6 +52,10 @@
4752
* determined by {@link BlowdryerSetup}.
4853
*/
4954
public class Blowdryer {
55+
56+
private static final String FILE_PROTOCOL = "file:///";
57+
private static final String JAR_FILE_RESOURCE_SEPARATOR = "!/";
58+
5059
private Blowdryer() {}
5160

5261
static {
@@ -111,7 +120,7 @@ public static File immutableUrl(String url) {
111120
urlToContent.put(url, dataFile);
112121
return dataFile;
113122
}
114-
} catch (IOException e) {
123+
} catch (IOException | URISyntaxException e) {
115124
throw Errors.asRuntime(e);
116125
}
117126
}
@@ -131,7 +140,35 @@ private static Map<String, String> loadPropertyFile(File file) throws IOExceptio
131140

132141
private static final String PROP_URL = "url";
133142

134-
private static void download(String url, File dst) throws IOException {
143+
private static void download(String url, File dst) throws IOException, URISyntaxException {
144+
if (url.startsWith(FILE_PROTOCOL)) {
145+
downloadLocal(url, dst);
146+
} else {
147+
downloadRemote(url, dst);
148+
}
149+
}
150+
151+
private static void downloadLocal(String url, File dst) throws IOException, URISyntaxException {
152+
153+
String[] splitUrl = url.split(JAR_FILE_RESOURCE_SEPARATOR);
154+
if (splitUrl.length != 2) {
155+
throw new IllegalArgumentException("Expected a file URL in the format: file:///path-to-dependency.jar!/path-to-file.ext");
156+
}
157+
158+
String jarPath = splitUrl[0];
159+
String filename = splitUrl[1];
160+
161+
URI jarPathUri = new URI(jarPath);
162+
try (ZipFile jar = new ZipFile(new File(jarPathUri))) {
163+
ZipEntry foundEntry = jar.stream()
164+
.filter(s -> s.getName().equals(filename)).findAny()
165+
.orElseThrow(() -> new FileNotFoundException("Could not find '" + filename + "' in '" + jarPath + "'"));
166+
167+
java.nio.file.Files.copy(jar.getInputStream(foundEntry), dst.toPath());
168+
}
169+
}
170+
171+
private static void downloadRemote(String url, File dst) throws IOException {
135172
OkHttpClient client = new OkHttpClient.Builder().build();
136173
Request.Builder req = new Request.Builder().url(url);
137174
authPlugin.addAuthToken(url, req);
@@ -154,7 +191,7 @@ private static void download(String url, File dst) throws IOException {
154191

155192
/** Returns either the filename safe URL, or (first40)--(Base64 filenamesafe)(last40). */
156193
static String filenameSafe(String url) {
157-
String allSafeCharacters = url.replaceAll("[^a-zA-Z0-9-+_\\.]", "-");
194+
String allSafeCharacters = url.replaceAll("[^a-zA-Z0-9-+_.]", "-");
158195
String noDuplicateDash = allSafeCharacters.replaceAll("-+", "-");
159196
if (noDuplicateDash.length() <= MAX_FILE_LENGTH) {
160197
return noDuplicateDash;

src/main/java/com/diffplug/blowdryer/BlowdryerSetup.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,18 @@ private GitLab setGlobals() {
146146
}
147147
}
148148

149+
/**
150+
* Uses the provided {@code jarFile} to extract a file resource.
151+
* @param jarFile Absolute path to JAR on the file system.
152+
*/
153+
public void localJar(File jarFile) {
154+
Objects.requireNonNull(jarFile, "jarFile must not be null.");
155+
Blowdryer.setResourcePluginNull();
156+
157+
String rootUrl = "file:///" + jarFile.getAbsolutePath() + "!/";
158+
Blowdryer.setResourcePlugin(resource -> rootUrl + resource);
159+
}
160+
149161
@NotNull
150162
private String getFullResourcePath(String resource) {
151163
return (repoSubfolder.isEmpty() ? "" : repoSubfolder + "/") + resource;

src/test/java/com/diffplug/blowdryer/BlowdryerPluginTest.java

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,46 +23,56 @@
2323
import org.junit.Test;
2424

2525
public class BlowdryerPluginTest extends GradleHarness {
26+
27+
private static final String SETTINGS_GRADLE = "settings.gradle";
28+
private static final String BUILD_GRADLE = "build.gradle";
29+
2630
private void settingsGithub(String tag, String... extra) throws IOException {
27-
write("settings.gradle",
31+
write(SETTINGS_GRADLE,
2832
"plugins { id 'com.diffplug.blowdryerSetup' }",
2933
"blowdryerSetup { github('diffplug/blowdryer', 'tag', '" + tag + "') }",
3034
Arrays.stream(extra).collect(Collectors.joining("\n")));
3135
}
3236

3337
private void settingsGitlab(String tag, String... extra) throws IOException {
34-
write("settings.gradle",
38+
write(SETTINGS_GRADLE,
3539
"plugins { id 'com.diffplug.blowdryerSetup' }",
3640
"blowdryerSetup { gitlab('diffplug/blowdryer', 'tag', '" + tag + "') }",
3741
Arrays.stream(extra).collect(Collectors.joining("\n")));
3842
}
3943

4044
private void settingsCustomGitlab(String tag, String... extra) throws IOException {
41-
write("settings.gradle",
45+
write(SETTINGS_GRADLE,
4246
"plugins { id 'com.diffplug.blowdryerSetup' }",
4347
"blowdryerSetup { gitlab('diffplug/blowdryer', 'tag', '" + tag + "').customDomainHttps('gitlab.com') }",
4448
Arrays.stream(extra).collect(Collectors.joining("\n")));
4549
}
4650

4751
private void settingsGitlabRootFolder(String tag, String... extra) throws IOException {
48-
write("settings.gradle",
52+
write(SETTINGS_GRADLE,
4953
"plugins { id 'com.diffplug.blowdryerSetup' }",
5054
"blowdryerSetup { repoSubfolder(''); gitlab('diffplug/blowdryer', 'tag', '" + tag + "') }",
5155
Arrays.stream(extra).collect(Collectors.joining("\n")));
5256
}
5357

58+
private void settingsLocalJar(String dependency) throws IOException {
59+
write(SETTINGS_GRADLE,
60+
"plugins { id 'com.diffplug.blowdryerSetup' }",
61+
"blowdryerSetup { localJar(file('" + dependency + "')) }");
62+
}
63+
5464
@Test
5565
public void githubTag() throws IOException {
5666
settingsGithub("test/2/a");
57-
write("build.gradle",
67+
write(BUILD_GRADLE,
5868
"apply plugin: 'com.diffplug.blowdryer'",
5969
"assert 干.file('sample').text == 'a'",
6070
"assert 干.prop('sample', 'name') == 'test'",
6171
"assert 干.prop('sample', 'ver_spotless') == '1.2.0'");
6272
gradleRunner().build();
6373

6474
settingsGithub("test/2/b");
65-
write("build.gradle",
75+
write(BUILD_GRADLE,
6676
"apply plugin: 'com.diffplug.blowdryer'",
6777
"assert 干.file('sample').text == 'b'",
6878
"assert 干.prop('sample', 'name') == 'testB'",
@@ -71,7 +81,7 @@ public void githubTag() throws IOException {
7181

7282
// double-check that failures do fail
7383
settingsGithub("test/2/b");
74-
write("build.gradle",
84+
write(BUILD_GRADLE,
7585
"plugins { id 'com.diffplug.blowdryer' }",
7686
"assert Blowdryer.file('sample').text == 'a'");
7787
gradleRunner().buildAndFail();
@@ -80,15 +90,15 @@ public void githubTag() throws IOException {
8090
@Test
8191
public void gitlabTag() throws IOException {
8292
settingsGitlab("test/2/a");
83-
write("build.gradle",
93+
write(BUILD_GRADLE,
8494
"apply plugin: 'com.diffplug.blowdryer'",
8595
"assert 干.file('sample').text == 'a'",
8696
"assert 干.prop('sample', 'name') == 'test'",
8797
"assert 干.prop('sample', 'ver_spotless') == '1.2.0'");
8898
gradleRunner().build();
8999

90100
settingsGitlab("test/2/b");
91-
write("build.gradle",
101+
write(BUILD_GRADLE,
92102
"apply plugin: 'com.diffplug.blowdryer'",
93103
"assert 干.file('sample').text == 'b'",
94104
"assert 干.prop('sample', 'name') == 'testB'",
@@ -97,7 +107,7 @@ public void gitlabTag() throws IOException {
97107

98108
// double-check that failures do fail
99109
settingsGitlab("test/2/b");
100-
write("build.gradle",
110+
write(BUILD_GRADLE,
101111
"plugins { id 'com.diffplug.blowdryer' }",
102112
"assert Blowdryer.file('sample').text == 'a'");
103113
gradleRunner().buildAndFail();
@@ -106,15 +116,15 @@ public void gitlabTag() throws IOException {
106116
@Test
107117
public void customGitlabTag() throws IOException {
108118
settingsCustomGitlab("test/2/a");
109-
write("build.gradle",
119+
write(BUILD_GRADLE,
110120
"apply plugin: 'com.diffplug.blowdryer'",
111121
"assert 干.file('sample').text == 'a'",
112122
"assert 干.prop('sample', 'name') == 'test'",
113123
"assert 干.prop('sample', 'ver_spotless') == '1.2.0'");
114124
gradleRunner().build();
115125

116126
settingsCustomGitlab("test/2/b");
117-
write("build.gradle",
127+
write(BUILD_GRADLE,
118128
"apply plugin: 'com.diffplug.blowdryer'",
119129
"assert 干.file('sample').text == 'b'",
120130
"assert 干.prop('sample', 'name') == 'testB'",
@@ -123,7 +133,7 @@ public void customGitlabTag() throws IOException {
123133

124134
// double-check that failures do fail
125135
settingsCustomGitlab("test/2/b");
126-
write("build.gradle",
136+
write(BUILD_GRADLE,
127137
"plugins { id 'com.diffplug.blowdryer' }",
128138
"assert Blowdryer.file('sample').text == 'a'");
129139
gradleRunner().buildAndFail();
@@ -132,15 +142,15 @@ public void customGitlabTag() throws IOException {
132142
@Test
133143
public void rootfolderGitlabTag() throws IOException {
134144
settingsGitlabRootFolder("test/2/a");
135-
write("build.gradle",
145+
write(BUILD_GRADLE,
136146
"apply plugin: 'com.diffplug.blowdryer'",
137147
"assert 干.file('src/main/resources/sample').text == 'a'",
138148
"assert 干.prop('src/main/resources/sample', 'name') == 'test'",
139149
"assert 干.prop('src/main/resources/sample', 'ver_spotless') == '1.2.0'");
140150
gradleRunner().build();
141151

142152
settingsGitlabRootFolder("test/2/b");
143-
write("build.gradle",
153+
write(BUILD_GRADLE,
144154
"apply plugin: 'com.diffplug.blowdryer'",
145155
"assert 干.file('src/main/resources/sample').text == 'b'",
146156
"assert 干.prop('src/main/resources/sample', 'name') == 'testB'",
@@ -149,7 +159,7 @@ public void rootfolderGitlabTag() throws IOException {
149159

150160
// double-check that failures do fail
151161
settingsGitlabRootFolder("test/2/b");
152-
write("build.gradle",
162+
write(BUILD_GRADLE,
153163
"plugins { id 'com.diffplug.blowdryer' }",
154164
"assert Blowdryer.file('src/main/resources/sample').text == 'a'");
155165
gradleRunner().buildAndFail();
@@ -161,10 +171,10 @@ public void devLocal() throws IOException {
161171
write("../blowdryer-script/src/main/resources/sample.properties",
162172
"name=test",
163173
"group=com.diffplug.gradle");
164-
write("settings.gradle",
174+
write(SETTINGS_GRADLE,
165175
"plugins { id 'com.diffplug.blowdryerSetup' }",
166176
"blowdryerSetup { devLocal('../blowdryer-script') }");
167-
write("build.gradle",
177+
write(BUILD_GRADLE,
168178
"apply plugin: 'com.diffplug.blowdryer'",
169179
// .replace('\\r', '') fixes test on windows
170180
"assert 干.file('sample').text.replace('\\r', '') == 'c\\n'",
@@ -177,7 +187,7 @@ public void devLocal() throws IOException {
177187
public void multiproject() throws IOException {
178188
settingsGithub("test/2/a",
179189
"include 'subproject'");
180-
write("build.gradle",
190+
write(BUILD_GRADLE,
181191
"apply plugin: 'com.diffplug.blowdryer'",
182192
"assert 干.file('sample').text == 'a'",
183193
"assert 干.prop('sample', 'name') == 'test'",
@@ -199,7 +209,7 @@ public void multiproject() throws IOException {
199209
@Test
200210
public void missingResourceThrowsError() throws IOException {
201211
settingsGithub("test/2/a");
202-
write("build.gradle",
212+
write(BUILD_GRADLE,
203213
"plugins { id 'com.diffplug.blowdryer' }",
204214
"干.file('notPresent')");
205215
Assertions.assertThat(gradleRunner().buildAndFail().getOutput().replace("\r\n", "\n")).contains(
@@ -213,7 +223,7 @@ public void cfgTestGroovy() throws IOException {
213223
write("../blowdryer-script/src/main/resources/sample.properties",
214224
"name=test",
215225
"group=com.diffplug.gradle");
216-
write("settings.gradle",
226+
write(SETTINGS_GRADLE,
217227
"plugins { id 'com.diffplug.blowdryerSetup' }",
218228
"blowdryerSetup { devLocal('../blowdryer-script') }");
219229
write("../blowdryer-script/src/main/resources/script.gradle",
@@ -223,7 +233,7 @@ public void cfgTestGroovy() throws IOException {
223233
"println 干.proj(File.class, 'keyFile', 'location of the keyFile')",
224234
"println 干.prop('sample', 'group')",
225235
"");
226-
write("build.gradle",
236+
write(BUILD_GRADLE,
227237
"apply plugin: 'com.diffplug.blowdryer'",
228238
"ext.pluginPass = 'supersecret'",
229239
"ext.keyFile = new File('keyFile.txt')",
@@ -267,7 +277,7 @@ public void cfgTestKotlin() throws IOException {
267277

268278
@Test
269279
public void settingsTest() throws IOException {
270-
write("settings.gradle",
280+
write(SETTINGS_GRADLE,
271281
"plugins { id 'com.diffplug.blowdryerSetup' }",
272282
"blowdryerSetup { github('diffplug/blowdryer', 'tag', 'test/2/a') }",
273283
"import com.diffplug.blowdryer.干",
@@ -277,4 +287,28 @@ public void settingsTest() throws IOException {
277287
"println 'test was success'");
278288
Assertions.assertThat(gradleRunner().build().getOutput().replace("\r\n", "\n"));
279289
}
290+
291+
@Test
292+
public void localJarFileDownloadExists() throws IOException {
293+
String jarFile = BlowdryerPluginTest.class.getResource("test.jar").getFile();
294+
settingsLocalJar(jarFile);
295+
296+
write(BUILD_GRADLE,
297+
"apply plugin: 'com.diffplug.blowdryer'",
298+
"assert 干.file('sample').exists()");
299+
300+
gradleRunner().build();
301+
}
302+
303+
@Test
304+
public void localJarFileDownloadDoesNotExist() throws IOException {
305+
String jarFile = BlowdryerPluginTest.class.getResource("test.jar").getFile();
306+
settingsLocalJar(jarFile);
307+
308+
write(BUILD_GRADLE,
309+
"apply plugin: 'com.diffplug.blowdryer'",
310+
"assert 干.file('invalid-file.txt').exists()");
311+
312+
gradleRunner().buildAndFail();
313+
}
280314
}

src/test/java/com/diffplug/blowdryer/BlowdryerTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import org.junit.Test;
2121

2222
public class BlowdryerTest {
23+
private static final String JAR_FILE_RESOURCE_SEPARATOR = "!/";
24+
private static final String FILE_PROTOCOL = "file:///";
25+
2326
@Test
2427
public void filenameSafe() {
2528
filenameSafe("http://shortName.com/a+b-0-9~Z", "http-shortName.com-a+b-0-9-Z");
@@ -38,4 +41,10 @@ public void cachedFileDeleted_issue_11() {
3841
Blowdryer.immutableUrl(test).delete();
3942
Assertions.assertThat(Blowdryer.immutableUrl(test)).hasContent("b");
4043
}
44+
45+
@Test
46+
public void immutableUrlOfLocalJar() {
47+
String jarFile = BlowdryerPluginTest.class.getResource("test.jar").getFile();
48+
Assertions.assertThat(Blowdryer.immutableUrl(FILE_PROTOCOL + jarFile + JAR_FILE_RESOURCE_SEPARATOR + "sample")).exists();
49+
}
4150
}
164 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)