aboutsummaryrefslogtreecommitdiff
path: root/infra/libkookie/nixpkgs/pkgs/applications/misc/cura
diff options
context:
space:
mode:
authorMx Kookie <kookie@spacekookie.de>2020-10-31 19:35:09 +0100
committerMx Kookie <kookie@spacekookie.de>2020-10-31 19:35:09 +0100
commitc4625b175f8200f643fd6e11010932ea44c78433 (patch)
treebce3f89888c8ac3991fa5569a878a9eab6801ccc /infra/libkookie/nixpkgs/pkgs/applications/misc/cura
parent49f735974dd103039ddc4cb576bb76555164a9e7 (diff)
parentd661aa56a8843e991261510c1bb28fdc2f6975ae (diff)
Add 'infra/libkookie/' from commit 'd661aa56a8843e991261510c1bb28fdc2f6975ae'
git-subtree-dir: infra/libkookie git-subtree-mainline: 49f735974dd103039ddc4cb576bb76555164a9e7 git-subtree-split: d661aa56a8843e991261510c1bb28fdc2f6975ae
Diffstat (limited to 'infra/libkookie/nixpkgs/pkgs/applications/misc/cura')
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/default.nix64
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/curaengine-openmp-compat.patch47
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/curaengine.nix27
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/default.nix82
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/libarcus.nix33
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/libsavitar.nix33
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/uranium.nix38
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/numpy-cast.patch12
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/plugins.nix37
-rw-r--r--infra/libkookie/nixpkgs/pkgs/applications/misc/cura/stable.nix73
10 files changed, 446 insertions, 0 deletions
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/default.nix b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/default.nix
new file mode 100644
index 000000000000..c0aa0a481bdc
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/default.nix
@@ -0,0 +1,64 @@
+{ mkDerivation, lib, fetchFromGitHub, cmake, python3, qtbase, qtquickcontrols2, qtgraphicaleffects, curaengine, plugins ? [] }:
+
+mkDerivation rec {
+ pname = "cura";
+ version = "4.7.1";
+
+ src = fetchFromGitHub {
+ owner = "Ultimaker";
+ repo = "Cura";
+ rev = version;
+ sha256 = "19an168iad3cb5w8i71c0wbr79qnz5qnpxqx1j6dgh64qz6ffn2r";
+ };
+
+ materials = fetchFromGitHub {
+ owner = "Ultimaker";
+ repo = "fdm_materials";
+ rev = version;
+ sha256 = "1w6i0dlff8b30q987x3y0zv8847fc8ppfcr9vi982msmv284c89z";
+ };
+
+ buildInputs = [ qtbase qtquickcontrols2 qtgraphicaleffects ];
+ propagatedBuildInputs = with python3.pkgs; [
+ libsavitar numpy-stl pyserial requests uranium zeroconf
+ sentry-sdk trimesh
+ ] ++ plugins;
+ nativeBuildInputs = [ cmake python3.pkgs.wrapPython ];
+
+ cmakeFlags = [
+ "-DURANIUM_DIR=${python3.pkgs.uranium.src}"
+ "-DCURA_VERSION=${version}"
+ ];
+
+ makeWrapperArgs = [
+ # hacky workaround for https://github.com/NixOS/nixpkgs/issues/59901
+ "--set OMP_NUM_THREADS 1"
+ ];
+
+ postPatch = ''
+ sed -i 's,/python''${PYTHON_VERSION_MAJOR}/dist-packages,/python''${PYTHON_VERSION_MAJOR}.''${PYTHON_VERSION_MINOR}/site-packages,g' CMakeLists.txt
+ sed -i 's, executable_name = .*, executable_name = "${curaengine}/bin/CuraEngine",' plugins/CuraEngineBackend/CuraEngineBackend.py
+ '';
+
+ postInstall = ''
+ mkdir -p $out/share/cura/resources/materials
+ cp ${materials}/*.fdm_material $out/share/cura/resources/materials/
+ mkdir -p $out/lib/cura/plugins
+ for plugin in ${toString plugins}; do
+ ln -s $plugin/lib/cura/plugins/* $out/lib/cura/plugins
+ done
+ '';
+
+ postFixup = ''
+ wrapPythonPrograms
+ wrapQtApp $out/bin/cura
+ '';
+
+ meta = with lib; {
+ description = "3D printer / slicing GUI built on top of the Uranium framework";
+ homepage = "https://github.com/Ultimaker/Cura";
+ license = licenses.lgpl3Plus;
+ platforms = platforms.linux;
+ maintainers = with maintainers; [ abbradar gebner ];
+ };
+}
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/curaengine-openmp-compat.patch b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/curaengine-openmp-compat.patch
new file mode 100644
index 000000000000..3826e92440f0
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/curaengine-openmp-compat.patch
@@ -0,0 +1,47 @@
+# Notes by Charles Duffy <charles@dyfis.net> --
+#
+# - The new version of OpenMP does not allow outside variables to be referenced
+# *at all* without an explicit declaration of how they're supposed to be
+# handled. Thus, this was an outright build failure beforehand. The new
+# pragmas copy the initial value from the outer scope into each parallel
+# thread. Since these variables are all constant within the loops, this is
+# clearly correct. (Not sure it's *optimal*, but quite sure it isn't
+# *wrong*).
+# - Upstream has been contacted -- I'm a Lulzbot customer with an active
+# support contract and sent them the patch. That said, they're in the middle
+# of some major corporate churn (sold themselves out of near-bankruptcy to an
+# out-of-state business entity formed as a holding company; moved to that
+# state; have been slowly restaffing after), so a response may take a while.
+# - The patch is purely my own work.
+
+--- curaengine/src/support.cpp.orig 2020-03-28 10:38:01.953912363 -0500
++++ curaengine/src/support.cpp 2020-03-28 10:45:28.999791908 -0500
+@@ -854,7 +854,7 @@
+ const double tan_angle = tan(angle) - 0.01; // the XY-component of the supportAngle
+ xy_disallowed_per_layer[0] = storage.getLayerOutlines(0, false).offset(xy_distance);
+ // for all other layers (of non support meshes) compute the overhang area and possibly use that when calculating the support disallowed area
+- #pragma omp parallel for default(none) shared(xy_disallowed_per_layer, storage, mesh) schedule(dynamic)
++ #pragma omp parallel for default(none) firstprivate(layer_count, is_support_mesh_place_holder, use_xy_distance_overhang, z_distance_top, tan_angle, xy_distance, xy_distance_overhang) shared(xy_disallowed_per_layer, storage, mesh) schedule(dynamic)
+ for (unsigned int layer_idx = 1; layer_idx < layer_count; layer_idx++)
+ {
+ Polygons outlines = storage.getLayerOutlines(layer_idx, false);
+@@ -1054,7 +1054,7 @@
+ const int max_checking_layer_idx = std::min(static_cast<int>(storage.support.supportLayers.size())
+ , static_cast<int>(layer_count - (layer_z_distance_top - 1)));
+ const size_t max_checking_idx_size_t = std::max(0, max_checking_layer_idx);
+-#pragma omp parallel for default(none) shared(support_areas, storage) schedule(dynamic)
++#pragma omp parallel for default(none) firstprivate(max_checking_idx_size_t, layer_z_distance_top) shared(support_areas, storage) schedule(dynamic)
+ for (size_t layer_idx = 0; layer_idx < max_checking_idx_size_t; layer_idx++)
+ {
+ support_areas[layer_idx] = support_areas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layer_z_distance_top - 1, false));
+--- curaengine/src/layerPart.cpp.orig 2020-03-28 10:36:40.381023651 -0500
++++ curaengine/src/layerPart.cpp 2020-03-28 10:39:54.584140465 -0500
+@@ -49,7 +49,7 @@
+ {
+ const auto total_layers = slicer->layers.size();
+ assert(mesh.layers.size() == total_layers);
+-#pragma omp parallel for default(none) shared(mesh, slicer) schedule(dynamic)
++#pragma omp parallel for default(none) firstprivate(total_layers) shared(mesh, slicer) schedule(dynamic)
+ for (unsigned int layer_nr = 0; layer_nr < total_layers; layer_nr++)
+ {
+ SliceLayer& layer_storage = mesh.layers[layer_nr];
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/curaengine.nix b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/curaengine.nix
new file mode 100644
index 000000000000..a5cfa937fd8d
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/curaengine.nix
@@ -0,0 +1,27 @@
+{ gcc8Stdenv, callPackage, fetchgit, fetchpatch, cmake, libarcusLulzbot, stb, protobuf }:
+
+gcc8Stdenv.mkDerivation rec {
+ pname = "curaengine-lulzBot";
+ version = "3.6.21";
+
+ src = fetchgit {
+ url = "https://code.alephobjects.com/source/curaengine-lulzbot.git";
+ rev = "ec6a1a0f0aa387ef97e5c106633cf8d7fb9cd00d";
+ sha256 = "0wdkvg1hmqp1gaym804lw09x4ngf5ffasd861jhflpy7djbmkfn8";
+ };
+
+ patches = [ ./curaengine-openmp-compat.patch ];
+
+ nativeBuildInputs = [ cmake ];
+ buildInputs = [ libarcusLulzbot stb protobuf ];
+
+ cmakeFlags = [ "-DCURA_ENGINE_VERSION=${version}" ];
+
+ meta = with gcc8Stdenv.lib; {
+ description = "A powerful, fast and robust engine for processing 3D models into 3D printing instruction";
+ homepage = "https://code.alephobjects.com/source/curaengine-lulzbot/";
+ license = licenses.agpl3;
+ platforms = platforms.linux;
+ maintainers = with maintainers; [ chaduffy ];
+ };
+}
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/default.nix b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/default.nix
new file mode 100644
index 000000000000..229966561c6d
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/default.nix
@@ -0,0 +1,82 @@
+{ lib, mkDerivation, wrapQtAppsHook, callPackage, fetchgit, cmake, jq, python3, qtbase, qtquickcontrols2 }:
+
+let
+ # admittedly, we're using (printer firmware) blobs when we could compile them ourselves.
+ curaBinaryDataVersion = "3.6.21"; # Marlin v2.0.0.174 for Bio, v2.0.0.144 for others.
+ curaBinaryData = fetchgit {
+ url = "https://code.alephobjects.com/diffusion/CBD/cura-binary-data.git";
+ rev = "5c75d0f6c10d8b7a903e2072a48cd1f08059509e";
+ sha256 = "1qdsj6rczwzdwzyr7nz7fnypbphckjrnwl8c9dr6izsxyzs465c4";
+ };
+
+ libarcusLulzbot = callPackage ./libarcus.nix {
+ inherit (python3.pkgs) buildPythonPackage sip pythonOlder;
+ };
+ libsavitarLulzbot = callPackage ./libsavitar.nix {
+ inherit (python3.pkgs) buildPythonPackage sip pythonOlder;
+ };
+
+ inherit (python3.pkgs) buildPythonPackage pyqt5 numpy scipy shapely pythonOlder;
+ curaengine = callPackage ./curaengine.nix {
+ inherit libarcusLulzbot;
+ };
+ uraniumLulzbot = callPackage ./uranium.nix {
+ inherit callPackage libarcusLulzbot;
+ inherit (python3.pkgs) buildPythonPackage pyqt5 numpy scipy shapely pythonOlder;
+ };
+in
+mkDerivation rec {
+ pname = "cura-lulzbot";
+ version = "3.6.21";
+
+ src = fetchgit {
+ url = "https://code.alephobjects.com/source/cura-lulzbot.git";
+ rev = "7faeb18604c83004846a02c60cb240708db0034f";
+ sha256 = "10q38s8c8x6xkh1vns4p3iqa5y267vrjh5vq8h55mg1q5001scyq";
+ };
+
+ buildInputs = [ qtbase qtquickcontrols2 ];
+ # numpy-stl temporarily disabled due to https://code.alephobjects.com/T8415
+ propagatedBuildInputs = with python3.pkgs; [ pyserial requests zeroconf ] ++ [ libsavitarLulzbot uraniumLulzbot libarcusLulzbot ]; # numpy-stl
+ nativeBuildInputs = [ cmake python3.pkgs.wrapPython ];
+
+ cmakeFlags = [
+ "-DURANIUM_DIR=${uraniumLulzbot.src}"
+ "-DCURA_VERSION=${version}"
+ ];
+
+ postPatch = ''
+ sed -i 's,/python''${PYTHON_VERSION_MAJOR}/dist-packages,/python''${PYTHON_VERSION_MAJOR}.''${PYTHON_VERSION_MINOR}/site-packages,g' CMakeLists.txt
+ sed -i 's, executable_name = .*, executable_name = "${curaengine}/bin/CuraEngine",' plugins/CuraEngineBackend/CuraEngineBackend.py
+ '';
+
+ preFixup = ''
+ substituteInPlace "$out/bin/cura-lulzbot" --replace 'import cura.CuraApplication' 'import Savitar; import cura.CuraApplication'
+ ln -sT "${curaBinaryData}/cura/resources/firmware" "$out/share/cura/resources/firmware"
+ ln -sT "${uraniumLulzbot}/share/uranium" "$out/share/uranium"
+ ${jq}/bin/jq --arg out "$out" '.build=$out' >"$out/version.json" <<'EOF'
+ ${builtins.toJSON {
+ cura = version;
+ cura_version = version;
+ binarydata = curaBinaryDataVersion;
+ engine = curaengine.version;
+ libarcus = libarcusLulzbot.version;
+ libsavitar = libsavitarLulzbot.version;
+ uranium = uraniumLulzbot.version;
+ }}
+ EOF
+ '';
+
+ postFixup = ''
+ wrapPythonPrograms
+ wrapQtApp "$out/bin/cura-lulzbot"
+ '';
+
+ meta = with lib; {
+ description = "3D printer / slicing GUI built on top of the Uranium framework";
+ homepage = "https://code.alephobjects.com/diffusion/CURA/";
+ license = licenses.agpl3; # a partial relicense to LGPL has happened, but not certain that all AGPL bits are expunged
+ platforms = platforms.linux;
+ maintainers = with maintainers; [ chaduffy ];
+ };
+}
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/libarcus.nix b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/libarcus.nix
new file mode 100644
index 000000000000..5edaabbacb0f
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/libarcus.nix
@@ -0,0 +1,33 @@
+{ stdenv, buildPythonPackage, fetchgit, fetchurl, cmake, sip, protobuf, pythonOlder }:
+
+buildPythonPackage {
+ pname = "libarcus";
+ version = "3.6.21";
+ format = "other";
+
+ src = fetchgit {
+ url = "https://code.alephobjects.com/source/arcus.git";
+ rev = "aeda02d7727f45b657afb72cef203283fbf09325";
+ sha256 = "1ak0d4k745sx7paic27was3s4987z9h3czscjs21hxbi6qy83g99";
+ };
+
+ disabled = pythonOlder "3.4.0";
+
+ propagatedBuildInputs = [ sip ];
+ nativeBuildInputs = [ cmake ];
+ buildInputs = [ protobuf ];
+
+ postPatch = ''
+ # To workaround buggy SIP detection which overrides PYTHONPATH
+ sed -i '/SET(ENV{PYTHONPATH}/d' cmake/FindSIP.cmake
+ '';
+
+ meta = with stdenv.lib; {
+ description = "Communication library between internal components for Ultimaker software";
+ homepage = "https://code.alephobjects.com/source/arcus/";
+ license = licenses.lgpl3Plus;
+ platforms = platforms.linux;
+ maintainers = with maintainers; [ chaduffy ];
+ };
+}
+
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/libsavitar.nix b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/libsavitar.nix
new file mode 100644
index 000000000000..e32117a103ee
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/libsavitar.nix
@@ -0,0 +1,33 @@
+{ stdenv, buildPythonPackage, pythonOlder, fetchgit, cmake, sip }:
+
+buildPythonPackage {
+ pname = "libsavitar-lulzbot";
+ name = "libsavitar-lulzbot";
+ version = "3.6.21";
+ format = "other";
+
+ src = fetchgit {
+ url = "https://code.alephobjects.com/source/savitar.git";
+ rev = "ee8ada42c55f54727ce4d275c294ba426d3d8234";
+ sha256 = "1wm5ii3cmni8dk3c65kw4wglpypkdsfpgd480d3hc1r5bqpq0d6j";
+ };
+
+ postPatch = ''
+ # To workaround buggy SIP detection which overrides PYTHONPATH
+ sed -i '/SET(ENV{PYTHONPATH}/d' cmake/FindSIP.cmake
+ '';
+
+ nativeBuildInputs = [ cmake ];
+
+ propagatedBuildInputs = [ sip ];
+
+ disabled = pythonOlder "3.4.0";
+
+ meta = with stdenv.lib; {
+ description = "C++ implementation of 3mf loading with SIP python bindings";
+ homepage = "https://github.com/Ultimaker/libSavitar";
+ license = licenses.lgpl3Plus;
+ platforms = platforms.unix;
+ maintainers = with maintainers; [ chaduffy ];
+ };
+}
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/uranium.nix b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/uranium.nix
new file mode 100644
index 000000000000..2ce0fab170ea
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/lulzbot/uranium.nix
@@ -0,0 +1,38 @@
+{ stdenv, callPackage, fetchurl, fetchgit, buildPythonPackage, fetchFromGitHub, python, cmake
+, pyqt5, numpy, scipy, shapely, libarcusLulzbot, doxygen, gettext, pythonOlder }:
+
+buildPythonPackage {
+ version = "3.6.21";
+ pname = "uranium";
+ name = "uraniumLulzbot";
+ format = "other";
+
+ src = fetchgit {
+ url = "https://code.alephobjects.com/diffusion/U/uranium.git";
+ rev = "54d911edd2551c5875c554928896122835a0dd6c";
+ sha256 = "04bym3vwikaxw8ab0mymv9sc9n8i7yw5kfsv99ic811g9lzz3j1i";
+ };
+
+ disabled = pythonOlder "3.5.0";
+
+ buildInputs = [ python gettext ];
+ propagatedBuildInputs = [ pyqt5 numpy scipy shapely libarcusLulzbot ];
+ nativeBuildInputs = [ cmake doxygen ];
+
+ postPatch = ''
+ sed -i 's,/python''${PYTHON_VERSION_MAJOR}/dist-packages,/python''${PYTHON_VERSION_MAJOR}.''${PYTHON_VERSION_MINOR}/site-packages,g' CMakeLists.txt
+ sed -i \
+ -e "s,Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)).*,Resources.addSearchPath(\"$out/share/uranium/resources\")," \
+ -e "s,self._plugin_registry.addPluginLocation(os.path.join(os.path.abspath(os.path.dirname(__file__)).*,self._plugin_registry.addPluginLocation(\"$out/lib/uranium/plugins\")," \
+ UM/Application.py
+ '';
+
+ meta = with stdenv.lib; {
+ description = "A Python framework for building Desktop applications";
+ homepage = "https://code.alephobjects.com/diffusion/U/";
+ license = licenses.lgpl3Plus;
+ platforms = platforms.linux;
+ maintainers = with maintainers; [ chaduffy ];
+ };
+}
+
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/numpy-cast.patch b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/numpy-cast.patch
new file mode 100644
index 000000000000..efb14182b3e6
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/numpy-cast.patch
@@ -0,0 +1,12 @@
+diff -urN Cura-15.04.old/Cura/util/sliceEngine.py Cura-15.04/Cura/util/sliceEngine.py
+--- Cura-15.04.old/Cura/util/sliceEngine.py 2016-05-07 20:34:17.305020334 +0200
++++ Cura-15.04/Cura/util/sliceEngine.py 2016-05-07 20:40:02.993286467 +0200
+@@ -343,7 +343,7 @@
+ objMax[1] = max(oMax[1], objMax[1])
+ if objMin is None:
+ return
+- pos += (objMin + objMax) / 2.0 * 1000
++ pos = numpy.add( pos, (objMin + objMax) / 2.0 * 1000, out=pos, casting='unsafe')
+ commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
+
+ vertexTotal = [0] * 4
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/plugins.nix b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/plugins.nix
new file mode 100644
index 000000000000..9082feb38a7a
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/plugins.nix
@@ -0,0 +1,37 @@
+{ stdenv, fetchFromGitHub, fetchpatch, python3Packages }:
+
+let
+
+ self = {
+
+ octoprint = stdenv.mkDerivation rec {
+ pname = "Cura-OctoPrintPlugin";
+ version = "3.5.16";
+
+ src = fetchFromGitHub {
+ owner = "fieldOfView";
+ repo = pname;
+ rev = "8affa8aa9796cb37129d3b7222fff03f86c936cd";
+ sha256 = "0l4qfcashkdmpdm8nm3klz6hmi1f0bmbpb9b1yn4mvg0fam6c5xi";
+ };
+
+ propagatedBuildInputs = with python3Packages; [
+ netifaces
+ ];
+
+ installPhase = ''
+ mkdir -p $out/lib/cura/plugins/OctoPrintPlugin
+ cp -rv . $out/lib/cura/plugins/OctoPrintPlugin/
+ '';
+
+ meta = with stdenv.lib; {
+ description = "Enables printing directly to OctoPrint and monitoring the process";
+ homepage = "https://github.com/fieldOfView/Cura-OctoPrintPlugin";
+ license = licenses.agpl3;
+ maintainers = with maintainers; [ gebner ];
+ };
+ };
+
+ };
+
+in self
diff --git a/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/stable.nix b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/stable.nix
new file mode 100644
index 000000000000..87d2aba891b6
--- /dev/null
+++ b/infra/libkookie/nixpkgs/pkgs/applications/misc/cura/stable.nix
@@ -0,0 +1,73 @@
+{ stdenv, python27Packages, curaengine, makeDesktopItem, fetchurl }:
+let
+ py = python27Packages;
+ version = "15.04";
+in
+stdenv.mkDerivation rec {
+ pname = "cura";
+ inherit version;
+
+ src = fetchurl {
+ url = "https://github.com/daid/Cura/archive/${version}.tar.gz";
+ sha256 = "0xbjvzhp8wzq9lnpmcg1fjf7j5h39bj5463sd5c8jzdjl96izizl";
+ };
+
+ desktopItem = makeDesktopItem {
+ name = "Cura";
+ exec = "cura";
+ icon = "cura";
+ comment = "Cura";
+ desktopName = "Cura";
+ genericName = "3D printing host software";
+ categories = "GNOME;GTK;Utility;";
+ };
+
+ python_deps = with py; [ pyopengl pyserial numpy wxPython30 power setuptools ];
+
+ pythonPath = python_deps;
+
+ propagatedBuildInputs = python_deps;
+
+ buildInputs = [ curaengine py.wrapPython ];
+
+ configurePhase = "";
+ buildPhase = "";
+
+ patches = [ ./numpy-cast.patch ];
+
+ installPhase = ''
+ # Install Python code.
+ site_packages=$out/lib/python2.7/site-packages
+ mkdir -p $site_packages
+ cp -r Cura $site_packages/
+
+ # Install resources.
+ resources=$out/share/cura
+ mkdir -p $resources
+ cp -r resources/* $resources/
+ sed -i 's|os.path.join(os.path.dirname(__file__), "../../resources")|"'$resources'"|g' $site_packages/Cura/util/resources.py
+
+ # Install executable.
+ mkdir -p $out/bin
+ cp Cura/cura.py $out/bin/cura
+ chmod +x $out/bin/cura
+ sed -i 's|#!/usr/bin/python|#!/usr/bin/env python|' $out/bin/cura
+ wrapPythonPrograms
+
+ # Make it find CuraEngine.
+ echo "def getEngineFilename(): return '${curaengine}/bin/CuraEngine'" >> $site_packages/Cura/util/sliceEngine.py
+
+ # Install desktop item.
+ mkdir -p "$out"/share/applications
+ cp "$desktopItem"/share/applications/* "$out"/share/applications/
+ mkdir -p "$out"/share/icons
+ ln -s "$resources/images/c.png" "$out"/share/icons/cura.png
+ '';
+
+ meta = with stdenv.lib; {
+ description = "3D printing host software";
+ homepage = "https://github.com/daid/Cura";
+ license = licenses.agpl3;
+ platforms = platforms.linux;
+ };
+}