diff --git a/flake.nix b/flake.nix index bd5f8c40..5581b195 100644 --- a/flake.nix +++ b/flake.nix @@ -34,6 +34,7 @@ ./nix/windows/flake-module.nix ./nix/linux/flake-module.nix ./nix/macos/flake-module.nix + ./nix/recorder/flake-module.nix ]; }; } diff --git a/nix/checks.nix b/nix/checks.nix index dc6c6f30..2384eba6 100644 --- a/nix/checks.nix +++ b/nix/checks.nix @@ -55,6 +55,8 @@ let "linux-nix-options-validation" "linux-schema-fresh" ]; + recorder-lint = [ "recorder-clippy" ]; + recorder-test = [ "recorder-nextest" ]; macos-lint = [ "macos-clippy" ]; macos-test = [ "macos-nextest" ]; macos-options = [ @@ -94,6 +96,8 @@ let "macos-lint" "macos-test" "macos-options" + "recorder-lint" + "recorder-test" ]; in { diff --git a/nix/common.nix b/nix/common.nix index 414c8286..2fae2bd4 100644 --- a/nix/common.nix +++ b/nix/common.nix @@ -32,8 +32,8 @@ in # nix/linux/flake-module.nix) or the macOS ones (overlays.macos) overlays.default = final: prev: - (if final.stdenv.hostPlatform.isDarwin then self.overlays.macos else self.overlays.linux) final - prev; + (if final.stdenv.hostPlatform.isDarwin then self.overlays.macos else self.overlays.linux) final prev + // self.overlays.recorder final prev; overlays.komorebi = self.overlays.default; }; @@ -88,6 +88,11 @@ in pkgs.cargo-deny pkgs.cargo-nextest pkgs.cargo-outdated + # `komorebi-recorder frames` and `selftest` extract frames with ffmpeg; it is never used for + # capture and is not bundled into the packaged binary + pkgs.ffmpeg-headless + # `just icon` renders the watermelon of the recorder + pkgs.resvg pkgs.check-jsonschema pkgs.jq pkgs.just @@ -141,6 +146,18 @@ in packages = tools; } + # the recorder's video on Linux is GStreamer's, and the libraries its window draws through are + # opened when they are needed, not linked + // pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux ( + let + runtime = import ./recorder/runtime.nix { inherit pkgs; }; + in + { + buildInputs = runtime.gstreamerPackages; + GST_PLUGIN_SYSTEM_PATH_1_0 = runtime.gstreamerPluginPath; + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath runtime.linuxRuntimeLibraries; + } + ) // pkgs.lib.optionalAttrs (crossToWindows) { # the Windows e2e guest (e2e/platforms/qemu_windows): the build # scripts and the runner find OVMF here, and the vendored core diff --git a/nix/linux/tests/vm/default.nix b/nix/linux/tests/vm/default.nix index 66d0f7a0..9bd12690 100644 --- a/nix/linux/tests/vm/default.nix +++ b/nix/linux/tests/vm/default.nix @@ -15,8 +15,8 @@ let inherit (hostPkgs) lib; - # `komorebi-recorder`, when the run is given one: its repository is private, so it is not an - # input of the flake. `KOMOREBI_RECORDER=$(nix build --print-out-paths ...)` and `--impure`. + # `komorebi-recorder`, when the run is given one, so that a suite does not build it unless asked: + # `KOMOREBI_RECORDER=$(nix build .#komorebi-recorder --print-out-paths)` and `--impure`. recorder = let path = builtins.getEnv "KOMOREBI_RECORDER"; diff --git a/nix/recorder/build.nix b/nix/recorder/build.nix index ca20deb0..0046b1e0 100644 --- a/nix/recorder/build.nix +++ b/nix/recorder/build.nix @@ -1,433 +1,137 @@ +# The crane derivations of komorebi-recorder on macOS and Linux, from the one Cargo workspace +# (nix/workspace-src.nix, platform "recorder": the recorder and the sources of the daemons it +# indexes). On Windows the recorder is built with the rest of the workspace (nix/windows/build.nix). +{ inputs, self }: +let + lib' = import ../lib.nix { inherit inputs; }; + inherit (inputs) crane; + # the recorder has a version of its own: it is released with komorebi, but is not komorebi + version = + (builtins.fromTOML (builtins.readFile ../../komorebi-recorder/Cargo.toml)).package.version; +in { - description = "komorebi-recorder: synchronized screen, log and trace capture for komorebi bug reproduction"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - flake-parts.url = "github:hercules-ci/flake-parts"; - crane.url = "github:ipetkov/crane"; - rust-overlay.url = "github:oxalica/rust-overlay"; - rust-overlay.inputs.nixpkgs.follows = "nixpkgs"; - treefmt-nix.url = "github:numtide/treefmt-nix"; - treefmt-nix.inputs.nixpkgs.follows = "nixpkgs"; - git-hooks-nix.url = "github:cachix/git-hooks.nix"; - git-hooks-nix.inputs.nixpkgs.follows = "nixpkgs"; - - # komorebi for Mac and komorebi for Windows: only their sources, which the recorder indexes so - # that `code` can map a line of a session's log to the statement that wrote it - komorebi-mac = { - url = "github:LGUG2Z/komorebi-for-mac"; - flake = false; - }; - komorebi-windows = { - url = "github:LGUG2Z/komorebi"; - flake = false; - }; - }; - - outputs = - inputs@{ - nixpkgs, - flake-parts, - crane, - rust-overlay, - ... - }: + mkRecorderPackages = + { pkgs }: let - windows = import ./nix/windows.nix; + runtime = import ./runtime.nix { inherit pkgs; }; + toolchain = pkgs.rust-bin.fromRustupToolchainFile ../../rust-toolchain.toml; + craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; - # the sources the recorder indexes for each flavor of komorebi (see komorebi-recorder/build.rs), - # which are also the trees the tests that read komorebi's source read - sourceEnv = { - KOMOREBI_MAC_SRC = "${inputs.komorebi-mac}"; - KOMOREBI_MAC_COMMIT = inputs.komorebi-mac.rev; - KOMOREBI_WINDOWS_SRC = "${inputs.komorebi-windows}"; - KOMOREBI_WINDOWS_COMMIT = inputs.komorebi-windows.rev; - }; + inherit + (import ../workspace-src.nix { + inherit pkgs craneLib; + repoRoot = ../..; + platform = "recorder"; + }) + src + ; - version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package.version; + lockFile = lib'.repoFile "Cargo.lock"; + tomlFile = lib'.repoFile "Cargo.toml"; - # what GStreamer needs on Linux: the libraries to link, and the plugins that decode (libav, - # for H.264 and HEVC) and encode (x264, in ugly) the recorded video - gstreamerPackages = - pkgs: with pkgs.gst_all_1; [ - gstreamer - gst-plugins-base - gst-plugins-good - gst-plugins-bad - gst-plugins-ugly - gst-libav - pkgs.pipewire + commonArgs = { + pname = "komorebi-recorder"; + inherit version src; + cargoExtraArgs = "--locked -p komorebi-recorder"; + # the lock and the root manifest as files of their own: a path inside the filtered source + # would put all of it into the context of every derivation, and an edit of any file + # would then change the dependencies + cargoLock = lockFile; + cargoToml = tomlFile; + cargoVendorDir = craneLib.vendorCargoDeps { cargoLock = lockFile; }; + strictDeps = true; + # the commit of the komorebi source the build script indexes: a constant, so that the + # dependencies and every check are the same derivations for every commit; only the build + # below stamps the real one (outside a git checkout the build script is told it) + KOMOREBI_COMMIT = "nix-check"; + } + // pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin { + nativeBuildInputs = [ + pkgs.darwin.cctools + # the tests that clone, and the ones that read the history of the source + pkgs.git ]; - - gstreamerPluginPath = - pkgs: pkgs.lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" (gstreamerPackages pkgs); - - # the libraries the program opens when it needs them: Wayland, for the compositor and the - # window, and what the window draws through - linuxRuntimeLibraries = pkgs: [ - pkgs.wayland - pkgs.libxkbcommon - pkgs.libGL - pkgs.vulkan-loader - pkgs.libx11 - pkgs.libxcursor - pkgs.libxi - pkgs.libxrandr - ]; - - # what the build needs of the repository: Cargo sources, and the files the crate embeds or - # its tests read - mkSource = - { pkgs, craneLib }: - pkgs.lib.cleanSourceWith { - src = ./.; - filter = - path: type: - (craneLib.filterCargoSources path type) - || (pkgs.lib.hasSuffix "/komorebi-recorder/src/guide.md" path) - || (pkgs.lib.hasInfix "/komorebi-recorder/tests/fixtures/" path) - # the installer, which `tests/packaging.rs` checks - || (pkgs.lib.hasInfix "/wix/" path) - # the icon, which `src/icon.rs` embeds and `build.rs` compiles into the Windows executables - || (pkgs.lib.hasInfix "/komorebi-recorder/assets/" path); - }; - - mkPackages = - { pkgs }: - let - toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; - craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; - src = mkSource { inherit pkgs craneLib; }; - - commonArgs = { - inherit src version; - pname = "komorebi-recorder"; - strictDeps = true; - inherit (sourceEnv) - KOMOREBI_MAC_SRC - KOMOREBI_MAC_COMMIT - KOMOREBI_WINDOWS_SRC - KOMOREBI_WINDOWS_COMMIT - ; - } - // pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin { - nativeBuildInputs = [ - pkgs.darwin.cctools - ]; - postFixup = '' - for bin in $out/bin/*; do - if [ -f "$bin" ] && [ -x "$bin" ]; then - # Get all linked libraries and fix libiconv references - otool -L "$bin" | grep -o '/nix/store/[^/]*/lib/libiconv[^ ]*' | while read -r lib; do - install_name_tool -change "$lib" /usr/lib/libiconv.dylib "$bin" - done - fi + postFixup = '' + for bin in $out/bin/*; do + if [ -f "$bin" ] && [ -x "$bin" ]; then + # Get all linked libraries and fix libiconv references + otool -L "$bin" | grep -o '/nix/store/[^/]*/lib/libiconv[^ ]*' | while read -r lib; do + install_name_tool -change "$lib" /usr/lib/libiconv.dylib "$bin" done - ''; - } - # on Linux the video is encoded and decoded by GStreamer (the OS media stack there, as - # AVFoundation is on a Mac), and found at run time through its plugin path - // pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { - nativeBuildInputs = [ - pkgs.pkg-config - pkgs.makeWrapper - # the tests that record a video to read back make it with ffmpeg - pkgs.ffmpeg-headless - ]; - buildInputs = gstreamerPackages pkgs; - postFixup = '' - for bin in $out/bin/*; do - if [ -f "$bin" ] && [ -x "$bin" ]; then - wrapProgram "$bin" \ - --prefix GST_PLUGIN_SYSTEM_PATH_1_0 : ${gstreamerPluginPath pkgs} \ - --prefix LD_LIBRARY_PATH : ${pkgs.lib.makeLibraryPath (linuxRuntimeLibraries pkgs)} - fi - done - ''; - }; - - cargoArtifacts = craneLib.buildDepsOnly commonArgs; - - individualCrateArgs = commonArgs // { - inherit cargoArtifacts; - doCheck = false; - doDoc = false; - }; - - fullBuild = craneLib.buildPackage individualCrateArgs; - - # `komorebi-recorder-gui` is the same program as `komorebi-recorder` on a Mac; on Linux - # the wrapped programs are all copied, so that the wrappers keep what they wrap - komorebi-recorder = pkgs.runCommand "komorebi-recorder" { meta = fullBuild.meta // { }; } ( - if pkgs.stdenv.hostPlatform.isLinux then - '' - mkdir -p $out/bin - cp -a ${fullBuild}/bin/. $out/bin/ - '' - else - '' - mkdir -p $out/bin - cp ${fullBuild}/bin/komorebi-recorder $out/bin/ - '' - ); - in - { - inherit - craneLib - src - individualCrateArgs - fullBuild - komorebi-recorder - ; - }; - - # komorebi-recorder for Windows, cross-compiled from this host - mkWindowsPackages = - { pkgs, windowsSdk }: - let - toolchain = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml).override { - targets = [ "x86_64-pc-windows-msvc" ]; - }; - craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; - msvcEnv = windows.mkMsvcEnv { inherit pkgs windowsSdk; }; - src = mkSource { inherit pkgs craneLib; }; - - commonArgs = { - inherit src version; - pname = "komorebi-recorder-windows"; - strictDeps = true; - cargoExtraArgs = "--locked -p komorebi-recorder"; - inherit (sourceEnv) - KOMOREBI_MAC_SRC - KOMOREBI_MAC_COMMIT - KOMOREBI_WINDOWS_SRC - KOMOREBI_WINDOWS_COMMIT - ; - - nativeBuildInputs = [ - pkgs.llvmPackages.clang-unwrapped - pkgs.llvmPackages.lld - pkgs.llvmPackages.llvm - ]; - } - // msvcEnv; - - cargoArtifacts = craneLib.buildDepsOnly commonArgs; - individualCrateArgs = commonArgs // { - inherit cargoArtifacts; - doCheck = false; - doDoc = false; - }; - - komorebi-recorder = craneLib.buildPackage individualCrateArgs; - in - { - inherit - craneLib - individualCrateArgs - msvcEnv - komorebi-recorder - ; - }; - - mkPkgs = - system: - import nixpkgs { - inherit system; - overlays = [ (import rust-overlay) ]; - }; - in - flake-parts.lib.mkFlake { inherit inputs; } { - systems = [ - "aarch64-darwin" - "x86_64-darwin" - "x86_64-linux" - ]; - - imports = [ - inputs.treefmt-nix.flakeModule - inputs.git-hooks-nix.flakeModule - ]; - - perSystem = - { config, system, ... }: - let - pkgs = mkPkgs system; - build = mkPackages { inherit pkgs; }; - windowsSdk = windows.mkWindowsSdk { - inherit pkgs; - inherit (windows) windowsSdkVersion windowsCrtVersion; - }; - windowsBuild = mkWindowsPackages { inherit pkgs windowsSdk; }; - rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; - nightlyRustfmt = pkgs.rust-bin.nightly.latest.rustfmt; - rustToolchainWithNightlyRustfmt = pkgs.symlinkJoin { - name = "rust-toolchain-with-nightly-rustfmt"; - paths = [ - nightlyRustfmt - rustToolchain - ]; - }; - in - { - treefmt = { - projectRootFile = "flake.nix"; - programs = { - deadnix.enable = true; - just.enable = true; - nixfmt.enable = true; - taplo.enable = true; - rustfmt = { - enable = true; - package = pkgs.rust-bin.nightly.latest.rustfmt; - }; - }; - }; - - checks = { - komorebi-recorder-clippy = build.craneLib.cargoClippy ( - build.individualCrateArgs - // { - cargoClippyExtraArgs = "--all-targets -- -D warnings"; - } - ); - - komorebi-recorder-fmt = build.craneLib.cargoFmt { - inherit (build) src; - pname = "komorebi-recorder"; - }; - - komorebi-recorder-toml-fmt = build.craneLib.taploFmt { - src = pkgs.lib.sources.sourceFilesBySuffices build.src [ ".toml" ]; - pname = "komorebi-recorder"; - }; - - komorebi-recorder-deny = build.craneLib.cargoDeny { - inherit (build) src; - pname = "komorebi-recorder"; - }; - - komorebi-recorder-nextest = build.craneLib.cargoNextest build.individualCrateArgs; - - # `--all-targets` so that every line of `cfg(windows)` code, tests included, is type-checked - # without a Windows machine - komorebi-recorder-windows-clippy = windowsBuild.craneLib.cargoClippy ( - windowsBuild.individualCrateArgs - // { - cargoClippyExtraArgs = "--all-targets -- -D warnings"; - } - ); - }; - - packages = { - inherit (build) komorebi-recorder; - inherit windowsSdk; - komorebi-recorder-windows = windowsBuild.komorebi-recorder; - default = build.komorebi-recorder; - }; - - apps = { - komorebi-recorder = { - type = "app"; - program = "${build.komorebi-recorder}/bin/komorebi-recorder"; - }; - default = { - type = "app"; - program = "${build.komorebi-recorder}/bin/komorebi-recorder"; - }; - }; - - devShells.default = pkgs.mkShell ( - { - name = "komorebi-recorder"; - - RUST_BACKTRACE = "full"; - - inherit (sourceEnv) - KOMOREBI_MAC_SRC - KOMOREBI_MAC_COMMIT - KOMOREBI_WINDOWS_SRC - KOMOREBI_WINDOWS_COMMIT - ; - - inputsFrom = [ build.fullBuild ]; - - packages = [ - rustToolchainWithNightlyRustfmt - - pkgs.cargo-deny - pkgs.cargo-nextest - # `komorebi-recorder frames` and `selftest` extract frames with ffmpeg; it is never - # used for capture and is not bundled into the packaged binary - pkgs.ffmpeg-headless - pkgs.jq - pkgs.just - pkgs.ripgrep - # `just icon` renders the watermelon - pkgs.resvg - ]; - } - // pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { - # the libraries that Wayland, the window and the GPU are reached through are opened - # when they are needed, not linked - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath (linuxRuntimeLibraries pkgs); - } - ); - - # For working on the Windows side from a Mac: `nix develop .#windows`, then plain - # `cargo clippy --all-targets` (the target is already `x86_64-pc-windows-msvc`). - devShells.windows = pkgs.mkShell { - name = "komorebi-recorder-windows"; - - RUST_BACKTRACE = "full"; - - inherit (windowsBuild.msvcEnv) - CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER - CC_x86_64_pc_windows_msvc - CXX_x86_64_pc_windows_msvc - AR_x86_64_pc_windows_msvc - CFLAGS_x86_64_pc_windows_msvc - CXXFLAGS_x86_64_pc_windows_msvc - CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS - CARGO_BUILD_TARGET - ; - inherit (sourceEnv) - KOMOREBI_MAC_SRC - KOMOREBI_MAC_COMMIT - KOMOREBI_WINDOWS_SRC - KOMOREBI_WINDOWS_COMMIT - ; - - packages = [ - (rustToolchain.override { targets = [ "x86_64-pc-windows-msvc" ]; }) - pkgs.llvmPackages.clang-unwrapped # provides clang-cl - pkgs.llvmPackages.lld # provides lld-link - pkgs.llvmPackages.llvm # provides llvm-lib - pkgs.cargo-deny - pkgs.just - ]; - }; - - pre-commit = { - check.enable = true; - settings.hooks.treefmt = { - enable = true; - package = config.treefmt.build.wrapper; - pass_filenames = false; - }; - }; - }; - - flake = { - overlays.default = - final: _: - let - pkgs = mkPkgs final.system; - build = mkPackages { inherit pkgs; }; - in - { - inherit (build) komorebi-recorder; - }; + fi + done + ''; + } + # on Linux the video is encoded and decoded by GStreamer (the OS media stack there, as + # AVFoundation is on a Mac), and found at run time through its plugin path + // pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { + nativeBuildInputs = [ + pkgs.pkg-config + pkgs.makeWrapper + # the tests that clone, and the ones that read the history of the source + pkgs.git + # the tests that record a video to read back make it with ffmpeg + pkgs.ffmpeg-headless + ]; + buildInputs = runtime.gstreamerPackages; + postFixup = '' + for bin in $out/bin/*; do + if [ -f "$bin" ] && [ -x "$bin" ]; then + wrapProgram "$bin" \ + --prefix GST_PLUGIN_SYSTEM_PATH_1_0 : ${runtime.gstreamerPluginPath} \ + --prefix LD_LIBRARY_PATH : ${pkgs.lib.makeLibraryPath runtime.linuxRuntimeLibraries} + fi + done + ''; }; + + # the dummy source is of the manifests alone (nix/lib.nix): the dependencies are the same + # derivations for every source file and every stub, and nothing is built at evaluation + cargoArtifacts = craneLib.buildDepsOnly ( + builtins.removeAttrs commonArgs [ "src" ] + // { + dummySrc = craneLib.mkDummySrc { + src = lib'.manifestSource pkgs.lib; + cargoLock = lockFile; + }; + } + ); + + individualCrateArgs = commonArgs // { + inherit cargoArtifacts; + doCheck = false; + doDoc = false; + }; + + fullBuild = craneLib.buildPackage ( + individualCrateArgs + // { + KOMOREBI_COMMIT = self.rev or (pkgs.lib.removeSuffix "-dirty" (self.dirtyRev or "unknown")); + } + ); + + # `komorebi-recorder-gui` is the same program as `komorebi-recorder` on a Mac; on Linux the + # wrapped programs are all copied, so that the wrappers keep what they wrap + komorebi-recorder = pkgs.runCommand "komorebi-recorder" { meta = fullBuild.meta // { }; } ( + if pkgs.stdenv.hostPlatform.isLinux then + '' + mkdir -p $out/bin + cp -a ${fullBuild}/bin/. $out/bin/ + '' + else + '' + mkdir -p $out/bin + cp ${fullBuild}/bin/komorebi-recorder $out/bin/ + '' + ); + in + { + inherit + craneLib + src + individualCrateArgs + fullBuild + komorebi-recorder + ; }; } diff --git a/nix/recorder/flake-module.nix b/nix/recorder/flake-module.nix new file mode 100644 index 00000000..3d59f5c4 --- /dev/null +++ b/nix/recorder/flake-module.nix @@ -0,0 +1,52 @@ +# komorebi-recorder: the native packages on macOS and Linux and their checks. On Windows it is built +# with the rest of the workspace (nix/windows), and its Windows checks are the `windows-*` ones. +{ + inputs, + self, + lib, + ... +}: +let + lib' = import ../lib.nix { inherit inputs; }; + recorder = import ./build.nix { inherit inputs self; }; + inherit (lib') mkPkgs; +in +{ + perSystem = + { pkgs, system, ... }: + let + build = recorder.mkRecorderPackages { inherit pkgs; }; + in + lib.optionalAttrs (builtins.elem system (lib'.macosSystems ++ lib'.linuxSystems)) { + allChecks = { + # the format, the TOML and the licenses of the recorder are checked with those of the rest of + # the workspace (`windows-fmt`, `windows-toml-fmt`, `windows-deny`) + recorder-clippy = build.craneLib.cargoClippy ( + build.individualCrateArgs + // { + cargoClippyExtraArgs = "--all-targets -- -D warnings"; + } + ); + + recorder-nextest = build.craneLib.cargoNextest (build.individualCrateArgs // { doCheck = true; }); + }; + + packages = { + inherit (build) komorebi-recorder; + komorebi-recorder-full = build.fullBuild; + }; + + apps.komorebi-recorder = { + type = "app"; + program = "${build.komorebi-recorder}/bin/komorebi-recorder"; + }; + }; + + flake.overlays.recorder = + final: _: + lib.optionalAttrs (builtins.elem final.stdenv.hostPlatform.system (lib'.macosSystems ++ lib'.linuxSystems)) { + inherit (recorder.mkRecorderPackages { pkgs = mkPkgs final.stdenv.hostPlatform.system; }) + komorebi-recorder + ; + }; +} diff --git a/nix/recorder/runtime.nix b/nix/recorder/runtime.nix new file mode 100644 index 00000000..eef8aef2 --- /dev/null +++ b/nix/recorder/runtime.nix @@ -0,0 +1,31 @@ +# What komorebi-recorder needs of the system on Linux: the packages and libraries, for its build, its +# wrapper and the dev shell. +{ pkgs }: +rec { + # what GStreamer needs: the libraries to link, and the plugins that decode (libav, for H.264 and + # HEVC) and encode (x264, in ugly) the recorded video + gstreamerPackages = with pkgs.gst_all_1; [ + gstreamer + gst-plugins-base + gst-plugins-good + gst-plugins-bad + gst-plugins-ugly + gst-libav + pkgs.pipewire + ]; + + gstreamerPluginPath = pkgs.lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" gstreamerPackages; + + # the libraries the program opens when it needs them: Wayland, for the compositor and the window, + # and what the window draws through + linuxRuntimeLibraries = [ + pkgs.wayland + pkgs.libxkbcommon + pkgs.libGL + pkgs.vulkan-loader + pkgs.libx11 + pkgs.libxcursor + pkgs.libxi + pkgs.libxrandr + ]; +} diff --git a/nix/windows/build.nix b/nix/windows/build.nix index 7e9db655..2ba7737f 100644 --- a/nix/windows/build.nix +++ b/nix/windows/build.nix @@ -277,6 +277,8 @@ let komorebi-bar = extractBinary "komorebi-bar"; komorebi-gui = extractBinary "komorebi-gui"; komorebi-shortcuts = extractBinary "komorebi-shortcuts"; + komorebi-recorder = extractBinary "komorebi-recorder"; + komorebi-recorder-gui = extractBinary "komorebi-recorder-gui"; komorebi-testwin = extractBinary "komorebi-testwin"; komorebi-e2e-agent = extractBinary "komorebi-e2e-agent"; }; diff --git a/nix/windows/flake-module.nix b/nix/windows/flake-module.nix index 8008dd50..db448e8a 100644 --- a/nix/windows/flake-module.nix +++ b/nix/windows/flake-module.nix @@ -108,7 +108,7 @@ in pwd > $out/srcroot mkdir -p $out/data find . -path ./target -prune -o -type f \ - \( -path './schemas/*' -o -path '*/tests/*' -o -path '*/fixtures/*' \) \ + \( -path './schemas/*' -o -path './wix/*' -o -path '*/tests/*' -o -path '*/fixtures/*' \) \ ! -name '*.rs' -print | cpio -pdm $out/data 2>/dev/null ''; } @@ -201,6 +201,8 @@ in windows-komorebi-bar = build.komorebi-bar; windows-komorebi-gui = build.komorebi-gui; windows-komorebi-shortcuts = build.komorebi-shortcuts; + windows-komorebi-recorder = build.komorebi-recorder; + windows-komorebi-recorder-gui = build.komorebi-recorder-gui; windows-komorebi-testwin = build.komorebi-testwin; windows-komorebi-e2e-agent = build.komorebi-e2e-agent; windows-sdk = windowsSdk; @@ -236,6 +238,10 @@ in type = "app"; program = "${build.komorebi-shortcuts}/bin/komorebi-shortcuts.exe"; }; + windows-komorebi-recorder = { + type = "app"; + program = "${build.komorebi-recorder}/bin/komorebi-recorder.exe"; + }; windows-default = { type = "app"; program = "${build.fullBuild}/bin/komorebi.exe"; diff --git a/nix/workspace-src.nix b/nix/workspace-src.nix index ed0cebdc..1ababd15 100644 --- a/nix/workspace-src.nix +++ b/nix/workspace-src.nix @@ -1,6 +1,6 @@ # The source of a build of one platform, cut from the one Cargo workspace of this repository. # -# import ./workspace-src.nix { pkgs; craneLib; repoRoot; platform = "windows" | "linux" | "macos"; } +# import ./workspace-src.nix { pkgs; craneLib; repoRoot; platform = "windows" | "linux" | "macos" | "recorder"; } # # Cargo has to load every member of the workspace (the root manifest lists the members of all three # platforms), but a build of one platform needs the sources of that platform's crates only. The result: @@ -13,6 +13,10 @@ # members the members of the platform; stubbed the others; stubbedPackages their package names (for # `cargo deny --exclude`) # +# The platform "recorder" is the source of komorebi-recorder's own builds on macOS and Linux: the recorder +# indexes the log statements of the daemons of all three platforms (komorebi-recorder/build.rs), so it +# has their sources, whole, and nothing else; the Windows build has the recorder as one of its members. +# # An edit under one platform therefore changes nothing in the derivations of the others, except where # the edit is in a crate they share or in the root manifest, lock or toolchain files. { @@ -40,7 +44,20 @@ let ]; macosOnly = [ "komorebi-macos" ]; + # the recorder and the crates whose source its build script indexes (komorebi-recorder/build.rs) + recorderMembers = [ + "komorebi-recorder" + "komorebi-windows" + "komorebi-macos" + "komorebi-linux" + "komorebi-client" + "komorebi-layouts" + "crates/komorebi-core" + "crates/komorebi-transport" + ]; + membersOf = { + recorder = recorderMembers; # everything but the other two platforms' daemons windows = builtins.filter (m: !(builtins.elem m (linuxOnly ++ macosOnly))) allMembers; linux = linuxOnly ++ linuxShared; @@ -77,7 +94,8 @@ let linux = "(src/linux(\\.rs|/.*)|tests/linux_.*)"; macos = "(src/macos(\\.rs|/.*)|tests/macos_.*)"; }; - otherMarkers = builtins.attrValues (removeAttrs markers [ platform ]); + # the recorder indexes every platform's files + otherMarkers = if platform == "recorder" then [ ] else builtins.attrValues (removeAttrs markers [ platform ]); ofOtherPlatform = rel: builtins.any ( @@ -91,11 +109,21 @@ let # the directories of the source (a file is kept only under one of them) roots = members - ++ [ - "docs" - "schemas" - ".cargo" - ] + ++ lib.optional (platform == "windows") "wix" + ++ ( + if platform == "recorder" then + [ + ".cargo" + # the installer, which a test of the recorder checks for its binaries + "wix" + ] + else + [ + "docs" + "schemas" + ".cargo" + ] + ) # the configurations that the config_parity test of komorebi-linux loads ++ lib.optional (platform == "linux") "spikes/config-parity"; underRoot = rel: builtins.any (r: rel == r || lib.hasPrefix "${r}/" rel) roots; @@ -121,7 +149,10 @@ let ) || lib.hasPrefix "docs/macos/cli/" rel || lib.hasPrefix "schemas/" rel - || lib.hasPrefix "komorebic/fixtures/" rel; + || lib.hasPrefix "komorebic/fixtures/" rel + # the icon and the guide the recorder embeds, and the installer a test of it reads + || lib.hasPrefix "komorebi-recorder/" rel + || lib.hasPrefix "wix/" rel; linux = # the script komorebi loads into KWin and the JSON the tests and the daemon read (lib.hasSuffix ".js" rel || lib.hasSuffix ".json" rel) @@ -145,6 +176,8 @@ let || lib.hasPrefix "docs/macos/" rel || lib.hasPrefix "schemas/macos/" rel || lib.hasPrefix "komorebic/fixtures/" rel; + # the guide and the icon the recorder embeds, and the installer + recorder = lib.hasPrefix "komorebi-recorder/" rel || lib.hasPrefix "wix/" rel; } .${platform};