update packages / nix packaging

master
tuxcoder 2023-09-30 12:58:24 +02:00
parent 230d3e5fe8
commit 536668d8b9
11 changed files with 254 additions and 180 deletions

2
.gitignore vendored
View File

@ -10,3 +10,5 @@ node_modules
*.egg-info
/.tox
/dist
build
result

View File

@ -1,3 +1,6 @@
{
"nixEnvSelector.nixFile": "${workspaceRoot}/shell.nix"
"nixEnvSelector.suggestion": false,
"nixEnvSelector.nixFile": "${workspaceRoot}/shell.nix",
"python.linting.mypyEnabled": true,
"python.linting.enabled": true
}

View File

@ -16,14 +16,32 @@
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nix-node-package": {
"flake": false,
"locked": {
"lastModified": 1645439390,
"narHash": "sha256-mYkNbWBzQkv7O0mVZ4llqo9ZNeeo/IWPJk5WMa34SgQ=",
"lastModified": 1694372307,
"narHash": "sha256-18dhHWJfa0QB0fPsaYvRwGd86BVn6xMkN6mDmiDKack=",
"owner": "mkg20001",
"repo": "nix-node-package",
"rev": "03285e212016db5f28530563b58cfcc5706ff73f",
"rev": "97ac59276f12f768062e4eb336fc77079d5fb6a0",
"type": "github"
},
"original": {
@ -34,11 +52,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1679037998,
"narHash": "sha256-WnlfwX3IbZ/+hgxNZokGBVDwN7EciJA3ivrKQqoRr00=",
"lastModified": 1696022471,
"narHash": "sha256-3U5nqHQ9JFUoY4GJ89ErqzRmkgAhPYjbPn4vP+CpltM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1a19ae5b677797c0f2ba4f28304dd054964ed3b9",
"rev": "336d12bc4cdb0980f5ff450d7bc599bdb4ed5e74",
"type": "github"
},
"original": {
@ -50,9 +68,25 @@
"root": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"nix-node-package": "nix-node-package",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

166
flake.nix
View File

@ -2,7 +2,8 @@
description = "Lenticular cloud interface";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-compat = {
flake-utils.url = "github:numtide/flake-utils";
flake-compat = { # for shell.nix
url = "github:edolstra/flake-compat";
flake = false;
};
@ -11,150 +12,33 @@
flake = false;
};
};
outputs = inputs@{ self, nixpkgs, nix-node-package, ... }:
let
makeNode = nix-node-package.lib.nix-node-package.makeNode;
node-env = makeNode { };
pkgs = nixpkgs.legacyPackages.x86_64-linux;
python_default = pkgs.python310;
nodejs = pkgs.nodejs;
lenticular_cloud = {python}: with python.pkgs; let
outputs = { self, nixpkgs, nix-node-package, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = nixpkgs.legacyPackages.${system}.extend (import ./overlay.nix);
in rec {
formatter = pkgs.nixpkgs-fmt;
devShells.default = pkgs.python3.withPackages (ps: (
pkgs.lenticular-cloud.propagatedBuildInputs ++
pkgs.lenticular-cloud.testBuildInputs
));
urlobject = buildPythonPackage rec {
pname = "URLObject";
version = "2.4.3";
src = fetchPypi {
inherit pname version;
sha256 = "47b2e20e6ab9c8366b2f4a3566b6ff4053025dad311c4bb71279bbcfa2430caa";
};
doCheck = true;
propagatedBuildInputs = [
];
};
flask-dance = with python.pkgs; buildPythonPackage rec {
pname = "Flask-Dance";
version = "6.0.0";
src = fetchPypi {
inherit pname version;
sha256 = "15bb3c412eb789a2d904bfd0fd44aac2d94f82703a51d14123fd336136d55db0";
};
doCheck = false;
propagatedBuildInputs = [
requests
oauthlib
requests_oauthlib
flask
urlobject
];
checkInputs = [
pytest
nose
pytest-mock
responses
freezegun
coverage
# testing sqlalchemy support
sqlalchemy
flask_sqlalchemy
# testing integration with other extensions
flask_login
flask-caching
betamax
# we need the `signedtoken` extra for `oauthlib`
# oauthlib[signedtoken]
];
packages.default = pkgs.lenticular-cloud;
};
ory-hydra-client = buildPythonPackage rec {
pname = "ory-hydra-client";
version = "2.0.3";
src = ./libs/ory-hydra-client;
# doCheck = false;
propagatedBuildInputs = [
urllib3
python-dateutil
attrs
httpx
];
};
in
buildPythonApplication rec { # TODO change to buildPythonApplication
pname = "lenticular_cloud";
version = "0.2";
src = ./.;
propagatedBuildInputs = [
flask
flask-restful
flask_sqlalchemy
flask_wtf
flask-babel
flask_login
requests
requests_oauthlib
ldap3
#ldap3-orm
pyotp
cryptography
blinker
ory-hydra-client
authlib # as oauth client lib
fido2 # for webauthn
flask_migrate # db migrations
nodejs
#node-env
gunicorn
flask-dance
];
testBuildInputs = with python.pkgs; [
pytest
pytest-mypy
flask_testing
tox
types-dateutil
nose
mypy
];
passthru = {
inherit python;
pythonPath = python.pkgs.makePythonPath propagatedBuildInputs;
};
doCheck = false;
checkInputs = [
pytest
] ++ lenticular_settings.testBuildInputs;
checks = {
package = packages.default;
devShells = devShells.default;
};
in {
formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixpkgs-fmt;
#packages.x86_64-linux.default = import ./shell.nix { inherit pkgs; };
# TODO
packages.x86_64-linux.default = lenticular_cloud {python=python_default;};
}) // {
nixosModules = {
default = (import "${self}/module.nix" { inherit lenticular_cloud; });
default = import ./module.nix;
};
overlays.default = import ./overlay.nix;
nixosConfigurations.testSystem = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
self.nixosModules.default
"${nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix"
];
};
};
}
#ldap3-orm = with python.pkgs; buildPythonPackage rec {
# pname = "ldap3-orm";
# version = "2.7.0";
# src = fetchPypi {
# inherit pname version;
# sha256 = "8783886d4ce90d66da61ce24619593a265b50f0de1fbebe86df95c6788661664";
# };
# doCheck = false;
# propagatedBuildInputs = [
# ldap3
# six
# ];#
#};

View File

@ -11,12 +11,14 @@ import logging
import crypt
import secrets
import string
from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Mapped, mapped_column, relationship, declarative_base
from flask_sqlalchemy import SQLAlchemy
from flask_sqlalchemy.model import Model, DefaultMeta
from flask_sqlalchemy.extension import _FSAModel
from flask_migrate import Migrate
from datetime import datetime
import uuid
import pyotp
from typing import Optional, Callable
from typing import Optional, List, Dict, Tuple, Any, Type, TYPE_CHECKING
from cryptography.x509 import Certificate as CertificateObj
from sqlalchemy.ext.declarative import DeclarativeMeta
@ -28,8 +30,17 @@ logger = logging.getLogger(__name__)
db = SQLAlchemy()
migrate = Migrate()
class BaseModelIntern(MappedAsDataclass, DeclarativeBase):
pass
BaseModel: DeclarativeMeta = db.Model
if TYPE_CHECKING:
class BaseModel (_FSAModel,BaseModelIntern):
pass
else:
BaseModel: Type[_FSAModel] = db.Model
class ModelUpdatedMixin:
created_at: Mapped[datetime] = mapped_column(db.DateTime, default=datetime.now())
last_update: Mapped[datetime] = mapped_column(db.DateTime, default=datetime.now(), onupdate=datetime.now)
class SecurityUser(UserMixin):

View File

@ -14,24 +14,24 @@ LANGUAGES = {
def get_locale() -> str:
# if a user is logged in, use the locale from the user settings
user = current_user # type: Optional[User]
#user = current_user # type: Optional[User]
return 'de'
# prefer lang argument
if 'lang' in request.args:
lang = request.args['lang'] # type: str
if lang in LANGUAGES:
if not isinstance(user, User):
return lang
user.locale = lang
db.session.commit()
# if 'lang' in request.args:
# lang = request.args['lang'] # type: str
# if lang in LANGUAGES:
# if not isinstance(user, User):
# return lang
# user.locale = lang
# db.session.commit()
if isinstance(user, User):
return user.locale
# otherwise try to guess the language from the user accept
# header the browser transmits. We support de/fr/en in this
# example. The best match wins.
return request.accept_languages.best_match(['de'])
# if isinstance(user, User):
# return user.locale
# # otherwise try to guess the language from the user accept
# # header the browser transmits. We support de/fr/en in this
# # example. The best match wins.
# return request.accept_languages.best_match(['de'])
def get_timezone() -> Optional[str]:
# user = getattr(g, 'user', None)

View File

@ -1,10 +1,7 @@
{ lenticular_cloud }: { config, pkgs, lib, modulesPath, ... }:
{ config, pkgs, lib, ... }:
let
python = pkgs.python310;
gevent = python.pkgs.gevent;
gunicorn = python.pkgs.gunicorn;
psycopg2 = python.pkgs.psycopg2;
lenticular-pkg = lenticular_cloud { inherit python;};
cfg = config.services.lenticular-cloud;
python = pkgs.python3;
in
{
options = with lib.options; {
@ -12,10 +9,12 @@ in
enable = mkEnableOption "lenticluar service enable";
};
};
imports = [
];
config = {
environment.systemPackages = [ lenticular-pkg ];
environment.systemPackages = [ pkgs.lenticular-cloud ];
nixpkgs.overlays = [
(import ./overlay.nix)
];
users = {
groups.lenticular = {
@ -35,12 +34,14 @@ in
description = "lenticular account";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
enable = cfg.enable;
environment = let
python_path = python.pkgs.makePythonPath [ lenticular-pkg gevent psycopg2];
python_path = with python.pkgs; makePythonPath [ lenticular-cloud gevent psycopg2];
in {
CONFIG_FILE = "/etc/lenticular_cloud/production.conf";
PYTHONPATH = "${lenticular-pkg.pythonPath}:${lenticular-pkg}/lib/python3.10/site-packages:${python_path}";
PYTHONPATH = "${python_path}";
# PYTHONPATH = "${lenticular-pkg.pythonPath}:${lenticular-pkg}/lib/python3.10/site-packages:${python_path}";
};
serviceConfig = {
@ -52,9 +53,9 @@ in
#cat > /var/lib/lenticular/foobar.conf <<EOF
#SECRET_KEY=""
#EOF
${lenticular-pkg}/bin/lenticular_cloud-cli db_upgrade
${pkgs.lenticular-cloud}/bin/lenticular_cloud-cli db_upgrade
'';
ExecStart = ''${gunicorn}/bin/gunicorn lenticular_cloud.wsgi --name lenticular_cloud \
ExecStart = ''${python.pkgs.gunicorn}/bin/gunicorn lenticular_cloud.wsgi --name lenticular_cloud \
-u lenticular \
-g lenticular \
--workers 3 --log-level=info \

136
overlay.nix Normal file
View File

@ -0,0 +1,136 @@
final: prev:
let
pkgs = final.pkgs;
in {
python3 = prev.python3.override {
packageOverrides = final: prev: with final; {
urlobject = buildPythonPackage rec {
pname = "URLObject";
version = "2.4.3";
src = fetchPypi {
inherit pname version;
sha256 = "47b2e20e6ab9c8366b2f4a3566b6ff4053025dad311c4bb71279bbcfa2430caa";
};
doCheck = true;
propagatedBuildInputs = [
];
};
flask-dance = buildPythonPackage rec {
pname = "Flask-Dance";
version = "7.0.0";
format = "pyproject";
src = fetchPypi {
inherit pname version;
sha256 = "a37dec5c3a21f13966178285d5c10691cd72203dcef8a01db802fef6287e716d";
};
doCheck = false;
propagatedBuildInputs = [
requests
oauthlib
requests_oauthlib
flask
urlobject
flit-core
];
checkInputs = [
pytest
nose
pytest-mock
responses
freezegun
coverage
# testing sqlalchemy support
sqlalchemy
flask_sqlalchemy
# testing integration with other extensions
flask_login
flask-caching
betamax
# we need the `signedtoken` extra for `oauthlib`
# oauthlib[signedtoken]
];
};
ory-hydra-client = buildPythonPackage {
pname = "ory-hydra-client";
version = "2.0.3";
src = ./libs/ory-hydra-client;
doCheck = false;
propagatedBuildInputs = [
urllib3
python-dateutil
attrs
httpx
];
};
flask-sqlalchemy = prev.flask-sqlalchemy.overridePythonAttrs (old: rec {
version = "3.1.1";
# version = "3.0.3";
src = fetchPypi {
pname = "flask_sqlalchemy";
inherit version;
sha256 = "e4b68bb881802dda1a7d878b2fc84c06d1ee57fb40b874d3dc97dabfa36b8312";
};
propagatedBuildInputs = old.propagatedBuildInputs ++ [
flit-core sqlalchemy
];
nativeCheckInputs = old.nativeCheckInputs ++ [
typing-extensions
];
});
};
};
lenticular-cloud = with final.python3.pkgs; buildPythonApplication {
pname = "lenticular_cloud";
version = "0.2";
src = ./.;
propagatedBuildInputs = [
flask
flask-restful
flask_sqlalchemy
flask_wtf
flask-babel
flask_login
requests
requests_oauthlib
ldap3
#ldap3-orm
pyotp
cryptography
blinker
authlib # as oauth client lib
fido2 # for webauthn
flask_migrate # db migrations
flask-dance
ory-hydra-client
pkgs.nodejs
#node-env
gunicorn
];
testBuildInputs = [
pytest
pytest-mypy
flask_testing
tox
types-dateutil
nose
mypy
];
# passthru = {
# inherit python;
# pythonPath = python.pkgs.makePythonPath propagatedBuildInputs;
# };
doCheck = false;
checkInputs = [
pytest
];
};
}

View File

@ -1,3 +1,6 @@
flask-debug
types-python-dateutil
types-ldap3
pylint
mypy

View File

@ -1,4 +1,4 @@
Flask
Flask[async]
gunicorn
flask_babel
flask_wtf

View File

@ -7,4 +7,4 @@
}
)
{ src = ./.; }
).defaultNix
).shellNix