bl-odoo 0.3.0__py3-none-any.whl → 0.3.2__py3-none-any.whl
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.
- bl/__main__.py +14 -10
- bl/freezer.py +3 -4
- bl/spec_parser.py +16 -9
- bl/spec_processor.py +1 -0
- bl/utils.py +5 -3
- bl_odoo-0.3.2.dist-info/METADATA +95 -0
- bl_odoo-0.3.2.dist-info/RECORD +13 -0
- bl_odoo-0.3.0.dist-info/METADATA +0 -17
- bl_odoo-0.3.0.dist-info/RECORD +0 -13
- {bl_odoo-0.3.0.dist-info → bl_odoo-0.3.2.dist-info}/WHEEL +0 -0
- {bl_odoo-0.3.0.dist-info → bl_odoo-0.3.2.dist-info}/entry_points.txt +0 -0
- {bl_odoo-0.3.0.dist-info → bl_odoo-0.3.2.dist-info}/licenses/LICENSE +0 -0
- {bl_odoo-0.3.0.dist-info → bl_odoo-0.3.2.dist-info}/top_level.txt +0 -0
bl/__main__.py
CHANGED
|
@@ -12,15 +12,19 @@ def run():
|
|
|
12
12
|
parser = argparse.ArgumentParser(
|
|
13
13
|
description="Process a project specification.", formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
|
14
14
|
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
parser.add_argument(
|
|
15
|
+
|
|
16
|
+
parent_parser = argparse.ArgumentParser(add_help=False)
|
|
17
|
+
parent_parser.add_argument(
|
|
19
18
|
"-c", "--config", type=Path, help="Path to the project specification file.", default="spec.yaml"
|
|
20
19
|
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
parent_parser.add_argument("-z", "--frozen", type=Path, help="Path to the frozen specification file.")
|
|
21
|
+
parent_parser.add_argument("-j", "--concurrency", type=int, default=28, help="Number of concurrent tasks.")
|
|
22
|
+
parent_parser.add_argument("-w", "--workdir", type=Path, help="Working directory. Defaults to config directory.")
|
|
23
|
+
|
|
24
|
+
sub = parser.add_subparsers(help="subcommand help", dest="command")
|
|
25
|
+
build = sub.add_parser("build", parents=[parent_parser], help="build help")
|
|
26
|
+
freeze = sub.add_parser("freeze", parents=[parent_parser], help="freeze help")
|
|
27
|
+
|
|
24
28
|
args = parser.parse_args()
|
|
25
29
|
|
|
26
30
|
project_spec = load_spec_file(args.config, args.frozen, args.workdir)
|
|
@@ -28,9 +32,9 @@ def run():
|
|
|
28
32
|
sys.exit(1)
|
|
29
33
|
|
|
30
34
|
try:
|
|
31
|
-
if args.freeze:
|
|
32
|
-
asyncio.run(freeze_project(project_spec, args.
|
|
33
|
-
|
|
35
|
+
if args.command == "freeze":
|
|
36
|
+
asyncio.run(freeze_project(project_spec, args.frozen, concurrency=args.concurrency))
|
|
37
|
+
elif args.command == "build":
|
|
34
38
|
asyncio.run(process_project(project_spec, concurrency=args.concurrency))
|
|
35
39
|
except Exception:
|
|
36
40
|
sys.exit(1)
|
bl/freezer.py
CHANGED
|
@@ -40,7 +40,7 @@ async def freeze_spec(
|
|
|
40
40
|
async def freeze_project(project_spec: ProjectSpec, freeze_file: Path | bool, concurrency: int):
|
|
41
41
|
frz_semaphore = asyncio.Semaphore(concurrency)
|
|
42
42
|
workdir = project_spec.workdir
|
|
43
|
-
freeze_file_name = freeze_file if freeze_file
|
|
43
|
+
freeze_file_name = freeze_file if freeze_file else "frozen.yaml"
|
|
44
44
|
freeze_file_path = workdir / freeze_file_name
|
|
45
45
|
|
|
46
46
|
task_count_progress = Progress(
|
|
@@ -49,14 +49,14 @@ async def freeze_project(project_spec: ProjectSpec, freeze_file: Path | bool, co
|
|
|
49
49
|
MofNCompleteColumn(),
|
|
50
50
|
)
|
|
51
51
|
count_task = task_count_progress.add_task(
|
|
52
|
-
f"Freezing modules into {freeze_file_path}", total=len(project_spec.
|
|
52
|
+
f"Freezing modules into {freeze_file_path}", total=len(project_spec.repos)
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
freeze_data = {}
|
|
56
56
|
|
|
57
57
|
with Live(task_count_progress, console=console, refresh_per_second=10):
|
|
58
58
|
task_list = []
|
|
59
|
-
for name, spec in project_spec.
|
|
59
|
+
for name, spec in project_spec.repos.items():
|
|
60
60
|
task_list.append(
|
|
61
61
|
freeze_spec(
|
|
62
62
|
frz_semaphore,
|
|
@@ -71,7 +71,6 @@ async def freeze_project(project_spec: ProjectSpec, freeze_file: Path | bool, co
|
|
|
71
71
|
for item in freeze_list:
|
|
72
72
|
freeze_data.update(item)
|
|
73
73
|
|
|
74
|
-
console.print(yaml.dump(freeze_data, default_flow_style=False))
|
|
75
74
|
with open(freeze_file_path, "w") as freeze_stream:
|
|
76
75
|
yaml.dump(freeze_data, freeze_stream, default_flow_style=False)
|
|
77
76
|
|
bl/spec_parser.py
CHANGED
|
@@ -3,7 +3,7 @@ import warnings
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from enum import Enum
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Any, Dict, List, Optional
|
|
6
|
+
from typing import Any, Dict, List, Optional, Type
|
|
7
7
|
|
|
8
8
|
import yaml
|
|
9
9
|
|
|
@@ -69,6 +69,13 @@ def parse_remote_refspec_from_parts(parts: List[str], frozen_repo: Dict[str, Dic
|
|
|
69
69
|
return RefspecInfo(remote_key, ref_spec, ref_type, ref_name)
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
def get_with_syntax_check(name, data, key: str, type: Type):
|
|
73
|
+
result = data.get(key, type())
|
|
74
|
+
if not isinstance(result, type):
|
|
75
|
+
raise Exception(f"Key {key} not of proper syntax should be {str(type)} in {name} description")
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
|
|
72
79
|
def load_spec_file(config: Path, frozen: Path, workdir: Path) -> Optional[ProjectSpec]:
|
|
73
80
|
"""
|
|
74
81
|
Loads and parses the project specification from a YAML file.
|
|
@@ -115,14 +122,14 @@ def load_spec_file(config: Path, frozen: Path, workdir: Path) -> Optional[Projec
|
|
|
115
122
|
|
|
116
123
|
repos: Dict[str, RepoInfo] = {}
|
|
117
124
|
for repo_name, repo_data in data.items():
|
|
118
|
-
modules = repo_data
|
|
119
|
-
src = repo_data
|
|
120
|
-
remotes = repo_data
|
|
121
|
-
merges = repo_data
|
|
122
|
-
shell_commands = repo_data
|
|
123
|
-
patch_globs_to_apply = repo_data
|
|
124
|
-
target_folder = repo_data
|
|
125
|
-
locales = repo_data
|
|
125
|
+
modules = get_with_syntax_check(repo_name, repo_data, "modules", list)
|
|
126
|
+
src = get_with_syntax_check(repo_name, repo_data, "src", str)
|
|
127
|
+
remotes = get_with_syntax_check(repo_name, repo_data, "remotes", dict)
|
|
128
|
+
merges = get_with_syntax_check(repo_name, repo_data, "merges", list)
|
|
129
|
+
shell_commands = get_with_syntax_check(repo_name, repo_data, "shell_command_after", list)
|
|
130
|
+
patch_globs_to_apply = get_with_syntax_check(repo_name, repo_data, "patch_globs", list)
|
|
131
|
+
target_folder = get_with_syntax_check(repo_name, repo_data, "target_folder", str)
|
|
132
|
+
locales = get_with_syntax_check(repo_name, repo_data, "locales", list)
|
|
126
133
|
|
|
127
134
|
frozen_repo = frozen_mapping.get(repo_name, {})
|
|
128
135
|
|
bl/spec_processor.py
CHANGED
|
@@ -4,6 +4,7 @@ import warnings
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import Dict, List
|
|
6
6
|
|
|
7
|
+
from rich import progress
|
|
7
8
|
from rich.console import Console
|
|
8
9
|
from rich.live import Live
|
|
9
10
|
from rich.progress import BarColumn, MofNCompleteColumn, Progress, SpinnerColumn, TaskID, TextColumn
|
bl/utils.py
CHANGED
|
@@ -14,14 +14,14 @@ english_env["LANG"] = "en_US.UTF-8"
|
|
|
14
14
|
|
|
15
15
|
def get_module_path(workdir: Path, module_name: str, module_spec: RepoInfo) -> Path:
|
|
16
16
|
"""Returns the path to the module directory."""
|
|
17
|
-
if module_name == "odoo" and module_spec.target_folder
|
|
17
|
+
if module_name == "odoo" and not module_spec.target_folder:
|
|
18
18
|
warnings.warn(
|
|
19
19
|
"importing 'odoo' without a 'target_folder' "
|
|
20
20
|
+ "property is deprecated. Use target_folder: 'src/' in spec.yaml.",
|
|
21
21
|
DeprecationWarning,
|
|
22
22
|
)
|
|
23
23
|
return workdir / "src/"
|
|
24
|
-
elif module_spec.target_folder
|
|
24
|
+
elif module_spec.target_folder:
|
|
25
25
|
return workdir / module_spec.target_folder
|
|
26
26
|
else:
|
|
27
27
|
return workdir / "external-src" / module_name
|
|
@@ -29,13 +29,15 @@ def get_module_path(workdir: Path, module_name: str, module_spec: RepoInfo) -> P
|
|
|
29
29
|
|
|
30
30
|
def get_local_ref(origin: RefspecInfo) -> str:
|
|
31
31
|
"""Generates a local reference name for a given origin."""
|
|
32
|
-
return f"
|
|
32
|
+
return f"{origin.ref_name or origin.refspec}"
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
async def run_git(*args: str, cwd: Optional[Path] = None) -> tuple[int, str, str]:
|
|
36
36
|
"""Executes a git command asynchronously."""
|
|
37
37
|
proc = await asyncio.create_subprocess_exec(
|
|
38
38
|
"git",
|
|
39
|
+
"--git-dir",
|
|
40
|
+
".git/",
|
|
39
41
|
*args,
|
|
40
42
|
stdout=asyncio.subprocess.PIPE,
|
|
41
43
|
stderr=asyncio.subprocess.PIPE,
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bl-odoo
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: A command-line tool for managing Odoo dependencies.
|
|
5
|
+
Author-email: Your Name <your.email@example.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
11
|
+
Requires-Dist: rich
|
|
12
|
+
Requires-Dist: typer
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# bl
|
|
16
|
+
|
|
17
|
+
## Why BL
|
|
18
|
+
|
|
19
|
+
Because `ak` is slow and `bl` is fast
|
|
20
|
+
|
|
21
|
+
Because `ak` crashes if anything goes wrong
|
|
22
|
+
|
|
23
|
+
Because `ak` error are impossible to find
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
`pipx install bl-odoo`
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### Build
|
|
32
|
+
|
|
33
|
+
```bl build -c <path_to_spec.yaml> -z <path_to_frozen.yaml> -j <concurrency>```
|
|
34
|
+
|
|
35
|
+
#### Params
|
|
36
|
+
* `path_to_spec.yaml` should be the path to your spec (default: spec.yaml)
|
|
37
|
+
* `path_to_frozen.yaml` should be the path to your spec (default: frozen.yaml)
|
|
38
|
+
* `concurrency` number of module clone simultaneously (default: 28)
|
|
39
|
+
|
|
40
|
+
#### How it looks
|
|
41
|
+
<img width="1683" height="756" alt="bl_build" src="https://github.com/user-attachments/assets/22fc1565-3a54-4f57-9b85-a11263b9b536" />
|
|
42
|
+
|
|
43
|
+
### Freeze
|
|
44
|
+
|
|
45
|
+
```bl freeze -c <path_to_spec.yaml> -z <path_to_frozen.yaml> -j <concurrency>```
|
|
46
|
+
|
|
47
|
+
#### Params
|
|
48
|
+
* `path_to_spec.yaml` should be the path to your spec (default: spec.yaml)
|
|
49
|
+
* `path_to_frozen.yaml` should be the path to your spec (default: frozen.yaml)
|
|
50
|
+
* `concurrency` number of module clone simultaneously (default: 28)
|
|
51
|
+
|
|
52
|
+
## Odoo is taking a really long time to clone
|
|
53
|
+
|
|
54
|
+
Yes !
|
|
55
|
+
|
|
56
|
+
You can add a locales entry to your odoo repo in `spec.yaml` like so:
|
|
57
|
+
```
|
|
58
|
+
odoo:
|
|
59
|
+
modules:
|
|
60
|
+
- account
|
|
61
|
+
...
|
|
62
|
+
remotes:
|
|
63
|
+
odoo: https://github.com/odoo/odoo
|
|
64
|
+
merges:
|
|
65
|
+
- odoo 14.0
|
|
66
|
+
locales:
|
|
67
|
+
- fr
|
|
68
|
+
- en
|
|
69
|
+
```
|
|
70
|
+
It will only download the french and english translation instead of all of them
|
|
71
|
+
- without locales: 849MB and 40 seconds fresh build
|
|
72
|
+
- with locales fr, en: 169MB and 27 seconds fresh build
|
|
73
|
+
|
|
74
|
+
## Benchmarks
|
|
75
|
+
|
|
76
|
+
### Ak benchmarks
|
|
77
|
+
#### Fresh install
|
|
78
|
+
<img width="1462" height="347" alt="ak_bench_cold" src="https://github.com/user-attachments/assets/e29cd3d9-831c-43c1-8f29-e040ebee5740" />
|
|
79
|
+
|
|
80
|
+
#### Already cloned once
|
|
81
|
+
<img width="1419" height="356" alt="ak_bench_hot" src="https://github.com/user-attachments/assets/47b5756e-efe1-4272-82b7-e160f73af1be" />
|
|
82
|
+
|
|
83
|
+
### Bl benchmarks
|
|
84
|
+
#### Fresh install
|
|
85
|
+
<img width="1335" height="343" alt="bl_bench_cold" src="https://github.com/user-attachments/assets/a64ba1c4-17bd-4017-acfd-5749df505f50" />
|
|
86
|
+
|
|
87
|
+
#### Already cloned once
|
|
88
|
+
<img width="1373" height="342" alt="bl_bench_hot" src="https://github.com/user-attachments/assets/b11e60c2-368b-496c-bc88-f5a765f44bfe" />
|
|
89
|
+
|
|
90
|
+
### Results
|
|
91
|
+
|Type| AK | BL |
|
|
92
|
+
|----|----|----|
|
|
93
|
+
|Cold| ~100s | 2 - 10x faster |
|
|
94
|
+
|Hot| 3-20s | 2 - 10x faster |
|
|
95
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
bl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
bl/__main__.py,sha256=EoFSp4KttZ3QvJqymAvilLUhkzAGVig0JVJY5FyzYko,1643
|
|
3
|
+
bl/freezer.py,sha256=vabN0MY_JRx8ztNou0ymZgDCWb2EKGf6xUnhG6z33u8,2432
|
|
4
|
+
bl/spec_parser.py,sha256=dVvaK4fhtut5_vI3sm7g5oGk0hc_vFAvDfnVDVTf_64,5457
|
|
5
|
+
bl/spec_processor.py,sha256=KsgNX-IAizLZ_22WcFKJAeCJKd98clDZb4qQ0kclqOs,17893
|
|
6
|
+
bl/types.py,sha256=h14FXDVCrYRxY7lYTEu8jhdrEHr1PvSNyZRIHm33CTk,2158
|
|
7
|
+
bl/utils.py,sha256=BFczSYKSpKCcaYilHVm1yQVXbbV0yw4QdOAu474vNlY,1618
|
|
8
|
+
bl_odoo-0.3.2.dist-info/licenses/LICENSE,sha256=GTVQl3vH6ht70wJXKC0yMT8CmXKHxv_YyO_utAgm7EA,1065
|
|
9
|
+
bl_odoo-0.3.2.dist-info/METADATA,sha256=1PDB9kSY8YP8lSviWJ5xbXTWxqXUv9HT7xi6ZJpiRFg,2639
|
|
10
|
+
bl_odoo-0.3.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
11
|
+
bl_odoo-0.3.2.dist-info/entry_points.txt,sha256=fmdGhYYJlP-XByamgaZdM0bo3JK4LJFswU_Nilq6SSw,39
|
|
12
|
+
bl_odoo-0.3.2.dist-info/top_level.txt,sha256=1o4tN3wszdw7U5SnGgdF5P2sTYA0Schf0vKFy9_2D6A,3
|
|
13
|
+
bl_odoo-0.3.2.dist-info/RECORD,,
|
bl_odoo-0.3.0.dist-info/METADATA
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: bl-odoo
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Summary: A command-line tool for managing Odoo dependencies.
|
|
5
|
-
Author-email: Your Name <your.email@example.com>
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Requires-Python: >=3.9
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Requires-Dist: pyyaml>=6.0.3
|
|
11
|
-
Requires-Dist: rich
|
|
12
|
-
Requires-Dist: typer
|
|
13
|
-
Dynamic: license-file
|
|
14
|
-
|
|
15
|
-
# bl
|
|
16
|
-
|
|
17
|
-
A new Python project.
|
bl_odoo-0.3.0.dist-info/RECORD
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
bl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
bl/__main__.py,sha256=v1d-voJ7N1QBLGJJh8JdrTxXtzf0JFHQv4RUBxlCkcg,1428
|
|
3
|
-
bl/freezer.py,sha256=wUYNd0zKU-0OGdIXSLJol-_xJmxSSkXvzV_VbF2HJyg,2512
|
|
4
|
-
bl/spec_parser.py,sha256=nZTwMh_ja4Mc7CKqB7-5cwECHrP15xd1S8zb_LW79BU,4953
|
|
5
|
-
bl/spec_processor.py,sha256=yejkFFig_Yfbv1Ail1xTpteFv-f7dE7gasF_YU1oTXs,17867
|
|
6
|
-
bl/types.py,sha256=h14FXDVCrYRxY7lYTEu8jhdrEHr1PvSNyZRIHm33CTk,2158
|
|
7
|
-
bl/utils.py,sha256=JNLsxgJgWaa71Xs62gcoOwJnPjNHkrW0q9HFB0vQ60E,1600
|
|
8
|
-
bl_odoo-0.3.0.dist-info/licenses/LICENSE,sha256=GTVQl3vH6ht70wJXKC0yMT8CmXKHxv_YyO_utAgm7EA,1065
|
|
9
|
-
bl_odoo-0.3.0.dist-info/METADATA,sha256=VRKm91QHoxE_y5hSphmULSNRdjzvyvcSfBbQ5iRwafs,391
|
|
10
|
-
bl_odoo-0.3.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
11
|
-
bl_odoo-0.3.0.dist-info/entry_points.txt,sha256=fmdGhYYJlP-XByamgaZdM0bo3JK4LJFswU_Nilq6SSw,39
|
|
12
|
-
bl_odoo-0.3.0.dist-info/top_level.txt,sha256=1o4tN3wszdw7U5SnGgdF5P2sTYA0Schf0vKFy9_2D6A,3
|
|
13
|
-
bl_odoo-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|