io.dekorate.nodejs.NodeInfoReader Maven / Gradle / Ivy
/**
* Copyright 2018 The original authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.dekorate.nodejs;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import io.dekorate.DekorateException;
import io.dekorate.Logger;
import io.dekorate.LoggerFactory;
import io.dekorate.project.BuildInfo;
import io.dekorate.project.BuildInfoBuilder;
import io.dekorate.project.BuildInfoReader;
import io.dekorate.utils.Exec;
import io.dekorate.utils.Exec.ProjectExec;
import io.dekorate.utils.Git;
import io.dekorate.utils.Strings;
public class NodeInfoReader implements BuildInfoReader {
private final Logger LOGGER = LoggerFactory.getLogger();
private static final String NPM = "npm";
private static final String PACKAGE_JSON = "package.json";
private static final String SRC = "src";
private static final String OPEN_BRACKET = "{";
private static final String CLOSE_BRACKET = "}";
private static final String QUOTE = "'";
private static final String EQUALS = "=";
private static final String COLON = ":";
private static final String DASH = "-";
private static final String DOT = ".";
private static final String NAME = "name";
private static final String VERSION = "version";
private static final String BIN = "bin";
private static final String MAIN = "main";
public static final String NEW_LINE = "[\\n\\r]+";
private static final String INDEX_JS = "index.js";
@Override
public int order() {
return 500;
}
@Override
public boolean isApplicable(Path root) {
return root.resolve(PACKAGE_JSON).toFile().exists();
}
@Override
public BuildInfo getInfo(Path root) {
Path packageJson = root.resolve(PACKAGE_JSON);
Map properties = new HashMap<>();
properties.putAll(readPackageJson(packageJson));
String name = properties.getOrDefault(NAME, properties.getOrDefault(NAME, root.getFileName().toString()));
String version = properties.get(VERSION);
String main = properties.getOrDefault(MAIN, INDEX_JS);
StringBuilder sb = new StringBuilder();
sb.append(name);
if (Strings.isNotNullOrEmpty(version)) {
sb.append(DASH).append(version);
}
if (version == null) {
LOGGER.warning("Could not detect project version. Using 'latest'.");
version = "latest";
}
return new BuildInfoBuilder()
.withName(name)
.withVersion(version)
.withPackaging("js")
.withBuildTool(NPM)
.withBuildToolVersion(getVersion(root))
.withOutputFile(root.resolve(main))
.withClassOutputDir(null)
.withResourceDir(null)
.build();
}
/**
* Parse package.json and read the nodejs configuration as a {@link Map}.
* In detail, it parses:
* - name
* - version
* - main
*
* @param path The path to package.json.
* @return A map containing all configuration.
*/
protected static Map readPackageJson(Path path) {
AtomicInteger quotes = new AtomicInteger(0);
Map properties = new HashMap<>();
try {
Files.lines(path).map(l -> l.replaceAll("[ ]*", "")).forEach(l -> {
if (l.contains(OPEN_BRACKET)) {
quotes.incrementAndGet();
}
if (l.contains(CLOSE_BRACKET)) {
quotes.decrementAndGet();
}
if (quotes.get() == 1 && l.contains(NAME)) {
String name = readValue(l);
properties.put(NAME, name);
}
if (quotes.get() == 1 && l.contains(VERSION)) {
String version = readValue(l);
properties.put(VERSION, version);
}
if (quotes.get() == 1 && l.contains(MAIN)) {
String main = readValue(l);
properties.put(MAIN, main);
}
});
} catch (IOException e) {
throw DekorateException.launderThrowable(e);
}
return properties;
}
private static String readValue(String l) {
return l.substring(l.lastIndexOf(COLON) + 1)
.replaceAll(QUOTE, "")
.replaceAll(Pattern.quote("\""), "")
.replaceAll(",$", "").trim();
}
public static String getVersion(Path modulePath) {
Path packageJson = Git.getRoot(modulePath).orElse(modulePath).resolve(PACKAGE_JSON);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ProjectExec exec = Exec.inPath(modulePath).redirectingOutput(out);
boolean success = exec.commands(NPM, VERSION);
return getVersionFromOutput(new String(out.toByteArray()));
}
protected static String getVersionFromOutput(String output) {
if (Strings.isNullOrEmpty(output)) {
throw new IllegalArgumentException("nodejs version output should not be empty!");
}
return Arrays.stream(output.split(NEW_LINE))
.filter(l -> l.contains("npm"))
.map(NodeInfoReader::readValue)
.findFirst()
.orElseThrow(
() -> new IllegalStateException("Unknown nodejs version output format. Expected at least one line!"));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy