gOdoo-cli 0.7.0__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.
- godoo_cli/__init__.py +2 -0
- godoo_cli/__main__.py +5 -0
- godoo_cli/cli.py +87 -0
- godoo_cli/cli_common.py +183 -0
- godoo_cli/commands/__init__.py +9 -0
- godoo_cli/commands/backup/__init__.py +1 -0
- godoo_cli/commands/backup/cli.py +17 -0
- godoo_cli/commands/backup/load.py +110 -0
- godoo_cli/commands/backup/pull.py +134 -0
- godoo_cli/commands/backup/util.py +35 -0
- godoo_cli/commands/bootstrap.py +187 -0
- godoo_cli/commands/config.py +43 -0
- godoo_cli/commands/db/__init__.py +1 -0
- godoo_cli/commands/db/cli.py +18 -0
- godoo_cli/commands/db/connection.py +94 -0
- godoo_cli/commands/db/passwords.py +56 -0
- godoo_cli/commands/db/query.py +41 -0
- godoo_cli/commands/launch.py +325 -0
- godoo_cli/commands/rpc/__init__.py +8 -0
- godoo_cli/commands/rpc/cli.py +34 -0
- godoo_cli/commands/rpc/config_parameters.py +48 -0
- godoo_cli/commands/rpc/importer.py +70 -0
- godoo_cli/commands/rpc/modules.py +144 -0
- godoo_cli/commands/rpc/translations.py +129 -0
- godoo_cli/commands/shell.py +45 -0
- godoo_cli/commands/source_get.py +279 -0
- godoo_cli/commands/test.py +126 -0
- godoo_cli/git/__init__.py +4 -0
- godoo_cli/git/git_odoo.py +89 -0
- godoo_cli/git/git_odoo_addons.py +95 -0
- godoo_cli/git/git_repo.py +207 -0
- godoo_cli/git/git_url.py +152 -0
- godoo_cli/git/zip_download.py +49 -0
- godoo_cli/helpers/__init__.py +1 -0
- godoo_cli/helpers/bootstrap.py +61 -0
- godoo_cli/helpers/cli.py +15 -0
- godoo_cli/helpers/odoo_files.py +278 -0
- godoo_cli/helpers/odoo_manifest.py +112 -0
- godoo_cli/helpers/system.py +176 -0
- godoo_cli/version.py +1 -0
- godoo_cli-0.7.0.dist-info/LICENSE +165 -0
- godoo_cli-0.7.0.dist-info/METADATA +197 -0
- godoo_cli-0.7.0.dist-info/RECORD +45 -0
- godoo_cli-0.7.0.dist-info/WHEEL +4 -0
- godoo_cli-0.7.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""Functions that operate on Odoos Source Code."""
|
|
2
|
+
import logging
|
|
3
|
+
from ast import literal_eval
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Union
|
|
6
|
+
|
|
7
|
+
from git import Repo
|
|
8
|
+
|
|
9
|
+
from .system import run_cmd
|
|
10
|
+
|
|
11
|
+
LOGGER = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def odoo_bin_get_version(odoo_main_repo_path: Path) -> str:
|
|
15
|
+
"""Get Odoo Version by calling 'odoo-bin --version'
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
odoo_main_repo_path : Path
|
|
20
|
+
Path to odoo-bin folder
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
str
|
|
25
|
+
odoo-bin --version output
|
|
26
|
+
"""
|
|
27
|
+
odoo_bin_path = odoo_main_repo_path / "odoo-bin"
|
|
28
|
+
version_out = run_cmd(f"{odoo_bin_path.absolute()} --version", capture_output=True, text=True)
|
|
29
|
+
return version_out.stdout
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_zip_addon_path(thirdparty_path: Path) -> Path:
|
|
33
|
+
return thirdparty_path / "custom"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def folder_is_odoo_module(folder: Path) -> bool:
|
|
37
|
+
"""Wether folder is a valid odoo module.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
folder : Path
|
|
42
|
+
Folder to check
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
bool
|
|
47
|
+
true if folder contains a module
|
|
48
|
+
"""
|
|
49
|
+
return folder.is_dir() and any(folder.glob("__manifest__.py"))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_odoo_module_paths(search_folders: Union[List[Path], Path]) -> List[Path]:
|
|
53
|
+
"""List all Valid odoo module names in one or many Odoo addons folder.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
search_folders : Path
|
|
58
|
+
Folder(s) to search in.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
List[Path]
|
|
63
|
+
List of Valid Module Folders within search_folder
|
|
64
|
+
"""
|
|
65
|
+
if not isinstance(search_folders, List):
|
|
66
|
+
search_folders = [search_folders]
|
|
67
|
+
|
|
68
|
+
module_paths = []
|
|
69
|
+
for folder in search_folders:
|
|
70
|
+
if not folder.exists():
|
|
71
|
+
return
|
|
72
|
+
for folder in folder.iterdir():
|
|
73
|
+
if folder_is_odoo_module(folder):
|
|
74
|
+
module_paths.append(folder)
|
|
75
|
+
return module_paths
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_changed_modules(
|
|
79
|
+
addon_path: Path,
|
|
80
|
+
diff_branch: str,
|
|
81
|
+
) -> List[Path]:
|
|
82
|
+
"""Get Paths of changed modules since git diff.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
addon_path : Path
|
|
87
|
+
Folder in git repo where to look for changes
|
|
88
|
+
diff_branch : str
|
|
89
|
+
Branch or diffable ref for git
|
|
90
|
+
|
|
91
|
+
Returns
|
|
92
|
+
-------
|
|
93
|
+
List[Path]
|
|
94
|
+
List of Paths where something has changed since git diff
|
|
95
|
+
"""
|
|
96
|
+
addon_path = addon_path.absolute()
|
|
97
|
+
repo = Repo(addon_path, search_parent_directories=True)
|
|
98
|
+
git_root = Path(repo.git.rev_parse("--show-toplevel"))
|
|
99
|
+
changed_module_files = []
|
|
100
|
+
for change in repo.git.diff("--name-status", diff_branch).split("\n"):
|
|
101
|
+
path = git_root / change.split("\t")[1]
|
|
102
|
+
if addon_path in path.parents:
|
|
103
|
+
changed_module_files.append(path)
|
|
104
|
+
|
|
105
|
+
changed_module_folders = []
|
|
106
|
+
for f in changed_module_files:
|
|
107
|
+
for pf in f.parents:
|
|
108
|
+
if pf.absolute() == addon_path.absolute():
|
|
109
|
+
break
|
|
110
|
+
if pf.absolute() not in changed_module_folders and folder_is_odoo_module(pf):
|
|
111
|
+
changed_module_folders.append(pf.absolute())
|
|
112
|
+
if changed_module_folders:
|
|
113
|
+
LOGGER.debug(
|
|
114
|
+
"Found Modules changed to branch '%s':\n %s",
|
|
115
|
+
diff_branch,
|
|
116
|
+
"\n".join(["\t" + str(f) for f in changed_module_folders]),
|
|
117
|
+
)
|
|
118
|
+
return changed_module_folders
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_depends_of_module(
|
|
122
|
+
all_modules: List[Path],
|
|
123
|
+
module_to_check: Path,
|
|
124
|
+
already_done_modules: List[Path] = None,
|
|
125
|
+
):
|
|
126
|
+
"""Recursively Searches sub dependencies for Odoo modules.
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
all_modules : List[Path]
|
|
132
|
+
List of Path objects pointing to odoo modules
|
|
133
|
+
module_to_check : Path
|
|
134
|
+
path with odoo module
|
|
135
|
+
already_done_modules : List[Path], optional
|
|
136
|
+
Only used internally for recursion caching, by default None
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
List[Path]
|
|
141
|
+
Paths to dependency modules
|
|
142
|
+
"""
|
|
143
|
+
manifest_path = module_to_check / "__manifest__.py"
|
|
144
|
+
|
|
145
|
+
if not already_done_modules:
|
|
146
|
+
already_done_modules = []
|
|
147
|
+
if module_to_check.absolute() in already_done_modules:
|
|
148
|
+
return []
|
|
149
|
+
already_done_modules.append(module_to_check.absolute())
|
|
150
|
+
|
|
151
|
+
manifest = literal_eval(manifest_path.read_text())
|
|
152
|
+
module_depends = manifest.get("depends", [])
|
|
153
|
+
sub_depends = []
|
|
154
|
+
for dep in module_depends:
|
|
155
|
+
dep_path = [p for p in all_modules if p.stem == dep]
|
|
156
|
+
if dep_path:
|
|
157
|
+
dep_path = dep_path[0]
|
|
158
|
+
if dep_path.absolute() in already_done_modules:
|
|
159
|
+
continue
|
|
160
|
+
sub_depends.append(dep_path.absolute())
|
|
161
|
+
sub_depends += get_depends_of_module(all_modules, dep_path, already_done_modules)
|
|
162
|
+
elif dep != "base":
|
|
163
|
+
LOGGER.warn("Could not find Dependency: '%s' in available modules", dep)
|
|
164
|
+
|
|
165
|
+
return list(set(sub_depends))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def get_addon_paths(
|
|
169
|
+
odoo_main_repo: Path,
|
|
170
|
+
workspace_addon_path: Path,
|
|
171
|
+
thirdparty_addon_path: Path,
|
|
172
|
+
) -> List[Path]:
|
|
173
|
+
"""Get Odoo Addon Paths for odoo.conf.
|
|
174
|
+
|
|
175
|
+
Parameters
|
|
176
|
+
----------
|
|
177
|
+
odoo_main_repo : Path
|
|
178
|
+
Path to main odoo repo
|
|
179
|
+
workspace_addon_path : Path
|
|
180
|
+
Path to workspace addons
|
|
181
|
+
thirdparty_addon_path : Path
|
|
182
|
+
path to git cloned addon repos
|
|
183
|
+
|
|
184
|
+
Returns
|
|
185
|
+
-------
|
|
186
|
+
List[Path]
|
|
187
|
+
List of valid addon Paths
|
|
188
|
+
"""
|
|
189
|
+
odoo_addon_paths = [odoo_main_repo / "addons"]
|
|
190
|
+
if get_odoo_module_paths(workspace_addon_path):
|
|
191
|
+
odoo_addon_paths.append(workspace_addon_path)
|
|
192
|
+
zip_addon_path = get_zip_addon_path(thirdparty_addon_path)
|
|
193
|
+
zip_addon_repos = [f for f in zip_addon_path.iterdir() if f.is_dir() and get_odoo_module_paths(f)]
|
|
194
|
+
odoo_addon_paths += zip_addon_repos
|
|
195
|
+
git_thirdparty_addon_repos = [
|
|
196
|
+
p for p in thirdparty_addon_path.iterdir() if p.is_dir() and not p.resolve() == zip_addon_path.resolve()
|
|
197
|
+
]
|
|
198
|
+
odoo_addon_paths += git_thirdparty_addon_repos
|
|
199
|
+
return odoo_addon_paths
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _get_odoo_main_path(addon_paths: List[Path]) -> Path:
|
|
203
|
+
"""Get Odoo main path by location of odoo-bin from addon folders.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
addon_paths : List[Path]
|
|
208
|
+
List of possible paths
|
|
209
|
+
|
|
210
|
+
Returns
|
|
211
|
+
-------
|
|
212
|
+
Path
|
|
213
|
+
Path with odoo-bin and main addons folder
|
|
214
|
+
"""
|
|
215
|
+
for path in addon_paths:
|
|
216
|
+
# The main odoo addon path is odoo/addons.
|
|
217
|
+
# so one up should be the launch script
|
|
218
|
+
bin_path = path.parent / "odoo-bin"
|
|
219
|
+
if bin_path.exists() and bin_path.is_file():
|
|
220
|
+
return path
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _get_python_requirements_of_modules(addon_paths: List[Path], filter_module_names: List[str] = None):
|
|
224
|
+
"""Install python requirements mentioned in module manifests
|
|
225
|
+
|
|
226
|
+
Parameters
|
|
227
|
+
----------
|
|
228
|
+
addon_paths : List[Path]
|
|
229
|
+
Paths to look for addons. (same as odoo-bin)
|
|
230
|
+
filter_module_names : List[str], optional
|
|
231
|
+
Modules to look for manifests, by default all available modules
|
|
232
|
+
"""
|
|
233
|
+
available_modules = get_odoo_module_paths(addon_paths)
|
|
234
|
+
available_module_names = [p.stem for p in available_modules]
|
|
235
|
+
|
|
236
|
+
if not filter_module_names:
|
|
237
|
+
filter_module_names = available_module_names
|
|
238
|
+
filter_module_names = [f for f in filter_module_names if f != "base"]
|
|
239
|
+
|
|
240
|
+
LOGGER.debug("Checking python requirements of Modules: %s", sorted(filter_module_names))
|
|
241
|
+
if unavailable_modules := set(filter_module_names).difference(available_module_names):
|
|
242
|
+
LOGGER.warning("Could not find __manifest__ for: %s", unavailable_modules)
|
|
243
|
+
LOGGER.debug("Search Paths:\n%s", "\n".join(map(str, addon_paths)))
|
|
244
|
+
|
|
245
|
+
check_modules = [mp for mp in available_modules if mp.stem in filter_module_names]
|
|
246
|
+
|
|
247
|
+
if odoo_main_path := _get_odoo_main_path(addon_paths):
|
|
248
|
+
# When the Odoo main path is in the supplied path, exclude those modules.
|
|
249
|
+
# Odoos base requirements are set in their requirements.txt
|
|
250
|
+
LOGGER.debug("Py install: Excluding Odoo main Modules in: '%s'", odoo_main_path)
|
|
251
|
+
check_modules = [mp for mp in check_modules if odoo_main_path not in mp.parents]
|
|
252
|
+
|
|
253
|
+
check_modules_dependencies = []
|
|
254
|
+
for module in check_modules:
|
|
255
|
+
check_modules_dependencies += get_depends_of_module(
|
|
256
|
+
available_modules, module, already_done_modules=check_modules_dependencies
|
|
257
|
+
)
|
|
258
|
+
LOGGER.debug(
|
|
259
|
+
"adding children of requested modules to check list:\n%s",
|
|
260
|
+
"\n".join(sorted([p.stem for p in check_modules_dependencies])),
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
check_modules += check_modules_dependencies
|
|
264
|
+
|
|
265
|
+
check_modules = set(check_modules)
|
|
266
|
+
|
|
267
|
+
if not check_modules:
|
|
268
|
+
LOGGER.debug("No Modules provided to check for python Requirements")
|
|
269
|
+
return
|
|
270
|
+
python_depends = []
|
|
271
|
+
for module_path in check_modules:
|
|
272
|
+
LOGGER.debug("Checking for External Depends: %s", module_path)
|
|
273
|
+
manifest_path = module_path / "__manifest__.py"
|
|
274
|
+
manifest = literal_eval(manifest_path.read_text())
|
|
275
|
+
if module_depends := manifest.get("external_dependencies", {}).get("python"):
|
|
276
|
+
python_depends += module_depends
|
|
277
|
+
|
|
278
|
+
return list(set(python_depends))
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import shutil
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
from ruamel.yaml import YAML
|
|
7
|
+
|
|
8
|
+
from ..git.git_url import GitUrl
|
|
9
|
+
|
|
10
|
+
LOGGER = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def remove_unused_folders(thirdparty_addon_path: Path, thirdparty_repos, keep_folders: List[Path]):
|
|
14
|
+
"""Remove folders that are not included in git_repos anymore
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
thirdparty_addon_path : Path
|
|
19
|
+
Folder to check for deletions
|
|
20
|
+
thirdparty_repos : Dict
|
|
21
|
+
Dict of Prefix:[dict[url],..]
|
|
22
|
+
"""
|
|
23
|
+
allowed_folders = []
|
|
24
|
+
keep_folders_absolute = [p.absolute() for p in keep_folders]
|
|
25
|
+
for prefix in thirdparty_repos:
|
|
26
|
+
for repo in thirdparty_repos[prefix]:
|
|
27
|
+
repo_url = GitUrl(repo["url"])
|
|
28
|
+
allowed_folders.append(f"{prefix}_{repo_url.name}")
|
|
29
|
+
for folder in thirdparty_addon_path.iterdir():
|
|
30
|
+
if not folder.is_dir() or folder.absolute() in keep_folders_absolute:
|
|
31
|
+
continue
|
|
32
|
+
if folder.stem not in allowed_folders:
|
|
33
|
+
LOGGER.info("Removing unspecified Addon Folder: %s", folder)
|
|
34
|
+
shutil.rmtree(folder)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def update_yml(
|
|
38
|
+
repo_yml,
|
|
39
|
+
generate_yml_compare_comments: bool = False,
|
|
40
|
+
):
|
|
41
|
+
"""Process yaml after thirdparty clone.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
repo_yml : Yaml Dict
|
|
46
|
+
Ruamel Yaml Dict of prefix and list of repos (url,commit,branch)
|
|
47
|
+
generate_yml_compare_comments : bool, optional
|
|
48
|
+
add github compare links as comment to repo yml, by default False
|
|
49
|
+
"""
|
|
50
|
+
thirdparty_repos = repo_yml["thirdparty"]
|
|
51
|
+
odoo_default_branch = repo_yml["odoo"].get("branch")
|
|
52
|
+
if not odoo_default_branch:
|
|
53
|
+
LOGGER.error("Odoo Key in manifest missing branch argument.")
|
|
54
|
+
return
|
|
55
|
+
|
|
56
|
+
for prefix in thirdparty_repos:
|
|
57
|
+
for repo in thirdparty_repos[prefix]:
|
|
58
|
+
if generate_yml_compare_comments:
|
|
59
|
+
yaml_add_compare_commit(repo, odoo_default_branch)
|
|
60
|
+
else:
|
|
61
|
+
yaml_remove_compare_commit(repo)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def yaml_add_compare_commit(repo_dict, compare_target: str):
|
|
65
|
+
"""Add comment with Compare URL to Repo:
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
repo_dict : _type_
|
|
70
|
+
Yaml Dict of url and commit
|
|
71
|
+
compare_target : str
|
|
72
|
+
git ref to compare to
|
|
73
|
+
"""
|
|
74
|
+
git_url = GitUrl(repo_dict["url"])
|
|
75
|
+
try:
|
|
76
|
+
compare_url = git_url.get_compare_url(repo_dict["commit"], compare_target)
|
|
77
|
+
repo_dict.yaml_add_eol_comment(compare_url, "commit")
|
|
78
|
+
except Exception as e:
|
|
79
|
+
LOGGER.warn(f"Cannot Generate compare URL for: {git_url.url}")
|
|
80
|
+
LOGGER.debug(e)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def yaml_remove_compare_commit(repo_dict):
|
|
84
|
+
"""Remove Comments that have /compare/ in them.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
repo_dict : RuamelYaml Dict
|
|
89
|
+
yaml dict
|
|
90
|
+
"""
|
|
91
|
+
del_list = []
|
|
92
|
+
for target, comments in repo_dict.ca.items.items():
|
|
93
|
+
for subcomment in comments:
|
|
94
|
+
if subcomment and "/compare/" in subcomment.value:
|
|
95
|
+
del_list.append(target)
|
|
96
|
+
|
|
97
|
+
for target in del_list:
|
|
98
|
+
del repo_dict.ca.items[target]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def yaml_roundtrip_loader() -> YAML:
|
|
102
|
+
"""Return Ruamel Roundtrip loader.
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
YAML
|
|
107
|
+
Yaml Loader
|
|
108
|
+
"""
|
|
109
|
+
yaml = YAML()
|
|
110
|
+
yaml.preserve_quotes = True
|
|
111
|
+
yaml.indent(mapping=2, sequence=4, offset=2)
|
|
112
|
+
return yaml
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Helper functions around the host system"""
|
|
2
|
+
import datetime
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
import subprocess
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import List, Union
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
import requests
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from rich.logging import RichHandler
|
|
13
|
+
from rich.prompt import Confirm
|
|
14
|
+
from rich.table import Table
|
|
15
|
+
from rich.traceback import install as install_rich_traceback
|
|
16
|
+
|
|
17
|
+
from . import cli as godoo_cli_helpers
|
|
18
|
+
|
|
19
|
+
LOGGER = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def run_cmd(command: str, log_name: str = "", **kwargs) -> subprocess.CompletedProcess:
|
|
23
|
+
"""Runs command via subprocess.run
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
command : str
|
|
28
|
+
Command string
|
|
29
|
+
**kwargs
|
|
30
|
+
get passed down to Run
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
CompletedProcess
|
|
35
|
+
"""
|
|
36
|
+
LOGGER.debug("Running shell: '%s'", command)
|
|
37
|
+
if not kwargs.get("shell"):
|
|
38
|
+
kwargs["shell"] = True
|
|
39
|
+
proc = subprocess.run(command, **kwargs)
|
|
40
|
+
if proc.returncode != 0 and log_name:
|
|
41
|
+
LOGGER.error("Failed: %s", log_name)
|
|
42
|
+
return proc
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def ensure_dotenv(varname: str) -> str:
|
|
46
|
+
"""
|
|
47
|
+
Load Env Var.
|
|
48
|
+
Raise Error if not Set.
|
|
49
|
+
|
|
50
|
+
Parameters
|
|
51
|
+
----------
|
|
52
|
+
varname : str
|
|
53
|
+
env var name
|
|
54
|
+
|
|
55
|
+
Returns
|
|
56
|
+
-------
|
|
57
|
+
str
|
|
58
|
+
env value
|
|
59
|
+
|
|
60
|
+
Raises
|
|
61
|
+
------
|
|
62
|
+
ReferenceError
|
|
63
|
+
if env var is none
|
|
64
|
+
"""
|
|
65
|
+
var = os.getenv(varname)
|
|
66
|
+
if var is None:
|
|
67
|
+
raise ReferenceError(f"Env Variable: {varname} is not set")
|
|
68
|
+
return var
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def set_logging(verbose: bool = False) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Set the Logging Config according to passed arguments.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
verbose : bool
|
|
78
|
+
Wether to Log debug Messages
|
|
79
|
+
"""
|
|
80
|
+
if verbose:
|
|
81
|
+
install_rich_traceback(suppress=[click, godoo_cli_helpers])
|
|
82
|
+
logging.basicConfig(
|
|
83
|
+
level=logging.DEBUG,
|
|
84
|
+
format="{message}",
|
|
85
|
+
style="{",
|
|
86
|
+
handlers=[
|
|
87
|
+
RichHandler(
|
|
88
|
+
level=logging.DEBUG,
|
|
89
|
+
show_path=True,
|
|
90
|
+
rich_tracebacks=True,
|
|
91
|
+
tracebacks_show_locals=True,
|
|
92
|
+
)
|
|
93
|
+
],
|
|
94
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
95
|
+
)
|
|
96
|
+
else:
|
|
97
|
+
logging.basicConfig(
|
|
98
|
+
level=logging.INFO,
|
|
99
|
+
format="{message}",
|
|
100
|
+
style="{",
|
|
101
|
+
handlers=[RichHandler(level=logging.INFO, show_path=False, rich_tracebacks=False)],
|
|
102
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def download_file(url: str, save_path: Path, chunk_size: int = 128) -> None:
|
|
107
|
+
"""Download file from URL.
|
|
108
|
+
|
|
109
|
+
Parameters
|
|
110
|
+
----------
|
|
111
|
+
url : _type_
|
|
112
|
+
url to get file from
|
|
113
|
+
save_path : _type_
|
|
114
|
+
Where to save the file
|
|
115
|
+
chunk_size : int, optional
|
|
116
|
+
Chunk size to iterate over request, by default 128
|
|
117
|
+
"""
|
|
118
|
+
LOGGER.debug("Downloading File: '%s' to '%s'", url, save_path)
|
|
119
|
+
r = requests.get(url, stream=True)
|
|
120
|
+
with open(save_path, "wb") as fd:
|
|
121
|
+
for chunk in r.iter_content(chunk_size=chunk_size):
|
|
122
|
+
fd.write(chunk)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def typer_ask_overwrite_path(paths: Union[List[Path], Path]) -> bool:
|
|
126
|
+
"""Checks if the provided Paths do already exist.
|
|
127
|
+
Ignores 0 size files and empty folders.
|
|
128
|
+
Prints table of Paths with size and Changedate.
|
|
129
|
+
Prompts user to continue or abort typer.
|
|
130
|
+
|
|
131
|
+
Returns
|
|
132
|
+
---------
|
|
133
|
+
False, when we shall not overwrite files.
|
|
134
|
+
True, when there are no files to override or we should override
|
|
135
|
+
"""
|
|
136
|
+
if isinstance(paths, Path):
|
|
137
|
+
paths = [paths]
|
|
138
|
+
|
|
139
|
+
def path_exists(path: Path):
|
|
140
|
+
"""If Path exists and is no empty dir"""
|
|
141
|
+
if path.is_dir():
|
|
142
|
+
return bool(path.glob("*"))
|
|
143
|
+
else:
|
|
144
|
+
return path.exists() and path.stat().st_size
|
|
145
|
+
|
|
146
|
+
existing_paths = [p for p in paths if path_exists(p)]
|
|
147
|
+
if not existing_paths:
|
|
148
|
+
return True
|
|
149
|
+
table = Table()
|
|
150
|
+
table.add_column("Name")
|
|
151
|
+
table.add_column("Size", justify="right")
|
|
152
|
+
table.add_column("Date Changed")
|
|
153
|
+
|
|
154
|
+
def file_or_folder_size_mb(path: Path) -> float:
|
|
155
|
+
"""Get size of file or all files in folder summed in MB"""
|
|
156
|
+
|
|
157
|
+
def file_size_mb(file: Path) -> float:
|
|
158
|
+
"""Get size of file in MB"""
|
|
159
|
+
return file.stat().st_size / (1024 * 1024)
|
|
160
|
+
|
|
161
|
+
if path.is_file():
|
|
162
|
+
return file_size_mb(path)
|
|
163
|
+
else:
|
|
164
|
+
return sum([file_size_mb(f) for f in path.rglob("*")])
|
|
165
|
+
|
|
166
|
+
for p in existing_paths:
|
|
167
|
+
timestamp = datetime.datetime.fromtimestamp(p.stat().st_mtime)
|
|
168
|
+
path_size = round(file_or_folder_size_mb(p), 2)
|
|
169
|
+
table.add_row(p.name, f"{path_size}mb", timestamp.strftime("%Y-%m-%d: %H:%M:%S"))
|
|
170
|
+
LOGGER.warning("Found Existing Odoo Files:")
|
|
171
|
+
Console().print(table)
|
|
172
|
+
override = Confirm.ask("override?")
|
|
173
|
+
if override:
|
|
174
|
+
return True
|
|
175
|
+
LOGGER.info("Aborting")
|
|
176
|
+
return False
|
godoo_cli/version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.0"
|