diff --git a/.gitignore b/.gitignore
index 284acf248c..d7fd92b074 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ CMakeUserPresets.json
/*build*/
**/target/
/*install*/
+/Nixpile-build
*.swp
diff --git a/README.md b/README.md
index 97789702c9..0b58c93010 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,35 @@ If you're having trouble with something, want to suggest a feature or report a b
You can directly [report issues here on GitHub](/drawpile/Drawpile/issues). If you got Discord, you can [join the Drawpile server](https://drawpile.net/discord/) on there. You can also [use the chatroom on libera.chat](https://drawpile.net/irc/), it can be done directly through the browser and doesn't need any account.
+## Drawpile on nix
+
+> Linux users hate him for descovering how to reproduce an ENTIRE ENVIROMENT with just ONE COMMAND
+> \- Qubic 2023
+
+Having a reproducible work enviroment is nice.
+Especialy if you can do it only with one command.
+
+### Dev enviroment
+
+To get a dev shell with nix you just do `nix shell .#(cmake profile without linux prefix)`
+(I did not include linux prefix becuse I'm quite sure it will probably work with nix + macOs)
+
+### Dev shell functions
+
+In dev shells you have 2 very simple functions
+
+`firstBuild` for setuping cmake and building drawpile for first time
+`incrementalBuild` for building drawpile successive times
+
+### Package names
+
+We name packages same way we name shell-s
+
+
+
## Contributing
Pull requests are welcome, be it for code or anything else! If you want to contribute documentation, you can do so [over in this repository](/drawpile/drawpile.github.io).
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000000..90fefe10a4
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,6 @@
+(import (let lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+in fetchTarball {
+ url =
+ lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+ sha256 = lock.nodes.flake-compat.locked.narHash;
+}) { src = ./.; }).defaultNix
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000000..90fc50df7b
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,92 @@
+{
+ "nodes": {
+ "flake-compat": {
+ "locked": {
+ "lastModified": 1696426674,
+ "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+ "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+ "revCount": 57,
+ "type": "tarball",
+ "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
+ },
+ "original": {
+ "type": "tarball",
+ "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+ }
+ },
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1705309234,
+ "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nix-filter": {
+ "locked": {
+ "lastModified": 1705332318,
+ "narHash": "sha256-kcw1yFeJe9N4PjQji9ZeX47jg0p9A0DuU4djKvg1a7I=",
+ "owner": "numtide",
+ "repo": "nix-filter",
+ "rev": "3449dc925982ad46246cfc36469baf66e1b64f17",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "nix-filter",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1706550542,
+ "narHash": "sha256-UcsnCG6wx++23yeER4Hg18CXWbgNpqNXcHIo5/1Y+hc=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "97b17f32362e475016f942bbdfda4a4a72a8a652",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-compat": "flake-compat",
+ "flake-utils": "flake-utils",
+ "nix-filter": "nix-filter",
+ "nixpkgs": "nixpkgs"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000000..f0eb9e83a0
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,240 @@
+# TODO: Consider using mold (linker)
+#TODO: Add declarative drawpile server support
+#TODO: Consider my terrible life choices that led me to derive os-es from config files
+{
+ description = "Collaborative drawing program that lets multiple people draw.";
+
+ inputs = {
+ #main packages
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+
+ #utilities in writing flakes
+ flake-utils.url = "github:numtide/flake-utils";
+
+ #compatibility with non flaked nix
+ flake-compat.url = "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz";
+
+ # source filtering
+ nix-filter.url = "github:numtide/nix-filter";
+ };
+
+ outputs = { self, nixpkgs, flake-utils, nix-filter, ... }:
+ #Support x86_64/arm linux
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = nixpkgs.legacyPackages.${system};
+
+ #Compile time libs
+
+ mkNativeInputs = { qt5 }:
+ let
+ qtStuff = if qt5 then
+ [ pkgs.libsForQt5.qt5.wrapQtAppsHook ]
+ else
+ [ pkgs.qt6.wrapQtAppsHook ];
+
+ buildSystems = with pkgs; [ cmake ninja gcc ];
+
+ in qtStuff ++ buildSystems;
+
+ mkDepends = { qt5, shell }:
+ let
+ #decide what QT to use
+ qtDependences = if qt5 then
+ with pkgs.libsForQt5.qt5;
+ [ qtbase qtsvg qttools qtmultimedia ]
+ ++ [ pkgs.libsForQt5.karchive ]
+ else
+ with pkgs; [ qt6.qtbase qt6.qtsvg qt6.qttools qt6.qtmultimedia ];
+
+ #Other dependencies required for building
+ otherDeps = with pkgs; [
+
+ git
+ libxkbcommon
+ libzip
+ libsodium
+ libmicrohttpd
+ libpulseaudio
+ ];
+
+ shellDpeneds = if shell then
+ with pkgs; [ cargo rustc rustfmt clippy ]
+ else
+ with pkgs; [ ];
+
+ in qtDependences ++ shellDpeneds ++ otherDeps;
+
+ mkDpShell = { useQt5, preset, debug ? false }:
+ pkgs.mkShell {
+
+ nativeBuildInputs = mkNativeInputs { qt5 = useQt5; };
+
+ buildInputs = mkDepends {
+ qt5 = useQt5;
+ shell = true;
+ };
+
+ shellHook = ''
+ export ROOT="$PWD/Nixpile-build/${preset}"
+ mkdir -p "$ROOT"
+ export LD_LIBRARY_PATH="$CMAKE_LIBRARY_PATH"
+
+ configure() {
+ cmake -S "$ROOT/../../" -B "$ROOT" \
+ --preset ${preset} \
+ "-DCMAKE_INSTALL_PREFIX=$out"
+ }
+
+ build() {
+ if ! [ -e "$ROOT" ]; then
+ configure || return 1
+ fi
+ if [ -e "$ROOT/bin/.drawpile-wrapped" ]; then
+ mv "$ROOT/bin/.drawpile-wrapped" "$ROOT/bin/drawpile"
+ fi
+ cmake --build "$ROOT" || return 1
+ wrapQtApp "$ROOT/bin/drawpile"
+ }
+
+ run() {
+ build || return 1
+ "$ROOT/bin/drawpile"
+ }
+ '';
+ };
+
+ mkDrawpile = { useQt5, preset, debug ? false }:
+ pkgs.rustPlatform.buildRustPackage {
+ name = "drawpile";
+
+ src = nix-filter {
+ root = ./.;
+ # Filter source
+ include = [
+ # Include /src
+ "src"
+ # Include rust stuff
+ ./Cargo.toml
+ ./Cargo.lock
+ # Include CMAKE stuff
+ "cmake"
+ ./CMakePresets.json
+ ./CMakeLists.txt
+
+ #Other misalanius stuff
+ ./LICENSE.txt
+ ./ChangeLog
+ ./README.md
+ "doc"
+ ];
+ };
+
+ nativeBuildInputs = mkNativeInputs { qt5 = useQt5; };
+
+ buildInputs = mkDepends {
+ qt5 = useQt5;
+ shell = false;
+ };
+
+ cargoLock = { lockFile = ./Cargo.lock; };
+
+ configurePhase = ''
+ cmake -S ./ -B Drawpile-build \
+ --preset ${preset} \
+ -DCMAKE_INSTALL_PREFIX=$out
+ '';
+
+ enableParallelBuilding = true;
+
+ buildPhase = ''
+ cmake --build ./Drawpile-build
+ '';
+
+ installPhase = ''
+ mkdir -p $out
+ cmake --install ./Drawpile-build
+ '';
+ };
+
+ in rec {
+
+ packages = {
+ debug-qt6-all-ninja = mkDrawpile {
+ preset = "linux-debug-qt6-all-ninja";
+ useQt5 = false;
+ };
+
+ release-qt6-all-ninja = mkDrawpile {
+ preset = "linux-release-qt6-all-ninja";
+ useQt5 = false;
+ };
+
+ release-qt6-server-ninja = mkDrawpile {
+ preset = "linux-release-qt6-server-ninja";
+ useQt5 = false;
+ };
+
+ debug-qt5-all-ninja = mkDrawpile {
+ preset = "linux-debug-qt5-all-ninja";
+ useQt5 = true;
+ };
+
+ release-qt5-all-ninja = mkDrawpile {
+ preset = "linux-release-qt5-all-ninja";
+ useQt5 = true;
+ };
+
+ release-qt5-server-ninja = mkDrawpile {
+ preset = "linux-release-qt5-server-ninja";
+ useQt5 = true;
+ };
+
+ default = self.outputs.packages.${system}.release-qt6-all-ninja;
+ };
+
+ #Dev shells
+
+ devShells = rec {
+ debug-qt6-all-ninja = mkDpShell {
+ preset = "linux-debug-qt6-all-ninja";
+ useQt5 = false;
+ debug = true;
+ };
+
+ release-qt6-all-ninja = mkDpShell {
+ preset = "linux-release-qt6-all-ninja";
+ useQt5 = false;
+ debug = true;
+ };
+
+ release-qt6-server-ninja = mkDpShell {
+ preset = "linux-release-qt6-server-ninja";
+ useQt5 = false;
+ debug = true;
+ };
+
+ debug-qt5-all-ninja = mkDpShell {
+ preset = "linux-debug-qt5-all-ninja";
+ useQt5 = true;
+ debug = true;
+ };
+
+ release-qt5-all-ninja = mkDpShell {
+ preset = "linux-release-qt5-all-ninja";
+ useQt5 = true;
+ debug = true;
+ };
+
+ release-qt5-server-ninja = mkDpShell {
+ preset = "linux-release-qt5-server-ninja";
+ useQt5 = true;
+ debug = true;
+ };
+
+ default = self.outputs.devShells.${system}.debug-qt6-all-ninja;
+ };
+
+ formatter = pkgs.nixfmt;
+ });
+}
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000000..71e7def5b6
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,6 @@
+(import (let lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+in fetchTarball {
+ url =
+ lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
+ sha256 = lock.nodes.flake-compat.locked.narHash;
+}) { src = ./.; }).shellNix