View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2014 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.maven.plugins.nodejs.installation;
21  
22  import java.io.File;
23  
24  import org.apache.commons.lang3.StringUtils;
25  import org.apache.maven.artifact.versioning.ArtifactVersion;
26  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
27  import org.apache.maven.model.Dependency;
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.codehaus.plexus.util.Os;
30  
31  /**
32   * Holds the general information about the node installation. Provides node and npm executables
33   */
34  public class NodeInstallationInformation {
35  
36    private static final String NODEJS_BINARIES_GROUPID = "org.nodejs.dist";
37    private static final String NODEJS_BINARIES_ARTIFACTID = "nodejs-binaries";
38    private static final String NPM_CLI_EXECUTABLE_PATH = File.separator + "npm" + File.separator + "bin" + File.separator + "npm-cli.js";
39  
40    private static final String TYPE_TAR_GZ = "tar.gz";
41    static final String TYPE_ZIP = "zip";
42  
43    private static final String OS_WINDOWS = "win";
44    private static final String OS_MACOS = "darwin";
45    private static final String OS_LINUX = "linux";
46  
47    private Dependency nodeJsDependency;
48    private Dependency npmDependency;
49    private File archive;
50    private String nodeExecutableRelativePath;
51    private String nodeJsInstallPath;
52    private String npmPrefixPath;
53    private String nodeModulesBuiltInRootPath;
54    private String nodeModulesRootPath;
55  
56    public Dependency getNodeJsDependency() {
57      return this.nodeJsDependency;
58    }
59  
60    void setNodeJsDependency(Dependency nodeJsDependency) {
61      this.nodeJsDependency = nodeJsDependency;
62    }
63  
64    public Dependency getNpmDependency() {
65      return this.npmDependency;
66    }
67  
68    void setNpmDependency(Dependency npmDependency) {
69      this.npmDependency = npmDependency;
70    }
71  
72    public File getArchive() {
73      return archive;
74    }
75  
76    void setArchive(File archive) {
77      this.archive = archive;
78    }
79  
80    public File getNodeExecutable() {
81      return new File(this.nodeJsInstallPath + File.separator + nodeExecutableRelativePath);
82    }
83  
84    void setNodeExecutableRelativePath(String nodeExecutableRelativePath) {
85      this.nodeExecutableRelativePath = nodeExecutableRelativePath;
86    }
87  
88    public File getNpmExecutable() {
89      return new File(this.nodeModulesRootPath + File.separator + "node_modules" + NPM_CLI_EXECUTABLE_PATH);
90    }
91  
92    public File getNpmExecutableBundledWithNodeJs() {
93      return new File(this.nodeModulesBuiltInRootPath + File.separator + "node_modules" + NPM_CLI_EXECUTABLE_PATH);
94    }
95  
96    public String getNodeJsInstallPath() {
97      return nodeJsInstallPath;
98    }
99  
100   void setNodeJsInstallPath(String nodeJsInstallPath) {
101     this.nodeJsInstallPath = nodeJsInstallPath;
102   }
103 
104   public String getNpmPrefixPath() {
105     return this.npmPrefixPath;
106   }
107 
108   public void setNpmPrefixPath(String npmPrefixPath) {
109     this.npmPrefixPath = npmPrefixPath;
110   }
111 
112   public String getNodeModulesBuiltInRootPath() {
113     return this.nodeModulesBuiltInRootPath;
114   }
115 
116   void setNodeModulesBuiltInRootPath(String nodeModulesBuiltInRootPath) {
117     this.nodeModulesBuiltInRootPath = nodeModulesBuiltInRootPath;
118   }
119 
120   public String getNodeModulesRootPath() {
121     return this.nodeModulesRootPath;
122   }
123 
124   void setNodeModulesRootPath(String nodeModulesRootPath) {
125     this.nodeModulesRootPath = nodeModulesRootPath;
126   }
127 
128   /**
129    * Creates a {@link NodeInstallationInformation} for a specific Node.js and npm version and directory
130    * @param version Version
131    * @param npmVersion NPM version
132    * @param directory directory
133    * @return {@link NodeInstallationInformation}
134    * @throws MojoExecutionException Mojo execution exception
135    */
136   public static NodeInstallationInformation forVersion(String version, String npmVersion, File directory) throws MojoExecutionException {
137     int nodejsMajorVersion = getMajorVersion(version);
138 
139     String arch;
140     if (Os.isArch("x86") || Os.isArch("i386")) {
141       arch = "x86";
142     }
143     else if (Os.isArch("x86_64") || Os.isArch("amd64")) {
144       arch = "x64";
145     }
146     else if (Os.isArch("aarch64")) {
147       if (Os.isFamily(Os.FAMILY_MAC) && nodejsMajorVersion < 16) {
148         arch = "x64";
149       }
150       else {
151         arch = "arm64";
152       }
153     }
154     else {
155       throw new MojoExecutionException("Unsupported OS arch: " + Os.OS_ARCH);
156     }
157 
158     NodeInstallationInformation result = new NodeInstallationInformation();
159 
160     String basePath = directory.getAbsolutePath() + File.separator;
161 
162     if (Os.isFamily(Os.FAMILY_WINDOWS) || Os.isFamily(Os.FAMILY_WIN9X)) {
163       String nodeJsInstallPath = basePath + "node-v" + version + "-" + OS_WINDOWS + "-" + arch;
164       result.setNodeJsInstallPath(nodeJsInstallPath);
165       result.setNodeJsDependency(buildDependency(NODEJS_BINARIES_GROUPID, NODEJS_BINARIES_ARTIFACTID, version, OS_WINDOWS, arch, TYPE_ZIP));
166       result.setArchive(new File(nodeJsInstallPath + "." + TYPE_ZIP));
167       result.setNodeExecutableRelativePath("node.exe");
168       result.setNodeModulesBuiltInRootPath(nodeJsInstallPath);
169       result.setNpmPrefixPath(nodeJsInstallPath + getNodeModulesRootPathNpmSuffix(npmVersion));
170       result.setNodeModulesRootPath(result.getNpmPrefixPath());
171     }
172     else if (Os.isFamily(Os.FAMILY_MAC)) {
173       String nodeJsInstallPath = basePath + "node-v" + version + "-" + OS_MACOS + "-" + arch;
174       result.setNodeJsInstallPath(nodeJsInstallPath);
175       result.setNodeJsDependency(buildDependency(NODEJS_BINARIES_GROUPID, NODEJS_BINARIES_ARTIFACTID, version, OS_MACOS, arch, TYPE_TAR_GZ));
176       result.setArchive(new File(nodeJsInstallPath + "." + TYPE_TAR_GZ));
177       result.setNodeExecutableRelativePath("bin" + File.separator + "node");
178       result.setNodeModulesBuiltInRootPath(nodeJsInstallPath + File.separator + "lib");
179       result.setNpmPrefixPath(nodeJsInstallPath + getNodeModulesRootPathNpmSuffix(npmVersion));
180       result.setNodeModulesRootPath(result.getNpmPrefixPath() + File.separator + "lib");
181     }
182     else if (Os.isFamily(Os.FAMILY_UNIX)) {
183       String nodeJsInstallPath = basePath + "node-v" + version + "-" + OS_LINUX + "-" + arch;
184       result.setNodeJsInstallPath(nodeJsInstallPath);
185       result.setNodeJsDependency(buildDependency(NODEJS_BINARIES_GROUPID, NODEJS_BINARIES_ARTIFACTID, version, OS_LINUX, arch, TYPE_TAR_GZ));
186       result.setArchive(new File(nodeJsInstallPath + "." + TYPE_TAR_GZ));
187       result.setNodeExecutableRelativePath("bin" + File.separator + "node");
188       result.setNodeModulesBuiltInRootPath(nodeJsInstallPath + File.separator + "lib");
189       result.setNpmPrefixPath(nodeJsInstallPath + getNodeModulesRootPathNpmSuffix(npmVersion));
190       result.setNodeModulesRootPath(result.getNpmPrefixPath() + File.separator + "lib");
191     }
192     else {
193       throw new MojoExecutionException("Unsupported OS: " + Os.OS_FAMILY);
194     }
195 
196     return result;
197   }
198 
199   private static int getMajorVersion(String version) {
200     ArtifactVersion versionInfo = new DefaultArtifactVersion(version);
201     return versionInfo.getMajorVersion();
202   }
203 
204   private static String getNodeModulesRootPathNpmSuffix(String npmVersion) {
205     if (StringUtils.isNotEmpty(npmVersion)) {
206       return File.separator + "npm-v" + npmVersion;
207     }
208     else {
209       return "";
210     }
211   }
212 
213   @SuppressWarnings("PMD.UseStringBufferForStringAppends")
214   private static Dependency buildDependency(String groupId, String artifactId, String version, String os, String arch, String type) {
215     String classifier = null;
216     if (StringUtils.isNotEmpty(os)) {
217       classifier = os;
218     }
219     if (StringUtils.isNotEmpty(arch)) {
220       classifier += "-" + arch;
221     }
222 
223     Dependency dependency = new Dependency();
224     dependency.setGroupId(groupId);
225     dependency.setArtifactId(artifactId);
226     dependency.setVersion(version);
227     dependency.setType(type);
228     dependency.setClassifier(classifier);
229     return dependency;
230   }
231 
232 }