Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions odev/commands/git/clone.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,17 @@ def _clone_repository(self):
"""Find and clone the correct repository."""
git = GitConnector(self.args.repository or self._database.repository.full_name)

if git.path.exists():
logger.info(f"Repository {git.name!r} already cloned under {git.path.as_posix()}")
git.checkout(revision=self.args.branch or None)
else:
git.clone(revision=self.args.branch or None)

if not git.path.exists():
raise self.error(f"Failed to clone repository {git.name!r}")
try:
if git.path.exists():
logger.info(f"Repository {git.name!r} already cloned under {git.path.as_posix()}")
git.checkout(revision=self.args.branch or None)
else:
git.clone(revision=self.args.branch or None)

if not git.path.exists():
raise self.error(f"Failed to clone repository {git.name!r}")
except Exception as e:
raise self.error(f"An error occurred while cloning the repository: {e}")

def __check_repository(self):
"""Check if a repository is available to clone."""
Expand Down
4 changes: 1 addition & 3 deletions odev/common/connectors/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,11 +505,9 @@ def clone(self, revision: str | None = None):
multi_options=self._get_clone_options(revision),
)
except GitCommandError as error:
message: str = f"Failed to clone repository {self.name!r} to {self.path}"

message: str = f"Failed to clone repository {self.name!r} to {self.path}\n{str(error)}"
if error.stderr:
message += f": {error.stderr}"

raise ConnectorError(message, self) from error
else:
logger.info(
Expand Down
40 changes: 32 additions & 8 deletions odev/common/databases/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def version(self) -> OdooVersion | None: # type: ignore [override]
if version is not None:
return OdooVersion(version)

return OdooVersion("master")
return None

@cached_property
def edition(self) -> Literal["community", "enterprise"] | None: # type: ignore [override]
Expand Down Expand Up @@ -724,6 +724,7 @@ def _restore_buffered_sql(
if mode == "sql":
self._buffered_sql_check_restrict(dump)
self._buffered_sql_enable_extensions(dump)
self.ensure_roles()
elif mode == "dump":
self.unaccent()

Expand Down Expand Up @@ -927,14 +928,40 @@ def _buffered_sql_enable_extensions(self, dump: gzip.GzipFile | bz2.BZ2File | IO

:param dump: The dump file to restore SQL data from.
"""
immutable_defined = False
for index, line in enumerate(dump):
if index >= SQL_DUMP_IGNORE_LINES_NUMBER or "LANGUAGE sql IMMUTABLE" in line.decode():
if index >= SQL_DUMP_IGNORE_LINES_NUMBER:
break
else:
if "LANGUAGE sql IMMUTABLE" in line.decode(errors="ignore"):
immutable_defined = True
break

if not immutable_defined:
self.unaccent()

dump.seek(0)

@ensure_connected
def ensure_roles(self) -> bool:
"""Create database roles commonly referenced by Odoo SQL dumps.

Plain SQL dumps often contain ``GRANT ... TO odoo`` statements. When restoring in fast mode
(``--single-transaction`` with ``ON_ERROR_STOP=1``), a missing ``odoo`` role raises
``role "odoo" does not exist`` and rolls back the whole restore. Creating the role beforehand
keeps those statements valid without falling back to the slower degraded mode.
"""
return self.query(
"""
DO $$
BEGIN
CREATE ROLE odoo;
EXCEPTION
WHEN duplicate_object
THEN null;
END; $$
"""
)

@ensure_connected
def unaccent(self) -> bool:
"""Install the unaccent extension on the database."""
Expand Down Expand Up @@ -982,15 +1009,12 @@ def pg_vector(self) -> bool:

try:
self.query(pg_vector_query)
except RuntimeError:
except RuntimeError as re:
link = string.link(
"pgextwlist",
"https://github.com/dimitri/pgextwlist?tab=readme-ov-file#postgresql-extension-whitelist",
)
logger.error(
"Failed to install 'pgvector' extension, please ensure it is installed on your system "
f"and whitelisted with {link}"
)
logger.error(re.args[0])
return False

return True
Expand Down
2 changes: 1 addition & 1 deletion odev/common/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,6 @@ def _cmpkey(master: bool, major: int, minor: int, module: tuple, enterprise: boo
_saas = int(saas)

# Master versions should sort before non-master versions
_master = int(master)
_master = -int(master)

return _master, major, minor, _module, enterprise, _saas