splent-cli 0.0.2__tar.gz → 0.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- splent_cli-0.0.3/PKG-INFO +38 -0
- splent_cli-0.0.3/pyproject.toml +59 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/cli.py +1 -1
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/db_seed.py +38 -33
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/feature_create.py +32 -24
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/feature_list.py +8 -8
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/product_create.py +53 -22
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/webpack_compile.py +5 -15
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/utils/dynamic_imports.py +6 -2
- splent_cli-0.0.3/src/splent_cli/utils/feature_installer.py +47 -0
- splent_cli-0.0.3/src/splent_cli/utils/feature_utils.py +24 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/utils/path_utils.py +12 -24
- splent_cli-0.0.3/src/splent_cli.egg-info/PKG-INFO +38 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli.egg-info/SOURCES.txt +1 -1
- splent_cli-0.0.3/src/splent_cli.egg-info/requires.txt +26 -0
- splent_cli-0.0.2/PKG-INFO +0 -22
- splent_cli-0.0.2/pyproject.toml +0 -39
- splent_cli-0.0.2/src/splent_cli/commands/update.py +0 -159
- splent_cli-0.0.2/src/splent_cli/utils/feature_installer.py +0 -54
- splent_cli-0.0.2/src/splent_cli.egg-info/PKG-INFO +0 -22
- splent_cli-0.0.2/src/splent_cli.egg-info/requires.txt +0 -9
- {splent_cli-0.0.2 → splent_cli-0.0.3}/LICENSE +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/README.md +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/setup.cfg +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/__init__.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/__main__.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/__init__.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/clear_cache.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/clear_log.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/clear_uploads.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/compose_env.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/coverage.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/db_console.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/db_dump.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/db_migrate.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/db_reset.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/env.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/info.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/linter.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/locust.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/route_list.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/selenium.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/commands/test.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli/utils/__init__.py +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli.egg-info/dependency_links.txt +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli.egg-info/entry_points.txt +0 -0
- {splent_cli-0.0.2 → splent_cli-0.0.3}/src/splent_cli.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: splent_cli
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: SPLENT-CLI is a CLI to be able to work on your development more easily.
|
|
5
|
+
Author-email: DiversoLab <diversolab@us.es>
|
|
6
|
+
Project-URL: Homepage, https://github.com/diverso-lab/splent_cli
|
|
7
|
+
Project-URL: Issues, https://github.com/diverso-lab/splent_cli/issues
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: click==8.1.8
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: setuptools==80.3.1; extra == "dev"
|
|
14
|
+
Requires-Dist: pytest==8.3.4; extra == "dev"
|
|
15
|
+
Requires-Dist: pytest-cov==6.0.0; extra == "dev"
|
|
16
|
+
Requires-Dist: ruff==0.11.8; extra == "dev"
|
|
17
|
+
Requires-Dist: build==1.2.2.post1; extra == "dev"
|
|
18
|
+
Requires-Dist: twine==6.1.0; extra == "dev"
|
|
19
|
+
Requires-Dist: black==24.10.0; extra == "dev"
|
|
20
|
+
Requires-Dist: coverage==7.6.10; extra == "dev"
|
|
21
|
+
Requires-Dist: docker==7.1.0; extra == "dev"
|
|
22
|
+
Requires-Dist: Faker==33.3.1; extra == "dev"
|
|
23
|
+
Requires-Dist: flake8==7.1.1; extra == "dev"
|
|
24
|
+
Requires-Dist: graphviz==0.20.3; extra == "dev"
|
|
25
|
+
Requires-Dist: iniconfig==2.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: locust==2.32.6; extra == "dev"
|
|
27
|
+
Requires-Dist: mccabe==0.7.0; extra == "dev"
|
|
28
|
+
Requires-Dist: mypy-extensions==1.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: pathspec==0.12.1; extra == "dev"
|
|
30
|
+
Requires-Dist: platformdirs==4.3.6; extra == "dev"
|
|
31
|
+
Requires-Dist: pycodestyle==2.12.1; extra == "dev"
|
|
32
|
+
Requires-Dist: pyflakes==3.2.0; extra == "dev"
|
|
33
|
+
Requires-Dist: selenium==4.28.0; extra == "dev"
|
|
34
|
+
Requires-Dist: selenium-wire==5.1.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pip-tools==7.4.1; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# splent_cli
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=80.3.1", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "splent_cli"
|
|
7
|
+
version = "0.0.3"
|
|
8
|
+
description = "SPLENT-CLI is a CLI to be able to work on your development more easily."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
authors = [{ name = "DiversoLab", email = "diversolab@us.es" }]
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
|
|
14
|
+
dependencies = [
|
|
15
|
+
"click==8.1.8"
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
dev = [
|
|
20
|
+
"setuptools==80.3.1",
|
|
21
|
+
"pytest==8.3.4",
|
|
22
|
+
"pytest-cov==6.0.0",
|
|
23
|
+
"ruff==0.11.8",
|
|
24
|
+
"build==1.2.2.post1",
|
|
25
|
+
"twine==6.1.0",
|
|
26
|
+
"black==24.10.0",
|
|
27
|
+
"coverage==7.6.10",
|
|
28
|
+
"docker==7.1.0",
|
|
29
|
+
"Faker==33.3.1",
|
|
30
|
+
"flake8==7.1.1",
|
|
31
|
+
"graphviz==0.20.3",
|
|
32
|
+
"iniconfig==2.0.0",
|
|
33
|
+
"locust==2.32.6",
|
|
34
|
+
"mccabe==0.7.0",
|
|
35
|
+
"mypy-extensions==1.0.0",
|
|
36
|
+
"pathspec==0.12.1",
|
|
37
|
+
"platformdirs==4.3.6",
|
|
38
|
+
"pycodestyle==2.12.1",
|
|
39
|
+
"pyflakes==3.2.0",
|
|
40
|
+
"selenium==4.28.0",
|
|
41
|
+
"selenium-wire==5.1.0",
|
|
42
|
+
"pip-tools==7.4.1"
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project.scripts]
|
|
46
|
+
splent_cli = "splent_cli.__main__:main"
|
|
47
|
+
|
|
48
|
+
[tool.setuptools]
|
|
49
|
+
package-dir = { "" = "src" }
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.packages.find]
|
|
52
|
+
where = ["src"]
|
|
53
|
+
|
|
54
|
+
[tool.black]
|
|
55
|
+
line-length = 79
|
|
56
|
+
|
|
57
|
+
[project.urls]
|
|
58
|
+
Homepage = "https://github.com/diverso-lab/splent_cli"
|
|
59
|
+
Issues = "https://github.com/diverso-lab/splent_cli/issues"
|
|
@@ -15,7 +15,7 @@ def check_working_dir():
|
|
|
15
15
|
working_dir = os.getenv("WORKING_DIR", "").strip()
|
|
16
16
|
|
|
17
17
|
if working_dir != "/workspace":
|
|
18
|
-
print(f"❌ ERROR: WORKING_DIR must be set to '/workspace', but got '{working_dir}'.")
|
|
18
|
+
print(f"❌ CLI ERROR: WORKING_DIR must be set to '/workspace', but got '{working_dir}'.")
|
|
19
19
|
sys.exit(1)
|
|
20
20
|
|
|
21
21
|
|
|
@@ -2,46 +2,52 @@ import inspect
|
|
|
2
2
|
import os
|
|
3
3
|
import importlib
|
|
4
4
|
import click
|
|
5
|
-
|
|
5
|
+
import tomllib
|
|
6
6
|
|
|
7
|
+
from flask.cli import with_appcontext
|
|
7
8
|
from splent_cli.commands.db_reset import db_reset
|
|
8
9
|
from splent_cli.utils.path_utils import PathUtils
|
|
9
10
|
from splent_framework.core.seeders.BaseSeeder import BaseSeeder
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
def get_installed_seeders(
|
|
13
|
+
def get_installed_seeders(specific_module=None):
|
|
13
14
|
seeders = []
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
pyproject_path = os.path.join(PathUtils.get_app_base_dir(), "pyproject.toml")
|
|
17
|
+
|
|
18
|
+
if not os.path.exists(pyproject_path):
|
|
19
|
+
click.echo(click.style(f"❌ pyproject.toml not found at {pyproject_path}", fg="red"))
|
|
20
|
+
return seeders
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
with open(pyproject_path, "rb") as f:
|
|
24
|
+
data = tomllib.load(f)
|
|
25
|
+
features = data["project"]["optional-dependencies"].get("features", [])
|
|
26
|
+
except Exception as e:
|
|
27
|
+
click.echo(click.style(f"❌ Failed to read features from pyproject.toml: {e}", fg="red"))
|
|
17
28
|
return seeders
|
|
18
29
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
except Exception as e:
|
|
41
|
-
click.echo(
|
|
42
|
-
f"❌ Error loading seeders from {feature}: {e}",
|
|
43
|
-
err=True,
|
|
44
|
-
)
|
|
30
|
+
for feature in features:
|
|
31
|
+
if specific_module and specific_module != feature.split("_")[-1]:
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
seeder_module = importlib.import_module(f"{feature}.seeders")
|
|
36
|
+
importlib.reload(seeder_module)
|
|
37
|
+
|
|
38
|
+
for attr in dir(seeder_module):
|
|
39
|
+
obj = getattr(seeder_module, attr)
|
|
40
|
+
if (
|
|
41
|
+
inspect.isclass(obj)
|
|
42
|
+
and issubclass(obj, BaseSeeder)
|
|
43
|
+
and obj is not BaseSeeder
|
|
44
|
+
):
|
|
45
|
+
seeders.append(obj())
|
|
46
|
+
except Exception as e:
|
|
47
|
+
click.echo(
|
|
48
|
+
click.style(f"❌ Error loading seeders from {feature}: {e}", fg="red"),
|
|
49
|
+
err=True,
|
|
50
|
+
)
|
|
45
51
|
|
|
46
52
|
seeders.sort(key=lambda s: s.priority)
|
|
47
53
|
return seeders
|
|
@@ -76,8 +82,7 @@ def db_seed(reset, yes, module):
|
|
|
76
82
|
click.echo(click.style("Database reset cancelled.", fg="yellow"))
|
|
77
83
|
return
|
|
78
84
|
|
|
79
|
-
|
|
80
|
-
seeders = get_installed_seeders(features_file_path, specific_module=module)
|
|
85
|
+
seeders = get_installed_seeders(specific_module=module)
|
|
81
86
|
success = True
|
|
82
87
|
|
|
83
88
|
if module:
|
|
@@ -39,48 +39,56 @@ def make_feature(name):
|
|
|
39
39
|
return
|
|
40
40
|
|
|
41
41
|
env = setup_jinja_env()
|
|
42
|
-
context = {"
|
|
42
|
+
context = {"feature_name": name}
|
|
43
43
|
|
|
44
44
|
# Archivos que van dentro de src/splent_feature_<name>
|
|
45
|
-
|
|
46
|
-
"__init__.py": "
|
|
47
|
-
"routes.py": "
|
|
48
|
-
"models.py": "
|
|
49
|
-
"repositories.py": "
|
|
50
|
-
"services.py": "
|
|
51
|
-
"forms.py": "
|
|
52
|
-
"seeders.py": "
|
|
53
|
-
os.path.join("templates", name, "index.html"): "
|
|
54
|
-
os.path.join("assets", "js", "scripts.js"): "
|
|
55
|
-
os.path.join("assets", "js", "webpack.config.js"): "
|
|
45
|
+
src_files_and_templates = {
|
|
46
|
+
"__init__.py": "feature/feature_init.py.j2",
|
|
47
|
+
"routes.py": "feature/feature_routes.py.j2",
|
|
48
|
+
"models.py": "feature/feature_models.py.j2",
|
|
49
|
+
"repositories.py": "feature/feature_repositories.py.j2",
|
|
50
|
+
"services.py": "feature/feature_services.py.j2",
|
|
51
|
+
"forms.py": "feature/feature_forms.py.j2",
|
|
52
|
+
"seeders.py": "feature/feature_seeders.py.j2",
|
|
53
|
+
os.path.join("templates", name, "index.html"): "feature/feature_templates_index.html.j2",
|
|
54
|
+
os.path.join("assets", "js", "scripts.js"): "feature/feature_scripts.js.j2",
|
|
55
|
+
os.path.join("assets", "js", "webpack.config.js"): "feature/feature_webpack.config.js.j2",
|
|
56
56
|
os.path.join("tests", "__init__.py"): None,
|
|
57
|
-
os.path.join("tests", "test_unit.py"): "
|
|
58
|
-
os.path.join("tests", "locustfile.py"): "
|
|
59
|
-
os.path.join("tests", "test_selenium.py"): "
|
|
57
|
+
os.path.join("tests", "test_unit.py"): "feature/feature_tests_test_unit.py.j2",
|
|
58
|
+
os.path.join("tests", "locustfile.py"): "feature/feature_tests_locustfile.py.j2",
|
|
59
|
+
os.path.join("tests", "test_selenium.py"): "feature/feature_tests_test_selenium.py.j2",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Archivos que van en la raíz de splent_feature_<name>
|
|
63
|
+
base_files_and_templates = {
|
|
64
|
+
".gitignore": "feature/feature_.gitignore.j2",
|
|
65
|
+
"pyproject.toml": "feature/feature_pyproject.toml.j2",
|
|
66
|
+
"MANIFEST.in": "feature/feature_MANIFEST.in.j2"
|
|
60
67
|
}
|
|
61
68
|
|
|
62
69
|
# Crear todos los archivos de código en src_path
|
|
63
|
-
for filename, template in
|
|
70
|
+
for filename, template in src_files_and_templates.items():
|
|
64
71
|
full_path = os.path.join(src_path, filename)
|
|
65
72
|
if template:
|
|
66
73
|
render_and_write_file(env, template, full_path, context)
|
|
67
74
|
else:
|
|
68
75
|
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
|
69
76
|
open(full_path, "a").close()
|
|
77
|
+
|
|
78
|
+
# Crear todos los archivos de código en base_path
|
|
79
|
+
for filename, template in base_files_and_templates.items():
|
|
80
|
+
full_path = os.path.join(base_path, filename)
|
|
81
|
+
if template:
|
|
82
|
+
render_and_write_file(env, template, full_path, context)
|
|
83
|
+
else:
|
|
84
|
+
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
|
85
|
+
open(full_path, "a").close()
|
|
70
86
|
|
|
71
87
|
# Crear src/__init__.py vacío
|
|
72
88
|
src_root = os.path.join(base_path, "src")
|
|
73
89
|
os.makedirs(src_root, exist_ok=True)
|
|
74
90
|
open(os.path.join(src_root, "__init__.py"), "a").close()
|
|
75
91
|
|
|
76
|
-
# Crear el pyproject.toml en la raíz del módulo
|
|
77
|
-
render_and_write_file(
|
|
78
|
-
env,
|
|
79
|
-
"module_pyproject.toml.j2",
|
|
80
|
-
os.path.join(base_path, "pyproject.toml"),
|
|
81
|
-
context,
|
|
82
|
-
)
|
|
83
|
-
|
|
84
92
|
# Cambiar permisos y propietario
|
|
85
93
|
uid = 1000
|
|
86
94
|
gid = 1000
|
|
@@ -8,22 +8,22 @@ from splent_framework.core.managers.feature_manager import FeatureManager
|
|
|
8
8
|
"feature:list", help="Lists all feautures and those ignored by .featureignore."
|
|
9
9
|
)
|
|
10
10
|
@with_appcontext
|
|
11
|
-
def
|
|
11
|
+
def feature_list():
|
|
12
12
|
app = get_app
|
|
13
13
|
manager = FeatureManager(app)
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
loaded_features, ignored_features = manager.get_features()
|
|
16
16
|
|
|
17
17
|
click.echo(
|
|
18
|
-
click.style(f"Loaded features ({len(
|
|
18
|
+
click.style(f"Loaded features ({len(loaded_features)}):", fg="green")
|
|
19
19
|
)
|
|
20
|
-
for
|
|
21
|
-
click.echo(f"- {
|
|
20
|
+
for feature in loaded_features:
|
|
21
|
+
click.echo(f"- {feature}")
|
|
22
22
|
|
|
23
23
|
click.echo(
|
|
24
24
|
click.style(
|
|
25
|
-
f"\nIgnored features ({len(
|
|
25
|
+
f"\nIgnored features ({len(ignored_features)}):", fg="bright_yellow"
|
|
26
26
|
)
|
|
27
27
|
)
|
|
28
|
-
for
|
|
29
|
-
click.echo(click.style(f"- {
|
|
28
|
+
for feature in ignored_features:
|
|
29
|
+
click.echo(click.style(f"- {feature}", fg="bright_yellow"))
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import shutil
|
|
3
3
|
import stat
|
|
4
4
|
import click
|
|
5
|
+
import zlib
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
7
8
|
|
|
@@ -10,7 +11,6 @@ from splent_cli.utils.path_utils import PathUtils
|
|
|
10
11
|
def pascalcase(s):
|
|
11
12
|
return "".join(word.capitalize() for word in s.split("_"))
|
|
12
13
|
|
|
13
|
-
|
|
14
14
|
def setup_jinja_env():
|
|
15
15
|
env = Environment(
|
|
16
16
|
loader=FileSystemLoader(searchpath=PathUtils.get_splent_cli_templates_dir()),
|
|
@@ -25,31 +25,54 @@ def render_and_write_file(env, template_name, filename, context):
|
|
|
25
25
|
with open(filename, "w") as f:
|
|
26
26
|
f.write(content)
|
|
27
27
|
|
|
28
|
+
def copy_raw_file(template_name, filename):
|
|
29
|
+
src = os.path.join(PathUtils.get_splent_cli_templates_dir(), template_name)
|
|
30
|
+
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
|
31
|
+
shutil.copy(src, filename)
|
|
32
|
+
|
|
28
33
|
@click.command("product:create", help="Creates a new product with a given name.")
|
|
29
34
|
@click.argument("name")
|
|
30
35
|
@click.option("--features-file", type=click.Path(exists=True), help="Path to features.txt")
|
|
31
36
|
def make_product(name, features_file):
|
|
32
37
|
env = setup_jinja_env()
|
|
38
|
+
offset = zlib.crc32(name.encode("utf-8")) % 1000 # 0–999
|
|
39
|
+
web_port = 5000 + offset
|
|
40
|
+
db_port = 33060 + offset
|
|
41
|
+
redis_port = 6379 + offset
|
|
33
42
|
context = {
|
|
34
43
|
"product_name": name,
|
|
35
|
-
"pascal_name": pascalcase(name)
|
|
44
|
+
"pascal_name": pascalcase(name),
|
|
45
|
+
"web_port": web_port,
|
|
46
|
+
"db_port": db_port,
|
|
47
|
+
"redis_port": redis_port
|
|
36
48
|
}
|
|
37
49
|
|
|
38
50
|
base_path = os.path.join(PathUtils.get_working_dir(), name)
|
|
39
|
-
src_path = os.path.join(base_path, "src", name)
|
|
40
51
|
|
|
41
52
|
if os.path.exists(base_path):
|
|
42
53
|
click.echo(click.style(f"The product '{name}' already exists.", fg="red"))
|
|
43
54
|
return
|
|
44
55
|
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
for subdir in [
|
|
57
|
+
"docker", "entrypoints", "scripts", f"src/{name}",
|
|
58
|
+
f"src/{name}/static", f"src/{name}/static/css",
|
|
59
|
+
f"src/{name}/static/fonts", f"src/{name}/static/js",
|
|
60
|
+
f"src/{name}/templates"
|
|
61
|
+
]:
|
|
47
62
|
os.makedirs(os.path.join(base_path, subdir), exist_ok=True)
|
|
63
|
+
|
|
48
64
|
open(os.path.join(base_path, "src", "__init__.py"), "a").close()
|
|
49
65
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
66
|
+
jinja_templates = {
|
|
67
|
+
"docker/.env.dev.example": "product/product_.env.dev.example.j2",
|
|
68
|
+
"docker/.env.prod.example": "product/product_.env.prod.example.j2",
|
|
69
|
+
"docker/docker-compose.dev.yml": "product/product_docker-compose.dev.yml.j2",
|
|
70
|
+
"docker/docker-compose.prod.yml": "product/product_docker-compose.prod.yml.j2",
|
|
71
|
+
f"docker/Dockerfile.{name}.dev": "product/product_Dockerfile.dev.j2",
|
|
72
|
+
f"docker/Dockerfile.{name}.prod": "product/product_Dockerfile.prod.j2",
|
|
73
|
+
"entrypoints/entrypoint.dev.sh": "product/product_entrypoint.dev.sh.j2",
|
|
74
|
+
"entrypoints/entrypoint.prod.sh": "product/product_entrypoint.prod.sh.j2",
|
|
75
|
+
"scripts/00_core_requirements_dev.sh": "product/product_00_core_requirements_dev.sh.j2",
|
|
53
76
|
"scripts/00_install_features.sh": "product/product_00_install_features.sh.j2",
|
|
54
77
|
"scripts/01_compile_assets.sh": "product/product_01_compile_assets.sh.j2",
|
|
55
78
|
"scripts/02_0_db_wait_connection.sh": "product/product_02_0_db_wait_connection.sh.j2",
|
|
@@ -57,29 +80,37 @@ def make_product(name, features_file):
|
|
|
57
80
|
"scripts/03_initialize_migrations.sh": "product/product_03_initialize_migrations.sh.j2",
|
|
58
81
|
"scripts/04_handle_migrations.sh": "product/product_04_handle_migrations.sh.j2",
|
|
59
82
|
"scripts/05_0_start_app_dev.sh": "product/product_05_0_start_app_dev.sh.j2",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"features.txt": "product/product_features.txt.j2",
|
|
83
|
+
"scripts/05_1_start_app_prod.sh": "product/product_05_1_start_app_prod.sh.j2",
|
|
84
|
+
".gitignore": "product/product_.gitignore.j2",
|
|
63
85
|
"LICENSE": "product/product_LICENSE.j2",
|
|
64
86
|
"package.json": "product/product_package.json.j2",
|
|
65
|
-
".
|
|
87
|
+
"pyproject.toml": "product/product_pyproject.toml.j2",
|
|
88
|
+
"README.md": "product/product_README.md.j2",
|
|
66
89
|
f"src/{name}/__init__.py": "product/product_init.py.j2",
|
|
90
|
+
}
|
|
67
91
|
|
|
92
|
+
raw_files = {
|
|
93
|
+
f"src/{name}/static/css/app.css": "product/product_app.css",
|
|
94
|
+
f"src/{name}/static/css/dropzone.css": "product/product_dropzone.css",
|
|
95
|
+
f"src/{name}/static/css/own.css": "product/product_own.css",
|
|
96
|
+
f"src/{name}/static/js/app.js": "product/product_app.js",
|
|
97
|
+
f"src/{name}/templates/400.html": "product/product_400.html",
|
|
98
|
+
f"src/{name}/templates/401.html": "product/product_401.html",
|
|
99
|
+
f"src/{name}/templates/404.html": "product/product_404.html",
|
|
100
|
+
f"src/{name}/templates/500.html": "product/product_500.html",
|
|
101
|
+
f"src/{name}/templates/base_template.html": "product/product_base_template.html",
|
|
68
102
|
}
|
|
69
103
|
|
|
70
|
-
for rel_path, tpl in
|
|
104
|
+
for rel_path, tpl in jinja_templates.items():
|
|
71
105
|
abs_path = os.path.join(base_path, rel_path)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# Cambiar permisos y propietario
|
|
106
|
+
render_and_write_file(env, tpl, abs_path, context)
|
|
107
|
+
|
|
108
|
+
for rel_path, tpl in raw_files.items():
|
|
109
|
+
abs_path = os.path.join(base_path, rel_path)
|
|
110
|
+
copy_raw_file(tpl, abs_path)
|
|
111
|
+
|
|
80
112
|
uid = 1000
|
|
81
113
|
gid = 1000
|
|
82
|
-
|
|
83
114
|
os.chown(base_path, uid, gid)
|
|
84
115
|
os.chmod(base_path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH)
|
|
85
116
|
|
|
@@ -2,19 +2,12 @@ import logging
|
|
|
2
2
|
import click
|
|
3
3
|
import os
|
|
4
4
|
import subprocess
|
|
5
|
+
import tomllib
|
|
5
6
|
|
|
6
|
-
from splent_cli.utils.
|
|
7
|
-
|
|
8
|
-
logger = logging.getLogger(__name__)
|
|
9
|
-
|
|
10
|
-
FEATURES_FILE = PathUtils.get_features_file()
|
|
7
|
+
from splent_cli.utils.feature_utils import get_features_from_pyproject,get_normalize_feature_name_in_splent_format
|
|
11
8
|
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
if not os.path.isfile(FEATURES_FILE):
|
|
15
|
-
return []
|
|
16
|
-
with open(FEATURES_FILE) as f:
|
|
17
|
-
return [line.strip() for line in f if line.strip()]
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
18
11
|
|
|
19
12
|
|
|
20
13
|
@click.command("webpack:compile", help="Compile webpack for one or all features.")
|
|
@@ -23,13 +16,10 @@ def get_features():
|
|
|
23
16
|
def webpack_compile(feature_name, watch):
|
|
24
17
|
production = os.getenv("FLASK_ENV", "develop") == "production"
|
|
25
18
|
|
|
26
|
-
def normalize_feature_name(name):
|
|
27
|
-
return name if name.startswith("splent_feature_") else f"splent_feature_{name}"
|
|
28
|
-
|
|
29
19
|
features = (
|
|
30
|
-
[
|
|
20
|
+
[get_normalize_feature_name_in_splent_format(feature_name)]
|
|
31
21
|
if feature_name
|
|
32
|
-
else
|
|
22
|
+
else get_features_from_pyproject()
|
|
33
23
|
)
|
|
34
24
|
|
|
35
25
|
for feature in features:
|
|
@@ -6,13 +6,17 @@ import importlib
|
|
|
6
6
|
from dotenv import load_dotenv
|
|
7
7
|
from importlib.metadata import distributions
|
|
8
8
|
|
|
9
|
+
from splent_cli.utils.path_utils import PathUtils
|
|
10
|
+
|
|
11
|
+
load_dotenv()
|
|
12
|
+
|
|
9
13
|
_app_instance = None
|
|
10
14
|
_db_instance = None
|
|
11
15
|
_module_cache = None
|
|
12
16
|
_mail_service_instance = None
|
|
13
17
|
|
|
14
|
-
module_name = os.
|
|
15
|
-
dotenv_path =
|
|
18
|
+
module_name = os.getenv("SPLENT_APP", "splent_app")
|
|
19
|
+
dotenv_path = PathUtils.get_app_env_file()
|
|
16
20
|
|
|
17
21
|
if os.path.exists(dotenv_path):
|
|
18
22
|
load_dotenv(dotenv_path, override=True)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import tomllib
|
|
4
|
+
|
|
5
|
+
from splent_cli.utils.feature_utils import get_features_from_pyproject
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_installed_packages() -> set[str]:
|
|
9
|
+
result = subprocess.run(
|
|
10
|
+
["pip", "list", "--format=freeze"],
|
|
11
|
+
stdout=subprocess.PIPE, text=True, check=True
|
|
12
|
+
)
|
|
13
|
+
return {line.split("==")[0] for line in result.stdout.strip().splitlines() if "==" in line}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_package_name(feature_path: Path) -> str | None:
|
|
17
|
+
pyproject_path = feature_path / "pyproject.toml"
|
|
18
|
+
if not pyproject_path.is_file():
|
|
19
|
+
return None
|
|
20
|
+
try:
|
|
21
|
+
with pyproject_path.open("rb") as f:
|
|
22
|
+
data = tomllib.load(f)
|
|
23
|
+
return data.get("project", {}).get("name")
|
|
24
|
+
except Exception:
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def ensure_editable_features_installed():
|
|
29
|
+
features = get_features_from_pyproject()
|
|
30
|
+
installed = get_installed_packages()
|
|
31
|
+
|
|
32
|
+
for feature in features:
|
|
33
|
+
feature_path = Path("/workspace") / feature
|
|
34
|
+
package_name = get_package_name(feature_path)
|
|
35
|
+
|
|
36
|
+
if not package_name:
|
|
37
|
+
print(f"⚠️ Skipping {feature}: no valid pyproject.toml or name.")
|
|
38
|
+
continue
|
|
39
|
+
|
|
40
|
+
if package_name in installed:
|
|
41
|
+
continue
|
|
42
|
+
|
|
43
|
+
print(f"➡️ Installing {package_name} in editable mode...")
|
|
44
|
+
subprocess.run(
|
|
45
|
+
["pip", "install", "-e", str(feature_path)],
|
|
46
|
+
check=True
|
|
47
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tomllib
|
|
3
|
+
from splent_cli.utils.path_utils import PathUtils
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_features_from_pyproject():
|
|
7
|
+
"""
|
|
8
|
+
Devuelve la lista de features declaradas en [project.optional-dependencies].features del pyproject.toml
|
|
9
|
+
"""
|
|
10
|
+
pyproject_path = os.path.join(PathUtils.get_app_base_dir(), "pyproject.toml")
|
|
11
|
+
|
|
12
|
+
if not os.path.exists(pyproject_path):
|
|
13
|
+
return []
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
with open(pyproject_path, "rb") as f:
|
|
17
|
+
data = tomllib.load(f)
|
|
18
|
+
return data["project"]["optional-dependencies"].get("features", [])
|
|
19
|
+
except Exception:
|
|
20
|
+
return []
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_normalize_feature_name_in_splent_format(name):
|
|
24
|
+
return name if name.startswith("splent_feature_") else f"splent_feature_{name}"
|
|
@@ -17,22 +17,22 @@ class PathUtils:
|
|
|
17
17
|
return os.getenv("WORKING_DIR", "")
|
|
18
18
|
|
|
19
19
|
@staticmethod
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
splent_app = os.getenv("SPLENT_APP", "splent_app")
|
|
23
|
-
|
|
20
|
+
def get_app_base_dir():
|
|
24
21
|
working_dir = PathUtils.get_working_dir()
|
|
25
|
-
|
|
26
|
-
return os.path.join(working_dir, splent_app
|
|
22
|
+
splent_app = os.getenv("SPLENT_APP", "splent_app")
|
|
23
|
+
return os.path.join(working_dir, splent_app)
|
|
27
24
|
|
|
28
25
|
@staticmethod
|
|
29
26
|
def get_app_dir():
|
|
30
27
|
|
|
31
28
|
splent_app = os.getenv("SPLENT_APP", "splent_app")
|
|
32
|
-
|
|
29
|
+
return os.path.join(PathUtils.get_app_base_dir(), "src", splent_app)
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def get_app_env_file():
|
|
33
33
|
working_dir = PathUtils.get_working_dir()
|
|
34
|
-
|
|
35
|
-
return os.path.join(working_dir, splent_app, "
|
|
34
|
+
splent_app = os.getenv("SPLENT_APP", "splent_app")
|
|
35
|
+
return os.path.join(working_dir, splent_app, "docker", ".env")
|
|
36
36
|
|
|
37
37
|
@staticmethod
|
|
38
38
|
def get_modules_dir():
|
|
@@ -44,12 +44,8 @@ class PathUtils:
|
|
|
44
44
|
|
|
45
45
|
@staticmethod
|
|
46
46
|
def get_splent_cli_dir():
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if is_splent_dev_mode():
|
|
50
|
-
return os.path.join(base_dir, "splent_cli", "src", "splent_cli")
|
|
51
|
-
|
|
52
|
-
return os.path.join(base_dir, "splent_cli")
|
|
47
|
+
working_dir = PathUtils.get_working_dir()
|
|
48
|
+
return os.path.join(working_dir, "splent_cli", "src", "splent_cli")
|
|
53
49
|
|
|
54
50
|
@staticmethod
|
|
55
51
|
def get_splent_cli_templates_dir():
|
|
@@ -66,15 +62,7 @@ class PathUtils:
|
|
|
66
62
|
@staticmethod
|
|
67
63
|
def get_splent_framework_dir():
|
|
68
64
|
working_dir = PathUtils.get_working_dir()
|
|
69
|
-
|
|
70
|
-
if is_splent_dev_mode():
|
|
71
|
-
return os.path.join(working_dir, "splent_framework", "src", "splent_framework")
|
|
72
|
-
|
|
73
|
-
package = importlib.util.find_spec("splent_framework")
|
|
74
|
-
if package and package.origin:
|
|
75
|
-
return os.path.dirname(package.origin)
|
|
76
|
-
|
|
77
|
-
raise FileNotFoundError("Could not find 'splent_framework'. Check the installation.")
|
|
65
|
+
return os.path.join(working_dir, "splent_framework", "src", "splent_framework")
|
|
78
66
|
|
|
79
67
|
@staticmethod
|
|
80
68
|
def get_core_dir():
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: splent_cli
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: SPLENT-CLI is a CLI to be able to work on your development more easily.
|
|
5
|
+
Author-email: DiversoLab <diversolab@us.es>
|
|
6
|
+
Project-URL: Homepage, https://github.com/diverso-lab/splent_cli
|
|
7
|
+
Project-URL: Issues, https://github.com/diverso-lab/splent_cli/issues
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: click==8.1.8
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: setuptools==80.3.1; extra == "dev"
|
|
14
|
+
Requires-Dist: pytest==8.3.4; extra == "dev"
|
|
15
|
+
Requires-Dist: pytest-cov==6.0.0; extra == "dev"
|
|
16
|
+
Requires-Dist: ruff==0.11.8; extra == "dev"
|
|
17
|
+
Requires-Dist: build==1.2.2.post1; extra == "dev"
|
|
18
|
+
Requires-Dist: twine==6.1.0; extra == "dev"
|
|
19
|
+
Requires-Dist: black==24.10.0; extra == "dev"
|
|
20
|
+
Requires-Dist: coverage==7.6.10; extra == "dev"
|
|
21
|
+
Requires-Dist: docker==7.1.0; extra == "dev"
|
|
22
|
+
Requires-Dist: Faker==33.3.1; extra == "dev"
|
|
23
|
+
Requires-Dist: flake8==7.1.1; extra == "dev"
|
|
24
|
+
Requires-Dist: graphviz==0.20.3; extra == "dev"
|
|
25
|
+
Requires-Dist: iniconfig==2.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: locust==2.32.6; extra == "dev"
|
|
27
|
+
Requires-Dist: mccabe==0.7.0; extra == "dev"
|
|
28
|
+
Requires-Dist: mypy-extensions==1.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: pathspec==0.12.1; extra == "dev"
|
|
30
|
+
Requires-Dist: platformdirs==4.3.6; extra == "dev"
|
|
31
|
+
Requires-Dist: pycodestyle==2.12.1; extra == "dev"
|
|
32
|
+
Requires-Dist: pyflakes==3.2.0; extra == "dev"
|
|
33
|
+
Requires-Dist: selenium==4.28.0; extra == "dev"
|
|
34
|
+
Requires-Dist: selenium-wire==5.1.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pip-tools==7.4.1; extra == "dev"
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# splent_cli
|
|
@@ -31,9 +31,9 @@ src/splent_cli/commands/product_create.py
|
|
|
31
31
|
src/splent_cli/commands/route_list.py
|
|
32
32
|
src/splent_cli/commands/selenium.py
|
|
33
33
|
src/splent_cli/commands/test.py
|
|
34
|
-
src/splent_cli/commands/update.py
|
|
35
34
|
src/splent_cli/commands/webpack_compile.py
|
|
36
35
|
src/splent_cli/utils/__init__.py
|
|
37
36
|
src/splent_cli/utils/dynamic_imports.py
|
|
38
37
|
src/splent_cli/utils/feature_installer.py
|
|
38
|
+
src/splent_cli/utils/feature_utils.py
|
|
39
39
|
src/splent_cli/utils/path_utils.py
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
click==8.1.8
|
|
2
|
+
|
|
3
|
+
[dev]
|
|
4
|
+
setuptools==80.3.1
|
|
5
|
+
pytest==8.3.4
|
|
6
|
+
pytest-cov==6.0.0
|
|
7
|
+
ruff==0.11.8
|
|
8
|
+
build==1.2.2.post1
|
|
9
|
+
twine==6.1.0
|
|
10
|
+
black==24.10.0
|
|
11
|
+
coverage==7.6.10
|
|
12
|
+
docker==7.1.0
|
|
13
|
+
Faker==33.3.1
|
|
14
|
+
flake8==7.1.1
|
|
15
|
+
graphviz==0.20.3
|
|
16
|
+
iniconfig==2.0.0
|
|
17
|
+
locust==2.32.6
|
|
18
|
+
mccabe==0.7.0
|
|
19
|
+
mypy-extensions==1.0.0
|
|
20
|
+
pathspec==0.12.1
|
|
21
|
+
platformdirs==4.3.6
|
|
22
|
+
pycodestyle==2.12.1
|
|
23
|
+
pyflakes==3.2.0
|
|
24
|
+
selenium==4.28.0
|
|
25
|
+
selenium-wire==5.1.0
|
|
26
|
+
pip-tools==7.4.1
|
splent_cli-0.0.2/PKG-INFO
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: splent_cli
|
|
3
|
-
Version: 0.0.2
|
|
4
|
-
Summary: SPLENT-CLI is a CLI to be able to work on your development more easily.
|
|
5
|
-
Author-email: DiversoLab <diversolab@us.es>
|
|
6
|
-
Project-URL: Homepage, https://github.com/diverso-lab/splent_cli
|
|
7
|
-
Project-URL: Issues, https://github.com/diverso-lab/splent_cli/issues
|
|
8
|
-
Requires-Python: >=3.12
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Requires-Dist: click
|
|
12
|
-
Requires-Dist: python-dotenv
|
|
13
|
-
Requires-Dist: flask
|
|
14
|
-
Requires-Dist: setuptools
|
|
15
|
-
Requires-Dist: pytest
|
|
16
|
-
Requires-Dist: pytest-cov
|
|
17
|
-
Requires-Dist: ruff
|
|
18
|
-
Requires-Dist: build
|
|
19
|
-
Requires-Dist: twine
|
|
20
|
-
Dynamic: license-file
|
|
21
|
-
|
|
22
|
-
# splent_cli
|
splent_cli-0.0.2/pyproject.toml
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "splent_cli"
|
|
7
|
-
version = "0.0.2"
|
|
8
|
-
description = "SPLENT-CLI is a CLI to be able to work on your development more easily."
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.12"
|
|
11
|
-
authors = [{ name = "DiversoLab", email = "diversolab@us.es" }]
|
|
12
|
-
license-files = ["LICENSE"]
|
|
13
|
-
dependencies = [
|
|
14
|
-
"click",
|
|
15
|
-
"python-dotenv",
|
|
16
|
-
"flask",
|
|
17
|
-
"setuptools",
|
|
18
|
-
"pytest",
|
|
19
|
-
"pytest-cov",
|
|
20
|
-
"ruff",
|
|
21
|
-
"build",
|
|
22
|
-
"twine"
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
[project.scripts]
|
|
26
|
-
splent_cli = "splent_cli.__main__:main"
|
|
27
|
-
|
|
28
|
-
[tool.setuptools]
|
|
29
|
-
package-dir = { "" = "src" }
|
|
30
|
-
|
|
31
|
-
[tool.setuptools.packages.find]
|
|
32
|
-
where = ["src"]
|
|
33
|
-
|
|
34
|
-
[tool.black]
|
|
35
|
-
line-length = 79
|
|
36
|
-
|
|
37
|
-
[project.urls]
|
|
38
|
-
Homepage = "https://github.com/diverso-lab/splent_cli"
|
|
39
|
-
Issues = "https://github.com/diverso-lab/splent_cli/issues"
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
import os
|
|
3
|
-
import subprocess
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def create_temp_requirements(requirements_path, temp_requirements_path):
|
|
7
|
-
"""Create a temporary requirements file without versions and handle editable sources."""
|
|
8
|
-
editable_package = None
|
|
9
|
-
with (
|
|
10
|
-
open(requirements_path) as f,
|
|
11
|
-
open(temp_requirements_path, "w") as temp_f,
|
|
12
|
-
):
|
|
13
|
-
for line in f:
|
|
14
|
-
if line.startswith("-e"):
|
|
15
|
-
editable_package = line.strip() # Store the editable package
|
|
16
|
-
elif line.strip():
|
|
17
|
-
package = line.split("==")[
|
|
18
|
-
0
|
|
19
|
-
].strip() # Remove version information
|
|
20
|
-
temp_f.write(package + "\n")
|
|
21
|
-
return editable_package
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def uninstall_packages():
|
|
25
|
-
"""Uninstall all non-editable packages."""
|
|
26
|
-
installed_packages = (
|
|
27
|
-
subprocess.check_output(["pip", "freeze"]).decode("utf-8").splitlines()
|
|
28
|
-
)
|
|
29
|
-
non_editable_packages = [
|
|
30
|
-
pkg for pkg in installed_packages if not pkg.startswith("-e")
|
|
31
|
-
]
|
|
32
|
-
if non_editable_packages:
|
|
33
|
-
subprocess.run(
|
|
34
|
-
["pip", "uninstall", "-y"]
|
|
35
|
-
+ [pkg.split("==")[0] for pkg in non_editable_packages]
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def install_packages(requirements_file):
|
|
40
|
-
"""Install packages from a requirements file."""
|
|
41
|
-
subprocess.run(["pip", "install", "-r", requirements_file])
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def regenerate_requirements(requirements_path):
|
|
45
|
-
"""Regenerate requirements.txt with resolved versions."""
|
|
46
|
-
freeze_output = subprocess.check_output(["pip", "freeze"]).decode("utf-8")
|
|
47
|
-
with open(requirements_path, "w") as f:
|
|
48
|
-
f.write(freeze_output)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def reinstall_editable_package(editable_package):
|
|
52
|
-
"""Reinstall the editable package."""
|
|
53
|
-
if editable_package:
|
|
54
|
-
editable_path = editable_package.split()[
|
|
55
|
-
1
|
|
56
|
-
] # Extract the path from '-e ./app'
|
|
57
|
-
subprocess.run(
|
|
58
|
-
["pip", "install", "-e", editable_path],
|
|
59
|
-
stdout=subprocess.DEVNULL, # Suppress output
|
|
60
|
-
stderr=subprocess.DEVNULL, # Suppress errors
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def clean_up(temp_requirements_path):
|
|
65
|
-
"""Remove the temporary requirements file."""
|
|
66
|
-
if os.path.exists(temp_requirements_path):
|
|
67
|
-
os.remove(temp_requirements_path)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def update_pip():
|
|
71
|
-
"""Update pip dependencies."""
|
|
72
|
-
requirements_path = os.path.join(
|
|
73
|
-
os.getenv("WORKING_DIR", ""), "requirements.txt"
|
|
74
|
-
)
|
|
75
|
-
temp_requirements_path = os.path.join(
|
|
76
|
-
os.getenv("WORKING_DIR", ""), "temp_requirements.txt"
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
editable_package = create_temp_requirements(
|
|
80
|
-
requirements_path, temp_requirements_path
|
|
81
|
-
)
|
|
82
|
-
uninstall_packages()
|
|
83
|
-
install_packages(temp_requirements_path)
|
|
84
|
-
regenerate_requirements(requirements_path)
|
|
85
|
-
reinstall_editable_package(editable_package)
|
|
86
|
-
clean_up(temp_requirements_path)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def update_npm():
|
|
90
|
-
"""Update npm dependencies."""
|
|
91
|
-
working_dir = os.getenv("WORKING_DIR", "")
|
|
92
|
-
package_json_path = os.path.join(working_dir, "package.json")
|
|
93
|
-
|
|
94
|
-
if not os.path.exists(package_json_path):
|
|
95
|
-
click.echo(
|
|
96
|
-
click.style(
|
|
97
|
-
"No package.json found. Skipping npm update.", fg="yellow"
|
|
98
|
-
)
|
|
99
|
-
)
|
|
100
|
-
return
|
|
101
|
-
|
|
102
|
-
try:
|
|
103
|
-
# Step 1: Update package.json to latest versions
|
|
104
|
-
subprocess.run(["npx", "npm-check-updates", "-u"], cwd=working_dir)
|
|
105
|
-
|
|
106
|
-
# Step 2: Install updated dependencies
|
|
107
|
-
subprocess.run(["npm", "install"], cwd=working_dir)
|
|
108
|
-
|
|
109
|
-
click.echo(
|
|
110
|
-
click.style("NPM dependencies updated successfully!", fg="green")
|
|
111
|
-
)
|
|
112
|
-
except subprocess.CalledProcessError as e:
|
|
113
|
-
click.echo(click.style(f"Error during npm update: {e}", fg="red"))
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
@click.command("update", help="Upload all pip dependencies.")
|
|
118
|
-
def update():
|
|
119
|
-
"""Update both pip and npm dependencies."""
|
|
120
|
-
try:
|
|
121
|
-
click.echo("Updating pip dependencies...")
|
|
122
|
-
update_pip()
|
|
123
|
-
click.echo("Updating npm dependencies...")
|
|
124
|
-
update_npm()
|
|
125
|
-
click.echo(
|
|
126
|
-
click.style("All dependencies updated successfully!", fg="green")
|
|
127
|
-
)
|
|
128
|
-
except Exception as e:
|
|
129
|
-
click.echo(click.style(f"Error during update: {e}", fg="red"))
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
@click.command("update:pip", help="Upload all pip dependencies.")
|
|
133
|
-
def update_pip_cmd():
|
|
134
|
-
"""Update only pip dependencies."""
|
|
135
|
-
try:
|
|
136
|
-
click.echo("Updating pip dependencies...")
|
|
137
|
-
update_pip()
|
|
138
|
-
click.echo(
|
|
139
|
-
click.style("Pip dependencies updated successfully!", fg="green")
|
|
140
|
-
)
|
|
141
|
-
except Exception as e:
|
|
142
|
-
click.echo(click.style(f"Error during pip update: {e}", fg="red"))
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
@click.command("update:npm", help="Upload all npm dependencies.")
|
|
146
|
-
def update_npm_cmd():
|
|
147
|
-
"""Update only npm dependencies."""
|
|
148
|
-
try:
|
|
149
|
-
click.echo("Updating npm dependencies...")
|
|
150
|
-
update_npm()
|
|
151
|
-
click.echo(
|
|
152
|
-
click.style("NPM dependencies updated successfully!", fg="green")
|
|
153
|
-
)
|
|
154
|
-
except Exception as e:
|
|
155
|
-
click.echo(click.style(f"Error during npm update: {e}", fg="red"))
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if __name__ == "__main__":
|
|
159
|
-
cli()
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import sys
|
|
3
|
-
import subprocess
|
|
4
|
-
import tomllib # Python 3.11+
|
|
5
|
-
from importlib.metadata import distributions
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def ensure_editable_features_installed():
|
|
9
|
-
"""Installs missing editable features defined in features.txt of the SPLENT app."""
|
|
10
|
-
splent_app_name = os.getenv("SPLENT_APP")
|
|
11
|
-
if not splent_app_name:
|
|
12
|
-
print("❌ Environment variable SPLENT_APP not set.")
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
features_file = f"/workspace/{splent_app_name}/features.txt"
|
|
16
|
-
if not os.path.isfile(features_file):
|
|
17
|
-
print(f"⚠️ No features.txt found in {splent_app_name}, skipping feature installation.")
|
|
18
|
-
return
|
|
19
|
-
|
|
20
|
-
def get_installed_package_names():
|
|
21
|
-
return {dist.metadata["Name"] for dist in distributions() if "Name" in dist.metadata}
|
|
22
|
-
|
|
23
|
-
def extract_package_name(pyproject_path):
|
|
24
|
-
with open(pyproject_path, "rb") as f:
|
|
25
|
-
pyproject = tomllib.load(f)
|
|
26
|
-
return pyproject["project"]["name"]
|
|
27
|
-
|
|
28
|
-
installed_names = get_installed_package_names()
|
|
29
|
-
|
|
30
|
-
with open(features_file) as f:
|
|
31
|
-
for line in f:
|
|
32
|
-
feature = line.strip()
|
|
33
|
-
if not feature:
|
|
34
|
-
continue
|
|
35
|
-
|
|
36
|
-
path = os.path.join("/workspace", feature)
|
|
37
|
-
pyproject_path = os.path.join(path, "pyproject.toml")
|
|
38
|
-
|
|
39
|
-
if not os.path.isfile(pyproject_path):
|
|
40
|
-
print(f"❌ pyproject.toml not found in {path}. Skipping.")
|
|
41
|
-
continue
|
|
42
|
-
|
|
43
|
-
try:
|
|
44
|
-
package_name = extract_package_name(pyproject_path)
|
|
45
|
-
except Exception as e:
|
|
46
|
-
print(f"❌ Could not read package name from {pyproject_path}: {e}")
|
|
47
|
-
continue
|
|
48
|
-
|
|
49
|
-
if package_name not in installed_names:
|
|
50
|
-
print(f"➡️ Installing {package_name}...")
|
|
51
|
-
subprocess.run(
|
|
52
|
-
[sys.executable, "-m", "pip", "install", "-e", path],
|
|
53
|
-
check=True
|
|
54
|
-
)
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: splent_cli
|
|
3
|
-
Version: 0.0.2
|
|
4
|
-
Summary: SPLENT-CLI is a CLI to be able to work on your development more easily.
|
|
5
|
-
Author-email: DiversoLab <diversolab@us.es>
|
|
6
|
-
Project-URL: Homepage, https://github.com/diverso-lab/splent_cli
|
|
7
|
-
Project-URL: Issues, https://github.com/diverso-lab/splent_cli/issues
|
|
8
|
-
Requires-Python: >=3.12
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Requires-Dist: click
|
|
12
|
-
Requires-Dist: python-dotenv
|
|
13
|
-
Requires-Dist: flask
|
|
14
|
-
Requires-Dist: setuptools
|
|
15
|
-
Requires-Dist: pytest
|
|
16
|
-
Requires-Dist: pytest-cov
|
|
17
|
-
Requires-Dist: ruff
|
|
18
|
-
Requires-Dist: build
|
|
19
|
-
Requires-Dist: twine
|
|
20
|
-
Dynamic: license-file
|
|
21
|
-
|
|
22
|
-
# splent_cli
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|