grepsr-cli 0.7.4__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.
- grepsr_cli-0.7.4.dist-info/LICENSE.md +1 -0
- grepsr_cli-0.7.4.dist-info/METADATA +92 -0
- grepsr_cli-0.7.4.dist-info/RECORD +35 -0
- grepsr_cli-0.7.4.dist-info/WHEEL +5 -0
- grepsr_cli-0.7.4.dist-info/entry_points.txt +2 -0
- grepsr_cli-0.7.4.dist-info/top_level.txt +1 -0
- grepsrcli/__init__.py +0 -0
- grepsrcli/controllers/__init__.py +0 -0
- grepsrcli/controllers/base.py +55 -0
- grepsrcli/controllers/crawler.py +480 -0
- grepsrcli/controllers/generate.py +34 -0
- grepsrcli/controllers/report.py +63 -0
- grepsrcli/core/__init__.py +0 -0
- grepsrcli/core/aws_s3.py +39 -0
- grepsrcli/core/config.py +191 -0
- grepsrcli/core/exc.py +4 -0
- grepsrcli/core/input_prompts.py +0 -0
- grepsrcli/core/message_log.py +34 -0
- grepsrcli/core/multiproc_server.py +126 -0
- grepsrcli/core/report_api.py +39 -0
- grepsrcli/core/sdk_setup.py +84 -0
- grepsrcli/core/test_local.py +136 -0
- grepsrcli/core/utils.py +308 -0
- grepsrcli/ext/__init__.py +0 -0
- grepsrcli/main.py +91 -0
- grepsrcli/plugins/__init__.py +0 -0
- grepsrcli/templates/__init__.py +0 -0
- grepsrcli/templates/autocomplete.jinja2 +12 -0
- grepsrcli/templates/autocomplete_zsh.jinja2 +20 -0
- grepsrcli/templates/composer.jinja2 +21 -0
- grepsrcli/templates/node_boilerplate.jinja2 +100 -0
- grepsrcli/templates/php_boilerplate.jinja2 +63 -0
- grepsrcli/templates/php_brp_boilerplate.jinja2 +83 -0
- grepsrcli/templates/php_vc_boilerplate.jinja2 +65 -0
- grepsrcli/templates/py_boilerplate.jinja2 +56 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: grepsr-cli
|
|
3
|
+
Version: 0.7.4
|
|
4
|
+
Summary: A Cli tool for Grepsr Developers
|
|
5
|
+
Home-page: https://bitbucket.org/grepsr/grepsr-cli/
|
|
6
|
+
Author: grepsr
|
|
7
|
+
Author-email: dev@grepsr.com
|
|
8
|
+
License: unlicensed
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE.md
|
|
11
|
+
Requires-Dist: cement (>=3.0.4)
|
|
12
|
+
Requires-Dist: Jinja2 (>=2.11.3)
|
|
13
|
+
Requires-Dist: PyYAML (==5.4.1)
|
|
14
|
+
Requires-Dist: colorlog (>=4.8.0)
|
|
15
|
+
Requires-Dist: semver (>=2.13.0)
|
|
16
|
+
Requires-Dist: terminaltables (>=3.1.0)
|
|
17
|
+
Requires-Dist: requests (>=2.25.1)
|
|
18
|
+
Requires-Dist: boto3 (<2.0.0,>=1.9.0)
|
|
19
|
+
|
|
20
|
+
# A Cli tool for Grepsr Developers
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
```
|
|
24
|
+
$ pip install grepsr-cli
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
### passing parameters to `amazon_com` service.
|
|
30
|
+
```bash
|
|
31
|
+
gcli crawler test -s amazon_com -p '{"urls":["https://amazon.com/VVUH4HJ","https://amazon.com/FV4434"]}'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### if JSON is complex, use file instead
|
|
35
|
+
```
|
|
36
|
+
# contents of /tmp/amazon_params.json
|
|
37
|
+
{"urls": ["https://amazon.com/VV%20UH4HJ"], "strip": ["'", "\"", "\\"]}
|
|
38
|
+
|
|
39
|
+
gcli crawler test -s amazon_com --params-file '/tmp/amazon_params.json'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Hacks Used.
|
|
43
|
+
> If the json parameter has a space, it might break parameter parsing.
|
|
44
|
+
> If the json parameter has a dash `-` and any character after it has a space, it will break parameter parsing.
|
|
45
|
+
Cause: no double quoting around $@ in `run_service.php:5:49` [here](https://bitbucket.org/grepsr/vortex-backend/src/09c263fb0bb538003db01e1d6742a43ae6ebc61a/deploy/vortex-backend/scripts/run_service.sh#lines-5)
|
|
46
|
+
> This is fixed hackily by replacing string with its unicode \u0020 sequence. This works beacause $@ does not split on \u0020.
|
|
47
|
+
|
|
48
|
+
### inject custom command.
|
|
49
|
+
Say, for example you wanted to a inject a php function so that it could be called from inside you service_code when testing locally.
|
|
50
|
+
Note: All these files should only be created inside `~/.grepsr/tmp`. Creating it outside will not work.
|
|
51
|
+
|
|
52
|
+
1. Create a file called `inject.php` inside `~/.grepsr/tmp/`
|
|
53
|
+
2. Implement your function inside `~/.grepsr/tmp/inject.php`
|
|
54
|
+
```php
|
|
55
|
+
function addRowLocal($arr) {
|
|
56
|
+
...
|
|
57
|
+
...
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
3. Create a file called `inject.sh` inside `~/.grepsr/tmp/`
|
|
61
|
+
4. inside inject.sh add:
|
|
62
|
+
```
|
|
63
|
+
alias php='php -d auto_prepend_file=/tmp/inject.php'
|
|
64
|
+
```
|
|
65
|
+
Note: the file location is `/tmp/inject.php` instead of `~/.grepsr/tmp/inject.php`.
|
|
66
|
+
This is because, the local path `~/.grepsr/tmp` gets mapped to `/tmp` in the docker container.
|
|
67
|
+
And `inject.sh` runs inside docker, instead of the local filesystem.
|
|
68
|
+
5. Add an entry in `~/.grepst/config.yml` like so:
|
|
69
|
+
```yml
|
|
70
|
+
php:
|
|
71
|
+
...
|
|
72
|
+
sdk_image: ...
|
|
73
|
+
pre_entry_run_file: inject.sh # relative and limited to the tmp/ dir
|
|
74
|
+
```
|
|
75
|
+
6. Now you can use `addRowLocal()` in your any of your files.
|
|
76
|
+
```php
|
|
77
|
+
public function main($params) {
|
|
78
|
+
...
|
|
79
|
+
$arr = $this->dataSet->getEmptyRow();
|
|
80
|
+
addRowLocal($arr); // won't throw error
|
|
81
|
+
...
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
## Development
|
|
85
|
+
> Be sure to uninstall gcli first, with
|
|
86
|
+
`pip uninstall grepsr-cli`
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
git clone git@bitbucket.org:zznixt07/gcli.git grepsrcli
|
|
90
|
+
cd grepsrcli
|
|
91
|
+
pip install -e .
|
|
92
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
grepsrcli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
grepsrcli/main.py,sha256=u62FPNQZ7IK-icIirLCiJxH2TJ-eSajYn_iMHGlG_Iw,2169
|
|
3
|
+
grepsrcli/controllers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
grepsrcli/controllers/base.py,sha256=oieX7zkGBAv6YSujy1lUb6dvGLoqtKJaxE50xpcjtX0,1549
|
|
5
|
+
grepsrcli/controllers/crawler.py,sha256=Mh1vHrTYWUcYThM_AyCVW0e5KAWZKrICcO5uEKD6_yg,18101
|
|
6
|
+
grepsrcli/controllers/generate.py,sha256=0QEjaU70HRqko8QKoC3cgu5MFWc4u-_gpR736bzVq5o,1018
|
|
7
|
+
grepsrcli/controllers/report.py,sha256=YDDarWk6OL5lODqAzws0cZMLNDcaocVxVRmd8uPrlkI,2106
|
|
8
|
+
grepsrcli/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
grepsrcli/core/aws_s3.py,sha256=WRpXqB1lwLJ1qxnwBBn9JLpzRlJ2R8P5Oi3SbqOxOBc,1185
|
|
10
|
+
grepsrcli/core/config.py,sha256=R5xNlwLowzH6vwZC4SjmIdwbgZKA7UpJ3Ix4jcpmYUQ,7454
|
|
11
|
+
grepsrcli/core/exc.py,sha256=bkhZoyJa83ppqutrF0faLlEaF8L3MnNAI5eeO9vFyAg,69
|
|
12
|
+
grepsrcli/core/input_prompts.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
grepsrcli/core/message_log.py,sha256=8MbAGfh2WM32jgMADaUbz1i9qSz2TLfjHUT45Zw7VnY,825
|
|
14
|
+
grepsrcli/core/multiproc_server.py,sha256=NfY7SpbNkGkcjlwQNUgoRYRM6pa7Xll36qlgtLOatNY,5244
|
|
15
|
+
grepsrcli/core/report_api.py,sha256=JDNAYfU13ViHviMa3siPKNYSRbaHw5KgG61a2aBl7hc,885
|
|
16
|
+
grepsrcli/core/sdk_setup.py,sha256=F86HC6c3U52vEfZXVveOxmeL0JuUw_o55XD1Wku3bOU,3221
|
|
17
|
+
grepsrcli/core/test_local.py,sha256=lpmU6-GpbLQmb2g9L6Oft6Ee_uzXNjwXsY2vYtkONdU,6178
|
|
18
|
+
grepsrcli/core/utils.py,sha256=cbOr9B4zzGfCGkl2F_idJ7WtC4UqgtCfbZxYVTmaWb4,11117
|
|
19
|
+
grepsrcli/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
grepsrcli/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
grepsrcli/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
grepsrcli/templates/autocomplete.jinja2,sha256=BIoIXodloNikAPAcZkf0Vj2XH2mD6_iB7_6lbqI5DkI,296
|
|
23
|
+
grepsrcli/templates/autocomplete_zsh.jinja2,sha256=oRG_isrx9bL1hwItxcrdnzdYA08cfMU78ZXplHa5N7c,577
|
|
24
|
+
grepsrcli/templates/composer.jinja2,sha256=QMTKcz8ZeTEiaGsm75KtmBDg8RCi3TIEJntQuiPwLPY,488
|
|
25
|
+
grepsrcli/templates/node_boilerplate.jinja2,sha256=ednowfsqn7MkOu-6bWwG9sRdJoBJm89HaSZ5K9hAyK4,3049
|
|
26
|
+
grepsrcli/templates/php_boilerplate.jinja2,sha256=ThMzrkgCTQ918qJyYtuDumy4JiIH3io3Z8OlenEKEtU,1846
|
|
27
|
+
grepsrcli/templates/php_brp_boilerplate.jinja2,sha256=RFTYYmQceI93CbXVSXsje1ZZYmD_ffGAA4-jMhd7CkY,3087
|
|
28
|
+
grepsrcli/templates/php_vc_boilerplate.jinja2,sha256=8_h-BBnV2vI-JR1FGlODEmlKQgM8oNhzTzzlN0sUDg8,1904
|
|
29
|
+
grepsrcli/templates/py_boilerplate.jinja2,sha256=TFsnff_Vuq1iwZFmeJDW0uzsX6dDIxkBzifJOFbizDk,1753
|
|
30
|
+
grepsr_cli-0.7.4.dist-info/LICENSE.md,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
31
|
+
grepsr_cli-0.7.4.dist-info/METADATA,sha256=HN8Kui_hW1af_vLxyd7WUR9TEEd7SlrrmCXJ4SwfZRk,3006
|
|
32
|
+
grepsr_cli-0.7.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
33
|
+
grepsr_cli-0.7.4.dist-info/entry_points.txt,sha256=u-xyDCaDmX6R3h_bh3gehaQ4qUniDW29gOSerW4QjGw,45
|
|
34
|
+
grepsr_cli-0.7.4.dist-info/top_level.txt,sha256=jjRVZvVITG5pRVj8L_GTLIiQ_4yIuxk1suTKtTMiwow,10
|
|
35
|
+
grepsr_cli-0.7.4.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
grepsrcli
|
grepsrcli/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from os import system
|
|
2
|
+
from grepsrcli.core.message_log import Log
|
|
3
|
+
from cement import Controller, ex
|
|
4
|
+
import pkg_resources
|
|
5
|
+
from grepsrcli.core.sdk_setup import SDKSetup
|
|
6
|
+
from grepsrcli.core.config import save_config
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
version = pkg_resources.require("grepsr-cli")[0].version
|
|
10
|
+
|
|
11
|
+
VERSION_BANNER = """
|
|
12
|
+
gcli: cli tool for grepsr developers verion: %s
|
|
13
|
+
""" % (version)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Base(Controller):
|
|
17
|
+
|
|
18
|
+
class Meta:
|
|
19
|
+
label = 'base'
|
|
20
|
+
|
|
21
|
+
arguments = [
|
|
22
|
+
(['-v', '--version'],
|
|
23
|
+
{'action': 'version',
|
|
24
|
+
'version': VERSION_BANNER}),
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
def _default(self):
|
|
28
|
+
self.app.args.print_help()
|
|
29
|
+
|
|
30
|
+
@ex(help="setup SDKs for crawling",
|
|
31
|
+
arguments=[
|
|
32
|
+
(['-t', '--type'], {'action': 'store', 'dest': 'type'}),
|
|
33
|
+
(['--dryrun'], {'action': 'store_true', 'dest': 'dryrun'}),
|
|
34
|
+
(['--sdk'], {'action': 'store', 'dest': 'sdk'}),
|
|
35
|
+
]
|
|
36
|
+
)
|
|
37
|
+
def setup_sdk(self):
|
|
38
|
+
|
|
39
|
+
if self.app.pargs.type is not None:
|
|
40
|
+
SDKSetup(self.app.pargs.type,
|
|
41
|
+
self.app.pargs.dryrun, self.app.pargs.sdk)
|
|
42
|
+
else:
|
|
43
|
+
Log.error(
|
|
44
|
+
"Please select the platform to setup the sdk.\nExample: gcli setup-sdk -t php|php_next")
|
|
45
|
+
|
|
46
|
+
@ex(help="Update configuration for gcli",
|
|
47
|
+
arguments=[
|
|
48
|
+
(['--update'], {'action': 'store_true', 'dest': 'update'}),
|
|
49
|
+
]
|
|
50
|
+
)
|
|
51
|
+
def configure(self):
|
|
52
|
+
if(self.app.pargs.update == True):
|
|
53
|
+
save_config(update=True)
|
|
54
|
+
else:
|
|
55
|
+
save_config(update=False)
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
from os import system, path
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import subprocess
|
|
5
|
+
import multiprocessing
|
|
6
|
+
import signal
|
|
7
|
+
import json
|
|
8
|
+
import pathlib
|
|
9
|
+
from semver import VersionInfo
|
|
10
|
+
from cement import Controller, ex
|
|
11
|
+
from ..core.config import load_config
|
|
12
|
+
from ..core.utils import (
|
|
13
|
+
create_boilerplate,
|
|
14
|
+
render_boilerplate,
|
|
15
|
+
get_plugin_info,
|
|
16
|
+
get_plugin_path,
|
|
17
|
+
show_schema,
|
|
18
|
+
user_input,
|
|
19
|
+
insert_all_chained_dependencies
|
|
20
|
+
)
|
|
21
|
+
from ..core.test_local import TestLocal
|
|
22
|
+
from ..core.message_log import Log
|
|
23
|
+
from ..core.aws_s3 import S3
|
|
24
|
+
|
|
25
|
+
class CrawlerBase(Controller):
|
|
26
|
+
class Meta:
|
|
27
|
+
label = 'crawler_base'
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Crawler(Controller):
|
|
31
|
+
config = load_config('config.yml')
|
|
32
|
+
|
|
33
|
+
class Meta:
|
|
34
|
+
label = 'crawler'
|
|
35
|
+
stacked_on = 'crawler_base'
|
|
36
|
+
stacked_type = 'nested'
|
|
37
|
+
|
|
38
|
+
@ex(
|
|
39
|
+
help="test a plugin locally",
|
|
40
|
+
aliases=['tst'],
|
|
41
|
+
arguments=[
|
|
42
|
+
(['-s'], {
|
|
43
|
+
'action': 'store',
|
|
44
|
+
'dest': 'plugin_name',
|
|
45
|
+
'help': "The name of the service/plugin to run locally"
|
|
46
|
+
}),
|
|
47
|
+
(['-p'], {
|
|
48
|
+
'action': 'store',
|
|
49
|
+
'dest': 'params',
|
|
50
|
+
'help': 'Parameters (as JSON) to pass to the arguments of the main function',
|
|
51
|
+
}),
|
|
52
|
+
(['-m'], {
|
|
53
|
+
'action': 'store',
|
|
54
|
+
'dest': 'multi_proc_mode',
|
|
55
|
+
'help': 'Multiprocess mode',
|
|
56
|
+
}),
|
|
57
|
+
(['--params-file'], {
|
|
58
|
+
'action': 'store',
|
|
59
|
+
'dest': 'params_file',
|
|
60
|
+
'help': 'JSON file location containing parameters to pass to the arguments of the main function'
|
|
61
|
+
}),
|
|
62
|
+
|
|
63
|
+
]
|
|
64
|
+
)
|
|
65
|
+
def test(self):
|
|
66
|
+
plugin_name = self.app.pargs.plugin_name
|
|
67
|
+
main_fn_params = self.app.pargs.params
|
|
68
|
+
main_fn_params_file = self.app.pargs.params_file
|
|
69
|
+
is_multi_proc = self.app.pargs.multi_proc_mode
|
|
70
|
+
|
|
71
|
+
platforms = ['php', 'php_next']
|
|
72
|
+
proc = None
|
|
73
|
+
for platform in platforms:
|
|
74
|
+
if platform in self.config:
|
|
75
|
+
plugin_path = get_plugin_path(plugin_name, type=platform)
|
|
76
|
+
if plugin_path:
|
|
77
|
+
base_path = pathlib.Path(get_plugin_path(plugin_name, type=platform)).parent
|
|
78
|
+
if is_multi_proc == '1':
|
|
79
|
+
from ..core import multiproc_server
|
|
80
|
+
proc = multiprocessing.Process(target=multiproc_server.start, args=[])
|
|
81
|
+
proc.start()
|
|
82
|
+
try:
|
|
83
|
+
TestLocal(type=platform, base_path=base_path, plugin_name=plugin_name, params=main_fn_params, params_file=main_fn_params_file, is_multi_proc=is_multi_proc)
|
|
84
|
+
except json.JSONDecodeError as e:
|
|
85
|
+
self.app.log.error(f"Error decoding params as JSON. {e}")
|
|
86
|
+
self.app.exit_code = 10
|
|
87
|
+
except FileNotFoundError as e:
|
|
88
|
+
self.app.log.error(f"Params file: `{main_fn_params_file}` not found. {e}")
|
|
89
|
+
self.app.exit_code = 20
|
|
90
|
+
break
|
|
91
|
+
else:
|
|
92
|
+
self.app.log.error(f"path: {plugin_name} not found!")
|
|
93
|
+
self.app.exit_code = 127
|
|
94
|
+
if proc:
|
|
95
|
+
print('terminating server proc', flush=True)
|
|
96
|
+
|
|
97
|
+
'''these 2 methods cannot kill the currently running process on linux.
|
|
98
|
+
Although they will raise an Exception on the target server process,
|
|
99
|
+
the child process of that script cannot be terminated from it.
|
|
100
|
+
'''
|
|
101
|
+
# proc.terminate()
|
|
102
|
+
# proc.kill()
|
|
103
|
+
|
|
104
|
+
'''instead killing whole process group works on linux.
|
|
105
|
+
The OS handles this, killing all the processes at once.
|
|
106
|
+
'''
|
|
107
|
+
pgid = os.getpgid(os.getpid())
|
|
108
|
+
if pgid == 1:
|
|
109
|
+
os.kill(os.getpid(), signal.SIGINT)
|
|
110
|
+
else:
|
|
111
|
+
os.killpg(os.getpgid(os.getpid()), signal.SIGINT)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@ex(
|
|
115
|
+
help="performs git pull to update the codebase",
|
|
116
|
+
arguments=[
|
|
117
|
+
(['-t', '--type'], {
|
|
118
|
+
'action': 'store',
|
|
119
|
+
'dest': 'type',
|
|
120
|
+
'help': "Platform type: php|node|python|php_next"
|
|
121
|
+
})
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
def sync(self):
|
|
125
|
+
if(self.app.pargs.type):
|
|
126
|
+
type = self.app.pargs.type
|
|
127
|
+
crawler_paths = self.config[type]['paths']
|
|
128
|
+
|
|
129
|
+
for crawler_path in crawler_paths:
|
|
130
|
+
Log.info(f"Syncing: {crawler_path}")
|
|
131
|
+
system(
|
|
132
|
+
f"""cd {crawler_path} && git pull origin master""")
|
|
133
|
+
else:
|
|
134
|
+
Log.warn("Please enter a valid type")
|
|
135
|
+
|
|
136
|
+
@ex(
|
|
137
|
+
help="create basic boilerplate for plugins ",
|
|
138
|
+
arguments=[
|
|
139
|
+
(['-s'], {
|
|
140
|
+
"action": "store",
|
|
141
|
+
"dest": "plugin_name",
|
|
142
|
+
"help": "the name of the plugin to be created"
|
|
143
|
+
}), (['-pid'], {
|
|
144
|
+
"action": "store",
|
|
145
|
+
"dest": 'pid',
|
|
146
|
+
"help": "the project id of the plugin"
|
|
147
|
+
}), (
|
|
148
|
+
['-t', '--template'], {
|
|
149
|
+
"action": "store",
|
|
150
|
+
"dest": 'template',
|
|
151
|
+
"help": "choose a template to boilerplate php|node|py|vc defaults to php"
|
|
152
|
+
}
|
|
153
|
+
), (
|
|
154
|
+
['--path'], {
|
|
155
|
+
'action': "store",
|
|
156
|
+
'dest': 'folder_path',
|
|
157
|
+
'help': 'the path of the folder where the plugin will reside'
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
]
|
|
161
|
+
)
|
|
162
|
+
def create(self):
|
|
163
|
+
|
|
164
|
+
template = self.app.pargs.template
|
|
165
|
+
|
|
166
|
+
if self.app.pargs.folder_path is not None:
|
|
167
|
+
folder_path = self.app.pargs.folder_path
|
|
168
|
+
folder_path = folder_path.rstrip('/')
|
|
169
|
+
folder_path = path.expanduser(folder_path)
|
|
170
|
+
else:
|
|
171
|
+
folder_path = pathlib.Path().resolve()
|
|
172
|
+
folder_path = str(folder_path)
|
|
173
|
+
|
|
174
|
+
if self.app.pargs.plugin_name is not None:
|
|
175
|
+
plugin_name = self.app.pargs.plugin_name
|
|
176
|
+
else:
|
|
177
|
+
self.app.log.error(
|
|
178
|
+
"cannot create boilerplate file without plugin's name")
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
if self.app.pargs.pid is not None:
|
|
182
|
+
pid = self.app.pargs.pid
|
|
183
|
+
else:
|
|
184
|
+
pid = '***'
|
|
185
|
+
|
|
186
|
+
data = {
|
|
187
|
+
'plugin_name': plugin_name,
|
|
188
|
+
'pid': pid
|
|
189
|
+
}
|
|
190
|
+
plugin_path = folder_path + '/' + plugin_name
|
|
191
|
+
if template == 'vc':
|
|
192
|
+
create_boilerplate(
|
|
193
|
+
plugin_path, "php_vc_boilerplate.jinja2", data, 'php')
|
|
194
|
+
|
|
195
|
+
elif template == 'py':
|
|
196
|
+
create_boilerplate(
|
|
197
|
+
plugin_path, "py_boilerplate.jinja2", data, 'py')
|
|
198
|
+
|
|
199
|
+
elif template == 'node':
|
|
200
|
+
create_boilerplate(
|
|
201
|
+
plugin_path, "node_boilerplate.jinja2", data, 'js')
|
|
202
|
+
elif template == 'brp':
|
|
203
|
+
create_boilerplate(
|
|
204
|
+
plugin_path, "php_brp_boilerplate.jinja2", data, 'php')
|
|
205
|
+
else:
|
|
206
|
+
create_boilerplate(
|
|
207
|
+
plugin_path, "php_boilerplate.jinja2", data, 'php')
|
|
208
|
+
|
|
209
|
+
@ex(
|
|
210
|
+
help="deploy a specific plugin to live with versioning",
|
|
211
|
+
arguments=[
|
|
212
|
+
(['-s'], {
|
|
213
|
+
"action": "store",
|
|
214
|
+
"dest": 'plugin_name'
|
|
215
|
+
}), (['-m'], {
|
|
216
|
+
"action": "store",
|
|
217
|
+
"dest": "message"
|
|
218
|
+
}), (['-st', '--stable'], {
|
|
219
|
+
"action": "store_true",
|
|
220
|
+
"dest": "stable_flag"
|
|
221
|
+
}), (['--patch'], {
|
|
222
|
+
"action": "store_true",
|
|
223
|
+
"dest": "patch_flag"
|
|
224
|
+
}), (['--minor'], {
|
|
225
|
+
"action": "store_true",
|
|
226
|
+
"dest": "minor_flag",
|
|
227
|
+
"help": "set major of a version"
|
|
228
|
+
}), (['--major'], {
|
|
229
|
+
"action": "store_true",
|
|
230
|
+
"dest": "major_flag"
|
|
231
|
+
}),
|
|
232
|
+
(['--verbose'], {
|
|
233
|
+
"action": 'store_true',
|
|
234
|
+
"dest": "verbose"
|
|
235
|
+
})
|
|
236
|
+
]
|
|
237
|
+
)
|
|
238
|
+
def deploy(self):
|
|
239
|
+
|
|
240
|
+
toolbar_width = 50
|
|
241
|
+
verbose_mode = False
|
|
242
|
+
|
|
243
|
+
try:
|
|
244
|
+
if self.config['deploy']['verbose'] == True or self.app.pargs.verbose == True:
|
|
245
|
+
verbose_mode = True
|
|
246
|
+
except:
|
|
247
|
+
if self.app.pargs.verbose == True:
|
|
248
|
+
verbose_mode = True
|
|
249
|
+
|
|
250
|
+
input_plugin_name = self.app.pargs.plugin_name
|
|
251
|
+
deploy_message = self.app.pargs.message
|
|
252
|
+
|
|
253
|
+
if input_plugin_name is None:
|
|
254
|
+
self.app.log.error("cannot deploy without service code")
|
|
255
|
+
return False
|
|
256
|
+
if deploy_message is None:
|
|
257
|
+
self.app.log.error("cannot deploy without deploy message")
|
|
258
|
+
return False
|
|
259
|
+
|
|
260
|
+
if self.app.pargs.stable_flag:
|
|
261
|
+
deploy_type = "DEPLOY-STABLE"
|
|
262
|
+
else:
|
|
263
|
+
deploy_type = "DEPLOY"
|
|
264
|
+
|
|
265
|
+
major_flag = self.app.pargs.major_flag
|
|
266
|
+
minor_flag = self.app.pargs.minor_flag
|
|
267
|
+
|
|
268
|
+
plugin_names = False
|
|
269
|
+
if ',' in input_plugin_name:
|
|
270
|
+
plugin_names = input_plugin_name.split(',')
|
|
271
|
+
|
|
272
|
+
if plugin_names == False:
|
|
273
|
+
plugin_names = []
|
|
274
|
+
plugin_names.append(input_plugin_name)
|
|
275
|
+
|
|
276
|
+
for plugin_name in plugin_names:
|
|
277
|
+
plugin_name = plugin_name.strip()
|
|
278
|
+
plugin_dir_path = get_plugin_path(plugin_name, all_types=True)
|
|
279
|
+
|
|
280
|
+
if not plugin_dir_path:
|
|
281
|
+
self.app.log.error(f'Could not find plugin: {plugin_name}')
|
|
282
|
+
continue
|
|
283
|
+
|
|
284
|
+
plugin_info = get_plugin_info(plugin_dir_path)
|
|
285
|
+
if plugin_info:
|
|
286
|
+
base_class = plugin_info['base_class']
|
|
287
|
+
if base_class != 'Vtx_Service_Plugin':
|
|
288
|
+
if base_class not in plugin_info['dependencies']:
|
|
289
|
+
msg = f'Plugin extends {base_class} but does not declare it as a dependency.'
|
|
290
|
+
self.app.log.warning(msg)
|
|
291
|
+
if user_input(f'[Experimental] Do you want to automatically add dependencies?') == 'Y':
|
|
292
|
+
insert_all_chained_dependencies(plugin_name)
|
|
293
|
+
go_fwd = user_input(f'Do you want to continue?')
|
|
294
|
+
if go_fwd == 'N':
|
|
295
|
+
continue
|
|
296
|
+
# add .version or update .version
|
|
297
|
+
version_path = '{}/.version'.format(plugin_dir_path)
|
|
298
|
+
if path.exists(version_path):
|
|
299
|
+
with open(version_path, 'r') as f:
|
|
300
|
+
version_info = VersionInfo.parse(f.read())
|
|
301
|
+
if(major_flag):
|
|
302
|
+
version_info = version_info.next_version(
|
|
303
|
+
part='major')
|
|
304
|
+
elif(minor_flag):
|
|
305
|
+
version_info = version_info.next_version(
|
|
306
|
+
part='minor')
|
|
307
|
+
else:
|
|
308
|
+
version_info = version_info.bump_patch()
|
|
309
|
+
|
|
310
|
+
version_info = str(version_info)
|
|
311
|
+
with open(version_path, 'w') as w:
|
|
312
|
+
w.write(version_info)
|
|
313
|
+
|
|
314
|
+
self.app.log.info(
|
|
315
|
+
"[{}] [{}] {}".format(deploy_type, version_info, deploy_message))
|
|
316
|
+
else:
|
|
317
|
+
if plugin_info:
|
|
318
|
+
# if its already deployed then the service probabily works fine.
|
|
319
|
+
# if its the first deploy, we annoy the user.
|
|
320
|
+
if not plugin_info.get('pid_forced'):
|
|
321
|
+
# TODO: maybe read all files and check if any service already has pid in which case force ought to be required.
|
|
322
|
+
self.app.log.warning("PID was not forced. This may cause issues.")
|
|
323
|
+
|
|
324
|
+
with open(version_path, 'w') as f:
|
|
325
|
+
if major_flag:
|
|
326
|
+
version_info = "1.0.0"
|
|
327
|
+
elif minor_flag:
|
|
328
|
+
version_info = "0.1.0"
|
|
329
|
+
else:
|
|
330
|
+
version_info = "0.0.1"
|
|
331
|
+
|
|
332
|
+
f.write(version_info)
|
|
333
|
+
|
|
334
|
+
self.app.log.info(
|
|
335
|
+
"[{}] [{}] {}".format(deploy_type, version_info, deploy_message))
|
|
336
|
+
|
|
337
|
+
if verbose_mode is False:
|
|
338
|
+
sys.stdout.write(
|
|
339
|
+
"Deploying: [%s]" % (" " * toolbar_width))
|
|
340
|
+
sys.stdout.write("\b" * (toolbar_width + 1))
|
|
341
|
+
sys.stdout.flush()
|
|
342
|
+
try:
|
|
343
|
+
quiet_mode = "" if verbose_mode else "--quiet"
|
|
344
|
+
cd_to_repo_cmd = f"cd {plugin_dir_path} && cd .."
|
|
345
|
+
# dont pop stash. cuz if there is a merge conflict, good luck with that.
|
|
346
|
+
# instead apply stash and if and only if everything has passed, then drop the stash.
|
|
347
|
+
# TODO: only apply stash if git stash stashed > 0 files.
|
|
348
|
+
cmds = [
|
|
349
|
+
cd_to_repo_cmd,
|
|
350
|
+
f'git stash --include-untracked {quiet_mode}',
|
|
351
|
+
f'git pull origin master {quiet_mode}',
|
|
352
|
+
f'git stash apply {quiet_mode}',
|
|
353
|
+
f'git add {plugin_name}/',
|
|
354
|
+
f'git commit -m "[{deploy_type}] [{version_info}] {deploy_message}" {quiet_mode}',
|
|
355
|
+
f'git push origin master {quiet_mode}',
|
|
356
|
+
]
|
|
357
|
+
post_deploy_cmds = [
|
|
358
|
+
cd_to_repo_cmd,
|
|
359
|
+
f'git stash drop {quiet_mode}'
|
|
360
|
+
]
|
|
361
|
+
try:
|
|
362
|
+
multiplier = toolbar_width // len(cmds)
|
|
363
|
+
except ZeroDivisionError:
|
|
364
|
+
multiplier = 0
|
|
365
|
+
if verbose_mode:
|
|
366
|
+
multiplier = 0
|
|
367
|
+
# just echo some dashes after each command for progress. lol.
|
|
368
|
+
echoer = 'echo -n ' + '-' * multiplier
|
|
369
|
+
# .join() only does n-1 additions. Hence add a echoer at last. And then echo remaining to fill the bar (caused by floor division)
|
|
370
|
+
cmd = f' && {echoer} &&'.join(cmds) + f' && {echoer}' + f' && echo -n {"-" * (toolbar_width - (len(cmds) * multiplier))}'
|
|
371
|
+
try:
|
|
372
|
+
proc = subprocess.run(cmd, shell=True, check=True, timeout=300)
|
|
373
|
+
if proc.returncode == 0:
|
|
374
|
+
proc = subprocess.run(' && '.join(post_deploy_cmds), shell=True)
|
|
375
|
+
if proc.returncode != 0:
|
|
376
|
+
self.app.log.warning('Failed to drop the latest stash.')
|
|
377
|
+
|
|
378
|
+
except subprocess.TimeoutExpired:
|
|
379
|
+
self.app.log.error(f'Timeout occured when deploying {plugin_name}')
|
|
380
|
+
|
|
381
|
+
except subprocess.CalledProcessError as e:
|
|
382
|
+
self.app.log.error(f'There was a problem deploying {plugin_name}')
|
|
383
|
+
|
|
384
|
+
return
|
|
385
|
+
|
|
386
|
+
if verbose_mode is False:
|
|
387
|
+
sys.stdout.flush()
|
|
388
|
+
sys.stdout.write("\n")
|
|
389
|
+
|
|
390
|
+
show_schema(plugin_dir_path)
|
|
391
|
+
|
|
392
|
+
try:
|
|
393
|
+
app_url = f'https://platform.grepsr.com/projects/{plugin_info["pid"]}'
|
|
394
|
+
self.app.log.info(f"App Url: {app_url}")
|
|
395
|
+
except KeyError:
|
|
396
|
+
self.app.log.warning(f"Cannot find pid in plugin, please find the project's url manually")
|
|
397
|
+
|
|
398
|
+
self.app.log.info(
|
|
399
|
+
f"Plugin: {plugin_name} deployed successfully")
|
|
400
|
+
|
|
401
|
+
@ex(
|
|
402
|
+
help="use a base plugin from: https://bitbucket.org/grepsr/vortex-plugins-services-base",
|
|
403
|
+
arguments=[
|
|
404
|
+
(['-s'], {
|
|
405
|
+
"help": "name of the base crawler you want to use",
|
|
406
|
+
"action": "store",
|
|
407
|
+
"dest": "base_plugin_name"
|
|
408
|
+
}),
|
|
409
|
+
(['-t'], {
|
|
410
|
+
"help": "name of target crawler that you want to use",
|
|
411
|
+
"action": "store",
|
|
412
|
+
"dest": "plugin_name"
|
|
413
|
+
})
|
|
414
|
+
]
|
|
415
|
+
)
|
|
416
|
+
def use_basecrawler(self):
|
|
417
|
+
|
|
418
|
+
s3 = S3(aws_id=self.config['aws_access_key_id'],
|
|
419
|
+
aws_sec_key=self.config['aws_secret_access_key'])
|
|
420
|
+
|
|
421
|
+
version = None
|
|
422
|
+
base_plugin_name = self.app.pargs.base_plugin_name
|
|
423
|
+
target_plugin_name = self.app.pargs.plugin_name
|
|
424
|
+
|
|
425
|
+
if(base_plugin_name is None or target_plugin_name is None):
|
|
426
|
+
Log.error(
|
|
427
|
+
"Please Enter base crawler and target cralwers.\nUse gcli crawler use-basecrawler -h for more information")
|
|
428
|
+
return
|
|
429
|
+
|
|
430
|
+
if('-' in base_plugin_name):
|
|
431
|
+
version = base_plugin_name.split('-')[1]
|
|
432
|
+
base_plugin_name = base_plugin_name.split('-')[0]
|
|
433
|
+
|
|
434
|
+
# to check if there is a base-plugin in thier gcli settings ...
|
|
435
|
+
base_plugin_dir_path = get_plugin_path(
|
|
436
|
+
base_plugin_name, type='php')
|
|
437
|
+
|
|
438
|
+
target_plugin_path = get_plugin_path(
|
|
439
|
+
target_plugin_name, type='php'
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
if(version is None and base_plugin_dir_path):
|
|
443
|
+
f = open(f"{base_plugin_dir_path}/.version", mode='r')
|
|
444
|
+
version = f.read()
|
|
445
|
+
f.close()
|
|
446
|
+
|
|
447
|
+
if(version is None):
|
|
448
|
+
Log.error(
|
|
449
|
+
"Please Specify the version of base crawler that you want to use")
|
|
450
|
+
return
|
|
451
|
+
|
|
452
|
+
if(target_plugin_path):
|
|
453
|
+
Log.info(
|
|
454
|
+
f'Getting Secure Url of target plugin: {base_plugin_name}, {version}')
|
|
455
|
+
|
|
456
|
+
presigned_url = s3.get_secure_url(bucket='crawler-plugins',
|
|
457
|
+
filename=f'php/vortex-plugins-services-base/{base_plugin_name}/{base_plugin_name}-{version}.tar.gz')
|
|
458
|
+
|
|
459
|
+
data = {
|
|
460
|
+
'presigned_url': presigned_url,
|
|
461
|
+
'plugin_name': base_plugin_name,
|
|
462
|
+
'version': version
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
render_boilerplate(boilerplate='composer.jinja2', data=data,
|
|
466
|
+
destination_path=target_plugin_path + '/composer.json')
|
|
467
|
+
system(
|
|
468
|
+
f""" cd {target_plugin_path} && composer install""")
|
|
469
|
+
else:
|
|
470
|
+
Log.error(f"Target plugin: {target_plugin_name} not found")
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
@ex(
|
|
474
|
+
help="start multiprocess facilitation server",
|
|
475
|
+
arguments=[]
|
|
476
|
+
)
|
|
477
|
+
def multiprocess(self):
|
|
478
|
+
from ..core import multiproc_server
|
|
479
|
+
multiproc_server.start()
|
|
480
|
+
|