Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint_everything.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jobs:
- name: Build nix flake
run: |
cd tests/nix-flake
nix build --no-write-lock-file --dry-run
nix build --no-write-lock-file --dry-run .#podman .#docker .#fhs
yaml-lint:
name: Yaml - Lint with yamllint
runs-on: ubuntu-latest
Expand Down
4 changes: 3 additions & 1 deletion docs/advanced/nixos.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ environment variables in camelCase:
image = "docker.io/netbrain/zwift";
# The zwift game version to run
version = "1.67.0";
# Container tool to run zwift (e.g., "podman" or "docker")
# Container tool to run zwift ("podman", "docker", or "fhs" for native Wine)
containerTool = "podman";
# If true, do not pull the image (use locally cached image)
dontPull = false;
Expand Down Expand Up @@ -82,6 +82,8 @@ environment variables in camelCase:
debug = false;
# If set, run container in privileged mode ("--privileged --security-opt label=disable")
privilegedContainer = false;
# Custom Wine prefix directory (only used when containerTool = "fhs", defaults to ~/.wine-zwift)
winePrefix = "";
};
}
```
Expand Down
8 changes: 4 additions & 4 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

306 changes: 21 additions & 285 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -1,281 +1,30 @@
{
description = "Easily zwift on linux";

inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";

outputs =
{ nixpkgs, self }:
{
nixpkgs,
self,
}:
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
wrapPackage =
{
image,
tag,
dontCheck,
dontPull,
dontClean,
dryRun,
interactive,
containerTool,
containerExtraArgs,
zwiftUsername,
zwiftPassword,
zwiftWorkoutDir,
zwiftActivityDir,
zwiftLogDir,
zwiftScreenshotsDir,
zwiftOverrideGraphics,
zwiftOverrideResolution,
zwiftFg,
zwiftNoGameMode,
wineExperimentalWayland,
networking,
zwiftUid,
zwiftGid,
vgaDeviceFlag,
debug,
verbosity,
privilegedContainer,
}:
pkgs.stdenv.mkDerivation rec {
pname = "zwift";
version = "0-unstable";

src = self.packages.x86_64-linux.zwift;

nixosRun = pkgs.writeShellScript "zwift-nixos.sh" ''
${pkgs.lib.optionalString (image != "") "export IMAGE='${image}'"}
${pkgs.lib.optionalString (tag != "") "export VERSION='${tag}'"}
${pkgs.lib.optionalString (dontCheck != "") "export DONT_CHECK=${dontCheck}"}
${pkgs.lib.optionalString (dontPull != "") "export DONT_PULL=${dontPull}"}
${pkgs.lib.optionalString (dontClean != "") "export DONT_CLEAN=${dontClean}"}
${pkgs.lib.optionalString (dryRun != "") "export DRYRUN=${dryRun}"}
${pkgs.lib.optionalString (interactive != "") "export INTERACTIVE=${interactive}"}
${pkgs.lib.optionalString (containerTool != "") "export CONTAINER_TOOL='${containerTool}'"}
${pkgs.lib.optionalString (
containerExtraArgs != ""
) "export CONTAINER_EXTRA_ARGS='${containerExtraArgs}'"}
${pkgs.lib.optionalString (zwiftUsername != "") "export ZWIFT_USERNAME='${zwiftUsername}'"}
${pkgs.lib.optionalString (zwiftPassword != "") "export ZWIFT_PASSWORD='${zwiftPassword}'"}
${pkgs.lib.optionalString (zwiftWorkoutDir != "") "export ZWIFT_WORKOUT_DIR='${zwiftWorkoutDir}'"}
${pkgs.lib.optionalString (
zwiftActivityDir != ""
) "export ZWIFT_ACTIVITY_DIR='${zwiftActivityDir}'"}
${pkgs.lib.optionalString (zwiftLogDir != "") "export ZWIFT_LOG_DIR='${zwiftLogDir}'"}
${pkgs.lib.optionalString (
zwiftScreenshotsDir != ""
) "export ZWIFT_SCREENSHOTS_DIR='${zwiftScreenshotsDir}'"}
${pkgs.lib.optionalString (
zwiftOverrideGraphics != ""
) "export ZWIFT_OVERRIDE_GRAPHICS=${zwiftOverrideGraphics}"}
${pkgs.lib.optionalString (
zwiftOverrideResolution != ""
) "export ZWIFT_OVERRIDE_RESOLUTION='${zwiftOverrideResolution}'"}
${pkgs.lib.optionalString (zwiftFg != "") "export ZWIFT_FG=${zwiftFg}"}
${pkgs.lib.optionalString (zwiftNoGameMode != "") "export ZWIFT_NO_GAMEMODE=${zwiftNoGameMode}"}
${pkgs.lib.optionalString (
wineExperimentalWayland != ""
) "export WINE_EXPERIMENTAL_WAYLAND=${wineExperimentalWayland}"}
${pkgs.lib.optionalString (networking != "") "export NETWORKING='${networking}'"}
${pkgs.lib.optionalString (zwiftUid != "") "export ZWIFT_UID='${zwiftUid}'"}
${pkgs.lib.optionalString (zwiftGid != "") "export ZWIFT_GID='${zwiftGid}'"}
${pkgs.lib.optionalString (debug != "") "export DEBUG=${debug}"}
${pkgs.lib.optionalString (verbosity != "") "export VERBOSITY='${verbosity}'"}
${pkgs.lib.optionalString (vgaDeviceFlag != "") "export VGA_DEVICE_FLAG='${vgaDeviceFlag}'"}
${pkgs.lib.optionalString (
privilegedContainer != ""
) "export PRIVILEGED_CONTAINER=${privilegedContainer}"}
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};

${./src/zwift.sh}
'';
zwift-fhs = import ./nix/zwift-fhs-package.nix { inherit pkgs; };

nativeBuildInputs = [ pkgs.copyDesktopItems ];
zwift-container = import ./nix/zwift-container-package.nix { inherit pkgs; };

installPhase = ''
runHook preInstall
install -Dm755 ${nixosRun} -T $out/bin/${pname}
install -Dm644 $src/share/icons/hicolor/scalable/apps/zwift.svg \
-T $out/share/icons/hicolor/scalable/apps/zwift.svg
runHook postInstall
'';

desktopItems = [ "share/applications/Zwift.desktop" ];
};
nixosModule = import ./nix/module.nix;
in
{
nixosModules = {
zwift =
{ config, lib, ... }:
let
inherit (lib.types) str bool enum;
inherit (lib) mkEnableOption mkOption;
in
{
options.programs.zwift = {
enable = mkEnableOption "zwift on linux";

image = lib.mkOption {
type = str;
default = "";
};
version = mkOption {
type = str;
default = "";
};
dontCheck = mkOption {
type = lib.types.bool;
default = false;
};
dontPull = mkOption {
type = bool;
default = false;
};
dontClean = mkOption {
type = bool;
default = false;
};
dryRun = mkOption {
type = bool;
default = false;
};
interactive = mkOption {
type = bool;
default = false;
};
containerTool = mkOption {
type = enum [
"docker"
"podman"
];
default = "podman";
};
containerExtraArgs = mkOption {
type = str;
default = "";
};
zwiftUsername = mkOption {
type = str;
default = "";
};
zwiftPassword = mkOption {
type = str;
default = "";
};
zwiftWorkoutDir = mkOption {
type = str;
default = "";
};
zwiftActivityDir = mkOption {
type = str;
default = "";
};
zwiftLogDir = mkOption {
type = str;
default = "";
};
zwiftScreenshotsDir = mkOption {
type = str;
default = "";
};
zwiftOverrideGraphics = mkOption {
type = bool;
default = false;
};
zwiftOverrideResolution = mkOption {
type = str;
default = "";
};
zwiftFg = mkOption {
type = bool;
default = false;
};
zwiftNoGameMode = mkOption {
type = bool;
default = false;
};
wineExperimentalWayland = mkOption {
type = bool;
default = false;
};
networking = mkOption {
type = str;
default = "";
};
zwiftUid = mkOption {
type = str;
default = "";
};
zwiftGid = mkOption {
type = str;
default = "";
};
vgaDeviceFlag = mkOption {
type = str;
default = "";
};
debug = mkOption {
type = bool;
default = false;
};
verbosity = mkOption {
type = enum [
"0"
"1"
"2"
"3"
];
default = "1";
};
privilegedContainer = mkOption {
type = bool;
default = false;
};
};

config = lib.mkIf config.programs.zwift.enable {
virtualisation.podman.enable = lib.mkDefault (config.programs.zwift.containerTool == "podman");
virtualisation.docker.enable = lib.mkDefault (config.programs.zwift.containerTool == "docker");
environment = {
systemPackages = with config.programs.zwift; [
(wrapPackage {
inherit
image
containerTool
containerExtraArgs
zwiftUsername
zwiftPassword
zwiftWorkoutDir
zwiftActivityDir
zwiftLogDir
zwiftScreenshotsDir
zwiftOverrideResolution
networking
zwiftUid
zwiftGid
vgaDeviceFlag
verbosity
;
tag = version;
dontCheck = if dontCheck then "1" else "";
dontPull = if dontPull then "1" else "";
dontClean = if dontClean then "1" else "";
dryRun = if dryRun then "1" else "";
interactive = if interactive then "1" else "";
zwiftOverrideGraphics = if zwiftOverrideGraphics then "1" else "";
zwiftFg = if zwiftFg then "1" else "";
zwiftNoGameMode = if zwiftNoGameMode then "1" else "";
wineExperimentalWayland = if wineExperimentalWayland then "1" else "";
debug = if debug then "1" else "";
privilegedContainer = if privilegedContainer then "1" else "";
})
];
};
};
};
default = self.nixosModules.zwift;
zwift = nixosModule;
default = nixosModule;
};

devShells.x86_64-linux.default = pkgs.mkShell {
devShells.${system}.default = pkgs.mkShell {
packages = with pkgs; [
# Bash
shellcheck
Expand All @@ -289,8 +38,8 @@
hadolint

# Markdown
nodePackages.markdownlint-cli2
nodePackages.cspell
markdownlint-cli2
cspell

# Documentation (Jekyll)
ruby
Expand All @@ -312,25 +61,12 @@
];
};

packages.x86_64-linux = {
zwift = pkgs.stdenv.mkDerivation rec {
pname = "zwift-unwrapped";
version = "0-unstable";

src = ./.;

nativeBuildInputs = [ pkgs.copyDesktopItems ];

installPhase = ''
runHook preInstall
install -Dm755 $src/src/zwift.sh -T $out/bin/${pname}
install -Dm644 $src/bin/Zwift.svg -T $out/share/icons/hicolor/scalable/apps/zwift.svg
runHook postInstall
'';

desktopItems = [ "bin/Zwift.desktop" ];
};
default = self.packages.x86_64-linux.zwift;
packages.${system} = {
inherit
zwift-fhs
zwift-container
;
default = zwift-container;
};
};
}
Loading