orbit-cli 0.1.24__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.
- orbit_cli-0.1.24/LICENSE.md +21 -0
- orbit_cli-0.1.24/PKG-INFO +21 -0
- orbit_cli-0.1.24/README.md +3 -0
- orbit_cli-0.1.24/orbit_cli/__main__.py +24 -0
- orbit_cli-0.1.24/orbit_cli/cli_application.py +344 -0
- orbit_cli-0.1.24/orbit_cli/cli_common.py +119 -0
- orbit_cli-0.1.24/orbit_cli/cli_main.py +51 -0
- orbit_cli-0.1.24/orbit_cli/cli_utils.py +99 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/.gitignore +4 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/.version +5 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/Makefile +25 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/README.md +3 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/apt/DEBIAN/control +10 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/apt/DEBIAN/postinst +7 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/apt/etc/systemd/system/project.service +13 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/apt/opt/service/scripts/make_keys.sh +57 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/client/App.vue +15 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/client/Makefile +8 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/client/index.html +13 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/client/main.css +50 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/client/main.js +28 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/client/package.json +41 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/client/vite.config.js +52 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/common/favicon.ico +0 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/common/fonts.txt +3 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/common/orbit-logo.png +0 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/scripts/VERSION +1 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/scripts/roll_version.py +39 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/server/Makefile +21 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/server/README.md +3 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/server/__main__.py +5 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/server/make_keys.sh +57 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/server/orbit.spec +41 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/server/pyproject.toml +32 -0
- orbit_cli-0.1.24/orbit_cli/templates/application/server/version.py +1 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/.gitignore +3 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/.version +5 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/Makefile +7 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/README.md +3 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/client/Makefile +0 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/client/index.js +2 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/client/main.vue +97 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/client/main_old.vue +83 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/client/main_old2.vue +30 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/client/menu.js +15 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/client/mytableStore.js +24 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/client/package.json +39 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/client/vite.config.js +35 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/scripts/roll_version.py +39 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/server/Makefile +0 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/server/MyTable.py +22 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/server/README.md +3 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/server/__init__.py +2 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/server/plugin.py +23 -0
- orbit_cli-0.1.24/orbit_cli/templates/component/server/pyproject.toml +29 -0
- orbit_cli-0.1.24/pyproject.toml +21 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
## Copyright (c) 2023 Mad Penguin Consulting Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: orbit-cli
|
|
3
|
+
Version: 0.1.24
|
|
4
|
+
Summary: This tool aims to make things easier when you come to create a new application or a new component
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Gareth Bult
|
|
7
|
+
Author-email: gareth@madpenguin.uk
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
|
|
14
|
+
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
15
|
+
Requires-Dist: rich (>=13.4.2,<14.0.0)
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# Orbit-CLI
|
|
19
|
+
|
|
20
|
+
#### This tool aims to make things easier when you come to create a new application or a new component. It will generate all the boilerplate files you need (from templates) to get up and running with a minimum of fuss. Whereas it won't do everything for you, it should do 99% of the hard work when it comes to setting up a new project.
|
|
21
|
+
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
# Orbit-CLI
|
|
2
|
+
|
|
3
|
+
#### This tool aims to make things easier when you come to create a new application or a new component. It will generate all the boilerplate files you need (from templates) to get up and running with a minimum of fuss. Whereas it won't do everything for you, it should do 99% of the hard work when it comes to setting up a new project.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
██████╗ ██████╗ ██████╗ ██╗████████╗ ██████╗██╗ ██╗
|
|
4
|
+
██╔═══██╗██╔══██╗██╔══██╗██║╚══██╔══╝ ██╔════╝██║ ██║
|
|
5
|
+
██║ ██║██████╔╝██████╔╝██║ ██║█████╗██║ ██║ ██║
|
|
6
|
+
██║ ██║██╔══██╗██╔══██╗██║ ██║╚════╝██║ ██║ ██║
|
|
7
|
+
╚██████╔╝██║ ██║██████╔╝██║ ██║ ╚██████╗███████╗██║
|
|
8
|
+
╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝"""
|
|
9
|
+
from orbit_cli.cli_main import Main
|
|
10
|
+
#
|
|
11
|
+
# Banner from "figlet -w200 -f 'ansi-shadow'"
|
|
12
|
+
#
|
|
13
|
+
__version__ = "0.1.24"
|
|
14
|
+
#
|
|
15
|
+
# Entry point when run as an installed package
|
|
16
|
+
#
|
|
17
|
+
def main ():
|
|
18
|
+
Main(__doc__, __version__).run()
|
|
19
|
+
#
|
|
20
|
+
# Entry point when testing
|
|
21
|
+
#
|
|
22
|
+
if __name__ == '__main__':
|
|
23
|
+
main ()
|
|
24
|
+
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from shutil import copyfile
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
from rich.table import Table
|
|
5
|
+
from orbit_cli.cli_common import Common
|
|
6
|
+
from json import dump
|
|
7
|
+
from requests import get as requests_get
|
|
8
|
+
from urllib.parse import urlparse
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Application (Common):
|
|
12
|
+
|
|
13
|
+
def configure_component (self):
|
|
14
|
+
self.msg ('Creating folders ...')
|
|
15
|
+
server_src = f'server/orbit_component_{self.project}/'
|
|
16
|
+
for path in [
|
|
17
|
+
'client/src/stores',
|
|
18
|
+
'client/src/widgets',
|
|
19
|
+
'client/src/views',
|
|
20
|
+
'server/scripts',
|
|
21
|
+
'scripts',
|
|
22
|
+
f'{server_src}/schema']:
|
|
23
|
+
self.ensure_folder(self.project_path, path)
|
|
24
|
+
self.install ('README.md')
|
|
25
|
+
self.install ('Makefile')
|
|
26
|
+
self.install ('.gitignore')
|
|
27
|
+
self.install ('.version')
|
|
28
|
+
self.install ('server/README.md' , 'server')
|
|
29
|
+
self.install ('server/pyproject.toml' , 'server')
|
|
30
|
+
self.install ('server/Makefile' , 'server')
|
|
31
|
+
self.install ('server/__init__.py' , f'{server_src}')
|
|
32
|
+
self.install ('server/plugin.py' , f'{server_src}')
|
|
33
|
+
self.install ('server/MyTable.py' , f'{server_src}/schema')
|
|
34
|
+
self.install ('scripts/roll_version.py' , 'scripts', chmod=0o755)
|
|
35
|
+
self.install ('client/Makefile' , 'client')
|
|
36
|
+
self.install ('client/package.json' , 'client')
|
|
37
|
+
self.install ('client/vite.config.js' , 'client')
|
|
38
|
+
self.install ('client/index.js' , 'client')
|
|
39
|
+
self.install ('client/menu.js' , 'client')
|
|
40
|
+
self.install ('client/main.vue' , f'client/src/{self.project}.vue', full=True)
|
|
41
|
+
# self.install ('client/mainComponent.vue', f'client/src/{self.project}Component.vue', full=True)
|
|
42
|
+
self.install ('client/mytableStore.js' , 'client/src/stores')
|
|
43
|
+
|
|
44
|
+
def configure_application (self):
|
|
45
|
+
self.msg ('Creating folders ...')
|
|
46
|
+
for path in [
|
|
47
|
+
'apt/etc/systemd/system',
|
|
48
|
+
'apt/usr/local/bin',
|
|
49
|
+
'apt/DEBIAN',
|
|
50
|
+
f'apt/opt/{self.project}/scripts',
|
|
51
|
+
f'apt/opt/{self.project}/web/assets',
|
|
52
|
+
'client/public',
|
|
53
|
+
'client/src/assets',
|
|
54
|
+
'client/src/components',
|
|
55
|
+
'client/src/views',
|
|
56
|
+
'scripts',
|
|
57
|
+
'server/src',
|
|
58
|
+
'server/scripts']:
|
|
59
|
+
self.ensure_folder(self.project, path)
|
|
60
|
+
self.install ('README.md')
|
|
61
|
+
self.install ('Makefile')
|
|
62
|
+
self.install ('.gitignore')
|
|
63
|
+
self.install ('.version')
|
|
64
|
+
self.install ('server/README.md' , 'server')
|
|
65
|
+
self.install ('server/pyproject.toml' , 'server')
|
|
66
|
+
self.install ('server/orbit.spec' , 'server')
|
|
67
|
+
self.install ('server/Makefile' , 'server')
|
|
68
|
+
self.install ('server/__main__.py' , 'server/src')
|
|
69
|
+
self.install ('server/version.py' , 'server/src')
|
|
70
|
+
self.install ('server/make_keys.sh' , 'server/scripts')
|
|
71
|
+
self.install ('apt/DEBIAN/control' , 'apt/DEBIAN')
|
|
72
|
+
self.install ('apt/DEBIAN/postinst' , 'apt/DEBIAN', chmod=0o755)
|
|
73
|
+
self.install ('apt/etc/systemd/system/project.service' , f'apt/etc/systemd/system/{self.project}.service', full=True)
|
|
74
|
+
self.install ('apt/opt/service/scripts/make_keys.sh' , f'apt/opt/{self.project}/scripts', chmod=0o755)
|
|
75
|
+
self.install ('scripts/roll_version.py', 'scripts', chmod=0o755)
|
|
76
|
+
self.install ('client/index.html' , 'client')
|
|
77
|
+
self.install ('client/Makefile' , 'client')
|
|
78
|
+
self.install ('client/package.json' , 'client')
|
|
79
|
+
self.install ('client/vite.config.js' , 'client')
|
|
80
|
+
self.install ('client/App.vue' , 'client/src')
|
|
81
|
+
self.install ('client/main.js' , 'client/src')
|
|
82
|
+
self.install ('client/main.css' , 'client/src/assets')
|
|
83
|
+
self.install ('common/orbit-logo.png' , 'client/src/assets', binary=True)
|
|
84
|
+
self.install ('common/favicon.ico' , 'client/public', binary=True)
|
|
85
|
+
|
|
86
|
+
def ensure_folder (self, project, path):
|
|
87
|
+
if Path(path).exists():
|
|
88
|
+
return self.warn (f'Already exists: {path}')
|
|
89
|
+
self.msg (f'Creating folder: {path}')
|
|
90
|
+
(Path(project) / path ).mkdir(parents=True)
|
|
91
|
+
|
|
92
|
+
def install (self, src, dst='.', full=False, binary=False, force=False, chmod=None):
|
|
93
|
+
name = src.split('/')[-1]
|
|
94
|
+
self.msg (f'Installing [bold]{name}[/bold] in [bold]{dst}[/bold]')
|
|
95
|
+
target = f'{self.project_path}/{dst}/{name}' if not full else f'{self.project_path}/{dst}'
|
|
96
|
+
if Path(target).exists() and not force:
|
|
97
|
+
return self.warn (f'Skipped: [bold]{target}[/bold] - already exists!')
|
|
98
|
+
source = f'{self._templates}/{self.project_type}/{src}'
|
|
99
|
+
if not Path(source).exists():
|
|
100
|
+
return self.warn (f'Skipped: [bold]{source}[/bold] - template is MISSING!')
|
|
101
|
+
if binary:
|
|
102
|
+
with open(target, 'wb') as out:
|
|
103
|
+
with open(source, 'rb') as inp:
|
|
104
|
+
out.write(inp.read())
|
|
105
|
+
else:
|
|
106
|
+
with open(target, 'w') as io:
|
|
107
|
+
io.write (self._env.get_template(f'{self.project_type}/{src}').render(self._vars))
|
|
108
|
+
if chmod:
|
|
109
|
+
Path(target).chmod(chmod)
|
|
110
|
+
|
|
111
|
+
def component_update (self):
|
|
112
|
+
if not self.project:
|
|
113
|
+
self._vars['project'] = self._args.update
|
|
114
|
+
if not Path(self.project_path) or not Path(self.project_path).is_dir():
|
|
115
|
+
self.error (f"Can't see project: {self.project_path}")
|
|
116
|
+
self.manage_local_repos()
|
|
117
|
+
self.msg (f'Running [bold]update_components[/bold] for project [bold]{self.project}[/bold]')
|
|
118
|
+
self.install ('common/fonts.txt', 'client/src/components/fonts.template', full=True, force=True)
|
|
119
|
+
components = set(self.get_js_components(self.project_path))
|
|
120
|
+
if 'orbit-component-shell' not in components:
|
|
121
|
+
components.add('orbit-component-shell')
|
|
122
|
+
if 'orbit-component-base' in components:
|
|
123
|
+
components.remove('orbit-component-base')
|
|
124
|
+
|
|
125
|
+
installed = []
|
|
126
|
+
for component in components:
|
|
127
|
+
name = component[16:]
|
|
128
|
+
src = Path(f'{self.project_path}/client/node_modules/{component}/menu.js')
|
|
129
|
+
dst = Path(f'{self.project_path}/client/src/components/{name}.js.template')
|
|
130
|
+
copyfile (src, dst)
|
|
131
|
+
|
|
132
|
+
if Path(f'{self.project}/client/src/components/{name}.js').exists():
|
|
133
|
+
installed.append((component.replace('-', '_'), f'@/components/{name}.js'))
|
|
134
|
+
else:
|
|
135
|
+
installed.append((component.replace('-', '_'), f'@/../node_modules/{component}/menu.js'))
|
|
136
|
+
|
|
137
|
+
if not (src := Path(f'{self.project_path}/client/src/components/fonts.txt')).exists():
|
|
138
|
+
src = f'{self._templates}/{self.project_type}/common/fonts.txt'
|
|
139
|
+
fonts = []
|
|
140
|
+
with open(src) as io:
|
|
141
|
+
while line := io.readline():
|
|
142
|
+
fonts.append(line.split('\n')[0])
|
|
143
|
+
|
|
144
|
+
self._vars['fonts'] = fonts
|
|
145
|
+
self._vars['components'] = installed
|
|
146
|
+
self.install ('client/main.js', 'client/src', force=True)
|
|
147
|
+
|
|
148
|
+
def component_build (self):
|
|
149
|
+
self._vars['project'] = self._args.build
|
|
150
|
+
self.shell(
|
|
151
|
+
f'Build a .DEB installer for [bold]{self._args.build}[/bold] >>>>',
|
|
152
|
+
f'cd {self.project_path} && make build_deb')
|
|
153
|
+
self.msg ('<<<<')
|
|
154
|
+
|
|
155
|
+
def component_list (self):
|
|
156
|
+
self._vars['project'] = self._args.list
|
|
157
|
+
js_components, py_components = self.resolve_components(self.project)
|
|
158
|
+
tab = Table(min_width=50)
|
|
159
|
+
for field in ['Idx', 'Name', 'Front-End', 'Back-End']:
|
|
160
|
+
tab.add_column(field, style='cyan', header_style='deep_sky_blue4', no_wrap=True)
|
|
161
|
+
for (idx, name) in enumerate(py_components | js_components):
|
|
162
|
+
tab.add_row(
|
|
163
|
+
str(idx),
|
|
164
|
+
name,
|
|
165
|
+
'installed' if name in js_components else '[magenta]none[/magenta]',
|
|
166
|
+
'installed' if name in py_components else '[magenta]none[/magenta]'
|
|
167
|
+
)
|
|
168
|
+
Console().print(tab)
|
|
169
|
+
|
|
170
|
+
def component_add (self):
|
|
171
|
+
self.manage_local_repos()
|
|
172
|
+
self._vars['project'] = self._args.add
|
|
173
|
+
for component in self._args.components:
|
|
174
|
+
self._vars['component'] = component
|
|
175
|
+
self.msg (f"Adding component [bold]{self.component}[/bold] to [bold]{self.project}[/bold]")
|
|
176
|
+
js_components, py_components = self.resolve_components(self.project)
|
|
177
|
+
if self.component not in js_components:
|
|
178
|
+
# registry = f'--registry={self._args.local_npm} --force' if self._args.local_npm else ""
|
|
179
|
+
self.call_shell(
|
|
180
|
+
f'Installing JS component [bold]{self.component}[/bold] >>>>',
|
|
181
|
+
f'cd {self.project_path}/client && npm install {self.component}')
|
|
182
|
+
# f'cd {self.project_path}/client && npm install {self.component};npm run build')
|
|
183
|
+
self.msg ('<<<<')
|
|
184
|
+
else:
|
|
185
|
+
self.msg ('[red]already installed[/red]')
|
|
186
|
+
if self.component not in py_components:
|
|
187
|
+
if self.component:
|
|
188
|
+
self.run_shell(
|
|
189
|
+
f'Installing PY component [bold]{self.component}[/bold] >>>>',
|
|
190
|
+
f'cd {self.project_path}/server && poetry add {self.component}')
|
|
191
|
+
self.msg ('<<<<')
|
|
192
|
+
else:
|
|
193
|
+
self.msg ('[red]already installed[/red]')
|
|
194
|
+
self.component_update ()
|
|
195
|
+
self.msg ('Complete.')
|
|
196
|
+
|
|
197
|
+
def component_remove (self):
|
|
198
|
+
self._vars['project'] = self._args.rem
|
|
199
|
+
for component in self._args.components:
|
|
200
|
+
self._vars['component'] = component
|
|
201
|
+
self.msg (f"Removing component [bold]{self.component}[/bold] from [bold]{self.project}[/bold]")
|
|
202
|
+
js_components, py_components = self.resolve_components(self.project)
|
|
203
|
+
if self.component in js_components:
|
|
204
|
+
self.run_shell(
|
|
205
|
+
f'Removing JS component [bold]{self.component}[/bold] >>>>',
|
|
206
|
+
f'cd {self.project_path}/client;npm uninstall {self.component}')
|
|
207
|
+
self.msg ('<<<<')
|
|
208
|
+
else:
|
|
209
|
+
self.msg ('[red]not installed[/red]')
|
|
210
|
+
if self.component in py_components:
|
|
211
|
+
self.run_shell(
|
|
212
|
+
f'Removing PY component [bold]{self.component}[/bold] >>>>',
|
|
213
|
+
f'cd {self.project_path}/server && poetry add {self.component}')
|
|
214
|
+
self.msg ('<<<<')
|
|
215
|
+
else:
|
|
216
|
+
self.msg ('[red]not installed[/red]')
|
|
217
|
+
self.component_update ()
|
|
218
|
+
self.msg ('Complete.')
|
|
219
|
+
|
|
220
|
+
def create_project (self, project):
|
|
221
|
+
if not self.confirm (f'Create project [bold]{project}[/bold]?'):
|
|
222
|
+
self.error ('Aborted!')
|
|
223
|
+
if self.project_type == 'application':
|
|
224
|
+
project_path = project
|
|
225
|
+
else:
|
|
226
|
+
project = project.replace('-', '_')
|
|
227
|
+
project_path = f"orbit-component-{project}"
|
|
228
|
+
if Path(project_path).mkdir():
|
|
229
|
+
self.error ('Unable to create the project!')
|
|
230
|
+
self.call_shell(
|
|
231
|
+
f'Creating virtual env [project_path]',
|
|
232
|
+
f'pyenv virtualenv {project_path}')
|
|
233
|
+
return project_path
|
|
234
|
+
|
|
235
|
+
def collect_project_information (self):
|
|
236
|
+
self.msg ('Collecting project information...')
|
|
237
|
+
while True:
|
|
238
|
+
project = self.ask('Enter your project name', 'my-demo-project' if self.project_type == 'application' else 'mycomp')
|
|
239
|
+
if not Path(project).exists():
|
|
240
|
+
break
|
|
241
|
+
self.msg ('[red]Project folder already exists![/red]')
|
|
242
|
+
self._vars['project'] = project
|
|
243
|
+
self._vars['description'] = self.ask('Enter your project description', 'Just an example Orbit application' if self.project_type == 'application' else 'A Demo Component')
|
|
244
|
+
self._vars['author'] = self.ask('Enter your name (project author)', 'John Doe')
|
|
245
|
+
self._vars['email'] = self.ask('Enter your email address (bugs email)', 'support@madpenguin.uk')
|
|
246
|
+
self._vars['url'] = self.ask('Enter your project home page', 'https://linux.uk')
|
|
247
|
+
self._vars['project_path'] = self.create_project(project)
|
|
248
|
+
|
|
249
|
+
def manage_local_repos (self):
|
|
250
|
+
if self._args.local_npm:
|
|
251
|
+
self.call_shell(
|
|
252
|
+
f'Setting local NPM registry to: {self._args.local_npm}',
|
|
253
|
+
f'cd {self.project_path}/client && npm config set registry {self._args.local_npm} && npm config set legacy-peer-deps true')
|
|
254
|
+
if self._args.local_pypi:
|
|
255
|
+
host = urlparse(self._args.local_pypi).netloc.split(':')[0]
|
|
256
|
+
self.run_shell(
|
|
257
|
+
f'Setting local PYPI registry to: {self._args.local_pypi}',
|
|
258
|
+
f'cd {self.project_path}/server && pip config --user set global.index-url {self._args.local_pypi} && pip config --user set global.trusted-host {host}')
|
|
259
|
+
self.run_shell(
|
|
260
|
+
f'Setting local Poetry registry to: {self._args.local_pypi}',
|
|
261
|
+
f"""
|
|
262
|
+
cd {self.project_path}/server &&\n
|
|
263
|
+
poetry source add borg {self._args.local_pypi} --priority="primary" &&\n
|
|
264
|
+
poetry source add pypi --priority="supplemental"
|
|
265
|
+
""")
|
|
266
|
+
|
|
267
|
+
# def repo_create (self):
|
|
268
|
+
# self.shell(
|
|
269
|
+
# f'Installing local Python REPOSITORY [bold]{self._args.local_repo[0]}[/bold] >>>>',
|
|
270
|
+
# f"""
|
|
271
|
+
# cd {self.project_path}/server &&\n
|
|
272
|
+
# poetry source add {self._args.local_repo[0]} {self._args.local_repo[1]} --priority="primary" &&\n
|
|
273
|
+
# poetry source add pypi --priority="supplemental"
|
|
274
|
+
# """)
|
|
275
|
+
|
|
276
|
+
def component_install_nltk (self):
|
|
277
|
+
self.run_shell(
|
|
278
|
+
f'Installing NLTK for FTX indexing ...',
|
|
279
|
+
f"""cd {self.project_path}/server && python -c 'import nltk;nltk.download("stopwords");nltk.download("punkt")' """)
|
|
280
|
+
|
|
281
|
+
def component_create (self):
|
|
282
|
+
self.ensure_tools()
|
|
283
|
+
self.collect_project_information ()
|
|
284
|
+
self.ensure_poetry()
|
|
285
|
+
if self.project_type == 'application':
|
|
286
|
+
self.configure_application()
|
|
287
|
+
elif self.project_type == 'component':
|
|
288
|
+
self.configure_component()
|
|
289
|
+
else:
|
|
290
|
+
self.error ('unknown type, must be application or component')
|
|
291
|
+
self.manage_local_repos()
|
|
292
|
+
# registry = f'--registry={self._args.local_npm} --force' if self._args.local_npm else ""
|
|
293
|
+
self.call_shell(
|
|
294
|
+
f'Installing JS components >>>>',
|
|
295
|
+
f'cd {self.project_path}/client;npm install')
|
|
296
|
+
self.msg ('<<<<')
|
|
297
|
+
# if self._args.local_repo:
|
|
298
|
+
# self.repo_create ()
|
|
299
|
+
self.run_shell(
|
|
300
|
+
f'Installing PY components >>>>',
|
|
301
|
+
f'cd {self.project_path}/server && poetry install')
|
|
302
|
+
self.msg ('<<<<')
|
|
303
|
+
if self.project_type == 'application':
|
|
304
|
+
self.component_install_nltk()
|
|
305
|
+
self.component_update ()
|
|
306
|
+
self.msg ('Complete.')
|
|
307
|
+
|
|
308
|
+
def component_populate (self):
|
|
309
|
+
self._vars['project'] = self._args.populate
|
|
310
|
+
self.msg (f'Populating [bold]{self.project}[/bold] data')
|
|
311
|
+
r = requests_get(f'https://swapi.dev/api/')
|
|
312
|
+
if r.status_code != 200:
|
|
313
|
+
self.error (f'unable to read remote table [code={r.status_code}]')
|
|
314
|
+
for table in r.json():
|
|
315
|
+
self.msg (f'Processing [bold]{table}[/bold] ...')
|
|
316
|
+
count = 0
|
|
317
|
+
page = 1
|
|
318
|
+
with open(f'{self.project}/demo_data_{table}.json', 'w') as io:
|
|
319
|
+
io.write('{\n')
|
|
320
|
+
while True:
|
|
321
|
+
r = requests_get(f'https://swapi.dev/api/{table}?page={page}')
|
|
322
|
+
if r.status_code != 200:
|
|
323
|
+
self.error (f'problem reading page: {page} for {table}')
|
|
324
|
+
json = r.json()
|
|
325
|
+
self.msg (f'=> {page}...')
|
|
326
|
+
for result in json['results']:
|
|
327
|
+
if count: io.write(',\n')
|
|
328
|
+
io.write(f' "{count}": ')
|
|
329
|
+
dump(result, io)
|
|
330
|
+
count += 1
|
|
331
|
+
if not json['next']:
|
|
332
|
+
break
|
|
333
|
+
page += 1
|
|
334
|
+
io.write('\n}\n')
|
|
335
|
+
break
|
|
336
|
+
self.msg ('Complete')
|
|
337
|
+
|
|
338
|
+
def component_upgrade (self):
|
|
339
|
+
if not self.confirm (f'Upgrade [bold]ORBIT_CLI[/bold] via PIP?'):
|
|
340
|
+
self.error ('Aborted!')
|
|
341
|
+
self.call_shell(
|
|
342
|
+
f'Running "pip -q install --upgrade orbit-cli"',
|
|
343
|
+
f'pip -q install --upgrade orbit-cli')
|
|
344
|
+
self.msg ('Complete')
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from requests import get as requests_get
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from shutil import which
|
|
4
|
+
from tempfile import NamedTemporaryFile
|
|
5
|
+
from subprocess import call as call_process
|
|
6
|
+
from orbit_cli.cli_utils import Utils
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Common (Utils):
|
|
10
|
+
|
|
11
|
+
PYENV = 'export PATH="$PATH:$HOME/.pyenv/bin:$HOME/.local/bin"\neval "$(pyenv init -)"\neval "$(pyenv virtualenv-init -)"\n'
|
|
12
|
+
NVENV = 'export NVM_DIR="$HOME/.nvm"\n[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"\n[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"\n'
|
|
13
|
+
PYENV_INSTALLER = 'https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer'
|
|
14
|
+
NVM_INSTALLER = 'https://raw.githubusercontent.com/creationix/nvm/master/install.sh'
|
|
15
|
+
|
|
16
|
+
def reset (self):
|
|
17
|
+
yn = self.confirm ('This will [bold]REMOVE[/bold], pyenv, nvm, npm, poetry etc from this users profile, are you sure?')
|
|
18
|
+
if not yn:
|
|
19
|
+
self.error (f'Nothing to do here!')
|
|
20
|
+
with NamedTemporaryFile(suffix='.sh', mode='w') as io:
|
|
21
|
+
io.write('#!/usr/bin/env bash\n')
|
|
22
|
+
io.write('rm -rf .pyenv\n')
|
|
23
|
+
io.write('rm -rf .nvm\n')
|
|
24
|
+
io.write('rm -rf .npm\n')
|
|
25
|
+
io.flush()
|
|
26
|
+
call_process (['bash', io.name])
|
|
27
|
+
path = Path('~/.bash_profile').expanduser()
|
|
28
|
+
if path.exists():
|
|
29
|
+
self.strip_from_file('~/.bash_profile', ['pyenv', 'NVM'])
|
|
30
|
+
self.msg ('[red]Complete, please log out and in again![/red]')
|
|
31
|
+
|
|
32
|
+
def ensure_tools (self):
|
|
33
|
+
self.ensure_pyenv()
|
|
34
|
+
self.ensure_nvm()
|
|
35
|
+
self.ensure_npm()
|
|
36
|
+
|
|
37
|
+
def ensure_pyenv (self):
|
|
38
|
+
if not self.ensure('pyenv'):
|
|
39
|
+
self.download_and_run('pyenv', self.PYENV_INSTALLER)
|
|
40
|
+
self.add_to_file('~/.bash_profile', 'pyenv', self.PYENV)
|
|
41
|
+
return False
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
def ensure_nvm (self):
|
|
45
|
+
if not self.ensure ('nvm'):
|
|
46
|
+
self.download_and_run('nvm', self.NVM_INSTALLER)
|
|
47
|
+
self.add_to_file('~/.bash_profile', 'nvm', self.NVENV)
|
|
48
|
+
return False
|
|
49
|
+
return True
|
|
50
|
+
|
|
51
|
+
def ensure_npm (self):
|
|
52
|
+
if not self.ensure('npm'):
|
|
53
|
+
with NamedTemporaryFile(suffix='.sh', mode='w') as io:
|
|
54
|
+
io.write('#!/usr/bin/env bash\n')
|
|
55
|
+
io.write('source ~/.bash_profile\n')
|
|
56
|
+
io.write('export NVM_DIR="$HOME/.nvm"\n')
|
|
57
|
+
io.write('export PATH="$PATH:$HOME/.local/bin"\n')
|
|
58
|
+
io.write('[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"\n')
|
|
59
|
+
io.write('[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"\n')
|
|
60
|
+
io.write('nvm install node\n')
|
|
61
|
+
io.flush()
|
|
62
|
+
call_process (['bash', io.name])
|
|
63
|
+
return False
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
def ensure_poetry (self):
|
|
67
|
+
if not self.ensure('poetry', which('poetry')):
|
|
68
|
+
result = self.shell(
|
|
69
|
+
f'Installing [bold]Poetry[/bold] >>>>',
|
|
70
|
+
f'pip install poetry')
|
|
71
|
+
return False
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
def ensure (self, name, test=None):
|
|
75
|
+
self.msg(f'Ensuring [bold]{name}[/bold] is set up ...')
|
|
76
|
+
if test is None:
|
|
77
|
+
test = Path(f'.{name}').exists()
|
|
78
|
+
if test:
|
|
79
|
+
return True
|
|
80
|
+
yn = self.confirm (f'Unable to locate [bold]{name}[/bold], would you like to install it?')
|
|
81
|
+
if not yn:
|
|
82
|
+
self.error (f'Unable to continue without [bold]{name}[/bold]')
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
def download_and_run (self, name, url):
|
|
86
|
+
self.msg (f'Downloading [bold]{name}[/bold] installer ...')
|
|
87
|
+
result = requests_get(url)
|
|
88
|
+
if result.status_code != 200:
|
|
89
|
+
self.error ('Failed to download installer: [bold]{r.status_code}[/bold]')
|
|
90
|
+
self.call (f'Running [bold]{name}[/bold] installer ...', result.text)
|
|
91
|
+
|
|
92
|
+
def add_to_file (self, file_name: str, token: str, text: str):
|
|
93
|
+
path = Path(file_name).expanduser()
|
|
94
|
+
if path.exists():
|
|
95
|
+
with open(path) as io:
|
|
96
|
+
file = io.read()
|
|
97
|
+
else:
|
|
98
|
+
file = ''
|
|
99
|
+
if token in file:
|
|
100
|
+
self.warn (f'We already seem to have [bold]{token}[/bold] in .bash_profile, please check!')
|
|
101
|
+
return
|
|
102
|
+
with open(path, 'w') as io:
|
|
103
|
+
io.write(file + text)
|
|
104
|
+
|
|
105
|
+
def strip_from_file (self, file_name: str, tokens: list):
|
|
106
|
+
path = Path(file_name).expanduser()
|
|
107
|
+
with open(path) as io:
|
|
108
|
+
lines = io.read().split('\n')
|
|
109
|
+
output = []
|
|
110
|
+
for line in lines:
|
|
111
|
+
remove = False
|
|
112
|
+
for token in tokens:
|
|
113
|
+
if token in line:
|
|
114
|
+
remove = True
|
|
115
|
+
if not remove:
|
|
116
|
+
output.append(line)
|
|
117
|
+
with open(path, 'w') as io:
|
|
118
|
+
io.write('\n'.join(output))
|
|
119
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from argparse import ArgumentParser
|
|
2
|
+
from rich.console import Console
|
|
3
|
+
from rich import print
|
|
4
|
+
from orbit_cli.cli_application import Application
|
|
5
|
+
from orbit_cli.cli_common import Common
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Main:
|
|
10
|
+
|
|
11
|
+
def __init__ (self, banner, version):
|
|
12
|
+
print(f'[blue]{ banner }[/blue]')
|
|
13
|
+
print(f'[blue]=>[/blue][magenta] Mad Penguin Consulting Ltd (c) 2023 (MIT License)[/magenta] [blue]v{version}[/blue]')
|
|
14
|
+
print()
|
|
15
|
+
path = Path('~/.bash_profile').expanduser()
|
|
16
|
+
if not path.exists():
|
|
17
|
+
with open(str(path), 'w') as io:
|
|
18
|
+
io.write('#!/usr/bin/env bash\n')
|
|
19
|
+
|
|
20
|
+
# FIXME: strip trailing "/" from project name"
|
|
21
|
+
def run (self):
|
|
22
|
+
try:
|
|
23
|
+
parser = ArgumentParser ()
|
|
24
|
+
parser.add_argument ("--init", type=str, metavar="TYPE", help="Specify whether we're working with an 'application' or 'component'")
|
|
25
|
+
parser.add_argument ("--update", type=str, metavar="PROJECT", help="Update main.js based on currently installed components")
|
|
26
|
+
parser.add_argument ("--build", type=str, metavar="PROJECT", help="Build a .DEB intaller for the specified project")
|
|
27
|
+
parser.add_argument ("--list", type=str, metavar="PROJECT", help="List installed components")
|
|
28
|
+
parser.add_argument ("--add", type=str, metavar='PROJECT', help="Add new components")
|
|
29
|
+
parser.add_argument ("--rem", type=str, metavar='PROJECT', help="Remove installed components")
|
|
30
|
+
parser.add_argument ("--components", type=str, nargs='*', metavar=('COMPONENTS'), help="Components to operate on")
|
|
31
|
+
parser.add_argument ("--populate", type=str, metavar="PROJECT", help="Download sample data into project folder from sample API")
|
|
32
|
+
parser.add_argument ("--reset", action='store_true', help="Remove and reinstall all tools [pyenv, nvm etc]")
|
|
33
|
+
parser.add_argument ("--local-pypi", type=str, metavar='REPO', help='Local PYPI repository')
|
|
34
|
+
parser.add_argument ("--local-npm", type=str, metavar='REGISTRY', help='Address of local NPM registry')
|
|
35
|
+
parser.add_argument ("--upgrade", action='store_true', help='Upgrade the orbit_cli code to the latest version via PIP')
|
|
36
|
+
application = Application(args := parser.parse_args ())
|
|
37
|
+
if args.init: application.component_create ()
|
|
38
|
+
elif args.update: application.component_update ()
|
|
39
|
+
elif args.build: application.component_build ()
|
|
40
|
+
elif args.list: application.component_list ()
|
|
41
|
+
elif args.rem: application.component_remove ()
|
|
42
|
+
elif args.add: application.component_add ()
|
|
43
|
+
elif args.populate: application.component_populate ()
|
|
44
|
+
elif args.reset: Common(args).reset()
|
|
45
|
+
elif args.upgrade: application.component_upgrade ()
|
|
46
|
+
else:
|
|
47
|
+
print ('No action specified!\n')
|
|
48
|
+
except KeyboardInterrupt:
|
|
49
|
+
pass
|
|
50
|
+
except Exception:
|
|
51
|
+
Console().print_exception(show_locals=True)
|