odoogci 0.2.2__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.
- odoogci-0.2.2/PKG-INFO +101 -0
- odoogci-0.2.2/README.md +81 -0
- odoogci-0.2.2/odoogci/__init__.py +0 -0
- odoogci-0.2.2/odoogci/main.py +189 -0
- odoogci-0.2.2/pyproject.toml +18 -0
odoogci-0.2.2/PKG-INFO
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: odoogci
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Utility to clone odoo modules repository with requirements installation
|
|
5
|
+
License: GNU/GPL V2
|
|
6
|
+
Author: Alitux
|
|
7
|
+
Author-email: alitux@disroot.org
|
|
8
|
+
Requires-Python: >=3.9,<4.0
|
|
9
|
+
Classifier: License :: Other/Proprietary License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Requires-Dist: typer (>=0.15.1,<0.16.0)
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# odoogci
|
|
21
|
+
|
|
22
|
+
A utility for cloning Git repositories, removing unnecessary files, and installing dependencies from `requirements.txt`. It is specifically designed to facilitate building Odoo Docker images.
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
Ensure you have the following tools installed on your system:
|
|
27
|
+
|
|
28
|
+
- Python ^3.9
|
|
29
|
+
- Git
|
|
30
|
+
- pip (Python package manager)
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
### Via pipx (Recommended for CLI)
|
|
35
|
+
```sh
|
|
36
|
+
pipx install odoogci
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Via pip
|
|
40
|
+
```sh
|
|
41
|
+
pip install odoogci
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### In a Dockerfile (From source)
|
|
45
|
+
Add the following line to your Dockerfile:
|
|
46
|
+
|
|
47
|
+
```Dockerfile
|
|
48
|
+
RUN pip3 install git+https://gitlab.com/alitux/odoogci.git
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
The general usage of the tool is:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
odoogci [URL] [OPTIONS]
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Arguments
|
|
60
|
+
|
|
61
|
+
* `URL`: URL of the repository to clone.
|
|
62
|
+
|
|
63
|
+
### Options
|
|
64
|
+
|
|
65
|
+
* `--branch TEXT`: Branch of the repository.
|
|
66
|
+
* `--repositories TEXT`: JSON string with a list of repositories to clone.
|
|
67
|
+
* `--requirements / --no-requirements`: Install dependencies from `requirements.txt`. [default: no-requirements]
|
|
68
|
+
* `--repopath TEXT`: Local path where the repository will be cloned.
|
|
69
|
+
* `--token TEXT`: Access token for the repository (supports GitHub and GitLab).
|
|
70
|
+
|
|
71
|
+
### Examples
|
|
72
|
+
|
|
73
|
+
#### Simple Clone
|
|
74
|
+
```sh
|
|
75
|
+
odoogci https://github.com/ingadhoc/odoo-argentina --branch 16.0
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Clone Multiple Repositories using JSON
|
|
79
|
+
```sh
|
|
80
|
+
odoogci --repositories '[
|
|
81
|
+
{
|
|
82
|
+
"url": "https://github.com/org/repo1",
|
|
83
|
+
"branch": "18.0",
|
|
84
|
+
"repo_path": "repo1"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"url": "https://github.com/OCA/commission",
|
|
88
|
+
"branch": "18.0",
|
|
89
|
+
"repo_path": "oca/commission"
|
|
90
|
+
}
|
|
91
|
+
]'
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### Usage in a Dockerfile
|
|
95
|
+
|
|
96
|
+
```Dockerfile
|
|
97
|
+
RUN cd /usr/lib/python3/dist-packages/odoo/addons/ && \
|
|
98
|
+
odoogci https://github.com/ingadhoc/odoo-argentina --branch 16.0 && \
|
|
99
|
+
odoogci https://github.com/ingadhoc/account-invoicing --branch 16.0
|
|
100
|
+
```
|
|
101
|
+
|
odoogci-0.2.2/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# odoogci
|
|
2
|
+
|
|
3
|
+
A utility for cloning Git repositories, removing unnecessary files, and installing dependencies from `requirements.txt`. It is specifically designed to facilitate building Odoo Docker images.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
Ensure you have the following tools installed on your system:
|
|
8
|
+
|
|
9
|
+
- Python ^3.9
|
|
10
|
+
- Git
|
|
11
|
+
- pip (Python package manager)
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
### Via pipx (Recommended for CLI)
|
|
16
|
+
```sh
|
|
17
|
+
pipx install odoogci
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Via pip
|
|
21
|
+
```sh
|
|
22
|
+
pip install odoogci
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### In a Dockerfile (From source)
|
|
26
|
+
Add the following line to your Dockerfile:
|
|
27
|
+
|
|
28
|
+
```Dockerfile
|
|
29
|
+
RUN pip3 install git+https://gitlab.com/alitux/odoogci.git
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
The general usage of the tool is:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
odoogci [URL] [OPTIONS]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Arguments
|
|
41
|
+
|
|
42
|
+
* `URL`: URL of the repository to clone.
|
|
43
|
+
|
|
44
|
+
### Options
|
|
45
|
+
|
|
46
|
+
* `--branch TEXT`: Branch of the repository.
|
|
47
|
+
* `--repositories TEXT`: JSON string with a list of repositories to clone.
|
|
48
|
+
* `--requirements / --no-requirements`: Install dependencies from `requirements.txt`. [default: no-requirements]
|
|
49
|
+
* `--repopath TEXT`: Local path where the repository will be cloned.
|
|
50
|
+
* `--token TEXT`: Access token for the repository (supports GitHub and GitLab).
|
|
51
|
+
|
|
52
|
+
### Examples
|
|
53
|
+
|
|
54
|
+
#### Simple Clone
|
|
55
|
+
```sh
|
|
56
|
+
odoogci https://github.com/ingadhoc/odoo-argentina --branch 16.0
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### Clone Multiple Repositories using JSON
|
|
60
|
+
```sh
|
|
61
|
+
odoogci --repositories '[
|
|
62
|
+
{
|
|
63
|
+
"url": "https://github.com/org/repo1",
|
|
64
|
+
"branch": "18.0",
|
|
65
|
+
"repo_path": "repo1"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"url": "https://github.com/OCA/commission",
|
|
69
|
+
"branch": "18.0",
|
|
70
|
+
"repo_path": "oca/commission"
|
|
71
|
+
}
|
|
72
|
+
]'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Usage in a Dockerfile
|
|
76
|
+
|
|
77
|
+
```Dockerfile
|
|
78
|
+
RUN cd /usr/lib/python3/dist-packages/odoo/addons/ && \
|
|
79
|
+
odoogci https://github.com/ingadhoc/odoo-argentina --branch 16.0 && \
|
|
80
|
+
odoogci https://github.com/ingadhoc/account-invoicing --branch 16.0
|
|
81
|
+
```
|
|
File without changes
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# import uuid
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
import typer
|
|
7
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from typing import Optional
|
|
10
|
+
from typing_extensions import Annotated
|
|
11
|
+
|
|
12
|
+
app = typer.Typer()
|
|
13
|
+
err_console = Console(stderr=True)
|
|
14
|
+
ABS_PATH = os.path.join(os.path.dirname(__file__))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def install_req(repo_path: str, archive: str = "requirements.txt"):
|
|
18
|
+
"""Install dependencies from requirements.txt"""
|
|
19
|
+
archive_abs_path = f"{repo_path}/{archive}"
|
|
20
|
+
if os.path.exists(archive_abs_path):
|
|
21
|
+
print("Instalando dependencias ", end=" ")
|
|
22
|
+
try:
|
|
23
|
+
command = f"pip install -r {archive_abs_path}"
|
|
24
|
+
subprocess.run(command, shell=True, check=True)
|
|
25
|
+
print("[OK]")
|
|
26
|
+
except:
|
|
27
|
+
print("[ERROR]")
|
|
28
|
+
else:
|
|
29
|
+
print("No hay archivo de dependencias[OK]")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def remove_garbage(repo_path: str):
|
|
33
|
+
"""Remove unnecessary files"""
|
|
34
|
+
print("Removiendo archivos innecesarios ", end=" ")
|
|
35
|
+
items = os.listdir(f"{repo_path}/")
|
|
36
|
+
try:
|
|
37
|
+
for item in items:
|
|
38
|
+
if os.path.isfile(f"{repo_path}/{item}"):
|
|
39
|
+
command = f"rm -rf {repo_path}/{item}"
|
|
40
|
+
subprocess.run(command, shell=True, check=True)
|
|
41
|
+
subprocess.run(f"rm -rf {repo_path}/.git", shell=True, check=True)
|
|
42
|
+
subprocess.run(f"rm -rf {repo_path}/setup", shell=True, check=True)
|
|
43
|
+
print("[OK]")
|
|
44
|
+
except:
|
|
45
|
+
print("[ERROR]")
|
|
46
|
+
sys.exit(1)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def move_folders(repo_path: str):
|
|
50
|
+
"""Move folders to current directory"""
|
|
51
|
+
print("Moviendo repositorio a carpeta actual ", end=" ")
|
|
52
|
+
try:
|
|
53
|
+
subprocess.run(f"mv {repo_path}/* .", shell=True, check=True)
|
|
54
|
+
subprocess.run(f"rm -rf {repo_path}", shell=True, check=True)
|
|
55
|
+
print("[OK]")
|
|
56
|
+
except:
|
|
57
|
+
print("[ERROR]")
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
|
|
60
|
+
def git_clone_update(url: str, branch: str, token: str = None, repo_path: str = None):
|
|
61
|
+
"""Clona o actualiza un repositorio Git.
|
|
62
|
+
Si en local hay cambios directamente hace un hard reset y vuelve a pullear
|
|
63
|
+
"""
|
|
64
|
+
url_old = url
|
|
65
|
+
|
|
66
|
+
if not repo_path:
|
|
67
|
+
if ".git" in url:
|
|
68
|
+
repo_path = url.split(".git")[0].split("/")[-1]
|
|
69
|
+
if not ".git" in url:
|
|
70
|
+
repo_path = url.split("/")[-1]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
if token:
|
|
74
|
+
if "github.com" in url:
|
|
75
|
+
url = url.replace("github.com", f"{token}@github.com") + ".git"
|
|
76
|
+
elif "gitlab.com" in url:
|
|
77
|
+
url = url.replace("gitlab.com", f"oauth2:{token}@gitlab.com")+".git"
|
|
78
|
+
if os.path.exists(repo_path) and os.path.exists(f"{repo_path}/.git"):
|
|
79
|
+
message = f"[cyan] Actualizando {repo_path}... [/cyan]"
|
|
80
|
+
command = ["git", "-C", repo_path, "pull"]
|
|
81
|
+
## Se hace un reset para obviar cambios locales
|
|
82
|
+
subprocess.run(["git", "-C", repo_path, "reset", "--hard"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
83
|
+
else:
|
|
84
|
+
message = f"[cyan] Clonando {url_old} ({branch})... [/cyan]"
|
|
85
|
+
command = ["git", "clone", "--recurse-submodules", url, "-b", branch, repo_path]
|
|
86
|
+
|
|
87
|
+
with Progress(SpinnerColumn(), TextColumn("{task.description}")) as progress:
|
|
88
|
+
task = progress.add_task(description=message, total=None)
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
|
92
|
+
stdout, stderr = process.communicate()
|
|
93
|
+
|
|
94
|
+
if process.returncode == 0:
|
|
95
|
+
progress.update(task, description=f"[green]{message} ✔[/green]", completed=1)
|
|
96
|
+
else:
|
|
97
|
+
progress.update(task, description=f"[red]Error en {repo_path} ✖[/red]", completed=1)
|
|
98
|
+
print(f"\n[red]Salida de Git:[/red]\n{stderr.strip()}")
|
|
99
|
+
sys.exit(1)
|
|
100
|
+
|
|
101
|
+
except Exception as e:
|
|
102
|
+
progress.update(task, description=f"[red]Error en {repo_path} ✖[/red]", completed=1)
|
|
103
|
+
print(f"\n[red]Error inesperado:[/red] {e}")
|
|
104
|
+
sys.exit(1)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def git_update_all():
|
|
108
|
+
"""Update all repositories in the current directory"""
|
|
109
|
+
with Progress(SpinnerColumn(), TextColumn("{task.description}")) as progress:
|
|
110
|
+
for carpeta in os.listdir():
|
|
111
|
+
ruta_completa = os.path.join(os.getcwd(), carpeta)
|
|
112
|
+
if os.path.isdir(ruta_completa) and os.path.isdir(os.path.join(ruta_completa, ".git")):
|
|
113
|
+
try:
|
|
114
|
+
message = f"[cyan] Actualizando {carpeta}... [/cyan]"
|
|
115
|
+
task = progress.add_task(description=message, total=None)
|
|
116
|
+
subprocess.run(["git", "-C", ruta_completa, "pull"], check=True)
|
|
117
|
+
progress.update(task, description=f"[green]{message} ✔[/green]", completed=1)
|
|
118
|
+
except subprocess.CalledProcessError:
|
|
119
|
+
progress.update(task, description=f"[red]Error en {carpeta} ✖[/red]", completed=1)
|
|
120
|
+
|
|
121
|
+
@app.command()
|
|
122
|
+
def main(
|
|
123
|
+
url: Annotated[Optional[str], typer.Argument(help="URL del repositorio")]=None,
|
|
124
|
+
repositories: Annotated[
|
|
125
|
+
Optional[str], typer.Option(help="JSON con con repositorios a clonar"),
|
|
126
|
+
] = None,
|
|
127
|
+
branch: Annotated[Optional[str], typer.Option(help="Branch del repositorio")] = None,
|
|
128
|
+
requirements : Annotated[
|
|
129
|
+
Optional[bool], typer.Option(help="No instala dependencias"),
|
|
130
|
+
] = False,
|
|
131
|
+
# update: Annotated[
|
|
132
|
+
# Optional[bool], typer.Option(help="Actualiza todos los repositorios"),
|
|
133
|
+
# ] = False,
|
|
134
|
+
# garbage: Annotated[
|
|
135
|
+
# Optional[bool], typer.Option(help="No elimina archivos innecesarios"),
|
|
136
|
+
# ] = True,
|
|
137
|
+
repopath: Annotated[
|
|
138
|
+
Optional[str], typer.Option(help="Ruta del repositorio"),
|
|
139
|
+
] = None,
|
|
140
|
+
token: Annotated[
|
|
141
|
+
Optional[str], typer.Option(help="Token de acceso a repositorio"),
|
|
142
|
+
] = None,
|
|
143
|
+
):
|
|
144
|
+
|
|
145
|
+
"""Utility for cloning Git repositories, removing unnecessary files, and installing dependencies from requirements.txt."""
|
|
146
|
+
|
|
147
|
+
# if update:
|
|
148
|
+
# git_update_all()
|
|
149
|
+
# sys.exit(0)
|
|
150
|
+
|
|
151
|
+
if not repositories:
|
|
152
|
+
"""Clonado simple de un repositorio"""
|
|
153
|
+
git_clone_update(url=url, branch=branch, token=token, repo_path=repopath)
|
|
154
|
+
|
|
155
|
+
if requirements:
|
|
156
|
+
install_req(repo_path=repopath)
|
|
157
|
+
# if garbage:
|
|
158
|
+
# remove_garbage(repo_path=repopath)
|
|
159
|
+
# if not repopath:
|
|
160
|
+
# move_folders(repo_path=repopath)
|
|
161
|
+
|
|
162
|
+
if repositories:
|
|
163
|
+
"""
|
|
164
|
+
Clonado de varios repositorios
|
|
165
|
+
Formato de JSON:
|
|
166
|
+
[
|
|
167
|
+
{
|
|
168
|
+
"url": "https://github.com/org/repo1",
|
|
169
|
+
"branch": "18.0",
|
|
170
|
+
"repo_path": "repo1"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"url": "https://github.com/OCA/commission",
|
|
174
|
+
"branch": "18.0",
|
|
175
|
+
"repo_path": "oca/commission"
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
"""
|
|
179
|
+
for repo in json.loads(repositories):
|
|
180
|
+
if "branch" not in repo and not branch:
|
|
181
|
+
err_console.print("✖[red] Branch Not defined [/red]")
|
|
182
|
+
raise typer.Exit(1)
|
|
183
|
+
branch = branch if branch else repo["branch"]
|
|
184
|
+
repo_path = repo["repo_path"] if "repo_path" in repo else None
|
|
185
|
+
git_clone_update(url=repo["url"], branch=branch, token=token, repo_path=repo_path)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
if __name__ == "__main__":
|
|
189
|
+
app()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "odoogci"
|
|
3
|
+
version = "0.2.2"
|
|
4
|
+
description = "Utility to clone odoo modules repository with requirements installation"
|
|
5
|
+
authors = ["Alitux <alitux@disroot.org>"]
|
|
6
|
+
license = "GNU/GPL V2"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
|
|
9
|
+
[tool.poetry.dependencies]
|
|
10
|
+
python = ">=3.9,<4.0"
|
|
11
|
+
typer = "^0.15.1"
|
|
12
|
+
|
|
13
|
+
[build-system]
|
|
14
|
+
requires = ["poetry-core"]
|
|
15
|
+
build-backend = "poetry.core.masonry.api"
|
|
16
|
+
|
|
17
|
+
[tool.poetry.scripts]
|
|
18
|
+
odoogci = "odoogci.main:app"
|