Compare commits
37 Commits
Version_1.
...
master
Author | SHA1 | Date |
---|---|---|
Robinson | b2926a4693 | |
Robinson | 0598176fe0 | |
Robinson | b9f921bf06 | |
Robinson | cd2d50d5d8 | |
Robinson | e0b4eded81 | |
Robinson | 0c1f718f49 | |
Robinson | 4b90e718ca | |
Robinson | da300e87dc | |
Nohus | 111d48db7c | |
Nohus | 6a37f3e652 | |
Robinson | 509e4c8e0a | |
Robinson | 614baf966f | |
Robinson | e204a8f781 | |
Robinson | 244ac97eab | |
Robinson | db41a118a4 | |
Robinson | d6544fa6ca | |
Robinson | 6322092ecb | |
Robinson | b69dcdbba4 | |
Robinson | 4b48e12894 | |
Robinson | d2aacbdc2e | |
Robinson | 99714cbc2e | |
Robinson | 3275224b1d | |
Robinson | a70f3d2bb0 | |
Robinson | 44c26cacf0 | |
Robinson | f1f3b83681 | |
Robinson | 027150f109 | |
Robinson | 13d4fb000a | |
Robinson | d3a1ba30fe | |
Robinson | d2f72ecd1d | |
Robinson | 278ec16646 | |
Robinson | 6774c901b2 | |
Robinson | a7afb15412 | |
Robinson | af8e0ee0cc | |
Robinson | b41e5397ef | |
Robinson | ef9ef92c19 | |
Robinson | 940194a9f8 | |
Robinson | fd88eb7847 |
2
LICENSE
2
LICENSE
|
@ -1,7 +1,7 @@
|
|||
- OS - Information about the system, Java runtime, OS, Window Manager, and Desktop Environment.
|
||||
[The Apache Software License, Version 2.0]
|
||||
https://git.dorkbox.com/dorkbox/OS
|
||||
Copyright 2022
|
||||
Copyright 2023
|
||||
Dorkbox LLC
|
||||
|
||||
Extra license information
|
||||
|
|
|
@ -20,7 +20,7 @@ Maven Info
|
|||
<dependency>
|
||||
<groupId>com.dorkbox</groupId>
|
||||
<artifactId>OS</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.11</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
@ -30,7 +30,7 @@ Gradle Info
|
|||
```
|
||||
dependencies {
|
||||
...
|
||||
implementation("com.dorkbox:OS:1.0")
|
||||
implementation("com.dorkbox:OS:1.11")
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2020 dorkbox, llc
|
||||
* Copyright 2023 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,8 +14,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
///////////////////////////////
|
||||
////// PUBLISH TO SONATYPE / MAVEN CENTRAL
|
||||
////// TESTING : (to local maven repo) <'publish and release' - 'publishToMavenLocal'>
|
||||
|
@ -26,19 +24,19 @@ gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS // always show th
|
|||
|
||||
|
||||
plugins {
|
||||
id("com.dorkbox.GradleUtils") version "2.16"
|
||||
id("com.dorkbox.Licensing") version "2.12"
|
||||
id("com.dorkbox.VersionUpdate") version "2.4"
|
||||
id("com.dorkbox.GradlePublish") version "1.12"
|
||||
id("com.dorkbox.GradleUtils") version "3.18"
|
||||
id("com.dorkbox.Licensing") version "2.22"
|
||||
id("com.dorkbox.VersionUpdate") version "2.8"
|
||||
id("com.dorkbox.GradlePublish") version "1.22"
|
||||
|
||||
kotlin("jvm") version "1.6.10"
|
||||
kotlin("jvm") version "1.9.0"
|
||||
}
|
||||
|
||||
object Extras {
|
||||
// set for the project
|
||||
const val description = "Information about the system, Java runtime, OS, Window Manager, and Desktop Environment."
|
||||
const val group = "com.dorkbox"
|
||||
const val version = "1.0"
|
||||
const val version = "1.11"
|
||||
|
||||
// set as project.ext
|
||||
const val name = "OS"
|
||||
|
@ -46,8 +44,6 @@ object Extras {
|
|||
const val vendor = "Dorkbox LLC"
|
||||
const val vendorUrl = "https://dorkbox.com"
|
||||
const val url = "https://git.dorkbox.com/dorkbox/OS"
|
||||
|
||||
val buildDate = Instant.now().toString()
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
|
@ -77,7 +73,7 @@ tasks.jar.get().apply {
|
|||
attributes["Specification-Vendor"] = Extras.vendor
|
||||
|
||||
attributes["Implementation-Title"] = "${Extras.group}.${Extras.id}"
|
||||
attributes["Implementation-Version"] = Extras.buildDate
|
||||
attributes["Implementation-Version"] = GradleUtils.now()
|
||||
attributes["Implementation-Vendor"] = Extras.vendor
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +82,7 @@ dependencies {
|
|||
api("com.dorkbox:Updates:1.1")
|
||||
}
|
||||
|
||||
|
||||
publishToSonatype {
|
||||
groupId = Extras.group
|
||||
artifactId = Extras.id
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2018 dorkbox, llc
|
||||
* Copyright 2023 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,3 +13,4 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
rootProject.name = "OS"
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package dorkbox.os
|
||||
|
||||
internal object JVM {
|
||||
// java 8 cannot use JPMS. We use a multi-release jar to detect the state for java9+ runtimes
|
||||
|
||||
/**
|
||||
* Returns true if the currently running JVM is using the classpath or modules (JPMS)
|
||||
*/
|
||||
var usesJpms = false
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2022 dorkbox, llc
|
||||
* Copyright 2023 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -20,8 +20,6 @@ package dorkbox.os
|
|||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.security.AccessController
|
||||
import java.security.PrivilegedAction
|
||||
import java.util.*
|
||||
import java.util.concurrent.*
|
||||
|
||||
|
@ -29,7 +27,7 @@ object OS {
|
|||
/**
|
||||
* Gets the version number.
|
||||
*/
|
||||
const val version = "1.0"
|
||||
const val version = "1.11"
|
||||
|
||||
init {
|
||||
// Add this project to the updates system, which verifies this class + UUID + version information
|
||||
|
@ -74,10 +72,15 @@ object OS {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the currently running JVM is using the classpath or modules (JPMS)
|
||||
*/
|
||||
val usesJpms = JVM.usesJpms
|
||||
|
||||
/**
|
||||
* Returns the *ORIGINAL* system time zone, before (*IF*) it was changed to UTC
|
||||
*/
|
||||
val originalTimeZone = TimeZone.getDefault().id
|
||||
val originalTimeZone = TimeZone.getDefault().id!!
|
||||
|
||||
/**
|
||||
* JVM reported osName, the default (if there is none detected) is 'linux'
|
||||
|
@ -107,7 +110,7 @@ object OS {
|
|||
// android check from https://stackoverflow.com/questions/14859954/android-os-arch-output-for-arm-mips-x86
|
||||
when (osArch) {
|
||||
"armeabi" -> {
|
||||
OSType.AndroidArm56 // really old/low-end non-hf 32bit cpu
|
||||
OSType.AndroidArm56 // old/low-end non-hf 32bit cpu
|
||||
}
|
||||
"armeabi-v7a" -> {
|
||||
OSType.AndroidArm7 // 32bit hf cpu
|
||||
|
@ -175,11 +178,14 @@ object OS {
|
|||
}
|
||||
} else if (osName.startsWith("mac") || osName.startsWith("darwin")) {
|
||||
when (osArch) {
|
||||
"x86_64", "aarch64" -> {
|
||||
"x86_64" -> {
|
||||
OSType.MacOsX64
|
||||
}
|
||||
"aarch64" -> {
|
||||
OSType.MacOsArm
|
||||
}
|
||||
else -> {
|
||||
OSType.MacOsX32 // new macosx is no longer 32 bit, but just in case.
|
||||
OSType.MacOsX32 // new macOS is no longer 32 bit, but just in case.
|
||||
}
|
||||
}
|
||||
} else if (osName.startsWith("freebsd") ||
|
||||
|
@ -235,19 +241,32 @@ object OS {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears/removes the property from the system properties.
|
||||
*/
|
||||
fun clearProperty(property: String) {
|
||||
System.clearProperty(property)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the previous value of the system property, or 'null' if it did not have one.
|
||||
*/
|
||||
fun setProperty(property: String, value: String): String? {
|
||||
return System.setProperty(property, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the previous value of the system property, or the [defaultValue] if it did not have one.
|
||||
*/
|
||||
fun setProperty(property: String, value: String, defaultValue: String): String {
|
||||
return System.setProperty(property, value) ?: defaultValue
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value of the Java system property with the specified `property`, or null if it does not exist.
|
||||
*/
|
||||
fun getProperty(property: String): String? {
|
||||
return try {
|
||||
if (System.getSecurityManager() == null) {
|
||||
System.getProperty(property, null)
|
||||
} else {
|
||||
AccessController.doPrivileged(PrivilegedAction { System.getProperty(property, null) })
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
}
|
||||
return System.getProperty(property, null)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -255,45 +274,29 @@ object OS {
|
|||
* specified default value if the property access fails.
|
||||
*/
|
||||
fun getProperty(property: String, defaultValue: String): String {
|
||||
return try {
|
||||
if (System.getSecurityManager() == null) {
|
||||
System.getProperty(property, defaultValue)
|
||||
} else {
|
||||
AccessController.doPrivileged(PrivilegedAction { System.getProperty(property, defaultValue) })
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
defaultValue
|
||||
}
|
||||
return System.getProperty(property, defaultValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Java system properties in a safe way.
|
||||
*/
|
||||
fun getProperties(): Map<String, String> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return System.getProperties().toMap() as Map<String, String>
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the System Environment property in a safe way for a given property, or null if it does not exist.
|
||||
*/
|
||||
fun getEnv(): Map<String, String> {
|
||||
return try {
|
||||
if (System.getSecurityManager() == null) {
|
||||
System.getenv()
|
||||
} else {
|
||||
AccessController.doPrivileged(PrivilegedAction { System.getenv() })
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
mapOf()
|
||||
}
|
||||
return System.getenv()
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the System Environment property in a safe way for a given property, or null if it does not exist.
|
||||
*/
|
||||
fun getEnv(property: String): String? {
|
||||
return try {
|
||||
if (System.getSecurityManager() == null) {
|
||||
System.getenv(property)
|
||||
} else {
|
||||
AccessController.doPrivileged(PrivilegedAction { System.getenv(property) })
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
null
|
||||
}
|
||||
return System.getenv(property)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -301,7 +304,7 @@ object OS {
|
|||
* specified default value if the property access fails.
|
||||
*/
|
||||
fun getEnv(property: String, defaultValue: String): String {
|
||||
return getEnv(property) ?: defaultValue
|
||||
return getEnv(property, defaultValue)
|
||||
}
|
||||
|
||||
|
||||
|
@ -311,7 +314,7 @@ object OS {
|
|||
*/
|
||||
fun getBoolean(property: String, defaultValue: Boolean): Boolean {
|
||||
var value = getProperty(property) ?: return defaultValue
|
||||
value = value.trim { it <= ' ' }.lowercase(Locale.getDefault())
|
||||
value = value.trim().lowercase(Locale.getDefault())
|
||||
if (value.isEmpty()) {
|
||||
return defaultValue
|
||||
}
|
||||
|
@ -331,7 +334,7 @@ object OS {
|
|||
*/
|
||||
fun getInt(property: String, defaultValue: Int): Int {
|
||||
var value = getProperty(property) ?: return defaultValue
|
||||
value = value.trim { it <= ' ' }
|
||||
value = value.trim()
|
||||
|
||||
try {
|
||||
return value.toInt()
|
||||
|
@ -346,7 +349,7 @@ object OS {
|
|||
*/
|
||||
fun getLong(property: String, defaultValue: Long): Long {
|
||||
var value = getProperty(property) ?: return defaultValue
|
||||
value = value.trim { it <= ' ' }
|
||||
value = value.trim()
|
||||
|
||||
try {
|
||||
return value.toLong()
|
||||
|
@ -361,7 +364,7 @@ object OS {
|
|||
*/
|
||||
fun getFloat(property: String, defaultValue: Float): Float {
|
||||
var value = getProperty(property) ?: return defaultValue
|
||||
value = value.trim { it <= ' ' }
|
||||
value = value.trim()
|
||||
|
||||
try {
|
||||
return value.toFloat()
|
||||
|
@ -376,7 +379,7 @@ object OS {
|
|||
*/
|
||||
fun getDouble(property: String, defaultValue: Double): Double {
|
||||
var value = getProperty(property) ?: return defaultValue
|
||||
value = value.trim { it <= ' ' }
|
||||
value = value.trim()
|
||||
|
||||
try {
|
||||
return value.toDouble()
|
||||
|
@ -391,7 +394,7 @@ object OS {
|
|||
val is64bit = type.is64bit
|
||||
|
||||
/**
|
||||
* @return true if this is a x86/x64/arm architecture (intel/amd/etc) processor.
|
||||
* @return true if this is x86/x64/arm architecture (intel/amd/etc) processor.
|
||||
*/
|
||||
val isX86 = type.isX86
|
||||
val isMips = type.isMips
|
||||
|
@ -435,12 +438,13 @@ object OS {
|
|||
* This is based on an aggregate of the answers provided here: [https://stackoverflow.com/questions/35421699/how-to-invoke-external-command-from-within-kotlin-code]
|
||||
*/
|
||||
private fun execute(vararg args: String, timeout: Long = 60): String {
|
||||
return ProcessBuilder(args.toList())
|
||||
val process = ProcessBuilder(args.toList())
|
||||
.redirectOutput(ProcessBuilder.Redirect.PIPE)
|
||||
.redirectError(ProcessBuilder.Redirect.PIPE)
|
||||
.start()
|
||||
.apply { waitFor(timeout, TimeUnit.SECONDS) }
|
||||
.inputStream.bufferedReader().readText().trim()
|
||||
val text = process.inputStream.bufferedReader().readText().trim()
|
||||
process.waitFor(timeout, TimeUnit.SECONDS)
|
||||
return text
|
||||
}
|
||||
|
||||
// true if the exit code is 0 (meaning standard exit)
|
||||
|
@ -495,23 +499,39 @@ object OS {
|
|||
Windows 10 10.0.14393 (2016-07-18)
|
||||
|
||||
Windows Server 2016 10.0.14393 (2016-10-12)
|
||||
```
|
||||
Windows Server 2019 10.0.17763 (2018-10-02)
|
||||
Windows Server 2022 10.0.20348 (2021-08-18)
|
||||
|
||||
Windows 11 Original Release 10.0.22000 (2021-10-05)
|
||||
Windows 11 2022 Update 10.0.22621 (2022-09-20)
|
||||
```
|
||||
* @return the {major}{minor} version of windows, ie: Windows Version 10.0.10586 -> {10}{0}
|
||||
*/
|
||||
val version: IntArray by lazy {
|
||||
if (!isWindows) {
|
||||
intArrayOf(0, 0)
|
||||
intArrayOf(0, 0, 0)
|
||||
} else {
|
||||
val version = IntArray(2)
|
||||
val version = IntArray(3)
|
||||
|
||||
try {
|
||||
val output = getProperty("os.version")
|
||||
if (output != null) {
|
||||
val split = output.split("\\.").dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (split.size <= 2) {
|
||||
for (i in split.indices) {
|
||||
version[i] = split[i].toInt()
|
||||
}
|
||||
val output = execute("cmd.exe", "/c", "ver")
|
||||
if (output.isNotEmpty()) {
|
||||
// OF NOTE: It is possible to have a different encoding of windows, where the word "Version" doesn't exist.
|
||||
// in this case, we'll just take the next set of numbers available
|
||||
// Microsoft Windows [Version 10.0.22000.2600]
|
||||
// Microsoft Windows [??? 10.0.22621.2283] (different encoding)
|
||||
|
||||
// slice out the [] because we don't want to include windows product names! (like Windows 2012) in the name!
|
||||
// I don't specifically have this version to test, however it is easy enough to guard against.
|
||||
val shortenedOutput = output.substring(output.indexOf("[") + 1, output.indexOf("]"))
|
||||
val index = shortenedOutput.indexOfFirst { it.isDigit() }
|
||||
val versionInfoOnly = shortenedOutput.substring(index, shortenedOutput.length)
|
||||
|
||||
val split = versionInfoOnly.split(".").toTypedArray()
|
||||
if (split.size == 4) {
|
||||
version[0] = split[0].toInt()
|
||||
version[1] = split[1].toInt()
|
||||
version[2] = split[2].toInt()
|
||||
}
|
||||
}
|
||||
} catch (ignored: Throwable) {
|
||||
|
@ -521,32 +541,32 @@ object OS {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return is windows XP or equivalent
|
||||
* @return is Windows XP or equivalent
|
||||
*/
|
||||
val isWindowsXP = version[0] == 5
|
||||
|
||||
/**
|
||||
* @return is windows Vista or equivalent
|
||||
* @return is Windows Vista or equivalent
|
||||
*/
|
||||
val isWindowsVista = version[0] == 6 && version[1] == 0
|
||||
|
||||
/**
|
||||
* @return is windows 7 or equivalent
|
||||
* @return is Windows 7 or equivalent
|
||||
*/
|
||||
val isWindows7 = version[0] == 6 && version[1] == 1
|
||||
|
||||
/**
|
||||
* @return is windows 8 or equivalent
|
||||
* @return is Windows 8 or equivalent
|
||||
*/
|
||||
val isWindows8 = version[0] == 6 && version[1] == 2
|
||||
|
||||
/**
|
||||
* @return is windows 8.1 or equivalent
|
||||
* @return is Windows 8.1 or equivalent
|
||||
*/
|
||||
val isWindows8_1 = version[0] == 6 && version[1] == 3
|
||||
|
||||
/**
|
||||
* @return is greater than or equal to windows 8.1 or equivalent
|
||||
* @return is greater than or equal to Windows 8.1 or equivalent
|
||||
*/
|
||||
val isWindows8_1_plus: Boolean by lazy {
|
||||
val version = version
|
||||
|
@ -558,19 +578,24 @@ object OS {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return is windows 10 or equivalent
|
||||
* @return is Windows 10 or equivalent
|
||||
*/
|
||||
val isWindows10 = version[0] == 10
|
||||
|
||||
/**
|
||||
* @return is windows 11 or equivalent
|
||||
*/
|
||||
val isWindows11 = version[0] == 11
|
||||
|
||||
/**
|
||||
* @return is windows 10 or greater
|
||||
* @return is Windows 10 or greater
|
||||
*/
|
||||
val isWindows10_plus = version[0] >= 10
|
||||
|
||||
/**
|
||||
* @return is Windows 11 (original release was 21H2)
|
||||
*/
|
||||
val isWindows11 = version[0] == 10 && version[1] == 0 && version[2] >= 22000
|
||||
|
||||
/**
|
||||
* @return is Windows 11 update 22H2
|
||||
*/
|
||||
val isWindows11_22H2 = version[0] == 10 && version[1] == 0 && version[2] >= 22621
|
||||
}
|
||||
|
||||
object Unix {
|
||||
|
@ -728,7 +753,7 @@ object OS {
|
|||
if (!isUbuntu) {
|
||||
intArrayOf(0, 0)
|
||||
} else if (distribReleaseInfo != null) {
|
||||
val split = distribReleaseInfo!!.split("\\.").toTypedArray()
|
||||
val split = distribReleaseInfo!!.split(".").toTypedArray()
|
||||
intArrayOf(split[0].toInt(), split[1].toInt())
|
||||
} else {
|
||||
intArrayOf(0, 0)
|
||||
|
@ -746,7 +771,7 @@ object OS {
|
|||
if (!isElementaryOS) {
|
||||
intArrayOf(0, 0)
|
||||
} else if (distribReleaseInfo != null) {
|
||||
val split = distribReleaseInfo!!.split("\\.").toTypedArray()
|
||||
val split = distribReleaseInfo!!.split(".").toTypedArray()
|
||||
intArrayOf(split[0].toInt(), split[1].toInt())
|
||||
} else {
|
||||
intArrayOf(0, 0)
|
||||
|
@ -809,7 +834,7 @@ object OS {
|
|||
if (data == null) {
|
||||
// reading the file didn't work for whatever reason...
|
||||
// uname -v
|
||||
data = execute("uname", "-v").contains("-Microsoft")
|
||||
data = execute("/usr/bin/uname", "-v").contains("-Microsoft")
|
||||
}
|
||||
|
||||
if (data == true) {
|
||||
|
@ -830,7 +855,7 @@ object OS {
|
|||
// running as root (also can be "sudo" user). A lot slower that checking a sys env, but this is guaranteed to work
|
||||
try {
|
||||
// id -u
|
||||
isSudoOrRoot = "0" == execute("id", "-u")
|
||||
isSudoOrRoot = "0" == execute("/usr/bin/id", "-u")
|
||||
} catch (ignored: Throwable) {
|
||||
}
|
||||
}
|
||||
|
@ -870,7 +895,7 @@ object OS {
|
|||
// dpkg-query: package 'libappindicator3' is not installed
|
||||
val is_dpkg = File("/usr/bin/dpkg").canExecute()
|
||||
if (is_dpkg) {
|
||||
return !execute("dpkg", "-L", packageName).contains("is not installed")
|
||||
return !execute("/usr/bin/dpkg", "-L", packageName).contains("is not installed")
|
||||
}
|
||||
|
||||
// rpm
|
||||
|
@ -878,7 +903,7 @@ object OS {
|
|||
// package libappindicator234 is not installed
|
||||
val is_rpm = File("/usr/bin/rpm").canExecute()
|
||||
if (is_rpm) {
|
||||
return !execute("rpm", "-q", packageName).contains("is not installed")
|
||||
return !execute("/usr/bin/rpm", "-q", packageName).contains("is not installed")
|
||||
}
|
||||
|
||||
|
||||
|
@ -889,7 +914,7 @@ object OS {
|
|||
try {
|
||||
// use the exit code to determine if the packages exists on the system
|
||||
// 0 the package exists, 1 it doesn't
|
||||
return executeStatus("pacman", "-Qi", packageName)
|
||||
return executeStatus("/usr/bin/pacman", "-Qi", packageName)
|
||||
|
||||
//return start == 0
|
||||
} catch (ignored: Exception) {
|
||||
|
@ -910,6 +935,229 @@ object OS {
|
|||
X11, WAYLAND, Unknown
|
||||
}
|
||||
|
||||
private fun isValidCommand(partialExpectationInOutput: String, commandOutput: String): Boolean {
|
||||
return (commandOutput.contains(partialExpectationInOutput) &&
|
||||
!commandOutput.contains("not installed") &&
|
||||
!commandOutput.contains("No such file or directory"))
|
||||
}
|
||||
|
||||
// have no idea how this can happen....
|
||||
val type: EnvType by lazy {
|
||||
when (getEnv("XDG_SESSION_TYPE")) {
|
||||
"x11" -> {
|
||||
EnvType.X11
|
||||
}
|
||||
"wayland" -> {
|
||||
EnvType.WAYLAND
|
||||
}
|
||||
else -> {
|
||||
EnvType.Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isX11 = type == EnvType.X11
|
||||
val isWayland = type == EnvType.WAYLAND
|
||||
|
||||
|
||||
val isMATE: Boolean by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
File("/usr/bin/mate-about").exists()
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isGnome: Boolean by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
// note: some versions of linux can ONLY access "ps a"; FreeBSD and most linux is "ps x"
|
||||
// we try "x" first
|
||||
|
||||
// ps x | grep gnome-shell
|
||||
var contains = execute("/usr/bin/ps", "x").contains("gnome-shell")
|
||||
if (!contains && isLinux) {
|
||||
// only try again if we are linux
|
||||
|
||||
// ps a | grep gnome-shell
|
||||
contains = execute("/usr/bin/ps", "a").contains("gnome-shell")
|
||||
}
|
||||
contains
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a string representing the current gnome-shell version, or NULL if it could not be found
|
||||
*/
|
||||
val gnomeVersion: String? by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
null
|
||||
} else {
|
||||
try {
|
||||
// gnome-shell --version
|
||||
val versionString = execute("/usr/bin/gnome-shell", "--version")
|
||||
if (versionString.isNotEmpty()) {
|
||||
// GNOME Shell 3.14.1
|
||||
val version = versionString.replace("[^\\d.]".toRegex(), "")
|
||||
if (version.isNotEmpty() && version.indexOf('.') > 0) {
|
||||
// should just be 3.14.1 or 3.20 or similar
|
||||
version
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (ignored: Throwable) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if plasmashell is running, if it is -- then we are most likely KDE
|
||||
val isKDE: Boolean by lazy {
|
||||
val XDG = getEnv("XDG_CURRENT_DESKTOP")
|
||||
if (XDG == null) {
|
||||
// Check if plasmashell is running, if it is -- then we are most likely KDE
|
||||
plasmaVersionFull != null && !plasmaVersionFull!!.startsWith("0")
|
||||
} else {
|
||||
"kde".equals(XDG, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The full version number of plasma shell (if running) as a String.
|
||||
*
|
||||
* @return cannot represent '5.6.5' as a number, so we return a String instead or NULL if unknown
|
||||
*/
|
||||
val plasmaVersionFull: String? by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
null
|
||||
} else {
|
||||
try {
|
||||
// plasma-desktop -v
|
||||
// plasmashell --version
|
||||
val output = execute("/usr/bin/plasmashell", "--version")
|
||||
if (output.isNotEmpty()) {
|
||||
// DEFAULT icon size is 16. KDE is bananas on what they did with tray icon scale
|
||||
// should be: plasmashell 5.6.5 or something
|
||||
val s = "plasmashell "
|
||||
if (isValidCommand(s, output)) {
|
||||
output.substring(output.indexOf(s) + s.length)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (ignored: Throwable) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isXfce: Boolean by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
// note: some versions of linux can ONLY access "ps a"; FreeBSD and most linux is "ps x"
|
||||
// we try "x" first
|
||||
|
||||
// ps x | grep xfce
|
||||
var contains = execute("/usr/bin/ps", "x").contains("xfce")
|
||||
if (!contains && isLinux) {
|
||||
// only try again if we are linux
|
||||
|
||||
// ps a | grep gnome-shell
|
||||
contains = execute("/usr/bin/ps", "a").contains("xfce")
|
||||
}
|
||||
contains
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* There are sometimes problems with nautilus (the file browser) and some GTK methods. It is ridiculous for me to have to
|
||||
* work around their bugs like this.
|
||||
*
|
||||
* see: https://askubuntu.com/questions/788182/nautilus-not-opening-up-showing-glib-error
|
||||
*/
|
||||
val isNautilus: Boolean by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
// nautilus --version
|
||||
val output = execute("/usr/bin/nautilus", "--version")
|
||||
if (output.isNotEmpty()) {
|
||||
// should be: GNOME nautilus 3.14.3 or something
|
||||
val s = "GNOME nautilus "
|
||||
isValidCommand(s, output)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isChromeOS: Boolean by lazy {
|
||||
if (!isLinux) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
// ps aux | grep chromeos
|
||||
execute("/usr/bin/ps", "aux").contains("chromeos")
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channel which XFCE channel to query. Cannot be null
|
||||
* @param property which property (in the channel) to query. Null will list all properties in the channel
|
||||
*
|
||||
* @return the property value or "".
|
||||
*/
|
||||
fun queryXfce(channel: String, property: String?): String {
|
||||
if (!isLinux && !isUnix) {
|
||||
return ""
|
||||
}
|
||||
try {
|
||||
// xfconf-query -c xfce4-panel -l
|
||||
val commands: MutableList<String> = ArrayList()
|
||||
commands.add("/usr/bin/xfconf-query")
|
||||
commands.add("-c")
|
||||
commands.add(channel)
|
||||
if (property != null) {
|
||||
// get property for channel
|
||||
commands.add("-p")
|
||||
commands.add(property)
|
||||
} else {
|
||||
// list all properties for the channel
|
||||
commands.add("-l")
|
||||
}
|
||||
|
||||
return execute(*commands.toTypedArray())
|
||||
} catch (ignored: Throwable) {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
val env: Env by lazy {
|
||||
// if we are running as ROOT, we *** WILL NOT *** have access to 'XDG_CURRENT_DESKTOP'
|
||||
// *unless env's are preserved, but they are not guaranteed to be
|
||||
|
@ -963,251 +1211,10 @@ object OS {
|
|||
}
|
||||
}
|
||||
|
||||
private fun isValidCommand(partialExpectationInOutput: String, commandOutput: String): Boolean {
|
||||
return (commandOutput.contains(partialExpectationInOutput) &&
|
||||
!commandOutput.contains("not installed") &&
|
||||
!commandOutput.contains("No such file or directory"))
|
||||
}
|
||||
|
||||
// have no idea how this can happen....
|
||||
val type: EnvType by lazy {
|
||||
when (getEnv("XDG_SESSION_TYPE")) {
|
||||
"x11" -> {
|
||||
EnvType.X11
|
||||
}
|
||||
"wayland" -> {
|
||||
EnvType.WAYLAND
|
||||
}
|
||||
else -> {
|
||||
EnvType.Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isX11 = type == EnvType.X11
|
||||
val isWayland = type == EnvType.WAYLAND
|
||||
val isUnity = isUnity(env)
|
||||
|
||||
fun isUnity(env: Env): Boolean {
|
||||
return env == Env.Unity || env == Env.Unity7
|
||||
}
|
||||
|
||||
val isMATE: Boolean by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
File("/usr/bin/mate-about").exists()
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isGnome: Boolean by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
// note: some versions of linux can ONLY access "ps a"; FreeBSD and most linux is "ps x"
|
||||
// we try "x" first
|
||||
|
||||
// ps x | grep gnome-shell
|
||||
var contains = execute("ps", "x").contains("gnome-shell")
|
||||
if (!contains && isLinux) {
|
||||
// only try again if we are linux
|
||||
|
||||
// ps a | grep gnome-shell
|
||||
contains = execute("ps", "a").contains("gnome-shell")
|
||||
}
|
||||
contains
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a string representing the current gnome-shell version, or NULL if it could not be found
|
||||
*/
|
||||
val gnomeVersion: String? by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
null
|
||||
} else {
|
||||
try {
|
||||
// gnome-shell --version
|
||||
val versionString = execute("gnome-shell", "--version")
|
||||
if (versionString.isNotEmpty()) {
|
||||
// GNOME Shell 3.14.1
|
||||
val version = versionString.replace("[^\\d.]".toRegex(), "")
|
||||
if (version.isNotEmpty() && version.indexOf('.') > 0) {
|
||||
// should just be 3.14.1 or 3.20 or similar
|
||||
version
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (ignored: Throwable) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if plasmashell is running, if it is -- then we are most likely KDE
|
||||
val isKDE: Boolean by lazy {
|
||||
val XDG = getEnv("XDG_CURRENT_DESKTOP")
|
||||
if (XDG == null) {
|
||||
// Check if plasmashell is running, if it is -- then we are most likely KDE
|
||||
val plasmaVersion = plasmaVersion
|
||||
plasmaVersion > 0
|
||||
} else {
|
||||
"kde".equals(XDG, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The full version number of plasma shell (if running) as a String.
|
||||
*
|
||||
* @return cannot represent '5.6.5' as a number, so we return a String instead or NULL if unknown
|
||||
*/
|
||||
val plasmaVersionFull: String? by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
null
|
||||
} else {
|
||||
try {
|
||||
// plasma-desktop -v
|
||||
// plasmashell --version
|
||||
val output = execute("plasmashell", "--version")
|
||||
if (output.isNotEmpty()) {
|
||||
// DEFAULT icon size is 16. KDE is bananas on what they did with tray icon scale
|
||||
// should be: plasmashell 5.6.5 or something
|
||||
val s = "plasmashell "
|
||||
if (isValidCommand(s, output)) {
|
||||
output.substring(output.indexOf(s) + s.length)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (ignored: Throwable) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The first two decimal places of the version number of plasma shell (if running) as a double.
|
||||
*
|
||||
* @return cannot represent '5.6.5' as a number, so we return just the first two decimal places instead
|
||||
*/
|
||||
val plasmaVersion: Double by lazy {
|
||||
if (plasmaVersionFull == null || plasmaVersionFull!!.startsWith("0")) {
|
||||
0.0
|
||||
} else {
|
||||
// this isn't the BEST way to do this, but it's simple and easy to understand
|
||||
val split = plasmaVersionFull!!.split("\\.", limit = 3).toTypedArray()
|
||||
if (split.size > 2) {
|
||||
(split[0] + "." + split[1]).toDouble()
|
||||
} else {
|
||||
split[0].toDouble()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isXfce: Boolean by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
// note: some versions of linux can ONLY access "ps a"; FreeBSD and most linux is "ps x"
|
||||
// we try "x" first
|
||||
|
||||
// ps x | grep xfce
|
||||
var contains = execute("ps", "x").contains("xfce")
|
||||
if (!contains && isLinux) {
|
||||
// only try again if we are linux
|
||||
|
||||
// ps a | grep gnome-shell
|
||||
contains = execute("ps", "a").contains("xfce")
|
||||
}
|
||||
contains
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* There are sometimes problems with nautilus (the file browser) and some GTK methods. It is ridiculous for me to have to
|
||||
* work around their bugs like this.
|
||||
*
|
||||
* see: https://askubuntu.com/questions/788182/nautilus-not-opening-up-showing-glib-error
|
||||
*/
|
||||
val isNautilus: Boolean by lazy {
|
||||
if (!isLinux && !isUnix) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
// nautilus --version
|
||||
val output = execute("nautilus", "--version")
|
||||
if (output.isNotEmpty()) {
|
||||
// should be: GNOME nautilus 3.14.3 or something
|
||||
val s = "GNOME nautilus "
|
||||
isValidCommand(s, output)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isChromeOS: Boolean by lazy {
|
||||
if (!isLinux) {
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
// ps aux | grep chromeos
|
||||
execute("ps", "aux").contains("chromeos")
|
||||
} catch (ignored: Throwable) {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channel which XFCE channel to query. Cannot be null
|
||||
* @param property which property (in the channel) to query. Null will list all properties in the channel
|
||||
*
|
||||
* @return the property value or "".
|
||||
*/
|
||||
fun queryXfce(channel: String, property: String?): String {
|
||||
if (!isLinux && !isUnix) {
|
||||
return ""
|
||||
}
|
||||
try {
|
||||
// xfconf-query -c xfce4-panel -l
|
||||
val commands: MutableList<String> = ArrayList()
|
||||
commands.add("xfconf-query")
|
||||
commands.add("-c")
|
||||
commands.add(channel)
|
||||
if (property != null) {
|
||||
// get property for channel
|
||||
commands.add("-p")
|
||||
commands.add(property)
|
||||
} else {
|
||||
// list all properties for the channel
|
||||
commands.add("-l")
|
||||
}
|
||||
|
||||
return execute(*commands.toTypedArray())
|
||||
} catch (ignored: Throwable) {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2010 dorkbox, llc
|
||||
* Copyright 2023 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -23,6 +23,7 @@ enum class OSType(name: String, vararg libraryNames: String) {
|
|||
|
||||
MacOsX32("macosx_32", ".jnilib", ".dylib"),
|
||||
MacOsX64("macosx_64", ".jnilib", ".dylib"),
|
||||
MacOsArm("macosx_aarch64", ".jnilib", ".dylib"),
|
||||
UnixArm("unix_arm", ".so"),
|
||||
Unix32("unix_32",".so"),
|
||||
|
||||
|
@ -54,7 +55,7 @@ enum class OSType(name: String, vararg libraryNames: String) {
|
|||
|
||||
val is64bit: Boolean
|
||||
get() {
|
||||
return this == Linux64 || this == LinuxArm64 || this == Windows64 || this == MacOsX64 || this == AndroidArm8 || this == AndroidX86_64 || this == AndroidMips64 || this == Unix64
|
||||
return this == Linux64 || this == LinuxArm64 || this == Windows64 || this == MacOsX64 || this == MacOsArm || this == AndroidArm8 || this == AndroidX86_64 || this == AndroidMips64 || this == Unix64
|
||||
}
|
||||
|
||||
val is32bit: Boolean
|
||||
|
@ -71,7 +72,7 @@ enum class OSType(name: String, vararg libraryNames: String) {
|
|||
val isX86: Boolean
|
||||
get() = this == Linux64 || this == LinuxArm64 || this == Windows64 || this == MacOsX64 || this == Linux32 || this == LinuxArm32 || this == Windows32 || this == MacOsX32 || this == Unix32 || this == Unix64 || this == AndroidX86 || this == AndroidX86_64
|
||||
val isArm: Boolean
|
||||
get() = this == LinuxArm32 || this == LinuxArm64 || this == AndroidArm56 || this == AndroidArm7 || this == AndroidArm8
|
||||
get() = this == LinuxArm32 || this == LinuxArm64 || this == AndroidArm56 || this == AndroidArm7 || this == AndroidArm8 || this == MacOsArm || this == UnixArm
|
||||
val isLinux: Boolean
|
||||
get() = this == Linux32 || this == Linux64 || this == LinuxArm64 || this == LinuxArm32
|
||||
val isUnix: Boolean
|
||||
|
@ -81,7 +82,7 @@ enum class OSType(name: String, vararg libraryNames: String) {
|
|||
val isWindows: Boolean
|
||||
get() = this == Windows64 || this == Windows32
|
||||
val isMacOsX: Boolean
|
||||
get() = this == MacOsX64 || this == MacOsX32
|
||||
get() = this == MacOsX64 || this == MacOsX32 || this == MacOsArm
|
||||
val isAndroid: Boolean
|
||||
get() = this == AndroidArm56 || this == AndroidArm7 || this == AndroidX86 || this == AndroidMips || this == AndroidArm8 || this == AndroidX86_64 || this == AndroidMips64
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 dorkbox, llc
|
||||
*
|
||||
* 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 dorkbox.os;
|
||||
|
||||
/**
|
||||
* Required for intellij to not complain regarding `module-info` for a multi-release jar.
|
||||
* This file is completely ignored by the gradle build process
|
||||
*/
|
||||
public
|
||||
class EmptyClass {}
|
|
@ -0,0 +1,8 @@
|
|||
package dorkbox.os
|
||||
|
||||
internal object JVM {
|
||||
/**
|
||||
* Returns true if the currently running JVM is using the classpath or modules (JPMS)
|
||||
*/
|
||||
var usesJpms = true == java.lang.ModuleLayer.boot().findModule("java.desktop").isPresent
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
module dorkbox.os {
|
||||
exports dorkbox.os;
|
||||
|
||||
requires transitive dorkbox.updates;
|
||||
|
||||
requires transitive kotlin.stdlib;
|
||||
|
||||
requires java.base;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue