mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
Build nix packages from source (#253)
* nix: get source tarball with update.py * nix: build from source nix: remove u2c and partyfuse packages The main copyparty package has u2c and partyfuse, so these packages are redundant now nix: add fusepy dependency fix: nix: use replace pyfuse with fusepy * nix: fix extra python packages * nix: add optional dependencies * nix: add partftpy package * nix: add tftp parameter to package * nix: enable pyproject for partftpy package * nix: replace partftpy overlay with real package * nix: add updater for partftpy * nix: bring back local release pin to update.py nix: update local release pin function in update.py --------- Signed-off-by: Toast <39011842+toast003@users.noreply.github.com>
This commit is contained in:
parent
43a19779c1
commit
187cae25bf
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
stdenv,
|
buildPythonApplication,
|
||||||
makeWrapper,
|
|
||||||
fetchurl,
|
fetchurl,
|
||||||
util-linux,
|
util-linux,
|
||||||
python,
|
python,
|
||||||
|
setuptools,
|
||||||
jinja2,
|
jinja2,
|
||||||
impacket,
|
impacket,
|
||||||
pyopenssl,
|
pyopenssl,
|
||||||
|
@ -15,6 +15,10 @@
|
||||||
pyzmq,
|
pyzmq,
|
||||||
ffmpeg,
|
ffmpeg,
|
||||||
mutagen,
|
mutagen,
|
||||||
|
pyftpdlib,
|
||||||
|
magic,
|
||||||
|
partftpy,
|
||||||
|
fusepy, # for partyfuse
|
||||||
|
|
||||||
# use argon2id-hashed passwords in config files (sha2 is always available)
|
# use argon2id-hashed passwords in config files (sha2 is always available)
|
||||||
withHashedPasswords ? true,
|
withHashedPasswords ? true,
|
||||||
|
@ -40,12 +44,21 @@
|
||||||
# send ZeroMQ messages from event-hooks
|
# send ZeroMQ messages from event-hooks
|
||||||
withZeroMQ ? true,
|
withZeroMQ ? true,
|
||||||
|
|
||||||
|
# enable FTP server
|
||||||
|
withFTP ? true,
|
||||||
|
|
||||||
# enable FTPS support in the FTP server
|
# enable FTPS support in the FTP server
|
||||||
withFTPS ? false,
|
withFTPS ? false,
|
||||||
|
|
||||||
|
# enable TFTP server
|
||||||
|
withTFTP ? false,
|
||||||
|
|
||||||
# samba/cifs server; dangerous and buggy, enable if you really need it
|
# samba/cifs server; dangerous and buggy, enable if you really need it
|
||||||
withSMB ? false,
|
withSMB ? false,
|
||||||
|
|
||||||
|
# enables filetype detection for nameless uploads
|
||||||
|
withMagic ? false,
|
||||||
|
|
||||||
# extra packages to add to the PATH
|
# extra packages to add to the PATH
|
||||||
extraPackages ? [ ],
|
extraPackages ? [ ],
|
||||||
|
|
||||||
|
@ -58,14 +71,23 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
pinData = lib.importJSON ./pin.json;
|
pinData = lib.importJSON ./pin.json;
|
||||||
pyEnv = python.withPackages (
|
runtimeDeps = ([ util-linux ] ++ extraPackages ++ lib.optional withMediaProcessing ffmpeg);
|
||||||
ps:
|
in
|
||||||
with ps;
|
buildPythonApplication {
|
||||||
|
pname = "copyparty";
|
||||||
|
inherit (pinData) version;
|
||||||
|
src = fetchurl {
|
||||||
|
inherit (pinData) url hash;
|
||||||
|
};
|
||||||
|
dependencies =
|
||||||
[
|
[
|
||||||
jinja2
|
jinja2
|
||||||
|
fusepy
|
||||||
]
|
]
|
||||||
++ lib.optional withSMB impacket
|
++ lib.optional withSMB impacket
|
||||||
|
++ lib.optional withFTP pyftpdlib
|
||||||
++ lib.optional withFTPS pyopenssl
|
++ lib.optional withFTPS pyopenssl
|
||||||
|
++ lib.optional withTFTP partftpy
|
||||||
++ lib.optional withCertgen cfssl
|
++ lib.optional withCertgen cfssl
|
||||||
++ lib.optional withThumbnails pillow
|
++ lib.optional withThumbnails pillow
|
||||||
++ lib.optional withFastThumbnails pyvips
|
++ lib.optional withFastThumbnails pyvips
|
||||||
|
@ -73,25 +95,14 @@ let
|
||||||
++ lib.optional withBasicAudioMetadata mutagen
|
++ lib.optional withBasicAudioMetadata mutagen
|
||||||
++ lib.optional withHashedPasswords argon2-cffi
|
++ lib.optional withHashedPasswords argon2-cffi
|
||||||
++ lib.optional withZeroMQ pyzmq
|
++ lib.optional withZeroMQ pyzmq
|
||||||
++ (extraPythonPackages ps)
|
++ lib.optional withMagic magic
|
||||||
);
|
++ (extraPythonPackages python.pkgs);
|
||||||
|
makeWrapperArgs = [ "--prefix PATH : ${lib.makeBinPath runtimeDeps}" ];
|
||||||
|
|
||||||
runtimeDeps = ([ util-linux ] ++ extraPackages ++ lib.optional withMediaProcessing ffmpeg);
|
pyproject = true;
|
||||||
in
|
build-system = [
|
||||||
stdenv.mkDerivation {
|
setuptools
|
||||||
pname = "copyparty";
|
];
|
||||||
inherit (pinData) version;
|
|
||||||
src = fetchurl {
|
|
||||||
inherit (pinData) url hash;
|
|
||||||
};
|
|
||||||
nativeBuildInputs = [ makeWrapper ];
|
|
||||||
dontUnpack = true;
|
|
||||||
installPhase = ''
|
|
||||||
install -Dm755 $src $out/share/copyparty-sfx.py
|
|
||||||
makeWrapper ${pyEnv.interpreter} $out/bin/copyparty \
|
|
||||||
--prefix PATH : ${lib.makeBinPath runtimeDeps} \
|
|
||||||
--add-flag $out/share/copyparty-sfx.py
|
|
||||||
'';
|
|
||||||
meta = {
|
meta = {
|
||||||
description = "Turn almost any device into a file server";
|
description = "Turn almost any device into a file server";
|
||||||
longDescription = ''
|
longDescription = ''
|
||||||
|
@ -101,8 +112,7 @@ stdenv.mkDerivation {
|
||||||
homepage = "https://github.com/9001/copyparty";
|
homepage = "https://github.com/9001/copyparty";
|
||||||
changelog = "https://github.com/9001/copyparty/releases/tag/v${pinData.version}";
|
changelog = "https://github.com/9001/copyparty/releases/tag/v${pinData.version}";
|
||||||
license = lib.licenses.mit;
|
license = lib.licenses.mit;
|
||||||
inherit (python.meta) platforms;
|
|
||||||
mainProgram = "copyparty";
|
mainProgram = "copyparty";
|
||||||
sourceProvenance = [ lib.sourceTypes.binaryBytecode ];
|
sourceProvenance = [ lib.sourceTypes.fromSource ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"url": "https://github.com/9001/copyparty/releases/download/v1.19.1/copyparty-sfx.py",
|
"url": "https://github.com/9001/copyparty/releases/download/v1.19.1/copyparty-1.19.1.tar.gz",
|
||||||
"version": "1.19.1",
|
"version": "1.19.1",
|
||||||
"hash": "sha256-Orn0N//DD5/5rIWK9yYRcvyOnt/bKCE9CeoxkfNO76s="
|
"hash": "sha256-u8JQ2yPrgLyWwnsu+kVs4ef0nH36q625GlcfcAZLb5E="
|
||||||
}
|
}
|
|
@ -11,14 +11,14 @@ import base64
|
||||||
import json
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
import sys
|
import sys
|
||||||
import re
|
import tarfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
OUTPUT_FILE = Path("pin.json")
|
OUTPUT_FILE = Path("pin.json")
|
||||||
TARGET_ASSET = "copyparty-sfx.py"
|
TARGET_ASSET = lambda version: f"copyparty-{version}.tar.gz"
|
||||||
HASH_TYPE = "sha256"
|
HASH_TYPE = "sha256"
|
||||||
LATEST_RELEASE_URL = "https://api.github.com/repos/9001/copyparty/releases/latest"
|
LATEST_RELEASE_URL = "https://api.github.com/repos/9001/copyparty/releases/latest"
|
||||||
DOWNLOAD_URL = lambda version: f"https://github.com/9001/copyparty/releases/download/v{version}/{TARGET_ASSET}"
|
DOWNLOAD_URL = lambda version: f"https://github.com/9001/copyparty/releases/download/v{version}/{TARGET_ASSET(version)}"
|
||||||
|
|
||||||
|
|
||||||
def get_formatted_hash(binary):
|
def get_formatted_hash(binary):
|
||||||
|
@ -29,11 +29,13 @@ def get_formatted_hash(binary):
|
||||||
return f"{HASH_TYPE}-{encoded_hash}"
|
return f"{HASH_TYPE}-{encoded_hash}"
|
||||||
|
|
||||||
|
|
||||||
def version_from_sfx(binary):
|
def version_from_tar_gz(path):
|
||||||
result = re.search(b'^VER = "(.*)"$', binary, re.MULTILINE)
|
with tarfile.open(path) as tarball:
|
||||||
if result:
|
release_name = tarball.getmembers()[0].name
|
||||||
return result.groups(1)[0].decode("ascii")
|
prefix = "copyparty-"
|
||||||
|
|
||||||
|
if release_name.startswith(prefix):
|
||||||
|
return release_name.replace(prefix, "")
|
||||||
raise ValueError("version not found in provided file")
|
raise ValueError("version not found in provided file")
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,7 +44,7 @@ def remote_release_pin():
|
||||||
|
|
||||||
response = requests.get(LATEST_RELEASE_URL).json()
|
response = requests.get(LATEST_RELEASE_URL).json()
|
||||||
version = response["tag_name"].lstrip("v")
|
version = response["tag_name"].lstrip("v")
|
||||||
asset_info = [a for a in response["assets"] if a["name"] == TARGET_ASSET][0]
|
asset_info = [a for a in response["assets"] if a["name"] == TARGET_ASSET(version)][0]
|
||||||
download_url = asset_info["browser_download_url"]
|
download_url = asset_info["browser_download_url"]
|
||||||
asset = requests.get(download_url)
|
asset = requests.get(download_url)
|
||||||
formatted_hash = get_formatted_hash(asset.content)
|
formatted_hash = get_formatted_hash(asset.content)
|
||||||
|
@ -52,10 +54,9 @@ def remote_release_pin():
|
||||||
|
|
||||||
|
|
||||||
def local_release_pin(path):
|
def local_release_pin(path):
|
||||||
asset = path.read_bytes()
|
version = version_from_tar_gz(path)
|
||||||
version = version_from_sfx(asset)
|
|
||||||
download_url = DOWNLOAD_URL(version)
|
download_url = DOWNLOAD_URL(version)
|
||||||
formatted_hash = get_formatted_hash(asset)
|
formatted_hash = get_formatted_hash(path.read_bytes())
|
||||||
|
|
||||||
result = {"url": download_url, "version": version, "hash": formatted_hash}
|
result = {"url": download_url, "version": version, "hash": formatted_hash}
|
||||||
return result
|
return result
|
||||||
|
|
30
contrib/package/nix/partftpy/default.nix
Normal file
30
contrib/package/nix/partftpy/default.nix
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
buildPythonPackage,
|
||||||
|
fetchurl,
|
||||||
|
setuptools,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
pinData = lib.importJSON ./pin.json;
|
||||||
|
in
|
||||||
|
|
||||||
|
buildPythonPackage rec {
|
||||||
|
pname = "partftpy";
|
||||||
|
inherit (pinData) version;
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
inherit (pinData) url hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
build-system = [ setuptools ];
|
||||||
|
|
||||||
|
pythonImportsCheck = [ "partftpy.TftpServer" ];
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Pure Python TFTP library (copyparty edition)";
|
||||||
|
homepage = "https://github.com/9001/partftpy";
|
||||||
|
changelog = "https://github.com/9001/partftpy/releases/tag/${version}";
|
||||||
|
license = lib.licenses.mit;
|
||||||
|
};
|
||||||
|
}
|
5
contrib/package/nix/partftpy/pin.json
Normal file
5
contrib/package/nix/partftpy/pin.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"url": "https://github.com/9001/partftpy/releases/download/v0.4.0/partftpy-0.4.0.tar.gz",
|
||||||
|
"version": "0.4.0",
|
||||||
|
"hash": "sha256-5Q2zyuJ892PGZmb+YXg0ZPW/DK8RDL1uE0j5HPd4We0="
|
||||||
|
}
|
50
contrib/package/nix/partftpy/update.py
Executable file
50
contrib/package/nix/partftpy/update.py
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Update the Nix package pin
|
||||||
|
#
|
||||||
|
# Usage: ./update.sh
|
||||||
|
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import hashlib
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
OUTPUT_FILE = Path("pin.json")
|
||||||
|
TARGET_ASSET = lambda version: f"partftpy-{version}.tar.gz"
|
||||||
|
HASH_TYPE = "sha256"
|
||||||
|
LATEST_RELEASE_URL = "https://api.github.com/repos/9001/partftpy/releases/latest"
|
||||||
|
|
||||||
|
|
||||||
|
def get_formatted_hash(binary):
|
||||||
|
hasher = hashlib.new("sha256")
|
||||||
|
hasher.update(binary)
|
||||||
|
asset_hash = hasher.digest()
|
||||||
|
encoded_hash = base64.b64encode(asset_hash).decode("ascii")
|
||||||
|
return f"{HASH_TYPE}-{encoded_hash}"
|
||||||
|
|
||||||
|
|
||||||
|
def remote_release_pin():
|
||||||
|
import requests
|
||||||
|
|
||||||
|
response = requests.get(LATEST_RELEASE_URL).json()
|
||||||
|
version = response["tag_name"].lstrip("v")
|
||||||
|
asset_info = [a for a in response["assets"] if a["name"] == TARGET_ASSET(version)][0]
|
||||||
|
download_url = asset_info["browser_download_url"]
|
||||||
|
asset = requests.get(download_url)
|
||||||
|
formatted_hash = get_formatted_hash(asset.content)
|
||||||
|
|
||||||
|
result = {"url": download_url, "version": version, "hash": formatted_hash}
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
result = remote_release_pin()
|
||||||
|
|
||||||
|
print(result)
|
||||||
|
json_result = json.dumps(result, indent=4)
|
||||||
|
OUTPUT_FILE.write_text(json_result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
stdenvNoCC,
|
|
||||||
copyparty,
|
|
||||||
python3,
|
|
||||||
makeBinaryWrapper,
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
python = python3.withPackages (p: [ p.fusepy ]);
|
|
||||||
in
|
|
||||||
stdenvNoCC.mkDerivation {
|
|
||||||
pname = "partyfuse";
|
|
||||||
inherit (copyparty) version meta;
|
|
||||||
src = ../../../..;
|
|
||||||
|
|
||||||
nativeBuildInputs = [ makeBinaryWrapper ];
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
|
|
||||||
install -Dm444 bin/partyfuse.py -t $out/share/copyparty
|
|
||||||
makeWrapper ${python.interpreter} $out/bin/partyfuse \
|
|
||||||
--add-flag $out/share/copyparty/partyfuse.py
|
|
||||||
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
{
|
|
||||||
stdenvNoCC,
|
|
||||||
copyparty,
|
|
||||||
python312,
|
|
||||||
makeBinaryWrapper,
|
|
||||||
}:
|
|
||||||
stdenvNoCC.mkDerivation {
|
|
||||||
pname = "u2c";
|
|
||||||
inherit (copyparty) version meta;
|
|
||||||
src = ../../../..;
|
|
||||||
|
|
||||||
nativeBuildInputs = [ makeBinaryWrapper ];
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
|
|
||||||
install -Dm444 bin/u2c.py -t $out/share/copyparty
|
|
||||||
mkdir $out/bin
|
|
||||||
makeWrapper ${python312.interpreter} $out/bin/u2c \
|
|
||||||
--add-flag $out/share/copyparty/u2c.py
|
|
||||||
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
}
|
|
13
flake.nix
13
flake.nix
|
@ -12,17 +12,14 @@
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
nixosModules.default = ./contrib/nixos/modules/copyparty.nix;
|
nixosModules.default = ./contrib/nixos/modules/copyparty.nix;
|
||||||
overlays.default = final: prev: rec {
|
overlays.default = final: prev: {
|
||||||
copyparty = final.python3.pkgs.callPackage ./contrib/package/nix/copyparty {
|
copyparty = final.python3.pkgs.callPackage ./contrib/package/nix/copyparty {
|
||||||
ffmpeg = final.ffmpeg-full;
|
ffmpeg = final.ffmpeg-full;
|
||||||
};
|
};
|
||||||
|
python3 = prev.python3.override {
|
||||||
partyfuse = prev.callPackage ./contrib/package/nix/partyfuse {
|
packageOverrides = pyFinal: pyPrev: {
|
||||||
inherit copyparty;
|
partftpy = pyFinal.callPackage ./contrib/package/nix/partftpy { };
|
||||||
};
|
};
|
||||||
|
|
||||||
u2c = prev.callPackage ./contrib/package/nix/u2c {
|
|
||||||
inherit copyparty;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -54,8 +51,6 @@
|
||||||
packages = {
|
packages = {
|
||||||
inherit (pkgs)
|
inherit (pkgs)
|
||||||
copyparty
|
copyparty
|
||||||
partyfuse
|
|
||||||
u2c
|
|
||||||
;
|
;
|
||||||
default = self.packages.${system}.copyparty;
|
default = self.packages.${system}.copyparty;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue