diff options
66 files changed, 2461 insertions, 463 deletions
diff --git a/machines/aszlig/dnyarri.nix b/machines/aszlig/dnyarri.nix index 7e42f607..482395ee 100644 --- a/machines/aszlig/dnyarri.nix +++ b/machines/aszlig/dnyarri.nix @@ -63,7 +63,7 @@ in { # This is very ugly and I really want to avoid non-free packages on all # of my workstations. But right now I need to get rid of useless paper. nixpkgs.config.allowUnfreePredicate = pkg: let - inherit (builtins.parseDrvName pkg.name) name; + inherit (builtins.parseDrvName (pkg.name or "")) name; in name == "hplip"; nixpkgs.overlays = lib.singleton (lib.const (super: { hplip = super.hplip.override { withPlugin = true; }; diff --git a/machines/aszlig/managed/brawndo.nix b/machines/aszlig/managed/brawndo.nix index 0275a4e5..d08b7a3d 100644 --- a/machines/aszlig/managed/brawndo.nix +++ b/machines/aszlig/managed/brawndo.nix @@ -44,10 +44,7 @@ in { services = { deluge.enable = true; - printing.drivers = [ pkgs.cups-bjnp ]; - - xserver.synaptics.enable = true; - xserver.synaptics.twoFingerScroll = true; + printing.drivers = [ pkgs.cups-bjnp pkgs.cnijfilter2 ]; }; swapDevices = lib.singleton { label = "swap"; }; diff --git a/machines/aszlig/managed/shakti.nix b/machines/aszlig/managed/shakti.nix index 9e7856b8..449bbe3c 100644 --- a/machines/aszlig/managed/shakti.nix +++ b/machines/aszlig/managed/shakti.nix @@ -65,7 +65,6 @@ nix.maxJobs = 4; services.xserver.xkbOptions = "eurosign:e,caps:none"; - services.xserver.libinput.enable = true; services.deluge.enable = true; diff --git a/machines/aszlig/managed/tyree.nix b/machines/aszlig/managed/tyree.nix index 151a53ef..3768f11c 100644 --- a/machines/aszlig/managed/tyree.nix +++ b/machines/aszlig/managed/tyree.nix @@ -62,7 +62,6 @@ services.xserver.xkbOptions = "eurosign:e,caps:none"; services.xserver.wacom.enable = true; - services.xserver.libinput.enable = true; vuizvui.user.aszlig.profiles.managed.enable = true; vuizvui.user.aszlig.profiles.managed.mainUser = "bla"; diff --git a/machines/default.nix b/machines/default.nix index 1f33708f..236d2a5d 100644 --- a/machines/default.nix +++ b/machines/default.nix @@ -12,9 +12,10 @@ with import ../lib; }; }; devhell = { - eris = callMachine devhell/eris.nix {}; - skunkworks = callMachine devhell/skunkworks.nix {}; - titan = callMachine devhell/titan.nix {}; + eir = callMachine devhell/eir.nix {}; + sigrun = callMachine devhell/sigrun.nix {}; + hildr = callMachine devhell/hildr.nix {}; + gunnr = callMachine devhell/gunnr.nix {}; }; openlab = { hannswurscht = callMachine ./openlab/hannswurscht.nix {}; diff --git a/machines/devhell/eris.nix b/machines/devhell/eir.nix index e878e6e6..a76be6e5 100644 --- a/machines/devhell/eris.nix +++ b/machines/devhell/eir.nix @@ -27,6 +27,7 @@ }; hardware = { + cpu.intel.updateMicrocode = true; opengl = { enable = true; extraPackages = [ pkgs.libvdpau-va-gl pkgs.vaapiVdpau pkgs.vaapiIntel ]; @@ -54,11 +55,11 @@ # FIXME Check if this is still necessary in the future systemd.services.systemd-networkd-wait-online.enable = false; - # XXX Ensure that these are added in addition to the DHCP proviced DNS servers - systemd.network.networks."99-main".dns = [ "1.1.1.1" "8.8.8.8" ]; + # XXX Ensure that these are added in addition to the DHCP provided DNS servers + systemd.network.networks."99-main".dns = [ "1.1.1.1" "1.0.0.1" ]; networking = { - hostName = "eris"; + hostName = "eir"; wireless.iwd.enable = true; useNetworkd = true; }; @@ -73,7 +74,7 @@ }; i18n = { - consoleFont = "lat9w-16"; + consoleFont = "Lat2-Terminus16"; consoleKeyMap = "uk"; defaultLocale = "en_GB.UTF-8"; }; @@ -83,12 +84,23 @@ vuizvui.user.devhell.profiles.services.enable = true; services = { + thermald.enable = true; tftpd.enable = false; gnome3.gnome-keyring.enable = true; printing = { enable = true; drivers = [ pkgs.foo2zjs pkgs.hplip pkgs.cups-brother-hl1110 ]; }; + offlineimap = { + enable = true; + install = true; + path = [ pkgs.notmuch ]; + }; + syncthing = { + enable = true; + user = "dev"; + dataDir = "/home/dev/syncthing/"; + }; }; services.udev = { @@ -110,17 +122,10 @@ ''; }; - services.compton = { - enable = true; - extraOptions = '' - inactive-dim = 0.2; - ''; - }; - services.xserver = { enable = true; layout = "gb"; - videoDrivers = [ "intel" ]; + videoDrivers = [ "modesetting" ]; libinput = { enable = true; @@ -137,10 +142,6 @@ # duplicated in the other machine configurations. displayManager.sessionCommands = '' ${pkgs.nitrogen}/bin/nitrogen --restore & - #${pkgs.xorg.xsetroot}/bin/xsetroot -solid black - #${pkgs.networkmanagerapplet}/bin/nm-applet & - #${pkgs.pasystray}/bin/pasystray & - #${pkgs.compton}/bin/compton -f & ${pkgs.rofi}/bin/rofi & ${pkgs.xorg.xrdb}/bin/xrdb "${pkgs.writeText "xrdb.conf" '' Xft.dpi: 96 @@ -224,6 +225,8 @@ nixpkgs.config.mpv.vaapiSupport = true; + programs.light.enable = true; + environment.systemPackages = with pkgs; [ aircrackng cdrtools @@ -245,6 +248,5 @@ vdpauinfo wavemon xbindkeys - xorg.xbacklight ]; } diff --git a/machines/devhell/gunnr.nix b/machines/devhell/gunnr.nix new file mode 100644 index 00000000..25016054 --- /dev/null +++ b/machines/devhell/gunnr.nix @@ -0,0 +1,158 @@ +{ config, pkgs, lib, ... }: + +{ + vuizvui.user.devhell.profiles.base.enable = true; + vuizvui.system.kernel.bfq.enable = true; + + boot = { + loader = { + grub = { + enable = true; + version = 2; + copyKernels = true; + devices = [ "/dev/sda" "/dev/sdb" ]; + }; + }; + + zfs = { + enableUnstable = true; + requestEncryptionCredentials = true; + }; + + initrd = { + availableKernelModules = [ "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; + kernelModules = [ "fuse" ]; + }; + + kernelParams = [ ]; + kernelModules = [ "kvm-amd" ]; + extraModulePackages = [ ]; + blacklistedKernelModules = [ ]; + }; + + hardware = { + cpu.amd.updateMicrocode = true; + opengl = { + enable = true; + extraPackages = [ pkgs.libvdpau-va-gl pkgs.vaapiVdpau ]; + }; + }; + + fileSystems."/" = { + device = "zpool/root/nixos"; + fsType = "zfs"; + }; + + fileSystems."/home" = { + device = "zpool/home"; + fsType = "zfs"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-label/boot"; + fsType = "ext4"; + }; + + zramSwap.enable = true; + + # FIXME Check if this is still necessary in the future + systemd.services.systemd-networkd-wait-online.enable = false; + + networking = { + hostName = "gunnr"; + hostId = "29e6affc"; + wireless.enable = false; + useNetworkd = true; + proxy = { + default = "http://wproxy.canterbury.ac.uk:3128/"; + noProxy = "127.0.0.1,localhost"; + }; + }; + + nix = { + maxJobs = lib.mkDefault 16; + extraOptions = '' + auto-optimise-store = true + ''; + }; + + i18n = { + consoleFont = "Lat2-Terminus16"; + consoleKeyMap = "dvorak"; + defaultLocale = "en_GB.UTF-8"; + }; + + #### Machine-specific service configuration #### + + vuizvui.user.devhell.profiles.services.enable = true; + + services.zfs.autoScrub.enable = true; + + services.xserver = { + enable = true; + layout = "dvorak"; + videoDrivers = [ "modesetting" ]; + + # XXX: Factor out and make DRY, because a lot of the stuff here is + # duplicated in the other machine configurations. + displayManager.sessionCommands = '' + ${pkgs.xbindkeys}/bin/xbindkeys & + ${pkgs.nitrogen}/bin/nitrogen --restore & + ${pkgs.xscreensaver}/bin/xscreensaver -no-splash & + ${pkgs.rofi}/bin/rofi & + ${pkgs.xorg.xrdb}/bin/xrdb "${pkgs.writeText "xrdb.conf" '' + Xft.dpi: 96 + Xft.antialias: true + Xft.hinting: full + Xft.hintstyle: hintslight + Xft.rgba: rgb + Xft.lcdfilter: lcddefault + Xft.autohint: 1 + Xcursor.theme: Vanilla-DMZ-AA + Xcursor.size: 22 + *.charClass:33:48,35:48,37:48,43:48,45-47:48,61:48,63:48,64:48,95:48,126:48,35:48,58:48 + *background: #121212 + *foreground: #babdb6 + ${lib.concatMapStrings (xterm: '' + ${xterm}.termName: xterm-256color + ${xterm}*bellIsUrgent: true + ${xterm}*utf8: 1 + ${xterm}*locale: true + ${xterm}*utf8Title: true + ${xterm}*utf8Fonts: 1 + ${xterm}*utf8Latin1: true + ${xterm}*dynamicColors: true + ${xterm}*eightBitInput: true + ${xterm}*faceName: xft:DejaVu Sans Mono for Powerline:pixelsize=9:antialias=true:hinting=true + ${xterm}*faceNameDoublesize: xft:Unifont:pixelsize=12:antialias=true:hinting=true + ${xterm}*cursorColor: #545f65 + '') [ "UXTerm" "XTerm" ]} + ''}" + ''; + }; + + services.timesyncd = { + servers = [ "ntp.canterbury.ac.uk" ]; + }; + + #### Machine-specific packages configuration #### + + vuizvui.user.devhell.profiles.packages.enable = true; + + nixpkgs.config.mpv.vaapiSupport = true; + nixpkgs.config.mpv.bs2bSupport = true; + + environment.systemPackages = with pkgs; [ + cdrtools + docker + dvdplusrwtools + glxinfo + ipmitool + libva + libvdpau-va-gl + pamixer + vaapiVdpau + vdpauinfo + xbindkeys + ]; +} diff --git a/machines/devhell/titan.nix b/machines/devhell/hildr.nix index 11b7dd30..9230ca7b 100644 --- a/machines/devhell/titan.nix +++ b/machines/devhell/hildr.nix @@ -24,6 +24,7 @@ }; hardware = { + cpu.intel.updateMicrocode = true; opengl = { enable = true; extraPackages = [ pkgs.libvdpau-va-gl pkgs.vaapiVdpau pkgs.vaapiIntel ]; @@ -53,11 +54,11 @@ # FIXME Check if this is still necessary in the future systemd.services.systemd-networkd-wait-online.enable = false; - # XXX Ensure that these are added in addition to the DHCP proviced DNS servers - systemd.network.networks."99-main".dns = [ "1.1.1.1" "8.8.8.8" ]; + # XXX Ensure that these are added in addition to the DHCP provided DNS servers + systemd.network.networks."99-main".dns = [ "1.1.1.1" "1.0.0.1" ]; networking = { - hostName = "titan"; + hostName = "hildr"; wireless.enable = true; useNetworkd = true; }; @@ -67,7 +68,7 @@ cpuFreqGovernor = "powersave"; }; - virtualisation.docker.enable = true; +# virtualisation.docker.enable = true; nix = { maxJobs = lib.mkDefault 4; @@ -87,12 +88,23 @@ vuizvui.user.devhell.profiles.services.enable = true; services = { + thermald.enable = true; tftpd.enable = false; gnome3.gnome-keyring.enable = true; printing = { enable = true; drivers = [ pkgs.foo2zjs pkgs.cups-brother-hl1110 ]; }; + offlineimap = { + enable = true; + install = true; + path = [ pkgs.notmuch ]; + }; + syncthing = { + enable = true; + user = "dev"; + dataDir = "/home/dev/syncthing/"; + }; }; services.acpid = { @@ -108,17 +120,10 @@ ''; }; - services.compton = { - enable = true; - extraOptions = '' - inactive-dim = 0.2; - ''; - }; - services.xserver = { enable = true; layout = "gb"; - videoDrivers = [ "intel" ]; + videoDrivers = [ "modesetting" ]; libinput = { enable = true; @@ -136,11 +141,7 @@ displayManager.sessionCommands = '' ${pkgs.xbindkeys}/bin/xbindkeys & ${pkgs.nitrogen}/bin/nitrogen --restore & - #${pkgs.networkmanagerapplet}/bin/nm-applet & - #${pkgs.connmanui}/bin/connman-ui-gtk & ${pkgs.xscreensaver}/bin/xscreensaver -no-splash & - #${pkgs.pasystray}/bin/pasystray & - #${pkgs.compton}/bin/compton -f -c & ${pkgs.rofi}/bin/rofi & ${pkgs.xorg.xrdb}/bin/xrdb "${pkgs.writeText "xrdb.conf" '' Xft.dpi: 96 @@ -179,6 +180,8 @@ nixpkgs.config.mpv.vaapiSupport = true; + programs.light.enable = true; + environment.systemPackages = with pkgs; [ aircrackng cdrtools @@ -202,6 +205,5 @@ vdpauinfo wavemon xbindkeys - xorg.xbacklight ]; } diff --git a/machines/devhell/skunkworks.nix b/machines/devhell/sigrun.nix index dc8d6265..4fba2ffe 100644 --- a/machines/devhell/skunkworks.nix +++ b/machines/devhell/sigrun.nix @@ -28,6 +28,7 @@ }; hardware = { + cpu.intel.updateMicrocode = true; opengl = { extraPackages = [ pkgs.vaapiVdpau ]; }; @@ -63,14 +64,14 @@ { device = "/dev/disk/by-uuid/3f1835a8-5587-4963-9b6c-66ecb36059de"; } ]; - networking.hostName = "skunkworks"; + networking.hostName = "sigrun"; networking.wireless.enable = false; networking.useNetworkd = true; nix.maxJobs = 8; i18n = { - consoleFont = "lat9w-16"; + consoleFont = "Lat2-Terminus16"; consoleKeyMap = "dvorak"; defaultLocale = "en_US.UTF-8"; }; @@ -91,9 +92,20 @@ enable = true; drivers = [ pkgs.hplipWithPlugin ]; }; + thermald.enable = true; timesyncd.enable = true; resolved.enable = true; canto-daemon.enable = true; + offlineimap = { + enable = true; + install = true; + path = [ pkgs.notmuch ]; + }; + syncthing = { + enable = true; + user = "dev"; + dataDir = "/home/dev/syncthing/"; + }; }; services.xserver = { @@ -262,6 +274,5 @@ hplip nzbget slrn - twister ]; } diff --git a/machines/profpatsch/base-workstation.nix b/machines/profpatsch/base-workstation.nix index ad7d6140..82dee85d 100644 --- a/machines/profpatsch/base-workstation.nix +++ b/machines/profpatsch/base-workstation.nix @@ -1,4 +1,4 @@ -# A base configuration that still assumes a workstation +# A base configuration for Thinkpads. { pkgs, lib, ... }: let myPkgs = import ./pkgs.nix { inherit pkgs lib myLib; }; @@ -14,6 +14,9 @@ in { config = { + ########### + # Hardware + boot.loader = { grub.enable = true; grub.version = 2; @@ -34,13 +37,76 @@ in { i18n = { consoleFont = "lat9w-16"; consoleKeyMap = "neo"; - # TODO: kinda broken? - # inputMethod = { - # enabled = "fcitx"; - # fcitx.engines = with pkgs.fcitx-engines; [ mozc ]; - # }; }; + # Enables drivers, acpi, power management + vuizvui.hardware.thinkpad.enable = true; + + ################### + # Graphical System + + services.xserver = { + + enable = true; + layout = "de"; + xkbVariant = "neo"; + xkbOptions = "altwin:swap_alt_win"; + serverFlagsSection = '' + Option "StandbyTime" "10" + Option "SuspendTime" "20" + Option "OffTime" "30" + ''; + + # otherwise xterm is enabled, creating an xterm that spawns the window manager. + desktopManager.xterm.enable = false; + + windowManager.xmonad = { + enable = true; + enableContribAndExtras = true; + }; + + displayManager = { + sessionCommands = with pkgs; '' + #TODO add as nixpkg + export PATH+=":$HOME/scripts" #add utility scripts + export EDITOR=emacsclient + export TERMINAL=${lilyterm-git}/bin/lilyterm + + ${xorg.xset}/bin/xset r rate 250 35 + + set-background & + # TODO xbindkeys user service file + ${lib.getBin xbindkeys}/bin/xbindkeys + # synchronize clipboards + ${lib.getBin autocutsel}/bin/autocutsel -s PRIMARY & + ''; + }; + + synaptics = { + enable = true; + minSpeed = "0.6"; + maxSpeed = "1.5"; + accelFactor = "0.015"; + twoFingerScroll = true; + vertEdgeScroll = false; + }; + + }; + + fonts.fontconfig = { + enable = true; + defaultFonts = { + monospace = [ "Source Code Pro" "DejaVu Sans Mono" ]; # TODO does not work + sansSerif = [ "Liberation Sans" ]; + }; + ultimate = { + enable = true; + substitutions = "combi"; + preset = "ultimate4"; + }; + }; + + programs.ssh.startAgent = false; ########### @@ -53,6 +119,7 @@ in { # of utmost necessity for me to function basePkgs = [ silver-searcher # file content searcher, > ack > grep + lr # list recursively, ls & find replacement dos2unix # text file conversion manpages # system manpages (not included by default) mkpasswd # UNIX password creator @@ -62,7 +129,12 @@ in { traceroute # trace ip routes wirelesstools # iwlist (wifi scan) ]; - in basePkgs; + # minimal set of gui applications + guiPkgs = [ + lilyterm-git # terminal emulator, best one around + dmenu # minimal launcher + ]; + in basePkgs ++ guiPkgs; # friendly user shell programs.fish.enable = true; @@ -77,15 +149,7 @@ in { # bounded journal size services.journald.extraConfig = "SystemMaxUse=50M"; - services.xserver = { - # otherwise xterm is enabled, creating an xterm that spawns the window manager. - desktopManager.xterm.enable = false; - - windowManager.xmonad = { - enable = true; - enableContribAndExtras = true; - }; - }; + vuizvui.programs.fish.fasd.enable = true; ######## # Users diff --git a/machines/profpatsch/base.nix b/machines/profpatsch/base.nix index a44f36d6..e91a7b12 100644 --- a/machines/profpatsch/base.nix +++ b/machines/profpatsch/base.nix @@ -42,6 +42,8 @@ in tmux # detachable terminal multiplexer wget # the other URL file fetcher myPkgs.vim # slight improvement over vi + lr # list recursively, ls & find replacement + xe # xargs with a modern interface ]; i18n = { diff --git a/machines/profpatsch/haku.nix b/machines/profpatsch/haku.nix index 8b81378b..866fc05b 100644 --- a/machines/profpatsch/haku.nix +++ b/machines/profpatsch/haku.nix @@ -5,6 +5,18 @@ let myPkgs = import ./pkgs.nix { inherit pkgs lib myLib; }; warpspeedPort = 1338; + ethernetInterface = "enp0s20"; + wireguard = { + port = 6889; + interface = "wg0"; + internalNetwork = + let genIp = cidr: lastByte: "10.42.0.${toString lastByte}/${toString cidr}"; + in { + addr = genIp 32; + range = genIp 24 0; + server = genIp 24 1; + }; + }; myKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNMQvmOfon956Z0ZVdp186YhPHtSBrXsBwaCt0JAbkf/U/P+4fG0OROA++fHDiFM4RrRHH6plsGY3W6L26mSsCM2LtlHJINFZtVILkI26MDEIKWEsfBatDW+XNAvkfYEahy16P5CBtTVNKEGsTcPD+VDistHseFNKiVlSLDCvJ0vMwOykHhq+rdJmjJ8tkUWC2bNqTIH26bU0UbhMAtJstWqaTUGnB0WVutKmkZbnylLMICAvnFoZLoMPmbvx8efgLYY2vD1pRd8Uwnq9MFV1EPbkJoinTf1XSo8VUo7WCjL79aYSIvHmXG+5qKB9ed2GWbBLolAoXkZ00E4WsVp9H philip@nyx"; @@ -69,6 +81,7 @@ in "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUgS0VB5XayQobQfOi0tYeqpSSCXzftTKEyII4OYDhuF0/CdXSqOIvdqnWQ8933lPZ5234qCXCniIlRJpJQLBPJdJ7/XnC6W37asuft6yVYxTZnZat8edCuJETMvwZJZNttxHC04k3JPf9RMj25luICWabICH5XP9Mz3GoWSaOz7IOm7jiLQiF3UtiFOG06w76d3UfcIVbqjImwWv8nysphi9IQfL0XgC24zNE6LSeE7IN5xTOxoZxORQGsCEnFNCPevReNcSB0pI9xQ1iao7evaZkpzT4D4iQ/K7Ss8dsfFWN30NPMQS5ReQTUKtmGn1YlgkitiYTEXbMjkYbQaQr daniel@shadow" "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtfWeIH7YZpWUUOZ3oC5FB2/J+P3scxm29gUQdVij/K0TuxW1yN/HtcvrO1mwSshS6sNZ2N6/Kb6+kuGyx1mEnaFt87K5ucxC7TNqiURh4eeZE1xX7B5Ob8TVegrBxoe+vcfaoyxn7sUzgF719H0aYC7PP6p3AIbhq3hRLcvY26u9/gZ39H79A71wCunauvpcnpb+rqyJMN6m2YoeOcoloe7wUDI8Xw5dUetHpNKn9k1vzS16CdwP4pAKI8aBtdNK7ZojVMe9LfBG8HHPr9K+cwcaxQuXkFBJzrfrtBCfQwrgWppsu/W/kGBs1ybku2bOFI5UXJBnsraXQqr1NLIfL phj@phj-X220" "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDj8dla7nOE7RSho2/9LAn+DANYkB1BmMoNryzTQ5mUJWukf5coCc+aNJcXYeu5dSTEicW2qQuD8mt8SDI5Qzv4oSpIYEsd0j4eW/BlC5XYd+4jS7Hfk/a1mJjMG7jdvOUtK3lLtrKaHxVUUjqdxKzzFBZlPov6FgHSJ//h1HxreV/Y0jL94qSvK39FZde5xlV/wQBvpglrMNu7FFWqyeKrOZ7U8D70scFliIuPok/02iQ31P+ncUfV3XrFyJodQq8J3hYEorGVKp3nNM1zaLlg8uqHk18Zt0GFnEAClBrC13yjM0jpMvaMyuXMaWuKeqsBZeUyaSo1j6BNsW/bFjiJ thomas-glamsch@gmx.de" + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCneS9f0u6sITEzKULgIK7LGKskPpyXlQoSLB6aYAS9ZUkZXHh97XwIQqv20/edsAwpKhSSw//n08bvlYjpUSDAg9V/iZzdEV1M7fxek1c0rxtFxbeCds5K67JV+wGEusVyQdtmVzyshBBg+Mk/66E3KgqMyjCyGPk/0qWaj6187DOxerbXI5QkO7lCPIa5jP2YR4yzmFomcGb4PqpPlWfOcjjEjtpenQkhy7iS0ukfkQ9jhIcppuvkZ9A8PL/ccHDNVg0YKNJbsviB5MwKm/6drK87fprP9SP0i7QZsdKhaaW3rQtzCiWup4Avwx91VfeLvef8JJnmDrx+tR7azdGCiiRQvLakT2aIyMSTcDG41PYsesFvqBhRidSgzdZ4I2jjT1iHL4XREQVSjB5voAFdXHrndZj9PT8mTMo1RsdM1YMspHD1ohn2a3YkzKHD6g1n0UM379lyJ2mBEA1w+Nb48s60Mecuy2MlFgN6MbwYXifJkm806nI09ExEfgan8JvWOUQLgCDtp4mGt62vYMmBb5UqyUpvTcPbxoAbpHx+LEAD9Q0OE8S8WGnmkXxnnP2fL1fkcL1wjwvDbW0q9ezl9SrMfxcd+n46kbkYnSJ8HwZSZPX3wn2FAqIAKR+46BSsXW5FTo0xwR9wEjaBC7/6PxcxmAivGJZzYUZ0cjCCOw== lisanne.wolters@gmx.net" ]; }; }; @@ -111,15 +124,54 @@ in }; networking = { + nat = { + enable = true; + externalInterface = ethernetInterface; + internalInterfaces = [ wireguard.interface ]; + }; + hostName = "haku"; firewall = { - allowedTCPPorts = - [ 80 443 - ]; - allowedTCPPortRanges = - # rtorrent - [{ from = 6881; to = 6889; }]; + allowedTCPPorts = [ + 80 443 + 6882 + 1337 2342 4223 + 60100 + ]; + allowedUDPPorts = [ + wireguard.port + 60100 + ]; + # forward wireguard connections to ethernet device (VPN) + extraCommands = '' + iptables -t nat -A POSTROUTING -s ${wireguard.internalNetwork.range} -o ${ethernetInterface} -j MASQUERADE + '' + # drop every other kind of forwarding, except from wg0 to epn (and bridge wg) + + '' + iptables -P FORWARD DROP + iptables -A FORWARD -i ${wireguard.interface} -o ${ethernetInterface} -j ACCEPT + iptables -A FORWARD -o ${wireguard.interface} -i ${ethernetInterface} -j ACCEPT + iptables -A FORWARD -i ${wireguard.interface} -o ${wireguard.interface} -j ACCEPT + ''; }; + + wireguard.interfaces.${wireguard.interface} = { + ips = [ wireguard.internalNetwork.server ]; + listenPort = wireguard.port; + privateKeyFile = "/root/keys/wg/vpn.priv"; + + peers = [ + { # shiki (TODO: factor out) + publicKey = "x3ko/R8PLzcyjVjqot9qmGBb3NrG/4JvgRkIOQMEsUA="; + allowedIPs = [ (wireguard.internalNetwork.addr 2) ]; + } + { # mushu + publicKey = "Stx6N4/JurtAuYX+43WPOCLBqheE99O6WRvxW+sd3jw="; + allowedIPs = [ (wireguard.internalNetwork.addr 3) ]; + } + ]; + }; + nameservers = [ "62.210.16.6" "62.210.16.7" diff --git a/machines/profpatsch/lib.nix b/machines/profpatsch/lib.nix index 745fc156..ae730824 100644 --- a/machines/profpatsch/lib.nix +++ b/machines/profpatsch/lib.nix @@ -6,7 +6,7 @@ rec { philip = rec { name = "philip"; - extraGroups = [ "wheel" "networkmanager" ]; + extraGroups = [ "wheel" "networkmanager" "docker" "vboxuser" "libvirtd" ]; uid = 1000; createHome = true; home = "/home/philip"; diff --git a/machines/profpatsch/shiki.nix b/machines/profpatsch/shiki.nix index f916905d..4d66f81e 100644 --- a/machines/profpatsch/shiki.nix +++ b/machines/profpatsch/shiki.nix @@ -51,12 +51,17 @@ in { support32Bit = true; }; # steam - hardware.opengl.driSupport32Bit = true; - # needed by some games (TODO: general module for games) - # hardware.opengl.driSupport32Bit = true; + hardware.opengl.driSupport32Bit = true; - vuizvui.hardware.thinkpad.enable = true; + # TODO: kinda broken? + # i18n = { + # inputMethod = { + # enabled = "fcitx"; + # Japanese input + # fcitx.engines = with pkgs.fcitx-engines; [ mozc ]; + # }; + # }; ###### # Nix @@ -110,8 +115,10 @@ in { # wifiAndEthernet = { # interfaces = [ "wlp3s0" "enp0s25" ]; # driverOptions = { - # miimon = "100"; + # # how often to check for link failures, i.e. ethernet down (ms) + # miimon = "500"; # primary = "enp0s25"; + # primary_reselect = "always"; # mode = "active-backup"; # }; # }; @@ -137,7 +144,6 @@ in { wpa_supplicant_gui # configure wireless connections ]; xPkgs = [ - dmenu # simple UI menu builder dunst # notification daemon (interfaces with libnotify) # TODO: replace by xscreensaver or i3lock alock # lock screen @@ -156,6 +162,7 @@ in { # myPkgs.fast-init # fast-init of haskell projects gitAndTools.git-annex # version controlled binary file storage gitAndTools.git-dit # decentral issue tracking for git + gitAndTools.git-hub # lightweight GitHub integration # TODO: move to user config go @@ -166,7 +173,7 @@ in { pkgs.vuizvui.profpatsch.nix-http-serve # serve nix builds and rebuild on reloads pkgs.vuizvui.profpatsch.nman # open man pages in temporary nix shell pkgs.vuizvui.profpatsch.warpspeed # trivial http file server - pkgs.vuizvui.profpatsch.nix-gen # generate nix expressions + # pkgs.vuizvui.profpatsch.nix-gen # generate nix expressions pkgs.vuizvui.profpatsch.watch-server # restart server on code change pkgs.vuizvui.profpatsch.until # restart until cmd succeeds myPkgs.execlineb-with-builtins @@ -192,7 +199,6 @@ in { gimp # graphics inkscape # vector graphics libreoffice # a giant ball of C++, that sometimes helps with proprietary shitformats - lilyterm-git # terminal emulator, best one around myPkgs.mpv # you are my sun and my stars, and you play my stuff. pass # standard unix password manager picard # jean-luc, music tagger @@ -204,8 +210,14 @@ in { youtube-dl # download videos zathura # pdf viewer ]; - userScripts = with pkgs.vuizvui.profpatsch; [ + userScripts = with pkgs.vuizvui.profpatsch; + let + di-notify = pkgs.writers.writeBashBin "display-infos-notify" '' + ${pkgs.libnotify}/bin/notify-send "$(${display-infos}/bin/display-infos)" + ''; + in [ display-infos # show time & battery + di-notify # same, but pipe to libnotify show-qr-code # display a QR code backlight # adjust laptop backlight ]; @@ -224,6 +236,8 @@ in { redshift # increases screen warmth at night (so i don’t have to feel cold) # pdfjam is the best CLI pdf modification suite (texlive.combine { inherit (texlive) scheme-small pdfjam; }) + # move script/nix-cache-binary to here + cdb ]; in systemPkgs ++ xPkgs ++ guiPkgs ++ programmingTools ++ documentation @@ -242,63 +256,16 @@ in { LidSwitchIgnoreInhibited=no ''; + # TMP + + vuizvui.services.guix.enable = true; ################### # Graphical System services.xserver = { - enable = true; - layout = "de"; - xkbVariant = "neo"; - xkbOptions = "altwin:swap_alt_win"; - serverFlagsSection = '' - Option "StandbyTime" "10" - Option "SuspendTime" "20" - Option "OffTime" "30" - ''; - - synaptics = { - enable = true; - minSpeed = "0.6"; - maxSpeed = "1.5"; - accelFactor = "0.015"; - twoFingerScroll = true; - vertEdgeScroll = false; - }; - - videoDrivers = [ "intel" ]; - - displayManager = { - sessionCommands = with pkgs; '' - #TODO add as nixpkg - export PATH+=":$HOME/scripts" #add utility scripts - export EDITOR=emacsclient - export TERMINAL=${lilyterm}/bin/lilyterm - - ${xorg.xset}/bin/xset r rate 250 35 - - set-background & - # TODO xbindkeys user service file - ${lib.getBin xbindkeys}/bin/xbindkeys - # synchronize clipboards - ${lib.getBin autocutsel}/bin/autocutsel -s PRIMARY & - ''; - }; - }; - fonts.fontconfig = { - enable = true; - defaultFonts = { - monospace = [ "Source Code Pro" "DejaVu Sans Mono" ]; # TODO does not work - sansSerif = [ "Liberation Sans" ]; - }; - ultimate = { - enable = true; - substitutions = "combi"; - preset = "ultimate4"; - }; - }; fonts.fonts = with pkgs; [ unfreeAndNonDistributablePkgs.corefonts source-han-sans-japanese @@ -328,9 +295,6 @@ in { }; }; - # TODO: base config? - vuizvui.programs.fish.fasd.enable = true; - vuizvui.user.profpatsch.programs.scanning = { enable = true; #remoteScanners = '' diff --git a/modules/core/common.nix b/modules/core/common.nix index f394b038..9c9c7a67 100644 --- a/modules/core/common.nix +++ b/modules/core/common.nix @@ -1,4 +1,4 @@ -{ config, options, pkgs, lib, ... }: +{ config, pkgs, lib, ... }: with lib; @@ -41,9 +41,7 @@ with lib; vuizvui = import ../../pkgs { inherit pkgs; }; }); - nix.binaryCaches = options.nix.binaryCaches.default ++ [ - "https://headcounter.org/hydra/" - ]; + nix.binaryCaches = [ "https://headcounter.org/hydra/" ]; nix.binaryCachePublicKeys = [ "headcounter.org:/7YANMvnQnyvcVB6rgFTdb8p5LG1OTXaO+21CaOSBzg=" ]; diff --git a/modules/module-list.nix b/modules/module-list.nix index c75b8dae..df539e6e 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -11,6 +11,7 @@ ./programs/fish/fasd.nix ./services/postfix ./services/starbound.nix + ./services/guix.nix ./system/iso.nix ./system/kernel/bfq ./system/kernel/rckernel.nix diff --git a/modules/services/guix.nix b/modules/services/guix.nix new file mode 100644 index 00000000..287ac619 --- /dev/null +++ b/modules/services/guix.nix @@ -0,0 +1,106 @@ +# ATTN: this is a WIP service, use at your own risk! +{ config, lib, pkgs, ... }: +# https://www.gnu.org/software/guix/manual/en/html_node/Binary-Installation.html + +let + guixBinaryTar = pkgs.fetchurl { + url = "https://alpha.gnu.org/gnu/guix/guix-binary-0.16.0.x86_64-linux.tar.xz"; + sha256 = "049l0zim30cd0gyly2h3jaw4cshdk78h7xdb9ac173h72i13afbj"; + }; + + #*/ + guixInstallScriptIdempotent = pkgs.writeScript "guix-install.sh" '' + #!/bin/sh + set -euo pipefail + + # extract guix + if ! test -e /gnu; then + echo "INFO: installing guix" + + tmp=$(mktemp -d) + pushd $tmp >/dev/null + export PATH=${pkgs.xz}/bin:$PATH + ${pkgs.gnutar}/bin/tar xf ${guixBinaryTar} + mkdir -p /var + cp -r ./var/guix /var + cp -r ./gnu / + popd >/dev/null + + # XXX + # change the mtime of all compiled guile files, + # because tar in this script somehow changes the mtime + # of extracted files to the current time, and nobody knows + # why. If the sources are newer than the .go files, guile + # will try to recompile everything. + find /gnu/store/ -ipath "*guile*ccache*/*.go" | xargs touch -m + fi + + # install root user profile + if ! test -e /root/.config/guix/current; then + mkdir -p /root/.config/guix + ln -s /var/guix/profiles/per-user/root/current-guix \ + /root/.config/guix/current + fi + + echo INFO: finished installing guix! + ''; + + guixBuildGroup = "guixbuilders"; + + guixBuildUser = id: { + name = "guix-build-user-${toString id}"; + createHome = false; + description = "Guix build user ${toString id}"; + extraGroups = [ guixBuildGroup ]; + isSystemUser = true; + }; + + guixBuildUsers = numberOfUsers: + builtins.listToAttrs + (map (user: { + name = user.name; + value = user; + }) (builtins.genList guixBuildUser numberOfUsers)); +in +{ + options = { + vuizvui.services.guix.enable = + lib.mkEnableOption "the guix daemon and init /gnu/store"; + }; + + config = lib.mkIf config.vuizvui.services.guix.enable { + users.users = guixBuildUsers 10; + users.groups = { "${guixBuildGroup}" = {}; }; + + systemd.services.guix-install = { + serviceConfig = { + ExecStart = guixInstallScriptIdempotent; + Type = "oneshot"; + }; + }; + + systemd.services.guix-daemon = { + serviceConfig = { + ExecStart = "/var/guix/profiles/per-user/root/current-guix/bin/guix-daemon --build-users-group=${guixBuildGroup}"; + Environment = "GUIX_LOCPATH=/var/guix/profiles/per-user/root/guix-profix/lib/locale"; + RemainAfterExit = true; + StandardOutput = "syslog"; + StandardError = "syslog"; + TasksMax = 8192; + }; + wantedBy = [ "multi-user.target" ]; + after = [ "guix-install.service" ]; + wants = [ "guix-install.service" ]; + }; + + environment.shellInit = '' + export GUIX_PROFILE="$HOME/.config/guix/current" + source $GUIX_PROFILE/etc/profile + export GUIX_LOCPATH="${pkgs.glibcLocales}/lib/locale" + export INFOPATH="$GUIX_PROFILE/share/info:$INFOPATH" + + guix archive --authorize < \ + /root/.config/guix/current/share/guix/ci.guix.info.pub + ''; + }; +} diff --git a/modules/user/aszlig/profiles/workstation/default.nix b/modules/user/aszlig/profiles/workstation/default.nix index e9893f29..ec195727 100644 --- a/modules/user/aszlig/profiles/workstation/default.nix +++ b/modules/user/aszlig/profiles/workstation/default.nix @@ -25,7 +25,12 @@ in { in singleton (pkgs.writeScriptBin "xreset" '' #!${pkgs.stdenv.shell} ${pkgs.xorg.xrandr}/bin/xrandr ${concatStringsSep " " randrConf} - '') ++ import ./packages.nix pkgs; + '') ++ import ./packages.nix pkgs ++ [ + (pkgs.vuizvui.aszlig.psi.override { + jid = "aszlig@aszlig.net"; + resource = config.networking.hostName; + }) + ]; environment.pathsToLink = lib.singleton "/share/chromium/extensions"; @@ -117,6 +122,9 @@ in { vuizvui.system.kernel.zswap.enable = true; + location.latitude = 48.4284; + location.longitude = 10.866; + services = { openssh.enable = true; @@ -144,8 +152,6 @@ in { redshift = { enable = true; - latitude = "48.428404"; - longitude = "10.866007"; temperature.day = 5500; temperature.night = 3500; }; diff --git a/modules/user/aszlig/profiles/workstation/packages.nix b/modules/user/aszlig/profiles/workstation/packages.nix index 72b04be1..093e2bed 100644 --- a/modules/user/aszlig/profiles/workstation/packages.nix +++ b/modules/user/aszlig/profiles/workstation/packages.nix @@ -17,7 +17,6 @@ pkgs: with pkgs; [ figlet firefox flac - gajim gdb ghostscript vuizvui.aszlig.git-detach @@ -62,7 +61,6 @@ pkgs: with pkgs; [ radare2 rlwrap rsync - vuizvui.aszlig.santander samplicator screen scrot diff --git a/modules/user/aszlig/programs/zsh/default.nix b/modules/user/aszlig/programs/zsh/default.nix index fb3b9a49..e66be125 100644 --- a/modules/user/aszlig/programs/zsh/default.nix +++ b/modules/user/aszlig/programs/zsh/default.nix @@ -41,25 +41,26 @@ in { programs.zsh.shellAliases.t = "task"; programs.zsh.shellAliases.p = "gopass"; + programs.zsh.setOptions = lib.mkForce [ + "auto_cd" + "auto_pushd" + "beep" + "correct" + "dvorak" + "extended_glob" + "extended_history" + "hist_fcntl_lock" + "hist_ignore_dups" + "hist_no_store" + "hist_reduce_blanks" + "interactive_comments" + ]; + programs.zsh.interactiveShellInit = mkAfter '' export HISTFILE=~/.histfile export HISTSIZE=100000 export SAVEHIST=100000 - unsetopt SHARE_HISTORY - - setopt extendedglob - setopt extendedhistory - setopt globcomplete - setopt histnostore - setopt histreduceblanks - setopt correct - setopt dvorak - setopt interactivecomments - setopt autopushd - setopt autocd - setopt beep - bindkey -v if [[ "$TERM" = xterm ]]; then bindkey -v '\e[H' vi-beginning-of-line @@ -110,9 +111,6 @@ in { zstyle ':completion:*' use-compctl false zstyle ':completion:*' verbose true - autoload -Uz compinit - compinit - autoload -Uz zmv ''; diff --git a/modules/user/devhell/profiles/base.nix b/modules/user/devhell/profiles/base.nix index 17fdf073..cba7f19e 100644 --- a/modules/user/devhell/profiles/base.nix +++ b/modules/user/devhell/profiles/base.nix @@ -33,7 +33,6 @@ in { hardware = { enableAllFirmware = true; - cpu.intel.updateMicrocode = true; opengl = { s3tcSupport = true; driSupport32Bit = true; @@ -41,6 +40,7 @@ in { pulseaudio = { enable = true; systemWide = false; + extraConfig = "load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1"; }; }; @@ -48,7 +48,7 @@ in { users.users.dev = { isNormalUser = true; - extraGroups = [ "plugdev" "docker" "vboxusers" "wheel" "mpd" "libvirtd" "wireshark" ]; + extraGroups = [ "plugdev" "docker" "vboxusers" "wheel" "mpd" "libvirtd" "wireshark" "video" "audio" ]; uid = 1000; shell = "${pkgs.zsh}/bin/zsh"; }; @@ -111,7 +111,7 @@ in { ttf_bitstream_vera ubuntu_font_family unifont - vistafonts + #vistafonts wqy_microhei ] ++ lib.filter lib.isDerivation (lib.attrValues lohit-fonts); }; diff --git a/modules/user/devhell/profiles/packages.nix b/modules/user/devhell/profiles/packages.nix index 47a96100..a37381c9 100644 --- a/modules/user/devhell/profiles/packages.nix +++ b/modules/user/devhell/profiles/packages.nix @@ -16,7 +16,9 @@ in { }; polybar = super.polybar.override { - i3Support = true; + nlSupport = true; + pulseSupport = true; + i3GapsSupport = true; mpdSupport = true; }; @@ -130,6 +132,7 @@ in { hplipWithPlugin htop i3lock-color + i3lock-fancy iftop imagemagick iotop @@ -173,6 +176,7 @@ in { netrw netsniff-ng nitrogen + nitrokey-udev-rules nixops nload nmap @@ -245,6 +249,7 @@ in { vlock vorbisTools vorbisgain + vscodium w3m wavpack weechat diff --git a/modules/user/devhell/profiles/services.nix b/modules/user/devhell/profiles/services.nix index 144dcaff..927fa3e9 100644 --- a/modules/user/devhell/profiles/services.nix +++ b/modules/user/devhell/profiles/services.nix @@ -22,30 +22,46 @@ in { }; }; + location.provider = "geoclue2"; + services = { keybase.enable = true; pcscd.enable = true; gpm.enable = true; openssh.enable = true; - thermald.enable = true; udisks2.enable = true; geoip-updater.enable = true; geoclue2.enable = true; + redshift.enable = true; - redshift = { + compton = { enable = true; - provider = "geoclue2"; + vSync = true; + backend = "glx"; }; }; - services.offlineimap = { - enable = true; - install = true; - path = [ pkgs.notmuch ]; - }; services.xserver = { - displayManager.lightdm.enable = true; + displayManager.lightdm = { + enable = true; + greeters.mini = { + enable = true; + user = "dev"; + extraConfig = '' + [greeter] + show-password-label = true + password-label-text = > + show-input-cursor = false + [greeter-theme] + text-color = "#4C566A" + window-color = "#3B4252" + border-width = 0px + layout-space = 5 + password-background-color = "#3B4252" + ''; + }; + }; desktopManager.xterm.enable = false; desktopManager.default = "none"; }; @@ -58,12 +74,6 @@ in { }; }; - services.syncthing = { - enable = true; - user = "dev"; - dataDir = "/home/dev/syncthing/"; - }; - services.journald.extraConfig = '' SystemMaxUse = 50M ''; diff --git a/pkgs/aszlig/default.nix b/pkgs/aszlig/default.nix index 70c6ff9d..d1dbcb73 100644 --- a/pkgs/aszlig/default.nix +++ b/pkgs/aszlig/default.nix @@ -8,8 +8,8 @@ grandpa = callPackage ./grandpa { }; librxtx_java = callPackage ./librxtx-java { }; lockdev = callPackage ./lockdev { }; + psi = callPackage ./psi { }; pvolctrl = callPackage ./pvolctrl { }; - santander = callPackage_i686 ./santander { }; vim = callPackage ./vim { vim = vim_configurable; }; xournal = callPackage ./xournal { inherit xournal; }; } diff --git a/pkgs/aszlig/psi/config.patch b/pkgs/aszlig/psi/config.patch new file mode 100644 index 00000000..a9462102 --- /dev/null +++ b/pkgs/aszlig/psi/config.patch @@ -0,0 +1,278 @@ +diff --git a/options/default.xml b/options/default.xml +index 90f019b3..ef33997b 100644 +--- a/options/default.xml ++++ b/options/default.xml +@@ -19,7 +19,7 @@ + <domain comment="Always use the same domain to register with. Leave this empty to allow the user to choose his server." type="QString"/> + </account> + <auto-update comment="Auto updater"> +- <check-on-startup comment="Check for available updates on startup" type="bool">true</check-on-startup> ++ <check-on-startup comment="Check for available updates on startup" type="bool">false</check-on-startup> + </auto-update> + <enable-multicast comment="Enable multicasting messages to multiple recipients" type="bool">false</enable-multicast> + <html comment="Hypertext markup options"> +@@ -86,7 +86,7 @@ + <security comment="Options related to the seciruty UI"> + <show comment="Show the security UI" type="bool">true</show> + </security> +- <single comment="Limit the client to a single account" type="bool">false</single> ++ <single comment="Limit the client to a single account" type="bool">true</single> + </account> + <message comment="Message options"> + <enabled comment="Enable message (i.e. non-chat) functionality" type="bool">true</enabled> +@@ -128,7 +128,7 @@ + <default-jid-mode comment="Default jid mode: barejid | auto" type="QString">auto</default-jid-mode> + <default-jid-mode-ignorelist comment="Default autojid mode ignore list: jid1,jid2,..." type="QString"></default-jid-mode-ignorelist> + <history comment="Message history options"> +- <preload-history-size comment="The number of preloaded messages" type="int">5</preload-history-size> ++ <preload-history-size comment="The number of preloaded messages" type="int">10</preload-history-size> + </history> + </chat> + <save> +@@ -146,8 +146,8 @@ + <auto-delete-unlisted comment="Automatically remove an unlisted contact from the contact list if it does not have any pending messages anymore" type="bool">false</auto-delete-unlisted> + <opacity comment="Opacity percentage of the contact list" type="int">100</opacity> + <status-messages comment="Status messages for contacts"> +- <single-line comment="Show status messages on the same line as the nickname" type="bool">true</single-line> +- <show comment="Show status messages" type="bool">false</show> ++ <single-line comment="Show status messages on the same line as the nickname" type="bool">false</single-line> ++ <show comment="Show status messages" type="bool">true</show> + </status-messages> + <tooltip comment="Display options for the contact list tooltips"> + <css type="QString"></css> +@@ -208,7 +208,7 @@ QLineEdit#le_status_text { + <always-on-top type="bool">false</always-on-top> + <automatically-resize-roster type="bool">false</automatically-resize-roster> + <grow-roster-upwards type="bool">true</grow-roster-upwards> +- <disable-scrollbar type="bool">true</disable-scrollbar> ++ <disable-scrollbar type="bool">false</disable-scrollbar> + <contact-sort-style type="QString">status</contact-sort-style> + <disable-service-discovery type="bool">false</disable-service-discovery> + <enable-groups type="bool">true</enable-groups> +@@ -223,7 +223,7 @@ QLineEdit#le_status_text { + <agent-contacts type="bool">true</agent-contacts> + <away-contacts type="bool">true</away-contacts> + <hidden-contacts-group type="bool">true</hidden-contacts-group> +- <offline-contacts type="bool">true</offline-contacts> ++ <offline-contacts type="bool">false</offline-contacts> + <self-contact type="bool">true</self-contact> + </show> + <show-group-counts type="bool">true</show-group-counts> +@@ -248,7 +248,7 @@ QLineEdit#le_status_text { + <use-left-click type="bool">false</use-left-click> + <use-single-click type="bool">false</use-single-click> + <use-status-change-animation type="bool">true</use-status-change-animation> +- <aio-left-roster type="bool">false</aio-left-roster> ++ <aio-left-roster type="bool">true</aio-left-roster> + <use-transport-icons type="bool">true</use-transport-icons> + <saved-window-geometry type="QRect" > + <x>64</x> +@@ -285,7 +285,7 @@ QLineEdit#le_status_text { + <custom-pgp-key comment="Show the 'assign pgp key' menu" type="bool">true</custom-pgp-key> + </contact> + <main comment="Options for the main menu"> +- <change-profile comment="Show the 'change profile' menu" type="bool">true</change-profile> ++ <change-profile comment="Show the 'change profile' menu" type="bool">false</change-profile> + </main> + <status comment="Options for the status menu"> + <chat comment="Enable free for chat" type="bool">true</chat> +@@ -335,7 +335,7 @@ QLineEdit#le_status_text { + <disable-send-button type="bool">true</disable-send-button> + <systemtray comment="Options related to the system tray"> + <use-old comment="Use the old system tray code (deprecated)" type="bool">false</use-old> +- <enable type="bool">true</enable> ++ <enable type="bool">false</enable> + <use-double-click type="bool">false</use-double-click> + </systemtray> + <flash-windows comment="Allow windows to flash upon activity" type="bool">true</flash-windows> +@@ -353,8 +353,8 @@ QLineEdit#le_status_text { + <contactlist> + <background type="QColor"/> + <grouping> +- <header-background type="QColor">#f0f0f0</header-background> +- <header-foreground type="QColor">#5a5a5a</header-foreground> ++ <header-background type="QColor">#00007f</header-background> ++ <header-foreground type="QColor">#969696</header-foreground> + </grouping> + <profile> + <header-background type="QColor">#969696</header-background> +@@ -364,16 +364,16 @@ QLineEdit#le_status_text { + <away type="QColor">#004bb4</away> + <do-not-disturb type="QColor">#7e0000</do-not-disturb> + <offline type="QColor">#646464</offline> +- <online type="QColor"/> ++ <online type="QColor">#ffffff</online> + </status> +- <status-change-animation1 type="QColor">#000000</status-change-animation1> ++ <status-change-animation1 type="QColor">#6f0000</status-change-animation1> + <status-change-animation2 type="QColor">#969696</status-change-animation2> + <status-messages type="QColor">#808080</status-messages> + </contactlist> + <tooltip> + <enable comment="Enable tooltip coloring feature" type="bool">true</enable> + <background comment="Tooltip background color" type="QColor">#e9ecc7</background> +- <text comment="Tooltip text color" type="QColor">#000000</text> ++ <text comment="Tooltip text color" type="QColor">#ffffff</text> + </tooltip> + <muc> + <nick-colors type="QStringList" > +@@ -384,21 +384,21 @@ QLineEdit#le_status_text { + <item>Red</item> + </nick-colors> + <role-moderator type="QColor">#910000</role-moderator> +- <role-participant type="QColor">#00008a</role-participant> ++ <role-participant type="QColor">#00aaff</role-participant> + <role-visitor type="QColor">#336600</role-visitor> +- <role-norole type="QColor">black</role-norole> ++ <role-norole type="QColor">#cccccc</role-norole> + </muc> + <messages comment="Message coloring."> +- <received type="QColor" comment="Color used to indicate received messages.">#0000ff</received> ++ <received type="QColor" comment="Color used to indicate received messages.">#0055ff</received> + <sent type="QColor" comment="Color used to indicate sent messages.">#ff0000</sent> + <informational type="QColor" comment="Color used to indicate informational (status change, spooled) messages.">#008000</informational> + <usertext type="QColor" comment="Color used to indicate additional text for informational messages.">#606060</usertext> + <highlighting type="QColor">#FF0000</highlighting> +- <link type="QColor">#000080</link> ++ <link type="QColor">#55ffff</link> + <link-visited type="QColor">#400080</link-visited> + </messages> + <chat> +- <composing-color type="QColor">darkGreen</composing-color> ++ <composing-color type="QColor">#cccccc</composing-color> + <unread-message-color type="QColor">red</unread-message-color> + <inactive-color type="QColor">grey</inactive-color> + </chat> +@@ -411,10 +411,10 @@ QLineEdit#le_status_text { + <use-slim-group-headings type="bool">false</use-slim-group-headings> + </contactlist> + <font> +- <chat type="QString">Sans Serif,11,-1,5,50,0,0,0,0,0</chat> +- <contactlist type="QString">Sans Serif,11,-1,5,50,0,0,0,0,0</contactlist> +- <message type="QString">Sans Serif,11,-1,5,50,0,0,0,0,0</message> +- <passive-popup type="QString">Sans Serif,9,-1,5,50,0,0,0,0,0</passive-popup> ++ <chat type="QString">Monospace,12,-1,5,50,0,0,0,0,0</chat> ++ <contactlist type="QString">Monospace,12,-1,5,50,0,0,0,0,0</contactlist> ++ <message type="QString">Monospace,12,-1,5,50,0,0,0,0,0</message> ++ <passive-popup type="QString">Monospace,12,-1,5,50,0,0,0,0,0</passive-popup> + </font> + <css type="QString" /> + </look> +@@ -462,20 +462,20 @@ QLineEdit#le_status_text { + <suppress-while-away type="bool">false</suppress-while-away> + </popup-dialogs> + <sounds> +- <chat-message type="QString">sound/chat2.wav</chat-message> +- <groupchat-message type="QString">sound/chat2.wav</groupchat-message> +- <completed-file-transfer type="QString">sound/ft_complete.wav</completed-file-transfer> +- <contact-offline type="QString">sound/offline.wav</contact-offline> +- <contact-online type="QString">sound/online.wav</contact-online> +- <enable type="bool">true</enable> +- <incoming-file-transfer type="QString">sound/ft_incoming.wav</incoming-file-transfer> +- <incoming-headline type="QString">sound/chat2.wav</incoming-headline> +- <incoming-message type="QString">sound/chat2.wav</incoming-message> +- <new-chat type="QString">sound/chat1.wav</new-chat> ++ <chat-message type="QString"/> ++ <groupchat-message type="QString"/> ++ <completed-file-transfer type="QString"/> ++ <contact-offline type="QString"/> ++ <contact-online type="QString"/> ++ <enable type="bool">false</enable> ++ <incoming-file-transfer type="QString"/> ++ <incoming-headline type="QString"/> ++ <incoming-message type="QString"/> ++ <new-chat type="QString"/> + <notify-every-muc-message type="bool">false</notify-every-muc-message> +- <outgoing-chat type="QString">sound/send.wav</outgoing-chat> +- <silent-while-away type="bool">false</silent-while-away> +- <system-message type="QString">sound/chat2.wav</system-message> ++ <outgoing-chat type="QString"/> ++ <silent-while-away type="bool">true</silent-while-away> ++ <system-message type="QString"/> + <unix-sound-player type="QString"/> + </sounds> + <successful-subscription type="bool">false</successful-subscription> +@@ -494,7 +494,7 @@ QLineEdit#le_status_text { + <mouse-middle-button type="QString">close</mouse-middle-button> <!-- hide|close|detach --> + <mouse-doubleclick-action type="QString">detach</mouse-doubleclick-action> + <size type="QString"></size> <!-- will be invalid when converted to QSize so we can detect first load --> +- <grouping type="QString" comment="A ':' seperated list of groups of kinds of tabs to keep in the same tabset. 'C' for chat and 'M' for mucs. 'A' means using all in one window patch.">CM</grouping> ++ <grouping type="QString" comment="A ':' seperated list of groups of kinds of tabs to keep in the same tabset. 'C' for chat and 'M' for mucs. 'A' means using all in one window patch.">ACM</grouping> + <group-state comment="Saved state data of the tabsets defined by options.ui.tabs.grouping"/> + <tab-singles type="QString" comment="Tab types that would have been untabbed are given their own tabset. 'C' for chat and 'M' for mucs"/> + <use-tab-shortcuts type="bool">true</use-tab-shortcuts> +@@ -627,7 +627,7 @@ QLineEdit#le_status_text { + <last-activity type="bool">true</last-activity> + </service-discovery> + <status> +- <ask-for-message-on-offline type="bool">false</ask-for-message-on-offline> ++ <ask-for-message-on-offline type="bool">true</ask-for-message-on-offline> + <ask-for-message-on-online type="bool">false</ask-for-message-on-online> + <ask-for-message-on-chat type="bool">true</ask-for-message-on-chat> + <ask-for-message-on-away type="bool">true</ask-for-message-on-away> +@@ -650,7 +650,20 @@ QLineEdit#le_status_text { + <by-template type="bool">true</by-template> + <by-status type="bool">false</by-status> + </last-overwrite> +- <presets/> ++ <presets> ++ <m0> ++ <key type="QString">zone</key> ++ <force-priority type="bool">false</force-priority> ++ <status type="QString">dnd</status> ++ <message type="QString">In The Zone[TM]</message> ++ </m0> ++ <m1> ++ <key type="QString">sleep</key> ++ <force-priority type="bool">false</force-priority> ++ <status type="QString">offline</status> ++ <message type="QString">Sleeping the hell out of here.</message> ++ </m1> ++ </presets> + <presets-in-status-menus type="QString" comment="'yes', 'no' or 'submenu'">submenu</presets-in-status-menus> + <show-only-online-offline type="bool">false</show-only-online-offline> + <show-choose type="bool">true</show-choose> +@@ -690,5 +703,9 @@ QLineEdit#le_status_text { + </keychain> + </options> + <accounts comment="Account definitions and options"/> +- <plugins comment="Plugin options"/> ++ <plugins comment="Plugin options"> ++ <auto-load> ++ <omemo type="bool">true</omemo> ++ </auto-load> ++ </plugins> + </psi> +diff --git a/src/psi_profiles.cpp b/src/psi_profiles.cpp +index 77fbd169..4b4bca11 100644 +--- a/src/psi_profiles.cpp ++++ b/src/psi_profiles.cpp +@@ -79,8 +79,8 @@ void UserAccount::reset() + req_mutual_auth = false; + legacy_ssl_probe = false; + security_level = QCA::SL_None; +- ssl = SSL_Auto; +- jid = ""; ++ ssl = SSL_Yes; ++ jid = "@jid@"; + pass = ""; + scramSaltedHashPassword = ""; + opt_pass = false; +@@ -90,7 +90,7 @@ void UserAccount::reset() + opt_automatic_resource = true; + priority_dep_on_status = true; + ignore_global_actions = false; +- resource = ApplicationInfo::name(); ++ resource = "@resource@"; + priority = 55; + ibbOnly = false; + opt_keepAlive = true; +@@ -133,7 +133,7 @@ void UserAccount::reset() + << "stun.voipbuster.com" + << "stun.voxgratia.org"; + +- stunHost = stunHosts[0]; ++ stunHost = ""; + + keybind.clear(); + diff --git a/pkgs/aszlig/psi/darkstyle.patch b/pkgs/aszlig/psi/darkstyle.patch new file mode 100644 index 00000000..45c5067f --- /dev/null +++ b/pkgs/aszlig/psi/darkstyle.patch @@ -0,0 +1,32 @@ +diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt +index 7118ea75..c6f58e35 100644 +--- a/src/CMakeLists.txt ++++ b/src/CMakeLists.txt +@@ -237,6 +237,7 @@ endif() + set(RESOURCES + ${PROJECT_SOURCE_DIR}/psi.qrc + ${PROJECT_SOURCE_DIR}/iconsets.qrc ++ ${QDARKSTYLE_PATH}/qdarkstyle/style.qrc + ) + qt5_add_resources(QRC_SOURCES ${RESOURCES}) + +diff --git a/src/main.cpp b/src/main.cpp +index b45fbab0..1cbead4a 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -532,6 +532,15 @@ PSI_EXPORT_FUNC int main(int argc, char *argv[]) + QCoreApplication::addLibraryPath(appPath); + # endif + PsiApplication app(argc, argv); ++ ++ QFile darkstyle(":qdarkstyle/style.qss"); ++ if (!darkstyle.exists()) { ++ qWarning() << "Unable to set dark style"; ++ } else { ++ darkstyle.open(QFile::ReadOnly | QFile::Text); ++ QTextStream ts(&darkstyle); ++ app.setStyleSheet(ts.readAll()); ++ } + QApplication::setApplicationName(ApplicationInfo::name()); + QApplication::addLibraryPath(ApplicationInfo::resourcesDir()); + QApplication::addLibraryPath(ApplicationInfo::homeDir(ApplicationInfo::DataLocation)); diff --git a/pkgs/aszlig/psi/default.nix b/pkgs/aszlig/psi/default.nix new file mode 100644 index 00000000..d0e24c05 --- /dev/null +++ b/pkgs/aszlig/psi/default.nix @@ -0,0 +1,72 @@ +{ stdenv, lib, fetchFromGitHub, cmake, makeWrapper +, hunspell, libgcrypt, libgpgerror, libidn, libotr, libsForQt5 +, libsignal-protocol-c, libtidy, qt5 + +, substituteAll + +, jid ? "something@example.org" +, resource ? "psi-aszlig" +}: + +let + qdarkstyle = fetchFromGitHub { + owner = "ColinDuquesnoy"; + repo = "QDarkStyleSheet"; + rev = "c92d0c4c996e3e859134492e0f9f7f74bd0e12cd"; + sha256 = "1qrmp3ibvgzwh2v1qfrfh8xiwvj0kbhj1bm17bjx7zpmnb8byz3m"; + }; + +in stdenv.mkDerivation rec { + name = "psi-${version}"; + version = "2.0git20190922aszlig"; + + src = fetchFromGitHub { + owner = "psi-im"; + repo = "psi"; + rev = "af26ce1c04207d384a05ea530d571068310957c6"; + sha256 = "0pxd4ha391mfmsa7n7ag5kqw0nv825wsnkyfxi8wsa942bnbircg"; + fetchSubmodules = true; + }; + + plugins = fetchFromGitHub { + owner = "psi-im"; + repo = "plugins"; + rev = "5574afcc8ab4c5647831d38be111976fb1fa10d3"; + sha256 = "1h011j94iy40ksiqlprjamfyv7irql502hhhb0mpabk4mndxmjgn"; + }; + + patches = [ + ./disable-xep-0232.patch + ./darkstyle.patch + (substituteAll { + src = ./config.patch; + inherit jid resource; + }) + ]; + + preConfigure = '' + cp --no-preserve=all -rt src/plugins "$plugins"/* + ''; + + cmakeFlags = [ + "-DENABLE_PLUGINS=ON" "-DUSE_KEYCHAIN=OFF" "-DPSI_VERSION=${version}" + "-DQDARKSTYLE_PATH=${qdarkstyle}" + ]; + + enableParallelBuilding = true; + nativeBuildInputs = [ cmake makeWrapper qt5.wrapQtAppsHook ]; + buildInputs = [ + hunspell + libgcrypt + libgpgerror + libidn + libotr + libsForQt5.qca-qt5 + libsignal-protocol-c + libtidy + qt5.qtbase + qt5.qtmultimedia + qt5.qtwebengine + qt5.qtx11extras + ]; +} diff --git a/pkgs/aszlig/psi/disable-xep-0232.patch b/pkgs/aszlig/psi/disable-xep-0232.patch new file mode 100644 index 00000000..4788d262 --- /dev/null +++ b/pkgs/aszlig/psi/disable-xep-0232.patch @@ -0,0 +1,50 @@ +diff --git a/iris/src/xmpp/xmpp-im/client.cpp b/iris/src/xmpp/xmpp-im/client.cpp +index d8573bf..31af799 100644 +--- a/iris/src/xmpp/xmpp-im/client.cpp ++++ b/iris/src/xmpp/xmpp-im/client.cpp +@@ -1257,45 +1257,6 @@ DiscoItem Client::makeDiscoResult(const QString &node) const + + item.setFeatures(features); + +- // xep-0232 Software Information +- XData si; +- XData::FieldList si_fields; +- +- XData::Field si_type_field; +- si_type_field.setType(XData::Field::Field_Hidden); +- si_type_field.setVar("FORM_TYPE"); +- si_type_field.setValue(QStringList(QLatin1String("urn:xmpp:dataforms:softwareinfo"))); +- si_fields.append(si_type_field); +- +- XData::Field software_field; +- software_field.setType(XData::Field::Field_TextSingle); +- software_field.setVar("software"); +- software_field.setValue(QStringList(d->clientName)); +- si_fields.append(software_field); +- +- XData::Field software_v_field; +- software_v_field.setType(XData::Field::Field_TextSingle); +- software_v_field.setVar("software_version"); +- software_v_field.setValue(QStringList(d->clientVersion)); +- si_fields.append(software_v_field); +- +- XData::Field os_field; +- os_field.setType(XData::Field::Field_TextSingle); +- os_field.setVar("os"); +- os_field.setValue(QStringList(d->osName)); +- si_fields.append(os_field); +- +- XData::Field os_v_field; +- os_v_field.setType(XData::Field::Field_TextSingle); +- os_v_field.setVar("os_version"); +- os_v_field.setValue(QStringList(d->osVersion)); +- si_fields.append(os_v_field); +- +- si.setType(XData::Data_Result); +- si.setFields(si_fields); +- +- item.setExtensions(QList<XData>() << si); +- + return item; + } + diff --git a/pkgs/aszlig/santander/default.nix b/pkgs/aszlig/santander/default.nix deleted file mode 100644 index adac0a8d..00000000 --- a/pkgs/aszlig/santander/default.nix +++ /dev/null @@ -1,98 +0,0 @@ -{ stdenv, lib, fetchurl, fetchgit, fetchpatch, runCommand, p7zip, jq -, winePackages, pcsclite -}: - -let - patchedWine = let - libpcsclite = "${lib.getLib pcsclite}/lib/libpcsclite.so"; - in winePackages.minimal.overrideAttrs (drv: { - scard4wine = fetchgit { - url = "git://git.code.sf.net/p/scard4wine/code"; - rev = "c14c02c80bf1f2bb4cedd1f53a3a2ab9c48bed76"; - sha256 = "0ffmbl9mdnaih4h3ggpnzqbih3kgbwl3wv6j1ag5s4czn8gcpdq3"; - }; - - prePatch = (drv.prePatch or "") + '' - cp -t dlls/winscard "$scard4wine/src/"* - sed -i -re 's,"libpcsclite\.so(\.[0-9]+)*","${libpcsclite}",' \ - dlls/winscard/winscard.c - ''; - - patches = (drv.patches or []) ++ [ - ./winscard.patch - (fetchpatch { - url = "http://achurch.org/patch-pile/wine/3.0/disable-unixfs.diff"; - sha256 = "1yj3walwalya9g9aajcp4iygh348npp9dmks66r9dvwbd3fa8wcb"; - }) - ]; - - configureFlags = lib.toList (drv.configureFlags or []) ++ [ - "--disable-unixfs" - ]; - - postConfigure = (drv.postConfigure or "") + '' - # The wineprefix is within the Nix store, so let's ensure wine doesn't - # check the owner of the files: - sed -i -e '/HAVE_GETUID/d' include/config.h - ''; - }); - -in stdenv.mkDerivation rec { - name = "TRAVIC-Sign-${version}"; - version = "3.1.3.0"; - - src = fetchurl { - url = "https://service.santanderbank.de/special/banking/files/" - + "${name}-Installer.exe"; - sha256 = "19a14av3bg6i4iy5q5pa737cwxznqji0lcrapxw0q6qb8rs1rhs7"; - }; - - extensionId = "ilpoejcegjjlgpobjkpjmddkbdkdndaj"; - - buildInputs = [ p7zip jq ]; - - unpackCmd = "7z x -y -otavic-sign $curSrc"; - - phases = [ "unpackPhase" "patchPhase" "installPhase" ]; - - postPatch = '' - jq '.allowed_origins = [ - "chrome-extension://'"$extensionId"'/" - ] | .path = "'"$out/share/libexec/travic-sign/travic-sign"'" - | del(.allowed_extensions)' manifest-firefox.json > host.json - - 7z x -y -oextension FirefoxExtension.xpi - jq '.content_scripts[].matches = ["https://karte.santanderbank.de/*"] | { - # All the object attributes that we want to have (nothing more): - background, web_accessible_resources, content_scripts, page_action, - permissions, author, version, description, name, manifest_version - }' extension/manifest.json > new_manifest.json - mv new_manifest.json extension/manifest.json - (cd extension && 7z a -tzip ../travic-sign.crx *) - ''; - - winePrefix = runCommand "empty-wineprefix" { - buildInputs = [ patchedWine ]; - } '' - export WINEPREFIX="$out" - mkdir -p "$out" - wine wineboot.exe - ''; - - installPhase = '' - libexec="$out/share/libexec/travic-sign" - - install -vD -m 0644 TRAVIC-Sign-Service.exe "$libexec/service.exe" - install -vD -m 0644 host.json \ - "$out/etc/chromium/native-messaging-hosts/travic-sign.json" - install -vD -m 0644 travic-sign.crx \ - "$out/share/chromium/extensions/$extensionId.crx" - - cat > "$libexec/travic-sign" <<EOF - #!${stdenv.shell} - export WINEPREFIX="$winePrefix" - exec ${patchedWine}/bin/wine "$libexec/service.exe" - EOF - chmod +x "$libexec/travic-sign" - ''; -} diff --git a/pkgs/aszlig/santander/pipelight.patch b/pkgs/aszlig/santander/pipelight.patch deleted file mode 100644 index 3a07da72..00000000 --- a/pkgs/aszlig/santander/pipelight.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/windows/pluginloader/pluginloader.c b/src/windows/pluginloader/pluginloader.c -index 9e8556f..c50be2a 100644 ---- a/src/windows/pluginloader/pluginloader.c -+++ b/src/windows/pluginloader/pluginloader.c -@@ -1510,7 +1510,7 @@ void dispatcher(int functionid, Stack &stack){ - NPObject *objectValue; - NPError result; - -- if (variable == NPPVpluginScriptableNPObject) -+ if (variable == NPPVpluginScriptableNPObject && pluginFuncs.getvalue) - result = pluginFuncs.getvalue(instance, variable, &objectValue); - else{ - DBG_WARN("FUNCTION_NPP_GETVALUE_OBJECT - variable %d not allowed", variable); diff --git a/pkgs/aszlig/santander/winscard.patch b/pkgs/aszlig/santander/winscard.patch deleted file mode 100644 index 7dfa04ac..00000000 --- a/pkgs/aszlig/santander/winscard.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/dlls/winscard/winscard.c 1970-01-01 01:00:01.000000000 +0100 -+++ b/dlls/winscard/winscard.c 2016-06-06 01:52:53.631444433 +0200 -@@ -1527,7 +1527,7 @@ - { - LONG lRet; - TRACE(" 0x%08X %p %p %p %p %p %p\n",(unsigned int) hCard,mszReaderNames,pcchReaderLen,pdwState,pdwProtocol,pbAtr,pcbAtrLen); -- if(!pcchReaderLen || !pdwState || !pdwProtocol || !pcbAtrLen) -+ if(!pcchReaderLen || !pcbAtrLen) - lRet = SCARD_E_INVALID_PARAMETER; - else if(!liteSCardStatus) - lRet = SCARD_F_INTERNAL_ERROR; diff --git a/pkgs/aszlig/vim/default.nix b/pkgs/aszlig/vim/default.nix index 6c1c6bab..5a2a3962 100644 --- a/pkgs/aszlig/vim/default.nix +++ b/pkgs/aszlig/vim/default.nix @@ -335,6 +335,27 @@ let ''; installPhase = "cp -r data/syntax-highlighting/vim \"$out\""; }; + + jinja2 = stdenv.mkDerivation { + name = "jinja2-vim-${python3Packages.jinja2.version}"; + inherit (python3Packages.jinja2) src; + phases = [ "unpackPhase" "installPhase" ]; + installPhase = '' + install -vD -m 0644 ext/Vim/jinja.vim "$out/syntax/jinja.vim" + ''; + }; + + xdebug = fetchurl { + name = "vim-xt-syntax"; + url = "https://raw.githubusercontent.com/xdebug/xdebug/" + + "ce4f6bc7ae04ae542960af6c1b8975888e9c3e5e/contrib/xt.vim"; + sha256 = "05a3nry310s2w1h2q7w6yw2wick81jrnrs43x9vk0k7dqyavhvhi"; + downloadToTemp = true; + recursiveHash = true; + postFetch = '' + install -vD -m 0644 "$downloadedFile" "$out/syntax/xt.vim" + ''; + }; }; generic = '' @@ -384,6 +405,13 @@ let let g:ledger_commodity_before = 0 let g:ledger_commodity_sep = ' ' let g:ledger_fold_blanks = 1 + + " php + let php_noShortTags = 1 + let php_sql_query = 1 + let php_baselib = 1 + let php_htmlInStrings = 1 + let g:PHP_vintage_case_default_indent = 1 ''; autocmd = '' @@ -394,6 +422,7 @@ let " filetype defaults au BufNewFile,BufRead *.as setlocal ft=actionscript au BufNewFile,BufRead *.tt setlocal ft=tt2html ts=2 sw=2 sts=2 et + au BufNewFile,BufRead *.xt setlocal ft=xt foldlevel=4 au BufNewFile,BufRead *.html setlocal ts=2 sw=2 sts=2 et au FileType python setlocal textwidth=79 au FileType gitcommit setlocal textwidth=72 @@ -415,8 +444,8 @@ let " prevent colorscheme from overriding these highlights au ColorScheme * highlight ExtraWhitespace ctermbg=red guibg=red - " highlight everything exceeding 79 characters (except for CSV) - au BufWinEnter * if &ft !=# 'csv' + " highlight everything exceeding 79 characters (with exceptions) + au BufWinEnter * if index(['csv', 'strace', 'xt'], &ft) < 0 \ | let w:m2=matchadd('ErrorMsg', '\%>79v.\+', -1) \ | endif diff --git a/pkgs/build-support/build-sandbox/default.nix b/pkgs/build-support/build-sandbox/default.nix index 66797268..4e5cffe9 100644 --- a/pkgs/build-support/build-sandbox/default.nix +++ b/pkgs/build-support/build-sandbox/default.nix @@ -11,6 +11,10 @@ let pathsRuntimeVars = paths.runtimeVars or []; # Mount a dash shell in /bin/sh inside the chroot. allowBinSh = attrs.allowBinSh or false; + # Enable nix builds from within the sandbox. + # Has to write the full nix store to make the outputs accessible. + # TODO: get rid of nix & pkg-config if this is enabled (in the Makefile) + fullNixStore = attrs.fullNixStore or false; # Create code snippets for params.c to add extra_mount() calls. mkExtraMountParams = isRequired: lib.concatMapStringsSep "\n" (extra: let @@ -26,11 +30,13 @@ in stdenv.mkDerivation ({ inherit drv; + # writes files "sandbox-*" to the builder (see nix manual) exportReferencesGraph = [ "sandbox-closure" drv ] ++ lib.optionals allowBinSh [ "sandbox-binsh" dash ]; configurePhase = '' + # Reads the dependency closures and does … something? TODO: explain runtimeDeps="$(sed -ne ' p; n; n @@ -52,25 +58,36 @@ in stdenv.mkDerivation ({ echo '#include "setup.h"' > params.c echo 'bool setup_app_paths(void) {' >> params.c - for dep in $runtimeDeps; do - echo 'if (!bind_mount("'"$dep"'", true, true, true)) return false;' \ + ${if fullNixStore then '' + # /nix/var needs to be writable for nix to work inside the sandbox + echo 'if (!bind_mount("/nix/var", false, true, true)) return false;' \ + >> params.c + echo 'if (!bind_mount("/nix/store", true, true, true)) return false;' \ >> params.c - done + + '' else '' + for dep in $runtimeDeps; do + echo 'if (!bind_mount("'"$dep"'", true, true, true)) return false;' \ + >> params.c + done + ''} ${mkExtraMountParams true pathsRequired} ${mkExtraMountParams false pathsWanted} echo 'return true; }' >> params.c - echo 'bool mount_runtime_path_vars(struct query_state *qs) {' >> params.c + ${lib.optionalString (!fullNixStore) '' + echo 'bool mount_runtime_path_vars(struct query_state *qs) {' >> params.c - ${lib.concatMapStringsSep "\n" (pathvar: let - escaped = lib.escapeShellArg (lib.escape ["\\" "\""] pathvar); - fun = "mount_from_path_var"; - result = "echo 'if (!${fun}(qs, \"'${escaped}'\")) return false;'"; - in "${result} >> params.c") pathsRuntimeVars} + ${lib.concatMapStringsSep "\n" (pathvar: let + escaped = lib.escapeShellArg (lib.escape ["\\" "\""] pathvar); + fun = "mount_from_path_var"; + result = "echo 'if (!${fun}(qs, \"'${escaped}'\")) return false;'"; + in "${result} >> params.c") pathsRuntimeVars} - echo 'return true; }' >> params.c + echo 'return true; }' >> params.c + ''} ''; postInstall = '' @@ -82,8 +99,9 @@ in stdenv.mkDerivation ({ ''; nativeBuildInputs = [ pkgconfig ]; - buildInputs = [ nix boost ]; + buildInputs = [ boost nix ]; makeFlags = [ "BINDIR=${drv}/bin" ] - ++ lib.optional allowBinSh "BINSH_EXECUTABLE=${dash}/bin/dash"; + ++ lib.optional allowBinSh "BINSH_EXECUTABLE=${dash}/bin/dash" + ++ lib.optional fullNixStore "FULL_NIX_STORE=1"; } // removeAttrs attrs [ "paths" "allowBinSh" ]) diff --git a/pkgs/build-support/build-sandbox/src/Makefile b/pkgs/build-support/build-sandbox/src/Makefile index e18ec9d4..8e1218f6 100644 --- a/pkgs/build-support/build-sandbox/src/Makefile +++ b/pkgs/build-support/build-sandbox/src/Makefile @@ -1,19 +1,24 @@ BINARIES = $(wildcard $(BINDIR)/*) WRAPPERS = $(subst $(BINDIR),$(out)/bin,$(BINARIES)) +OBJECTS = path-cache.o params.o setup.o +CFLAGS = -g -Wall -std=gnu11 -DFS_ROOT_DIR=\"$(out)\" +CXXFLAGS = -g -Wall -std=c++14 `pkg-config --cflags nix-main` +LDFLAGS = -Wl,--copy-dt-needed-entries `pkg-config --libs nix-main` + +ifdef FULL_NIX_STORE +CFLAGS += -DFULL_NIX_STORE +else +OBJECTS += nix-query.o NIX_VERSION = `pkg-config --modversion nix-main | \ sed -e 's/^\([0-9]\+\)\.\([0-9][0-9]\).*/\1\2/' \ -e 's/^\([0-9]\+\)\.\([0-9]\).*/\10\2/'` +CXXFLAGS += -DNIX_VERSION=$(NIX_VERSION) +endif -OBJECTS = nix-query.o path-cache.o params.o setup.o - -CFLAGS = -g -Wall -std=gnu11 -DFS_ROOT_DIR=\"$(out)\" ifdef BINSH_EXECUTABLE CFLAGS += -DBINSH_EXECUTABLE=\"$(BINSH_EXECUTABLE)\" endif -CXXFLAGS = -g -Wall -std=c++14 `pkg-config --cflags nix-main` -CXXFLAGS += -DNIX_VERSION=$(NIX_VERSION) -LDFLAGS = -Wl,--copy-dt-needed-entries `pkg-config --libs nix-main` all: $(OBJECTS) diff --git a/pkgs/build-support/build-sandbox/src/setup.c b/pkgs/build-support/build-sandbox/src/setup.c index feafd6f6..98205710 100644 --- a/pkgs/build-support/build-sandbox/src/setup.c +++ b/pkgs/build-support/build-sandbox/src/setup.c @@ -9,7 +9,6 @@ #include <fcntl.h> #include <libgen.h> #include <limits.h> -#include <malloc.h> #include <sched.h> #include <stdbool.h> #include <stdio.h> @@ -18,8 +17,10 @@ #include <unistd.h> #include "params.h" -#include "nix-query.h" #include "path-cache.h" +#ifndef FULL_NIX_STORE +#include "nix-query.h" +#endif static path_cache cached_paths = NULL; @@ -604,6 +605,7 @@ static bool setup_binsh(const char *executable) } #endif +#ifndef FULL_NIX_STORE static bool is_dir(const char *path) { struct stat sb; @@ -663,6 +665,9 @@ bool mount_from_path_var(struct query_state *qs, const char *name) return true; } +/* `/etc/static` is a special symlink on NixOS, pointing to a storepath + of configs that have to be available at runtime for some programs + to function. So we need to mount the closure of that storepath. */ static bool setup_static_etc(struct query_state *qs) { char dest[PATH_MAX]; @@ -680,6 +685,7 @@ static bool setup_static_etc(struct query_state *qs) return mount_requisites(qs, dest); } +/* Bind-mount all necessary nix store paths. */ static bool setup_runtime_paths(void) { struct query_state *qs; @@ -702,6 +708,7 @@ static bool setup_runtime_paths(void) free_query(qs); return true; } +#endif static bool setup_runtime_debug(void) { @@ -782,8 +789,11 @@ static bool setup_chroot(void) if (!bind_mount("/tmp", false, true, false)) return false; + // We don’t need to query the nix store if we mount the full store +#ifndef FULL_NIX_STORE if (!setup_runtime_paths()) return false; +#endif if (!setup_app_paths()) return false; @@ -864,9 +874,25 @@ bool setup_sandbox(void) /* Just wait in the parent until the child exits. We need to fork because * otherwise we can't mount /proc in the right PID namespace. */ + int wstatus; if (pid > 0) { - waitpid(pid, NULL, 0); - _exit(1); + + if (waitpid(pid, &wstatus, 0) == -1) { + fputs("sandbox: waitpid failure", stderr); + _exit(EXIT_FAILURE); + } + else if (WIFEXITED(wstatus)) { + _exit(WEXITSTATUS(wstatus)); + } + else if (WIFSIGNALED(wstatus)) { + fprintf(stderr, "sandbox: killed by signal %d\n", WTERMSIG(wstatus)); + _exit(EXIT_FAILURE); + } + else { + // WIFSTOPPED, WIFCONTINUED? + fputs("sandbox: wait failed", stderr); + _exit(EXIT_FAILURE); + } } cached_paths = new_path_cache(); diff --git a/pkgs/games/gog/crosscode.nix b/pkgs/games/gog/crosscode.nix index 9e60ab08..f33cdb45 100644 --- a/pkgs/games/gog/crosscode.nix +++ b/pkgs/games/gog/crosscode.nix @@ -2,12 +2,12 @@ buildGame rec { name = "crosscode-${version}"; - version = "1.0.2"; + version = "1.1.0"; src = fetchGog { productId = 1252295864; downloadName = "en3installer0"; - sha256 = "0gd3i99g79w7nr6dnkjkpfq5s2y20dwrf706ipzkggknygmg9xad"; + sha256 = "1rqf1vlg151hxy5f9nwldmb4l3853dmvcf7fiakab8vzsmjmldlm"; }; nativeBuildInputs = [ makeWrapper ]; diff --git a/pkgs/games/gog/default.nix b/pkgs/games/gog/default.nix index 1ef58c30..f1010a00 100644 --- a/pkgs/games/gog/default.nix +++ b/pkgs/games/gog/default.nix @@ -15,13 +15,17 @@ let crosscode = callPackage ./crosscode.nix {}; dungeons3 = callPackage ./dungeons3.nix {}; epistory = callPackage ./epistory.nix { }; + homm3 = callPackage ./homm3 {}; + kingdoms-and-castles = callPackage ./kingdoms-and-castles.nix {}; overload = callPackage ./overload.nix {}; party-hard = callPackage ./party-hard.nix {}; satellite-reign = callPackage ./satellite-reign.nix {}; settlers2 = callPackage ./settlers2.nix {}; stardew-valley = callPackage ./stardew-valley.nix {}; + the-longest-journey = callPackage ./the-longest-journey {}; thimbleweed-park = callPackage ./thimbleweed-park.nix {}; war-for-the-overworld = callPackage ./war-for-the-overworld.nix {}; + warcraft2 = callPackage ./warcraft2 {}; wizard-of-legend = callPackage ./wizard-of-legend.nix {}; xeen = callPackage ./xeen.nix {}; }; diff --git a/pkgs/games/gog/fetch-gog/default.nix b/pkgs/games/gog/fetch-gog/default.nix index b49f0dab..c1d350ce 100644 --- a/pkgs/games/gog/fetch-gog/default.nix +++ b/pkgs/games/gog/fetch-gog/default.nix @@ -147,13 +147,24 @@ let } ''; - in runCommandCC "get-captcha" { - nativeBuildInputs = [ pkgconfig ]; + in stdenv.mkDerivation { + name = "get-captcha"; + + dontUnpack = true; + + nativeBuildInputs = [ pkgconfig (qt5.wrapQtAppsHook or null) ]; buildInputs = [ qt5.qtbase qt5.qtwebengine ]; - } '' - g++ $(pkg-config --libs --cflags Qt5WebEngineWidgets Qt5WebEngine) \ - -Wall -std=c++11 -o "$out" ${application} - ''; + preferLocalBuild = true; + + buildPhase = '' + g++ $(pkg-config --libs --cflags Qt5WebEngineWidgets Qt5WebEngine) \ + -Wall -std=c++11 -o get-captcha ${application} + ''; + + installPhase = '' + install -vD get-captcha "$out/bin/get-captcha" + ''; + }; mkPyStr = str: "'${stdenv.lib.escape ["'" "\\"] (toString str)}'"; @@ -177,7 +188,7 @@ let def login(self): browser = mechanicalsoup.StatefulBrowser() response = browser.open(${mkPyStr authURL}) - if "google.com/recaptcha" in response.text: + if "https://www.recaptcha.net/recaptcha" in response.text: token_url = self.login_with_captcha() else: browser.select_form('form[name="login"]') @@ -185,13 +196,19 @@ let browser['login[password]'] = ${mkPyStr password} browser.submit_selected() - auth_code = parse_qs(urlsplit(browser.get_url()).query)['code'] + query = parse_qs(urlsplit(browser.get_url()).query) + + if 'code' not in query: + sys.stderr.write( + "Unable to login with the provided GOG credentials.\n" + ) + raise SystemExit(1) token_url = "https://auth.gog.com/token?" + urlencode({ 'client_id': ${mkPyStr clientId}, 'client_secret': ${mkPyStr clientSecret}, 'grant_type': 'authorization_code', - 'code': auth_code, + 'code': query['code'], 'redirect_uri': ${mkPyStr redirectUri} }) @@ -203,7 +220,8 @@ let def login_with_captcha(self): sys.stderr.write("Solving a captcha is required to log in.\n") - sys.stderr.write("Please run " ${mkPyStr getCaptcha} " now.\n") + sys.stderr.write("Please run " ${mkPyStr getCaptcha} + "/bin/get-captcha now.\n") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sys.stderr.write("Waiting for connection") i = 0 @@ -278,6 +296,8 @@ in stdenv.mkDerivation { outputHashAlgo = "sha256"; outputHash = sha256; + preferLocalBuild = true; + nativeBuildInputs = [ curl python3Packages.tabulate python3Packages.MechanicalSoup ]; diff --git a/pkgs/games/gog/homm3/default.nix b/pkgs/games/gog/homm3/default.nix new file mode 100644 index 00000000..5aecb8f2 --- /dev/null +++ b/pkgs/games/gog/homm3/default.nix @@ -0,0 +1,97 @@ +{ stdenv, lib, buildSandbox, fetchGog, runCommand, makeWrapper, fetchFromGitHub +, cmake, pkgconfig, python3, boost, zlib, minizip, qt5 +, SDL2, SDL2_image, SDL2_mixer, SDL2_ttf +, innoextract, parallel, ffmpeg +}: + +let + data = runCommand "homm3-complete-data" rec { + version = "4.0"; + + # We need a newer version that 1.7, because GOG uses a newer archive + # format. + nativeBuildInputs = lib.singleton (innoextract.overrideAttrs (drv: { + src = fetchFromGitHub { + owner = "dscharrer"; + repo = "innoextract"; + rev = "4c61bc4da822fc89f2e05bdb2c45e6c4dd7a3673"; + sha256 = "197pr7dzlza4isssvhqhvnrr7wzc9c4b3wnnp03sxpmhviyidln1"; + }; + })) ++ [ parallel ffmpeg ]; + + data = fetchGog { + name = "setup_homm_3_complete_${version}.bin"; + productId = 1207658787; + downloadName = "en1installer1"; + sha256 = "1wfly3024yi64kaczfdca4wx5g09053dpc1gwp08w637833n4kq4"; + }; + + setup = fetchGog { + name = "setup_homm_3_complete_${version}.exe"; + productId = 1207658787; + downloadName = "en1installer0"; + sha256 = "1cwr28ml9z3iq6q9z1vs1jkbnjjrkv2m39bhqw78a5hvj43mgxza"; + }; + } '' + ln -s "$data" archive-1.bin + ln -s "$setup" archive.exe + innoextract -L -I Data -I Maps -I Mp3 archive.exe + mkdir -p "$out/music" + parallel -v ffmpeg -hide_banner -loglevel warning -i {} -acodec libvorbis \ + "$out/music/{/.}.ogg" ::: mp3/*.mp3 + mv -t "$out" data maps + ''; + + engine = stdenv.mkDerivation rec { + name = "vcmi-${version}"; + version = "20190609"; + + src = fetchFromGitHub { + owner = "vcmi"; + repo = "vcmi"; + rev = "e7bced112cf36007da8f418ba3313d2dd4b3e045"; + sha256 = "0qk0mpz3amg2kw5m99bk3qi19rwcwjj6s1lclby1ws0v8nxh2cmb"; + fetchSubmodules = true; + }; + + inherit data; + + patches = [ ./launcher-execl.patch ]; + + postPatch = '' + find -type f -name '*.cpp' -exec sed -i -e '/^ *# *include/ { + s!["<]SDL_\(ttf\|image\|mixer\)\.h[">]!<SDL2/SDL_\1.h>! + }' {} + + + sed -i -e 's/"Mp3"/"music"/' config/filesystem.json + ''; + + cmakeFlags = [ "-DCMAKE_INSTALL_LIBDIR=lib" "-DENABLE_TEST=0" ]; + enableParallelBuilding = true; + nativeBuildInputs = [ cmake pkgconfig python3 makeWrapper ]; + buildInputs = [ + boost zlib minizip SDL2 SDL2_image SDL2_mixer SDL2_ttf ffmpeg + qt5.qtbase + ]; + postInstall = let + inherit (qt5.qtbase) qtPluginPrefix; + qtPlugins = "${qt5.qtbase}/${qtPluginPrefix}"; + in '' + rm "$out/bin/vcmibuilder" + for i in "$out/bin/"*; do + rpath="$(patchelf --print-rpath "$i")" + patchelf --set-rpath "$out/lib/vcmi:$rpath" "$i" + done + + wrapProgram "$out/bin/vcmilauncher" \ + --suffix QT_PLUGIN_PATH : ${lib.escapeShellArg qtPlugins} + cp -rst "$out/share/vcmi" "$data"/* + ''; + dontStrip = true; + }; + +in buildSandbox engine { + allowBinSh = true; + paths.required = [ "$XDG_DATA_HOME/vcmi" "$XDG_CONFIG_HOME/vcmi" ]; + paths.runtimeVars = [ "LD_LIBRARY_PATH" "LOCALE_ARCHIVE" ]; +} diff --git a/pkgs/games/gog/homm3/launcher-execl.patch b/pkgs/games/gog/homm3/launcher-execl.patch new file mode 100644 index 00000000..fae0fa80 --- /dev/null +++ b/pkgs/games/gog/homm3/launcher-execl.patch @@ -0,0 +1,36 @@ +diff --git a/launcher/mainwindow_moc.cpp b/launcher/mainwindow_moc.cpp +index a07774ed2..3275af71a 100644 +--- a/launcher/mainwindow_moc.cpp ++++ b/launcher/mainwindow_moc.cpp +@@ -11,7 +11,7 @@ + #include "mainwindow_moc.h" + #include "ui_mainwindow_moc.h" + +-#include <QProcess> ++#include <unistd.h> + #include <QDir> + + #include "../lib/CConfigHandler.h" +@@ -77,19 +77,11 @@ void MainWindow::on_startGameButton_clicked() + + void MainWindow::startExecutable(QString name) + { +- QProcess process; +- +- // Start the executable +- if(process.startDetached(name)) +- { +- close(); // exit launcher +- } +- else +- { ++ if (execl(name.toLatin1().data(), "vcmiclient", nullptr) == -1) { ++ QString msg("Failed to start %1\nReason: %2"); + QMessageBox::critical(this, + "Error starting executable", +- "Failed to start " + name + "\n" +- "Reason: " + process.errorString(), ++ msg.arg(name).arg(strerror(errno)), + QMessageBox::Ok, + QMessageBox::Ok); + return; diff --git a/pkgs/games/gog/kingdoms-and-castles.nix b/pkgs/games/gog/kingdoms-and-castles.nix new file mode 100644 index 00000000..e31551cc --- /dev/null +++ b/pkgs/games/gog/kingdoms-and-castles.nix @@ -0,0 +1,14 @@ +{ buildUnity, fetchGog }: + +buildUnity { + name = "kingdoms-and-castles"; + fullName = "KingdomsAndCastles"; + saveDir = "LionShield/Kingdoms and Castles"; + version = "115r12"; + + src = fetchGog { + productId = 2067763543; + downloadName = "en3installer0"; + sha256 = "1ag03piq09z7hljcbs145hyj8z0gjcvffj99znf3mnbw2qipb7pq"; + }; +} diff --git a/pkgs/games/gog/the-longest-journey/default.nix b/pkgs/games/gog/the-longest-journey/default.nix new file mode 100644 index 00000000..9dca199a --- /dev/null +++ b/pkgs/games/gog/the-longest-journey/default.nix @@ -0,0 +1,106 @@ +{ stdenv, lib, fetchGog, fetchFromGitHub, innoextract, runCommand, buildSandbox +, SDL2, SDL2_net, freetype, libGLU_combined, glew, alsaLib +, libogg, libvorbis, xvfb_run +}: + +let + gameData = runCommand "the-longest-journey-data" rec { + version = "142"; + + # We need a newer version that 1.7, because GOG uses a newer archive + # format. + nativeBuildInputs = lib.singleton (innoextract.overrideAttrs (drv: { + src = fetchFromGitHub { + owner = "dscharrer"; + repo = "innoextract"; + rev = "4c61bc4da822fc89f2e05bdb2c45e6c4dd7a3673"; + sha256 = "197pr7dzlza4isssvhqhvnrr7wzc9c4b3wnnp03sxpmhviyidln1"; + }; + })); + + data = fetchGog { + name = "the-longest-journey-${version}.bin"; + productId = 1207658794; + downloadName = "en1installer1"; + sha256 = "08jg5snlxkzxppq37lsmbhgv9zhwnk1zr4cid5gynzq9b1048rzc"; + }; + + setup = fetchGog { + name = "the-longest-journey-${version}.exe"; + productId = 1207658794; + downloadName = "en1installer0"; + sha256 = "1h4c2bhf5mhz004r37dwdydl3rhpg1wyr4kyvxxwma7x9grxqyzc"; + }; + } '' + ln -s "$data" archive-1.bin + ln -s "$setup" archive.exe + innoextract -L -m archive.exe + mkdir "$out" + mv -t "$out" \ + game.exe gui.ini chapters.ini language.ini x.xarc \ + static global fonts [a-f0-9][a-f0-9] + ''; + + residualvm = stdenv.mkDerivation rec { + name = "residualvm-${version}"; + version = "20190611"; + + src = fetchFromGitHub { + owner = "residualvm"; + repo = "residualvm"; + rev = "ae1a7fbf6fa6bf88a7adebaedb2cd713d5ccc718"; + sha256 = "1521578jis9s3ilz0ws0msanviyqf70dp54db3d6ssfikc0w3myx"; + }; + + patches = [ ./predefined-config.patch ]; + + # Current Git version has an --enable-static option so the stdenv setup + # thinks that there is --disable-static as well, which doesn't exist. + dontDisableStatic = true; + + enableParallelBuilding = true; + buildInputs = [ + SDL2 SDL2_net freetype libGLU_combined glew alsaLib + libogg libvorbis + ]; + + configureFlags = [ "--disable-all-engines" "--enable-engine=stark" ]; + }; + + configFile = runCommand "residualvm-stark.ini" { + nativeBuildInputs = [ xvfb_run residualvm ]; + inherit gameData; + } '' + xvfb-run residualvm -p "$gameData" -a + sed -e '/^\[residualvm\]/a enable_unsupported_game_warning=false' \ + residualvm.ini > "$out" + ''; + + unsandboxed = runCommand "the-longest-journey-${gameData.version}" { + residualCmd = "${residualvm}/bin/residualvm"; + configArgs = let + mkXdg = what: fallback: extra: let + basePath = "\${XDG_${what}_HOME:-$HOME/${fallback}}"; + in "\"${basePath}/the-longest-journey${extra}\""; + in [ + "--savepath=${mkXdg "DATA" ".local/share" ""}" + "--config=${mkXdg "CONFIG" ".config" "/settings.ini"}" + ]; + inherit (stdenv) shell; + residualArgs = lib.escapeShellArgs [ "--predefined-config=${configFile}" ]; + } '' + mkdir -p "$out/bin" + cat > "$out/bin/the-longest-journey" <<EOF + #!$shell + exec $residualCmd $residualArgs $configArgs "\$@" tlj-win + EOF + chmod +x "$out/bin/the-longest-journey" + ''; + +in buildSandbox unsandboxed { + paths.required = [ + "$XDG_CONFIG_HOME/the-longest-journey" + "$XDG_DATA_HOME/the-longest-journey" + ]; + paths.runtimeVars = [ "LD_LIBRARY_PATH" ]; +} diff --git a/pkgs/games/gog/the-longest-journey/predefined-config.patch b/pkgs/games/gog/the-longest-journey/predefined-config.patch new file mode 100644 index 00000000..504e3867 --- /dev/null +++ b/pkgs/games/gog/the-longest-journey/predefined-config.patch @@ -0,0 +1,29 @@ +diff --git a/base/commandLine.cpp b/base/commandLine.cpp +index ab741917..8723fc0d 100644 +--- a/base/commandLine.cpp ++++ b/base/commandLine.cpp +@@ -425,6 +425,9 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha + DO_LONG_COMMAND("list-saves") + END_COMMAND + ++ DO_LONG_OPTION("predefined-config") ++ END_OPTION ++ + DO_OPTION('c', "config") + END_OPTION + +diff --git a/base/main.cpp b/base/main.cpp +index 2fbfc679..d74b15e5 100644 +--- a/base/main.cpp ++++ b/base/main.cpp +@@ -394,6 +394,10 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { + Common::StringMap settings; + command = Base::parseCommandLine(settings, argc, argv); + ++ // Load config file with predefined options ++ if (settings.contains("predefined-config")) ++ ConfMan.loadConfigFile(settings["predefined-config"]); ++ + // Load the config file (possibly overridden via command line): + if (settings.contains("config")) { + ConfMan.loadConfigFile(settings["config"]); diff --git a/pkgs/games/gog/warcraft2/default.nix b/pkgs/games/gog/warcraft2/default.nix new file mode 100644 index 00000000..c576439f --- /dev/null +++ b/pkgs/games/gog/warcraft2/default.nix @@ -0,0 +1,148 @@ +{ stdenv, lib, buildSandbox, writeTextFile, runCommand, fetchGog, fetchurl +, fetchFromGitHub, winePackages, xvfb_run, ffmpeg, rename + +# Dependencies for the Stratagus engine +, cmake, pkgconfig, toluapp, lua5_1, libpng, libmng, zlib, SDL, fluidsynth +, bzip2, libmikmod, libogg, libvorbis, libtheora, libGLU_combined, sqlite +}: + +let + timgm6mb = fetchurl { + name = "TimGM6mb.sf2"; + url = "https://sourceforge.net/p/mscore/code/3412/" + + "tree/trunk/mscore/share/sound/TimGM6mb.sf2?format=raw"; + sha256 = "0m68a5z43nirirq9rj2xzz6z5qpyhdwk40s83sqhr4lc09i8ndy5"; + }; + + stratagus = stdenv.mkDerivation { + name = "stratagus-${version}"; + version = "2.4.2git20190615"; + + src = fetchFromGitHub { + owner = "Wargus"; + repo = "stratagus"; + rev = "c7fc80ff7e89ab969d867121b6f679f81ea60ecb"; + sha256 = "1n39lxd8qg03kw884llcal3h95y34lys44hib2mdb3qhd5dg9a18"; + }; + + patches = [ ./xdg.patch ]; + + # Both check_version and detectPresence in addition to a bunch of functions + # in stratagus-tinyfiledialogs.h are trying to run various tools via + # /bin/sh, so let's NOP them out. + postPatch = '' + sed -i -e '/^int/!s/\(check_version\|detectPresence\)([^)]*)/1/g' \ + gameheaders/stratagus-game-launcher.h + sed -i -e '/^\(static \+\)\?int/!s/[a-zA-Z0-9]\+Present *([^)]*)/0/g' \ + gameheaders/stratagus-tinyfiledialogs.h + ''; + + NIX_CFLAGS_COMPILE = [ "-Wno-error=format-overflow" ]; + cmakeFlags = [ + "-DOpenGL_GL_PREFERENCE=GLVND" "-DENABLE_DEV=ON" + "-DGAMEDIR=${placeholder "out"}/bin" + ]; + nativeBuildInputs = [ cmake pkgconfig toluapp ]; + buildInputs = [ + toluapp lua5_1 libpng libmng zlib SDL fluidsynth bzip2 libmikmod libogg + libvorbis libtheora libGLU_combined sqlite + ]; + }; + + stormlib = stdenv.mkDerivation { + name = "stormlib-${version}"; + version = "9.22git20190615"; + + src = fetchFromGitHub { + owner = "ladislav-zezula"; + repo = "StormLib"; + rev = "2f0e0e69e6b3739d7c450ac3d38816aee45ac3c2"; + sha256 = "04f43c6bwfxiiw1kplxb3ds8g9r633y587z8ir97hrrzw5nmni3w"; + }; + + nativeBuildInputs = [ cmake ]; + buildInputs = [ zlib bzip2 ]; + }; + + wargus = stdenv.mkDerivation { + name = "wargus-${version}"; + version = "2.4.2git20190615"; + + src = fetchFromGitHub { + owner = "Wargus"; + repo = "wargus"; + rev = "932c4974dfea9805f6710f254de191e65dadb50d"; + sha256 = "13vpfd4yx43n5sqzj79km7gcv9al3mqskkij335f0c9p28rqf47v"; + }; + + # This fixes up the data path by letting it be set using an environment + # variable later in the wrapper and also hardcodes the MuseScore sound + # font. + # + # In addition, wartool.cpp contains a few lines like this: + # + # sprintf(extract, "%s.something", extract); + # + # The problem here is that sprintf() modifies the data pointed by extract + # *IN PLACE*, so this essentially truncates the contents to ".something". + # + # While it may be even better to use strncat() here, the application isn't + # critical for security, so for the sake of laziness, let's just use + # strcat() instead. + postPatch = '' + sed -i -e ' + s/^\( *# *define \+DATA_PATH\).*/\1 getenv("WARGUS_DATAPATH")/ + ' wargus.cpp + + sed -i -e 's!"[^"]*\/TimGM6mb.sf2"!"${timgm6mb}"!g' \ + wargus.cpp scripts/stratagus.lua + + sed -i -e ' + s/sprintf( *\([^,]\+\), "%s\([^"]\+\)", *\1 *)/strcat(\1, "\2")/ + ' wartool.cpp + + # XXX: Crashes the game, see https://github.com/Wargus/wargus/issues/260 + rm -r scripts/lists/campaigns/For\ the\ Motherland\ * + ''; + + cmakeFlags = [ "-DGAMEDIR=${placeholder "out"}/bin" ]; + nativeBuildInputs = [ cmake pkgconfig ]; + buildInputs = [ stratagus zlib libpng bzip2 stormlib ]; + }; + + version = "2.02.4"; + + # XXX: Unfortunately, innoextract (even Git master) doesn't support this + # archive, so let's resort to a headless wine for extraction. + gameData = runCommand "warcraft2-data-${version}" { + src = fetchGog { + name = "setup-warcraft-2-${version}.exe"; + productId = 1418669891; + downloadName = "en1installer0"; + sha256 = "1cf3c1ylgdrvkk7y25v47f66m6lp9m4wvl2aldpxzrrqdrlk34k3"; + }; + nativeBuildInputs = [ winePackages.minimal xvfb_run ffmpeg wargus rename ]; + } '' + export WINEPREFIX="$PWD" + wine wineboot.exe + xvfb-run -s '-screen 0 1024x768x24' wine "$src" /sp- /lang=english /silent + gameDir='drive_c/GOG Games/Warcraft II BNE' + find "$gameDir" -mindepth 1 -depth \ + -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \; + wartool -v -r "$gameDir" "$out" + cp -rnst "$out" ${lib.escapeShellArg wargus}/share/games/stratagus/wargus/* + ''; + +in buildSandbox (writeTextFile { + name = "warcraft2-${version}"; + destination = "/bin/warcraft2"; + executable = true; + text = '' + #!${stdenv.shell} + export WARGUS_DATAPATH=${lib.escapeShellArg gameData} + exec ${lib.escapeShellArg "${wargus}/bin/wargus"} "$@" + ''; +}) { + paths.required = [ "$XDG_DATA_HOME/wc2" ]; + paths.runtimeVars = [ "LD_LIBRARY_PATH" ]; +} diff --git a/pkgs/games/gog/warcraft2/xdg.patch b/pkgs/games/gog/warcraft2/xdg.patch new file mode 100644 index 00000000..979a86e3 --- /dev/null +++ b/pkgs/games/gog/warcraft2/xdg.patch @@ -0,0 +1,37 @@ +diff --git a/src/stratagus/parameters.cpp b/src/stratagus/parameters.cpp +index a705ba21d..8585856b0 100644 +--- a/src/stratagus/parameters.cpp ++++ b/src/stratagus/parameters.cpp +@@ -48,26 +48,13 @@ void Parameters::SetDefaultValues() + + void Parameters::SetDefaultUserDirectory() + { +-#ifdef USE_GAME_DIR +- userDirectory = StratagusLibPath; +-#elif USE_WIN32 +- userDirectory = getenv("APPDATA"); +-#else +- userDirectory = getenv("HOME"); +-#endif +- +- if (!userDirectory.empty()) { +- userDirectory += "/"; ++ const char *xdg_data_home = getenv("XDG_DATA_HOME"); ++ if (xdg_data_home == NULL) { ++ userDirectory = getenv("HOME"); ++ userDirectory += "/.local/share"; ++ } else { ++ userDirectory = xdg_data_home; + } +- +-#ifdef USE_GAME_DIR +-#elif USE_WIN32 +- userDirectory += "Stratagus"; +-#elif defined(USE_MAC) +- userDirectory += "Library/Stratagus"; +-#else +- userDirectory += ".stratagus"; +-#endif + } + + static std::string GetLocalPlayerNameFromEnv() diff --git a/pkgs/games/humblebundle/default.nix b/pkgs/games/humblebundle/default.nix index 2193ca50..5de3f40e 100644 --- a/pkgs/games/humblebundle/default.nix +++ b/pkgs/games/humblebundle/default.nix @@ -25,6 +25,7 @@ let jamestown = callPackage ./jamestown.nix {}; liads = callPackage ./liads.nix {}; megabytepunch = callPackage_i686 ./megabytepunch.nix {}; + minimetro = callPackage ./minimetro.nix {}; opus-magnum = callPackage ./opus-magnum.nix {}; owlboy = callPackage ./owlboy.nix {}; pico-8 = callPackage ./pico-8.nix {}; diff --git a/pkgs/games/humblebundle/fetch-humble-bundle/default.nix b/pkgs/games/humblebundle/fetch-humble-bundle/default.nix index 063d4a02..1340bce8 100644 --- a/pkgs/games/humblebundle/fetch-humble-bundle/default.nix +++ b/pkgs/games/humblebundle/fetch-humble-bundle/default.nix @@ -1,13 +1,20 @@ -{ stdenv, curl, cacert, writeText, fetchFromGitHub, fetchpatch -, python, pythonPackages +{ stdenv, curl, cacert, writeText, writeScript, fetchFromGitHub, fetchpatch +, python, python3, pythonPackages # Dependencies for the captcha solver -, pkgconfig, qt5, runCommandCC +, pkgconfig, qt5 , email, password }: -{ name ? null, machineName, downloadName ? "Download", suffix ? "humblebundle", md5 }: let +{ name ? null +, machineName +, downloadName ? "Download" +, suffix ? "humblebundle" +, md5 +}: + +let cafile = "${cacert}/etc/ssl/certs/ca-bundle.crt"; getCaptcha = let @@ -77,12 +84,34 @@ } ''; - in runCommandCC "get-captcha" { - nativeBuildInputs = [ pkgconfig ]; + in stdenv.mkDerivation { + name = "get-captcha"; + + dontUnpack = true; + + nativeBuildInputs = [ pkgconfig (qt5.wrapQtAppsHook or null) ]; buildInputs = [ qt5.qtbase qt5.qtwebengine ]; - } '' - g++ $(pkg-config --libs --cflags Qt5WebEngineWidgets Qt5WebEngine) \ - -Wall -std=c++11 -o "$out" ${application} + preferLocalBuild = true; + + buildPhase = '' + g++ $(pkg-config --libs --cflags Qt5WebEngineWidgets Qt5WebEngine) \ + -Wall -std=c++11 -o get-captcha ${application} + ''; + + installPhase = '' + install -vD get-captcha "$out/bin/get-captcha" + ''; + }; + + getGuard = writeScript "get-guard" '' + #!${python3.interpreter} + import socket + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.bind(('localhost', 18129)) + sock.listen(1) + with sock.accept()[0] as conn: + guard = input("Guard code: ") + conn.sendall(guard.encode()) ''; humbleAPI = pythonPackages.buildPythonPackage rec { @@ -96,6 +125,8 @@ sha256 = "1kcg42nh7sbjabim1pbqx14468pypznjy7fx2bv7dicy0sqd9b8j"; }; + patches = [ ./guard-code.patch ]; + postPatch = '' sed -i -e '/^LOGIN_URL *=/s,/login,/processlogin,' humblebundle/client.py sed -i -e '/self\.supports_canonical.*data.*supports_canonical/d' \ @@ -137,7 +168,8 @@ def login_with_captcha(hb): print >>sys.stderr, "Solving a captcha is required to log in." - print >>sys.stderr, "Please run " ${pyStr (toString getCaptcha)} " now." + print >>sys.stderr, "Please run " ${pyStr (toString getCaptcha)} \ + "/bin/get-captcha now." sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print >>sys.stderr, "Waiting for connection", i = 0 @@ -152,13 +184,41 @@ response = sock.recv(4096) sock.close() print >>sys.stderr, "Captcha solved correctly, logging in." - hb.login(${pyStr email}, ${pyStr password}, recaptcha_response=response) + api_login(hb, recaptcha_response=response) + + def login_with_guard(hb, skip_code): + print >>sys.stderr, "A guard code has been sent to your email address." + print >>sys.stderr, "Please run " ${pyStr (toString getGuard)} " now." + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + print >>sys.stderr, "Waiting for connection", + # XXX: DRY! + i = 0 + while sock.connect_ex(("127.0.0.1", 18129)) != 0: + time.sleep(0.1) + if i % 10 == 0: + sys.stderr.write('.') + sys.stderr.flush() + i += 1 + print >>sys.stderr, " connected." + print >>sys.stderr, "Waiting for guard code..." + response = sock.recv(4096) + sock.close() + print >>sys.stderr, "Guard code supplied, logging in." + api_login(hb, captcha_skip_code=skip_code, guard_code=response) + + def api_login(hb, recaptcha_response=None, + captcha_skip_code=None, guard_code=None): + try: + hb.login(${pyStr email}, ${pyStr password}, + recaptcha_response=recaptcha_response, + captcha_skip_code=captcha_skip_code, guard_code=guard_code) + except humblebundle.exceptions.HumbleCaptchaException: + login_with_captcha(hb) + except humblebundle.exceptions.HumbleGuardRequiredException as e: + login_with_guard(hb, e.captcha_skip_code) hb = humblebundle.HumbleApi() - try: - hb.login(${pyStr email}, ${pyStr password}) - except humblebundle.exceptions.HumbleCaptchaException: - login_with_captcha(hb) + api_login(hb) products = dict(get_products(hb)) dstruct = find_download(products) @@ -183,6 +243,7 @@ in stdenv.mkDerivation { outputHashAlgo = "md5"; outputHash = md5; + preferLocalBuild = true; buildInputs = [ python humbleAPI ]; buildCommand = '' diff --git a/pkgs/games/humblebundle/fetch-humble-bundle/guard-code.patch b/pkgs/games/humblebundle/fetch-humble-bundle/guard-code.patch new file mode 100644 index 00000000..f17928ae --- /dev/null +++ b/pkgs/games/humblebundle/fetch-humble-bundle/guard-code.patch @@ -0,0 +1,121 @@ +diff --git a/humblebundle/client.py b/humblebundle/client.py +index fbc31c9..44184a1 100644 +--- a/humblebundle/client.py ++++ b/humblebundle/client.py +@@ -75,7 +75,9 @@ class HumbleApi(object): + """ + + @callback +- def login(self, username, password, authy_token=None, recaptcha_challenge=None, recaptcha_response=None, ++ def login(self, username, password, authy_token=None, ++ recaptcha_challenge=None, recaptcha_response=None, ++ guard_code=None, captcha_skip_code=None, + *args, **kwargs): + """ + Login to the Humble Bundle API. The response sets the _simpleauth_sess cookie which is stored in the session +@@ -87,6 +89,8 @@ class HumbleApi(object): + :type authy_token: integer or str + :param str recaptcha_challenge: (optional) The challenge signed by Humble Bundle's public key from reCAPTCHA + :param str recaptcha_response: (optional) The plaintext solved CAPTCHA ++ :param str guard_code: (optional) The guard code sent via email ++ :param str captcha_skip_code: (optional) A token to skip the CAPTCHA + :param list args: (optional) Extra positional args to pass to the request + :param dict kwargs: (optional) Extra keyword args to pass to the request. If a data dict is supplied a key + collision with any of the above params will resolved in favor of the supplied param +@@ -108,7 +112,9 @@ class HumbleApi(object): + 'password': password, + 'authy-token': authy_token, + 'recaptcha_challenge_field': recaptcha_challenge, +- 'recaptcha_response_field': recaptcha_response} ++ 'recaptcha_response_field': recaptcha_response, ++ 'guard': guard_code, ++ 'captcha-skip-code': captcha_skip_code} + kwargs.setdefault('data', {}).update({k: v for k, v in default_data.items() if v is not None}) + + response = self._request('POST', LOGIN_URL, *args, **kwargs) +diff --git a/humblebundle/exceptions.py b/humblebundle/exceptions.py +index 9041219..fe4eeaf 100644 +--- a/humblebundle/exceptions.py ++++ b/humblebundle/exceptions.py +@@ -9,7 +9,7 @@ __copyright__ = "Copyright 2014, Joel Pedraza" + __license__ = "MIT" + + __all__ = ['HumbleException', 'HumbleResponseException', 'HumbleAuthenticationException', 'HumbleCredentialException', +- 'HumbleCaptchaException', 'HumbleTwoFactorException', 'HumbleParseException'] ++ 'HumbleCaptchaException', 'HumbleTwoFactorException', 'HumbleGuardRequiredException', 'HumbleParseException'] + + from requests import RequestException + +@@ -38,6 +38,7 @@ class HumbleAuthenticationException(HumbleResponseException): + def __init__(self, *args, **kwargs): + self.captcha_required = kwargs.pop('captcha_required', None) + self.authy_required = kwargs.pop('authy_required', None) ++ self.captcha_skip_code = kwargs.pop('captcha_skip_code', None) + super(HumbleAuthenticationException, self).__init__(*args, **kwargs) + + +@@ -62,6 +63,13 @@ class HumbleTwoFactorException(HumbleAuthenticationException): + pass + + ++class HumbleGuardRequiredException(HumbleAuthenticationException): ++ """ ++ A guard code is required ++ """ ++ pass ++ ++ + class HumbleParseException(HumbleResponseException): + """ + An error occurred while parsing +diff --git a/humblebundle/handlers.py b/humblebundle/handlers.py +index 36fc6e1..a8acebf 100644 +--- a/humblebundle/handlers.py ++++ b/humblebundle/handlers.py +@@ -64,29 +64,42 @@ def login_handler(client, response): + success = data.get('success', None) + if success is True: + return True ++ if data.get('goto', None) is not None: ++ return True + + captcha_required = data.get('captcha_required') + authy_required = data.get('authy_required') ++ captcha_skip_code = data.get('skip_code', [None])[0] ++ ++ guard = data.get('humble_guard_required', False) ++ if guard: ++ raise HumbleGuardRequiredException('Guard code required', request=response.request, response=response, ++ captcha_required=captcha_required, authy_required=authy_required, ++ captcha_skip_code=captcha_skip_code) + + errors, error_msg = get_errors(data) + if errors: + captcha = errors.get('captcha') + if captcha: + raise HumbleCaptchaException(error_msg, request=response.request, response=response, +- captcha_required=captcha_required, authy_required=authy_required) ++ captcha_required=captcha_required, authy_required=authy_required, ++ captcha_skip_code=captcha_skip_code) + + username = errors.get('username') + if username: + raise HumbleCredentialException(error_msg, request=response.request, response=response, +- captcha_required=captcha_required, authy_required=authy_required) ++ captcha_required=captcha_required, authy_required=authy_required, ++ captcha_skip_code=captcha_skip_code) + + authy_token = errors.get("authy-token") + if authy_token: + raise HumbleTwoFactorException(error_msg, request=response.request, response=response, +- captcha_required=captcha_required, authy_required=authy_required) ++ captcha_required=captcha_required, authy_required=authy_required, ++ captcha_skip_code=captcha_skip_code) + + raise HumbleAuthenticationException(error_msg, request=response.request, response=response, +- captcha_required=captcha_required, authy_required=authy_required) ++ captcha_required=captcha_required, authy_required=authy_required, ++ captcha_skip_code=captcha_skip_code) + + + def gamekeys_handler(client, response): diff --git a/pkgs/games/humblebundle/minimetro.nix b/pkgs/games/humblebundle/minimetro.nix new file mode 100644 index 00000000..a5c48775 --- /dev/null +++ b/pkgs/games/humblebundle/minimetro.nix @@ -0,0 +1,15 @@ +{ buildUnity, fetchHumbleBundle }: + +buildUnity rec { + name = "minimetro"; + version = "39"; + fullName = "Mini Metro"; + saveDir = "Dinosaur Polo Club/Mini Metro"; + + src = fetchHumbleBundle { + name = "MiniMetro-release-39-linux.tar.gz"; + machineName = "minimetro_linux"; + downloadName = "Download"; + md5 = "3e7afefbcc68b6295821394e31f5e48b"; + }; +} diff --git a/pkgs/games/itch/fetch-itch/default.nix b/pkgs/games/itch/fetch-itch/default.nix index 3700f5c6..121868be 100644 --- a/pkgs/games/itch/fetch-itch/default.nix +++ b/pkgs/games/itch/fetch-itch/default.nix @@ -69,6 +69,7 @@ in stdenv.mkDerivation { SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt"; + preferLocalBuild = true; nativeBuildInputs = [ python3Packages.python ]; buildCommand = '' diff --git a/pkgs/games/steam/fetchsteam/default.nix b/pkgs/games/steam/fetchsteam/default.nix index 5c1faf55..646e0a14 100644 --- a/pkgs/games/steam/fetchsteam/default.nix +++ b/pkgs/games/steam/fetchsteam/default.nix @@ -79,6 +79,7 @@ let in with stdenv.lib; runCommand "${name}-src" { buildInputs = [ DepotDownloader ]; inherit username password appId depotId manifestId; + preferLocalBuild = true; outputHashAlgo = "sha256"; outputHash = sha256; outputHashMode = "recursive"; diff --git a/pkgs/profpatsch/default.nix b/pkgs/profpatsch/default.nix index a4378ecf..dc746c2e 100644 --- a/pkgs/profpatsch/default.nix +++ b/pkgs/profpatsch/default.nix @@ -5,11 +5,25 @@ let # wrapper for execlineb that doesn’t need the execline commands # in PATH to work (making them appear like “builtins”) + # TODO: upstream into nixpkgs + # TODO: the grep could be nicer execlineb-with-builtins = let eldir = "${pkgs.execline}/bin"; in pkgs.writeScriptBin "execlineb" '' #!${eldir}/execlineb -s0 + # appends the execlineb bin dir to PATH if not yet in PATH ${eldir}/define eldir ${eldir} + ''${eldir}/ifelse + { + # since this is nix, we can grep for the execline drv hash in PATH + # to see whether it’s already in there + ''${eldir}/pipeline + { ${pkgs.coreutils}/bin/printenv PATH } + ${pkgs.gnugrep}/bin/grep --quiet "${eldir}" + } + # it’s there already + { ''${eldir}/execlineb $@ } + # not there yet, add it ''${eldir}/importas oldpath PATH ''${eldir}/export PATH "''${eldir}:''${oldpath}" ''${eldir}/execlineb $@ @@ -46,6 +60,52 @@ let allowSubstitutes = false; }) cmd; + testing = import ./testing { + inherit stdenv lib; + inherit (runExeclineFns) runExecline; + inherit (pkgs) runCommand; + bin = bins pkgs.s6PortableUtils [ "s6-touch" "s6-echo" ]; + }; + + runExeclineFns = + # todo: factor out calling tests + let + it = import ./execline/run-execline.nix { + bin = (bins execlineb-with-builtins [ "execlineb" ]) + // (bins pkgs.execline [ "redirfd" "importas" "exec" ]); + inherit stdenv lib; + }; + itLocal = name: args: execline: + it name (args // { + derivationArgs = args.derivationArgs or {} // { + preferLocalBuild = true; + allowSubstitutes = false; + }; + }) execline; + + tests = import ./execline/run-execline-tests.nix { + # can’t use runExeclineLocal in the tests, + # because it is tested by the tests (well, it does + # work, but then you have to run the tests every time) + runExecline = it; + inherit (testing) drvSeqL; + inherit (pkgs) coreutils; + inherit stdenv; + bin = (bins execlineb-with-builtins [ "execlineb" ]) + // (bins pkgs.execline [ + { use = "if"; as = "execlineIf"; } + "redirfd" "importas" + ]) + // (bins pkgs.s6PortableUtils + [ "s6-cat" "s6-grep" "s6-touch" "s6-test" "s6-chmod" ]); + }; + in { + runExecline = it; + runExeclineLocal = name: args: execline: + testing.drvSeqL tests (itLocal name args execline); + }; + + in rec { inherit (nixperiments) # filterSource by parsing a .gitignore file @@ -60,10 +120,11 @@ in rec { json2json json2string; backlight = callPackage ./backlight { inherit (pkgs.xorg) xbacklight; }; - display-infos = callPackage ./display-infos {}; + display-infos = callPackage ./display-infos { inherit sfttime; }; git-commit-index = callPackage ./git-commit-index { inherit script runCommandLocal; }; nix-http-serve = callPackage ./nix-http-serve {}; nman = callPackage ./nman {}; + sfttime = callPackage ./sfttime {}; show-qr-code = callPackage ./show-qr-code {}; warpspeed = callPackage ./warpspeed { inherit (pkgs.haskellPackages) ghcWithPackages; @@ -90,35 +151,8 @@ in rec { ]; }); - runExecline = - # todo: factor out calling tests - let - it = import ./execline/run-execline.nix { - bin = (bins execlineb-with-builtins [ "execlineb" ]) - // (bins pkgs.execline [ "redirfd" "importas" "exec" ]); - inherit stdenv; - }; - tests = import ./execline/run-execline-tests.nix { - runExecline = it; - inherit (testing) drvSeqL; - inherit (pkgs) coreutils; - inherit stdenv; - bin = (bins execlineb-with-builtins [ "execlineb" ]) - // (bins pkgs.execline [ - { use = "if"; as = "execlineIf"; } - "redirfd" "importas" - ]) - // (bins pkgs.s6PortableUtils - [ "s6-cat" "s6-grep" "s6-touch" "s6-test" "s6-chmod" ]); - }; - in tests; - - - testing = import ./testing { - inherit stdenv lib runExecline; - inherit (pkgs) runCommand; - bin = bins pkgs.s6PortableUtils [ "s6-touch" "s6-echo" ]; - }; + inherit (runExeclineFns) + runExecline runExeclineLocal; symlink = pkgs.callPackage ./execline/symlink.nix { inherit runExecline; diff --git a/pkgs/profpatsch/display-infos/default.nix b/pkgs/profpatsch/display-infos/default.nix index d213241c..b626e844 100644 --- a/pkgs/profpatsch/display-infos/default.nix +++ b/pkgs/profpatsch/display-infos/default.nix @@ -1,8 +1,8 @@ -{ lib, runCommand, python3, libnotify }: +{ lib, runCommand, writeText, python3, libnotify, bc, sfttime }: let name = "display-infos-0.1.0"; - script = builtins.toFile (name + "-script") '' + script = writeText (name + "-script") '' #!@python3@ import sys @@ -11,20 +11,53 @@ let import os.path as path import statistics as st + def readint(fn): + with open(fn, 'r') as f: + return int(f.read()) + + def seconds_to_sft(secs): + p = sub.Popen(["@bc@", "-l"], stdin=sub.PIPE, stdout=sub.PIPE) + (sft, _) = p.communicate(input="scale=2; obase=16; {} / 86400\n".format(secs).encode()) + p.terminate() + return str(sft.strip().decode()) + + charging = readint("/sys/class/power_supply/AC/online") + full = 0 now = 0 + # this is "to charged" if charging and "to empty" if not + seconds_remaining = 0 for bat in glob.iglob("/sys/class/power_supply/BAT*"): - def readint(fn): - with open(fn, 'r') as f: - return int(f.read()) + # these files might be different for different ACPI/battery providers + # see the full list in acpi.c of the acpi(1) tool + # unit: who knows full += readint(path.join(bat, "energy_full")) now += readint(path.join(bat, "energy_now" )) + # in unit?/hours, hopefully the same unit as above + # ACPI is a garbage fire + current_rate = readint(path.join(bat, "power_now")) + + if current_rate == 0: + continue + elif charging: + seconds_remaining += 3600 * (full - now) / current_rate + else: + seconds_remaining += 3600 * now / current_rate bat = round( now/full, 2 ) + ac = "🗲 " if charging else "" + sft_remaining = seconds_to_sft(seconds_remaining) date = sub.run(["date", "+%d.%m. %a %T"], stdout=sub.PIPE).stdout.strip().decode() - notify = "BAT: {}% | {}".format(int(bat*100), date) - sub.run(["@notify-send@", notify]) + sftdate = sub.run(["@sfttime@"], stdout=sub.PIPE).stdout.strip().decode() + notify = "BAT: {percent}% {ac}{charge}| {date} | {sftdate}".format( + percent = int(bat*100), + ac = ac, + charge = "{} ".format(sft_remaining) if seconds_remaining else "", + date = date, + sftdate = sftdate + ) + print(notify) ''; in @@ -33,6 +66,7 @@ in } '' substitute ${script} script \ --replace "@python3@" "${getBin python3}/bin/python3" \ - --replace "@notify-send@" "${getBin libnotify}/bin/notify-send" + --replace "@bc@" "${getBin bc}/bin/bc" \ + --replace "@sfttime@" "${getBin sfttime}/bin/sfttime" install -D script $out/bin/display-infos '' diff --git a/pkgs/profpatsch/execline/escape.nix b/pkgs/profpatsch/execline/escape.nix new file mode 100644 index 00000000..d9a0be0c --- /dev/null +++ b/pkgs/profpatsch/execline/escape.nix @@ -0,0 +1,30 @@ +{ lib }: +let + # replaces " and \ to \" and \\ respectively and quote with " + # e.g. + # a"b\c -> "a\"b\\c" + # a\"bc -> "a\\\"bc" + # TODO upsteam into nixpkgs + escapeExeclineArg = arg: + ''"${builtins.replaceStrings [ ''"'' ''\'' ] [ ''\"'' ''\\'' ] (toString arg)}"''; + + # Escapes an execline (list of execline strings) to be passed to execlineb + # Give it a nested list of strings. Nested lists are interpolated as execline + # blocks ({}). + # Everything is quoted correctly. + # + # Example: + # escapeExecline [ "if" [ "somecommand" ] "true" ] + # == ''"if" { "somecommand" } "true"'' + escapeExecline = execlineList: lib.concatStringsSep " " + (let + go = arg: + if builtins.isString arg then [(escapeExeclineArg arg)] + else if lib.isDerivation arg then [(escapeExeclineArg arg)] + else if builtins.isList arg then [ "{" ] ++ builtins.concatMap go arg ++ [ "}" ] + else abort "escapeExecline can only hande nested lists of strings, was ${lib.generators.toPretty {} arg}"; + in builtins.concatMap go execlineList); + +in { + inherit escapeExecline; +} diff --git a/pkgs/profpatsch/execline/run-execline-tests.nix b/pkgs/profpatsch/execline/run-execline-tests.nix index ebfdeb20..c3f534cc 100644 --- a/pkgs/profpatsch/execline/run-execline-tests.nix +++ b/pkgs/profpatsch/execline/run-execline-tests.nix @@ -2,26 +2,24 @@ # https://www.mail-archive.com/skaware@list.skarnet.org/msg01256.html , coreutils }: -# TODO: run all of these locally! runExeclineLocal - let # lol - writeScript = name: script: runExecline { - inherit name; + writeScript = name: script: runExecline name { derivationArgs = { inherit script; passAsFile = [ "script" ]; + preferLocalBuild = true; + allowSubstitutes = false; }; - execline = '' - importas -ui s scriptPath - importas -ui out out - foreground { - ${coreutils}/bin/mv $s $out - } - ${bin.s6-chmod} 0755 $out - ''; - }; + } [ + "importas" "-ui" "s" "scriptPath" + "importas" "-ui" "out" "out" + "foreground" [ + "${coreutils}/bin/mv" "$s" "$out" + ] + "${bin.s6-chmod}" "0755" "$out" + ]; # execline block of depth 1 block = args: builtins.map (arg: " ${arg}") args ++ [ "" ]; @@ -30,7 +28,7 @@ let # in the given file. Does not use runExecline, because # that should be tested after all. fileHasLine = line: file: derivation { - name = "file-${file.name}-has-line"; + name = "run-execline-test-file-${file.name}-has-line"; inherit (stdenv) system; builder = bin.execlineIf; args = @@ -43,41 +41,49 @@ let bin.importas "-ui" "out" "out" bin.s6-touch "$out" ]; + preferLocalBuild = true; + allowSubstitutes = false; }; # basic test that touches out - basic = runExecline { - name = "basic"; - execline = '' - importas -ui out out - ${bin.s6-touch} $out - ''; - }; + basic = runExecline "run-execline-test-basic" { + derivationArgs = { + preferLocalBuild = true; + allowSubstitutes = false; + }; + } [ + "importas" "-ui" "out" "out" + "${bin.s6-touch}" "$out" + ]; # whether the stdin argument works as intended - stdin = fileHasLine "foo" (runExecline { - name = "stdin"; + stdin = fileHasLine "foo" (runExecline "run-execline-test-stdin" { stdin = "foo\nbar\nfoo"; - execline = '' - importas -ui out out + derivationArgs = { + preferLocalBuild = true; + allowSubstitutes = false; + }; + } [ + "importas" "-ui" "out" "out" # this pipes stdout of s6-cat to $out # and s6-cat redirects from stdin to stdout - redirfd -w 1 $out ${bin.s6-cat} - ''; - }); + "redirfd" "-w" "1" "$out" bin.s6-cat + ]); - wrapWithVar = runExecline { - name = "wrap-with-var"; + wrapWithVar = runExecline "run-execline-test-wrap-with-var" { builderWrapper = writeScript "var-wrapper" '' #!${bin.execlineb} -S0 export myvar myvalue $@ ''; - execline = '' - importas -ui v myvar - if { ${bin.s6-test} myvalue = $v } - importas out out - ${bin.s6-touch} $out - ''; - }; + derivationArgs = { + preferLocalBuild = true; + allowSubstitutes = false; + }; + } [ + "importas" "-ui" "v" "myvar" + "if" [ bin.s6-test "myvalue" "=" "$v" ] + "importas" "out" "out" + bin.s6-touch "$out" + ]; -in args: drvSeqL [ basic stdin wrapWithVar ] (runExecline args) +in [ basic stdin wrapWithVar ] diff --git a/pkgs/profpatsch/execline/run-execline.nix b/pkgs/profpatsch/execline/run-execline.nix index dbc6f4fd..2efe43d6 100644 --- a/pkgs/profpatsch/execline/run-execline.nix +++ b/pkgs/profpatsch/execline/run-execline.nix @@ -1,15 +1,18 @@ -{ stdenv, bin }: -{ name -# the execline script as string -, execline +{ stdenv, bin, lib }: +name: +{ # a string to pass as stdin to the execline script -, stdin ? "" +stdin ? "" # a program wrapping the acutal execline invocation; # should be in Bernstein-chaining style , builderWrapper ? bin.exec # additional arguments to pass to the derivation , derivationArgs ? {} }: +# the execline script as a nested list of string, +# representing the blocks; +# see docs of `escapeExecline`. + execline: # those arguments can’t be overwritten assert !derivationArgs ? system; @@ -18,6 +21,7 @@ assert !derivationArgs ? builder; assert !derivationArgs ? args; derivation (derivationArgs // { + # TODO: what about cross? inherit (stdenv) system; inherit name; @@ -26,7 +30,10 @@ derivation (derivationArgs // { # to pass the script and stdin as envvar; # this might clash with another passed envar, # so we give it a long & unique name - _runExeclineScript = execline; + _runExeclineScript = + let + escape = (import ./escape.nix { inherit lib; }); + in escape.escapeExecline execline; _runExeclineStdin = stdin; passAsFile = [ "_runExeclineScript" diff --git a/pkgs/profpatsch/execline/symlink.nix b/pkgs/profpatsch/execline/symlink.nix index ca8684d2..c6a311d8 100644 --- a/pkgs/profpatsch/execline/symlink.nix +++ b/pkgs/profpatsch/execline/symlink.nix @@ -11,9 +11,7 @@ let "${toString (builtins.stringLength s)}:${s},"; in -runExecline { - inherit name; - +runExecline name { derivationArgs = { pathTuples = lib.concatMapStrings ({dest, orig}: toNetstring @@ -23,28 +21,26 @@ runExecline { # bah! coreutils just for cat :( PATH = lib.makeBinPath [ s6-portable-utils ]; }; +} [ + "importas" "-ui" "p" "pathTuplesPath" + "importas" "-ui" "out" "out" + "forbacktickx" "-d" "" "destorig" [ "${coreutils}/bin/cat" "$p" ] + "importas" "-ui" "do" "destorig" + "multidefine" "-d" "" "$do" [ "destsuffix" "orig" ] + "define" "dest" ''''${out}/''${destsuffix}'' - execline = '' - importas -ui p pathTuplesPath - importas -ui out out - forbacktickx -d "" destorig { ${coreutils}/bin/cat $p } - importas -ui do destorig - multidefine -d "" $do { destsuffix orig } - define dest ''${out}/''${destsuffix} - - # this call happens for every file, not very efficient - foreground { - backtick -n d { s6-dirname $dest } - importas -ui d d - s6-mkdir -p $d - } + # this call happens for every file, not very efficient + "foreground" [ + "backtick" "-n" "d" [ "s6-dirname" "$dest" ] + "importas" "-ui" "d" "d" + "s6-mkdir" "-p" "$d" + ] - ifthenelse { s6-test -L $orig } { - backtick -n res { s6-linkname -f $orig } - importas -ui res res - s6-ln -fs $res $dest - } { - s6-ln -fs $orig $dest - } - ''; -} + "ifthenelse" [ "s6-test" "-L" "$orig" ] [ + "backtick" "-n" "res" [ "s6-linkname" "-f" "$orig" ] + "importas" "-ui" "res" "res" + "s6-ln" "-fs" "$res" "$dest" + ] [ + "s6-ln" "-fs" "$orig" "$dest" + ] +] diff --git a/pkgs/profpatsch/nman/default.nix b/pkgs/profpatsch/nman/default.nix index b9b967cf..bbf4f00f 100644 --- a/pkgs/profpatsch/nman/default.nix +++ b/pkgs/profpatsch/nman/default.nix @@ -6,7 +6,9 @@ runCommandNoCC "nman" { license = licenses.gpl3; }; } '' - ${lib.getBin go}/bin/go build -o nman ${./nman.go} + mkdir cache + env GOCACHE="$PWD/cache" \ + ${lib.getBin go}/bin/go build -o nman ${./nman.go} install -D nman $out/bin/nman '' diff --git a/pkgs/profpatsch/sfttime/default.nix b/pkgs/profpatsch/sfttime/default.nix new file mode 100644 index 00000000..29d9170b --- /dev/null +++ b/pkgs/profpatsch/sfttime/default.nix @@ -0,0 +1,14 @@ +{ stdenv, makeWrapper, bc }: + +stdenv.mkDerivation { + name = "sfttime"; + + phases = [ "installPhase" "fixupPhase" ]; + buildInputs = [ makeWrapper ]; + + installPhase = '' + install -D ${./sfttime.sh} $out/bin/sfttime + wrapProgram $out/bin/sfttime \ + --prefix PATH : ${stdenv.lib.makeBinPath [ bc ]} + ''; +} diff --git a/pkgs/profpatsch/sfttime/sfttime.sh b/pkgs/profpatsch/sfttime/sfttime.sh new file mode 100755 index 00000000..949341b7 --- /dev/null +++ b/pkgs/profpatsch/sfttime/sfttime.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash +# this script was created in 3BBE.81[sft]. +# usage: +# to convert to sfttime: +# $0 [c date] [digitcount] [nodate] +# if date is given, converts the given date to sfttime. +# if date is not given, converts the current date to sfttime. +# digitcount specifies the accuracy for the time part. +# nodate hides the date part. +# to convert from sfttime: +# $0 r sfttime [unix] +# converts the given sfttime to 'standard' time. +# if 'unix' is provided, the output will be in unix time. +# to show info about sfttime units +# $0 i [[sft]]$num +# displays name of unit [sft]$num, as well as it's value +# in both days and 'standard' units. + +SFT_EPOCH_UNIX=49020 + +case $1 in + "c") + unixtime=$(date --date="$2" +%s.%N) + shift + shift + mode=fw + ;; + "r") + shift + sfttime=$1 + if [[ $sfttime =~ ^([0-9A-F]*(.[0-9A-F]+)?)(\[[sS][fF][tT]\])?$ ]] && [[ $sfttime ]]; then + sfttime=${BASH_REMATCH[1]} + else + echo "error" 2>&1 + exit 1 + fi + shift + mode=bw + ;; + "i") + shift + inforeq=$1 + if [[ $inforeq =~ ^(\[[sS][fF][tT]\])?(-?[0-9]+)$ ]]; then + inforeq=${BASH_REMATCH[2]} + let inforeq=$inforeq + mode=in + elif [[ $inforeq =~ ^(\[[sS][fF][tT]\])?[eE][pP][oO][cC][hH]$ ]]; then + echo "[sft]epoch:" + echo "unix time $SFT_EPOCH_UNIX" + echo "1970-01-01 13:37:00 UTC" + exit 0 + else + echo "error" 2>&1 + exit 1 + fi + shift + mode=in + ;; + *) + unixtime=$(date +%s.%N) + mode=fw + ;; +esac + +case $mode in + "fw") + sfttime=$(echo "obase=16; ($unixtime-$SFT_EPOCH_UNIX)/86400" | bc -l) + if [[ $1 -ge 1 ]]; then + digits=$1 + shift + elif [[ ! $1 ]] || [[ $1 == nodate ]]; then + digits=3 + else + digits=0 + fi + + if [[ $sfttime =~ ^([0-9A-F]+)[.]([0-9A-F]{$digits}).*$ ]]; then + date=${BASH_REMATCH[1]} + time=${BASH_REMATCH[2]} + else + echo "Error" &1>2 + exit 1 + fi + + if [[ $digits -eq 0 ]]; then + echo "$date[sft]" + else + if [[ $1 == nodate ]]; then + echo ".$time[sft]" + shift + else + echo "$date.$time[sft]" + fi + fi + ;; + "bw") + unixtime=$(echo "ibase=16; $sfttime*15180+BF7C" | bc -l) + case $1 in + unix) + shift + echo $unixtime + ;; + *) + date --date="1970-01-01 $unixtime sec" + ;; + esac + ;; + "in") + name="[sft]$inforeq" + case $inforeq in + -4) newname="[sft]tick";; + -3) newname="[sft]tentacle";; + -2) newname="[sft]schinken";; + -1) newname="[sft]major";; + 0) newname="day";; + 1) newname="[sft]vergil";; + 2) newname="[sft]stallman";; + 3) newname="[sft]odin";; + esac + if [[ $newname ]]; then + echo "alternative name for $name: $newname" + name="$newname" + fi + one="1 $name" + echo "$one after [sft]epoch:" + sfttime=$(echo "obase=16; 16^$inforeq" | bc -l)[sft] + echo $sfttime + echo "time equivalent of $one:" + echo "the duration of $(echo 794243384928000*16^$inforeq | bc -l) periods of the radiation corresponding to the transition between the two hyperfine levels of the ground state of the caesium 133 atom" + + echo "standard time units equivalent:" + seconds=$(echo "86400*16^$inforeq" | bc -l) + if [[ $(echo "$seconds < 60" | bc -l) == 1 ]]; then + echo "$seconds seconds" + elif [[ $(echo "$seconds < 3600" | bc -l) == 1 ]]; then + echo "$(echo $seconds/60 | bc -l) minutes" + elif [[ $(echo "$seconds < 86400" | bc -l) == 1 ]]; then + echo "$(echo $seconds/3600 | bc -l) hours" + elif [[ $(echo "$seconds < 86400*365.2425" | bc -l) == 1 ]]; then + echo "$(echo $seconds/86400 | bc -l) days" + else + echo "$(echo $seconds/86400/365.2425 | bc -l) years" + fi + ;; +esac diff --git a/pkgs/profpatsch/utils-hs/default.nix b/pkgs/profpatsch/utils-hs/default.nix index 423feb03..9ddd50ec 100644 --- a/pkgs/profpatsch/utils-hs/default.nix +++ b/pkgs/profpatsch/utils-hs/default.nix @@ -53,11 +53,23 @@ let rev = "e7efbb4f0624e86109acd818942c8cd18a7d9d3d"; sha256 = "0dismb9vl5fxynasc2kv5baqyzp6gpyybmd5p9g1hlcq3p7pfi24"; }; + broken = false; buildDepends = old.buildDepends or [] ++ (with hself; [ dependent-sum prettyprinter (hlib.doJailbreak ref-tf) ]); }); - } );# // (import /home/philip/kot/dhall/overlay.nix { inherit haskell fetchFromGitHub; } hself hsuper)); + + dhall-nix = hlib.justStaticExecutables (hlib.overrideCabal hsuper.dhall-nix (old: { + src = fetchFromGitHub { + owner = "Profpatsch"; + repo = "dhall-nix"; + # manual update to dhall @0.19 + rev = "feae0ce5b2ecf4daeeae15c39f427f126c33da7c"; + sha256 = "1kdsbnj681lf65dsdclcrzj4cab1hh0v22n2140386zvwmawyp6r"; + }; + broken = false; + })); + }); }; haskellDrv = { name, subfolder, deps }: hps.mkDerivation { diff --git a/pkgs/profpatsch/xmonad/DhallTypedInput.hs b/pkgs/profpatsch/xmonad/DhallTypedInput.hs new file mode 100644 index 00000000..18c32b22 --- /dev/null +++ b/pkgs/profpatsch/xmonad/DhallTypedInput.hs @@ -0,0 +1,232 @@ +{-# language RecordWildCards, NamedFieldPuns, OverloadedStrings, ScopedTypeVariables, KindSignatures, DataKinds, ScopedTypeVariables, RankNTypes, GADTs, TypeApplications, AllowAmbiguousTypes, LambdaCase #-} +{- Exports the `inputWithTypeArgs` function, which is able to read dhall files of the normalized form + +@ +\(CustomType: Type) -> +\(AnotherType: Type) -> +… +@ + +and set their actual representation on the Haskell side: + +This has various advantages: + +- dhall files still type check & normalize with the normal dhall + tooling, they are standalone (and the types can be instantiated from + dhall as well without any workarounds) +- It can be used like the default `input` function, no injection of + custom symbols in the Normalizer is reqired +- Brings this style of dhall integration to Haskell, where it was only + feasible in nix before, because that is untyped + +The dhall types can be instantiated by every Haskell type that has an +`Interpret` instance. The “name” of the type lambda variable is +compared on the Haskell side with a type-level string that the user +provides, to prevent mixups. + +TODO: +- Improve error messages (!) +- Provide a way to re-use the type mapping on the Haskell side, so + that the returned values are not just the normal `Interpret` types, + but the mapped ones (with name phantom type) +-} +module DhallTypedInput +( inputWithTypeArgs, TypeArg(..), TypeArgError(..), TypeArgEx(..), typeArg +) +where + +import Control.Monad.Trans.State.Strict as State +import Data.List (foldl') +import Control.Exception (Exception) +import qualified Control.Exception +import qualified Data.Text as Text + +import GHC.TypeLits (KnownSymbol, Symbol, symbolVal) +import Data.Proxy (Proxy(Proxy)) + +import Dhall (Type(..), InvalidType(..), InputSettings(..), EvaluateSettings(..), rootDirectory, startingContext, normalizer, standardVersion, sourceName, defaultEvaluateSettings, Interpret(..), auto) +import Dhall.TypeCheck (X) +import Dhall.Core +import Dhall.Parser (Src(..)) +import qualified Dhall.Import +import qualified Dhall.Pretty +import qualified Dhall.TypeCheck +import qualified Dhall.Parser + +import Lens.Family (LensLike', set, view) + +import Data.Text.Prettyprint.Doc (Pretty) +import qualified Data.Text.Prettyprint.Doc as Pretty +import qualified Data.Text.Prettyprint.Doc.Render.Text as Pretty +import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty + + +-- | Information about a type argument in the dhall input +-- +-- If the dhall file starts with @\(CustomType : Type) ->@, +-- that translates to @TypeArg "CustomType" interpretionType@ +-- where @"CustomType"@ is a type-level string describing the +-- name of the type in the dhall file (as a sanity check) and +-- @interpretationType@ is any type which implements +-- 'Dhall.Interpret'. +-- +-- This is basically a specialized 'Data.Proxy'. +data TypeArg (sym :: Symbol) t = TypeArg + +-- | Existential wrapper of a 'TypeArg', allows to create a list +-- of heterogenous 'TypeArg's. +data TypeArgEx + where TypeArgEx :: (KnownSymbol sym, Interpret t) => TypeArg sym t -> TypeArgEx + +-- | Shortcut for creating a 'TypeArgEx'. +-- +-- Use with @TypeApplications@: +-- +-- @ +-- typeArg @"CustomType" @Integer +-- @ +typeArg :: forall sym t. (KnownSymbol sym, Interpret t) => TypeArgEx +typeArg = TypeArgEx (TypeArg :: TypeArg sym t) + +-- | Possible errors returned when applying a 'TypeArg' +-- to a 'Dhall.Expr'. +data TypeArgError + = WrongLabel Text.Text + -- ^ The name (label) of the type was different, + -- the text value is the expected label. + | NoLambda + -- ^ The 'Dhall.Expr' does not start with 'Dhall.Lam'. + +-- | Apply a 'TypeArg' to a 'Dhall.Expr'. +-- +-- Checks that the dhall file starts with the 'Dhall.Lam' +-- corresponding to 'TypeArg`, then applies @t@ (dhall type application) +-- and normalizes, effectively stripping the 'Dhall.Lam'. +applyTypeArg + :: forall sym t. (KnownSymbol sym, Interpret t) + => Expr Src X + -> TypeArg sym t + -> Either TypeArgError (Expr Src X) +applyTypeArg expr ta@(TypeArg) = case expr of + (Lam label (Const Dhall.Core.Type) _) + -> let expectedLabel = getLabel ta + in if label /= getLabel ta + then Left (WrongLabel expectedLabel) + else let expr' = (normalize (App expr tExpect)) + in Right expr' + where + Dhall.Type _ tExpect = Dhall.auto :: Dhall.Type t + expr -> Left NoLambda + +-- | Inflect the type-level string @sym@ to a text value. +getLabel :: forall sym t. (KnownSymbol sym) => TypeArg sym t -> Text.Text +getLabel _ = Text.pack $ symbolVal (Proxy :: (Proxy :: Symbol -> *) sym) + +instance (KnownSymbol sym) => Show (TypeArg sym t) where + show TypeArg = + "TypeArg " + ++ (symbolVal (Proxy :: (Proxy :: Symbol -> *) sym)) + +-- | Takes a list of 'TypeArg's and parses the given +-- dhall string, applying the given 'TypeArg's in order +-- to the opaque dhall type arguments (see 'TypeArg' for +-- how these should look). +-- +-- This is a slightly changed 'Dhall.inputWith'. +-- +-- Discussion: Any trace of our custom type is removed from +-- the resulting +inputWithTypeArgs + :: InputSettings + -> [TypeArgEx] + -> Dhall.Type a + -> Text.Text + -> IO a +inputWithTypeArgs settings typeArgs (Dhall.Type {extract, expected}) txt = do + expr <- throws (Dhall.Parser.exprFromText (view sourceName settings) txt) + + -- TODO: evaluateSettings not exposed + -- let evSettings = view evaluateSettings settings + let evSettings :: EvaluateSettings = defaultEvaluateSettings + + -- -vvv copied verbatim from 'Dhall.inputWith' vvv- + let transform = + set Dhall.Import.standardVersion + (view standardVersion evSettings) + . set Dhall.Import.normalizer + (view normalizer evSettings) + . set Dhall.Import.startingContext + (view startingContext evSettings) + + let status = transform (Dhall.Import.emptyStatus + (view rootDirectory settings)) + + expr' <- State.evalStateT (Dhall.Import.loadWith expr) status + -- -^^^ copied verbatim ^^^- + + let + -- | if there’s a note, run the transformation and rewrap with the note + skipNote e f = case e of + Note n e -> Note n $ f e + e -> f e + + let + -- | strip one 'TypeArg' + stripTypeArg :: Expr Src X -> TypeArgEx -> Expr Src X + stripTypeArg e (TypeArgEx ta) = skipNote e $ \e' -> case e' of + (Lam label _ _) -> + case applyTypeArg e' ta of + Right e'' -> e'' + -- TODO obvously improve error messages + Left (WrongLabel l) -> + error $ "Wrong label, should have been `" ++ Text.unpack l ++ "` but was `" ++ Text.unpack label ++ "`" + Left NoLambda -> error $ "I expected a lambda of the form λ(" ++ Text.unpack label ++ ": Type) → but got: " ++ show e + e' -> error $ show e' + + -- strip all 'TypeArg's + let expr'' = foldl' stripTypeArg expr' typeArgs + + -- -vvv copied verbatim as well (expr' -> expr'') vvv- + let suffix = prettyToStrictText expected + let annot = case expr'' of + Note (Src begin end bytes) _ -> + Note (Src begin end bytes') (Annot expr'' expected) + where + bytes' = bytes <> " : " <> suffix + _ -> + Annot expr'' expected + + _ <- throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot) + case extract (Dhall.Core.normalizeWith (Dhall.Core.getReifiedNormalizer (view normalizer settings)) expr'') of + Just x -> return x + Nothing -> Control.Exception.throwIO InvalidType + + +-- copied from Dhall.Pretty.Internal +prettyToStrictText :: Pretty a => a -> Text.Text +prettyToStrictText = docToStrictText . Pretty.pretty + +-- copied from Dhall.Pretty.Internal +docToStrictText :: Pretty.Doc ann -> Text.Text +docToStrictText = Pretty.renderStrict . Pretty.layoutPretty options + where + options = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded } + +-- copied from somewhere in Dhall +throws :: Exception e => Either e a -> IO a +throws (Left e) = Control.Exception.throwIO e +throws (Right r) = return r + + +-- TODO: add errors like these +-- data WrongTypeLabel = WrongTypeLabel deriving (Typeable) + +-- _ERROR :: String +-- _ERROR = "\ESC[1;31mError\ESC[0m" + +-- instance Show WrongTypeLabel where +-- show WrongTypeLabel = +-- _ERROR <> ": Mislabelled type lambda +-- \ \n\ +-- \Expected your t provide an extract function that succeeds if an expression \n\ +-- \matches the expected type. You provided a Type that disobeys this contract \n" diff --git a/release.nix b/release.nix index 14179fc6..ac5eb687 100644 --- a/release.nix +++ b/release.nix @@ -194,6 +194,8 @@ in with pkgsUpstream.lib; with builtins; { admon.style = ""; }; + xsltPath = "${nixpkgs}/nixos/lib/make-options-doc"; + in pkgsUpstream.stdenv.mkDerivation { name = "vuizvui-options"; @@ -203,10 +205,10 @@ in with pkgsUpstream.lib; with builtins; { cp -r "${./doc}" doc chmod -R +w doc xsltproc -o intermediate.xml \ - "${nixpkgs}/nixos/doc/manual/options-to-docbook.xsl" \ + "${xsltPath}/options-to-docbook.xsl" \ ${optionsFile} xsltproc -o doc/options-db.xml \ - "${nixpkgs}/nixos/doc/manual/postprocess-option-descriptions.xsl" \ + "${xsltPath}/postprocess-option-descriptions.xsl" \ intermediate.xml dest="$out/share/doc/vuizvui" diff --git a/tests/aszlig/dnyarri/luks2-bcache.nix b/tests/aszlig/dnyarri/luks2-bcache.nix index c728a41a..0347a0da 100644 --- a/tests/aszlig/dnyarri/luks2-bcache.nix +++ b/tests/aszlig/dnyarri/luks2-bcache.nix @@ -92,6 +92,11 @@ my $csetuuid = $newmachine->succeed( 'make-bcache -C /dev/vde | sed -n -e "s/^Set UUID:[^a-f0-9]*//p"' ); + chomp $csetuuid; + + $newmachine->nest('wait for cache device to appear', sub { + $newmachine->waitUntilSucceeds("test -e /sys/fs/bcache/$csetuuid"); + }); $newmachine->succeed( "echo $csetuuid > /sys/block/$bcache1/bcache/attach", diff --git a/tests/aszlig/programs/psi.nix b/tests/aszlig/programs/psi.nix new file mode 100644 index 00000000..5ab34da3 --- /dev/null +++ b/tests/aszlig/programs/psi.nix @@ -0,0 +1,26 @@ +{ nixpkgsPath, ... }: + +{ + name = "psi-test"; + + machine = { pkgs, ... }: { + imports = [ + "${nixpkgsPath}/nixos/tests/common/user-account.nix" + "${nixpkgsPath}/nixos/tests/common/x11.nix" + ]; + services.xserver.displayManager.auto.enable = true; + services.xserver.displayManager.auto.user = "alice"; + environment.systemPackages = [ pkgs.vuizvui.aszlig.psi ]; + }; + + enableOCR = true; + + testScript = '' + $machine->waitForX; + $machine->waitForFile("/home/alice/.Xauthority"); + $machine->succeed("xauth merge ~alice/.Xauthority"); + $machine->succeed('su -c "DISPLAY=:0.0 psi" - alice &'); + $machine->waitForText(qr/Register new account/i); + $machine->screenshot('psi'); + ''; +} diff --git a/tests/default.nix b/tests/default.nix index 5e9355e0..edc022ad 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -10,6 +10,7 @@ let in { aszlig.dnyarri.luks2-bcache = callTest ./aszlig/dnyarri/luks2-bcache.nix; + aszlig.programs.psi = callTest aszlig/programs/psi.nix; games = { starbound = callTest ./games/starbound.nix; }; |