package jenkins.plugins.nodejs.tools; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.Locale; import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.commons.io.output.NullOutputStream; import hudson.FilePath; import hudson.Launcher; import hudson.Proc; import hudson.model.Computer; import hudson.model.Node; import hudson.remoting.VirtualChannel; import hudson.util.StreamTaskListener; import jenkins.MasterToSlaveFileCallable; /** * CPU type. */ public enum CPU { i386, amd64, armv7l, armv6l, arm64; /** * Determines the CPU of the given node. * * @param node * the computer node * @return a CPU value of the cpu of the given node * @throws IOException in case of IO issues with the remote Node * @throws InterruptedException in case the job is interrupted by user */ public static CPU of(@Nonnull Node node) throws IOException, InterruptedException { Computer computer = node.toComputer(); if (computer == null) { throw new DetectionFailedException("Node offline"); } return detect(computer, computer.getSystemProperties()); } /** * Determines the CPU of the current JVM. * * @return the current CPU * @throws DetectionFailedException * when the current platform node is not supported. */ public static CPU current() throws DetectionFailedException { return detect(null, System.getProperties()); } private static CPU detect(@Nullable Computer computer, Map<Object, Object> systemProperties) throws DetectionFailedException { String arch = ((String) systemProperties.get("os.arch")).toLowerCase(Locale.ENGLISH); if (arch.contains("amd64") || arch.contains("86_64")) { return amd64; } if (arch.contains("86")) { return i386; } if (arch.contains("arm")) { // try to get the specific architecture of arm CPU try { FilePath rootPath = new FilePath((computer != null ? computer.getChannel() : null), "/"); arch = rootPath.act(new ArchitectureCallable()); } catch (IOException | InterruptedException e) { throw new DetectionFailedException("Unknown CPU architecture: " + arch, e); } switch (arch) { case "armv7l": return armv7l; case "armv6l": return armv6l; case "arm64": return arm64; } } throw new DetectionFailedException("Unknown CPU architecture: " + arch); } /** * Returns the machine hardware name for the current Linux computer. * * @author Nikolas Falco */ /* package */static class ArchitectureCallable extends MasterToSlaveFileCallable<String> { private static final long serialVersionUID = 1L; @Override public String invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { Charset charset = Charset.defaultCharset(); FilePath basePath = new FilePath(f); Launcher launcher = basePath.createLauncher(new StreamTaskListener(new NullOutputStream(), charset)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); Proc starter = launcher.launch().cmdAsSingleString("uname -m").stdout(baos).start(); int exitCode = starter.join(); if (exitCode != 0) { throw new IOException("Fail to execute 'uname -m' because: " + baos.toString(charset.name())); } return new String(baos.toByteArray(), charset).trim(); } }; }