odoo-dev 0.1.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.
- odoo_dev/__init__.py +3 -0
- odoo_dev/cli.py +36 -0
- odoo_dev/commands/__init__.py +1 -0
- odoo_dev/commands/db.py +332 -0
- odoo_dev/commands/docker.py +196 -0
- odoo_dev/commands/run.py +432 -0
- odoo_dev/commands/setup.py +364 -0
- odoo_dev/config.py +101 -0
- odoo_dev/utils/__init__.py +1 -0
- odoo_dev/utils/console.py +25 -0
- odoo_dev-0.1.0.dist-info/METADATA +133 -0
- odoo_dev-0.1.0.dist-info/RECORD +14 -0
- odoo_dev-0.1.0.dist-info/WHEEL +4 -0
- odoo_dev-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
"""Setup commands for initializing Odoo development environment."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from odoo_dev.config import load_config
|
|
10
|
+
from odoo_dev.utils.console import error, success, warning
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def setup(
|
|
14
|
+
community: bool = typer.Option(
|
|
15
|
+
False, "--community", help="Set up Community edition only (skip Enterprise repos)"
|
|
16
|
+
),
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Complete setup: clone Odoo repos, configure VSCode, build image."""
|
|
19
|
+
cfg = load_config()
|
|
20
|
+
|
|
21
|
+
success("Setting up complete Odoo development environment...")
|
|
22
|
+
|
|
23
|
+
# Initialize/update git submodules first
|
|
24
|
+
_init_submodules(cfg)
|
|
25
|
+
|
|
26
|
+
# Clone/update Odoo repositories
|
|
27
|
+
if community:
|
|
28
|
+
warning("Setting up Community Edition")
|
|
29
|
+
_clone_odoo_repos(cfg, community_only=community)
|
|
30
|
+
|
|
31
|
+
# Set up VSCode configuration
|
|
32
|
+
success("\nSetting up VSCode configuration...")
|
|
33
|
+
vscode(cfg)
|
|
34
|
+
|
|
35
|
+
# Set up local virtual environment
|
|
36
|
+
success("\nSetting up local Python virtual environment...")
|
|
37
|
+
warning(f"This will install system dependencies and Python {cfg.python_version} if needed")
|
|
38
|
+
setup_venv()
|
|
39
|
+
|
|
40
|
+
# Prompt for Docker setup
|
|
41
|
+
warning("\nDo you want to set up the Docker environment?")
|
|
42
|
+
if typer.confirm("Continue with Docker setup?", default=True):
|
|
43
|
+
success("\nBuilding Docker image...")
|
|
44
|
+
from odoo_dev.commands.docker import build
|
|
45
|
+
build(community=community)
|
|
46
|
+
else:
|
|
47
|
+
warning("Skipping Docker setup. Run 'odoo-dev build' later.")
|
|
48
|
+
|
|
49
|
+
success("\nSetup complete! You can now:")
|
|
50
|
+
success(" - Start Odoo with Docker: odoo-dev start")
|
|
51
|
+
success(" - Use local Python environment: source .venv/bin/activate")
|
|
52
|
+
success(" - Debug with VSCode: Use the configured launch profiles")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def setup_venv() -> None:
|
|
56
|
+
"""Set up local Python virtual environment for development."""
|
|
57
|
+
cfg = load_config()
|
|
58
|
+
|
|
59
|
+
# Create config file first
|
|
60
|
+
_setup_odoo_config(cfg)
|
|
61
|
+
|
|
62
|
+
success(f"Setting up Python virtual environment for Odoo {cfg.odoo_version}...")
|
|
63
|
+
|
|
64
|
+
# Install system dependencies
|
|
65
|
+
_install_system_dependencies()
|
|
66
|
+
|
|
67
|
+
# Ensure uv is available
|
|
68
|
+
if subprocess.run(["which", "uv"], capture_output=True).returncode != 0:
|
|
69
|
+
success("Installing uv package manager...")
|
|
70
|
+
subprocess.run(
|
|
71
|
+
["curl", "-LsSf", "https://astral.sh/uv/install.sh"],
|
|
72
|
+
stdout=subprocess.PIPE,
|
|
73
|
+
)
|
|
74
|
+
# Would pipe to sh, but let's be explicit
|
|
75
|
+
warning("Please install uv manually: curl -LsSf https://astral.sh/uv/install.sh | sh")
|
|
76
|
+
|
|
77
|
+
# Create virtual environment
|
|
78
|
+
if not cfg.venv_path.exists():
|
|
79
|
+
success("Creating new Python virtual environment...")
|
|
80
|
+
subprocess.run(
|
|
81
|
+
["uv", "venv", str(cfg.venv_path), "--python", cfg.python_version],
|
|
82
|
+
check=True,
|
|
83
|
+
)
|
|
84
|
+
else:
|
|
85
|
+
warning("Virtual environment already exists. Skipping creation.")
|
|
86
|
+
|
|
87
|
+
# Update PYTHONPATH in activate script
|
|
88
|
+
_update_python_path(cfg)
|
|
89
|
+
|
|
90
|
+
# Install requirements
|
|
91
|
+
venv_pip = ["uv", "pip", "install", "--python", str(cfg.venv_path / "bin" / "python")]
|
|
92
|
+
|
|
93
|
+
# Install Odoo requirements
|
|
94
|
+
odoo_requirements = cfg.project_dir / "odoo" / "requirements.txt"
|
|
95
|
+
if odoo_requirements.exists():
|
|
96
|
+
success("Installing Odoo requirements...")
|
|
97
|
+
# Create temp requirements with psycopg2-binary substitution
|
|
98
|
+
temp_req = cfg.project_dir / "temp_requirements.txt"
|
|
99
|
+
content = odoo_requirements.read_text()
|
|
100
|
+
content = content.replace("psycopg2==", "psycopg2-binary>=")
|
|
101
|
+
temp_req.write_text(content)
|
|
102
|
+
subprocess.run([*venv_pip, "-r", str(temp_req)])
|
|
103
|
+
temp_req.unlink()
|
|
104
|
+
|
|
105
|
+
# Install project requirements
|
|
106
|
+
project_requirements = cfg.project_dir / "requirements.txt"
|
|
107
|
+
if project_requirements.exists():
|
|
108
|
+
success("Installing project requirements...")
|
|
109
|
+
subprocess.run([*venv_pip, "-r", str(project_requirements)])
|
|
110
|
+
|
|
111
|
+
# Install dev tools
|
|
112
|
+
success("Installing development tools...")
|
|
113
|
+
subprocess.run([*venv_pip, "pytest", "pytest-odoo", "debugpy", "manifestoo", "coverage"])
|
|
114
|
+
|
|
115
|
+
success("\nVirtual environment setup complete!")
|
|
116
|
+
success(f"To activate: source {cfg.venv_path}/bin/activate")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def vscode(cfg=None) -> None:
|
|
120
|
+
"""Set up VSCode configuration for debugging."""
|
|
121
|
+
if cfg is None:
|
|
122
|
+
cfg = load_config()
|
|
123
|
+
|
|
124
|
+
vscode_dir = cfg.project_dir / ".vscode"
|
|
125
|
+
vscode_dir.mkdir(exist_ok=True)
|
|
126
|
+
|
|
127
|
+
template_dir = cfg.script_dir / "templates" / "vscode"
|
|
128
|
+
|
|
129
|
+
# Copy template files
|
|
130
|
+
import shutil
|
|
131
|
+
|
|
132
|
+
for template_file in ["launch.json", "tasks.json"]:
|
|
133
|
+
src = template_dir / template_file
|
|
134
|
+
dst = vscode_dir / template_file
|
|
135
|
+
if src.exists():
|
|
136
|
+
shutil.copy(src, dst)
|
|
137
|
+
success(f"Copied {template_file}")
|
|
138
|
+
|
|
139
|
+
# Only copy settings.json if it doesn't exist
|
|
140
|
+
settings_src = template_dir / "settings.json"
|
|
141
|
+
settings_dst = vscode_dir / "settings.json"
|
|
142
|
+
if settings_src.exists() and not settings_dst.exists():
|
|
143
|
+
shutil.copy(settings_src, settings_dst)
|
|
144
|
+
success("Copied settings.json")
|
|
145
|
+
elif settings_dst.exists():
|
|
146
|
+
warning("settings.json already exists. Skipping.")
|
|
147
|
+
|
|
148
|
+
success("VSCode configuration set up successfully!")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _init_submodules(cfg) -> None:
|
|
152
|
+
"""Initialize and update git submodules if present."""
|
|
153
|
+
gitmodules = cfg.project_dir / ".gitmodules"
|
|
154
|
+
|
|
155
|
+
if not gitmodules.exists():
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
success("Initializing git submodules...")
|
|
159
|
+
|
|
160
|
+
result = subprocess.run(
|
|
161
|
+
["git", "submodule", "update", "--init", "--recursive"],
|
|
162
|
+
cwd=cfg.project_dir,
|
|
163
|
+
capture_output=True,
|
|
164
|
+
text=True,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if result.returncode == 0:
|
|
168
|
+
success("Git submodules initialized.")
|
|
169
|
+
else:
|
|
170
|
+
warning(f"Submodule initialization had issues: {result.stderr}")
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _setup_odoo_config(cfg, community_only: bool = False) -> None:
|
|
174
|
+
"""Create odoo.conf configuration file."""
|
|
175
|
+
conf_dir = cfg.project_dir / "conf"
|
|
176
|
+
conf_file = conf_dir / "odoo.conf"
|
|
177
|
+
|
|
178
|
+
# Create conf directory
|
|
179
|
+
conf_dir.mkdir(exist_ok=True)
|
|
180
|
+
|
|
181
|
+
if conf_file.exists():
|
|
182
|
+
warning(f"Config file already exists at {conf_file}")
|
|
183
|
+
return
|
|
184
|
+
|
|
185
|
+
success("Creating Odoo configuration file...")
|
|
186
|
+
|
|
187
|
+
# Build addons path
|
|
188
|
+
addons_paths = [
|
|
189
|
+
str(cfg.project_dir / "odoo" / "addons"),
|
|
190
|
+
str(cfg.project_dir / "odoo" / "odoo" / "addons"),
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
if not community_only:
|
|
194
|
+
addons_paths.append(str(cfg.project_dir / "enterprise"))
|
|
195
|
+
|
|
196
|
+
addons_paths.extend([
|
|
197
|
+
str(cfg.project_dir / "design-themes"),
|
|
198
|
+
str(cfg.project_dir / "addons"),
|
|
199
|
+
])
|
|
200
|
+
|
|
201
|
+
# Filter to only existing paths
|
|
202
|
+
addons_paths = [p for p in addons_paths if Path(p).exists()]
|
|
203
|
+
|
|
204
|
+
config_content = f"""[options]
|
|
205
|
+
addons_path = {",".join(addons_paths)}
|
|
206
|
+
admin_passwd = admin
|
|
207
|
+
db_user = odoo
|
|
208
|
+
db_password = odoo
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
conf_file.write_text(config_content)
|
|
212
|
+
conf_file.chmod(0o600)
|
|
213
|
+
success(f"Config file created at {conf_file}")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _clone_odoo_repos(cfg, community_only: bool = False) -> None:
|
|
217
|
+
"""Clone or update Odoo repositories."""
|
|
218
|
+
success("Setting up Odoo repositories...")
|
|
219
|
+
|
|
220
|
+
if community_only:
|
|
221
|
+
warning("Community edition mode: Enterprise repositories will be skipped")
|
|
222
|
+
|
|
223
|
+
repos = [
|
|
224
|
+
(f"git@github.com:odoo/odoo.git", "odoo", cfg.odoo_version),
|
|
225
|
+
(f"git@github.com:odoo/design-themes.git", "design-themes", cfg.odoo_version),
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
# Add enterprise if not community only
|
|
229
|
+
if not community_only:
|
|
230
|
+
repos.append(
|
|
231
|
+
(f"git@github.com:odoo/enterprise.git", "enterprise", cfg.odoo_version)
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# Add industry for Odoo 18+
|
|
235
|
+
if cfg.odoo_version.startswith("18") or cfg.odoo_version.startswith("19"):
|
|
236
|
+
repos.append(
|
|
237
|
+
(f"git@github.com:odoo/industry.git", "industry", cfg.odoo_version)
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
for repo_url, repo_dir, branch in repos:
|
|
241
|
+
repo_path = cfg.project_dir / repo_dir
|
|
242
|
+
|
|
243
|
+
if repo_path.exists():
|
|
244
|
+
warning(f"Updating {repo_dir} repository...")
|
|
245
|
+
subprocess.run(
|
|
246
|
+
["git", "fetch", "--depth", "1", "origin", branch],
|
|
247
|
+
cwd=repo_path,
|
|
248
|
+
)
|
|
249
|
+
subprocess.run(["git", "checkout", branch], cwd=repo_path)
|
|
250
|
+
subprocess.run(
|
|
251
|
+
["git", "pull", "--ff-only", "origin", branch],
|
|
252
|
+
cwd=repo_path,
|
|
253
|
+
)
|
|
254
|
+
else:
|
|
255
|
+
warning(f"Cloning {repo_dir} repository...")
|
|
256
|
+
subprocess.run(
|
|
257
|
+
[
|
|
258
|
+
"git",
|
|
259
|
+
"clone",
|
|
260
|
+
"--depth",
|
|
261
|
+
"1",
|
|
262
|
+
"--branch",
|
|
263
|
+
branch,
|
|
264
|
+
repo_url,
|
|
265
|
+
str(repo_path),
|
|
266
|
+
],
|
|
267
|
+
cwd=cfg.project_dir,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
success("Odoo repositories setup complete.")
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _install_system_dependencies() -> None:
|
|
274
|
+
"""Install system dependencies based on OS."""
|
|
275
|
+
import platform
|
|
276
|
+
|
|
277
|
+
system = platform.system()
|
|
278
|
+
|
|
279
|
+
if system == "Darwin":
|
|
280
|
+
success("Installing dependencies for macOS...")
|
|
281
|
+
subprocess.run(
|
|
282
|
+
[
|
|
283
|
+
"brew",
|
|
284
|
+
"install",
|
|
285
|
+
"postgresql",
|
|
286
|
+
"libpq",
|
|
287
|
+
"openssl",
|
|
288
|
+
"libxml2",
|
|
289
|
+
"libxslt",
|
|
290
|
+
],
|
|
291
|
+
check=False,
|
|
292
|
+
)
|
|
293
|
+
elif system == "Linux":
|
|
294
|
+
success("Installing dependencies for Linux...")
|
|
295
|
+
subprocess.run(
|
|
296
|
+
[
|
|
297
|
+
"sudo",
|
|
298
|
+
"apt-get",
|
|
299
|
+
"update",
|
|
300
|
+
],
|
|
301
|
+
check=False,
|
|
302
|
+
)
|
|
303
|
+
subprocess.run(
|
|
304
|
+
[
|
|
305
|
+
"sudo",
|
|
306
|
+
"apt-get",
|
|
307
|
+
"install",
|
|
308
|
+
"-y",
|
|
309
|
+
"--no-install-recommends",
|
|
310
|
+
"build-essential",
|
|
311
|
+
"libldap2-dev",
|
|
312
|
+
"libpq-dev",
|
|
313
|
+
"libsasl2-dev",
|
|
314
|
+
"libssl-dev",
|
|
315
|
+
"libxml2-dev",
|
|
316
|
+
"libxslt1-dev",
|
|
317
|
+
"postgresql-client",
|
|
318
|
+
],
|
|
319
|
+
check=False,
|
|
320
|
+
)
|
|
321
|
+
else:
|
|
322
|
+
warning(f"Unsupported OS: {system}. Please install dependencies manually.")
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def _update_python_path(cfg) -> None:
|
|
326
|
+
"""Update PYTHONPATH in venv activate script."""
|
|
327
|
+
activate_script = cfg.venv_path / "bin" / "activate"
|
|
328
|
+
|
|
329
|
+
if not activate_script.exists():
|
|
330
|
+
return
|
|
331
|
+
|
|
332
|
+
content = activate_script.read_text()
|
|
333
|
+
|
|
334
|
+
# Check if already modified
|
|
335
|
+
if "# Odoo PYTHONPATH setup" in content:
|
|
336
|
+
return
|
|
337
|
+
|
|
338
|
+
pythonpath_setup = '''
|
|
339
|
+
# Odoo PYTHONPATH setup
|
|
340
|
+
if [ -z "$_OLD_VIRTUAL_PYTHONPATH" ]; then
|
|
341
|
+
_OLD_VIRTUAL_PYTHONPATH="$PYTHONPATH"
|
|
342
|
+
fi
|
|
343
|
+
|
|
344
|
+
ODOO_PYTHONPATH=""
|
|
345
|
+
for dir in "odoo" "enterprise" "design-themes" "industry" "addons"; do
|
|
346
|
+
if [ -d "$VIRTUAL_ENV/../$dir" ]; then
|
|
347
|
+
if [ -z "$ODOO_PYTHONPATH" ]; then
|
|
348
|
+
ODOO_PYTHONPATH="$VIRTUAL_ENV/../$dir"
|
|
349
|
+
else
|
|
350
|
+
ODOO_PYTHONPATH="$ODOO_PYTHONPATH:$VIRTUAL_ENV/../$dir"
|
|
351
|
+
fi
|
|
352
|
+
fi
|
|
353
|
+
done
|
|
354
|
+
|
|
355
|
+
if [ -n "$ODOO_PYTHONPATH" ]; then
|
|
356
|
+
PYTHONPATH="$ODOO_PYTHONPATH${_OLD_VIRTUAL_PYTHONPATH:+:$_OLD_VIRTUAL_PYTHONPATH}"
|
|
357
|
+
export PYTHONPATH
|
|
358
|
+
fi
|
|
359
|
+
# End Odoo PYTHONPATH setup
|
|
360
|
+
'''
|
|
361
|
+
|
|
362
|
+
content += pythonpath_setup
|
|
363
|
+
activate_script.write_text(content)
|
|
364
|
+
success("PYTHONPATH updated in virtual environment activation script.")
|
odoo_dev/config.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Configuration loading and project detection."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class ProjectConfig:
|
|
10
|
+
"""Configuration for an Odoo development project."""
|
|
11
|
+
|
|
12
|
+
project_dir: Path
|
|
13
|
+
script_dir: Path
|
|
14
|
+
odoo_version: str
|
|
15
|
+
python_version: str
|
|
16
|
+
project_name: str
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def venv_path(self) -> Path:
|
|
20
|
+
"""Path to the Python virtual environment."""
|
|
21
|
+
return self.project_dir / ".venv"
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def config_file(self) -> Path:
|
|
25
|
+
"""Path to the local odoo.conf file."""
|
|
26
|
+
return self.project_dir / "conf" / "odoo.conf"
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def docker_config_file(self) -> Path:
|
|
30
|
+
"""Path to the Docker odoo.conf file."""
|
|
31
|
+
return self.script_dir / "odoo.conf"
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def odoo_bin(self) -> Path:
|
|
35
|
+
"""Path to the odoo-bin executable."""
|
|
36
|
+
return self.project_dir / "odoo" / "odoo-bin"
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def addons_dir(self) -> Path:
|
|
40
|
+
"""Path to the project's custom addons directory."""
|
|
41
|
+
return self.project_dir / "addons"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def find_project_root(start: Path | None = None) -> Path:
|
|
45
|
+
"""Walk up directory tree to find git repository root.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
start: Starting directory. Defaults to current working directory.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Path to the git repository root, or current directory if not found.
|
|
52
|
+
"""
|
|
53
|
+
current = start or Path.cwd()
|
|
54
|
+
while current != current.parent:
|
|
55
|
+
git_path = current / ".git"
|
|
56
|
+
# .git can be a directory (normal repo) or a file (submodule/worktree)
|
|
57
|
+
if git_path.is_dir() or git_path.is_file():
|
|
58
|
+
return current
|
|
59
|
+
current = current.parent
|
|
60
|
+
return Path.cwd()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def load_dotenv(path: Path) -> None:
|
|
64
|
+
"""Load environment variables from a .env file.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
path: Path to the .env file.
|
|
68
|
+
"""
|
|
69
|
+
if not path.exists():
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
for line in path.read_text().splitlines():
|
|
73
|
+
line = line.strip()
|
|
74
|
+
if line and not line.startswith("#") and "=" in line:
|
|
75
|
+
key, _, value = line.partition("=")
|
|
76
|
+
# Don't override existing environment variables
|
|
77
|
+
os.environ.setdefault(key.strip(), value.strip())
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def load_config(project_dir: Path | None = None) -> ProjectConfig:
|
|
81
|
+
"""Load configuration from environment and .env file.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
project_dir: Optional project directory override.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
ProjectConfig with all settings loaded.
|
|
88
|
+
"""
|
|
89
|
+
if project_dir is None:
|
|
90
|
+
project_dir = find_project_root()
|
|
91
|
+
|
|
92
|
+
# Load .env if it exists
|
|
93
|
+
load_dotenv(project_dir / ".env")
|
|
94
|
+
|
|
95
|
+
return ProjectConfig(
|
|
96
|
+
project_dir=project_dir,
|
|
97
|
+
script_dir=project_dir / ".odoo-deploy",
|
|
98
|
+
odoo_version=os.getenv("ODOO_VERSION", "18.0"),
|
|
99
|
+
python_version=os.getenv("PYTHON_VERSION", "3.12"),
|
|
100
|
+
project_name=project_dir.name,
|
|
101
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Utility modules for odoo-dev."""
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Console output helpers with colored formatting."""
|
|
2
|
+
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
|
|
5
|
+
console = Console()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def success(msg: str) -> None:
|
|
9
|
+
"""Print a success message in green."""
|
|
10
|
+
console.print(f"[green]{msg}[/green]")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def warning(msg: str) -> None:
|
|
14
|
+
"""Print a warning message in yellow."""
|
|
15
|
+
console.print(f"[yellow]{msg}[/yellow]")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def error(msg: str) -> None:
|
|
19
|
+
"""Print an error message in red."""
|
|
20
|
+
console.print(f"[red]{msg}[/red]")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def info(msg: str) -> None:
|
|
24
|
+
"""Print an info message."""
|
|
25
|
+
console.print(msg)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: odoo-dev
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Odoo Development Environment Helper
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: rich>=13.0.0
|
|
7
|
+
Requires-Dist: typer>=0.9.0
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
|
|
10
|
+
# odoo-dev
|
|
11
|
+
|
|
12
|
+
A CLI tool for managing Odoo development environments. Handles local Python setup, Docker containers, database operations, and more.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Install with uv (recommended)
|
|
18
|
+
uv tool install odoo-dev
|
|
19
|
+
|
|
20
|
+
# Or with pip
|
|
21
|
+
pip install odoo-dev
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# In your Odoo project directory
|
|
28
|
+
cd my-odoo-project
|
|
29
|
+
|
|
30
|
+
# Full setup: clone Odoo repos, create venv, configure VSCode
|
|
31
|
+
odoo-dev setup
|
|
32
|
+
|
|
33
|
+
# Or for community edition only
|
|
34
|
+
odoo-dev setup --community
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Commands
|
|
38
|
+
|
|
39
|
+
### Local Development (default)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
odoo-dev run # Start Odoo locally
|
|
43
|
+
odoo-dev run -d mydb --dev reload # With hot reload
|
|
44
|
+
odoo-dev run --debug # With debugpy (VSCode attach)
|
|
45
|
+
odoo-dev shell mydb # Open Odoo shell
|
|
46
|
+
odoo-dev update base -d mydb # Update modules
|
|
47
|
+
odoo-dev test my_module # Run tests with coverage
|
|
48
|
+
odoo-dev scaffold my_module # Create new module
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Database Operations
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
odoo-dev db list # List databases
|
|
55
|
+
odoo-dev db restore backup.zip # Restore from backup
|
|
56
|
+
odoo-dev db restore backup.zip mydb --no-neutralize
|
|
57
|
+
odoo-dev db drop mydb # Drop database
|
|
58
|
+
odoo-dev db neutralize mydb # Disable emails/crons
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Docker (optional)
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
odoo-dev docker start # Start containers
|
|
65
|
+
odoo-dev docker stop # Stop containers
|
|
66
|
+
odoo-dev docker logs # View logs
|
|
67
|
+
odoo-dev docker build # Rebuild image
|
|
68
|
+
odoo-dev docker shell mydb # Shell in container
|
|
69
|
+
odoo-dev docker psql # PostgreSQL shell
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Setup Commands
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
odoo-dev setup # Full setup
|
|
76
|
+
odoo-dev setup --community # Community edition only
|
|
77
|
+
odoo-dev setup-venv # Just create venv
|
|
78
|
+
odoo-dev vscode # Configure VSCode debugging
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Project Structure
|
|
82
|
+
|
|
83
|
+
odoo-dev expects this project structure:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
my-odoo-project/
|
|
87
|
+
├── .env # Optional: ODOO_VERSION, PYTHON_VERSION
|
|
88
|
+
├── addons/ # Your custom addons
|
|
89
|
+
├── requirements.txt # Project-specific Python deps
|
|
90
|
+
├── odoo/ # Cloned by setup
|
|
91
|
+
├── enterprise/ # Cloned by setup (unless --community)
|
|
92
|
+
├── design-themes/ # Cloned by setup
|
|
93
|
+
├── .venv/ # Created by setup
|
|
94
|
+
└── conf/
|
|
95
|
+
└── odoo.conf # Created by setup
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Configuration
|
|
99
|
+
|
|
100
|
+
Create a `.env` file in your project root:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
ODOO_VERSION=18.0
|
|
104
|
+
PYTHON_VERSION=3.12
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Requirements
|
|
108
|
+
|
|
109
|
+
- Python 3.12+
|
|
110
|
+
- uv (recommended) or pip
|
|
111
|
+
- Git
|
|
112
|
+
- PostgreSQL (for local development)
|
|
113
|
+
- Docker (optional, for containerized development)
|
|
114
|
+
|
|
115
|
+
## Development
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Clone and install for development
|
|
119
|
+
git clone git@git.bemade.org:bemade/odoo-dev.git
|
|
120
|
+
cd odoo-dev
|
|
121
|
+
uv sync
|
|
122
|
+
|
|
123
|
+
# Run tests
|
|
124
|
+
uv run pytest # All tests
|
|
125
|
+
uv run pytest -m "not slow" # Fast tests only
|
|
126
|
+
|
|
127
|
+
# Build
|
|
128
|
+
uv build
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
odoo_dev/__init__.py,sha256=k91qzqyJaW_n2LwmsJoDER8z90x2wcVNODzKACLUxKc,66
|
|
2
|
+
odoo_dev/cli.py,sha256=SqY07yLgOGEUkrUvbBM9Sfon87nUUbM_wDk96n_pScg,714
|
|
3
|
+
odoo_dev/config.py,sha256=LbWsJbcvIfE5fbxkZK_iItaYDhiB0t8mF6wQk2d8hpM,2865
|
|
4
|
+
odoo_dev/commands/__init__.py,sha256=yOxitS1Oes2ZS95F0nXyw3LDOBXCFWmudZInYbTu1eQ,33
|
|
5
|
+
odoo_dev/commands/db.py,sha256=7DnI28y2YpugnjoMkyTYymLMZ5MjNagfD6T15RWvZ0c,9605
|
|
6
|
+
odoo_dev/commands/docker.py,sha256=I5dvxRX4uHzwBwTM7d7yhMphge8fdKoqjXCKo_-7FQw,5386
|
|
7
|
+
odoo_dev/commands/run.py,sha256=FPi_rIyMOWadZfMPin0TXHbdBcW1YIuqUseBEhr4PnE,11882
|
|
8
|
+
odoo_dev/commands/setup.py,sha256=M67rE1qWA2iYA3S15cZAt_-Za2iXWau1QAbt-nvOCQU,11260
|
|
9
|
+
odoo_dev/utils/__init__.py,sha256=EDPdElYZN3cPJtZIkNjXFoItz1mPBPUsasQzb6mRrss,36
|
|
10
|
+
odoo_dev/utils/console.py,sha256=bRbXVD15QiMhdU8Rp4cyaoA1-J8vFX8r16TwsYurUug,549
|
|
11
|
+
odoo_dev-0.1.0.dist-info/METADATA,sha256=stKenzdej2YmQ_ubYOG2vsHzZdAGT6zhQu9re0gHkQE,3155
|
|
12
|
+
odoo_dev-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
13
|
+
odoo_dev-0.1.0.dist-info/entry_points.txt,sha256=EKJCgGArQtoRNYRBRcbkRfIXO_APFkYujr2u8-UCfXo,46
|
|
14
|
+
odoo_dev-0.1.0.dist-info/RECORD,,
|