at 24.05-pre 277 lines 8.9 kB view raw
1{ lib 2, alsa-lib 3, factorio-utils 4, fetchurl 5, libGL 6, libICE 7, libSM 8, libX11 9, libXcursor 10, libXext 11, libXi 12, libXinerama 13, libXrandr 14, libpulseaudio 15, libxkbcommon 16, makeDesktopItem 17, makeWrapper 18, releaseType 19, stdenv 20, wayland 21 22, mods-dat ? null 23, versionsJson ? ./versions.json 24, username ? "" 25, token ? "" # get/reset token at https://factorio.com/profile 26, experimental ? false # true means to always use the latest branch 27, ... 28} @ args: 29 30assert releaseType == "alpha" 31 || releaseType == "headless" 32 || releaseType == "demo"; 33 34let 35 36 inherit (lib) importJSON; 37 38 mods = args.mods or [ ]; 39 40 helpMsg = '' 41 42 ===FETCH FAILED=== 43 Please ensure you have set the username and token with config.nix, or 44 /etc/nix/nixpkgs-config.nix if on NixOS. 45 46 Your token can be seen at https://factorio.com/profile (after logging in). It is 47 not as sensitive as your password, but should still be safeguarded. There is a 48 link on that page to revoke/invalidate the token, if you believe it has been 49 leaked or wish to take precautions. 50 51 Example: 52 { 53 packageOverrides = pkgs: { 54 factorio = pkgs.factorio.override { 55 username = "FactorioPlayer1654"; 56 token = "d5ad5a8971267c895c0da598688761"; 57 }; 58 }; 59 } 60 61 Alternatively, instead of providing the username+token, you may manually 62 download the release through https://factorio.com/download , then add it to 63 the store using e.g.: 64 65 releaseType=alpha 66 version=0.17.74 67 nix-prefetch-url file://\''$HOME/Downloads/factorio_\''${releaseType}_x64_\''${version}.tar.xz --name factorio_\''${releaseType}_x64-\''${version}.tar.xz 68 69 Note the ultimate "_" is replaced with "-" in the --name arg! 70 ''; 71 72 desktopItem = makeDesktopItem { 73 name = "factorio"; 74 desktopName = "Factorio"; 75 comment = "A game in which you build and maintain factories."; 76 exec = "factorio"; 77 icon = "factorio"; 78 categories = [ "Game" ]; 79 }; 80 81 branch = if experimental then "experimental" else "stable"; 82 83 # NB `experimental` directs us to take the latest build, regardless of its branch; 84 # hence the (stable, experimental) pairs may sometimes refer to the same distributable. 85 versions = importJSON versionsJson; 86 binDists = makeBinDists versions; 87 88 actual = binDists.${stdenv.hostPlatform.system}.${releaseType}.${branch} or (throw "Factorio ${releaseType}-${branch} binaries for ${stdenv.hostPlatform.system} are not available for download."); 89 90 makeBinDists = versions: 91 let 92 f = path: name: value: 93 if builtins.isAttrs value then 94 if value ? "name" then 95 makeBinDist value 96 else 97 builtins.mapAttrs (f (path ++ [ name ])) value 98 else 99 throw "expected attrset at ${toString path} - got ${toString value}"; 100 in 101 builtins.mapAttrs (f [ ]) versions; 102 makeBinDist = { name, version, tarDirectory, url, sha256, needsAuth }: { 103 inherit version tarDirectory; 104 src = 105 if !needsAuth then 106 fetchurl { inherit name url sha256; } 107 else 108 (lib.overrideDerivation 109 (fetchurl { 110 inherit name url sha256; 111 curlOptsList = [ 112 "--get" 113 "--data-urlencode" 114 "username@username" 115 "--data-urlencode" 116 "token@token" 117 ]; 118 }) 119 (_: { 120 # This preHook hides the credentials from /proc 121 preHook = 122 if username != "" && token != "" then '' 123 echo -n "${username}" >username 124 echo -n "${token}" >token 125 '' else '' 126 # Deliberately failing since username/token was not provided, so we can't fetch. 127 # We can't use builtins.throw since we want the result to be used if the tar is in the store already. 128 exit 1 129 ''; 130 failureHook = '' 131 cat <<EOF 132 ${helpMsg} 133 EOF 134 ''; 135 })); 136 }; 137 138 configBaseCfg = '' 139 use-system-read-write-data-directories=false 140 [path] 141 read-data=$out/share/factorio/data/ 142 [other] 143 check_updates=false 144 ''; 145 146 updateConfigSh = '' 147 #! $SHELL 148 if [[ -e ~/.factorio/config.cfg ]]; then 149 # Config file exists, but may have wrong path. 150 # Try to edit it. I'm sure this is perfectly safe and will never go wrong. 151 sed -i 's|^read-data=.*|read-data=$out/share/factorio/data/|' ~/.factorio/config.cfg 152 else 153 # Config file does not exist. Phew. 154 install -D $out/share/factorio/config-base.cfg ~/.factorio/config.cfg 155 fi 156 ''; 157 158 modDir = factorio-utils.mkModDirDrv mods mods-dat; 159 160 base = with actual; { 161 pname = "factorio-${releaseType}"; 162 inherit version src; 163 164 preferLocalBuild = true; 165 dontBuild = true; 166 167 installPhase = '' 168 mkdir -p $out/{bin,share/factorio} 169 cp -a data $out/share/factorio 170 cp -a bin/${tarDirectory}/factorio $out/bin/factorio 171 patchelf \ 172 --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ 173 $out/bin/factorio 174 ''; 175 176 passthru.updateScript = 177 if (username != "" && token != "") then [ 178 ./update.py 179 "--username=${username}" 180 "--token=${token}" 181 ] else null; 182 183 meta = { 184 description = "A game in which you build and maintain factories"; 185 longDescription = '' 186 Factorio is a game in which you build and maintain factories. 187 188 You will be mining resources, researching technologies, building 189 infrastructure, automating production and fighting enemies. Use your 190 imagination to design your factory, combine simple elements into 191 ingenious structures, apply management skills to keep it working and 192 finally protect it from the creatures who don't really like you. 193 194 Factorio has been in development since spring of 2012, and reached 195 version 1.0 in mid 2020. 196 ''; 197 homepage = "https://www.factorio.com/"; 198 sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ]; 199 license = lib.licenses.unfree; 200 maintainers = with lib.maintainers; [ Baughn elitak erictapen priegger lukegb ]; 201 platforms = [ "x86_64-linux" ]; 202 }; 203 }; 204 205 releases = rec { 206 headless = base; 207 demo = base // { 208 209 nativeBuildInputs = [ makeWrapper ]; 210 buildInputs = [ libpulseaudio ]; 211 212 libPath = lib.makeLibraryPath [ 213 alsa-lib 214 libGL 215 libICE 216 libSM 217 libX11 218 libXcursor 219 libXext 220 libXi 221 libXinerama 222 libXrandr 223 libpulseaudio 224 libxkbcommon 225 wayland 226 ]; 227 228 installPhase = base.installPhase + '' 229 wrapProgram $out/bin/factorio \ 230 --prefix LD_LIBRARY_PATH : /run/opengl-driver/lib:$libPath \ 231 --run "$out/share/factorio/update-config.sh" \ 232 --argv0 "" \ 233 --add-flags "-c \$HOME/.factorio/config.cfg" \ 234 ${lib.optionalString (mods!=[]) "--add-flags --mod-directory=${modDir}"} 235 236 # TODO Currently, every time a mod is changed/added/removed using the 237 # modlist, a new derivation will take up the entire footprint of the 238 # client. The only way to avoid this is to remove the mods arg from the 239 # package function. The modsDir derivation will have to be built 240 # separately and have the user specify it in the .factorio config or 241 # right along side it using a symlink into the store I think i will 242 # just remove mods for the client derivation entirely. this is much 243 # cleaner and more useful for headless mode. 244 245 # TODO: trying to toggle off a mod will result in read-only-fs-error. 246 # not much we can do about that except warn the user somewhere. In 247 # fact, no exit will be clean, since this error will happen on close 248 # regardless. just prints an ugly stacktrace but seems to be otherwise 249 # harmless, unless maybe the user forgets and tries to use the mod 250 # manager. 251 252 install -m0644 <(cat << EOF 253 ${configBaseCfg} 254 EOF 255 ) $out/share/factorio/config-base.cfg 256 257 install -m0755 <(cat << EOF 258 ${updateConfigSh} 259 EOF 260 ) $out/share/factorio/update-config.sh 261 262 mkdir -p $out/share/icons/hicolor/{64x64,128x128}/apps 263 cp -a data/core/graphics/factorio-icon.png $out/share/icons/hicolor/64x64/apps/factorio.png 264 cp -a data/core/graphics/factorio-icon@2x.png $out/share/icons/hicolor/128x128/apps/factorio.png 265 ln -s ${desktopItem}/share/applications $out/share/ 266 ''; 267 }; 268 alpha = demo // { 269 270 installPhase = demo.installPhase + '' 271 cp -a doc-html $out/share/factorio 272 ''; 273 }; 274 }; 275 276in 277stdenv.mkDerivation (releases.${releaseType})