package aQute.bnd.osgi; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.osgi.resource.Capability; import aQute.bnd.osgi.resource.CapabilityBuilder; import aQute.bnd.osgi.resource.ResourceUtils; import aQute.bnd.version.MavenVersion; import aQute.bnd.version.Version; import aQute.lib.strings.Strings; /** * OS specific information, used by the native_capability macro for * osgi.native.* bundle properties. */ public class OSInformation { String osnames = null; Version osversion = null; static private String regexQualifierNotAllowedChars = "[^\\p{Alnum}-_]"; static private Pattern digitPattern = Pattern.compile("(\\d+).*"); final static String[][] processorFamilies = { new String[] { "x86-64", "amd64", "em64t", "x86_64" }, new String[] { "x86", "pentium", "i386", "i486", "i586", "i686" }, new String[] { "68k" }, new String[] { "ARM" }, new String[] { "ARM_be" }, new String[] { "ARM_le" }, new String[] { "Alpha" }, new String[] { "ia64n" }, new String[] { "ia64w" }, new String[] { "Ignite", "psc1k" }, new String[] { "Mips" }, new String[] { "PARisc" }, new String[] { "PowerPC", "power", "ppc" }, new String[] { "Sh4" }, new String[] { "Sparc" }, new String[] { "Sparcv9" }, new String[] { "S390" }, new String[] { "V850e" }, }; static String[] osarch = getProcessorAliases(System.getProperty("os.arch")); public static String[] getProcessorAliases(String osArch) { for (String[] pnames : processorFamilies) { for (String pname : pnames) if (pname.equalsIgnoreCase(osArch)) return pnames; } return null; } public static String[] getProcessorAliases() { return osarch; } /** * <p> * Convert a generic Unix kernel version to an OSGi version. * </p> * <p> * As long as we have digits separated by dots, convert the digits into the * respective version segments. Anything left after that conversion is the * qualifier. Illegal characters in that qualifier are converted into * underscores to ensure that the final qualifier is valid. * </p> * * @param sysPropOsVersion the system property "os.version" */ static Version convertUnixKernelVersion(String sysPropOsVersion) { Version osversion = new Version(0, 0, 0); String s = sysPropOsVersion.trim(); int index = 0; do { Matcher matcher = digitPattern.matcher(s); if (matcher.matches()) { String matchedDigit = matcher.group(1); int matchedDigitNumber; try { matchedDigitNumber = Integer.parseInt(matchedDigit); } catch (NumberFormatException e) { assert(false); break; } switch (index) { case 0 : osversion = new Version(matchedDigitNumber, osversion.getMinor(), osversion.getMicro()); break; case 1 : osversion = new Version(osversion.getMajor(), matchedDigitNumber, osversion.getMicro()); break; case 2 : osversion = new Version(osversion.getMajor(), osversion.getMinor(), matchedDigitNumber); break; default : assert(false); break; } s = s.substring(matchedDigit.length()); if (s.length() == 0 || s.charAt(0) != '.') { break; } s = s.substring(1); index++; } } while (index < 3); if (s.length() != 0) { String qualifier = s.replaceAll(regexQualifierNotAllowedChars, "_"); osversion = new Version(osversion.getMajor(), osversion.getMinor(), osversion.getMicro(), qualifier); } return osversion; } /** * Construct OS specific information * * @throws IllegalArgumentException */ public OSInformation() throws IllegalArgumentException { this(System.getProperty("os.name"), System.getProperty("os.version")); } public OSInformation(String sysPropOsName, String sysPropOsVersion) throws IllegalArgumentException { if (sysPropOsName == null || sysPropOsName.length() == 0 || sysPropOsVersion == null || sysPropOsVersion.length() == 0) { return; } OSNameVersion pair = getOperatingSystemAliases(sysPropOsName, sysPropOsVersion); if (pair == null) throw new IllegalArgumentException( "Unknown OS/version combination: " + sysPropOsName + " " + sysPropOsVersion); osversion = pair.osversion; osnames = pair.osnames; } static class NativeCapability { public List<String> processor = new ArrayList<>(); public List<String> osname = new ArrayList<>(); public Version osversion; public String language = "en"; } /** * Helper for the Processor._native_capability macro * * @param args the arguments of the macro * @return a provide capability clause for the native environment */ public static String getNativeCapabilityClause(Processor p, String args[]) throws Exception { NativeCapability clause = new NativeCapability(); parseNativeCapabilityArgs(p, args, clause); validateNativeCapability(clause); Capability cap = createCapability(clause); return ResourceUtils.toProvideCapability(cap); } static Capability createCapability(NativeCapability clause) throws Exception { CapabilityBuilder c = new CapabilityBuilder("osgi.native"); c.addAttribute("osgi.native.osname", clause.osname); c.addAttribute("osgi.native.osversion", clause.osversion); c.addAttribute("osgi.native.processor", clause.processor); c.addAttribute("osgi.native.language", clause.language); Capability cap = c.synthetic(); return cap; } static void validateNativeCapability(NativeCapability clause) { if (clause.osversion == null) throw new IllegalArgumentException("osversion/osgi.native.osversion not set in ${native_capability}"); if (clause.osname.isEmpty()) throw new IllegalArgumentException("osname/osgi.native.osname not set in ${native_capability}"); if (clause.processor.isEmpty()) throw new IllegalArgumentException("processor/osgi.native.processor not set in ${native_capability}"); } static void parseNativeCapabilityArgs(Processor p, String[] args, NativeCapability clause) throws Exception { if (args.length == 1) { OSInformation osi = new OSInformation(); clause.osname.addAll(Strings.split(osi.osnames)); clause.osversion = osi.osversion; clause.processor.addAll(Arrays.asList(getProcessorAliases(System.getProperty("os.arch")))); clause.language = Locale.getDefault().toString(); StringBuilder sb = new StringBuilder(); sb.append("osname=").append(System.getProperty("os.name")); sb.append(";").append("osversion=").append(MavenVersion.cleanupVersion(System.getProperty("os.version"))); sb.append(";").append("processor=").append(System.getProperty("os.arch")); sb.append(";").append("lang=").append(clause.language); String advice = sb.toString(); } else { String osname = null; for (int i = 1; i < args.length; i++) { String parts[] = args[i].split("\\s*=\\s*"); if (parts.length != 2) throw new IllegalArgumentException( "Illegal property syntax in \"" + args[i] + "\", use \"key=value\""); String key = Strings.trim(parts[0]); String value = Strings.trim(parts[1]); boolean isList = value.indexOf(',') > 0; switch (key) { case "processor" : case "osgi.native.processor" : if (isList) clause.processor.addAll(Strings.split(value)); else { if ("arm".equals(value)) { p.warning("The 'arm' processor is deprecated. Specify either 'arm_le' or 'arm_be'"); } String[] processorAliases = getProcessorAliases(value); if (processorAliases != null && processorAliases.length > 0) { clause.processor.addAll(Arrays.asList(processorAliases)); } else { clause.processor.add(value); } } break; case "osname" : case "osgi.native.osname" : if (isList) clause.osname.addAll(Strings.split(value)); else { if (osname == null) { osname = value; } else { clause.osname.add(osname); osname = value; } } break; case "osversion" : case "osgi.native.osversion" : if (clause.osversion == null) { clause.osversion = Version.parseVersion(value); } else throw new IllegalArgumentException( "osversion/osgi.native.osversion can only be set once in ${native_capability}"); break; case "osgi.native.language" : case "lang" : if (clause.language != null) throw new IllegalArgumentException( "lang/osgi.native.lang can only be set once in ${native_capability}"); clause.language = value; break; } } if (osname != null) { try { OSInformation osi = new OSInformation(osname, clause.osversion.toString()); clause.osname.addAll(Strings.split(osi.osnames)); } catch (Exception e) { clause.osname.add(osname); } } } } public static class OSNameVersion { public Version osversion; public String osnames; } public static OSNameVersion getOperatingSystemAliases(String sysPropOsName, String sysPropOsVersion) { OSNameVersion nc = new OSNameVersion(); if (sysPropOsName.startsWith("Windows")) { if (sysPropOsVersion.startsWith("10.0")) { nc.osversion = new Version(10, 0, 0); nc.osnames = "Windows10,Windows 10,Win32"; } else if (sysPropOsVersion.startsWith("6.3")) { nc.osversion = new Version(6, 3, 0); nc.osnames = "Windows8.1,Windows 8.1,Win32"; } else if (sysPropOsVersion.startsWith("6.2")) { nc.osversion = new Version(6, 2, 0); nc.osnames = "Windows8,Windows 8,Win32"; } else if (sysPropOsVersion.startsWith("6.1")) { nc.osversion = new Version(6, 1, 0); nc.osnames = "Windows7,Windows 7,Win32"; } else if (sysPropOsVersion.startsWith("6.0")) { nc.osversion = new Version(6, 0, 0); nc.osnames = "WindowsVista,WinVista,Windows Vista,Win32"; } else if (sysPropOsVersion.startsWith("5.1")) { nc.osversion = new Version(5, 1, 0); nc.osnames = "WindowsXP,WinXP,Windows XP,Win32"; } else { nc = null; } } else if (sysPropOsName.startsWith("Mac OS X")) { nc.osversion = convertUnixKernelVersion(sysPropOsVersion); nc.osnames = "MacOSX,Mac OS X"; return nc; } else if (sysPropOsName.toLowerCase().startsWith("linux")) { nc.osversion = convertUnixKernelVersion(sysPropOsVersion); nc.osnames = "Linux"; } else if (sysPropOsName.startsWith("Solaris")) { nc.osversion = convertUnixKernelVersion(sysPropOsVersion); nc.osnames = "Solaris"; } else if (sysPropOsName.startsWith("AIX")) { nc.osversion = convertUnixKernelVersion(sysPropOsVersion); nc.osnames = "AIX"; } else if (sysPropOsName.startsWith("HP-UX")) { nc.osversion = convertUnixKernelVersion(sysPropOsVersion); nc.osnames = "HPUX,hp-ux"; } return nc; } }