# cmdbox
- It is a command line application with a plugin mechanism.
- Documentation is [here](https://hamacom2004jp.github.io/cmdbox/).
- With cmdbox, you can easily implement commands with complex options.
- The implemented commands can be called from the CLI / RESTAPI / Web screen.
- The implemented commands can be executed on a remote server via redis.
# Install
- Install cmdbox with the following command.
```bash
pip install cmdbox
cmdbox -v
```
- Also install the docker version of the redis server.
```bash
docker run -p 6379:6379 --name redis -it ubuntu/redis:latest
```
# Tutorial
- Open the ```.sample/sample_project``` folder in the current directory with VSCode.
![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme001.png)
- Install dependent libraries.
```bash
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
```
- Run the project.
![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme002.png)
- The localhost web screen will open.
![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme003.png)
- Enter ```user01 / user01``` for the initial ID and PW to sign in.
- Using this web screen, you can easily execute the commands implemented in cmdbox.
![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme004.png)
- Let's look at the command to get a list of files as an example.
- Press the plus button under Commands to open the Add dialog.
- Then enter the following.
![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme005.png)
- Press the ```Save``` button once and then press the ```Execute``` button.
- The results of the command execution are displayed.
![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme006.png)
- Open the saved ```client_time``` and press the ```Raw``` button.
- You will see how to execute the same command on the command line; the RESTAPI URL is also displayed.
![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme007.png)
## How to implement a new command using cmdbox
- Under the ```sample/app/features/cli``` folder, you will find an implementation of the ```client_time``` mentioned earlier.
- The implementation is as follows. (Slightly abbreviated display)
- Create the following code and save it in the ```sample/app/features/cli``` folder.
```python
from cmdbox.app import common, feature
from typing import Dict, Any, Tuple, Union, List
import argparse
import datetime
import logging
class ClientTime(feature.Feature):
def get_mode(self) -> Union[str, List[str]]:
return "client"
def get_cmd(self):
return 'time'
def get_option(self):
return dict(
type="str", default=None, required=False, multi=False, hide=False, use_redis=self.USE_REDIS_FALSE,
discription_ja="クライアント側の現在時刻を表示します。",
discription_en="Displays the current time at the client side.",
choice=[
dict(opt="timedelta", type="int", default=9, required=False, multi=False, hide=False, choice=None,
discription_ja="時差の時間数を指定します。",
discription_en="Specify the number of hours of time difference."),
])
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
tz = datetime.timezone(datetime.timedelta(hours=args.timedelta))
dt = datetime.datetime.now(tz)
ret = dict(success=dict(data=dt.strftime('%Y-%m-%d %H:%M:%S')))
common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)
if 'success' not in ret:
return 1, ret, None
return 0, ret, None
```
- Open the file ```sample/extensions/features.yml```. The file should look something like this.
- This file specifies where new commands are to be read.
- For example, if you want to add a package to read, add a new ```package``` and ```prefix``` to ```features.cli```.
- Note that ```features.web``` can be used to add a new web screen.
- If you only want to call commands added in ```features.cli``` via RESTAPI, no additional implementation is needed in ```features.web```.
```yml
features:
cli:
- package: sample.app.features.cli
prefix: sample_
web:
- package: sample.app.features.web
prefix: sample_web_
args:
cli:
- rule:
mode: web
default:
coercion:
assets:
- f"{Path(self.ver.__file__).parent / 'web' / 'assets'}"
doc_root: f"{Path(self.ver.__file__).parent / 'web'}"
- rule:
mode: gui
default:
coercion:
assets:
- f"{Path(self.ver.__file__).parent / 'web' / 'assets'}"
doc_root: f"{Path(self.ver.__file__).parent / 'web'}"
```
- The following files should also be known when using commands on the web screen or RESTAPI.
- Open the file ```sample/extensions/user_list.yml```. The file should look something like this.
- This file manages the users and groups that are allowed Web access and their rules.
- The rule of the previous command is ```allow``` for users in the ```user``` group in ```cmdrule.rules```.
```yml
users:
- uid: 1
name: admin
password: XXXXXXXXXXX
hash: plain
groups: [admin]
email: admin@aaa.bbb.jp
- uid: 101
name: user01
password: XXXXXXXXXXX
hash: md5
groups: [user]
email: user01@aaa.bbb.jp
- uid: 102
name: user02
password: XXXXXXXXXXX
hash: sha1
groups: [readonly]
email: user02@aaa.bbb.jp
- uid: 103
name: user03
password: XXXXXXXXXXX
hash: sha256
groups: [editor]
email: user03@aaa.bbb.jp
groups:
- gid: 1
name: admin
- gid: 101
name: user
- gid: 102
name: readonly
parent: user
- gid: 103
name: editor
parent: user
cmdrule:
policy: deny # allow, deny
rules:
- groups: [admin]
rule: allow
- groups: [user]
mode: client
cmds: [file_download, file_list, server_info]
rule: allow
- groups: [user]
mode: server
cmds: [list]
rule: allow
- groups: [editor]
mode: client
cmds: [file_copy, file_mkdir, file_move, file_remove, file_rmdir, file_upload]
rule: allow
pathrule:
policy: deny # allow, deny
rules:
- groups: [admin]
paths: [/]
rule: allow
- groups: [user]
paths: [/signin, /assets, /bbforce_cmd, /copyright, /dosignin, /dosignout,
/exec_cmd, /exec_pipe, /filer, /gui, /get_server_opt, /usesignout, /versions_cmdbox, /versions_used]
rule: allow
- groups: [readonly]
paths: [/gui/del_cmd, /gui/del_pipe, /gui/save_cmd, /gui/save_pipe]
rule: deny
- groups: [editor]
paths: [/gui/del_cmd, /gui/del_pipe, /gui/save_cmd, /gui/save_pipe]
rule: allow
oauth2:
providers:
google:
enabled: false
client_id: XXXXXXXXXXX
client_secret: XXXXXXXXXXX
redirect_uri: https://localhost:8443/oauth2/google/callback
scope: ['email']
note:
- https://developers.google.com/identity/protocols/oauth2/web-server?hl=ja#httprest
github:
enabled: false
client_id: XXXXXXXXXXX
client_secret: XXXXXXXXXXX
redirect_uri: https://localhost:8443/oauth2/github/callback
scope: ['user:email']
note:
- https://docs.github.com/ja/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#scopes
```
- See the documentation for references to each file.
- Documentation is [here](https://hamacom2004jp.github.io/cmdbox/).
# Lisence
This project is licensed under the MIT License, see the LICENSE file for details
Raw data
{
"_id": null,
"home_page": "https://github.com/hamacom2004jp/cmdbox",
"name": "cmdbox",
"maintainer": "hamacom2004jp",
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "hamacom2004jp@gmail.com",
"keywords": "cli restapi redis fastapi",
"author": "hamacom2004jp",
"author_email": "hamacom2004jp@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/94/e3/832c3222da122d6d6c148c8d3be0068bf92ca636fbe4764c7c1f4fc2cb05/cmdbox-0.2.7.3.tar.gz",
"platform": null,
"description": "# cmdbox\r\n\r\n- It is a command line application with a plugin mechanism.\r\n- Documentation is [here](https://hamacom2004jp.github.io/cmdbox/).\r\n- With cmdbox, you can easily implement commands with complex options.\r\n- The implemented commands can be called from the CLI / RESTAPI / Web screen.\r\n- The implemented commands can be executed on a remote server via redis.\r\n\r\n# Install\r\n\r\n- Install cmdbox with the following command.\r\n\r\n```bash\r\npip install cmdbox\r\ncmdbox -v\r\n```\r\n\r\n- Also install the docker version of the redis server.\r\n\r\n```bash\r\ndocker run -p 6379:6379 --name redis -it ubuntu/redis:latest\r\n```\r\n\r\n# Tutorial\r\n\r\n- Open the ```.sample/sample_project``` folder in the current directory with VSCode.\r\n\r\n![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme001.png)\r\n\r\n- Install dependent libraries.\r\n\r\n```bash\r\npython -m venv .venv\r\n. .venv/bin/activate\r\npip install -r requirements.txt\r\n```\r\n\r\n- Run the project.\r\n\r\n![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme002.png)\r\n\r\n- The localhost web screen will open.\r\n\r\n![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme003.png)\r\n\r\n- Enter ```user01 / user01``` for the initial ID and PW to sign in.\r\n- Using this web screen, you can easily execute the commands implemented in cmdbox.\r\n\r\n![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme004.png)\r\n\r\n- Let's look at the command to get a list of files as an example.\r\n- Press the plus button under Commands to open the Add dialog.\r\n- Then enter the following.\r\n\r\n![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme005.png)\r\n\r\n- Press the ```Save``` button once and then press the ```Execute``` button.\r\n- The results of the command execution are displayed.\r\n\r\n![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme006.png)\r\n\r\n- Open the saved ```client_time``` and press the ```Raw``` button.\r\n- You will see how to execute the same command on the command line; the RESTAPI URL is also displayed.\r\n\r\n![image](https://github.com/hamacom2004jp/cmdbox/raw/main/docs_src/static/ss/readme007.png)\r\n\r\n\r\n## How to implement a new command using cmdbox\r\n\r\n- Under the ```sample/app/features/cli``` folder, you will find an implementation of the ```client_time``` mentioned earlier.\r\n- The implementation is as follows. (Slightly abbreviated display)\r\n- Create the following code and save it in the ```sample/app/features/cli``` folder.\r\n\r\n```python\r\nfrom cmdbox.app import common, feature\r\nfrom typing import Dict, Any, Tuple, Union, List\r\nimport argparse\r\nimport datetime\r\nimport logging\r\n\r\n\r\nclass ClientTime(feature.Feature):\r\n def get_mode(self) -> Union[str, List[str]]:\r\n return \"client\"\r\n\r\n def get_cmd(self):\r\n return 'time'\r\n\r\n def get_option(self):\r\n return dict(\r\n type=\"str\", default=None, required=False, multi=False, hide=False, use_redis=self.USE_REDIS_FALSE,\r\n discription_ja=\"\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u5074\u306e\u73fe\u5728\u6642\u523b\u3092\u8868\u793a\u3057\u307e\u3059\u3002\",\r\n discription_en=\"Displays the current time at the client side.\",\r\n choice=[\r\n dict(opt=\"timedelta\", type=\"int\", default=9, required=False, multi=False, hide=False, choice=None,\r\n discription_ja=\"\u6642\u5dee\u306e\u6642\u9593\u6570\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\",\r\n discription_en=\"Specify the number of hours of time difference.\"),\r\n ])\r\n\r\n def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:\r\n tz = datetime.timezone(datetime.timedelta(hours=args.timedelta))\r\n dt = datetime.datetime.now(tz)\r\n ret = dict(success=dict(data=dt.strftime('%Y-%m-%d %H:%M:%S')))\r\n common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)\r\n if 'success' not in ret:\r\n return 1, ret, None\r\n return 0, ret, None\r\n```\r\n\r\n- Open the file ```sample/extensions/features.yml```. The file should look something like this.\r\n- This file specifies where new commands are to be read.\r\n- For example, if you want to add a package to read, add a new ```package``` and ```prefix``` to ```features.cli```.\r\n- Note that ```features.web``` can be used to add a new web screen.\r\n- If you only want to call commands added in ```features.cli``` via RESTAPI, no additional implementation is needed in ```features.web```.\r\n\r\n\r\n```yml\r\nfeatures:\r\n cli:\r\n - package: sample.app.features.cli\r\n prefix: sample_\r\n web:\r\n - package: sample.app.features.web\r\n prefix: sample_web_\r\nargs:\r\n cli:\r\n - rule:\r\n mode: web\r\n default:\r\n coercion:\r\n assets:\r\n - f\"{Path(self.ver.__file__).parent / 'web' / 'assets'}\"\r\n doc_root: f\"{Path(self.ver.__file__).parent / 'web'}\"\r\n - rule:\r\n mode: gui\r\n default:\r\n coercion:\r\n assets:\r\n - f\"{Path(self.ver.__file__).parent / 'web' / 'assets'}\"\r\n doc_root: f\"{Path(self.ver.__file__).parent / 'web'}\"\r\n```\r\n\r\n- The following files should also be known when using commands on the web screen or RESTAPI.\r\n- Open the file ```sample/extensions/user_list.yml```. The file should look something like this.\r\n- This file manages the users and groups that are allowed Web access and their rules.\r\n- The rule of the previous command is ```allow``` for users in the ```user``` group in ```cmdrule.rules```.\r\n\r\n\r\n```yml\r\nusers:\r\n- uid: 1\r\n name: admin\r\n password: XXXXXXXXXXX\r\n hash: plain\r\n groups: [admin]\r\n email: admin@aaa.bbb.jp\r\n- uid: 101\r\n name: user01\r\n password: XXXXXXXXXXX\r\n hash: md5\r\n groups: [user]\r\n email: user01@aaa.bbb.jp\r\n- uid: 102\r\n name: user02\r\n password: XXXXXXXXXXX\r\n hash: sha1\r\n groups: [readonly]\r\n email: user02@aaa.bbb.jp\r\n- uid: 103\r\n name: user03\r\n password: XXXXXXXXXXX\r\n hash: sha256\r\n groups: [editor]\r\n email: user03@aaa.bbb.jp\r\ngroups:\r\n- gid: 1\r\n name: admin\r\n- gid: 101\r\n name: user\r\n- gid: 102\r\n name: readonly\r\n parent: user\r\n- gid: 103\r\n name: editor\r\n parent: user\r\ncmdrule:\r\n policy: deny # allow, deny\r\n rules:\r\n - groups: [admin]\r\n rule: allow\r\n - groups: [user]\r\n mode: client\r\n cmds: [file_download, file_list, server_info]\r\n rule: allow\r\n - groups: [user]\r\n mode: server\r\n cmds: [list]\r\n rule: allow\r\n - groups: [editor]\r\n mode: client\r\n cmds: [file_copy, file_mkdir, file_move, file_remove, file_rmdir, file_upload]\r\n rule: allow\r\npathrule:\r\n policy: deny # allow, deny\r\n rules:\r\n - groups: [admin]\r\n paths: [/]\r\n rule: allow\r\n - groups: [user]\r\n paths: [/signin, /assets, /bbforce_cmd, /copyright, /dosignin, /dosignout,\r\n /exec_cmd, /exec_pipe, /filer, /gui, /get_server_opt, /usesignout, /versions_cmdbox, /versions_used]\r\n rule: allow\r\n - groups: [readonly]\r\n paths: [/gui/del_cmd, /gui/del_pipe, /gui/save_cmd, /gui/save_pipe]\r\n rule: deny\r\n - groups: [editor]\r\n paths: [/gui/del_cmd, /gui/del_pipe, /gui/save_cmd, /gui/save_pipe]\r\n rule: allow\r\noauth2:\r\n providers:\r\n google:\r\n enabled: false\r\n client_id: XXXXXXXXXXX\r\n client_secret: XXXXXXXXXXX\r\n redirect_uri: https://localhost:8443/oauth2/google/callback\r\n scope: ['email']\r\n note:\r\n - https://developers.google.com/identity/protocols/oauth2/web-server?hl=ja#httprest\r\n github:\r\n enabled: false\r\n client_id: XXXXXXXXXXX\r\n client_secret: XXXXXXXXXXX\r\n redirect_uri: https://localhost:8443/oauth2/github/callback\r\n scope: ['user:email']\r\n note:\r\n - https://docs.github.com/ja/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#scopes\r\n```\r\n\r\n- See the documentation for references to each file.\r\n- Documentation is [here](https://hamacom2004jp.github.io/cmdbox/).\r\n\r\n\r\n# Lisence\r\n\r\nThis project is licensed under the MIT License, see the LICENSE file for details\r\n\r\n\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "cmdbox: It is a command line application with a plugin mechanism.",
"version": "0.2.7.3",
"project_urls": {
"Download": "https://github.com/hamacom2004jp/cmdbox",
"Homepage": "https://github.com/hamacom2004jp/cmdbox"
},
"split_keywords": [
"cli",
"restapi",
"redis",
"fastapi"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "5b3023f72d31a469a073221f98548ca8d23bfcbcb2a7a277b748bbb0ddc2ec4a",
"md5": "22c38f7c8390a3d7eafb7c49b7e2e138",
"sha256": "c073e0d73949270d32c7525638f8624ec250ae322454172ebb7a8ea16678568c"
},
"downloads": -1,
"filename": "cmdbox-0.2.7.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "22c38f7c8390a3d7eafb7c49b7e2e138",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 1709890,
"upload_time": "2025-01-11T14:05:17",
"upload_time_iso_8601": "2025-01-11T14:05:17.424001Z",
"url": "https://files.pythonhosted.org/packages/5b/30/23f72d31a469a073221f98548ca8d23bfcbcb2a7a277b748bbb0ddc2ec4a/cmdbox-0.2.7.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "94e3832c3222da122d6d6c148c8d3be0068bf92ca636fbe4764c7c1f4fc2cb05",
"md5": "5ca54091351b06005e022d8875f9b659",
"sha256": "0d333e8c18ddc9abdc821361c7e1364bfd24fd38c1146604975d29084709e1c5"
},
"downloads": -1,
"filename": "cmdbox-0.2.7.3.tar.gz",
"has_sig": false,
"md5_digest": "5ca54091351b06005e022d8875f9b659",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 1552487,
"upload_time": "2025-01-11T14:05:19",
"upload_time_iso_8601": "2025-01-11T14:05:19.666066Z",
"url": "https://files.pythonhosted.org/packages/94/e3/832c3222da122d6d6c148c8d3be0068bf92ca636fbe4764c7c1f4fc2cb05/cmdbox-0.2.7.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-11 14:05:19",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "hamacom2004jp",
"github_project": "cmdbox",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "argcomplete",
"specs": []
},
{
"name": "collectlicense",
"specs": []
},
{
"name": "cryptography",
"specs": []
},
{
"name": "fastapi",
"specs": []
},
{
"name": "gevent",
"specs": []
},
{
"name": "itsdangerous",
"specs": []
},
{
"name": "numpy",
"specs": []
},
{
"name": "Pillow",
"specs": []
},
{
"name": "python-multipart",
"specs": []
},
{
"name": "redis",
"specs": []
},
{
"name": "requests",
"specs": []
},
{
"name": "six",
"specs": []
},
{
"name": "sphinx",
"specs": []
},
{
"name": "sphinx-rtd-theme",
"specs": []
},
{
"name": "sphinx_fontawesome",
"specs": []
},
{
"name": "sphinx-intl",
"specs": []
},
{
"name": "sphinx-sitemap",
"specs": []
},
{
"name": "tabulate",
"specs": []
},
{
"name": "twine",
"specs": []
},
{
"name": "uvicorn",
"specs": []
},
{
"name": "wheel",
"specs": []
}
],
"lcname": "cmdbox"
}