├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── update-flake.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── NOTICE ├── README.md ├── application └── flake.nix ├── flake.lock ├── flake.nix ├── library └── flake.nix ├── modules ├── native.nix ├── nodejs.nix └── typelevelShell.nix ├── shell.nix └── tests └── scala-native ├── build.sbt ├── project ├── build.properties └── plugins.sbt └── src └── main └── scala └── Main.scala /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: cache 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: 15 | - macos-latest 16 | - ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: "Install Nix️" 21 | uses: cachix/install-nix-action@v31 22 | 23 | - name: "Run checks" 24 | run: nix flake check 25 | 26 | - name: "Build dev shells" 27 | run: for shell in library application; do nix develop .#${shell} -c true; done 28 | -------------------------------------------------------------------------------- /.github/workflows/update-flake.yml: -------------------------------------------------------------------------------- 1 | name: update-flake 2 | on: 3 | workflow_dispatch: # allows manual triggering 4 | schedule: 5 | - cron: '45 3 * * 1' # runs weekly on Monday at 03:45 6 | 7 | jobs: 8 | lockfile: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout repository 12 | uses: actions/checkout@v4 13 | - name: Install Nix 14 | uses: cachix/install-nix-action@v31 15 | with: 16 | extra_nix_config: | 17 | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} 18 | - uses: tibdex/github-app-token@v2 19 | id: generate-token 20 | with: 21 | app_id: 207424 22 | private_key: ${{ secrets.STEWARD_PRIVATE_KEY }} 23 | - name: Update flake.lock 24 | uses: DeterminateSystems/update-flake-lock@v24 25 | with: 26 | token: ${{ steps.generate-token.outputs.token }} 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2024-05-21 2 | 3 | The `overlay` flake output is deprecated by Nix, and has been replaced by `overlays.default`. See this [example fix](https://github.com/typelevel/scalacheck-xml/pull/156/commits/d76eeb0d8ff8aa678f8d614a8618797eafeffbf7). 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | typelevel-nix 2 | Copyright 2022 Ross A. Baker 3 | Licensed under Apache License 2.0 (see LICENSE) 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # typelevel-nix 2 | 3 | In antiquity, installing [sbt] was sufficient to compile, test, and run most Scala projects. sbt would fetch all your JVM dependencies, and you didn't have other dependencies. There was a [Scala CLR] target, but it was abandoned. 4 | 5 | Years passed, and [Scala.js] was born, and we were back to crossing platforms. We suddenly needed a [Node] installation to run our tests. More libraries are supporting [Scala Native]. Static site generators outside our JVM bubble have come and gone. 6 | 7 | "Faugh," you say. "The JVM is good enough for me". Fine, but your libraries target Java 8 for broad appeal and your applications target Java 17 because it's 9 bigger, and you have to juggle multiple JVMs. 8 | 9 | Wouldn't it be nice to have one-stop shopping for your development environment again? 10 | 11 | ## `nix develop` to the rescue 12 | 13 | Enter the [Nix] package manager. We can use [nix develop] to get a full, build enviroment for modern, cross-platform Scala. 14 | 15 | For now, you'll need at least Nix 2.4 and to enable the [Nix command]. 16 | 17 | ### The baseline 18 | 19 | ```console 20 | $ java -version 21 | bash: java: command not found 22 | $ sbt -version 23 | bash: sbt: command not found 24 | $ node --version 25 | bash: node: command not found 26 | ``` 27 | 28 | All my apes gone. 29 | 30 | ### Library shell 31 | 32 | The one-liner `nix develop github:typelevel/typelevel-nix#library` gets us a full environment: 33 | 34 | ```console 35 | $ nix develop github:typelevel/typelevel-nix#library 36 | 🔨 Welcome to typelevel-lib-shell 37 | 38 | [general commands] 39 | 40 | menu - prints this menu 41 | sbt - A build tool for Scala, Java and more 42 | scala-cli - Command-line tool to interact with the Scala language 43 | 44 | [versions] 45 | 46 | Java - 8.0.292 47 | Node - 16.13.1 48 | 49 | $ sbt -version 50 | sbt version in this project: 1.6.1 51 | sbt script version: 1.6.1 52 | $ exit 53 | ``` 54 | 55 | ### Application shell 56 | 57 | Alternatively, `nix develop github:typelevel/typelevel-nix#application` gives us the same, with a more contemporary JDK: 58 | 59 | ```console 60 | $ nix develop github:typelevel/typelevel-nix#application 61 | 🔨 Welcome to typelevel-app-shell 62 | 63 | [general commands] 64 | 65 | menu - prints this menu 66 | sbt - A build tool for Scala, Java and more 67 | scala-cli - Command-line tool to interact with the Scala language 68 | 69 | [versions] 70 | 71 | Java - 17.0.1 72 | 73 | $ sbt -version 74 | sbt version in this project: 1.6.1 75 | sbt script version: 1.6.1 76 | $ exit 77 | ``` 78 | 79 | ### Embed in your project 80 | 81 | The `typelevelShell` module can be imported into your `devshell.mkShell` configuration: 82 | 83 | ```nix 84 | { 85 | inputs = { 86 | typelevel-nix.url = "github:typelevel/typelevel-nix"; 87 | nixpkgs.follows = "typelevel-nix/nixpkgs"; 88 | flake-utils.follows = "typelevel-nix/flake-utils"; 89 | }; 90 | 91 | outputs = { self, nixpkgs, flake-utils, typelevel-nix }: 92 | flake-utils.lib.eachDefaultSystem (system: 93 | let 94 | pkgs = import nixpkgs { 95 | inherit system; 96 | overlays = [ typelevel-nix.overlays.default ]; 97 | }; 98 | in 99 | { 100 | devShell = pkgs.devshell.mkShell { 101 | imports = [ typelevel-nix.typelevelShell ]; 102 | name = "my-project-shell"; 103 | typelevelShell = { 104 | jdk.package = pkgs.jdk8; 105 | sbtMicrosites = { 106 | enable = true; 107 | siteDir = ./site; 108 | }; 109 | }; 110 | }; 111 | } 112 | ); 113 | } 114 | ``` 115 | 116 | if you don't currently have a `flake.nix` you can create one quickly with the following command. 117 | 118 | ```nix 119 | # For a library (defaults to jdk8) 120 | nix flake init -t github:typelevel/typelevel-nix#library 121 | # For an application service (defaults to jdk23) 122 | nix flake init -t github:typelevel/typelevel-nix#application 123 | ``` 124 | 125 | Don't forget to tweak the `devShell.name` property and customize to taste. 126 | 127 | Extra configuration in `typelevelShell`: 128 | 129 | * `typelevelShell.jdk.package`: the JDK package to use for `sbt` and the `$JAVA_HOME` environment. Defaults to `pkgs.jdk17`. If you're writing a library, you probably want `pkgs.jdk8`. 130 | * `typelevelShell.native.enable`: provide a clang environment for scala-native. Defaults to `true` in the library shell, and `false` elsewhere. 131 | * `typelevelShell.native.libraries`: a list of split-output libraries to include (dev output) and link (lib output). Defaults to `[ pkgs.zlib ]`. 132 | * `typelevelShell.nodejs.enable`: provide NodeJS. Defaults to `true` in the library shell, and `false` elsewhere. 133 | * `typelevelShell.nodejs.package`: the package to use for NodeJS. Defaults to `pkgs.nodejs`. 134 | * `typelevelShell.sbtMicrosites.enable`: enables Jekyll support for sbt-microsites. Defaults to `false`. 135 | * `typelevelShell.sbtMicrosites.siteDir`: directory with your `Gemfile`, `Gemfile.lock`, and `gemset.nix`. Run [bundix] to create a gemset.nix, and every time you upgrade Jekyll. 136 | 137 | ## Infrequently asked questions 138 | 139 | ### Is this stable? 140 | 141 | Not yet, but flake.lock makes it reproducible. 142 | 143 | ### Can I use it with trusty old `nix-shell`? 144 | 145 | Absolutely! The `shell.nix` provides a flakes-compatible shell that works with `nix-shell`. It selects the `application` shell by default, but you can be specific about it. E.g. 146 | 147 | ``` 148 | $ nix-shell --argstr shell library 149 | ``` 150 | 151 | To use it remotely, copy the content of the `shell.nix` in your project and point `src` to this repository instead. E.g. 152 | 153 | ```nix 154 | { 155 | src = fetchTarball { 156 | url = "https://github.com/typelevel/typelevel-nix/archive/main.tar.gz"; 157 | sha256 = "0000000000000000000000000000000000000000000000000000"; # replace hash 158 | }; 159 | }; 160 | ``` 161 | 162 | ### Can I embed this in a project to share with my colleagues and collaborators? 163 | 164 | Yes. You should be able to put a `flake.nix` so you can share with your colleagues or open source collaborators, and even provide a [direnv] so your `$SHELL` and `$EDITOR` do the right thing. Examples forthcoming. 165 | 166 | ### Can I read `.java-version` from jEnv to get an appropriate JDK? 167 | 168 | ```nix 169 | typelevelShell = { 170 | jdk.package = builtins.getAttr "jdk${pkgs.lib.fileContents ./.java-version}" pkgs; 171 | } 172 | ``` 173 | 174 | [sbt]: https://www.scala-sbt.org/ 175 | [Scala CLR]: https://www.scala-lang.org/old/sites/default/files/pdfs/PreviewScalaNET.pdf 176 | [Scala.js]: https://www.scala-js.org/ 177 | [Node]: https://nodejs.org/ 178 | [Scala Native]: https://scala-native.readthedocs.io/ 179 | [Nix]: https://nixos.org/ 180 | [nix develop]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-develop.html 181 | [Nix command]: https://nixos.wiki/wiki/Nix_command 182 | [direnv]: https://direnv.net/ 183 | [Laika]: https://planet42.github.io/Laika/ 184 | [bundix]: https://github.com/nix-community/bundix 185 | -------------------------------------------------------------------------------- /application/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | typelevel-nix.url = "github:typelevel/typelevel-nix"; 4 | nixpkgs.follows = "typelevel-nix/nixpkgs"; 5 | flake-utils.follows = "typelevel-nix/flake-utils"; 6 | }; 7 | 8 | outputs = { self, nixpkgs, flake-utils, typelevel-nix }: 9 | flake-utils.lib.eachDefaultSystem (system: 10 | let 11 | pkgs = import nixpkgs { 12 | inherit system; 13 | overlays = [ typelevel-nix.overlays.default ]; 14 | }; 15 | in { 16 | devShell = pkgs.devshell.mkShell { 17 | imports = [ typelevel-nix.typelevelShell ]; 18 | name = "my-application"; 19 | typelevelShell = { 20 | jdk.package = pkgs.jdk23; 21 | native.enable = true; 22 | nodejs.enable = true; 23 | }; 24 | }; 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "devshell": { 4 | "inputs": { 5 | "nixpkgs": [ 6 | "nixpkgs" 7 | ] 8 | }, 9 | "locked": { 10 | "lastModified": 1741473158, 11 | "narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=", 12 | "owner": "numtide", 13 | "repo": "devshell", 14 | "rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0", 15 | "type": "github" 16 | }, 17 | "original": { 18 | "owner": "numtide", 19 | "repo": "devshell", 20 | "type": "github" 21 | } 22 | }, 23 | "flake-utils": { 24 | "inputs": { 25 | "systems": "systems" 26 | }, 27 | "locked": { 28 | "lastModified": 1731533236, 29 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 30 | "owner": "numtide", 31 | "repo": "flake-utils", 32 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 33 | "type": "github" 34 | }, 35 | "original": { 36 | "owner": "numtide", 37 | "repo": "flake-utils", 38 | "type": "github" 39 | } 40 | }, 41 | "nixpkgs": { 42 | "locked": { 43 | "lastModified": 1749401433, 44 | "narHash": "sha256-HXIQzULIG/MEUW2Q/Ss47oE3QrjxvpUX7gUl4Xp6lnc=", 45 | "owner": "nixos", 46 | "repo": "nixpkgs", 47 | "rev": "08fcb0dcb59df0344652b38ea6326a2d8271baff", 48 | "type": "github" 49 | }, 50 | "original": { 51 | "owner": "nixos", 52 | "ref": "nixpkgs-unstable", 53 | "repo": "nixpkgs", 54 | "type": "github" 55 | } 56 | }, 57 | "root": { 58 | "inputs": { 59 | "devshell": "devshell", 60 | "flake-utils": "flake-utils", 61 | "nixpkgs": "nixpkgs" 62 | } 63 | }, 64 | "systems": { 65 | "locked": { 66 | "lastModified": 1681028828, 67 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 68 | "owner": "nix-systems", 69 | "repo": "default", 70 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 71 | "type": "github" 72 | }, 73 | "original": { 74 | "owner": "nix-systems", 75 | "repo": "default", 76 | "type": "github" 77 | } 78 | } 79 | }, 80 | "root": "root", 81 | "version": 7 82 | } 83 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Virtual environments for Scala projects"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 | devshell = { 7 | url = "github:numtide/devshell"; 8 | inputs.nixpkgs.follows = "nixpkgs"; 9 | }; 10 | flake-utils.url = "github:numtide/flake-utils"; 11 | }; 12 | 13 | outputs = { self, nixpkgs, flake-utils, devshell, ... }: 14 | let 15 | typelevelShell = ./modules/typelevelShell.nix; 16 | 17 | systems = [ 18 | "aarch64-darwin" 19 | # TODO no scala-cli 20 | # "aarch64-linux" 21 | # TODO jdk17 refers to openjdk-headless-16 22 | # "i686-linux" 23 | "x86_64-darwin" 24 | "x86_64-linux" 25 | ]; 26 | 27 | forSystem = system: 28 | let 29 | pkgs = import nixpkgs { 30 | inherit system; 31 | overlays = [ 32 | self.overlays.default 33 | ]; 34 | }; 35 | 36 | devShells = { 37 | library = pkgs.devshell.mkShell { 38 | imports = [ typelevelShell ]; 39 | name = "typelevel-lib-shell"; 40 | typelevelShell.jdk.package = pkgs.jdk8_headless; 41 | typelevelShell.nodejs.enable = true; 42 | typelevelShell.native.enable = true; 43 | }; 44 | application = pkgs.devshell.mkShell { 45 | imports = [ typelevelShell ]; 46 | name = "typelevel-app-shell"; 47 | typelevelShell.jdk.package = pkgs.jdk17_headless; 48 | }; 49 | }; 50 | in 51 | { 52 | inherit devShells; 53 | checks = devShells; 54 | }; 55 | in 56 | { 57 | inherit typelevelShell; 58 | overlays.default = devshell.overlays.default; 59 | templates = { 60 | library = { 61 | path = ./library; 62 | description = "A simple nix flake with the oldest LTS JDK supported set as the default."; 63 | }; 64 | application = { 65 | path = ./application; 66 | description = "A simple nix flake with a more recent supported JDK set as the default."; 67 | }; 68 | }; 69 | } // flake-utils.lib.eachSystem systems forSystem; 70 | } 71 | -------------------------------------------------------------------------------- /library/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | typelevel-nix.url = "github:typelevel/typelevel-nix"; 4 | nixpkgs.follows = "typelevel-nix/nixpkgs"; 5 | flake-utils.follows = "typelevel-nix/flake-utils"; 6 | }; 7 | 8 | outputs = { self, nixpkgs, flake-utils, typelevel-nix }: 9 | flake-utils.lib.eachDefaultSystem (system: 10 | let 11 | pkgs = import nixpkgs { 12 | inherit system; 13 | overlays = [ typelevel-nix.overlays.default ]; 14 | }; 15 | in { 16 | devShell = pkgs.devshell.mkShell { 17 | imports = [ typelevel-nix.typelevelShell ]; 18 | name = "my-library"; 19 | typelevelShell = { 20 | jdk.package = pkgs.jdk8; 21 | native.enable = true; 22 | nodejs.enable = true; 23 | }; 24 | }; 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /modules/native.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.typelevelShell.native; 6 | in 7 | { 8 | options.typelevelShell.native = { 9 | enable = mkEnableOption "Provide scala-native environment"; 10 | 11 | libraries = mkOption { 12 | type = types.listOf types.package; 13 | default = [ pkgs.zlib ]; 14 | description = "A list of split-output libraries to include (dev output) and link (lib output)"; 15 | }; 16 | }; 17 | 18 | config = mkIf cfg.enable { 19 | devshell.packages = [ 20 | pkgs.clang 21 | pkgs.llvmPackages.libcxx 22 | ] ++ flatten (map (e: [ (getDev e) (getLib e) ]) cfg.libraries); 23 | 24 | env = [ 25 | { 26 | name = "LIBRARY_PATH"; 27 | prefix = "$DEVSHELL_DIR/lib"; 28 | } 29 | { 30 | name = "C_INCLUDE_PATH"; 31 | prefix = "$DEVSHELL_DIR/include"; 32 | } 33 | { 34 | name = "LLVM_BIN"; 35 | value = "${pkgs.clang}/bin"; 36 | } 37 | ]; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /modules/nodejs.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.typelevelShell.nodejs; 6 | in 7 | { 8 | options.typelevelShell.nodejs = { 9 | enable = mkEnableOption "Provide nodejs"; 10 | 11 | package = mkOption { 12 | type = types.package; 13 | default = pkgs.nodejs; 14 | description = "Package to use for nodejs"; 15 | }; 16 | }; 17 | 18 | config = mkIf cfg.enable { 19 | devshell.packages = [ 20 | cfg.package 21 | ]; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /modules/typelevelShell.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | let 5 | cfg = config.typelevelShell; 6 | defaultMinJDKVersion = minPkg: ( 7 | if (lib.versionAtLeast cfg.jdk.package.version minPkg.version) 8 | then cfg.jdk.package 9 | else minPkg 10 | ); 11 | in 12 | { 13 | imports = [ 14 | ./native.nix 15 | ./nodejs.nix 16 | ]; 17 | 18 | options.typelevelShell = { 19 | jdk = { 20 | package = mkOption { 21 | type = types.package; 22 | default = pkgs.jdk17; 23 | }; 24 | metals = { 25 | package = mkOption { 26 | type = types.package; 27 | default = defaultMinJDKVersion pkgs.jdk17; 28 | }; 29 | }; 30 | scala-cli = { 31 | package = mkOption { 32 | type = types.package; 33 | default = defaultMinJDKVersion pkgs.jdk17; 34 | }; 35 | }; 36 | }; 37 | 38 | sbtMicrosites = { 39 | enable = mkEnableOption "Add support for sbt-microsites"; 40 | siteDir = mkOption { 41 | type = types.path; 42 | description = "Path to your microsite module. Should have a Gemfile, Gemfile.lock, and gemset.nix"; 43 | }; 44 | }; 45 | }; 46 | 47 | config = 48 | let 49 | main = { 50 | commands = [ 51 | { package = pkgs.metals.override { jre = cfg.jdk.metals.package; }; } 52 | { package = pkgs.scala-cli.override { jre = cfg.jdk.scala-cli.package; }; } 53 | { package = pkgs.sbt.override { jre = cfg.jdk.package; }; } 54 | ]; 55 | 56 | devshell.motd = 57 | let 58 | esc = ""; 59 | orange = "${esc}[38;5;202m"; 60 | reset = "${esc}[0m"; 61 | bold = "${esc}[1m"; 62 | differentVersion = name: pkg: if pkg != cfg.jdk.package then " ${name} - ${pkg.version}\n" else ""; 63 | metalsJDKVersion = differentVersion "Metals Java" cfg.jdk.metals.package; 64 | scalaCLIJDKVersion = differentVersion "Scala-cli Java" cfg.jdk.scala-cli.package; 65 | in 66 | '' 67 | ${orange}🔨 Welcome to ${config.devshell.name}${reset} 68 | $(type -p menu &>/dev/null && menu) 69 | 70 | ${bold}[versions]${reset} 71 | 72 | Java - ${cfg.jdk.package.version} 73 | '' + 74 | metalsJDKVersion + scalaCLIJDKVersion + 75 | optionalString cfg.nodejs.enable " Node - ${cfg.nodejs.package.version}\n"; 76 | 77 | devshell.packages = [ 78 | cfg.jdk.package 79 | ]; 80 | 81 | env = [ 82 | { 83 | name = "JAVA_HOME"; 84 | value = "${cfg.jdk.package}"; 85 | } 86 | ]; 87 | }; 88 | 89 | microsites = let 90 | gems = pkgs.bundlerEnv { 91 | name = "sbt-microsite-env"; 92 | inherit (pkgs) ruby; 93 | gemdir = cfg.sbtMicrosites.siteDir; 94 | }; 95 | in mkIf cfg.sbtMicrosites.enable { 96 | commands = [{ 97 | name = "jekyll"; 98 | command = "${gems}/bin/jekyll $@"; 99 | help = "Runs jekyll with your sbt-microsites config"; 100 | }]; 101 | }; 102 | in 103 | mkMerge [ main microsites ]; 104 | } 105 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { shell ? "application", system ? builtins.currentSystem or "unknown-system" }: 2 | 3 | (builtins.getFlake ("git+file://" + toString ./.)).devShells.${system}.${shell} 4 | -------------------------------------------------------------------------------- /tests/scala-native/build.sbt: -------------------------------------------------------------------------------- 1 | scalaVersion := "3.1.3" 2 | 3 | enablePlugins(ScalaNativePlugin) 4 | -------------------------------------------------------------------------------- /tests/scala-native/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 1.6.2 2 | -------------------------------------------------------------------------------- /tests/scala-native/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.5") 2 | -------------------------------------------------------------------------------- /tests/scala-native/src/main/scala/Main.scala: -------------------------------------------------------------------------------- 1 | import java.util.zip._ 2 | 3 | object Main { 4 | def main(args: Array[String]): Unit = { 5 | // Encode a String into bytes 6 | val inputString = "blahblahblah" 7 | val input = inputString.getBytes("UTF-8") 8 | 9 | // Compress the bytes 10 | val output = new Array[Byte](100) 11 | val compresser = new Deflater() 12 | compresser.setInput(input) 13 | compresser.finish() 14 | val compressedDataLength = compresser.deflate(output) 15 | compresser.end() 16 | 17 | // Decompress the bytes 18 | val decompresser = new Inflater() 19 | decompresser.setInput(output, 0, compressedDataLength) 20 | val result = new Array[Byte](100) 21 | val resultLength = decompresser.inflate(result) 22 | 23 | // Decode the bytes into a String 24 | val outputString = new String(result, 0, resultLength, "UTF-8") 25 | println(outputString) 26 | } 27 | } 28 | --------------------------------------------------------------------------------