diff options
-rw-r--r-- | default.nix | 2 | ||||
-rw-r--r-- | humblebundle/default.nix | 3 | ||||
-rw-r--r-- | humblebundle/fetch-humble-bundle/default.nix | 17 | ||||
-rw-r--r-- | humblebundle/guacamelee.nix | 61 | ||||
-rw-r--r-- | humblebundle/liads.nix | 43 | ||||
-rw-r--r-- | steam/default.nix | 38 | ||||
-rw-r--r-- | steam/fetchsteam/default.nix | 91 | ||||
-rw-r--r-- | steam/fetchsteam/downloader.patch | 34 | ||||
-rw-r--r-- | steam/starbound.nix | 132 |
9 files changed, 413 insertions, 8 deletions
diff --git a/default.nix b/default.nix index 80420a8b..d85bd191 100644 --- a/default.nix +++ b/default.nix @@ -20,6 +20,6 @@ let in ((import <nixpkgs/lib>).evalModules { modules = [ (if configuration == null then configFilePath else configuration) - ./base-module.nix ./humblebundle + ./base-module.nix ./humblebundle ./steam ]; }).config.packages diff --git a/humblebundle/default.nix b/humblebundle/default.nix index e77a7deb..237a5dc6 100644 --- a/humblebundle/default.nix +++ b/humblebundle/default.nix @@ -5,6 +5,7 @@ let self = rec { callPackage = pkgs.lib.callPackageWith (pkgs // self); + callPackage_i686 = pkgs.lib.callPackageWith (pkgs.pkgsi686Linux // self); fetchHumbleBundle = callPackage ./fetch-humble-bundle { inherit (config.humblebundle) email password; @@ -14,8 +15,10 @@ let cavestoryplus = callPackage ./cavestoryplus.nix {}; fez = callPackage ./fez.nix {}; ftl = callPackage ./ftl.nix {}; + guacamelee = callPackage_i686 ./guacamelee.nix {}; hammerwatch = callPackage ./hammerwatch.nix {}; jamestown = callPackage ./jamestown.nix {}; + liads = callPackage ./liads.nix {}; megabytepunch = callPackage ./megabytepunch.nix {}; rocketbirds = callPackage ./rocketbirds.nix {}; spaz = callPackage ./spaz.nix {}; diff --git a/humblebundle/fetch-humble-bundle/default.nix b/humblebundle/fetch-humble-bundle/default.nix index 3e0bc5ad..fbabaa8c 100644 --- a/humblebundle/fetch-humble-bundle/default.nix +++ b/humblebundle/fetch-humble-bundle/default.nix @@ -21,6 +21,8 @@ propagatedBuildInputs = with pythonPackages; [ requests2 ]; }; + pyStr = str: "'${stdenv.lib.escape ["'" "\\"] str}'"; + getDownloadURL = writeText "gethburl.py" '' import sys, humblebundle @@ -38,32 +40,33 @@ def find_download(downloads): for machine_name, dstruct in sum(downloads.values(), []): - if machine_name == '${machineName}': + if machine_name == ${pyStr machineName}: for ds in dstruct: - if ds.name == '${downloadName}': + if ds.name == ${pyStr downloadName}: return ds print >>sys.stderr, \ - 'Unable to find ${downloadName} for ${machineName}!' + ${pyStr "Unable to find ${downloadName} for ${machineName}!"} print >>sys.stderr, 'Available download types:' for ds in dstruct: print >>sys.stderr, " " + ds.name raise SystemExit(1) hb = humblebundle.HumbleApi() - hb.login('${email}', '${password}') + hb.login(${pyStr email}, ${pyStr password}) products = dict(get_products(hb)) dstruct = find_download(products) if dstruct is None: - print >>sys.stderr, 'Cannot find download for ${machineName}!' + print >>sys.stderr, ${pyStr "Cannot find download for ${machineName}!"} print >>sys.stderr, 'Available machine names:' for name, dstructs in sorted(products.items(), key=lambda x: x[0]): print >>sys.stderr, " * " + name print >>sys.stderr, " " + ', '.join(map(lambda x: x[0], dstructs)) raise SystemExit(1) - elif dstruct.md5 != '${md5}': + elif dstruct.md5 != ${pyStr md5}: print >>sys.stderr, \ - 'MD5 for ${machineName} is not ${md5} but ' + dstruct.md5 + '.' + ${pyStr "MD5 for ${machineName} is not ${md5} but "} \ + + dstruct.md5 + '.' raise SystemExit(1) else: print dstruct.url.web diff --git a/humblebundle/guacamelee.nix b/humblebundle/guacamelee.nix new file mode 100644 index 00000000..537ec945 --- /dev/null +++ b/humblebundle/guacamelee.nix @@ -0,0 +1,61 @@ +{ stdenv, fetchHumbleBundle, unzip, SDL2, mesa, writeText, makeWrapper }: + +stdenv.mkDerivation rec { + name = "guacamelee-${version}"; + version = "1393037377"; + + src = fetchHumbleBundle { + machineName = "guacamelee_goldedition_linux"; + suffix = "sh"; + md5 = "b06af932c1aaefb8f157c977061388ef"; + }; + + unpackCmd = '' + ${unzip}/bin/unzip "$src" 'data/*' || : + ''; + + preloader = writeText "guacamelee-preloader.c" '' + #define _GNU_SOURCE + #include <dlfcn.h> + + int chdir(const char *path) { + int (*_chdir) (const char *) = dlsym(RTLD_NEXT, "chdir"); + return _chdir(DATA); + } + ''; + + buildInputs = [ makeWrapper ]; + + buildPhase = let + rpath = stdenv.lib.makeLibraryPath [ SDL2 stdenv.cc.cc mesa ]; + fmodRpath = stdenv.lib.makeLibraryPath [ stdenv.cc.cc ]; + in '' + gcc -Werror -shared "$preloader" -o preloader.so -ldl \ + -DDATA=\"$out/share/guacamelee\" + + for i in libfmodevent-4.44.27.so libfmodex-4.44.27.so; do + patchelf --set-rpath "${fmodRpath}:$out/libexec/guacamelee" \ + "x86/lib32/$i" + done + patchelf \ + --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \ + --set-rpath "${rpath}:$out/libexec/guacamelee" x86/game-bin + ''; + + installPhase = '' + install -vD x86/game-bin "$out/libexec/guacamelee/guacamelee" + install -vD preloader.so "$out/libexec/guacamelee/preloader.so" + + makeWrapper "$out/libexec/guacamelee/guacamelee" "$out/bin/guacamelee" \ + --set LD_PRELOAD "$out/libexec/guacamelee/preloader.so" + + for i in libfmodevent-4.44.27.so libfmodex-4.44.27.so; do + install -vD "x86/lib32/$i" "$out/libexec/guacamelee/$i" + done + + mkdir -p "$out/share" + cp -vRd noarch "$out/share/guacamelee" + ''; + + dontStrip = true; +} diff --git a/humblebundle/liads.nix b/humblebundle/liads.nix new file mode 100644 index 00000000..a96af8e0 --- /dev/null +++ b/humblebundle/liads.nix @@ -0,0 +1,43 @@ +{ stdenv, fetchHumbleBundle, unzip, mesa, xorg, libpulseaudio }: + +stdenv.mkDerivation rec { + name = "liads-${version}"; + version = "20160121"; + + src = fetchHumbleBundle { + machineName = "loversinadangerousspacetime_linux"; + suffix = "zip"; + md5 = "0d81adb63ca9233165fb5de415fa5963"; + }; + + unpackCmd = '' + ${unzip}/bin/unzip -qq -d liads "$src" || : + ''; + + arch = if stdenv.system == "x86_64-linux" then "x86_64" else "x86"; + executable = "LoversInADangerousSpacetime.${arch}"; + + buildPhase = let + rpath = stdenv.lib.makeLibraryPath [ + stdenv.cc.cc mesa xorg.libX11 xorg.libXcursor xorg.libXrandr libpulseaudio + ]; + in '' + patchelf \ + --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \ + --set-rpath "${rpath}" "$executable" + ''; + + installPhase = '' + install -vD "$executable" "$out/libexec/liads/liads" + ln -s "$out/share/liads" "$out/libexec/liads/Data" + + mkdir -p "$out/bin" + ln -s "$out/libexec/liads/liads" "$out/bin/liads" + + mkdir -p "$out/share" + cp -vRd LoversInADangerousSpacetime_Data "$out/share/liads" + ''; + + dontStrip = true; + dontPatchELF = true; +} diff --git a/steam/default.nix b/steam/default.nix new file mode 100644 index 00000000..03e6b180 --- /dev/null +++ b/steam/default.nix @@ -0,0 +1,38 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.steam; + + self = rec { + callPackage = pkgs.lib.callPackageWith (pkgs // self); + + fetchSteam = callPackage ./fetchsteam { + inherit (config.steam) username password; + }; + + starbound = callPackage ./starbound.nix { flavor = "stable"; }; + starbound-unstable = callPackage ./starbound.nix { flavor = "unstable"; }; + }; +in with lib; { + options.steam = { + username = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + User name for your Steam account. + ''; + }; + + password = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Password for your Steam account. + ''; + }; + }; + + config.packages = { + steam = mkIf (cfg.username != null && cfg.password != null) self; + }; +} diff --git a/steam/fetchsteam/default.nix b/steam/fetchsteam/default.nix new file mode 100644 index 00000000..cccddb51 --- /dev/null +++ b/steam/fetchsteam/default.nix @@ -0,0 +1,91 @@ +{ stdenv, runCommand, writeText, fetchFromGitHub, buildDotnetPackage +, username, password +}: + +{ name, appId, depotId, manifestId, sha256, fileList ? [] }: + +let + protobuf-net = buildDotnetPackage rec { + baseName = "protobuf-net"; + version = "2.0.0.668"; + + src = fetchFromGitHub { + owner = "mgravell"; + repo = "protobuf-net"; + rev = "r668"; + sha256 = "1060pihqkbr9pd2z6m01d6fsbc9nj56m6y5a0pch9mqdmviv4896"; + }; + + sourceRoot = "${src.name}/${baseName}"; + }; + + SteamKit2 = buildDotnetPackage rec { + baseName = "SteamKit2"; + version = "1.6.4"; + + src = fetchFromGitHub { + owner = "SteamRE"; + repo = "SteamKit"; + rev = "SteamKit_${version}"; + sha256 = "17d7wi2f396qhp4w9sf37lazvsaqws8x071hfis9gv5llv6s7q46"; + }; + + buildInputs = [ protobuf-net ]; + + xBuildFiles = [ "SteamKit2/SteamKit2.sln" ]; + outputFiles = [ "SteamKit2/SteamKit2/bin/Release/*" ]; + }; + + DepotDownloader = buildDotnetPackage rec { + baseName = "DepotDownloader"; + version = "2.1.1git20160207"; + + src = fetchFromGitHub { + owner = "SteamRE"; + repo = baseName; + rev = "5fa6621d9f9448fcd20c974b427a8bd2cb044cb4"; + sha256 = "0vb566d7x1scd96c8ybq6gdbc2cv5jjq453ld458qcvfy587amfn"; + }; + + patches = [ ./downloader.patch ]; + + postPatch = '' + sed -i \ + -e 's/\(<[Rr]eference *[Ii]nclude="[^", ]\+\)[^"]*/\1/g' \ + -e 's,<[Ss]pecific[Vv]ersion>[Tt]rue</[Ss]pecific[Vv]ersion>,,g' \ + DepotDownloader/DepotDownloader.csproj + sed -i -e 's/ version="[^"]*"//g' DepotDownloader/packages.config + ''; + + buildInputs = [ SteamKit2 protobuf-net ]; + + outputFiles = [ "${baseName}/bin/Release/*" ]; + + # UUUGLY, but I don't want to spend a week trying to get this working + # without that nasty wrapper. + makeWrapperArgs = let + mkMono = name: path: "${path}/lib/dotnet/${name}"; + paths = stdenv.lib.mapAttrsToList mkMono { + inherit SteamKit2 protobuf-net; + }; + monoPath = stdenv.lib.concatStringsSep ":" paths; + in [ "--prefix MONO_PATH : \"${monoPath}\"" ]; + }; + + fileListFile = let + content = stdenv.lib.concatStringsSep "\n" fileList; + in writeText "steam-file-list-${name}.txt" content; + +in with stdenv.lib; runCommand "${name}-src" { + buildInputs = [ DepotDownloader ]; + inherit username password appId depotId manifestId; + outputHashAlgo = "sha256"; + outputHash = sha256; + outputHashMode = "recursive"; +} '' + depotdownloader -app "$appId" -depot "$depotId" -manifest "$manifestId" \ + ${optionalString (fileList != []) "-filelist \"${fileListFile}\""} \ + -username "$username" -password "$password" -dir "$out" + rm -r "$out/.DepotDownloader" + rm "$out/_steam_depot_manifest_$depotId.csv" +'' diff --git a/steam/fetchsteam/downloader.patch b/steam/fetchsteam/downloader.patch new file mode 100644 index 00000000..72e5c473 --- /dev/null +++ b/steam/fetchsteam/downloader.patch @@ -0,0 +1,34 @@ +diff --git a/DepotDownloader/ContentDownloader.cs b/DepotDownloader/ContentDownloader.cs +index 21c317e..81f2a93 100644 +--- a/DepotDownloader/ContentDownloader.cs ++++ b/DepotDownloader/ContentDownloader.cs +@@ -34,7 +34,7 @@ namespace DepotDownloader + public string installDir { get; private set; } + public string contentName { get; private set; } + +- public ulong manifestId { get; private set; } ++ public ulong manifestId { get; set; } + public byte[] depotKey; + + public DepotDownloadInfo(uint depotid, ulong manifestId, string installDir, string contentName) +@@ -198,9 +198,6 @@ namespace DepotDownloader + + static ulong GetSteam3DepotManifest(uint depotId, uint appId, string branch) + { +- if (Config.ManifestId != INVALID_MANIFEST_ID) +- return Config.ManifestId; +- + KeyValue depots = GetSteam3AppSection(appId, EAppInfoSection.Depots); + KeyValue depotChild = depots[depotId.ToString()]; + +@@ -583,6 +580,10 @@ namespace DepotDownloader + ConfigStore.TheConfig.LastManifests[depot.id] = INVALID_MANIFEST_ID; + ConfigStore.Save(); + ++ Console.WriteLine("Latest manifest ID is {0}.", depot.manifestId); ++ if (Config.ManifestId != INVALID_MANIFEST_ID) ++ depot.manifestId = Config.ManifestId; ++ + if (lastManifestId != INVALID_MANIFEST_ID) + { + var oldManifestFileName = Path.Combine(configDir, string.Format("{0}.bin", lastManifestId)); diff --git a/steam/starbound.nix b/steam/starbound.nix new file mode 100644 index 00000000..ba63fcfa --- /dev/null +++ b/steam/starbound.nix @@ -0,0 +1,132 @@ +{ stdenv, fetchSteam, makeWrapper, SDL, mesa, flavor ? "stable" }: + +let + renameAttrs = f: let + rename = name: value: { + name = f name; + inherit value; + }; + in stdenv.lib.mapAttrs' rename; + + darwinize = renameAttrs (bin: "Starbound.app/Contents/MacOS/${bin}"); + winize = renameAttrs (bin: "${bin}.exe"); + + mkOsBinaryDeps = with stdenv.lib; + if stdenv.system == "x86_64-darwin" then darwinize + else if elem stdenv.system [ "i686-cygwin" "x86_64-cygwin" ] then winize + else id; + + binaryDeps = mkOsBinaryDeps { + starbound.deps = [ SDL mesa ]; + starbound_server.name = "starbound-server"; + asset_packer.name = "starbound-asset-packer"; + asset_unpacker.name = "starbound-asset-unpacker"; + dump_versioned_json.name = "starbound-dump-versioned-json"; + make_versioned_json.name = "starbound-make-versioned-json"; + planet_mapgen.name = "starbound-planet-mapgen"; + }; + + binpath = if stdenv.system == "x86_64-linux" then "linux64" + else if stdenv.system == "i686-linux" then "linux32" + else if stdenv.system == "x86_64-darwin" then "osx" + else if stdenv.system == "i686-cygwin" then "win32" + else if stdenv.system == "x86_64-cygwin" then "win64" + else throw "Unsupported system ${stdenv.system} for Starbound"; + + upstream = let + attrs = if flavor == "stable" then { + name = "starbound"; + appId = 211820; + depotId = 211821; + manifestId = 1842730272313189605; + sha256 = "0qppfn56c778wsg38hi6sxgi3rl9nv72h9rmmxybi1vzpf3p49py"; + } else if flavor == "unstable" then { + name = "starbound-unstable"; + appId = 367540; + depotId = 367541; + manifestId = 6970641909803280413; + sha256 = "0qppfn56c778wsg38hi6sxgi3rl9nv72h9rmmxybi1vzpf3p49py"; + } else throw "Unsupported flavor, use either `stable' or `unstable'."; + in fetchSteam (attrs // { + fileList = [ + "^(?:assets|tiled)/" + ( "^${binpath}(?:/Starbound\\.app/Contents/MacOS)?" + + "/(?:[a-zA-Z0-9_-]+(?:\\.exe)?|sbboot\\.config)$") + ]; + }); + +in stdenv.mkDerivation { + name = "${upstream.name}-20160208"; + + unpackPhase = ":"; + + configurePhase = '' + libexec="$out/libexec/starbound" + data="$out/share/starbound" + ''; + + inherit binpath upstream; + + buildInputs = [ makeWrapper ]; + + buildPhase = with stdenv.lib; '' + mkdir -p patched + sed -e 's,\.\./assets,'"$data/assets"',g' \ + -e 's,\.\./giraffe_storage,.,g' \ + "$upstream/$binpath/sbboot.config" > "patched/sbboot.config" + '' + concatStrings (mapAttrsToList (bin: attrs: '' + mkdir -p "patched/$(dirname "${bin}")" + cp -t "patched/$(dirname "${bin}")" "$upstream/$binpath/${bin}" + chmod +x "patched/$(basename "${bin}")" + patchelf \ + --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \ + --set-rpath "${stdenv.lib.makeLibraryPath (attrs.deps or [])}" \ + "patched/$(basename "${bin}")" + if ldd "patched/$(basename "${bin}")" | grep -F 'not found'; then + exit 1; + fi + '') binaryDeps); + + doCheck = true; + + checkPhase = '' + checkFailed= + for i in "$upstream/$binpath"/*; do + [ -f "$i" ] || continue + [ "$(basename "$i")" != launcher ] || continue + [ ! -e "patched/$(basename "$i")" ] || continue + + echo "Found missing binary $i from the upstream tree." + checkFailed=1 + done + [ -z "$checkFailed" ] + ''; + + installPhase = '' + mkdir -p "$out/bin" + ${stdenv.lib.concatStrings (stdenv.lib.mapAttrsToList (bin: attrs: '' + prog="$(basename "${bin}")" + install -vD "patched/$prog" "$libexec/$prog" + cat > "$out/bin/${attrs.name or "$prog"}" <<EOF + #!${stdenv.shell} -e + [ -n "\$XDG_DATA_HOME" ] || XDG_DATA_HOME="\$HOME/.local/share" + mkdir -p "\$XDG_DATA_HOME/starbound/mods" + ln -sf "$out/etc/sbboot.config" "\$XDG_DATA_HOME/starbound/sbboot.config" + cd "\$XDG_DATA_HOME/starbound" + exec "$libexec/$prog" "\$@" + EOF + chmod +x "$out/bin/${attrs.name or "$prog"}" + '') binaryDeps)} + + install -vD -m 644 patched/sbboot.config "$out/etc/sbboot.config" + + mkdir -p "$data" + for i in assets tiled; do + echo -n "Installing $i..." + cp -rt "$data" "$upstream/$i" + echo " done." + done + ''; + + dontStrip = true; +} |