gradle-node-plugin
gradle-node-plugin copied to clipboard
PlatformHelper.getOsArch will be wrong when running 32-bit JVM on a 64-bit system
The value of Java system property 'os.arch' will return the bitness of the JRE, not the Operating System itself. I think this may be an issue when trying to install the proper version of node, etc.
See the following links: http://mark.koli.ch/javas-osarch-system-property-is-the-bitness-of-the-jre-not-the-operating-system https://blogs.oracle.com/DieterDeramoudt/entry/beware_when_detecting_32_and
Oh, that is bad. Any way of detecting this without using native calls?
Well, I think the easiest solution is to follow Gradle. It appears they use the following library:
https://github.com/adammurdoch/native-platform
You will have to review the supported platforms to see if it is comprehensive enough. Meaning, I think it will work on any platform supported by Gradle itself which I believe is only a subset of what Node supports. Hopefully that is okay. If not, then Gradle is probably not the right tool. Anyway, Gradle internal code will execute the following command and do a fallback to the system 'os.arch' property if it fails (ironically):
// Attempt to get the native system architecture because "os.arch" system property
// is the architecture of the JRE, NOT the Operating System. For example, it will report
// a 32-bit value when running a 32-bit JVM on a 64-bit OS.
try {
def osArch = net.rubygrapefruit.platform.Native.get(SystemInfo.class).getArchitectureName()
} catch (Exception e) {
//blah
}
Here is a link to the Gradle source code which fetches the current architecture (used internally): https://github.com/gradle/gradle/blob/f001402c8b7f404c923d972f1bc524b2de7b3fcd/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/platform/internal/DefaultNativePlatform.java See:
DefaultNativePlatform.getCurrentArchitecture()
Another thing I found useful is the following library since it seems to normalize the os name and architecture nicely: https://github.com/google/osdetector-gradle-plugin
I have not completed/finalized anything yet, but you will have to do something like the following code snippet in order to use the library with custom "os.arch" fetching (but not altering the system "os.arch" directly):
import kr.motd.maven.os.Detector
import net.rubygrapefruit.platform.SystemInfo
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
class OsDetector extends Detector {
private final Logger logger = Logging.getLogger(OsDetector)
@Override
protected void log(String message) {
logger.info(message);
}
@Override
protected void logProperty(String name, String value) {
logger.info(name + "=" + value);
}
OsDetector(final Properties detectedProperties) {
// Attempt to get the native system architecture because "os.arch" system property
// is the architecture of the JRE, NOT the Operating System. For example, it will report
// a 32-bit value when running a 32-bit JVM on a 64-bit OS.
try {
def osArch = net.rubygrapefruit.platform.Native.get(SystemInfo.class).getArchitectureName()
// overwrite 'os.arch'
detectedProperties.put('os.arch', osArch)
} catch (Exception e) {
logger.error(e)
}
detect(detectedProperties, [])
}
}
Usage:
final OsDetector osDetector = new OsDetector(properties)
final String osName = osDetector.getProperty(OsDetector.DETECTED_NAME)
final String osArch = osDetector.getProperty(OsDetector.DETECTED_ARCH)
Finally,
It would be nice if Gradle did more to expose these things. Hopefully in the future they will.
Cheers, Bradley
Or default the os.arch to 'x64' and not 'x86', since most users PC's or build systems are now 64-bit.
Hit the same issue today. I agree the best thing is to default x64 as per @mdoornik comment above.
I have managed to solve the issue myself but have no time to contribute exact code. I hope the following details make sense. If not, I will update this comment accordingly.
Regards,
Bradley
I use 2 libraries to help with managing the architecture:
- os-maven-plugin
- native-platform
Gradle Dependencies:
dependencies {
compile gradleApi()
compile localGroovy()
compile 'kr.motd.maven:os-maven-plugin:1.5.0.Final'
compile "net.rubygrapefruit:native-platform:0.10"
testCompile group: 'junit', name: 'junit', version: '4.12'
...
}
Related code to finding proper architecture:
// Attempt to get the native system architecture because "os.type" system property
// is the architecture of the JRE, NOT the Operating System. For example, it will report
// a 32-bit value when running a 32-bit JVM on a 64-bit OS.
try {
final String osArch = Native.get(SystemInfo.class).getArchitectureName()
// overwrite 'os.type'
tempProps.put('os.arch', osArch)
} catch (final Exception e) {
logger.error("Failed to fetch os.arch", e)
}
Where the System property 'os.arch' can be updated and any custom classes which could use the architecture name (like the maven-os-plugin classes).
Example class:
private static class Impl extends Detector {
final Properties detectedProperties
Impl(final Properties props) {
final Properties tempProps = new Properties(props)
// Attempt to get the native system architecture because "os.type" system property
// is the architecture of the JRE, NOT the Operating System. For example, it will report
// a 32-bit value when running a 32-bit JVM on a 64-bit OS.
try {
final String osArch = Native.get(SystemInfo.class).getArchitectureName()
// overwrite 'os.type'
tempProps.put('os.arch', osArch)
} catch (final Exception e) {
logger.error("Failed to fetch os.arch", e)
}
detect(tempProps, [])
this.detectedProperties = tempProps
}
@Override
protected void log(final String message) {
logger.info(message)
}
@Override
protected void logProperty(final String name, final String value) {
logger.info("{}={}", name, value)
}
}
I met this problem too. System.getProperty('os.arch')
does not return the proper arch number.
How can I check the bitness of my OS using Java?? (J2SE, not os.arch)
Any helps from this solution?
I posted a working solution above using the net.rubygrapefruit:native-platform:0.10 java library, which ultimately uses the following method:
final String osArch = Native.get(SystemInfo.class).getArchitectureName()