diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6c2be083..8cc95520 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -119,3 +119,84 @@ jobs: git -C tap add "${TAP_FILE_PATH}" git -C tap commit -m "chore(formula): rift ${{ steps.pkg.outputs.version }} (universal) - sha256 ${{ steps.pkg.outputs.sha256 }}" git -C tap push origin HEAD + + update-nix: + runs-on: ubuntu-latest + needs: build-and-publish + permissions: + contents: write + outputs: + commit_sha: ${{ steps.commit.outputs.sha }} + no_commit_sha: ${{ steps.no_commit.outputs.sha }} + steps: + - name: Checkout source + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Install Nix + uses: nixbuild/nix-quick-install-action@v34 + + - name: Find universal binary release asset + id: find_asset + run: | + ASSETS=$(gh api repos/${{ github.repository }}/releases/tags/${{ github.ref_name }} --jq '.assets[].name') + BINARY=$(echo "$ASSETS" | grep -i "universal" | head -1) + if [ -z "$BINARY" ]; then + echo "No universal binary found in release assets" + exit 1 + fi + echo "binary=${BINARY}" >> "$GITHUB_OUTPUT" + echo "Found binary: ${BINARY}" + env: + GH_TOKEN: ${{ github.token }} + + - name: Download and calculate hash + id: hash + run: | + DOWNLOAD_URL="https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/${{ steps.find_asset.outputs.binary }}" + echo "Downloading from: ${DOWNLOAD_URL}" + + HASH=$(nix-prefetch-url --type sha256 --unpack "${DOWNLOAD_URL}") + echo "hash=${HASH}" >> "$GITHUB_OUTPUT" + echo "Calculated hash: ${HASH}" + + - name: Update package.nix + run: | + VERSION="${{ github.ref_name }}" + VERSION="${VERSION#v}" + BINARY="${{ steps.find_asset.outputs.binary }}" + HASH="${{ steps.hash.outputs.hash }}" + + sed -i "s|version = \"[^\"]*\"|version = \"${VERSION}\"|g" nix/package.nix + sed -i "s|url = \"https://github.com/acsandmann/rift/releases/download/v[^/]*/[^\"]*\"|url = \"https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/${BINARY}\"|g" nix/package.nix + sed -i "s|sha256 = \"[^\"]*\"|sha256 = \"${HASH}\"|g" nix/package.nix + + - name: Check for changes + id: check_changes + run: | + if git diff --quiet nix/package.nix; then + echo "has_changes=false" >> "$GITHUB_OUTPUT" + else + echo "has_changes=true" >> "$GITHUB_OUTPUT" + nix flake update + fi + + - name: Commit package updates + if: steps.check_changes.outputs.has_changes == 'true' + id: commit + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add nix/package.nix flake.lock + git commit -m "chore(nix): update rift-bin package after release ${{ github.ref_name }}" + COMMIT_SHA=$(git rev-parse HEAD) + echo "sha=${COMMIT_SHA}" >> "$GITHUB_OUTPUT" + git push origin HEAD:main + + - name: Output commit SHA (no changes case) + if: steps.check_changes.outputs.has_changes == 'false' + id: no_commit + run: | + COMMIT_SHA=$(git rev-parse HEAD) + echo "sha=${COMMIT_SHA}" >> "$GITHUB_OUTPUT" diff --git a/Cargo.lock b/Cargo.lock index 9e555bbb..346a78a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1248,7 +1248,7 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rift-wm" -version = "0.1.0" +version = "0.1.2-beta" dependencies = [ "anyhow", "ascii_tree", diff --git a/Cargo.toml b/Cargo.toml index d2192727..3bcbce19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rift-wm" -version = "0.1.0" +version = "0.2.8-beta" edition = "2024" build = "build.rs" diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..c32e35fe --- /dev/null +++ b/flake.lock @@ -0,0 +1,151 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1765145449, + "narHash": "sha256-aBVHGWWRzSpfL++LubA0CwOOQ64WNLegrYHwsVuVN7A=", + "owner": "ipetkov", + "repo": "crane", + "rev": "69f538cdce5955fcd47abfed4395dc6d5194c1c5", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "devshell": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1764011051, + "narHash": "sha256-M7SZyPZiqZUR/EiiBJnmyUbOi5oE/03tCeFrTiUZchI=", + "owner": "numtide", + "repo": "devshell", + "rev": "17ed8d9744ebe70424659b0ef74ad6d41fc87071", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1765252472, + "narHash": "sha256-byMt/uMi7DJ8tRniFopDFZMO3leSjGp6GS4zWOFT+uQ=", + "owner": "nix-community", + "repo": "fenix", + "rev": "8456b985f6652e3eef0632ee9992b439735c5544", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1763759067, + "narHash": "sha256-LlLt2Jo/gMNYAwOgdRQBrsRoOz7BPRkzvNaI/fzXi2Q=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "2cccadc7357c0ba201788ae99c4dfa90728ef5e0", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1762156382, + "narHash": "sha256-Yg7Ag7ov5+36jEFC1DaZh/12SEXo6OO3/8rqADRxiqs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7241bcbb4f099a66aafca120d37c65e8dda32717", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1761765539, + "narHash": "sha256-b0yj6kfvO8ApcSE+QmA6mUfu8IYG6/uU28OFn4PaC8M=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "719359f4562934ae99f5443f20aa06c2ffff91fc", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1765186076, + "narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "devshell": "devshell", + "fenix": "fenix", + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs_2" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1765120009, + "narHash": "sha256-nG76b87rkaDzibWbnB5bYDm6a52b78A+fpm+03pqYIw=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "5e3e9c4e61bba8a5e72134b9ffefbef8f531d008", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..eb56fbce --- /dev/null +++ b/flake.nix @@ -0,0 +1,42 @@ +{ + description = "rift - a tiling window manager for macOS that focuses on performance and usability"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + crane.url = "github:ipetkov/crane"; + flake-parts.url = "github:hercules-ci/flake-parts"; + devshell.url = "github:numtide/devshell"; + }; + + outputs = + inputs@{ + flake-parts, + devshell, + ... + }: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ + "aarch64-darwin" + "x86_64-darwin" + ]; + imports = [ + devshell.flakeModule + (import ./nix/package.nix inputs) + ./nix/module.nix + ]; + perSystem = + { ... }: + { + devshells.default = { + motd = ""; + }; + }; + } + // { + overlays.default = import ./nix/overlay.nix inputs; + }; +} diff --git a/nix/module.nix b/nix/module.nix new file mode 100644 index 00000000..82072ccf --- /dev/null +++ b/nix/module.nix @@ -0,0 +1,76 @@ +{ self, ... }: + +{ + flake.darwinModules.default = + { + config, + lib, + pkgs, + ... + }: + let + cfg = config.services.rift; + + toml = pkgs.formats.toml { }; + + configFile = + if cfg.config == null then + null + else if lib.isPath cfg.config || lib.isString cfg.config then + cfg.config + else + toml.generate "rift.toml" cfg.config; + in + { + options.services.rift = { + enable = lib.mkEnableOption "Enable rift window manager service"; + + package = lib.mkOption { + type = lib.types.package; + default = self.packages.${pkgs.system}.default; + description = "rift (not rift-cli) package to use"; + }; + + config = lib.mkOption { + type = + with lib.types; + oneOf [ + str + path + toml.type + null + ]; + description = "Configuration settings for rift. Also accepts paths (string or path type) to a config file."; + default = ../rift.default.toml; + }; + }; + + config = lib.mkIf cfg.enable { + launchd.user.agents.rift = { + command = "${cfg.package}/bin/rift${ + if configFile == null then "" else " --config " + lib.escapeShellArg configFile + }"; + + serviceConfig = { + Label = "git.acsandmann.rift"; + EnvironmentVariables = { + RUST_LOG = "error,warn,info"; + # todo improve + PATH = "/run/current-system/sw/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"; + }; + RunAtLoad = true; + KeepAlive = { + SuccessfulExit = false; + Crashed = true; + }; + # todo add _{user} to log file name + StandardOutPath = "/tmp/rift.out.log"; + StandardErrorPath = "/tmp/rift.err.log"; + ProcessType = "Interactive"; + LimitLoadToSessionType = "Aqua"; + Nice = -20; + }; + }; + }; + }; +} diff --git a/nix/overlay.nix b/nix/overlay.nix new file mode 100644 index 00000000..d0197d4b --- /dev/null +++ b/nix/overlay.nix @@ -0,0 +1,13 @@ +inputs: final: prev: +let + system = final.system; + packageModule = (import ./package.nix inputs).perSystem { + inherit (final) lib; + pkgs = final; + inherit system; + }; +in +{ + rift = packageModule.packages.rift; + rift-bin = packageModule.packages.rift-bin; +} diff --git a/nix/package.nix b/nix/package.nix new file mode 100644 index 00000000..e23cef12 --- /dev/null +++ b/nix/package.nix @@ -0,0 +1,76 @@ +{ + crane, + fenix, + ... +}: +{ + perSystem = + { + pkgs, + lib, + system, + ... + }: + let + toolchain = fenix.packages.${system}.stable.toolchain; + craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; + root = ../.; + + args = { + src = lib.fileset.toSource { + inherit root; + fileset = lib.fileset.unions [ + (craneLib.fileset.commonCargoSources root) + (lib.fileset.fileFilter (file: file.hasExt "plist") root) + ]; + }; + strictDeps = true; + doCheck = false; + + nativeBuildInputs = [ ]; + buildInputs = [ ]; + }; + + build = craneLib.buildPackage ( + args + // { + cargoArtifacts = craneLib.buildDepsOnly args; + } + ); + + rift-bin = pkgs.stdenv.mkDerivation { + pname = "rift-bin"; + version = "0.2.8"; + src = builtins.fetchTarball { + url = "https://github.com/acsandmann/rift/releases/download/v0.2.8/rift-universal-macos-0.2.8.tar.gz"; + sha256 = "1cm3nqz6bl01i337yg1l9v616w4kkcsc1m725s9hgj5zgprhybna"; + }; + phases = [ "installPhase" ]; + installPhase = '' + mkdir -p $out/bin + cp -r $src/* $out/bin + chmod +x $out/bin/* + ''; + }; + in + { + checks.rift = build; + + packages.rift = build; + packages.rift-bin = rift-bin; + packages.default = rift-bin; + + devshells.default = { + packages = [ + toolchain + ]; + commands = [ + { + help = ""; + name = "hot"; + command = "${pkgs.watchexec}/bin/watchexec -e rs -w src -w Cargo.toml -w Cargo.lock -r ${toolchain}/bin/cargo run -- $@"; + } + ]; + }; + }; +}