mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-22 15:03:28 +00:00
mediagoblin: init at 0.14.0, nixos/mediagoblin: init (#350578)
This commit is contained in:
commit
ef9ef9ea88
@ -1479,6 +1479,7 @@
|
||||
./services/web-apps/ocis.nix
|
||||
./services/web-apps/onlyoffice.nix
|
||||
./services/web-apps/openvscode-server.nix
|
||||
./services/web-apps/mediagoblin.nix
|
||||
./services/web-apps/mobilizon.nix
|
||||
./services/web-apps/openwebrx.nix
|
||||
./services/web-apps/outline.nix
|
||||
|
377
nixos/modules/services/web-apps/mediagoblin.nix
Normal file
377
nixos/modules/services/web-apps/mediagoblin.nix
Normal file
@ -0,0 +1,377 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.mediagoblin;
|
||||
|
||||
mkSubSectionKeyValue =
|
||||
depth: k: v:
|
||||
if lib.isAttrs v then
|
||||
let
|
||||
inherit (lib.strings) replicate;
|
||||
in
|
||||
"${replicate depth "["}${k}${replicate depth "]"}\n"
|
||||
+ lib.generators.toINIWithGlobalSection {
|
||||
mkKeyValue = mkSubSectionKeyValue (depth + 1);
|
||||
} { globalSection = v; }
|
||||
else
|
||||
lib.generators.mkKeyValueDefault {
|
||||
mkValueString = v: if lib.isString v then ''"${v}"'' else lib.generators.mkValueStringDefault { } v;
|
||||
} " = " k v;
|
||||
|
||||
iniFormat = pkgs.formats.ini { };
|
||||
|
||||
# we need to build our own GI_TYPELIB_PATH because celery and paster need this information, too and cannot easily be re-wrapped
|
||||
GI_TYPELIB_PATH =
|
||||
let
|
||||
needsGst =
|
||||
(cfg.settings.mediagoblin.plugins ? "mediagoblin.media_types.audio")
|
||||
|| (cfg.settings.mediagoblin.plugins ? "mediagoblin.media_types.video");
|
||||
in
|
||||
lib.makeSearchPathOutput "out" "lib/girepository-1.0" (
|
||||
with pkgs.gst_all_1;
|
||||
[
|
||||
pkgs.glib
|
||||
gst-plugins-base
|
||||
gstreamer
|
||||
]
|
||||
# audio and video share most dependencies, so we can just take audio
|
||||
++ lib.optionals needsGst cfg.package.optional-dependencies.audio
|
||||
);
|
||||
|
||||
finalPackage = cfg.package.python.buildEnv.override {
|
||||
extraLibs =
|
||||
with cfg.package.python.pkgs;
|
||||
[
|
||||
(toPythonModule cfg.package)
|
||||
]
|
||||
++ cfg.pluginPackages
|
||||
# not documented in extras...
|
||||
++ lib.optional (lib.hasPrefix "postgresql://" cfg.settings.mediagoblin.sql_engine) psycopg2
|
||||
++ (
|
||||
let
|
||||
inherit (cfg.settings.mediagoblin) plugins;
|
||||
in
|
||||
with cfg.package.optional-dependencies;
|
||||
lib.optionals (plugins ? "mediagoblin.media_types.audio") audio
|
||||
++ lib.optionals (plugins ? "mediagoblin.media_types.video") video
|
||||
++ lib.optionals (plugins ? "mediagoblin.media_types.raw_image") raw_image
|
||||
++ lib.optionals (plugins ? "mediagoblin.media_types.ascii") ascii
|
||||
++ lib.optionals (plugins ? "mediagoblin.plugins.ldap") ldap
|
||||
);
|
||||
};
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.mediagoblin = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable MediaGoblin.
|
||||
|
||||
After the initial deployment, make sure to add an admin account:
|
||||
```
|
||||
mediagoblin-gmg adduser --username admin --email admin@example.com
|
||||
mediagoblin-gmg makeadmin admin
|
||||
```
|
||||
'';
|
||||
};
|
||||
|
||||
domain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "mediagoblin.example.com";
|
||||
description = "Domain under which mediagoblin will be served.";
|
||||
};
|
||||
|
||||
createDatabaseLocally = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
example = false;
|
||||
description = "Whether to configure a local postgres database and connect to it.";
|
||||
};
|
||||
|
||||
package = lib.mkPackageOption pkgs "mediagoblin" { };
|
||||
|
||||
pluginPackages = lib.mkOption {
|
||||
type = with lib.types; listOf package;
|
||||
default = [ ];
|
||||
description = "Plugins to add to the environment of MediaGoblin. They still need to be enabled in the config.";
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
description = "Settings which are written into `mediagoblin.ini`.";
|
||||
default = { };
|
||||
type = lib.types.submodule {
|
||||
freeformType = lib.types.anything;
|
||||
|
||||
options = {
|
||||
mediagoblin = {
|
||||
allow_registration = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable user self registration. This is generally not recommend due to spammers.
|
||||
See [upstream FAQ](https://docs.mediagoblin.org/en/stable/siteadmin/production-deployments.html#should-i-keep-open-registration-enabled).
|
||||
'';
|
||||
};
|
||||
|
||||
email_debug_mode = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
example = false;
|
||||
description = ''
|
||||
Disable email debug mode to start sending outgoing mails.
|
||||
This requires configuring SMTP settings,
|
||||
see the [upstream docs](https://docs.mediagoblin.org/en/stable/siteadmin/configuration.html#enabling-email-notifications)
|
||||
for details.
|
||||
'';
|
||||
};
|
||||
|
||||
email_sender_address = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "noreply@example.org";
|
||||
description = "Email address which notices are sent from.";
|
||||
};
|
||||
|
||||
sql_engine = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "sqlite:///var/lib/mediagoblin/mediagoblin.db";
|
||||
example = "postgresql:///mediagoblin";
|
||||
description = "Database to use.";
|
||||
};
|
||||
|
||||
plugins = lib.mkOption {
|
||||
defaultText = ''
|
||||
{
|
||||
"mediagoblin.plugins.geolocation" = { };
|
||||
"mediagoblin.plugins.processing_info" = { };
|
||||
"mediagoblin.plugins.basic_auth" = { };
|
||||
"mediagoblin.media_types.image" = { };
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Plugins to enable. See [upstream docs](https://docs.mediagoblin.org/en/stable/siteadmin/plugins.html) for details.
|
||||
Extra dependencies are automatically enabled.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
paste = {
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 6543;
|
||||
description = "Port under which paste will listen.";
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
description = "Settings which are written into `paste.ini`.";
|
||||
default = { };
|
||||
type = lib.types.submodule {
|
||||
freeformType = iniFormat.type;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellScriptBin "mediagoblin-gmg" ''
|
||||
sudo=exec
|
||||
if [[ "$USER" != mediagoblin ]]; then
|
||||
sudo='exec /run/wrappers/bin/sudo -u mediagoblin'
|
||||
fi
|
||||
$sudo sh -c "cd /var/lib/mediagoblin; env GI_TYPELIB_PATH=${GI_TYPELIB_PATH} ${lib.getExe' finalPackage "gmg"} $@"
|
||||
'')
|
||||
];
|
||||
|
||||
services = {
|
||||
mediagoblin.settings.mediagoblin = {
|
||||
plugins = {
|
||||
"mediagoblin.media_types.image" = { };
|
||||
"mediagoblin.plugins.basic_auth" = { };
|
||||
"mediagoblin.plugins.geolocation" = { };
|
||||
"mediagoblin.plugins.processing_info" = { };
|
||||
};
|
||||
sql_engine = lib.mkIf cfg.createDatabaseLocally "postgresql:///mediagoblin";
|
||||
};
|
||||
|
||||
nginx = {
|
||||
enable = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedProxySettings = true;
|
||||
virtualHosts = {
|
||||
# see https://git.sr.ht/~mediagoblin/mediagoblin/tree/bf61d38df21748aadb480c53fdd928647285e35f/item/nginx.conf.template
|
||||
"${cfg.domain}" = {
|
||||
forceSSL = true;
|
||||
extraConfig = ''
|
||||
# https://git.sr.ht/~mediagoblin/mediagoblin/tree/bf61d38df21748aadb480c53fdd928647285e35f/item/Dockerfile.nginx.in#L5
|
||||
client_max_body_size 100M;
|
||||
|
||||
more_set_headers X-Content-Type-Options nosniff;
|
||||
'';
|
||||
locations = {
|
||||
"/".proxyPass = "http://127.0.0.1:${toString cfg.paste.port}";
|
||||
"/mgoblin_static/".alias = "${finalPackage}/${finalPackage.python.sitePackages}/mediagoblin/static/";
|
||||
"/mgoblin_media/".alias = "/var/lib/mediagoblin/user_dev/media/public/";
|
||||
"/theme_static/".alias = "/var/lib/mediagoblin/user_dev/theme_static/";
|
||||
"/plugin_static/".alias = "/var/lib/mediagoblin/user_dev/plugin_static/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
postgresql = lib.mkIf cfg.createDatabaseLocally {
|
||||
enable = true;
|
||||
ensureDatabases = [ "mediagoblin" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "mediagoblin";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
rabbitmq.enable = true;
|
||||
};
|
||||
|
||||
systemd.services =
|
||||
let
|
||||
serviceDefaults = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path =
|
||||
lib.optionals (cfg.settings.mediagoblin.plugins ? "mediagoblin.media_types.stl") [ pkgs.blender ]
|
||||
++ lib.optionals (cfg.settings.mediagoblin.plugins ? "mediagoblin.media_types.pdf") (
|
||||
with pkgs;
|
||||
[
|
||||
poppler_utils
|
||||
unoconv
|
||||
]
|
||||
);
|
||||
serviceConfig = {
|
||||
AmbientCapabilities = "";
|
||||
CapabilityBoundingSet = [ "" ];
|
||||
DevicePolicy = "closed";
|
||||
Group = "mediagoblin";
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
PrivateTmp = true;
|
||||
ProcSubset = "pid";
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProtectSystem = "strict";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_UNIX"
|
||||
];
|
||||
RemoveIPC = true;
|
||||
StateDirectory = "mediagoblin";
|
||||
StateDirectoryMode = "0750";
|
||||
User = "mediagoblin";
|
||||
WorkingDirectory = "/var/lib/mediagoblin/";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
"@chown"
|
||||
];
|
||||
UMask = "0027";
|
||||
};
|
||||
};
|
||||
|
||||
generatedPasteConfig = iniFormat.generate "paste.ini" cfg.paste.settings;
|
||||
pasteConfig = pkgs.runCommand "paste-combined.ini" { nativeBuildInputs = [ pkgs.crudini ]; } ''
|
||||
cp ${cfg.package.src}/paste.ini $out
|
||||
chmod +w $out
|
||||
crudini --merge $out < ${generatedPasteConfig}
|
||||
'';
|
||||
in
|
||||
{
|
||||
mediagoblin-celeryd = lib.recursiveUpdate serviceDefaults {
|
||||
# we cannot change DEFAULT.data_dir inside mediagoblin.ini because of an annoying bug
|
||||
# https://todo.sr.ht/~mediagoblin/mediagoblin/57
|
||||
preStart = ''
|
||||
cp --remove-destination ${
|
||||
pkgs.writeText "mediagoblin.ini" (
|
||||
lib.generators.toINI { } (lib.filterAttrsRecursive (n: v: n != "plugins") cfg.settings)
|
||||
+ "\n"
|
||||
+ lib.generators.toINI { mkKeyValue = mkSubSectionKeyValue 2; } {
|
||||
inherit (cfg.settings.mediagoblin) plugins;
|
||||
}
|
||||
)
|
||||
} /var/lib/mediagoblin/mediagoblin.ini
|
||||
'';
|
||||
serviceConfig = {
|
||||
Environment = [
|
||||
"CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery"
|
||||
"GI_TYPELIB_PATH=${GI_TYPELIB_PATH}"
|
||||
"MEDIAGOBLIN_CONFIG=/var/lib/mediagoblin/mediagoblin.ini"
|
||||
"PASTE_CONFIG=${pasteConfig}"
|
||||
];
|
||||
ExecStart = "${lib.getExe' finalPackage "celery"} worker --loglevel=INFO";
|
||||
};
|
||||
unitConfig.Description = "MediaGoblin Celery";
|
||||
};
|
||||
|
||||
mediagoblin-paster = lib.recursiveUpdate serviceDefaults {
|
||||
after = [
|
||||
"mediagoblin-celeryd.service"
|
||||
"postgresql.service"
|
||||
];
|
||||
requires = [
|
||||
"mediagoblin-celeryd.service"
|
||||
"postgresql.service"
|
||||
];
|
||||
preStart = ''
|
||||
cp --remove-destination ${pasteConfig} /var/lib/mediagoblin/paste.ini
|
||||
${lib.getExe' finalPackage "gmg"} dbupdate
|
||||
'';
|
||||
serviceConfig = {
|
||||
Environment = [
|
||||
"CELERY_ALWAYS_EAGER=false"
|
||||
"GI_TYPELIB_PATH=${GI_TYPELIB_PATH}"
|
||||
];
|
||||
ExecStart = "${lib.getExe' finalPackage "paster"} serve /var/lib/mediagoblin/paste.ini";
|
||||
};
|
||||
unitConfig.Description = "Mediagoblin";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings."mediagoblin"."/var/lib/mediagoblin/user_dev".d = {
|
||||
group = "mediagoblin";
|
||||
mode = "2750";
|
||||
user = "mediagoblin";
|
||||
};
|
||||
|
||||
users = {
|
||||
groups.mediagoblin = { };
|
||||
users = {
|
||||
mediagoblin = {
|
||||
group = "mediagoblin";
|
||||
home = "/var/lib/mediagoblin";
|
||||
isSystemUser = true;
|
||||
};
|
||||
nginx.extraGroups = [ "mediagoblin" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
13
pkgs/by-name/me/mediagoblin/bower-packages.nix
Normal file
13
pkgs/by-name/me/mediagoblin/bower-packages.nix
Normal file
@ -0,0 +1,13 @@
|
||||
{ fetchbower, buildEnv }:
|
||||
buildEnv {
|
||||
name = "bower-env";
|
||||
ignoreCollisions = true;
|
||||
paths = [
|
||||
(fetchbower "jquery" "2.1.4" "~2.1.3" "1ywrpk2xsr6ghkm3j9gfnl9r3jn6xarfamp99b0bcm57kq9fm2k0")
|
||||
(fetchbower "video.js" "5.20.5" "~5.20.1" "1agvvid2valba7xxypknbb3k578jz8sa4rsmq5z2yc5010k3nkqp")
|
||||
(fetchbower "videojs-resolution-switcher" "0.4.2" "~0.4.2"
|
||||
"1bz2q1wwdglaxbb20fin9djgs1c71jywxhlrm16hm4bzg708ycaf"
|
||||
)
|
||||
(fetchbower "leaflet" "0.7.7" "~0.7.3" "0jim285bljmxxngpm3yx6bnnd10n2whwkgmmhzpcd1rdksnr5nca")
|
||||
];
|
||||
}
|
156
pkgs/by-name/me/mediagoblin/package.nix
Normal file
156
pkgs/by-name/me/mediagoblin/package.nix
Normal file
@ -0,0 +1,156 @@
|
||||
{
|
||||
lib,
|
||||
buildBowerComponents,
|
||||
fetchFromSourcehut,
|
||||
gobject-introspection,
|
||||
gst_all_1,
|
||||
poppler_utils,
|
||||
python3,
|
||||
xorg,
|
||||
}:
|
||||
|
||||
let
|
||||
python = python3.override {
|
||||
packageOverrides = final: prev: {
|
||||
celery = prev.celery.overridePythonAttrs {
|
||||
doCheck = false;
|
||||
};
|
||||
sqlalchemy = prev.sqlalchemy_1_4;
|
||||
};
|
||||
};
|
||||
|
||||
version = "0.14.0";
|
||||
src = fetchFromSourcehut {
|
||||
owner = "~mediagoblin";
|
||||
repo = "mediagoblin";
|
||||
rev = "v${version}";
|
||||
fetchSubmodules = true;
|
||||
hash = "sha256-Y1VnXLHEl6TR8nt+vKSfoCwleQ+oA2WPMN9q4fW9R3s=";
|
||||
};
|
||||
|
||||
extlib = buildBowerComponents {
|
||||
name = "mediagoblin-extlib";
|
||||
generated = ./bower-packages.nix;
|
||||
inherit src;
|
||||
};
|
||||
in
|
||||
python.pkgs.buildPythonApplication rec {
|
||||
pname = "mediagoblin";
|
||||
inherit version src;
|
||||
|
||||
postPatch = ''
|
||||
# https://git.sr.ht/~mediagoblin/mediagoblin/tree/bf61d38df21748aadb480c53fdd928647285e35f/item/.guix/modules/mediagoblin-package.scm#L60-62
|
||||
cp mediagoblin/_version.py.in mediagoblin/_version.py
|
||||
substituteInPlace mediagoblin/_version.py \
|
||||
--replace-fail "@PACKAGE_VERSION@" "${version}"
|
||||
|
||||
# https://git.sr.ht/~mediagoblin/mediagoblin/tree/bf61d38df21748aadb480c53fdd928647285e35f/item/.guix/modules/mediagoblin-package.scm#L66-67
|
||||
substituteInPlace mediagoblin/gmg_commands/__init__.py \
|
||||
--replace-fail "ArgumentParser(" "ArgumentParser(prog=\"gmg\","
|
||||
'';
|
||||
|
||||
nativeBuildInputs = [
|
||||
gobject-introspection
|
||||
python3.pkgs.babel
|
||||
xorg.lndir
|
||||
];
|
||||
|
||||
build-system = with python.pkgs; [
|
||||
setuptools
|
||||
];
|
||||
|
||||
dependencies = with python.pkgs; [
|
||||
alembic
|
||||
babel
|
||||
bcrypt
|
||||
celery
|
||||
certifi
|
||||
configobj
|
||||
email-validator
|
||||
exifread
|
||||
feedgenerator
|
||||
itsdangerous
|
||||
jinja2
|
||||
jsonschema
|
||||
lxml-html-clean
|
||||
markdown
|
||||
oauthlib
|
||||
pastescript
|
||||
pillow
|
||||
pyld
|
||||
python-dateutil
|
||||
requests
|
||||
soundfile
|
||||
sqlalchemy
|
||||
unidecode
|
||||
waitress
|
||||
werkzeug
|
||||
wtforms
|
||||
wtforms-sqlalchemy
|
||||
|
||||
# undocumented and fails to start without
|
||||
gst-python
|
||||
pygobject3
|
||||
];
|
||||
|
||||
optional-dependencies =
|
||||
with python.pkgs;
|
||||
let
|
||||
# not really documented in python build system
|
||||
gst = with gst_all_1; [
|
||||
# https://git.sr.ht/~mediagoblin/mediagoblin/tree/bf61d38df21748aadb480c53fdd928647285e35f/item/.guix/modules/mediagoblin-package.scm#L122-127
|
||||
gst-libav
|
||||
gst-plugins-bad
|
||||
gst-plugins-base
|
||||
gst-plugins-good
|
||||
gst-plugins-ugly
|
||||
gstreamer
|
||||
];
|
||||
in
|
||||
{
|
||||
ascii = [ chardet ];
|
||||
audio = [ numpy ] ++ gst;
|
||||
ldap = [ python-ldap ];
|
||||
openid = [ python3-openid ];
|
||||
raw_image = [ py3exiv2 ];
|
||||
video = [ pygobject3 ] ++ gst;
|
||||
};
|
||||
|
||||
postBuild = ''
|
||||
./devtools/compile_translations.sh
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
lndir -silent ${extlib}/bower_components/ $out/${python.sitePackages}/mediagoblin/static/extlib/
|
||||
|
||||
ln -rs $out/${python.sitePackages}/mediagoblin/static/extlib/jquery/dist/jquery.js $out/${python.sitePackages}/mediagoblin/static/js/extlib/jquery.js
|
||||
ln -rs $out/${python.sitePackages}/mediagoblin/static/extlib/leaflet/dist/leaflet.css $out/${python.sitePackages}/mediagoblin/static/extlib/leaflet/leaflet.css
|
||||
ln -rs $out/${python.sitePackages}/mediagoblin/static/extlib/leaflet/dist/leaflet.js $out/${python.sitePackages}/mediagoblin/static/extlib/leaflet/leaflet.js
|
||||
ln -rs $out/${python.sitePackages}/mediagoblin/static/extlib/leaflet/dist/images/ $out/${python.sitePackages}/mediagoblin/static/extlib/leaflet/
|
||||
'';
|
||||
|
||||
nativeCheckInputs =
|
||||
with python.pkgs;
|
||||
[
|
||||
pytest-forked
|
||||
pytest-xdist
|
||||
pytestCheckHook
|
||||
webtest
|
||||
|
||||
poppler_utils
|
||||
]
|
||||
++ lib.flatten (lib.attrValues optional-dependencies);
|
||||
|
||||
pythonImportsCheck = [ "mediagoblin" ];
|
||||
|
||||
passthru = {
|
||||
inherit python;
|
||||
};
|
||||
|
||||
meta = {
|
||||
description = "Free software media publishing platform that anyone can run";
|
||||
homepage = "https://mediagoblin.org/";
|
||||
license = lib.licenses.agpl3Plus;
|
||||
maintainers = lib.teams.c3d2.members;
|
||||
};
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
{
|
||||
lib,
|
||||
buildPythonPackage,
|
||||
fetchFromGitHub,
|
||||
pytestCheckHook,
|
||||
setuptools,
|
||||
sqlalchemy,
|
||||
wtforms,
|
||||
}:
|
||||
|
||||
buildPythonPackage rec {
|
||||
pname = "wtforms-sqlalchemy";
|
||||
version = "0.4.1";
|
||||
pyproject = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "wtforms";
|
||||
repo = "wtforms-sqlalchemy";
|
||||
rev = version;
|
||||
hash = "sha256-uR09LYfcyre+AC2TTEIhpjSI7y4Yo0GJ20smkzo5PRY=";
|
||||
};
|
||||
|
||||
build-system = [
|
||||
setuptools
|
||||
];
|
||||
|
||||
dependencies = [
|
||||
sqlalchemy
|
||||
wtforms
|
||||
];
|
||||
|
||||
nativeCheckInputs = [
|
||||
pytestCheckHook
|
||||
];
|
||||
|
||||
pythonImportsCheck = [ "wtforms_sqlalchemy" ];
|
||||
|
||||
meta = {
|
||||
description = "WTForms integration for SQLAlchemy";
|
||||
homepage = "https://github.com/wtforms/wtforms-sqlalchemy";
|
||||
changelog = "https://github.com/wtforms/wtforms-sqlalchemy/blob/${version}/CHANGES.rst";
|
||||
license = lib.licenses.bsd3;
|
||||
maintainers = with lib.maintainers; [ SuperSandro2000 ];
|
||||
};
|
||||
}
|
@ -17740,6 +17740,8 @@ self: super: with self; {
|
||||
|
||||
wtforms-bootstrap5 = callPackage ../development/python-modules/wtforms-bootstrap5 { };
|
||||
|
||||
wtforms-sqlalchemy = callPackage ../development/python-modules/wtforms-sqlalchemy { };
|
||||
|
||||
wunsen = callPackage ../development/python-modules/wunsen { };
|
||||
|
||||
wtf-peewee = callPackage ../development/python-modules/wtf-peewee { };
|
||||
|
Loading…
Reference in New Issue
Block a user