├── .clang-format ├── .editorconfig ├── .gitattributes ├── .github ├── dco.yml ├── dependabot.yml └── workflows │ ├── build-scan-commit-status.yml │ ├── codeql-analysis.yml │ ├── dependency-review-action.yml │ └── dependency-submission.yml ├── .gitignore ├── .lgtm.yml ├── .teamcity ├── Agent.kt ├── NativePlatformBuild.kt ├── NativePlatformCompatibilityTest.kt ├── NativePlatformPublishing.kt ├── Os.kt ├── ReleaseType.kt ├── extensions.kt ├── pom.xml └── settings.kts ├── .vscode ├── c_cpp_properties.json ├── launch.json └── settings.json ├── LICENSE ├── build.gradle.kts ├── buildSrc ├── build.gradle ├── settings.gradle └── src │ └── main │ └── java │ └── gradlebuild │ ├── FreeBsdPlugin.java │ ├── JniPlugin.java │ ├── NativePlatformComponentPlugin.java │ ├── NativePlatformVersionExtension.java │ ├── NativeRulesUtils.java │ ├── NcursesPlugin.java │ ├── PublishPlugin.java │ ├── PublishRepositoryCredentials.java │ ├── ReleasePlugin.java │ ├── VariantsExtension.java │ ├── VersionDetails.java │ ├── VersioningPlugin.java │ └── WriteNativeVersionSources.java ├── gradle.properties ├── gradle ├── verification-keyring.keys ├── verification-metadata.xml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── native-platform ├── build.gradle └── src │ ├── curses │ └── cpp │ │ └── curses.cpp │ ├── main │ ├── cpp │ │ ├── apple.cpp │ │ ├── freebsd.cpp │ │ ├── linux.cpp │ │ ├── posix.cpp │ │ └── win.cpp │ └── java │ │ └── net │ │ └── rubygrapefruit │ │ └── platform │ │ ├── MissingRegistryEntryException.java │ │ ├── Native.java │ │ ├── NativeException.java │ │ ├── NativeIntegration.java │ │ ├── NativeIntegrationLinkageException.java │ │ ├── NativeIntegrationUnavailableException.java │ │ ├── Process.java │ │ ├── ProcessLauncher.java │ │ ├── ResourceClosedException.java │ │ ├── SystemInfo.java │ │ ├── ThreadSafe.java │ │ ├── WindowsRegistry.java │ │ ├── file │ │ ├── CaseSensitivity.java │ │ ├── DirEntry.java │ │ ├── FileInfo.java │ │ ├── FilePermissionException.java │ │ ├── FileSystemInfo.java │ │ ├── FileSystems.java │ │ ├── Files.java │ │ ├── NoSuchFileException.java │ │ ├── NotADirectoryException.java │ │ ├── PosixFileInfo.java │ │ ├── PosixFiles.java │ │ ├── WindowsFileInfo.java │ │ ├── WindowsFiles.java │ │ └── package-info.java │ │ ├── internal │ │ ├── AbstractFiles.java │ │ ├── AbstractTerminal.java │ │ ├── AbstractTerminals.java │ │ ├── AbstractWindowsTerminalInput.java │ │ ├── AnsiTerminal.java │ │ ├── AnsiTerminals.java │ │ ├── CharInputBuffer.java │ │ ├── DefaultFileSystemInfo.java │ │ ├── DefaultOsxMemory.java │ │ ├── DefaultOsxMemoryInfo.java │ │ ├── DefaultPosixFiles.java │ │ ├── DefaultProcess.java │ │ ├── DefaultProcessLauncher.java │ │ ├── DefaultSystemInfo.java │ │ ├── DefaultWindowsFiles.java │ │ ├── DefaultWindowsMemory.java │ │ ├── DefaultWindowsMemoryInfo.java │ │ ├── DefaultWindowsRegistry.java │ │ ├── DirList.java │ │ ├── FileStat.java │ │ ├── FileSystemList.java │ │ ├── FunctionResult.java │ │ ├── LibraryDef.java │ │ ├── MutableSystemInfo.java │ │ ├── MutableTerminalSize.java │ │ ├── MutableTypeInfo.java │ │ ├── NativeLibraryLoader.java │ │ ├── NativeLibraryLocator.java │ │ ├── PeekInputStream.java │ │ ├── PlainTerminalInput.java │ │ ├── Platform.java │ │ ├── PosixFileSystems.java │ │ ├── PosixTerminalInput.java │ │ ├── PosixTerminals.java │ │ ├── TerminalCapabilities.java │ │ ├── TerminfoTerminal.java │ │ ├── WindowsDirList.java │ │ ├── WindowsFileStat.java │ │ ├── WindowsFileTime.java │ │ ├── WindowsProcessLauncher.java │ │ ├── WindowsTerminal.java │ │ ├── WindowsTerminalInput.java │ │ ├── WindowsTerminals.java │ │ ├── WrapperProcess.java │ │ ├── WrapperProcessLauncher.java │ │ └── jni │ │ │ ├── InsufficientResourcesForWatchingException.java │ │ │ ├── NativeLibraryFunctions.java │ │ │ ├── OsxMemoryFunctions.java │ │ │ ├── PosixFileFunctions.java │ │ │ ├── PosixFileSystemFunctions.java │ │ │ ├── PosixProcessFunctions.java │ │ │ ├── PosixTerminalFunctions.java │ │ │ ├── PosixTypeFunctions.java │ │ │ ├── TerminfoFunctions.java │ │ │ ├── WindowsConsoleFunctions.java │ │ │ ├── WindowsFileFunctions.java │ │ │ ├── WindowsHandleFunctions.java │ │ │ ├── WindowsMemoryFunctions.java │ │ │ └── WindowsRegistryFunctions.java │ │ ├── memory │ │ ├── Memory.java │ │ ├── MemoryInfo.java │ │ ├── OsxMemory.java │ │ ├── OsxMemoryInfo.java │ │ ├── WindowsMemory.java │ │ ├── WindowsMemoryInfo.java │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── prompts │ │ ├── AbstractListener.java │ │ ├── AbstractPrompter.java │ │ ├── InteractivePrompter.java │ │ ├── NonInteractivePrompter.java │ │ ├── PasswordView.java │ │ ├── PlainPrompter.java │ │ ├── Prompter.java │ │ ├── SelectView.java │ │ ├── SelectionListener.java │ │ ├── TextEntryListener.java │ │ ├── TextView.java │ │ ├── YesNoListener.java │ │ ├── YesNoView.java │ │ └── package-info.java │ │ └── terminal │ │ ├── TerminalInput.java │ │ ├── TerminalInputListener.java │ │ ├── TerminalOutput.java │ │ ├── TerminalSize.java │ │ ├── Terminals.java │ │ └── package-info.java │ ├── shared │ ├── cpp │ │ ├── generic.cpp │ │ ├── generic_posix.cpp │ │ ├── osx.cpp │ │ ├── unix_strings.cpp │ │ └── win.cpp │ └── headers │ │ ├── generic.h │ │ └── win.h │ ├── test │ └── groovy │ │ └── net │ │ └── rubygrapefruit │ │ └── platform │ │ ├── NativePlatformSpec.groovy │ │ ├── ProcessLauncherTest.groovy │ │ ├── ProcessTest.groovy │ │ ├── SystemInfoTest.groovy │ │ ├── WindowsRegistryTest.groovy │ │ ├── file │ │ ├── AbstractFilesTest.groovy │ │ ├── FileSystemsTest.groovy │ │ ├── FilesTest.groovy │ │ ├── PosixFilesTest.groovy │ │ └── WindowsFilesTest.groovy │ │ ├── internal │ │ ├── NativeTypeInfoTest.groovy │ │ └── PrompterTest.groovy │ │ ├── memory │ │ ├── MemoryTest.groovy │ │ ├── OsxMemoryTest.groovy │ │ └── WindowsMemoryTest.groovy │ │ ├── terminal │ │ └── TerminalsTest.groovy │ │ └── testfixture │ │ ├── JavaVersion.groovy │ │ └── JavaVersionTest.groovy │ └── testFixtures │ └── java │ └── net │ └── rubygrapefruit │ └── platform │ └── testfixture │ └── JniChecksEnabled.java ├── readme.md ├── settings.gradle.kts └── test-app ├── build.gradle └── src └── main └── java └── net └── rubygrapefruit └── platform └── test └── Main.java /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: WebKit 2 | AlignTrailingComments: true 3 | AllowShortFunctionsOnASingleLine: None 4 | BreakBeforeBraces: Attach 5 | BreakBeforeTernaryOperators: true 6 | IndentCaseLabels: true 7 | SpaceAfterCStyleCast: true 8 | SpacesBeforeTrailingComments: 4 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [gradle/verification-metadata.xml] 12 | indent_size = 3 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | 3 | # 4 | # The above will handle all files NOT found below 5 | # https://help.github.com/articles/dealing-with-line-endings/ 6 | # https://github.com/Danimoth/gitattributes 7 | 8 | # These are explicitly windows files and should use crlf 9 | *.bat text eol=crlf 10 | 11 | # These files are binary and should be left untouched 12 | # (binary is a macro for -text -diff) 13 | *.a binary 14 | *.lib binary 15 | *.icns binary 16 | *.png binary 17 | *.jpg binary 18 | *.jpeg binary 19 | *.gif binary 20 | *.ico binary 21 | *.mov binary 22 | *.mp4 binary 23 | *.mp3 binary 24 | *.flv binary 25 | *.fla binary 26 | *.swf binary 27 | *.gz binary 28 | *.zip binary 29 | *.jar binary 30 | *.tar binary 31 | *.tar.gz binary 32 | *.7z binary 33 | *.ttf binary 34 | *.pyc binary 35 | *.gpg binary 36 | -------------------------------------------------------------------------------- /.github/dco.yml: -------------------------------------------------------------------------------- 1 | # Disable sign-off checking for members of the Gradle GitHub organization 2 | require: 3 | members: false 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/build-scan-commit-status.yml: -------------------------------------------------------------------------------- 1 | name: Publish BuildScan Commit Status 2 | 3 | on: 4 | status 5 | 6 | permissions: 7 | statuses: write 8 | id-token: write 9 | 10 | jobs: 11 | build_scan_commit_status: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: configure aws credentials 15 | uses: aws-actions/configure-aws-credentials@v4 16 | with: 17 | role-to-assume: arn:aws:iam::992382829881:role/GHASecrets_native-platform_all 18 | aws-region: "eu-central-1" 19 | - name: get secrets 20 | uses: aws-actions/aws-secretsmanager-get-secrets@v2 21 | with: 22 | secret-ids: | 23 | GH_PAT, gha/native-platform/_all/GH_BOT_GITHUB_TOKEN 24 | - name: Checkout gradle-github-actions Repo 25 | uses: actions/checkout@v4 26 | with: 27 | repository: gradle/gradle-github-actions 28 | ref: main 29 | token: ${{ env.GH_PAT }} 30 | path: .github/actions/gradle-github-actions 31 | - name: Publish BuildScan Commit Status 32 | uses: ./.github/actions/gradle-github-actions/buildscan-commit-status-action 33 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '28 2 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | language: [ 'cpp', 'java' ] 32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 33 | # Learn more: 34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v4 39 | 40 | # Initializes the CodeQL tools for scanning. 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v3 43 | with: 44 | languages: ${{ matrix.language }} 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | - name: Autobuild (Java) 53 | uses: github/codeql-action/autobuild@v3 54 | if: ${{ matrix.language == 'java' }} 55 | 56 | - name: Autobuild (cpp) 57 | run: ./gradlew assemble 58 | if: ${{ matrix.language == 'cpp' }} 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 https://git.io/JvXDl 62 | 63 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 64 | # and modify them (or add more) to build your code if your project 65 | # uses a compiled language 66 | 67 | #- run: | 68 | # make bootstrap 69 | # make release 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v3 73 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review-action.yml: -------------------------------------------------------------------------------- 1 | name: Dependency review for pull requests 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | 7 | permissions: 8 | contents: write 9 | 10 | jobs: 11 | dependency-submission: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/setup-java@v4 16 | with: 17 | distribution: temurin 18 | java-version: 17 19 | 20 | - name: Generate and submit dependency graph 21 | uses: gradle/actions/dependency-submission@v4 22 | with: 23 | build-scan-publish: false 24 | 25 | - name: Perform dependency review 26 | uses: actions/dependency-review-action@v4 27 | -------------------------------------------------------------------------------- /.github/workflows/dependency-submission.yml: -------------------------------------------------------------------------------- 1 | name: Dependency Submission 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | 9 | permissions: 10 | contents: write 11 | 12 | jobs: 13 | dependency-submission: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout sources 17 | uses: actions/checkout@v4 18 | - name: Setup Java 19 | uses: actions/setup-java@v4 20 | with: 21 | distribution: 'temurin' 22 | java-version: 17 23 | - name: Generate and submit dependency graph 24 | uses: gradle/actions/dependency-submission@v4 25 | with: 26 | build-scan-publish: false 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | *.ipr 4 | *.iws 5 | *.log 6 | 7 | **/.classpath 8 | **/.project 9 | **/.settings/ 10 | 11 | .gradle/ 12 | 13 | .DS_Store 14 | 15 | **/build/ 16 | **/out/ 17 | **/bin/ 18 | **/target/ 19 | 20 | build-receipt.properties 21 | 22 | hs_err_pid*.log 23 | 24 | /local.properties 25 | -------------------------------------------------------------------------------- /.lgtm.yml: -------------------------------------------------------------------------------- 1 | 2 | # This is used to configure the LGTM.com website's build of gradle/native-platform 3 | # This happens passively without any explict configuration against our repository. 4 | # See: https://lgtm.com/projects/g/gradle/native-platform 5 | 6 | extraction: 7 | cpp: 8 | index: 9 | build_command: "./gradlew assemble" 10 | -------------------------------------------------------------------------------- /.teamcity/Agent.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | enum class Agent(val os: Os, val architecture: Architecture) { 18 | UbuntuAmd64(os = Os.Ubuntu16, architecture = Architecture.Amd64), 19 | UbuntuAarch64(os = Os.Ubuntu16, architecture = Architecture.Aarch64), 20 | AmazonLinuxAmd64(os = Os.AmazonLinux, architecture = Architecture.Amd64), 21 | AmazonLinuxAarch64(os = Os.AmazonLinux, architecture = Architecture.Aarch64), 22 | CentOsAmd64(os = Os.CentOs, architecture = Architecture.Amd64), 23 | FreeBsdAmd64(os = Os.FreeBsd, architecture = Architecture.Amd64), 24 | WindowsAmd64(os = Os.Windows, architecture = Architecture.Amd64), 25 | MacOsAmd64(os = Os.MacOs, architecture = Architecture.Amd64), 26 | MacOsAarch64(os = Os.MacOs, architecture = Architecture.Aarch64), 27 | } 28 | -------------------------------------------------------------------------------- /.teamcity/NativePlatformBuild.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import jetbrains.buildServer.configs.kotlin.BuildType 18 | import jetbrains.buildServer.configs.kotlin.DslContext 19 | import jetbrains.buildServer.configs.kotlin.FailureAction 20 | import jetbrains.buildServer.configs.kotlin.RelativeId 21 | import jetbrains.buildServer.configs.kotlin.buildSteps.gradle 22 | import jetbrains.buildServer.configs.kotlin.triggers.vcs 23 | 24 | open class NativePlatformBuild(agent: Agent, buildReceiptSource: Boolean = false, init: BuildType.() -> Unit = {}) : BuildType({ 25 | name = "Test on $agent" 26 | id = RelativeId("Build$agent") 27 | 28 | runOn(agent) 29 | 30 | vcs { 31 | root(DslContext.settingsRoot) 32 | } 33 | 34 | steps { 35 | gradle { 36 | tasks = "clean build -PagentName=${agent.name}${agent.allPublishTasks}" 37 | if (buildReceiptSource) { 38 | gradleParams = "-PignoreIncomingBuildReceipt" 39 | } 40 | buildFile = "" 41 | } 42 | } 43 | 44 | features { 45 | publishCommitStatus() 46 | lowerRequiredFreeDiskSpace() 47 | } 48 | 49 | failureConditions { 50 | testFailure = false 51 | executionTimeoutMin = 15 52 | } 53 | 54 | artifactRules = """ 55 | hs_err* 56 | **/build/**/output.txt 57 | build/repo => repo 58 | """.trimIndent() + "\n$archiveReports" 59 | 60 | init(this) 61 | }) 62 | 63 | class BuildTrigger(dependencies: List) : BuildType({ 64 | name = "Run platform tests (Trigger)" 65 | type = Type.COMPOSITE 66 | 67 | vcs { 68 | root(DslContext.settingsRoot) 69 | } 70 | 71 | triggers { 72 | vcs { 73 | branchFilter = """ 74 | +:* 75 | -:pull/* 76 | """.trimIndent() 77 | } 78 | } 79 | 80 | dependencies { 81 | dependencies.forEach { 82 | snapshot(it) { 83 | onDependencyFailure = FailureAction.FAIL_TO_START 84 | } 85 | } 86 | } 87 | 88 | features { 89 | publishCommitStatus() 90 | } 91 | }) 92 | -------------------------------------------------------------------------------- /.teamcity/NativePlatformCompatibilityTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import jetbrains.buildServer.configs.kotlin.BuildType 18 | import jetbrains.buildServer.configs.kotlin.DslContext 19 | import jetbrains.buildServer.configs.kotlin.FailureAction 20 | import jetbrains.buildServer.configs.kotlin.RelativeId 21 | import jetbrains.buildServer.configs.kotlin.buildSteps.gradle 22 | 23 | class NativePlatformCompatibilityTest(agent: Agent, buildDependencies: List, init: BuildType.() -> Unit = {}) : BuildType({ 24 | name = "Compatibility test on $agent" 25 | id = RelativeId("CompatibilityTest$agent") 26 | 27 | runOn(agent) 28 | 29 | steps { 30 | gradle { 31 | tasks = "clean :native-platform:test -PtestVersionFromLocalRepository" 32 | buildFile = "" 33 | } 34 | } 35 | 36 | vcs { 37 | root(DslContext.settingsRoot) 38 | } 39 | 40 | features { 41 | publishCommitStatus() 42 | lowerRequiredFreeDiskSpace() 43 | } 44 | 45 | failureConditions { 46 | testFailure = false 47 | executionTimeoutMin = 15 48 | } 49 | 50 | artifactRules = """ 51 | hs_err* 52 | **/build/**/output.txt 53 | """.trimIndent() + "\n$archiveReports" 54 | 55 | dependencies { 56 | buildDependencies.forEach { 57 | snapshot(it) { 58 | onDependencyFailure = FailureAction.FAIL_TO_START 59 | } 60 | dependency(it) { 61 | artifacts { 62 | cleanDestination = true 63 | artifactRules = "repo => incoming-repo/" 64 | } 65 | } 66 | } 67 | } 68 | 69 | init(this) 70 | }) 71 | -------------------------------------------------------------------------------- /.teamcity/Os.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import jetbrains.buildServer.configs.kotlin.Requirements 18 | 19 | interface Os { 20 | fun addAgentRequirements(requirements: Requirements) 21 | val osType: String 22 | 23 | object Ubuntu16 : Linux(Ncurses.Ncurses5) { 24 | override fun Requirements.additionalRequirements() { 25 | contains(osDistributionNameParameter, "ubuntu") 26 | contains(osDistributionVersionParameter, "16") 27 | } 28 | } 29 | 30 | object AmazonLinux : Linux(Ncurses.Ncurses6) { 31 | override fun Requirements.additionalRequirements() { 32 | contains(osDistributionNameParameter, "amazon") 33 | } 34 | } 35 | 36 | object CentOs : Linux(Ncurses.Ncurses6) { 37 | override fun Requirements.additionalRequirements() { 38 | contains(osDistributionNameParameter, "centos") 39 | contains(osDistributionVersionParameter, "9") 40 | } 41 | } 42 | 43 | object MacOs : OsWithNameRequirement("Mac OS X", "MacOs") 44 | 45 | object Windows : OsWithNameRequirement("Windows", "Windows") 46 | 47 | object FreeBsd : OsWithNameRequirement("FreeBSD", "FreeBsd") 48 | } 49 | 50 | private const val osDistributionNameParameter = "system.agent.os.distribution.name" 51 | private const val osDistributionVersionParameter = "system.agent.os.distribution.version" 52 | 53 | abstract class OsWithNameRequirement(private val osName: String, override val osType: String) : Os { 54 | override fun addAgentRequirements(requirements: Requirements) { 55 | requirements.contains("teamcity.agent.jvm.os.name", osName) 56 | requirements.additionalRequirements() 57 | } 58 | 59 | open fun Requirements.additionalRequirements() {} 60 | } 61 | 62 | abstract class Linux(val ncurses: Ncurses) : OsWithNameRequirement("Linux", "Linux") 63 | 64 | enum class Ncurses { 65 | Ncurses5, 66 | Ncurses6 67 | } 68 | 69 | enum class Architecture(val paramName: String) { 70 | Aarch64("aarch64") { 71 | override fun agentRequirementForOs(os: Os): String = "aarch64" 72 | }, 73 | Amd64("64bit") { 74 | override fun agentRequirementForOs(os: Os): String = when (os) { 75 | Os.MacOs -> "x86_64" 76 | else -> "amd64" 77 | } 78 | }; 79 | 80 | abstract fun agentRequirementForOs(os: Os): String 81 | } 82 | -------------------------------------------------------------------------------- /.teamcity/ReleaseType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const val gradleInternalRepositoryUsername = "%gradle.internal.repository.build-tool.publish.username%" 18 | const val gradleInternalRepositoryPassword = "%gradle.internal.repository.build-tool.publish.password%" 19 | 20 | enum class ReleaseType(val gradleProperty: String, val username: String, val password: String, val userProvidedVersion: Boolean = false) { 21 | Snapshot("snapshot", gradleInternalRepositoryUsername, gradleInternalRepositoryPassword), 22 | Alpha("alpha", gradleInternalRepositoryUsername, gradleInternalRepositoryPassword, true), 23 | Milestone("milestone", gradleInternalRepositoryUsername, gradleInternalRepositoryPassword), 24 | Release("release", gradleInternalRepositoryUsername, gradleInternalRepositoryPassword) 25 | } 26 | -------------------------------------------------------------------------------- /.teamcity/settings.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import jetbrains.buildServer.configs.kotlin.project 18 | import jetbrains.buildServer.configs.kotlin.version 19 | 20 | /* 21 | The settings script is an entry point for defining a single 22 | TeamCity project. TeamCity looks for the 'settings.kts' file in a 23 | project directory and runs it if it's found, so the script name 24 | shouldn't be changed and its package should be the same as the 25 | project's id. 26 | 27 | The script should contain a single call to the project() function 28 | with a Project instance or an init function as an argument. 29 | 30 | VcsRoots, BuildTypes, and Templates of this project must be 31 | registered inside project using the vcsRoot(), buildType(), and 32 | template() methods respectively. 33 | 34 | Subprojects can be defined either in their own settings.kts or by 35 | calling the subProjects() method in this project. 36 | 37 | To debug settings scripts in command-line, run the 38 | 39 | mvnDebug org.jetbrains.teamcity:teamcity-configs-maven-plugin:generate 40 | 41 | command and attach your debugger to the port 8000. 42 | 43 | To debug in IntelliJ Idea, open the 'Maven Projects' tool window (View -> 44 | Tool Windows -> Maven Projects), find the generate task 45 | node (Plugins -> teamcity-configs -> teamcity-configs:generate), 46 | the 'Debug' option is available in the context menu for the task. 47 | */ 48 | 49 | version = "2024.03" 50 | 51 | project { 52 | params { 53 | param("env.DEVELOCITY_ACCESS_KEY", "%ge.gradle.org.access.key%") 54 | } 55 | 56 | val buildReceiptSource = NativePlatformBuild(Agent.UbuntuAmd64, buildReceiptSource = true) { 57 | artifactRules = listOf(artifactRules, buildReceipt).joinToString("\n") 58 | } 59 | val testBuilds = listOf(buildReceiptSource) + 60 | Agent.entries.filter { it !in listOf(Agent.UbuntuAmd64, Agent.CentOsAmd64) }.map { NativePlatformBuild(it) } 61 | testBuilds.forEach(::buildType) 62 | val compatibilityTestBuilds = listOf(NativePlatformCompatibilityTest(Agent.CentOsAmd64, testBuilds).also(::buildType)) 63 | buildType(BuildTrigger(testBuilds + compatibilityTestBuilds)) 64 | 65 | subProject(Publishing(testBuilds, buildReceiptSource)) 66 | } 67 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "${env:JAVA_HOME}/include", 7 | "${env:JAVA_HOME}/include/darwin", 8 | "${workspaceFolder}/**", 9 | "${default}" 10 | ], 11 | "defines": [], 12 | "macFrameworkPath": [ 13 | "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" 14 | ], 15 | "cStandard": "c17", 16 | "cppStandard": "c++17", 17 | "intelliSenseMode": "clang-x64" 18 | }, 19 | { 20 | "name": "Linux", 21 | "includePath": [ 22 | "${env:JAVA_HOME}/include", 23 | "${env:JAVA_HOME}/include/linux", 24 | "${workspaceFolder}/**", 25 | "${default}" 26 | ], 27 | "defines": [], 28 | "cStandard": "c11", 29 | "cppStandard": "c++11", 30 | "intelliSenseMode": "gcc-x64" 31 | }, 32 | { 33 | "name": "Win32", 34 | "includePath": [ 35 | "${env:JAVA_HOME}/include", 36 | "${env:JAVA_HOME}/include/win32", 37 | "${workspaceFolder}/**", 38 | "${default}" 39 | ], 40 | "intelliSenseMode": "msvc-x64", 41 | "cStandard": "c11", 42 | "cppStandard": "c++17" 43 | } 44 | ], 45 | "version": 4 46 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Windows", 6 | "type": "cppvsdbg", 7 | "request": "attach", 8 | "processId": "${command:pickProcess}" 9 | }, 10 | { 11 | "name": "macOS", 12 | "type": "cppdbg", 13 | "request": "attach", 14 | "program": "${workspaceFolder}/build/libs/nativePlatform/shared/osx_amd64/libnative-platform.dylib", 15 | "processId": "${command:pickProcess}", 16 | "MIMode": "lldb" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.classpath": true, 4 | "**/.project": true, 5 | "**/.settings": true, 6 | "**/.factorypath": true 7 | }, 8 | "java.configuration.updateBuildConfiguration": "interactive", 9 | "cSpell.words": [ 10 | "JNICALL", 11 | "JNIEXPORT", 12 | "LPOVERLAPPED", 13 | "Ljava", 14 | "jboolean", 15 | "jchar", 16 | "jclass", 17 | "jfieldID", 18 | "jint", 19 | "jlong", 20 | "jmethodID", 21 | "jobject", 22 | "jsize" 23 | ], 24 | "C_Cpp.dimInactiveRegions": false 25 | } 26 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gradle/native-platform/87f4647e90db6006bf357db0ba7fa29925dcc32e/build.gradle.kts -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id('java-gradle-plugin') 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | gradlePluginPortal() 8 | } 9 | 10 | dependencies { 11 | implementation gradleApi() 12 | implementation 'org.apache.httpcomponents.client5:httpclient5:5.0.1' 13 | implementation 'com.google.guava:guava:28.2-jre' 14 | } 15 | 16 | java { 17 | sourceCompatibility = JavaVersion.VERSION_1_8 18 | targetCompatibility = JavaVersion.VERSION_1_8 19 | } 20 | 21 | if (JavaVersion.current() < JavaVersion.VERSION_1_8) { 22 | // Need to use Java 8 on some older platforms 23 | throw new UnsupportedOperationException("At least Java 8 is required to build native-platform. Earlier versions are not supported.") 24 | } 25 | 26 | gradlePlugin { 27 | plugins { 28 | jni { 29 | id = "gradlebuild.jni" 30 | implementationClass = "gradlebuild.JniPlugin" 31 | } 32 | nativeComponent { 33 | id = "gradlebuild.native-platform-component" 34 | implementationClass = "gradlebuild.NativePlatformComponentPlugin" 35 | } 36 | freebsd { 37 | id = "gradlebuild.freebsd" 38 | implementationClass = "gradlebuild.FreeBsdPlugin" 39 | } 40 | ncurses { 41 | id = "gradlebuild.ncurses" 42 | implementationClass = "gradlebuild.NcursesPlugin" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /buildSrc/settings.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gradle/native-platform/87f4647e90db6006bf357db0ba7fa29925dcc32e/buildSrc/settings.gradle -------------------------------------------------------------------------------- /buildSrc/src/main/java/gradlebuild/NativePlatformVersionExtension.java: -------------------------------------------------------------------------------- 1 | package gradlebuild; 2 | 3 | import org.gradle.api.provider.Property; 4 | 5 | public abstract class NativePlatformVersionExtension { 6 | public abstract Property getVersionClassPackageName(); 7 | public abstract Property getVersionClassName(); 8 | } 9 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/gradlebuild/NativeRulesUtils.java: -------------------------------------------------------------------------------- 1 | package gradlebuild; 2 | 3 | import org.gradle.nativeplatform.platform.NativePlatform; 4 | import org.gradle.platform.base.PlatformContainer; 5 | 6 | public interface NativeRulesUtils { 7 | static void addPlatform(PlatformContainer platformContainer, String name, String os, String architecture) { 8 | platformContainer.create(name, NativePlatform.class, platform -> { 9 | platform.operatingSystem(os); 10 | platform.architecture(architecture); 11 | }); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/gradlebuild/PublishRepositoryCredentials.java: -------------------------------------------------------------------------------- 1 | package gradlebuild; 2 | 3 | /** 4 | * Credentials for accessing the repository for publishing. Only required when releasing. 5 | */ 6 | public class PublishRepositoryCredentials { 7 | private String userName; 8 | private String apiKey; 9 | 10 | public String getUserName() { 11 | return userName; 12 | } 13 | 14 | public void setUserName(String userName) { 15 | this.userName = userName; 16 | } 17 | 18 | public String getApiKey() { 19 | return apiKey; 20 | } 21 | 22 | public void setApiKey(String apiKey) { 23 | this.apiKey = apiKey; 24 | } 25 | 26 | void assertPresent() { 27 | if (userName == null) { 28 | throw new IllegalStateException("No publish repository user name specified. You can set project property 'publishUserName' to provide this."); 29 | } 30 | if (apiKey == null) { 31 | throw new IllegalStateException("No publish repository API key specified. You can set project property 'publishApiKey' to provide this."); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/gradlebuild/VariantsExtension.java: -------------------------------------------------------------------------------- 1 | package gradlebuild; 2 | 3 | import org.gradle.api.provider.Property; 4 | import org.gradle.api.provider.SetProperty; 5 | 6 | public interface VariantsExtension { 7 | Property getGroupId(); 8 | Property getArtifactId(); 9 | Property getVersion(); 10 | 11 | /** 12 | * List of names of extra variants of this artifact. 13 | * 14 | * May be empty. 15 | */ 16 | SetProperty getVariantNames(); 17 | } 18 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/gradlebuild/VersionDetails.java: -------------------------------------------------------------------------------- 1 | package gradlebuild; 2 | 3 | import javax.annotation.Nullable; 4 | import javax.inject.Inject; 5 | import java.util.Optional; 6 | 7 | public class VersionDetails { 8 | private static final String GRADLE_INTERNAL_REPOSITORY_URL = System.getenv("GRADLE_INTERNAL_REPO_URL"); 9 | private static final String GRADLE_REPOSITORY_URL = GRADLE_INTERNAL_REPOSITORY_URL == null ? "https://repo.gradle.org/gradle" : GRADLE_INTERNAL_REPOSITORY_URL; 10 | 11 | public enum ReleaseRepository { 12 | GradleRepoSnapshots("libs-snapshots-local"), 13 | GradleRepoReleases("libs-releases-local"); 14 | 15 | private final String url; 16 | 17 | ReleaseRepository(String url) { 18 | this.url = GRADLE_REPOSITORY_URL + "/" + url; 19 | } 20 | 21 | public String getUrl() { 22 | return url; 23 | } 24 | } 25 | 26 | public enum BuildType { 27 | Dev(null), 28 | Snapshot(ReleaseRepository.GradleRepoSnapshots), 29 | Alpha(ReleaseRepository.GradleRepoReleases), 30 | Milestone(ReleaseRepository.GradleRepoReleases), 31 | Release(ReleaseRepository.GradleRepoReleases); 32 | 33 | private final ReleaseRepository releaseRepository; 34 | 35 | BuildType(@Nullable ReleaseRepository releaseRepository) { 36 | this.releaseRepository = releaseRepository; 37 | } 38 | 39 | Optional getReleaseRepository() { 40 | return Optional.ofNullable(releaseRepository); 41 | } 42 | } 43 | 44 | private final BuildType buildType; 45 | private final String version; 46 | 47 | @Inject 48 | public VersionDetails(BuildType buildType, String version) { 49 | this.buildType = buildType; 50 | this.version = version; 51 | } 52 | 53 | public boolean isUseRepo() { 54 | return buildType.getReleaseRepository().isPresent(); 55 | } 56 | 57 | public Optional getReleaseRepository() { 58 | return buildType.getReleaseRepository(); 59 | } 60 | 61 | public String getVersion() { 62 | return version; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Enable watching the file system 2 | # Remove the property when file system watching is enabled by default 3 | org.gradle.watch-fs=true 4 | nextVersion=0.22 5 | nextMilestone=14 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gradle/native-platform/87f4647e90db6006bf357db0ba7fa29925dcc32e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /native-platform/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'groovy' 3 | id 'java-test-fixtures' 4 | id 'cpp' 5 | id 'gradlebuild.jni' 6 | id 'gradlebuild.freebsd' 7 | id 'gradlebuild.ncurses' 8 | } 9 | 10 | nativeVersion { 11 | versionClassPackageName = "net.rubygrapefruit.platform.internal.jni" 12 | versionClassName = "NativeVersion" 13 | } 14 | 15 | dependencies { 16 | compileOnly 'com.google.code.findbugs:jsr305:3.0.2' 17 | } 18 | 19 | javadoc { 20 | exclude '**/internal/**' 21 | } 22 | 23 | model { 24 | components { 25 | nativePlatform(NativeLibrarySpec) { 26 | baseName 'native-platform' 27 | $.platforms.each { p -> 28 | if (p.name.contains("ncurses")) { 29 | return 30 | } 31 | targetPlatform p.name 32 | } 33 | sources { 34 | cpp { 35 | source.srcDirs = ['src/shared/cpp', 'src/main/cpp'] 36 | exportedHeaders.srcDirs = ['src/shared/headers'] 37 | } 38 | } 39 | } 40 | 41 | nativePlatformCurses(NativeLibrarySpec) { 42 | baseName 'native-platform-curses' 43 | $.platforms.each { p -> 44 | if (p.operatingSystem.windows) { 45 | return 46 | } 47 | if (p.operatingSystem.linux && !p.name.contains("ncurses")) { 48 | return 49 | } 50 | targetPlatform p.name 51 | } 52 | sources { 53 | cpp { 54 | source.srcDirs = ['src/shared/cpp', 'src/curses/cpp'] 55 | exportedHeaders.srcDirs = ['src/shared/headers'] 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /native-platform/src/main/cpp/freebsd.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * FreeBSD specific functions. 19 | */ 20 | #if defined(__FreeBSD__) 21 | 22 | #include "generic.h" 23 | #include "net_rubygrapefruit_platform_internal_jni_PosixFileSystemFunctions.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | /* 33 | * File system functions 34 | */ 35 | JNIEXPORT void JNICALL 36 | Java_net_rubygrapefruit_platform_internal_jni_PosixFileSystemFunctions_listFileSystems(JNIEnv* env, jclass target, jobject info, jobject result) { 37 | int fs_count = getfsstat(NULL, 0, MNT_NOWAIT); 38 | if (fs_count < 0) { 39 | mark_failed_with_errno(env, "could not stat file systems", result); 40 | return; 41 | } 42 | 43 | size_t len = fs_count * sizeof(struct statfs); 44 | struct statfs* buf = (struct statfs*) malloc(len); 45 | if (getfsstat(buf, len, MNT_NOWAIT) < 0) { 46 | mark_failed_with_errno(env, "could not stat file systems", result); 47 | free(buf); 48 | return; 49 | } 50 | 51 | jclass info_class = env->GetObjectClass(info); 52 | jmethodID method = env->GetMethodID(info_class, "add", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZ)V"); 53 | 54 | for (int i = 0; i < fs_count; i++) { 55 | jboolean caseSensitive = JNI_TRUE; 56 | jboolean casePreserving = JNI_TRUE; 57 | 58 | jstring mount_point = char_to_java(env, buf[i].f_mntonname, result); 59 | jstring file_system_type = char_to_java(env, buf[i].f_fstypename, result); 60 | jstring device_name = char_to_java(env, buf[i].f_mntfromname, result); 61 | jboolean remote = (buf[i].f_flags & MNT_LOCAL) == 0; 62 | env->CallVoidMethod(info, method, mount_point, file_system_type, device_name, remote, caseSensitive, casePreserving); 63 | } 64 | free(buf); 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /native-platform/src/main/cpp/linux.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Linux specific functions. 19 | */ 20 | #ifdef __linux__ 21 | 22 | #include "generic.h" 23 | #include "net_rubygrapefruit_platform_internal_jni_PosixFileSystemFunctions.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /* 32 | * File system functions 33 | */ 34 | JNIEXPORT void JNICALL 35 | Java_net_rubygrapefruit_platform_internal_jni_PosixFileSystemFunctions_listFileSystems(JNIEnv* env, jclass target, jobject info, jobject result) { 36 | FILE* fp = setmntent(MOUNTED, "r"); 37 | if (fp == NULL) { 38 | mark_failed_with_errno(env, "could not open mount file", result); 39 | return; 40 | } 41 | char buf[1024]; 42 | struct mntent mount_info; 43 | 44 | jclass info_class = env->GetObjectClass(info); 45 | jmethodID method = env->GetMethodID(info_class, "add", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZ)V"); 46 | 47 | while (getmntent_r(fp, &mount_info, buf, sizeof(buf)) != NULL) { 48 | jstring mount_point = char_to_java(env, mount_info.mnt_dir, result); 49 | jstring file_system_type = char_to_java(env, mount_info.mnt_type, result); 50 | jstring device_name = char_to_java(env, mount_info.mnt_fsname, result); 51 | env->CallVoidMethod(info, method, mount_point, file_system_type, device_name, JNI_FALSE, JNI_TRUE, JNI_TRUE); 52 | } 53 | 54 | endmntent(fp); 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/MissingRegistryEntryException.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform; 2 | 3 | /** 4 | * Thrown when attempting to query an unknown registry key or value. 5 | */ 6 | public class MissingRegistryEntryException extends NativeException { 7 | public MissingRegistryEntryException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/NativeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform; 18 | 19 | /** 20 | * Base exception for native integration. 21 | */ 22 | public class NativeException extends RuntimeException { 23 | public NativeException(String message, Throwable cause) { 24 | super(message, cause); 25 | } 26 | 27 | public NativeException(String message) { 28 | super(message); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/NativeIntegration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform; 18 | 19 | /** 20 | * A marker interface that represents a native integration. 21 | */ 22 | public interface NativeIntegration { 23 | } 24 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/NativeIntegrationLinkageException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform; 18 | 19 | /** 20 | * Thrown when a native integration is not available due to a native linkage error. 21 | */ 22 | public class NativeIntegrationLinkageException extends NativeIntegrationUnavailableException { 23 | public NativeIntegrationLinkageException(String message, Throwable cause) { 24 | super(message, cause); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/NativeIntegrationUnavailableException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform; 18 | 19 | /** 20 | * Thrown when a given integration is not available for the current machine. 21 | */ 22 | public class NativeIntegrationUnavailableException extends NativeException { 23 | public NativeIntegrationUnavailableException(String message) { 24 | super(message); 25 | } 26 | 27 | public NativeIntegrationUnavailableException(String message, Throwable cause) { 28 | super(message, cause); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/Process.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform; 18 | 19 | import java.io.File; 20 | 21 | /** 22 | * Functions to query and modify a process' state. 23 | */ 24 | @ThreadSafe 25 | public interface Process extends NativeIntegration { 26 | /** 27 | * Returns the process identifier. 28 | * 29 | * @throws NativeException On failure. 30 | */ 31 | @ThreadSafe 32 | int getProcessId() throws NativeException; 33 | 34 | /** 35 | * Detaches this process from the parent to ignore ctrl-c. 36 | * 37 | * @throws NativeException On failure. 38 | */ 39 | @ThreadSafe 40 | void detach() throws NativeException; 41 | 42 | /** 43 | * Returns the process' current working directory. 44 | * 45 | * @throws NativeException On failure. 46 | */ 47 | @ThreadSafe 48 | File getWorkingDirectory() throws NativeException; 49 | 50 | /** 51 | * Sets the process' working directory. 52 | * 53 | * @throws NativeException On failure. 54 | */ 55 | @ThreadSafe 56 | void setWorkingDirectory(File directory) throws NativeException; 57 | 58 | /** 59 | * Get the value of an environment variable. 60 | * 61 | * @return The value or null if no such environment variable. Also returns null for an environment variable whose 62 | * value is an empty string. 63 | * @throws NativeException On failure. 64 | */ 65 | @ThreadSafe 66 | String getEnvironmentVariable(String name) throws NativeException; 67 | 68 | /** 69 | * Sets the value of an environment variable. 70 | * 71 | * @param value the new value. Use null or an empty string to remove the environment variable. Note that on some 72 | * platforms it is not possible to remove the environment variable safely. On such platforms, the value is set to an 73 | * empty string instead. 74 | * @throws NativeException On failure. 75 | */ 76 | @ThreadSafe 77 | void setEnvironmentVariable(String name, String value) throws NativeException; 78 | } 79 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/ProcessLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform; 18 | 19 | import java.lang.Process; 20 | 21 | /** 22 | * Used to start processes, taking care of some platform-specific issues when launching processes concurrently or 23 | * launching processes that will run in the background. 24 | */ 25 | @ThreadSafe 26 | public interface ProcessLauncher extends NativeIntegration { 27 | /** 28 | * Starts a process from the given settings. 29 | * 30 | * @param processBuilder The process settings. 31 | * @return the process 32 | * @throws NativeException On failure to start the process. 33 | */ 34 | @ThreadSafe 35 | Process start(ProcessBuilder processBuilder) throws NativeException; 36 | } 37 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/ResourceClosedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform; 18 | 19 | /** 20 | * Thrown when attempting to use some resource has been closed. 21 | */ 22 | public class ResourceClosedException extends NativeException { 23 | public ResourceClosedException(String message) { 24 | super(message); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/SystemInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform; 18 | 19 | /** 20 | * Provides access to some system information. This is a snapshot view and does not change. 21 | */ 22 | @ThreadSafe 23 | public interface SystemInfo extends NativeIntegration { 24 | enum Architecture { i386, amd64, aarch64 } 25 | 26 | /** 27 | * Returns the name of the kernel for the current operating system. 28 | */ 29 | @ThreadSafe 30 | String getKernelName(); 31 | 32 | /** 33 | * Returns the version of the kernel for the current operating system. 34 | */ 35 | @ThreadSafe 36 | String getKernelVersion(); 37 | 38 | /** 39 | * Returns the machine architecture name, as reported by the operating system. 40 | */ 41 | @ThreadSafe 42 | String getArchitectureName(); 43 | 44 | /** 45 | * Returns the machine architecture, as reported by the operating system. 46 | */ 47 | @ThreadSafe 48 | Architecture getArchitecture(); 49 | 50 | /** 51 | * Returns the machine hostname, as reported by the operating system. 52 | */ 53 | @ThreadSafe 54 | String getHostname(); 55 | } 56 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/ThreadSafe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform; 18 | 19 | import java.lang.annotation.ElementType; 20 | import java.lang.annotation.Target; 21 | 22 | /** 23 | * Indicates that the given class or method is thread safe. 24 | */ 25 | @Target({ElementType.TYPE, ElementType.METHOD}) 26 | public @interface ThreadSafe { 27 | } 28 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/WindowsRegistry.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Provides access to the Windows registry. 7 | */ 8 | @ThreadSafe 9 | public interface WindowsRegistry extends NativeIntegration { 10 | enum Key { 11 | HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER 12 | } 13 | 14 | /** 15 | * Returns a registry key value as a String. 16 | * 17 | * @throws NativeException On failure. 18 | * @throws MissingRegistryEntryException When the requested key or value does not exist. 19 | */ 20 | String getStringValue(Key key, String subkey, String value) throws NativeException; 21 | 22 | /** 23 | * Lists the subkeys of a registry key. 24 | * 25 | * @throws NativeException On failure. 26 | * @throws MissingRegistryEntryException When the requested key does not exist. 27 | */ 28 | List getSubkeys(Key key, String subkey) throws NativeException; 29 | 30 | /** 31 | * Lists the value names of a registry key. 32 | * 33 | * @throws NativeException On failure. 34 | * @throws MissingRegistryEntryException When the requested key does not exist. 35 | */ 36 | List getValueNames(Key key, String subkey) throws NativeException; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/CaseSensitivity.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.file; 2 | 3 | import net.rubygrapefruit.platform.ThreadSafe; 4 | 5 | public interface CaseSensitivity { 6 | /** 7 | * Returns true if this file system performs case sensitive searches. 8 | */ 9 | @ThreadSafe 10 | boolean isCaseSensitive(); 11 | 12 | /** 13 | * Returns true if this file system preserves file name case. 14 | */ 15 | @ThreadSafe 16 | boolean isCasePreserving(); 17 | } 18 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/DirEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.ThreadSafe; 20 | 21 | /** 22 | * Details about a file in a directory. This is a snapshot and does not change. 23 | */ 24 | @ThreadSafe 25 | public interface DirEntry extends FileInfo { 26 | /** 27 | * Returns the name of the file. 28 | */ 29 | String getName(); 30 | } 31 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/FileInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.ThreadSafe; 20 | 21 | /** 22 | * Provides some information about a file. This is a snapshot and does not change. 23 | * 24 | *

A snapshot be fetched using {@link Files#stat(java.io.File)}.

25 | */ 26 | @ThreadSafe 27 | public interface FileInfo { 28 | // Order is significant here, see generic.h 29 | enum Type { 30 | File, Directory, Symlink, Other, Missing 31 | } 32 | 33 | /** 34 | * Returns the type of this file. 35 | */ 36 | Type getType(); 37 | 38 | /** 39 | * Returns the size of this file, in bytes. Returns 0 when this file is not a regular file. 40 | */ 41 | long getSize(); 42 | 43 | /** 44 | * Returns the last modification time of this file, in ms since epoch. Returns 0 when this file does not exist. 45 | */ 46 | long getLastModifiedTime(); 47 | } 48 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/FilePermissionException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | 21 | /** 22 | * Thrown when the user has insufficient permissions to perform some file system operation. 23 | */ 24 | public class FilePermissionException extends NativeException { 25 | public FilePermissionException(String message) { 26 | super(message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/FileSystemInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.ThreadSafe; 20 | 21 | import javax.annotation.Nullable; 22 | import java.io.File; 23 | 24 | /** 25 | * Information about a file system. This is a snapshot view and does not change. 26 | */ 27 | @ThreadSafe 28 | public interface FileSystemInfo { 29 | /** 30 | * Returns the root directory of this file system. 31 | */ 32 | @ThreadSafe 33 | File getMountPoint(); 34 | 35 | /** 36 | * Returns the operating system specific name for the type of this file system 37 | * or {@code "unknown"} if the type could not be determined. 38 | */ 39 | @ThreadSafe 40 | String getFileSystemType(); 41 | 42 | /** 43 | * Returns true if this file system is a remote file system, or false if local. 44 | */ 45 | @ThreadSafe 46 | boolean isRemote(); 47 | 48 | /** 49 | * Returns the operating system specific name for this file system. 50 | */ 51 | @ThreadSafe 52 | String getDeviceName(); 53 | 54 | /** 55 | * Returns case sensitivity information for the file system if known or {@code null}. 56 | */ 57 | @ThreadSafe 58 | @Nullable 59 | CaseSensitivity getCaseSensitivity(); 60 | 61 | /** 62 | * Returns true if this file system is performance case sensitive searches. 63 | * 64 | * @deprecated Use {@link #getCaseSensitivity()} instead. 65 | */ 66 | @Deprecated 67 | @ThreadSafe 68 | boolean isCaseSensitive(); 69 | 70 | /** 71 | * Returns true if this file system preserves file name case. 72 | * 73 | * @deprecated Use {@link #getCaseSensitivity()} instead. 74 | */ 75 | @Deprecated 76 | @ThreadSafe 77 | boolean isCasePreserving(); 78 | } 79 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/FileSystems.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.NativeIntegration; 21 | import net.rubygrapefruit.platform.ThreadSafe; 22 | 23 | import java.util.List; 24 | 25 | /** 26 | * Provides access to the file systems of the current machine. 27 | */ 28 | @ThreadSafe 29 | public interface FileSystems extends NativeIntegration { 30 | /** 31 | * Returns the set of all file systems for the current machine. 32 | * 33 | * @return The set of file systems. Never returns null. 34 | * @throws NativeException On failure. 35 | */ 36 | @ThreadSafe 37 | List getFileSystems() throws NativeException; 38 | } 39 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/NoSuchFileException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | 21 | /** 22 | * Thrown when attempting to query details of a file that does not exist. 23 | */ 24 | public class NoSuchFileException extends NativeException { 25 | public NoSuchFileException(String message) { 26 | super(message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/NotADirectoryException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | 21 | /** 22 | * Thrown when attempting to list the elements of a file that is not a directory. 23 | */ 24 | public class NotADirectoryException extends NativeException { 25 | public NotADirectoryException(String message) { 26 | super(message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/PosixFileInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.ThreadSafe; 20 | 21 | /** 22 | * Provides some information about a file on a Posix file system. This is a snapshot and does not change. 23 | * 24 | *

A snapshot be fetched using {@link PosixFiles#stat(java.io.File)}.

25 | */ 26 | @ThreadSafe 27 | public interface PosixFileInfo extends FileInfo { 28 | 29 | /** 30 | * Returns the mode, or permissions, of this file. 31 | */ 32 | int getMode(); 33 | 34 | /** 35 | * Returns the UID of this file. 36 | */ 37 | int getUid(); 38 | 39 | /** 40 | * Returns the GID of this file. 41 | */ 42 | int getGid(); 43 | 44 | /** 45 | * Returns the optimal block size for reading or writing to this file, in bytes. 46 | */ 47 | long getBlockSize(); 48 | 49 | /** 50 | * Returns the last modification time of this file, in ms since epoch. 51 | */ 52 | long getLastModifiedTime(); 53 | } 54 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/PosixFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.NativeIntegration; 21 | import net.rubygrapefruit.platform.ThreadSafe; 22 | 23 | import java.io.File; 24 | 25 | /** 26 | * Functions to query and modify files on a Posix file system. 27 | */ 28 | @ThreadSafe 29 | public interface PosixFiles extends Files, NativeIntegration { 30 | /** 31 | * Sets the mode for the given file. 32 | * 33 | * @throws NativeException On failure. 34 | */ 35 | @ThreadSafe 36 | void setMode(File path, int perms) throws NativeException; 37 | 38 | /** 39 | * Gets the mode for the given file. 40 | * 41 | * @throws NativeException On failure, e.g. when target does not exist. See also {@link #stat(File, boolean)}. 42 | */ 43 | @ThreadSafe 44 | int getMode(File path) throws NativeException; 45 | 46 | /** 47 | * Gets the mode for the given file. 48 | * 49 | * @param linkTarget When true and the file is a symlink, return details of the target of the symlink instead of details of the symlink itself. 50 | * @throws NativeException On failure, e.g. when target does not exist. See also {@link #stat(File, boolean)}. 51 | */ 52 | @ThreadSafe 53 | int getMode(File path, boolean linkTarget) throws NativeException; 54 | 55 | /** 56 | * Creates a symbolic link with given contents. 57 | * 58 | * @throws NativeException On failure. 59 | */ 60 | @ThreadSafe 61 | void symlink(File link, String contents) throws NativeException; 62 | 63 | /** 64 | * Reads the contents of a symbolic link. 65 | * 66 | * @throws NativeException On failure. 67 | */ 68 | @ThreadSafe 69 | String readLink(File link) throws NativeException; 70 | 71 | /** 72 | * {@inheritDoc} 73 | */ 74 | @ThreadSafe 75 | PosixFileInfo stat(File path) throws NativeException; 76 | 77 | /** 78 | * {@inheritDoc} 79 | */ 80 | @ThreadSafe 81 | PosixFileInfo stat(File file, boolean linkTarget) throws NativeException; 82 | } 83 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/WindowsFileInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.ThreadSafe; 20 | 21 | /** 22 | * Provides some information about a file on a Windows file system. This is a snapshot and does not change. 23 | * 24 | *

A snapshot be fetched using {@link WindowsFiles#stat(java.io.File)}

25 | */ 26 | @ThreadSafe 27 | public interface WindowsFileInfo extends FileInfo { 28 | } 29 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/WindowsFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.NativeIntegration; 21 | 22 | import java.io.File; 23 | 24 | /** 25 | * Functions to query files on a Windows file system. 26 | */ 27 | public interface WindowsFiles extends Files, NativeIntegration { 28 | /** 29 | * {@inheritDoc} 30 | */ 31 | WindowsFileInfo stat(File file) throws NativeException; 32 | 33 | /** 34 | * {@inheritDoc} 35 | */ 36 | WindowsFileInfo stat(File file, boolean linkTarget) throws NativeException; 37 | } 38 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/file/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Classes the provide access to the file system. 3 | */ 4 | package net.rubygrapefruit.platform.file; -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/AbstractFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.*; 20 | import net.rubygrapefruit.platform.file.FilePermissionException; 21 | import net.rubygrapefruit.platform.file.Files; 22 | import net.rubygrapefruit.platform.file.NoSuchFileException; 23 | import net.rubygrapefruit.platform.file.NotADirectoryException; 24 | 25 | import java.io.File; 26 | 27 | public abstract class AbstractFiles implements Files { 28 | protected NativeException listDirFailure(File dir, FunctionResult result) { 29 | if (result.getFailure() == FunctionResult.Failure.NoSuchFile) { 30 | throw new NoSuchFileException(String.format("Could not list directory %s as this directory does not exist.", dir)); 31 | } 32 | if (result.getFailure() == FunctionResult.Failure.NotADirectory) { 33 | throw new NotADirectoryException(String.format("Could not list directory %s as it is not a directory.", dir)); 34 | } 35 | if (result.getFailure() == FunctionResult.Failure.Permissions) { 36 | throw new FilePermissionException(String.format("Could not list directory %s: permission denied", dir)); 37 | } 38 | throw new NativeException(String.format("Could not list directory %s: %s", dir, result.getMessage())); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/AbstractTerminal.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.terminal.TerminalOutput; 21 | import net.rubygrapefruit.platform.terminal.Terminals; 22 | 23 | import java.io.FileDescriptor; 24 | import java.io.FileOutputStream; 25 | import java.io.IOException; 26 | import java.io.OutputStream; 27 | 28 | public abstract class AbstractTerminal implements TerminalOutput { 29 | protected static byte[] NEW_LINE = System.getProperty("line.separator").getBytes(); 30 | 31 | protected abstract void init(); 32 | 33 | protected static OutputStream streamForOutput(Terminals.Output output) { 34 | return output == Terminals.Output.Stdout ? new FileOutputStream(FileDescriptor.out) : new FileOutputStream(FileDescriptor.err); 35 | } 36 | 37 | @Override 38 | public TerminalOutput newline() throws NativeException { 39 | write(NEW_LINE); 40 | return this; 41 | } 42 | 43 | public TerminalOutput write(CharSequence text) throws NativeException { 44 | // TODO encode directly to output stream instead of creating intermediate String 45 | byte[] bytes = text.toString().getBytes(); 46 | write(bytes); 47 | return this; 48 | } 49 | 50 | @Override 51 | public TerminalOutput write(char ch) throws NativeException { 52 | // TODO encode directly to output stream instead of creating intermediate String 53 | write(Character.toString(ch)); 54 | return this; 55 | } 56 | 57 | protected void write(byte[] bytes) { 58 | try { 59 | getOutputStream().write(bytes); 60 | } catch (IOException e) { 61 | throw new NativeException("Could not write to output stream.", e); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/AbstractTerminals.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.terminal.TerminalInput; 21 | import net.rubygrapefruit.platform.terminal.TerminalOutput; 22 | import net.rubygrapefruit.platform.terminal.Terminals; 23 | 24 | public abstract class AbstractTerminals implements Terminals { 25 | private final Object lock = new Object(); 26 | private Output currentlyOpen; 27 | private AbstractTerminal currentOutput; 28 | private TerminalInput currentInput; 29 | 30 | @Override 31 | public Terminals withAnsiOutput() { 32 | return new AnsiTerminals(this); 33 | } 34 | 35 | public TerminalOutput getTerminal(Output output) { 36 | synchronized (lock) { 37 | if (currentlyOpen != null && currentlyOpen != output) { 38 | throw new UnsupportedOperationException("Currently only one output can be used as a terminal."); 39 | } 40 | 41 | if (currentOutput == null) { 42 | final AbstractTerminal terminal = createTerminal(output); 43 | terminal.init(); 44 | Runtime.getRuntime().addShutdownHook(new Thread(){ 45 | @Override 46 | public void run() { 47 | terminal.reset(); 48 | } 49 | }); 50 | currentlyOpen = output; 51 | currentOutput = terminal; 52 | } 53 | 54 | return currentOutput; 55 | } 56 | } 57 | 58 | @Override 59 | public TerminalInput getTerminalInput() throws NativeException { 60 | synchronized (lock) { 61 | if (currentInput == null) { 62 | currentInput = createInput(); 63 | Runtime.getRuntime().addShutdownHook(new Thread(){ 64 | @Override 65 | public void run() { 66 | currentInput.reset(); 67 | } 68 | }); 69 | } 70 | return currentInput; 71 | } 72 | } 73 | 74 | protected abstract TerminalInput createInput(); 75 | 76 | protected abstract AbstractTerminal createTerminal(Output output); 77 | 78 | } 79 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/AbstractWindowsTerminalInput.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal; 2 | 3 | import net.rubygrapefruit.platform.NativeException; 4 | import net.rubygrapefruit.platform.terminal.TerminalInput; 5 | import net.rubygrapefruit.platform.terminal.TerminalInputListener; 6 | 7 | import java.io.FileDescriptor; 8 | import java.io.FileInputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | 12 | public abstract class AbstractWindowsTerminalInput implements TerminalInput { 13 | private final PeekInputStream inputStream = new PeekInputStream(new FileInputStream(FileDescriptor.in)); 14 | final Object lock = new Object(); 15 | 16 | @Override 17 | public InputStream getInputStream() { 18 | return inputStream; 19 | } 20 | 21 | void readNonRaw(TerminalInputListener listener) { 22 | if (peek(0) == '\n' || (peek(0) == '\r' && peek(1) == '\n')) { 23 | inputStream.consumeAll(); 24 | listener.controlKey(TerminalInputListener.Key.Enter); 25 | return; 26 | } 27 | int ch = next(); 28 | if (ch < 0) { 29 | listener.endInput(); 30 | } else { 31 | listener.character((char) ch); 32 | } 33 | } 34 | 35 | int peek(int i) { 36 | try { 37 | return inputStream.peek(i); 38 | } catch (IOException e) { 39 | throw new NativeException("Could not read from console.", e); 40 | } 41 | } 42 | 43 | int next() { 44 | try { 45 | return inputStream.read(); 46 | } catch (IOException e) { 47 | throw new NativeException("Could not read from console.", e); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/AnsiTerminals.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal; 2 | 3 | import net.rubygrapefruit.platform.NativeException; 4 | import net.rubygrapefruit.platform.terminal.TerminalInput; 5 | import net.rubygrapefruit.platform.terminal.TerminalOutput; 6 | import net.rubygrapefruit.platform.terminal.Terminals; 7 | 8 | class AnsiTerminals implements Terminals { 9 | private final Terminals delegate; 10 | private final AnsiTerminal output; 11 | 12 | public AnsiTerminals(Terminals delegate) { 13 | this.delegate = delegate; 14 | this.output = new AnsiTerminal(Output.Stdout); 15 | } 16 | 17 | @Override 18 | public Terminals withAnsiOutput() { 19 | return this; 20 | } 21 | 22 | @Override 23 | public boolean isTerminal(Output output) throws NativeException { 24 | if (output == Output.Stdout) { 25 | return true; 26 | } 27 | return delegate.isTerminal(Output.Stderr); 28 | } 29 | 30 | @Override 31 | public boolean isTerminalInput() throws NativeException { 32 | return delegate.isTerminalInput(); 33 | } 34 | 35 | @Override 36 | public TerminalOutput getTerminal(Output output) throws NativeException { 37 | if (output == Output.Stdout) { 38 | return this.output; 39 | } 40 | return delegate.getTerminal(output); 41 | } 42 | 43 | @Override 44 | public TerminalInput getTerminalInput() throws NativeException { 45 | return delegate.getTerminalInput(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/CharInputBuffer.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal; 2 | 3 | import net.rubygrapefruit.platform.terminal.TerminalInputListener; 4 | 5 | public class CharInputBuffer { 6 | char ch; 7 | TerminalInputListener.Key key; 8 | 9 | public void character(char ch) { 10 | this.ch = ch; 11 | } 12 | 13 | public void key(int value) { 14 | this.key = TerminalInputListener.Key.values()[value]; 15 | } 16 | 17 | public void applyTo(TerminalInputListener listener) { 18 | if (key != null) { 19 | listener.controlKey(key); 20 | } else if (ch != 0) { 21 | listener.character(ch); 22 | } else { 23 | listener.endInput(); 24 | } 25 | key = null; 26 | ch = 0; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/DefaultOsxMemory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.internal.jni.OsxMemoryFunctions; 21 | import net.rubygrapefruit.platform.memory.OsxMemory; 22 | import net.rubygrapefruit.platform.memory.OsxMemoryInfo; 23 | 24 | public class DefaultOsxMemory implements OsxMemory { 25 | public OsxMemoryInfo getMemoryInfo() throws NativeException { 26 | FunctionResult result = new FunctionResult(); 27 | DefaultOsxMemoryInfo memoryInfo = new DefaultOsxMemoryInfo(); 28 | OsxMemoryFunctions.getOsxMemoryInfo(memoryInfo, result); 29 | if (result.isFailed()) { 30 | throw new NativeException(String.format("Could not get OSX memory info: %s", result.getMessage())); 31 | } 32 | return memoryInfo; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/DefaultOsxMemoryInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.memory.OsxMemoryInfo; 20 | 21 | public class DefaultOsxMemoryInfo implements OsxMemoryInfo { 22 | private long pageSize; 23 | private long freeCount; 24 | private long inactiveCount; 25 | private long wiredCount; 26 | private long activeCount; 27 | private long externalCount; 28 | private long speculativeCount; 29 | 30 | private long totalMem; 31 | private long availableMem; 32 | 33 | public void details(long pageSize, 34 | long freeCount, 35 | long inactiveCount, 36 | long wiredCount, 37 | long activeCount, 38 | long externalCount, 39 | long speculativeCount, 40 | long totalMem, 41 | long availableMem) { 42 | this.pageSize = pageSize; 43 | this.freeCount = freeCount; 44 | this.inactiveCount = inactiveCount; 45 | this.wiredCount = wiredCount; 46 | this.activeCount = activeCount; 47 | this.externalCount = externalCount; 48 | this.speculativeCount = speculativeCount; 49 | this.totalMem = totalMem; 50 | this.availableMem = availableMem; 51 | } 52 | 53 | public long getPageSize() { 54 | return pageSize; 55 | } 56 | 57 | public long getFreePagesCount() { 58 | return freeCount; 59 | } 60 | 61 | public long getInactivePagesCount() { 62 | return inactiveCount; 63 | } 64 | 65 | public long getWiredPagesCount() { 66 | return wiredCount; 67 | } 68 | 69 | public long getActivePagesCount() { 70 | return activeCount; 71 | } 72 | 73 | public long getExternalPagesCount() { 74 | return externalCount; 75 | } 76 | 77 | public long getSpeculativePagesCount() { 78 | return speculativeCount; 79 | } 80 | 81 | public long getTotalPhysicalMemory() { 82 | return totalMem; 83 | } 84 | 85 | public long getAvailablePhysicalMemory() { 86 | return availableMem; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/DefaultProcessLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.ProcessLauncher; 21 | 22 | public class DefaultProcessLauncher implements ProcessLauncher { 23 | public Process start(ProcessBuilder processBuilder) throws NativeException { 24 | try { 25 | return processBuilder.start(); 26 | } catch (Exception e) { 27 | throw new NativeException(String.format("Could not start '%s'", processBuilder.command().get(0)), e); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/DefaultSystemInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.SystemInfo; 21 | import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions; 22 | 23 | public class DefaultSystemInfo implements SystemInfo { 24 | MutableSystemInfo systemInfo = new MutableSystemInfo(); 25 | 26 | public DefaultSystemInfo() { 27 | FunctionResult result = new FunctionResult(); 28 | NativeLibraryFunctions.getSystemInfo(systemInfo, result); 29 | if (result.isFailed()) { 30 | throw new NativeException(String.format("Could not fetch system information: %s", 31 | result.getMessage())); 32 | } 33 | } 34 | 35 | public String getKernelName() { 36 | return systemInfo.getKernelName(); 37 | } 38 | 39 | public String getKernelVersion() { 40 | return systemInfo.getKernelVersion(); 41 | } 42 | 43 | public String getArchitectureName() { 44 | return systemInfo.getArchitectureName(); 45 | } 46 | 47 | public Architecture getArchitecture() { 48 | return systemInfo.getArchitecture(); 49 | } 50 | 51 | public String getHostname() { 52 | return systemInfo.getHostname(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/DefaultWindowsFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.*; 20 | import net.rubygrapefruit.platform.file.DirEntry; 21 | import net.rubygrapefruit.platform.file.WindowsFileInfo; 22 | import net.rubygrapefruit.platform.file.WindowsFiles; 23 | import net.rubygrapefruit.platform.internal.jni.WindowsFileFunctions; 24 | 25 | import java.io.File; 26 | import java.util.List; 27 | 28 | public class DefaultWindowsFiles extends AbstractFiles implements WindowsFiles { 29 | public WindowsFileInfo stat(File file) throws NativeException { 30 | return stat(file, false); 31 | } 32 | 33 | public WindowsFileInfo stat(File file, boolean linkTarget) throws NativeException { 34 | FunctionResult result = new FunctionResult(); 35 | WindowsFileStat stat = new WindowsFileStat(file.getPath()); 36 | WindowsFileFunctions.stat(file.getPath(), linkTarget, stat, result); 37 | if (result.isFailed()) { 38 | throw new NativeException(String.format("Could not get file details of %s: %s", file, result.getMessage())); 39 | } 40 | return stat; 41 | } 42 | 43 | public List listDir(File dir, boolean linkTarget) throws NativeException { 44 | FunctionResult result = new FunctionResult(); 45 | WindowsDirList dirList = new WindowsDirList(); 46 | WindowsFileFunctions.readdir(dir.getPath(), linkTarget, dirList, result); 47 | if (result.isFailed()) { 48 | throw listDirFailure(dir, result); 49 | } 50 | return dirList.files; 51 | } 52 | 53 | public List listDir(File dir) throws NativeException { 54 | return listDir(dir, false); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/DefaultWindowsMemory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.internal.jni.OsxMemoryFunctions; 21 | import net.rubygrapefruit.platform.internal.jni.WindowsMemoryFunctions; 22 | import net.rubygrapefruit.platform.memory.OsxMemory; 23 | import net.rubygrapefruit.platform.memory.OsxMemoryInfo; 24 | import net.rubygrapefruit.platform.memory.WindowsMemory; 25 | import net.rubygrapefruit.platform.memory.WindowsMemoryInfo; 26 | 27 | public class DefaultWindowsMemory implements WindowsMemory { 28 | public WindowsMemoryInfo getMemoryInfo() throws NativeException { 29 | FunctionResult result = new FunctionResult(); 30 | DefaultWindowsMemoryInfo memoryInfo = new DefaultWindowsMemoryInfo(); 31 | WindowsMemoryFunctions.getWindowsMemoryInfo(memoryInfo, result); 32 | if (result.isFailed()) { 33 | throw new NativeException(String.format("Could not get Windows memory info: %s", result.getMessage())); 34 | } 35 | return memoryInfo; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/DefaultWindowsMemoryInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.memory.WindowsMemoryInfo; 20 | 21 | public class DefaultWindowsMemoryInfo implements WindowsMemoryInfo { 22 | private long commitTotal; 23 | private long commitLimit; 24 | private long totalPhysicalMemory; 25 | private long availablePhysicalMemory; 26 | 27 | public void details(long commitTotal, long commitLimit, long totalPhysicalMemory, long availablePhysicalMemory) { 28 | this.commitTotal = commitTotal; 29 | this.commitLimit = commitLimit; 30 | this.totalPhysicalMemory = totalPhysicalMemory; 31 | this.availablePhysicalMemory = availablePhysicalMemory; 32 | } 33 | 34 | @Override 35 | public long getCommitTotal() { 36 | return commitTotal; 37 | } 38 | 39 | @Override 40 | public long getCommitLimit() { 41 | return commitLimit; 42 | } 43 | 44 | @Override 45 | public long getTotalPhysicalMemory() { 46 | return totalPhysicalMemory; 47 | } 48 | 49 | @Override 50 | public long getAvailablePhysicalMemory() { 51 | return availablePhysicalMemory; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/DefaultWindowsRegistry.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal; 2 | 3 | import net.rubygrapefruit.platform.MissingRegistryEntryException; 4 | import net.rubygrapefruit.platform.NativeException; 5 | import net.rubygrapefruit.platform.WindowsRegistry; 6 | import net.rubygrapefruit.platform.internal.jni.WindowsRegistryFunctions; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class DefaultWindowsRegistry implements WindowsRegistry { 12 | public String getStringValue(Key key, String subkey, String valueName) throws NativeException { 13 | FunctionResult result = new FunctionResult(); 14 | String value = WindowsRegistryFunctions.getStringValue(key.ordinal(), subkey, valueName, result); 15 | if (result.isFailed()) { 16 | throw new NativeException(String.format("Could not get value '%s' of registry key '%s\\%s': %s", valueName, 17 | key, 18 | subkey, result.getMessage())); 19 | } 20 | if (value == null) { 21 | throw new MissingRegistryEntryException(String.format( 22 | "Could not get value '%s' of registry key '%s\\%s' as it does not exist.", valueName, key, subkey)); 23 | } 24 | return value; 25 | } 26 | 27 | public List getSubkeys(Key key, String subkey) throws NativeException { 28 | FunctionResult result = new FunctionResult(); 29 | ArrayList subkeys = new ArrayList(); 30 | boolean found = WindowsRegistryFunctions.getSubkeys(key.ordinal(), subkey, subkeys, result); 31 | if (result.isFailed()) { 32 | throw new NativeException(String.format("Could not list the subkeys of registry key '%s\\%s': %s", key, 33 | subkey, result.getMessage())); 34 | } 35 | if (!found) { 36 | throw new MissingRegistryEntryException(String.format( 37 | "Could not list the subkeys of registry key '%s\\%s' as it does not exist.", key, subkey)); 38 | } 39 | return subkeys; 40 | } 41 | 42 | public List getValueNames(Key key, String subkey) throws NativeException { 43 | FunctionResult result = new FunctionResult(); 44 | ArrayList names = new ArrayList(); 45 | boolean found = WindowsRegistryFunctions.getValueNames(key.ordinal(), subkey, names, result); 46 | if (result.isFailed()) { 47 | throw new NativeException(String.format("Could not list the values of registry key '%s\\%s': %s", key, 48 | subkey, result.getMessage())); 49 | } 50 | if (!found) { 51 | throw new MissingRegistryEntryException(String.format( 52 | "Could not list the values of registry key '%s\\%s' as it does not exist.", key, subkey)); 53 | } 54 | return names; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/DirList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.file.DirEntry; 20 | import net.rubygrapefruit.platform.file.FileInfo; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class DirList { 26 | public List files = new ArrayList(); 27 | 28 | // Called from native code 29 | @SuppressWarnings("UnusedDeclaration") 30 | public void addFile(String name, int type, long size, long lastModified) { 31 | DefaultDirEntry fileStat = new DefaultDirEntry(name, FileInfo.Type.values()[type], size, lastModified); 32 | files.add(fileStat); 33 | } 34 | 35 | private static class DefaultDirEntry implements DirEntry { 36 | private final String name; 37 | private final Type type; 38 | private final long size; 39 | private final long lastModified; 40 | 41 | DefaultDirEntry(String name, Type type, long size, long lastModified) { 42 | this.name = name; 43 | this.type = type; 44 | this.size = size; 45 | this.lastModified = lastModified; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return name; 51 | } 52 | 53 | public String getName() { 54 | return name; 55 | } 56 | 57 | public Type getType() { 58 | return type; 59 | } 60 | 61 | public long getLastModifiedTime() { 62 | return lastModified; 63 | } 64 | 65 | public long getSize() { 66 | return size; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/FileStat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.file.PosixFileInfo; 20 | 21 | public class FileStat implements PosixFileInfo { 22 | private final String path; 23 | private int mode; 24 | private Type type; 25 | private int uid; 26 | private int gid; 27 | private long size; 28 | private long modificationTime; 29 | private long blockSize; 30 | 31 | public FileStat(String path) { 32 | this.path = path; 33 | } 34 | 35 | public void details(int type, int mode, int uid, int gid, long size, long modificationTime, int blockSize) { 36 | this.type = Type.values()[type]; 37 | this.mode = mode; 38 | this.uid = uid; 39 | this.gid = gid; 40 | this.size = size; 41 | this.modificationTime = modificationTime; 42 | this.blockSize = blockSize; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return path; 48 | } 49 | 50 | public int getMode() { 51 | return mode; 52 | } 53 | 54 | public Type getType() { 55 | return type; 56 | } 57 | 58 | public int getUid() { 59 | return uid; 60 | } 61 | 62 | public int getGid() { 63 | return gid; 64 | } 65 | 66 | public long getSize() { 67 | return size; 68 | } 69 | 70 | public long getBlockSize() { 71 | return blockSize; 72 | } 73 | 74 | public long getLastModifiedTime() { 75 | return modificationTime; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/FileSystemList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.file.CaseSensitivity; 20 | import net.rubygrapefruit.platform.file.FileSystemInfo; 21 | 22 | import javax.annotation.Nullable; 23 | import java.io.File; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | public class FileSystemList { 28 | public final List fileSystems = new ArrayList(); 29 | 30 | public void add(String mountPoint, String fileSystemType, String deviceName, boolean remote, boolean caseSensitive, boolean casePreserving) { 31 | fileSystems.add(new DefaultFileSystemInfo(new File(mountPoint), fileSystemType, deviceName, remote, new DefaultCaseSensitivity(caseSensitive, casePreserving))); 32 | } 33 | 34 | public void addForUnknownCaseSensitivity(String mountPoint, @Nullable String fileSystemType, String deviceName, boolean remote) { 35 | fileSystems.add(new DefaultFileSystemInfo(new File(mountPoint), fileSystemType == null ? "unknown" : fileSystemType, deviceName, remote, null)); 36 | } 37 | 38 | private static class DefaultCaseSensitivity implements CaseSensitivity { 39 | private final boolean caseSensitive; 40 | private final boolean casePreserving; 41 | 42 | public DefaultCaseSensitivity(boolean caseSensitive, boolean casePreserving) { 43 | this.caseSensitive = caseSensitive; 44 | this.casePreserving = casePreserving; 45 | } 46 | 47 | @Override 48 | public boolean isCaseSensitive() { 49 | return caseSensitive; 50 | } 51 | 52 | @Override 53 | public boolean isCasePreserving() { 54 | return casePreserving; 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return "CaseSensitivity{" + 60 | "caseSensitive=" + caseSensitive + 61 | ", casePreserving=" + casePreserving + 62 | '}'; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/FunctionResult.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | public class FunctionResult { 20 | public enum Failure { 21 | // Order is important - see generic.h 22 | Generic, 23 | NoSuchFile, 24 | NotADirectory, 25 | Permissions 26 | } 27 | private String message; 28 | private int errno; 29 | private Failure failure = Failure.Generic; 30 | private String errorCodeDescription; 31 | 32 | // Called from native code 33 | @SuppressWarnings("UnusedDeclaration") 34 | void failed(String message, int failure, int errno, String errorCodeDescription) { 35 | this.message = message; 36 | this.failure = Failure.values()[failure]; 37 | this.errno = errno; 38 | this.errorCodeDescription = errorCodeDescription; 39 | } 40 | 41 | // Called from native code 42 | @SuppressWarnings("UnusedDeclaration") 43 | void failed(String message) { 44 | this.message = message; 45 | } 46 | 47 | public boolean isFailed() { 48 | return message != null; 49 | } 50 | 51 | public Failure getFailure() { 52 | return failure; 53 | } 54 | 55 | public String getMessage() { 56 | if (errorCodeDescription != null && errorCodeDescription.length() > 0) { 57 | return String.format("%s (errno %d: %s)", message, errno, errorCodeDescription); 58 | } 59 | if (errno != 0) { 60 | return String.format("%s (errno %d)", message, errno); 61 | } 62 | return message; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/LibraryDef.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal; 2 | 3 | public class LibraryDef { 4 | final String name; 5 | final String platform; 6 | 7 | public LibraryDef(String name, String platform) { 8 | this.name = name; 9 | this.platform = platform; 10 | } 11 | 12 | @Override 13 | public boolean equals(Object obj) { 14 | if (obj == this) { 15 | return true; 16 | } 17 | if (obj == null || obj.getClass() != getClass()) { 18 | return false; 19 | } 20 | LibraryDef other = (LibraryDef) obj; 21 | return name.equals(other.name) && platform.equals(other.platform); 22 | } 23 | 24 | @Override 25 | public int hashCode() { 26 | return name.hashCode() ^ platform.hashCode(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/MutableTerminalSize.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.terminal.TerminalSize; 20 | 21 | public class MutableTerminalSize implements TerminalSize { 22 | int rows; 23 | int cols; 24 | 25 | public int getCols() { 26 | return cols; 27 | } 28 | 29 | public int getRows() { 30 | return rows; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/MutableTypeInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeIntegration; 20 | 21 | public class MutableTypeInfo implements NativeIntegration { 22 | // Fields set from native code 23 | int int_bytes; 24 | int u_long_bytes; 25 | int size_t_bytes; 26 | int uid_t_bytes; 27 | int gid_t_bytes; 28 | int off_t_bytes; 29 | } 30 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/NativeLibraryLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.NativeIntegrationLinkageException; 21 | import net.rubygrapefruit.platform.NativeIntegrationUnavailableException; 22 | 23 | import java.io.File; 24 | import java.util.HashSet; 25 | import java.util.List; 26 | import java.util.Set; 27 | 28 | public class NativeLibraryLoader { 29 | private final Set loaded = new HashSet(); 30 | private final Platform platform; 31 | private final NativeLibraryLocator nativeLibraryLocator; 32 | 33 | public NativeLibraryLoader(Platform platform, NativeLibraryLocator nativeLibraryLocator) { 34 | this.platform = platform; 35 | this.nativeLibraryLocator = nativeLibraryLocator; 36 | } 37 | 38 | public void load(String libraryFileName, List platforms) { 39 | if (loaded.contains(libraryFileName)) { 40 | return; 41 | } 42 | try { 43 | UnsatisfiedLinkError loadFailure = null; 44 | for (String platformId : platforms) { 45 | File libFile = nativeLibraryLocator.find(new LibraryDef(libraryFileName, platformId)); 46 | if (libFile == null) { 47 | continue; 48 | } 49 | 50 | try { 51 | System.load(libFile.getCanonicalPath()); 52 | } catch (UnsatisfiedLinkError e) { 53 | loadFailure = e; 54 | continue; 55 | } 56 | 57 | loaded.add(libraryFileName); 58 | return; 59 | } 60 | if (loadFailure != null) { 61 | throw new NativeIntegrationLinkageException(String.format("Native library '%s' could not be loaded for %s.", libraryFileName, platform), loadFailure); 62 | } 63 | throw new NativeIntegrationUnavailableException(String.format("Native library '%s' is not available for %s.", libraryFileName, platform)); 64 | } catch (NativeException e) { 65 | throw e; 66 | } catch (Throwable t) { 67 | throw new NativeException(String.format("Failed to load native library '%s' for %s.", libraryFileName, platform), t); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/PeekInputStream.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | public class PeekInputStream extends InputStream { 7 | private final InputStream delegate; 8 | private byte[] buffer; 9 | private int charsBuffered; 10 | 11 | public PeekInputStream(InputStream delegate) { 12 | this.delegate = delegate; 13 | buffer = new byte[4]; 14 | } 15 | 16 | public int peek(int depth) throws IOException { 17 | if (depth < charsBuffered) { 18 | return buffer[depth]; 19 | } 20 | if (depth != charsBuffered) { 21 | throw new UnsupportedOperationException("Not yet implemented."); 22 | } 23 | int ch = delegate.read(); 24 | if (ch < 0) { 25 | return ch; 26 | } 27 | buffer[charsBuffered] = (byte) ch; 28 | charsBuffered++; 29 | return ch; 30 | } 31 | 32 | public void consumeAll() { 33 | charsBuffered = 0; 34 | } 35 | 36 | @Override 37 | public int read() throws IOException { 38 | if (charsBuffered > 0) { 39 | byte result = buffer[0]; 40 | charsBuffered--; 41 | for (int i = 0; i < charsBuffered; i++) { 42 | buffer[i] = buffer[i + 1]; 43 | } 44 | return result; 45 | } 46 | return delegate.read(); 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/PlainTerminalInput.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal; 2 | 3 | import net.rubygrapefruit.platform.NativeException; 4 | import net.rubygrapefruit.platform.terminal.TerminalInput; 5 | import net.rubygrapefruit.platform.terminal.TerminalInputListener; 6 | 7 | public class PlainTerminalInput extends AbstractWindowsTerminalInput { 8 | @Override 9 | public String toString() { 10 | return "plain input on stdin"; 11 | } 12 | 13 | @Override 14 | public void read(TerminalInputListener listener) throws NativeException { 15 | synchronized (lock) { 16 | readNonRaw(listener); 17 | } 18 | } 19 | 20 | @Override 21 | public boolean supportsRawMode() { 22 | return false; 23 | } 24 | 25 | @Override 26 | public TerminalInput rawMode() throws NativeException { 27 | throw new NativeException("Raw mode is not supported for this terminal."); 28 | } 29 | 30 | @Override 31 | public TerminalInput reset() throws NativeException { 32 | // ignore 33 | return this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/PosixFileSystems.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.file.FileSystemInfo; 20 | import net.rubygrapefruit.platform.file.FileSystems; 21 | import net.rubygrapefruit.platform.NativeException; 22 | import net.rubygrapefruit.platform.internal.jni.PosixFileSystemFunctions; 23 | 24 | import java.util.List; 25 | 26 | public class PosixFileSystems implements FileSystems { 27 | public List getFileSystems() { 28 | FunctionResult result = new FunctionResult(); 29 | FileSystemList fileSystems = new FileSystemList(); 30 | PosixFileSystemFunctions.listFileSystems(fileSystems, result); 31 | if (result.isFailed()) { 32 | throw new NativeException(String.format("Could not query file systems: %s", result.getMessage())); 33 | } 34 | return fileSystems.fileSystems; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/PosixTerminals.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.terminal.TerminalInput; 21 | import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions; 22 | import net.rubygrapefruit.platform.internal.jni.PosixTerminalFunctions; 23 | 24 | public class PosixTerminals extends AbstractTerminals { 25 | public boolean isTerminal(Output output) { 26 | switch (output) { 27 | case Stdout: 28 | return PosixTerminalFunctions.isatty(NativeLibraryFunctions.STDOUT); 29 | case Stderr: 30 | return PosixTerminalFunctions.isatty(NativeLibraryFunctions.STDERR); 31 | default: 32 | throw new IllegalArgumentException(); 33 | } 34 | } 35 | 36 | @Override 37 | public boolean isTerminalInput() throws NativeException { 38 | return PosixTerminalFunctions.isatty(NativeLibraryFunctions.STDIN); 39 | } 40 | 41 | @Override 42 | protected TerminalInput createInput() { 43 | return new PosixTerminalInput(); 44 | } 45 | 46 | @Override 47 | protected AbstractTerminal createTerminal(Output output) { 48 | return new TerminfoTerminal(output); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/TerminalCapabilities.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | public class TerminalCapabilities { 20 | String terminalName; 21 | } 22 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/WindowsDirList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | public class WindowsDirList extends DirList { 20 | // Called from native code 21 | @SuppressWarnings("UnusedDeclaration") 22 | @Override 23 | public void addFile(String name, int type, long size, long lastModified) { 24 | super.addFile(name, type, size, WindowsFileTime.toJavaTime(lastModified)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/WindowsFileStat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.file.WindowsFileInfo; 20 | 21 | public class WindowsFileStat implements WindowsFileInfo { 22 | private final String path; 23 | private Type type; 24 | private long size; 25 | private long lastModified; 26 | 27 | public WindowsFileStat(String path) { 28 | this.path = path; 29 | } 30 | 31 | public void details(int type, long size, long lastModifiedWinTime) { 32 | this.type = Type.values()[type]; 33 | this.size = size; 34 | this.lastModified = WindowsFileTime.toJavaTime(lastModifiedWinTime); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return path; 40 | } 41 | 42 | public Type getType() { 43 | return type; 44 | } 45 | 46 | public long getSize() { 47 | return size; 48 | } 49 | 50 | public long getLastModifiedTime() { 51 | return lastModified; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/WindowsFileTime.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import java.util.Calendar; 20 | import java.util.GregorianCalendar; 21 | import java.util.TimeZone; 22 | 23 | public class WindowsFileTime { 24 | private static final long EPOCH_OFFSET = offset(); 25 | 26 | private static long offset() { 27 | Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 28 | calendar.set(1601, Calendar.JANUARY, 1, 0, 0, 0); 29 | calendar.set(Calendar.MILLISECOND, 0); 30 | return calendar.getTimeInMillis(); 31 | } 32 | 33 | public static long toJavaTime(long winFileTime) { 34 | if (winFileTime == 0) { 35 | return 0; 36 | } 37 | return winFileTime / 10000 + EPOCH_OFFSET; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/WindowsProcessLauncher.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal; 2 | 3 | import net.rubygrapefruit.platform.NativeException; 4 | import net.rubygrapefruit.platform.ProcessLauncher; 5 | import net.rubygrapefruit.platform.internal.jni.WindowsHandleFunctions; 6 | 7 | public class WindowsProcessLauncher implements ProcessLauncher { 8 | private final ProcessLauncher launcher; 9 | 10 | public WindowsProcessLauncher(ProcessLauncher launcher) { 11 | this.launcher = launcher; 12 | } 13 | 14 | public Process start(ProcessBuilder processBuilder) throws NativeException { 15 | FunctionResult result = new FunctionResult(); 16 | WindowsHandleFunctions.markStandardHandlesUninheritable(result); 17 | if (result.isFailed()) { 18 | throw new NativeException(String.format("Could not start '%s': %s", processBuilder.command().get(0), 19 | result.getMessage())); 20 | } 21 | try { 22 | return launcher.start(processBuilder); 23 | } finally { 24 | WindowsHandleFunctions.restoreStandardHandles(result); 25 | if (result.isFailed()) { 26 | throw new NativeException(String.format("Could not restore process handles: %s", result.getMessage())); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/WindowsTerminalInput.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal; 2 | 3 | import net.rubygrapefruit.platform.NativeException; 4 | import net.rubygrapefruit.platform.terminal.TerminalInput; 5 | import net.rubygrapefruit.platform.terminal.TerminalInputListener; 6 | import net.rubygrapefruit.platform.internal.jni.WindowsConsoleFunctions; 7 | 8 | import java.io.FileDescriptor; 9 | import java.io.FileInputStream; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | 13 | public class WindowsTerminalInput extends AbstractWindowsTerminalInput { 14 | private boolean raw; 15 | 16 | @Override 17 | public String toString() { 18 | return "Windows console on stdin"; 19 | } 20 | 21 | @Override 22 | public void read(TerminalInputListener listener) { 23 | synchronized (lock) { 24 | if (raw) { 25 | FunctionResult result = new FunctionResult(); 26 | CharInputBuffer buffer = new CharInputBuffer(); 27 | WindowsConsoleFunctions.readInput(buffer, result); 28 | if (result.isFailed()) { 29 | throw new NativeException(String.format("Could not read from console: %s", result.getMessage())); 30 | } 31 | buffer.applyTo(listener); 32 | } else { 33 | readNonRaw(listener); 34 | } 35 | } 36 | } 37 | 38 | @Override 39 | public boolean supportsRawMode() { 40 | return true; 41 | } 42 | 43 | @Override 44 | public TerminalInput rawMode() throws NativeException { 45 | synchronized (lock) { 46 | FunctionResult result = new FunctionResult(); 47 | WindowsConsoleFunctions.rawInputMode(result); 48 | if (result.isFailed()) { 49 | throw new NativeException(String.format("Could not switch console input to raw mode: %s", result.getMessage())); 50 | } 51 | raw = true; 52 | } 53 | return this; 54 | } 55 | 56 | @Override 57 | public TerminalInput reset() { 58 | synchronized (lock) { 59 | FunctionResult result = new FunctionResult(); 60 | WindowsConsoleFunctions.resetInputMode(result); 61 | if (result.isFailed()) { 62 | throw new NativeException(String.format("Could not reset console input mode: %s", result.getMessage())); 63 | } 64 | raw = false; 65 | } 66 | return this; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/WrapperProcessLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.ProcessLauncher; 21 | import net.rubygrapefruit.platform.ThreadSafe; 22 | 23 | @ThreadSafe 24 | public class WrapperProcessLauncher implements ProcessLauncher { 25 | private final Object startLock = new Object(); 26 | private final ProcessLauncher launcher; 27 | 28 | public WrapperProcessLauncher(ProcessLauncher launcher) { 29 | this.launcher = launcher; 30 | } 31 | 32 | public Process start(ProcessBuilder processBuilder) throws NativeException { 33 | synchronized (startLock) { 34 | // Start a single process at a time, to avoid streams to child process being inherited by other 35 | // children before the parent can close them 36 | return launcher.start(processBuilder); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/InsufficientResourcesForWatchingException.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal.jni; 2 | 3 | import net.rubygrapefruit.platform.NativeException; 4 | 5 | public class InsufficientResourcesForWatchingException extends NativeException { 6 | public InsufficientResourcesForWatchingException(String message) { 7 | super(message); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/NativeLibraryFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.FunctionResult; 20 | import net.rubygrapefruit.platform.internal.MutableSystemInfo; 21 | import net.rubygrapefruit.platform.terminal.Terminals; 22 | 23 | public class NativeLibraryFunctions { 24 | public static final int STDOUT = Terminals.Output.Stdout.ordinal(); 25 | public static final int STDERR = Terminals.Output.Stderr.ordinal(); 26 | public static final int STDIN = STDERR + 1; 27 | 28 | public static native String getVersion(); 29 | 30 | public static native void getSystemInfo(MutableSystemInfo systemInfo, FunctionResult result); 31 | } 32 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/OsxMemoryFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.DefaultOsxMemoryInfo; 20 | import net.rubygrapefruit.platform.internal.FunctionResult; 21 | 22 | public class OsxMemoryFunctions { 23 | public static native void getOsxMemoryInfo(DefaultOsxMemoryInfo memoryInfo, FunctionResult result); 24 | } 25 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/PosixFileFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.DirList; 20 | import net.rubygrapefruit.platform.internal.FileStat; 21 | import net.rubygrapefruit.platform.internal.FunctionResult; 22 | 23 | public class PosixFileFunctions { 24 | public static native void chmod(String file, int perms, FunctionResult result); 25 | 26 | public static native void stat(String file, boolean followLink, FileStat stat, FunctionResult result); 27 | 28 | public static native void readdir(String file, boolean followLink, DirList stat, FunctionResult result); 29 | 30 | public static native void symlink(String file, String content, FunctionResult result); 31 | 32 | public static native String readlink(String file, FunctionResult result); 33 | } 34 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/PosixFileSystemFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.FileSystemList; 20 | import net.rubygrapefruit.platform.internal.FunctionResult; 21 | 22 | public class PosixFileSystemFunctions { 23 | public static native void listFileSystems(FileSystemList fileSystems, FunctionResult result); 24 | } 25 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/PosixProcessFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.FunctionResult; 20 | 21 | public class PosixProcessFunctions { 22 | public static native int getPid(); 23 | 24 | public static native void detach(FunctionResult result); 25 | 26 | public static native String getWorkingDirectory(FunctionResult result); 27 | 28 | public static native void setWorkingDirectory(String dir, FunctionResult result); 29 | 30 | public static native String getEnvironmentVariable(String var, FunctionResult result); 31 | 32 | public static native void setEnvironmentVariable(String var, String value, FunctionResult result); 33 | } 34 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/PosixTerminalFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.FunctionResult; 20 | import net.rubygrapefruit.platform.internal.MutableTerminalSize; 21 | 22 | public class PosixTerminalFunctions { 23 | public static native boolean isatty(int filedes); 24 | 25 | public static native void getTerminalSize(int filedes, MutableTerminalSize size, FunctionResult result); 26 | 27 | public static native void rawInputMode(FunctionResult result); 28 | 29 | public static native void resetInputMode(FunctionResult result); 30 | } 31 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/PosixTypeFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.MutableTypeInfo; 20 | 21 | public class PosixTypeFunctions { 22 | public static native void getNativeTypeInfo(MutableTypeInfo systemInfo); 23 | } 24 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/TerminfoFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.FunctionResult; 20 | import net.rubygrapefruit.platform.internal.TerminalCapabilities; 21 | 22 | public class TerminfoFunctions { 23 | public static native String getVersion(); 24 | 25 | /** 26 | * Sets up output. 27 | */ 28 | public static native void initTerminal(int filedes, TerminalCapabilities terminalCapabilities, FunctionResult result); 29 | 30 | public static native byte[] boldOn(FunctionResult result); 31 | 32 | public static native byte[] dimOn(FunctionResult result); 33 | 34 | // May be null 35 | public static native byte[] reset(FunctionResult result); 36 | 37 | public static native byte[] foreground(int ansiColor, FunctionResult result); 38 | 39 | public static native byte[] defaultForeground(FunctionResult result); 40 | 41 | public static native byte[] hideCursor(FunctionResult result); 42 | 43 | public static native byte[] showCursor(FunctionResult result); 44 | 45 | public static native byte[] left(FunctionResult result); 46 | 47 | public static native byte[] right(FunctionResult result); 48 | 49 | public static native byte[] up(FunctionResult result); 50 | 51 | public static native byte[] down(FunctionResult result); 52 | 53 | public static native byte[] startLine(FunctionResult result); 54 | 55 | public static native byte[] clearToEndOfLine(FunctionResult result); 56 | } 57 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/WindowsConsoleFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.CharInputBuffer; 20 | import net.rubygrapefruit.platform.internal.FunctionResult; 21 | import net.rubygrapefruit.platform.internal.MutableTerminalSize; 22 | 23 | public class WindowsConsoleFunctions { 24 | public static final int CONSOLE_NONE = 0; 25 | public static final int CONSOLE_WINDOWS = 1; 26 | public static final int CONSOLE_CYGWIN = 2; 27 | 28 | /** 29 | * @return {@link #CONSOLE_NONE} when not a console, {@link #CONSOLE_WINDOWS} when Windows console, {@link #CONSOLE_CYGWIN} when Cygwin or msys console. 30 | */ 31 | public static native int isConsole(int filedes, FunctionResult result); 32 | 33 | public static native void getConsoleSize(int filedes, MutableTerminalSize size, FunctionResult result); 34 | 35 | public static native void initConsole(int filedes, FunctionResult result); 36 | 37 | public static native void rawInputMode(FunctionResult result); 38 | 39 | public static native void resetInputMode(FunctionResult result); 40 | 41 | public static native void readInput(CharInputBuffer buffer, FunctionResult result); 42 | 43 | public static native void boldOn(FunctionResult result); 44 | 45 | public static native void boldOff(FunctionResult result); 46 | 47 | public static native void reset(FunctionResult result); 48 | 49 | public static native void showCursor(FunctionResult result); 50 | 51 | public static native void hideCursor(FunctionResult result); 52 | 53 | public static native void foreground(int ansiColor, FunctionResult result); 54 | 55 | public static native void defaultForeground(FunctionResult result); 56 | 57 | public static native void left(int count, FunctionResult result); 58 | 59 | public static native void right(int count, FunctionResult result); 60 | 61 | public static native void up(int count, FunctionResult result); 62 | 63 | public static native void down(int count, FunctionResult result); 64 | 65 | public static native void startLine(FunctionResult result); 66 | 67 | public static native void clearToEndOfLine(FunctionResult result); 68 | } 69 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/WindowsFileFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.DirList; 20 | import net.rubygrapefruit.platform.internal.FunctionResult; 21 | import net.rubygrapefruit.platform.internal.WindowsFileStat; 22 | 23 | public class WindowsFileFunctions { 24 | public static native void stat(String file, boolean followLink, WindowsFileStat stat, FunctionResult result); 25 | 26 | public static native void readdir(String path, boolean followLink, DirList dirList, FunctionResult result); 27 | } 28 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/WindowsHandleFunctions.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal.jni; 2 | 3 | import net.rubygrapefruit.platform.internal.FunctionResult; 4 | 5 | public class WindowsHandleFunctions { 6 | public static native void markStandardHandlesUninheritable(FunctionResult result); 7 | 8 | public static native void restoreStandardHandles(FunctionResult result); 9 | } 10 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/WindowsMemoryFunctions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal.jni; 18 | 19 | import net.rubygrapefruit.platform.internal.DefaultOsxMemoryInfo; 20 | import net.rubygrapefruit.platform.internal.DefaultWindowsMemoryInfo; 21 | import net.rubygrapefruit.platform.internal.FunctionResult; 22 | 23 | public class WindowsMemoryFunctions { 24 | public static native void getWindowsMemoryInfo(DefaultWindowsMemoryInfo memoryInfo, FunctionResult result); 25 | } 26 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/internal/jni/WindowsRegistryFunctions.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.internal.jni; 2 | 3 | import net.rubygrapefruit.platform.internal.FunctionResult; 4 | 5 | import java.util.List; 6 | 7 | public class WindowsRegistryFunctions { 8 | // Returns null for unknown key or value 9 | public static native String getStringValue(int key, String subkey, String value, FunctionResult result); 10 | 11 | // Returns false for unknown key 12 | public static native boolean getSubkeys(int key, String subkey, List subkeys, FunctionResult result); 13 | 14 | // Returns false for unknown key 15 | public static native boolean getValueNames(int key, String subkey, List names, FunctionResult result); 16 | } 17 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/memory/Memory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.memory; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.NativeIntegration; 21 | import net.rubygrapefruit.platform.ThreadSafe; 22 | 23 | /** 24 | * Provides details about the system memory. 25 | */ 26 | @ThreadSafe 27 | public interface Memory extends NativeIntegration { 28 | /** 29 | * Queries the current state of the system memory. 30 | * 31 | * @return A snapshot of the current state of the system memory. 32 | * @throws NativeException On failure. 33 | */ 34 | @ThreadSafe 35 | MemoryInfo getMemoryInfo() throws NativeException; 36 | } 37 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/memory/MemoryInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.memory; 18 | 19 | import net.rubygrapefruit.platform.ThreadSafe; 20 | 21 | /** 22 | * Provides some information about the system memory. This is a snapshot and does not change. 23 | */ 24 | @ThreadSafe 25 | public interface MemoryInfo { 26 | /** 27 | * Returns the number of bytes of physical memory installed in the machine. 28 | */ 29 | long getTotalPhysicalMemory(); 30 | 31 | /** 32 | * Returns the number of bytes of physical memory that are available for use. Includes memory that is available without swapping. 33 | */ 34 | long getAvailablePhysicalMemory(); 35 | } 36 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/memory/OsxMemory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.memory; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.NativeIntegration; 21 | import net.rubygrapefruit.platform.ThreadSafe; 22 | 23 | /** 24 | * Provides MacOS specific details about the system memory. 25 | */ 26 | @ThreadSafe 27 | public interface OsxMemory extends Memory, NativeIntegration { 28 | /** 29 | * Queries the current state of the system memory. 30 | * 31 | * @throws NativeException On failure. 32 | */ 33 | @ThreadSafe 34 | OsxMemoryInfo getMemoryInfo() throws NativeException; 35 | } 36 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/memory/OsxMemoryInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.memory; 18 | 19 | import net.rubygrapefruit.platform.ThreadSafe; 20 | 21 | /** 22 | * Detailed OSX memory info. 23 | * 24 | * This is not exactly what {@literal vm_stat} displays: 25 | * 26 | * {@literal vm_stat}'s {@literal Free pages} 27 | * is {@link #getFreePagesCount()} minus {@link #getSpeculativePagesCount()}. 28 | * 29 | * {@link #getExternalPagesCount()} is displayed as {@literal File-backed pages}. 30 | */ 31 | @ThreadSafe 32 | public interface OsxMemoryInfo extends MemoryInfo { 33 | long getPageSize(); 34 | 35 | long getFreePagesCount(); 36 | 37 | long getInactivePagesCount(); 38 | 39 | long getWiredPagesCount(); 40 | 41 | long getActivePagesCount(); 42 | 43 | long getExternalPagesCount(); 44 | 45 | long getSpeculativePagesCount(); 46 | 47 | long getTotalPhysicalMemory(); 48 | 49 | /** 50 | * Calculated. 51 | */ 52 | long getAvailablePhysicalMemory(); 53 | } 54 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/memory/WindowsMemory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.memory; 18 | 19 | import net.rubygrapefruit.platform.NativeException; 20 | import net.rubygrapefruit.platform.NativeIntegration; 21 | import net.rubygrapefruit.platform.ThreadSafe; 22 | 23 | /** 24 | * Provides Windows-specific details about the system memory. 25 | */ 26 | @ThreadSafe 27 | public interface WindowsMemory extends Memory, NativeIntegration { 28 | /** 29 | * Queries the current state of the system memory. 30 | * 31 | * @throws NativeException On failure. 32 | */ 33 | @ThreadSafe 34 | WindowsMemoryInfo getMemoryInfo() throws NativeException; 35 | } 36 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/memory/WindowsMemoryInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.memory; 18 | 19 | import net.rubygrapefruit.platform.ThreadSafe; 20 | 21 | /** 22 | * Detailed Windows memory info. 23 | * 24 | *

25 | * See 26 | * the Windows Process Status API for detailed information on these values. 27 | *

28 | * 29 | *

30 | * Note that these integers are unsigned, so additional care must be taken to ensure that the values are interpreted 31 | * correctly. 32 | *

33 | */ 34 | @ThreadSafe 35 | public interface WindowsMemoryInfo extends MemoryInfo { 36 | long getCommitTotal(); 37 | 38 | long getCommitLimit(); 39 | } 40 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/memory/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Classes that provide details about the system memory. 3 | */ 4 | package net.rubygrapefruit.platform.memory; -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * Native integrations. 19 | * 20 | *

Use {@link net.rubygrapefruit.platform.Native#get(Class)} to access a {@link net.rubygrapefruit.platform.NativeIntegration}. 21 | */ 22 | package net.rubygrapefruit.platform; -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/AbstractListener.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | import net.rubygrapefruit.platform.terminal.TerminalInputListener; 4 | 5 | abstract class AbstractListener implements TerminalInputListener { 6 | abstract boolean isFinished(); 7 | } 8 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/AbstractPrompter.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | import java.util.List; 4 | 5 | abstract class AbstractPrompter { 6 | abstract boolean isInteractive(); 7 | 8 | Integer select(String prompt, List options, int defaultOption) { 9 | return defaultOption; 10 | } 11 | 12 | String enterText(String prompt, String defaultValue) { 13 | return defaultValue; 14 | } 15 | 16 | String enterPassword(String prompt) { 17 | return null; 18 | } 19 | 20 | Boolean askYesNo(String prompt, boolean defaultValue) { 21 | return defaultValue; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/InteractivePrompter.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | import net.rubygrapefruit.platform.terminal.TerminalInput; 4 | import net.rubygrapefruit.platform.terminal.TerminalOutput; 5 | import net.rubygrapefruit.platform.terminal.Terminals; 6 | 7 | import java.util.List; 8 | 9 | class InteractivePrompter extends AbstractPrompter { 10 | private final Terminals terminals; 11 | 12 | InteractivePrompter(Terminals terminals) { 13 | this.terminals = terminals; 14 | } 15 | 16 | @Override 17 | boolean isInteractive() { 18 | return true; 19 | } 20 | 21 | @Override 22 | Integer select(String prompt, List options, int defaultOption) { 23 | TerminalOutput output = terminals.getTerminal(Terminals.Output.Stdout); 24 | SelectView view = new SelectView(output, prompt, options, defaultOption); 25 | SelectionListener listener = new SelectionListener(view, options); 26 | view.render(); 27 | handleInput(listener); 28 | view.close(listener.getSelected()); 29 | return listener.getSelected(); 30 | } 31 | 32 | @Override 33 | String enterText(String prompt, String defaultValue) { 34 | TerminalOutput output = terminals.getTerminal(Terminals.Output.Stdout); 35 | TextView view = new TextView(output, prompt, defaultValue); 36 | TextEntryListener listener = new TextEntryListener(view, defaultValue); 37 | view.render(); 38 | handleInput(listener); 39 | view.close(listener.getEntered()); 40 | return listener.getEntered(); 41 | } 42 | 43 | @Override 44 | String enterPassword(String prompt) { 45 | TerminalOutput output = terminals.getTerminal(Terminals.Output.Stdout); 46 | PasswordView view = new PasswordView(output, prompt); 47 | TextEntryListener listener = new TextEntryListener(view, null); 48 | view.render(); 49 | handleInput(listener); 50 | view.close(listener.getEntered()); 51 | return listener.getEntered(); 52 | } 53 | 54 | @Override 55 | Boolean askYesNo(String prompt, boolean defaultValue) { 56 | TerminalOutput output = terminals.getTerminal(Terminals.Output.Stdout); 57 | YesNoView view = new YesNoView(output, prompt, defaultValue); 58 | YesNoListener listener = new YesNoListener(defaultValue); 59 | view.render(); 60 | handleInput(listener); 61 | view.close(listener.getSelected()); 62 | return listener.getSelected(); 63 | } 64 | 65 | private void handleInput(AbstractListener listener) { 66 | TerminalInput input = terminals.getTerminalInput(); 67 | input.rawMode(); 68 | try { 69 | while (!listener.isFinished()) { 70 | input.read(listener); 71 | } 72 | } finally { 73 | input.reset(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/NonInteractivePrompter.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | class NonInteractivePrompter extends AbstractPrompter { 4 | @Override 5 | boolean isInteractive() { 6 | return false; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/PasswordView.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | import net.rubygrapefruit.platform.terminal.TerminalOutput; 4 | 5 | class PasswordView extends TextView { 6 | PasswordView(TerminalOutput output, String prompt) { 7 | super(output, prompt, ""); 8 | } 9 | 10 | @Override 11 | protected int renderValue(CharSequence value) { 12 | for (int i = 0; i < value.length(); i++) { 13 | output.write('*'); 14 | } 15 | return value.length(); 16 | } 17 | 18 | @Override 19 | protected int renderFinalValue(CharSequence value) { 20 | output.write("[hidden]"); 21 | return 8; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/Prompter.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | import net.rubygrapefruit.platform.terminal.TerminalOutput; 4 | import net.rubygrapefruit.platform.terminal.Terminals; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Displays prompts on the terminal to ask the user various kinds of questions. 10 | */ 11 | public class Prompter { 12 | static final TerminalOutput.Color SELECTION_COLOR = TerminalOutput.Color.Cyan; 13 | private final AbstractPrompter implementation; 14 | 15 | public Prompter(Terminals terminals) { 16 | if (!terminals.isTerminalInput() || !terminals.isTerminal(Terminals.Output.Stdout)) { 17 | implementation = new NonInteractivePrompter(); 18 | } else { 19 | if (terminals.getTerminal(Terminals.Output.Stdout).supportsCursorMotion() && terminals.getTerminalInput().supportsRawMode()) { 20 | implementation = new InteractivePrompter(terminals); 21 | } else { 22 | implementation = new PlainPrompter(terminals); 23 | } 24 | } 25 | } 26 | 27 | /** 28 | * Returns {@code true} if this prompter can ask the user questions. 29 | */ 30 | public boolean isInteractive() { 31 | return implementation.isInteractive(); 32 | } 33 | 34 | /** 35 | * Asks the user to select an option from a list. 36 | * 37 | * @return The index of the selected option or {@code null} on end of input. Returns the default option when not interactive. 38 | */ 39 | public Integer select(String prompt, List options, int defaultOption) { 40 | return implementation.select(prompt, options, defaultOption); 41 | } 42 | 43 | /** 44 | * Asks the user to enter some text. 45 | * 46 | * @return The text or {@code null} on end of input. Returns the default value when not interactive. 47 | */ 48 | public String enterText(String prompt, String defaultValue) { 49 | return implementation.enterText(prompt, defaultValue); 50 | } 51 | 52 | /** 53 | * Asks the user to enter a password. 54 | * 55 | * @return The password or {@code null} on end of input or when not interactive or when not possible to prompt for a password without echoing the characters. 56 | */ 57 | public String enterPassword(String prompt) { 58 | return implementation.enterPassword(prompt); 59 | } 60 | 61 | /** 62 | * Asks the user a yes/no question. 63 | * 64 | * @return The selected value or null on end of input. Returns the default value when not interactive. 65 | */ 66 | public Boolean askYesNo(String prompt, boolean defaultValue) { 67 | return implementation.askYesNo(prompt, defaultValue); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/SelectView.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | import net.rubygrapefruit.platform.terminal.TerminalOutput; 4 | 5 | import java.util.List; 6 | 7 | class SelectView { 8 | private final TerminalOutput output; 9 | private final String prompt; 10 | private final List options; 11 | private int selected; 12 | 13 | SelectView(TerminalOutput output, String prompt, List options, int defaultOption) { 14 | this.output = output; 15 | this.prompt = prompt; 16 | this.options = options; 17 | this.selected = defaultOption; 18 | } 19 | 20 | int getSelected() { 21 | return selected; 22 | } 23 | 24 | void render() { 25 | output.newline(); 26 | output.hideCursor(); 27 | output.bold().write(prompt).write(":").normal().newline(); 28 | for (int i = 0; i < options.size(); i++) { 29 | renderItem(i); 30 | } 31 | output.dim() 32 | .write("Use the arrow keys to select an option and press enter") 33 | .normal() 34 | .cursorStartOfLine(); 35 | } 36 | 37 | private void renderItem(int i) { 38 | if (i == selected) { 39 | output.foreground(Prompter.SELECTION_COLOR); 40 | output.write("> "); 41 | } else { 42 | output.write(" "); 43 | } 44 | output.write(String.valueOf((i + 1))).write(") ").write(options.get(i)); 45 | output.defaultForeground(); 46 | output.newline(); 47 | } 48 | 49 | void selectPrevious() { 50 | if (selected == 0) { 51 | return; 52 | } 53 | selected--; 54 | int rowsToMoveUp = options.size() - selected; 55 | output.cursorUp(rowsToMoveUp); 56 | renderItem(selected); 57 | renderItem(selected + 1); 58 | output.cursorDown(rowsToMoveUp - 2); 59 | } 60 | 61 | void selectNext() { 62 | if (selected == options.size() - 1) { 63 | return; 64 | } 65 | selected++; 66 | int rowsToModeUp = options.size() - selected + 1; 67 | output.cursorUp(rowsToModeUp); 68 | renderItem(selected - 1); 69 | renderItem(selected); 70 | output.cursorDown(rowsToModeUp - 2); 71 | } 72 | 73 | void close(Integer selected) { 74 | output.clearToEndOfLine(); 75 | for (int i = 0; i < options.size(); i++) { 76 | output.cursorUp(1).clearToEndOfLine(); 77 | } 78 | output.cursorUp(1); 79 | output.write(prompt) 80 | .write(": "); 81 | if (selected != null) { 82 | output.foreground(Prompter.SELECTION_COLOR) 83 | .write(options.get(selected)) 84 | .reset(); 85 | } else { 86 | output.write(""); 87 | } 88 | output.showCursor(); 89 | output.newline(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/SelectionListener.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | import java.util.List; 4 | 5 | class SelectionListener extends AbstractListener { 6 | private final SelectView view; 7 | private final List options; 8 | private int selected; 9 | 10 | SelectionListener(SelectView view, List options) { 11 | this.view = view; 12 | this.options = options; 13 | selected = -1; 14 | } 15 | 16 | boolean isFinished() { 17 | return selected != -1; 18 | } 19 | 20 | Integer getSelected() { 21 | return selected < 0 ? null : selected; 22 | } 23 | 24 | @Override 25 | public void character(char ch) { 26 | if (Character.isDigit(ch)) { 27 | int index = ch - '0' - 1; 28 | if (index >= 0 && index < options.size()) { 29 | this.selected = index; 30 | } 31 | } 32 | } 33 | 34 | @Override 35 | public void controlKey(Key key) { 36 | if (key == Key.Enter) { 37 | selected = view.getSelected(); 38 | } else if (key == Key.UpArrow) { 39 | view.selectPrevious(); 40 | } else if (key == Key.DownArrow) { 41 | view.selectNext(); 42 | } 43 | } 44 | 45 | @Override 46 | public void endInput() { 47 | selected = -2; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/TextEntryListener.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | class TextEntryListener extends AbstractListener { 4 | private final TextView view; 5 | private final String defaultValue; 6 | private String entered; 7 | private boolean finished; 8 | 9 | TextEntryListener(TextView view, String defaultValue) { 10 | this.view = view; 11 | this.defaultValue = defaultValue; 12 | } 13 | 14 | boolean isFinished() { 15 | return finished; 16 | } 17 | 18 | String getEntered() { 19 | return entered; 20 | } 21 | 22 | @Override 23 | public void character(char ch) { 24 | view.insert(ch); 25 | } 26 | 27 | @Override 28 | public void controlKey(Key key) { 29 | if (key == Key.Enter) { 30 | if (!view.hasValue()) { 31 | entered = defaultValue; 32 | } else { 33 | entered = view.getValue(); 34 | } 35 | finished = true; 36 | } else if (key == Key.EraseBack) { 37 | view.eraseBack(); 38 | } else if (key == Key.EraseForward) { 39 | view.eraseForward(); 40 | } else if (key == Key.LeftArrow) { 41 | view.cursorLeft(); 42 | } else if (key == Key.RightArrow) { 43 | view.cursorRight(); 44 | } else if (key == Key.Home) { 45 | view.cursorStart(); 46 | } else if (key == Key.End) { 47 | view.cursorEnd(); 48 | } 49 | } 50 | 51 | @Override 52 | public void endInput() { 53 | finished = true; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/YesNoListener.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | class YesNoListener extends AbstractListener { 4 | private final boolean defaultValue; 5 | private Boolean selected; 6 | private boolean finished; 7 | 8 | YesNoListener(boolean defaultValue) { 9 | this.defaultValue = defaultValue; 10 | } 11 | 12 | public boolean isFinished() { 13 | return finished; 14 | } 15 | 16 | public Boolean getSelected() { 17 | return selected; 18 | } 19 | 20 | @Override 21 | public void character(char ch) { 22 | if (ch == 'y' || ch == 'Y') { 23 | selected = true; 24 | finished = true; 25 | } else if (ch == 'n' || ch == 'N') { 26 | selected = false; 27 | finished = true; 28 | } 29 | } 30 | 31 | @Override 32 | public void controlKey(Key key) { 33 | if (key == Key.Enter) { 34 | selected = defaultValue; 35 | finished = true; 36 | } 37 | } 38 | 39 | @Override 40 | public void endInput() { 41 | finished = true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/YesNoView.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.prompts; 2 | 3 | import net.rubygrapefruit.platform.terminal.TerminalOutput; 4 | 5 | import static net.rubygrapefruit.platform.prompts.Prompter.SELECTION_COLOR; 6 | 7 | class YesNoView { 8 | private final TerminalOutput output; 9 | private final String prompt; 10 | private final boolean defaultValue; 11 | 12 | YesNoView(TerminalOutput output, String prompt, boolean defaultValue) { 13 | this.output = output; 14 | this.prompt = prompt; 15 | this.defaultValue = defaultValue; 16 | } 17 | 18 | public void render() { 19 | output.newline(); 20 | output.hideCursor(); 21 | output.bold().write(prompt).normal().write(" [y/n]: "); 22 | output.dim().write(defaultValue ? "y" : "n").normal().cursorLeft(1); 23 | output.showCursor(); 24 | } 25 | 26 | public void close(Boolean selected) { 27 | output.cursorStartOfLine(); 28 | output.clearToEndOfLine(); 29 | output.write(prompt).write(": "); 30 | if (selected != null) { 31 | output.foreground(SELECTION_COLOR); 32 | output.write(selected ? "yes" : "no"); 33 | output.reset(); 34 | } else { 35 | output.write(""); 36 | } 37 | output.newline(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/prompts/package-info.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Utility classes to display prompts on the terminal. 4 | * 5 | *

Use the {@link net.rubygrapefruit.platform.prompts.Prompter} class to display the prompts. 6 | */ 7 | package net.rubygrapefruit.platform.prompts; -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/terminal/TerminalInput.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.terminal; 2 | 3 | import net.rubygrapefruit.platform.NativeException; 4 | import net.rubygrapefruit.platform.ThreadSafe; 5 | 6 | import java.io.InputStream; 7 | 8 | /** 9 | * Allows input to be received from the terminal. 10 | * 11 | *

On UNIX based platforms, this provides access to the terminal. On Windows platforms, this provides access to the 12 | * console. 13 | * 14 | *

To create an instance of this interface use the {@link Terminals#getTerminalInput()} method. 15 | */ 16 | @ThreadSafe 17 | public interface TerminalInput { 18 | /** 19 | * Returns an input stream that can be used to read characters from this terminal. 20 | */ 21 | InputStream getInputStream(); 22 | 23 | /** 24 | * Reads the next character or control keys from this terminal. Blocks until an event is available. 25 | * 26 | * @throws NativeException On failure. 27 | */ 28 | void read(TerminalInputListener listener) throws NativeException; 29 | 30 | /** 31 | * Returns true if this terminal supports setting raw mode. 32 | */ 33 | boolean supportsRawMode(); 34 | 35 | /** 36 | * Switches this terminal to raw mode. Keys are delivered as they are typed, are not echoed and are not processed. 37 | * 38 | * @throws NativeException On failure, or when raw mode is not supported by this terminal. 39 | */ 40 | TerminalInput rawMode() throws NativeException; 41 | 42 | /** 43 | * Resets this terminal to its default mode. 44 | * 45 | * @throws NativeException On failure. 46 | */ 47 | TerminalInput reset() throws NativeException; 48 | } 49 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/terminal/TerminalInputListener.java: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.terminal; 2 | 3 | /** 4 | * Receives terminal input. 5 | */ 6 | public interface TerminalInputListener { 7 | enum Key { 8 | // Order is significant, used by Windows native code 9 | Enter, 10 | UpArrow, 11 | DownArrow, 12 | LeftArrow, 13 | RightArrow, 14 | Home, 15 | End, 16 | EraseBack, 17 | EraseForward, 18 | BackTab, 19 | PageUp, 20 | PageDown 21 | } 22 | 23 | /** 24 | * Called when a character is typed. Note that this method is not called for the 'enter' key. 25 | */ 26 | void character(char ch); 27 | 28 | /** 29 | * Called when a control key is typed. 30 | */ 31 | void controlKey(Key key); 32 | 33 | /** 34 | * Called on the end of input. 35 | */ 36 | void endInput(); 37 | } 38 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/terminal/TerminalSize.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.terminal; 18 | 19 | import net.rubygrapefruit.platform.ThreadSafe; 20 | 21 | /** 22 | * The size of a terminal. This is a snapshot view and does not change. 23 | */ 24 | @ThreadSafe 25 | public interface TerminalSize { 26 | /** 27 | * Returns the number of character columns in the terminal. 28 | */ 29 | @ThreadSafe 30 | public int getCols(); 31 | 32 | /** 33 | * Returns the number of character rows in the terminal. 34 | */ 35 | @ThreadSafe 36 | public int getRows(); 37 | } 38 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/terminal/Terminals.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.terminal; 18 | 19 | import net.rubygrapefruit.platform.Native; 20 | import net.rubygrapefruit.platform.NativeException; 21 | import net.rubygrapefruit.platform.NativeIntegration; 22 | import net.rubygrapefruit.platform.ThreadSafe; 23 | 24 | /** 25 | * Provides access to the terminal/console. 26 | * 27 | *

On UNIX based platforms, this provides access to the terminal. On Windows platforms, this provides access to the 28 | * Windows console and Mintty. 29 | * 30 | *

To create an instance of this interface use the {@link Native#get(Class)} method. 31 | */ 32 | @ThreadSafe 33 | public interface Terminals extends NativeIntegration { 34 | /** 35 | * System outputs. 36 | */ 37 | enum Output {Stdout, Stderr} 38 | 39 | /** 40 | * Returns a copy of this terminal access that forces terminal output to use ANSI escape sequences. 41 | * This can be used to force rich terminal output when not attached to a terminal. 42 | * 43 | *

Terminal input is not changed. 44 | */ 45 | Terminals withAnsiOutput(); 46 | 47 | /** 48 | * Returns true if the given output is attached to a terminal. 49 | * 50 | * @throws NativeException On failure. 51 | */ 52 | @ThreadSafe 53 | boolean isTerminal(Output output) throws NativeException; 54 | 55 | /** 56 | * Returns true if the system input is attached to a terminal. 57 | */ 58 | @ThreadSafe 59 | boolean isTerminalInput() throws NativeException; 60 | 61 | /** 62 | * Returns the terminal attached to the given output. 63 | * 64 | * @return The terminal. Never returns null. 65 | * @throws NativeException When the output is not attached to a terminal. 66 | */ 67 | @ThreadSafe 68 | TerminalOutput getTerminal(Output output) throws NativeException; 69 | 70 | /** 71 | * Returns the terminal attached to system input 72 | * 73 | * @return The terminal. Never returns null. 74 | * @throws NativeException When the input is not attached to a terminal. 75 | */ 76 | @ThreadSafe 77 | TerminalInput getTerminalInput() throws NativeException; 78 | } 79 | -------------------------------------------------------------------------------- /native-platform/src/main/java/net/rubygrapefruit/platform/terminal/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Classes that provide access to the terminal/console. 3 | * 4 | *

To use, create an instance of {@link net.rubygrapefruit.platform.terminal.Terminals} using {@link net.rubygrapefruit.platform.Native#get(java.lang.Class)}. 5 | */ 6 | package net.rubygrapefruit.platform.terminal; -------------------------------------------------------------------------------- /native-platform/src/shared/cpp/generic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Generic cross-platform functions. 19 | */ 20 | #include "generic.h" 21 | #include "net_rubygrapefruit_platform_internal_jni_NativeLibraryFunctions.h" 22 | #include 23 | #include 24 | 25 | void mark_failed_with_message(JNIEnv* env, const char* message, jobject result) { 26 | mark_failed_with_code(env, message, 0, NULL, result); 27 | } 28 | 29 | void mark_failed_with_code(JNIEnv* env, const char* message, int error_code, const char* error_code_message, jobject result) { 30 | jclass destClass = env->GetObjectClass(result); 31 | jmethodID method = env->GetMethodID(destClass, "failed", "(Ljava/lang/String;IILjava/lang/String;)V"); 32 | jstring message_str = env->NewStringUTF(message); 33 | jstring error_code_str = error_code_message == NULL ? NULL : env->NewStringUTF(error_code_message); 34 | jint failure_code = map_error_code(error_code); 35 | env->CallVoidMethod(result, method, message_str, failure_code, error_code, error_code_str); 36 | if (error_code_str != NULL) { 37 | env->DeleteLocalRef(error_code_str); 38 | } 39 | } 40 | 41 | JNIEXPORT jstring JNICALL 42 | Java_net_rubygrapefruit_platform_internal_jni_NativeLibraryFunctions_getVersion(JNIEnv* env, jclass target) { 43 | return env->NewStringUTF(NATIVE_VERSION); 44 | } 45 | -------------------------------------------------------------------------------- /native-platform/src/shared/cpp/generic_posix.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * POSIX platform functions. 19 | */ 20 | #ifndef _WIN32 21 | 22 | #include "generic.h" 23 | #include 24 | #include 25 | #include 26 | 27 | void mark_failed_with_errno(JNIEnv* env, const char* message, jobject result) { 28 | char* buffer = (char*) malloc(1024); 29 | #if defined(__linux__) && _GNU_SOURCE 30 | // GNU semantics 31 | char* errno_message = strerror_r(errno, buffer, 1024); 32 | #else 33 | strerror_r(errno, buffer, 1024); 34 | char* errno_message = buffer; 35 | #endif 36 | mark_failed_with_code(env, message, errno, errno_message, result); 37 | free(buffer); 38 | } 39 | 40 | int map_error_code(int error_code) { 41 | if (error_code == ENOENT) { 42 | return FAILURE_NO_SUCH_FILE; 43 | } 44 | if (error_code == ENOTDIR) { 45 | return FAILURE_NOT_A_DIRECTORY; 46 | } 47 | if (error_code == EACCES) { 48 | return FAILURE_PERMISSIONS; 49 | } 50 | return FAILURE_GENERIC; 51 | } 52 | 53 | char* java_to_utf_char(JNIEnv* env, jstring string, jobject result) { 54 | size_t len = env->GetStringLength(string); 55 | size_t bytes = env->GetStringUTFLength(string); 56 | char* chars = (char*) malloc(bytes + 1); 57 | env->GetStringUTFRegion(string, 0, len, chars); 58 | chars[bytes] = 0; 59 | return chars; 60 | } 61 | 62 | jstring utf_char_to_java(JNIEnv* env, const char* chars, jobject result) { 63 | return env->NewStringUTF(chars); 64 | } 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /native-platform/src/shared/cpp/osx.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * POSIX platform functions. 19 | */ 20 | #ifdef __APPLE__ 21 | 22 | #include "generic.h" 23 | #include 24 | #include 25 | #include 26 | 27 | char* java_to_char(JNIEnv* env, jstring string, jobject result) { 28 | return java_to_utf_char(env, string, result); 29 | } 30 | 31 | jstring char_to_java(JNIEnv* env, const char* chars, jobject result) { 32 | return utf_char_to_java(env, chars, result); 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /native-platform/src/shared/cpp/unix_strings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * UNIX string conversion functions. 19 | */ 20 | #if defined(__linux__) || defined(__FreeBSD__) 21 | 22 | #include "generic.h" 23 | #include 24 | #include 25 | #include 26 | 27 | char* java_to_char(JNIEnv* env, jstring string, jobject result) { 28 | size_t stringLen = env->GetStringLength(string); 29 | wchar_t* wideString = (wchar_t*) malloc(sizeof(wchar_t) * (stringLen + 1)); 30 | const jchar* javaString = env->GetStringChars(string, NULL); 31 | for (size_t i = 0; i < stringLen; i++) { 32 | wideString[i] = javaString[i]; 33 | } 34 | wideString[stringLen] = L'\0'; 35 | env->ReleaseStringChars(string, javaString); 36 | 37 | size_t bytes = wcstombs(NULL, wideString, 0); 38 | if (bytes == (size_t) -1) { 39 | mark_failed_with_message(env, "could not convert string to current locale", result); 40 | free(wideString); 41 | return NULL; 42 | } 43 | 44 | char* chars = (char*) malloc(bytes + 1); 45 | wcstombs(chars, wideString, bytes + 1); 46 | free(wideString); 47 | 48 | return chars; 49 | } 50 | 51 | jstring char_to_java(JNIEnv* env, const char* chars, jobject result) { 52 | size_t bytes = strlen(chars); 53 | wchar_t* wideString = (wchar_t*) malloc(sizeof(wchar_t) * (bytes + 1)); 54 | if (mbstowcs(wideString, chars, bytes + 1) == (size_t) -1) { 55 | mark_failed_with_message(env, "could not convert string from current locale", result); 56 | free(wideString); 57 | return NULL; 58 | } 59 | size_t stringLen = wcslen(wideString); 60 | jchar* javaString = (jchar*) malloc(sizeof(jchar) * stringLen); 61 | for (int i = 0; i < stringLen; i++) { 62 | javaString[i] = (jchar) wideString[i]; 63 | } 64 | jstring string = env->NewString(javaString, stringLen); 65 | free(wideString); 66 | free(javaString); 67 | return string; 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /native-platform/src/shared/headers/win.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __INCLUDE_WIN_H__ 18 | #define __INCLUDE_WIN_H__ 19 | 20 | #ifdef _WIN32 21 | 22 | #include "generic.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | // 30 | // Converts a Java string to a UNICODE path, including the Long Path prefix ("\\?\") 31 | // so that the resulting path supports paths longer than MAX_PATH (260 characters) 32 | // 33 | extern wchar_t* java_to_wchar_path(JNIEnv* env, jstring string); 34 | 35 | // 36 | // Converts a UJNICODE path to a Java string, removing the Long Path prefix ("\\?\") 37 | // if present 38 | // 39 | extern jstring wchar_to_java_path(JNIEnv* env, const wchar_t* string); 40 | 41 | // 42 | // Returns 'true' if the path of the form "X:\", where 'X' is a drive letter. 43 | // 44 | extern bool is_path_absolute_local(wchar_t* path, int path_len); 45 | 46 | // 47 | // Returns 'true' if the path is of the form "\\server\share", i.e. is a UNC path. 48 | // 49 | extern bool is_path_absolute_unc(wchar_t* path, int path_len); 50 | 51 | // 52 | // Returns a UTF-16 string that is the concatenation of |prefix| and |path|. 53 | // 54 | extern wchar_t* add_prefix(wchar_t* path, int path_len, wchar_t* prefix); 55 | 56 | // 57 | // Returns a UTF-16 string that is the concatenation of |path| and |suffix|. 58 | // 59 | extern wchar_t* add_suffix(wchar_t* path, int path_len, wchar_t* suffix); 60 | 61 | #endif 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/NativePlatformSpec.groovy: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform 2 | 3 | import spock.lang.Specification 4 | 5 | class NativePlatformSpec extends Specification { 6 | private static Native nativeIntegration 7 | 8 | static protected T getIntegration(Class type) { 9 | synchronized (NativePlatformSpec) { 10 | if (nativeIntegration == null) { 11 | def tempRoot = java.nio.file.Paths.get("build/test-outputs") 12 | java.nio.file.Files.createDirectories(tempRoot) 13 | def cacheDir = java.nio.file.Files.createTempDirectory(tempRoot, "native-platform").toFile() 14 | cacheDir.mkdirs() 15 | nativeIntegration = Native.init(cacheDir) 16 | } 17 | } 18 | nativeIntegration.get(type) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/ProcessLauncherTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform 18 | 19 | class ProcessLauncherTest extends NativePlatformSpec { 20 | final ProcessLauncher launcher = getIntegration(ProcessLauncher) 21 | 22 | def "can start a child process"() { 23 | def javaHome = System.getProperty("java.home") 24 | def exe = "${javaHome}/bin/java" 25 | ProcessBuilder builder = new ProcessBuilder(exe, "-version") 26 | builder.redirectErrorStream(true) 27 | 28 | when: 29 | def process = launcher.start(builder) 30 | def stdout = new ByteArrayOutputStream() 31 | def stdoutThread = process.consumeProcessOutputStream(stdout) 32 | def result = process.waitFor() 33 | stdoutThread.join() 34 | 35 | then: 36 | result == 0 37 | stdout.toString().contains(System.getProperty('java.vm.version')) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/SystemInfoTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform 18 | 19 | class SystemInfoTest extends NativePlatformSpec { 20 | final SystemInfo systemInfo = getIntegration(SystemInfo) 21 | 22 | def "caches system info instance"() { 23 | expect: 24 | getIntegration(SystemInfo) == systemInfo 25 | } 26 | 27 | def "can query OS details"() { 28 | expect: 29 | systemInfo.kernelName 30 | systemInfo.kernelVersion 31 | systemInfo.architectureName 32 | systemInfo.architecture 33 | systemInfo.hostname 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/file/FileSystemsTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.file 18 | 19 | import net.rubygrapefruit.platform.NativePlatformSpec 20 | import net.rubygrapefruit.platform.internal.Platform 21 | import org.junit.Rule 22 | import org.junit.rules.TemporaryFolder 23 | import spock.lang.Requires 24 | 25 | import static org.junit.Assume.assumeTrue 26 | 27 | class FileSystemsTest extends NativePlatformSpec { 28 | private static final List EXPECTED_FILE_SYSTEM_TYPES = [ 29 | // APFS on macOS 30 | 'apfs', 31 | // HFS and HFS+ on macOS 32 | 'hfs', 33 | 'ext3', 34 | 'ext4', 35 | 'btrfs', 36 | 'xfs', 37 | // FreeBSD 38 | 'ufs', 39 | // NTFS on Windows 40 | 'NTFS' 41 | ] 42 | 43 | @Rule TemporaryFolder tmpDir 44 | 45 | final FileSystems fileSystems = getIntegration(FileSystems) 46 | 47 | def "caches file systems instance"() { 48 | expect: 49 | getIntegration(FileSystems) == fileSystems 50 | } 51 | 52 | def "can query filesystem details"() { 53 | when: 54 | def mountedFileSystems = fileSystems.fileSystems 55 | then: 56 | mountedFileSystems.collect() { it.mountPoint }.containsAll(File.listRoots()) 57 | mountedFileSystems.every { it.caseSensitivity != null } 58 | mountedFileSystems.any { EXPECTED_FILE_SYSTEM_TYPES.contains(it.fileSystemType) } 59 | } 60 | 61 | 62 | @Requires({ Platform.current().linux }) 63 | def "detects file systems of mount points correctly"() { 64 | def mountPoint = "/${fileSystemType}" 65 | assumeTrue("Mount point for ${fileSystemType} exists", new File(mountPoint).exists()) 66 | 67 | when: 68 | def mountedFileSystems = fileSystems.fileSystems 69 | def specialFileSystem = mountedFileSystems.find { it.mountPoint.absolutePath == mountPoint } 70 | then: 71 | specialFileSystem.fileSystemType == fileSystemType 72 | 73 | where: 74 | fileSystemType << ["xfs", "btrfs"] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/file/WindowsFilesTest.groovy: -------------------------------------------------------------------------------- 1 | package net.rubygrapefruit.platform.file 2 | 3 | import net.rubygrapefruit.platform.internal.Platform 4 | import spock.lang.IgnoreIf 5 | 6 | @IgnoreIf({ !Platform.current().windows }) 7 | class WindowsFilesTest extends FilesTest { 8 | final WindowsFiles files = getIntegration(WindowsFiles) 9 | 10 | @Override 11 | void assertIsFile(FileInfo stat, File file) { 12 | assert stat instanceof WindowsFileInfo 13 | super.assertIsFile(stat, file) 14 | } 15 | 16 | @Override 17 | void assertIsDirectory(FileInfo stat, File file) { 18 | assert stat instanceof WindowsFileInfo 19 | super.assertIsDirectory(stat, file) 20 | } 21 | 22 | @Override 23 | void assertIsSymlink(FileInfo stat, File file) { 24 | assert stat instanceof WindowsFileInfo 25 | super.assertIsSymlink(stat, file) 26 | } 27 | 28 | def "uses same instance for specialized file types"() { 29 | expect: 30 | getIntegration(WindowsFiles) == files 31 | getIntegration(Files) == files 32 | } 33 | 34 | def "can stat file using UNC path"() { 35 | def file = tmpDir.newFile() 36 | def testFile = new File('\\\\localhost\\' + file.absolutePath.charAt(0) + '$\\' + file.absolutePath.substring(2)) 37 | 38 | when: 39 | def stat = files.stat(testFile) 40 | 41 | then: 42 | stat.type == FileInfo.Type.File 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/internal/NativeTypeInfoTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.internal 18 | 19 | import net.rubygrapefruit.platform.NativePlatformSpec 20 | import spock.lang.IgnoreIf 21 | 22 | @IgnoreIf({Platform.current().windows}) 23 | class NativeTypeInfoTest extends NativePlatformSpec { 24 | def "can fetch native type info"() { 25 | expect: 26 | def typeInfo = getIntegration(MutableTypeInfo) 27 | println "int: ${typeInfo.int_bytes}" 28 | println "u_long: ${typeInfo.u_long_bytes}" 29 | println "size_t: ${typeInfo.size_t_bytes}" 30 | println "off_t: ${typeInfo.off_t_bytes}" 31 | println "uid_t: ${typeInfo.uid_t_bytes}" 32 | println "gid_t: ${typeInfo.gid_t_bytes}" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/memory/MemoryTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.memory 18 | 19 | import net.rubygrapefruit.platform.NativePlatformSpec 20 | import net.rubygrapefruit.platform.internal.Platform 21 | import spock.lang.Requires 22 | 23 | import java.lang.management.ManagementFactory 24 | 25 | @Requires({ Platform.current().macOs || Platform.current().windows }) 26 | class MemoryTest extends NativePlatformSpec { 27 | static long getJmxTotalPhysicalMemory() { 28 | ManagementFactory.operatingSystemMXBean.totalPhysicalMemorySize 29 | } 30 | 31 | static long getJmxAvailablePhysicalMemory() { 32 | ManagementFactory.operatingSystemMXBean.freePhysicalMemorySize 33 | } 34 | 35 | def "caches memory instance"() { 36 | expect: 37 | def memory = getIntegration(Memory) 38 | memory.is(getIntegration(Memory)) 39 | } 40 | 41 | def "can query system memory"() { 42 | expect: 43 | def memory = getIntegration(Memory) 44 | 45 | def memoryInfo = memory.memoryInfo 46 | memoryInfo.totalPhysicalMemory > 0 47 | memoryInfo.totalPhysicalMemory == jmxTotalPhysicalMemory 48 | memoryInfo.availablePhysicalMemory > 0 49 | memoryInfo.availablePhysicalMemory <= memoryInfo.totalPhysicalMemory 50 | } 51 | 52 | @Requires({ Platform.current().windows }) 53 | def "memory instance is the OS-specific implementation on Windows"() { 54 | expect: 55 | getIntegration(Memory) instanceof WindowsMemory 56 | } 57 | 58 | @Requires({ Platform.current().macOs }) 59 | def "memory instance is the OS-specific implementation on OSX"() { 60 | expect: 61 | getIntegration(Memory) instanceof OsxMemory 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/memory/WindowsMemoryTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.memory 18 | 19 | import net.rubygrapefruit.platform.NativePlatformSpec 20 | import net.rubygrapefruit.platform.internal.Platform 21 | import spock.lang.Requires 22 | 23 | @Requires({ Platform.current().windows }) 24 | class WindowsMemoryTest extends NativePlatformSpec { 25 | 26 | def "caches memory instance"() { 27 | expect: 28 | def memory = getIntegration(WindowsMemory) 29 | memory.is(getIntegration(WindowsMemory)) 30 | } 31 | 32 | def "can query Windows memory info"() { 33 | given: 34 | def memory = getIntegration(WindowsMemory) 35 | 36 | when: 37 | def memoryInfo = memory.memoryInfo 38 | def totalPhysicalMemory = MemoryTest.jmxTotalPhysicalMemory 39 | def availablePhysicalMemory = MemoryTest.jmxAvailablePhysicalMemory 40 | 41 | then: 42 | memoryInfo.totalPhysicalMemory > 0 43 | memoryInfo.availablePhysicalMemory > 0 44 | memoryInfo.availablePhysicalMemory <= memoryInfo.totalPhysicalMemory 45 | memoryInfo.commitTotal > 0 46 | memoryInfo.commitLimit > memoryInfo.commitTotal 47 | // Windows commitLimit must be greater than the physical memory, since it is that plus the page files 48 | memoryInfo.commitLimit >= memoryInfo.totalPhysicalMemory 49 | memoryInfo.totalPhysicalMemory == totalPhysicalMemory 50 | // These measurements should be close to each other, possibly inequal due to system memory churn 51 | Math.abs(memoryInfo.availablePhysicalMemory - availablePhysicalMemory) < 1024 * 1024 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/terminal/TerminalsTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Adam Murdoch 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.terminal 18 | 19 | import net.rubygrapefruit.platform.NativeException 20 | import net.rubygrapefruit.platform.NativePlatformSpec 21 | import net.rubygrapefruit.platform.internal.Platform 22 | import org.junit.Rule 23 | import org.junit.rules.TemporaryFolder 24 | import spock.lang.IgnoreIf 25 | 26 | class TerminalsTest extends NativePlatformSpec { 27 | @Rule TemporaryFolder tmpDir 28 | final Terminals terminals = getIntegration(Terminals) 29 | 30 | def "caches terminals instance"() { 31 | expect: 32 | getIntegration(Terminals) == terminals 33 | } 34 | 35 | def "can check if attached to terminal"() { 36 | expect: 37 | !terminals.isTerminal(Terminals.Output.Stdout) 38 | !terminals.isTerminal(Terminals.Output.Stderr) 39 | !terminals.isTerminalInput() 40 | } 41 | 42 | @IgnoreIf({Platform.current().windows}) 43 | def "cannot access posix terminal from a test"() { 44 | when: 45 | terminals.getTerminal(Terminals.Output.Stdout) 46 | 47 | then: 48 | NativeException e = thrown() 49 | e.message == 'Could not open terminal for stdout: not a terminal' 50 | } 51 | 52 | @IgnoreIf({!Platform.current().windows}) 53 | def "cannot access windows console from a test"() { 54 | when: 55 | terminals.getTerminal(Terminals.Output.Stdout) 56 | 57 | then: 58 | NativeException e = thrown() 59 | e.message == 'Could not open console for stdout: not a console' 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /native-platform/src/test/groovy/net/rubygrapefruit/platform/testfixture/JavaVersionTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.testfixture 18 | 19 | import spock.lang.Specification 20 | 21 | class JavaVersionTest extends Specification { 22 | def "parses java version"() { 23 | expect: 24 | JavaVersion.getMajorVersion("1.7.0_101") == 7 25 | JavaVersion.getMajorVersion("1.8.0_242") == 8 26 | JavaVersion.getMajorVersion("9.0.4") == 9 27 | JavaVersion.getMajorVersion("11.0.5") == 11 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /native-platform/src/testFixtures/java/net/rubygrapefruit/platform/testfixture/JniChecksEnabled.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.rubygrapefruit.platform.testfixture; 18 | 19 | /** 20 | * JUnit {@literal @}{@link org.junit.experimental.categories.Category} marker interface 21 | * for tests to run with `-Xcheck:jni` enabled. 22 | */ 23 | public interface JniChecksEnabled { 24 | } 25 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.gradle.develocity").version("3.18.1") 3 | id("io.github.gradle.gradle-enterprise-conventions-plugin").version("0.10.2") 4 | } 5 | 6 | rootProject.name = "native-platform" 7 | 8 | include("test-app") 9 | include("native-platform") 10 | 11 | enableFeaturePreview("GROOVY_COMPILATION_AVOIDANCE") 12 | -------------------------------------------------------------------------------- /test-app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id('application') 3 | id('gradlebuild.native-platform-component') 4 | } 5 | 6 | mainClassName = 'net.rubygrapefruit.platform.test.Main' 7 | applicationName = 'native-platform-test' 8 | archivesBaseName = 'native-platform-test' 9 | 10 | if (versions.useRepo) { 11 | configurations.all { 12 | resolutionStrategy.dependencySubstitution { 13 | substitute project(':native-platform') with module("net.rubygrapefruit:native-platform:${version}") 14 | } 15 | } 16 | configurations { 17 | download 18 | } 19 | dependencies { 20 | download "$group:${archivesBaseName}:${version}" 21 | } 22 | } 23 | 24 | dependencies { 25 | implementation project(':native-platform') 26 | implementation 'net.sf.jopt-simple:jopt-simple:4.2' 27 | } 28 | 29 | publishing { 30 | publications { 31 | main(MavenPublication) { 32 | artifact(distZip) 33 | } 34 | } 35 | } 36 | 37 | // Download and unpack the application to allow it to be tested 38 | task download { 39 | doLast { 40 | copy { 41 | from(configurations.download.files.collect { zipTree(it) }) 42 | into("$buildDir/download") 43 | } 44 | } 45 | } 46 | 47 | // Use System.in as input stream for the launched process to enable interactive input 48 | tasks.named("run", JavaExec) { 49 | standardInput = System.in 50 | } 51 | --------------------------------------------------------------------------------