S101Configurer.java 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * Copyright 2004-present the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * https://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package s101;
  17. import java.io.File;
  18. import java.io.FileOutputStream;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.io.InputStreamReader;
  22. import java.io.OutputStream;
  23. import java.io.OutputStreamWriter;
  24. import java.io.PrintWriter;
  25. import java.io.UncheckedIOException;
  26. import java.net.URL;
  27. import java.nio.file.Files;
  28. import java.nio.file.Path;
  29. import java.util.ArrayList;
  30. import java.util.HashMap;
  31. import java.util.LinkedHashMap;
  32. import java.util.List;
  33. import java.util.Map;
  34. import java.util.Set;
  35. import java.util.regex.Pattern;
  36. import java.util.zip.ZipEntry;
  37. import java.util.zip.ZipInputStream;
  38. import com.github.mustachejava.DefaultMustacheFactory;
  39. import com.github.mustachejava.Mustache;
  40. import com.github.mustachejava.MustacheFactory;
  41. import org.apache.commons.io.IOUtils;
  42. import org.gradle.api.Project;
  43. import org.gradle.api.logging.Logger;
  44. import org.gradle.api.tasks.SourceSet;
  45. import org.gradle.api.tasks.SourceSetContainer;
  46. import org.springframework.core.io.ClassPathResource;
  47. import org.springframework.core.io.Resource;
  48. public class S101Configurer {
  49. private static final Pattern VERSION = Pattern.compile("<local-project .* version=\"(.*?)\"");
  50. private static final int BUFFER = 1024;
  51. private static final long TOOBIG = 0x10000000; // ~268M
  52. private static final int TOOMANY = 200;
  53. private final MustacheFactory mustache = new DefaultMustacheFactory();
  54. private final Mustache hspTemplate;
  55. private final Mustache repositoryTemplate;
  56. private final Path licenseDirectory;
  57. private final String repository;
  58. private final String version;
  59. private final Project project;
  60. private final Logger logger;
  61. public S101Configurer(Project project) {
  62. this.project = project;
  63. this.logger = project.getLogger();
  64. Resource template = new ClassPathResource("s101/project.java.hsp");
  65. try (InputStream is = template.getInputStream()) {
  66. this.hspTemplate = this.mustache.compile(new InputStreamReader(is), "project");
  67. } catch (IOException ex) {
  68. throw new UncheckedIOException(ex);
  69. }
  70. template = new ClassPathResource("s101/repository.xml");
  71. try (InputStream is = template.getInputStream()) {
  72. this.repositoryTemplate = this.mustache.compile(new InputStreamReader(is), "repository");
  73. } catch (IOException ex) {
  74. throw new UncheckedIOException(ex);
  75. }
  76. this.licenseDirectory = new File(System.getProperty("user.home") + "/.Structure101/java").toPath();
  77. S101PluginExtension extension = project.getExtensions().getByType(S101PluginExtension.class);
  78. this.repository = extension.getRepository().get();
  79. this.version = extension.getVersion().get();
  80. }
  81. public void license(String licenseId) {
  82. Path licenseFile = this.licenseDirectory.resolve(".structure101license.properties");
  83. if (needsLicense(licenseFile, licenseId)) {
  84. writeLicense(licenseFile, licenseId);
  85. }
  86. }
  87. private boolean needsLicense(Path licenseFile, String licenseId) {
  88. if (!licenseFile.toFile().exists()) {
  89. return true;
  90. }
  91. try {
  92. String license = new String(Files.readAllBytes(licenseFile));
  93. return !license.contains(licenseId);
  94. } catch (IOException ex) {
  95. throw new RuntimeException(ex);
  96. }
  97. }
  98. private void writeLicense(Path licenseFile, String licenseId) {
  99. if (!this.licenseDirectory.toFile().mkdirs()) {
  100. this.licenseDirectory.forEach((path) -> path.toFile().delete());
  101. }
  102. try (PrintWriter pw = new PrintWriter(licenseFile.toFile())) {
  103. pw.println("licensecode=" + licenseId);
  104. } catch (IOException ex) {
  105. throw new RuntimeException(ex);
  106. }
  107. }
  108. public void install(File installationDirectory, File configurationDirectory) {
  109. deleteDirectory(installationDirectory);
  110. installBuildTool(installationDirectory, configurationDirectory);
  111. }
  112. public void configure(File installationDirectory, File configurationDirectory) {
  113. deleteDirectory(configurationDirectory);
  114. configureProject(this.version, configurationDirectory);
  115. }
  116. private boolean deleteDirectory(File directoryToBeDeleted) {
  117. File[] allContents = directoryToBeDeleted.listFiles();
  118. if (allContents != null) {
  119. for (File file : allContents) {
  120. deleteDirectory(file);
  121. }
  122. }
  123. return directoryToBeDeleted.delete();
  124. }
  125. private String installBuildTool(File installationDirectory, File configurationDirectory) {
  126. copyZipToFilesystem(this.repository, installationDirectory, "structure101-build-java-all-" + this.version);
  127. return this.version;
  128. }
  129. private void copyZipToFilesystem(String source, File destination, String name) {
  130. try (ZipInputStream in = new ZipInputStream(new URL(source + "/" + name + ".zip").openStream())) {
  131. ZipEntry entry;
  132. String build = destination.getName();
  133. int entries = 0;
  134. long size = 0;
  135. while ((entry = in.getNextEntry()) != null) {
  136. if (entry.getName().equals(name + "/")) {
  137. destination.mkdirs();
  138. } else if (entry.getName().startsWith(name)) {
  139. if (entries++ > TOOMANY) {
  140. throw new IllegalArgumentException("Zip file has more entries than expected");
  141. }
  142. if (size + BUFFER > TOOBIG) {
  143. throw new IllegalArgumentException("Zip file is larger than expected");
  144. }
  145. String filename = entry.getName().replace(name, build);
  146. if (filename.contains("maven")) {
  147. continue;
  148. }
  149. if (filename.contains("jxbrowser")) {
  150. continue;
  151. }
  152. if (filename.contains("jetty")) {
  153. continue;
  154. }
  155. if (filename.contains("jfreechart")) {
  156. continue;
  157. }
  158. if (filename.contains("piccolo2d")) {
  159. continue;
  160. }
  161. if (filename.contains("plexus")) {
  162. continue;
  163. }
  164. if (filename.contains("websocket")) {
  165. continue;
  166. }
  167. validateFilename(filename, build);
  168. this.logger.info("Downloading " + filename);
  169. try (OutputStream out = new FileOutputStream(new File(destination.getParentFile(), filename))) {
  170. byte[] data = new byte[BUFFER];
  171. int read;
  172. while ((read = in.read(data, 0, BUFFER)) != -1 && TOOBIG - size >= read) {
  173. out.write(data, 0, read);
  174. size += read;
  175. }
  176. }
  177. }
  178. }
  179. } catch (IOException e) {
  180. throw new RuntimeException(e);
  181. }
  182. }
  183. private String validateFilename(String filename, String intendedDir)
  184. throws java.io.IOException {
  185. File f = new File(filename);
  186. String canonicalPath = f.getCanonicalPath();
  187. File iD = new File(intendedDir);
  188. String canonicalID = iD.getCanonicalPath();
  189. if (canonicalPath.startsWith(canonicalID)) {
  190. return canonicalPath;
  191. } else {
  192. throw new IllegalArgumentException("File is outside extraction target directory.");
  193. }
  194. }
  195. private void configureProject(String version, File configurationDirectory) {
  196. configurationDirectory.mkdirs();
  197. Map<String, Object> model = hspTemplateValues(version, configurationDirectory);
  198. copyToProject(this.hspTemplate, model, new File(configurationDirectory, "project.java.hsp"));
  199. copyToProject("s101/config.xml", new File(configurationDirectory, "config.xml"));
  200. File repository = new File(configurationDirectory, "repository");
  201. File snapshots = new File(repository, "snapshots");
  202. if (!snapshots.exists() && !snapshots.mkdirs()) {
  203. throw new IllegalStateException("Unable to create snapshots directory");
  204. }
  205. copyToProject(this.repositoryTemplate, model, new File(repository, "repository.xml"));
  206. }
  207. private void copyToProject(String location, File destination) {
  208. Resource resource = new ClassPathResource(location);
  209. try (InputStream is = resource.getInputStream();
  210. OutputStream os = new FileOutputStream(destination)) {
  211. IOUtils.copy(is, os);
  212. } catch (IOException ex) {
  213. throw new UncheckedIOException(ex);
  214. }
  215. }
  216. private void copyToProject(Mustache view, Map<String, Object> model, File destination) {
  217. try (OutputStream os = new FileOutputStream(destination)) {
  218. view.execute(new OutputStreamWriter(os), model).flush();
  219. } catch (IOException ex) {
  220. throw new UncheckedIOException(ex);
  221. }
  222. }
  223. private Map<String, Object> hspTemplateValues(String version, File configurationDirectory) {
  224. Map<String, Object> values = new LinkedHashMap<>();
  225. values.put("version", version);
  226. values.put("patchVersion", version.split("\\.")[2]);
  227. values.put("relativeTo", "const(THIS_FILE)/" + configurationDirectory.toPath().relativize(this.project.getProjectDir().toPath()));
  228. List<Map<String, Object>> entries = new ArrayList<>();
  229. Set<Project> projects = this.project.getAllprojects();
  230. for (Project p : projects) {
  231. SourceSetContainer sourceSets = (SourceSetContainer) p.getExtensions().findByName("sourceSets");
  232. if (sourceSets == null) {
  233. continue;
  234. }
  235. for (SourceSet source : sourceSets) {
  236. Set<File> classDirs = source.getOutput().getClassesDirs().getFiles();
  237. for (File directory : classDirs) {
  238. Map<String, Object> entry = new HashMap<>();
  239. entry.put("path", this.project.getProjectDir().toPath().relativize(directory.toPath()));
  240. entry.put("module", p.getName());
  241. entries.add(entry);
  242. }
  243. }
  244. }
  245. values.put("entries", entries);
  246. return values;
  247. }
  248. }