PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/frontend-plugin-core/src/main/java/com/github/eirslett/maven/plugins/frontend/lib/NodeAndNPMInstaller.java

https://gitlab.com/robsonEXD/frontend-maven-plugin
Java | 232 lines | 195 code | 32 blank | 5 comment | 27 complexity | 82b5eeccabd776b3008cc582d9a582dd MD5 | raw file
  1. package com.github.eirslett.maven.plugins.frontend.lib;
  2. import org.apache.commons.io.FileUtils;
  3. import org.codehaus.jackson.map.ObjectMapper;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import java.io.File;
  7. import java.io.FileNotFoundException;
  8. import java.io.IOException;
  9. import java.util.Arrays;
  10. import java.util.HashMap;
  11. public interface NodeAndNPMInstaller {
  12. String DEFAULT_NODEJS_DOWNLOAD_ROOT = "http://nodejs.org/dist/";
  13. String DEFAULT_NPM_DOWNLOAD_ROOT = "http://registry.npmjs.org/npm/-/";
  14. void install(String nodeVersion, String npmVersion, String nodeDownloadRoot, String npmDownloadRoot) throws InstallationException;
  15. }
  16. final class DefaultNodeAndNPMInstaller implements NodeAndNPMInstaller {
  17. private final Logger logger;
  18. private final InstallConfig config;
  19. private final ArchiveExtractor archiveExtractor;
  20. private final FileDownloader fileDownloader;
  21. DefaultNodeAndNPMInstaller(InstallConfig config, ArchiveExtractor archiveExtractor, FileDownloader fileDownloader) {
  22. this.logger = LoggerFactory.getLogger(getClass());
  23. this.config = config;
  24. this.archiveExtractor = archiveExtractor;
  25. this.fileDownloader = fileDownloader;
  26. }
  27. @Override
  28. public void install(String nodeVersion, String npmVersion, String nodeDownloadRoot, String npmDownloadRoot) throws InstallationException {
  29. if(nodeDownloadRoot == null || nodeDownloadRoot.isEmpty()){
  30. nodeDownloadRoot = DEFAULT_NODEJS_DOWNLOAD_ROOT;
  31. }
  32. if(npmDownloadRoot == null || npmDownloadRoot.isEmpty()){
  33. npmDownloadRoot = DEFAULT_NPM_DOWNLOAD_ROOT;
  34. }
  35. new NodeAndNPMInstallAction(nodeVersion, npmVersion, nodeDownloadRoot, npmDownloadRoot).install();
  36. }
  37. private final class NodeAndNPMInstallAction {
  38. private static final String VERSION = "version";
  39. private final String nodeVersion;
  40. private final String npmVersion;
  41. private final String nodeDownloadRoot;
  42. private final String npmDownloadRoot;
  43. public NodeAndNPMInstallAction(String nodeVersion, String npmVersion, String nodeDownloadRoot, String npmDownloadRoot) {
  44. this.nodeVersion = nodeVersion;
  45. this.npmVersion = npmVersion;
  46. this.nodeDownloadRoot = nodeDownloadRoot;
  47. this.npmDownloadRoot = npmDownloadRoot;
  48. }
  49. public void install() throws InstallationException {
  50. if(!nodeIsAlreadyInstalled()){
  51. if(config.getPlatform().isWindows()){
  52. installNodeForWindows();
  53. } else {
  54. installNodeDefault();
  55. }
  56. }
  57. if(!npmIsAlreadyInstalled()) {
  58. installNpm();
  59. }
  60. }
  61. private boolean nodeIsAlreadyInstalled() {
  62. try {
  63. NodeExecutorConfig executorConfig = new InstallNodeExecutorConfig(config);
  64. File nodeFile = executorConfig.getNodePath();
  65. if(nodeFile.exists()){
  66. final String version = new NodeExecutor(executorConfig, Arrays.asList("--version")).executeAndGetResult();
  67. if(version.equals(nodeVersion)){
  68. logger.info("Node " + version + " is already installed.");
  69. return true;
  70. } else {
  71. logger.info("Node " + version + " was installed, but we need version " + nodeVersion);
  72. return false;
  73. }
  74. } else {
  75. return false;
  76. }
  77. } catch (ProcessExecutionException e) {
  78. return false;
  79. }
  80. }
  81. private boolean npmIsAlreadyInstalled(){
  82. try {
  83. final File npmPackageJson = new File(config.getInstallDirectory() + Utils.normalize("/node/npm/package.json"));
  84. if(npmPackageJson.exists()){
  85. HashMap<String,Object> data = new ObjectMapper().readValue(npmPackageJson, HashMap.class);
  86. if(data.containsKey(VERSION)){
  87. final String foundNpmVersion = data.get(VERSION).toString();
  88. logger.info("Found NPM version " + foundNpmVersion);
  89. if(foundNpmVersion.equals(npmVersion)) {
  90. return true;
  91. } else {
  92. logger.info("Mismatch between found NPM version and required NPM version");
  93. return false;
  94. }
  95. } else {
  96. logger.info("Could not read NPM version from package.json");
  97. return false;
  98. }
  99. } else {
  100. return false;
  101. }
  102. } catch (IOException ex){
  103. throw new RuntimeException("Could not read package.json", ex);
  104. }
  105. }
  106. private void installNpm() throws InstallationException {
  107. try {
  108. logger.info("Installing npm version " + npmVersion);
  109. final String downloadUrl = npmDownloadRoot +"npm-"+npmVersion+".tgz";
  110. String targetName = config.getInstallDirectory() + File.separator + "npm.tar.gz";
  111. logger.info("Downloading NPM from " + downloadUrl + " to " + targetName);
  112. downloadFile(downloadUrl, targetName);
  113. // We need to delete the existing npm directory first so we clean out any old files, and
  114. // so we can rename the package directory below.
  115. File npmDirectory = new File(config.getInstallDirectory(), "./node/npm");
  116. try {
  117. FileUtils.deleteDirectory(npmDirectory);
  118. } catch (IOException e) {
  119. logger.warn("Failed to delete existing NPM installation.");
  120. }
  121. logger.info("Extracting NPM files in node/");
  122. extractFile(targetName, config.getInstallDirectory() +"/node");
  123. new File(targetName).delete();
  124. // handles difference between old and new download root (nodejs.org/dist/npm and registry.npmjs.org)
  125. // see https://github.com/eirslett/frontend-maven-plugin/issues/65#issuecomment-52024254
  126. File packageDirectory = new File(config.getInstallDirectory(), "./node/package");
  127. if (packageDirectory.exists() && !npmDirectory.exists()) {
  128. packageDirectory.renameTo(npmDirectory);
  129. }
  130. logger.info("Installed NPM locally.");
  131. } catch (DownloadException e) {
  132. throw new InstallationException("Could not download npm", e);
  133. } catch (ArchiveExtractionException e) {
  134. throw new InstallationException("Could not extract the npm archive", e);
  135. }
  136. }
  137. private void installNodeDefault() throws InstallationException {
  138. String downloadUrl = "";
  139. try {
  140. logger.info("Installing node version " + nodeVersion);
  141. if (!nodeVersion.startsWith("v")) {
  142. logger.warn("Node version does not start with naming convention 'v'.");
  143. }
  144. final String longNodeFilename = config.getPlatform().getLongNodeFilename(nodeVersion);
  145. downloadUrl = nodeDownloadRoot + config.getPlatform().getNodeDownloadFilename(nodeVersion);
  146. final File tmpDirectory = new File(config.getInstallDirectory() + File.separator + "node_tmp");
  147. logger.info("Creating temporary directory " + tmpDirectory);
  148. tmpDirectory.mkdirs();
  149. final String targetName = config.getInstallDirectory() + "/node_tmp/node.tar.gz";
  150. logger.info("Downloading Node.js from " + downloadUrl + " to " + targetName);
  151. downloadFile(downloadUrl, targetName);
  152. logger.info("Extracting Node.js files in node_tmp");
  153. extractFile(targetName, config.getInstallDirectory() + "/node_tmp");
  154. // Search for the node binary
  155. File nodeBinary = new File(config.getInstallDirectory() + "/node_tmp/"+longNodeFilename+"/bin/node");
  156. if(!nodeBinary.exists()){
  157. throw new FileNotFoundException("Could not find the downloaded Node.js binary in "+nodeBinary);
  158. } else {
  159. File destinationDirectory = new File(config.getInstallDirectory() + "/node");
  160. destinationDirectory.mkdirs();
  161. File destination = new File(destinationDirectory + "/node");
  162. logger.info("Moving node binary to " + destination);
  163. if(!nodeBinary.renameTo(destination)){
  164. throw new InstallationException("Could not install Node: Was not allowed to rename "+nodeBinary+" to "+destination);
  165. }
  166. if(!destination.setExecutable(true, false)){
  167. throw new InstallationException("Cound not install Node: Was not allowed to make "+destination+" executable.");
  168. }
  169. logger.info("Deleting temporary directory " + tmpDirectory);
  170. FileUtils.deleteDirectory(tmpDirectory);
  171. logger.info("Installed node locally.");
  172. }
  173. } catch (IOException e) {
  174. throw new InstallationException("Could not install Node", e);
  175. } catch (DownloadException e) {
  176. throw new InstallationException("Could not download Node.js", e);
  177. } catch (ArchiveExtractionException e) {
  178. throw new InstallationException("Could not extract the Node archive", e);
  179. }
  180. }
  181. private void installNodeForWindows() throws InstallationException {
  182. final String downloadUrl = nodeDownloadRoot + config.getPlatform().getNodeDownloadFilename(nodeVersion);
  183. try {
  184. logger.info("Installing node version " + nodeVersion);
  185. new File(config.getInstallDirectory()+"\\node").mkdirs();
  186. downloadFile(downloadUrl, config.getInstallDirectory() +"\\node\\node.exe");
  187. logger.info("Installed node.exe locally.");
  188. } catch (DownloadException e) {
  189. throw new InstallationException("Could not download Node.js from: " + downloadUrl, e);
  190. }
  191. }
  192. private void extractFile(String archive, String destinationDirectory) throws ArchiveExtractionException {
  193. logger.info("Unpacking " + archive + " into " + destinationDirectory);
  194. archiveExtractor.extract(archive, destinationDirectory);
  195. }
  196. private void downloadFile(String downloadUrl, String destination) throws DownloadException {
  197. fileDownloader.download(downloadUrl, destination);
  198. }
  199. }
  200. }