Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect the current OS from Gradle

Tags:

gradle

Actually, I looked at the Gradle project, and this looks a little cleaner as it uses Ant's existing structure:

import org.apache.tools.ant.taskdefs.condition.Os

task checkWin() << {
    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
        println "*** Windows "
    }
}

I found this in the following Gradle branch, and it seems to work nicely. gradle/gradle-core/branches/RB-0.3/build.gradle


Mid 2020 Update: Still incubating:

OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem; 

Early 2019 Update: current() removed.

org.gradle.nativeplatform.platform.OperatingSystem.getDisplayName()

org.gradle.nativeplatform.platform.OperatingSystem.isLinux()

Keep in mind that it's still incubating though.

Mid 2018 Update: just like it was mentioned in comments, now this class moved to a different package, so one should use org.gradle.nativeplatform.platform.OperatingSystem.current()


As of mid 2015, Peter Kahn's answer is still valid. Environment-based profile activation is still something done relatively easier in Maven. But keep in mind that org.apache.tools.ant.taskdefs.condition.Os.isFamily is not exclusive in the sense that if it returns true with one particular parameter it is not necessarily means that it returns false for any other parameter. For instance:

import org.apache.tools.ant.taskdefs.condition.Os
task detect {
    doLast {
        println(Os.isFamily(Os.FAMILY_WINDOWS))
        println(Os.isFamily(Os.FAMILY_MAC))
        println(Os.isFamily(Os.FAMILY_UNIX))
    }
}

It will return true both for Os.FAMILY_MAC and Os.FAMILY_UNIX on MacOS. Usually it is not something you need in build scripts.

There is though another way to achieve this using Gradle 2+ API, namely:

import org.gradle.internal.os.OperatingSystem;

task detect {
    doLast {
        println(OperatingSystem.current().isMacOsX())
        println(OperatingSystem.current().isLinux())
    }
}

Check out the documentation for the org.gradle.nativeplatform.platform.OperatingSystem interface. It is worth to mention that this interface is marked with incubating annotation, that is, "the feature is currently a work-in-progress and may change at any time". The "internal" namespace in the implementation also gives us a hint that we should use this knowing that this can change.

But personally I'd go with this solution. It's just that it's better to write a wrapper class so as not to mess up in case something will change in the future.


One can differentiate the build environment in between Linux, Unix, Windows and OS X - while the Gradle nativeplatform.platform.OperatingSystem differentiates the target environment (incl. FreeBSD and Solaris).

import org.gradle.internal.os.OperatingSystem

String osName = OperatingSystem.current().getName();
String osVersion = OperatingSystem.current().getVersion();
println "*** $osName $osVersion was detected."

if (OperatingSystem.current().isLinux()) {
    // Consider Linux.
} else if (OperatingSystem.current().isUnix()) {
    // Consider UNIX.
} else if (OperatingSystem.current().isWindows()) {
    // Consider Windows.
} else if (OperatingSystem.current().isMacOsX()) {
    // Consider OS X.
} else {
    // Unknown OS.
}

One can also use an Ant task (source):

import org.apache.tools.ant.taskdefs.condition.Os

task checkWin() << {
    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
        // Consider Windows.
    }
}

Or you can define osName as a string...

import org.gradle.internal.os.OperatingSystem

switch (OperatingSystem.current()) {
    case OperatingSystem.LINUX:
        project.ext.osName = "Linux";
        break;
    case OperatingSystem.MAC_OS:
        project.ext.osName = "macOS";
        break;
    case OperatingSystem.WINDOWS:
        project.ext.osName = "Windows";
        break;
}

... and use it later - to include a native library for example:

run {
    systemProperty "java.library.path", "lib/$osName"
}

But it wouldn't change anything since OperatingSystem works exactly like your code:

public static OperatingSystem forName(String os) {
    String osName = os.toLowerCase();
    if (osName.contains("Windows")) {
        return WINDOWS;
    } else if (osName.contains("mac os x") || osName.contains("darwin") || osName.contains("osx")) {
        return MAC_OS;
    } else if (osName.contains("sunos") || osName.contains("solaris")) {
        return SOLARIS;
    } else if (osName.contains("linux")) {
        return LINUX;
    } else if (osName.contains("freebsd")) {
        return FREE_BSD;
    } else {
        // Not strictly true
        return UNIX;
    }
}

Source: https://github.com/gradle/gradle/blob/master/subprojects/base-services/src/main/java/org/gradle/internal/os/OperatingSystem.java

Edit:

You can do the same for the architecture:

project.ext.osArch = OperatingSystem.current().getArch();
if ("x86".equals(project.ext.osArch)) {
    project.ext.osArch = "i386";
}

and:

run {
    systemProperty "java.library.path", "lib/$osName/$osArch"
}

Just be aware that getArch() will return:

  • "ppc" on PowerPC
  • "amd64" on 64b
  • "i386" OR "x86" on 32b.

getArch() will return "x86" on Solaris or "i386" for any other platform.

Edit 2:

Or if you want to avoid any import, you can simply do it yourself:

def getOsName(project) {
    final String osName = System.getProperty("os.name").toLowerCase();

    if (osName.contains("linux")) {
        return ("linux");
    } else if (osName.contains("mac os x") || osName.contains("darwin") || osName.contains("osx")) {
        return ("macos");
    } else if (osName.contains("windows")) {
        return ("windows");
    } else if (osName.contains("sunos") || osName.contains("solaris")) {
        return ("solaris");
    } else if (osName.contains("freebsd")) {
        return ("freebsd");
    }
    return ("unix");
}

def getOsArch(project) {
    final String osArch = System.getProperty("os.arch");

    if ("x86".equals(osArch)) {
        return ("i386");
    }
    else if ("x86_64".equals(osArch)) {
        return ("amd64");
    }
    else if ("powerpc".equals(osArch)) {
        return ("ppc");
    }
    return (osArch);
}

Gradle doesn't provide a public API for detecting the operating system. Hence the os. system properties are your best bet.


I don't like detecting the OS in Gradle through properties or an Ant task, and the OperatingSystem class no longer contains the current() method.

So, in my opinion, the cleanest way to detect the OS would be:

Import DefaultNativePlatform:

import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform

Then use DefaultNativePlatform in your task:

if (DefaultNativePlatform.getCurrentOperatingSystem().isWindows()) {
   println 'Windows'
}

Mind that this method is not ideal as it is using the Gradle internal API.

It was tested with Gradle 4.10.