cmdbox 0.5.4__py3-none-any.whl → 0.6.0.1__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.

Potentially problematic release.


This version of cmdbox might be problematic. Click here for more details.

Files changed (148) hide show
  1. cmdbox/app/auth/signin.py +463 -303
  2. cmdbox/app/common.py +51 -3
  3. cmdbox/app/commons/loghandler.py +62 -13
  4. cmdbox/app/edge.py +5 -173
  5. cmdbox/app/edge_tool.py +177 -0
  6. cmdbox/app/feature.py +10 -9
  7. cmdbox/app/features/cli/agent_base.py +479 -0
  8. cmdbox/app/features/cli/audit_base.py +17 -5
  9. cmdbox/app/features/cli/cmdbox_audit_search.py +24 -1
  10. cmdbox/app/features/cli/cmdbox_client_file_download.py +1 -1
  11. cmdbox/app/features/cli/cmdbox_cmd_list.py +105 -0
  12. cmdbox/app/features/cli/cmdbox_cmd_load.py +104 -0
  13. cmdbox/app/features/cli/cmdbox_edge_config.py +2 -2
  14. cmdbox/app/features/cli/cmdbox_edge_start.py +1 -1
  15. cmdbox/app/features/cli/cmdbox_gui_start.py +9 -132
  16. cmdbox/app/features/cli/cmdbox_gui_stop.py +4 -21
  17. cmdbox/app/features/cli/cmdbox_server_start.py +1 -1
  18. cmdbox/app/features/cli/cmdbox_web_apikey_add.py +1 -1
  19. cmdbox/app/features/cli/cmdbox_web_apikey_del.py +1 -1
  20. cmdbox/app/features/cli/cmdbox_web_genpass.py +0 -3
  21. cmdbox/app/features/cli/cmdbox_web_group_add.py +1 -1
  22. cmdbox/app/features/cli/cmdbox_web_group_del.py +1 -1
  23. cmdbox/app/features/cli/cmdbox_web_group_edit.py +1 -1
  24. cmdbox/app/features/cli/cmdbox_web_group_list.py +1 -1
  25. cmdbox/app/features/cli/cmdbox_web_start.py +120 -104
  26. cmdbox/app/features/cli/cmdbox_web_stop.py +1 -1
  27. cmdbox/app/features/cli/cmdbox_web_user_add.py +1 -1
  28. cmdbox/app/features/cli/cmdbox_web_user_del.py +1 -1
  29. cmdbox/app/features/cli/cmdbox_web_user_edit.py +1 -1
  30. cmdbox/app/features/cli/cmdbox_web_user_list.py +1 -1
  31. cmdbox/app/features/web/cmdbox_web_agent.py +262 -0
  32. cmdbox/app/features/web/cmdbox_web_do_signout.py +3 -3
  33. cmdbox/app/features/web/cmdbox_web_exec_cmd.py +8 -3
  34. cmdbox/app/features/web/cmdbox_web_signin.py +5 -4
  35. cmdbox/app/features/web/cmdbox_web_users.py +2 -0
  36. cmdbox/app/options.py +62 -9
  37. cmdbox/app/web.py +139 -15
  38. cmdbox/extensions/features.yml +18 -0
  39. cmdbox/extensions/sample_project/sample/app/features/cli/__init__.py +0 -0
  40. cmdbox/extensions/sample_project/sample/app/features/web/__init__.py +0 -0
  41. cmdbox/extensions/sample_project/sample/extensions/features.yml +18 -0
  42. cmdbox/extensions/sample_project/sample/extensions/user_list.yml +2 -1
  43. cmdbox/extensions/sample_project/sample/logconf_sample.yml +14 -1
  44. cmdbox/extensions/user_list.yml +1 -0
  45. cmdbox/licenses/LICENSE.Authlib.1.5.2(BSD License).txt +29 -0
  46. cmdbox/licenses/LICENSE.Deprecated.1.2.18(MIT License).txt +21 -0
  47. cmdbox/licenses/LICENSE.SQLAlchemy.2.0.40(MIT License).txt +19 -0
  48. cmdbox/licenses/LICENSE.aiohappyeyeballs.2.6.1(Python Software Foundation License).txt +279 -0
  49. cmdbox/licenses/LICENSE.aiohttp.3.11.18(Apache Software License).txt +13 -0
  50. cmdbox/licenses/LICENSE.aiosignal.1.3.2(Apache Software License).txt +201 -0
  51. cmdbox/licenses/LICENSE.attrs.25.3.0(UNKNOWN).txt +21 -0
  52. cmdbox/licenses/LICENSE.cachetools.5.5.2(MIT License).txt +20 -0
  53. cmdbox/licenses/LICENSE.distro.1.9.0(Apache Software License).txt +202 -0
  54. cmdbox/licenses/LICENSE.docstring_parser.0.16(MIT License).txt +21 -0
  55. cmdbox/licenses/LICENSE.filelock.3.18.0(The Unlicense (Unlicense)).txt +24 -0
  56. cmdbox/licenses/LICENSE.frozenlist.1.6.0(Apache-2.0).txt +201 -0
  57. cmdbox/licenses/LICENSE.fsspec.2025.3.2(BSD License).txt +29 -0
  58. cmdbox/licenses/LICENSE.google-adk.0.5.0(Apache Software License).txt +202 -0
  59. cmdbox/licenses/LICENSE.google-api-python-client.2.169.0(Apache Software License).txt +201 -0
  60. cmdbox/licenses/LICENSE.google-auth-httplib2.0.2.0(Apache Software License).txt +201 -0
  61. cmdbox/licenses/LICENSE.google-auth.2.40.1(Apache Software License).txt +201 -0
  62. cmdbox/licenses/LICENSE.google-cloud-aiplatform.1.92.0(Apache 2.0).txt +202 -0
  63. cmdbox/licenses/LICENSE.google-cloud-bigquery.3.31.0(Apache Software License).txt +202 -0
  64. cmdbox/licenses/LICENSE.google-cloud-core.2.4.3(Apache Software License).txt +202 -0
  65. cmdbox/licenses/LICENSE.google-cloud-resource-manager.1.14.2(Apache Software License).txt +202 -0
  66. cmdbox/licenses/LICENSE.google-cloud-secret-manager.2.23.3(Apache Software License).txt +202 -0
  67. cmdbox/licenses/LICENSE.google-cloud-speech.2.32.0(Apache Software License).txt +202 -0
  68. cmdbox/licenses/LICENSE.google-cloud-storage.2.19.0(Apache Software License).txt +202 -0
  69. cmdbox/licenses/LICENSE.google-cloud-trace.1.16.1(Apache Software License).txt +202 -0
  70. cmdbox/licenses/LICENSE.google-crc32c.1.7.1(Apache 2.0).txt +202 -0
  71. cmdbox/licenses/LICENSE.google-genai.1.14.0(Apache Software License).txt +202 -0
  72. cmdbox/licenses/LICENSE.google-resumable-media.2.7.2(Apache Software License).txt +202 -0
  73. cmdbox/licenses/LICENSE.googleapis-common-protos.1.70.0(Apache Software License).txt +202 -0
  74. cmdbox/licenses/LICENSE.graphviz.0.20.3(MIT License).txt +21 -0
  75. cmdbox/licenses/LICENSE.grpc-google-iam-v1.0.14.2(Apache Software License).txt +202 -0
  76. cmdbox/licenses/LICENSE.grpcio-status.1.71.0(Apache Software License).txt +610 -0
  77. cmdbox/licenses/LICENSE.grpcio.1.71.0(Apache Software License).txt +610 -0
  78. cmdbox/licenses/LICENSE.httpcore.1.0.9(BSD License).txt +27 -0
  79. cmdbox/licenses/LICENSE.httplib2.0.22.0(MIT License).txt +23 -0
  80. cmdbox/licenses/LICENSE.httpx-sse.0.4.0(MIT).txt +21 -0
  81. cmdbox/licenses/LICENSE.httpx.0.28.1(BSD License).txt +12 -0
  82. cmdbox/licenses/LICENSE.huggingface-hub.0.31.1(Apache Software License).txt +201 -0
  83. cmdbox/licenses/LICENSE.importlib_metadata.8.6.1(Apache Software License).txt +202 -0
  84. cmdbox/licenses/LICENSE.jiter.0.9.0(MIT License).txt +1 -0
  85. cmdbox/licenses/LICENSE.jsonschema-specifications.2025.4.1(UNKNOWN).txt +19 -0
  86. cmdbox/licenses/LICENSE.jsonschema.4.23.0(MIT License).txt +19 -0
  87. cmdbox/licenses/LICENSE.litellm.1.69.0(MIT License).txt +26 -0
  88. cmdbox/licenses/LICENSE.mcp.1.8.0(MIT License).txt +21 -0
  89. cmdbox/licenses/LICENSE.multidict.6.4.3(Apache Software License).txt +13 -0
  90. cmdbox/licenses/LICENSE.openai.1.75.0(Apache Software License).txt +201 -0
  91. cmdbox/licenses/LICENSE.opentelemetry-api.1.33.0(Apache Software License).txt +201 -0
  92. cmdbox/licenses/LICENSE.opentelemetry-exporter-gcp-trace.1.9.0(Apache Software License).txt +201 -0
  93. cmdbox/licenses/LICENSE.opentelemetry-resourcedetector-gcp.1.9.0a0(Apache Software License).txt +201 -0
  94. cmdbox/licenses/LICENSE.opentelemetry-sdk.1.33.0(Apache Software License).txt +201 -0
  95. cmdbox/licenses/LICENSE.opentelemetry-semantic-conventions.0.54b0(Apache Software License).txt +201 -0
  96. cmdbox/licenses/LICENSE.propcache.0.3.1(Apache Software License).txt +202 -0
  97. cmdbox/licenses/LICENSE.proto-plus.1.26.1(Apache Software License).txt +202 -0
  98. cmdbox/licenses/LICENSE.protobuf.5.29.4(3-Clause BSD License).txt +32 -0
  99. cmdbox/licenses/LICENSE.pyasn1.0.6.1(BSD License).txt +24 -0
  100. cmdbox/licenses/LICENSE.pyasn1_modules.0.4.2(BSD License).txt +24 -0
  101. cmdbox/licenses/LICENSE.pydantic-settings.2.9.1(MIT License).txt +21 -0
  102. cmdbox/licenses/LICENSE.pyparsing.3.2.3(MIT License).txt +18 -0
  103. cmdbox/licenses/LICENSE.python-dateutil.2.9.0.post0(Apache Software License; BSD License).txt +54 -0
  104. cmdbox/licenses/LICENSE.referencing.0.36.2(UNKNOWN).txt +19 -0
  105. cmdbox/licenses/LICENSE.regex.2024.11.6(Apache Software License).txt +208 -0
  106. cmdbox/licenses/LICENSE.rpds-py.0.24.0(MIT).txt +19 -0
  107. cmdbox/licenses/LICENSE.rsa.4.9.1(Apache Software License).txt +13 -0
  108. cmdbox/licenses/LICENSE.shapely.2.1.0(BSD License).txt +29 -0
  109. cmdbox/licenses/LICENSE.sse-starlette.2.3.4(BSD License).txt +27 -0
  110. cmdbox/licenses/LICENSE.tiktoken.0.9.0(MIT License).txt +21 -0
  111. cmdbox/licenses/LICENSE.tokenizers.0.21.1(Apache Software License).txt +1 -0
  112. cmdbox/licenses/LICENSE.tqdm.4.67.1(MIT License; Mozilla Public License 2.0 (MPL 2.0)).txt +49 -0
  113. cmdbox/licenses/LICENSE.tzlocal.5.3.1(MIT License).txt +19 -0
  114. cmdbox/licenses/LICENSE.uritemplate.4.1.1(Apache Software License; BSD License).txt +3 -0
  115. cmdbox/licenses/LICENSE.wrapt.1.17.2(BSD License).txt +24 -0
  116. cmdbox/licenses/LICENSE.yarl.1.20.0(Apache Software License).txt +202 -0
  117. cmdbox/licenses/files.txt +104 -11
  118. cmdbox/logconf_audit.yml +16 -3
  119. cmdbox/logconf_client.yml +16 -3
  120. cmdbox/logconf_cmdbox.yml +16 -3
  121. cmdbox/logconf_edge.yml +16 -3
  122. cmdbox/logconf_gui.yml +15 -2
  123. cmdbox/logconf_server.yml +15 -2
  124. cmdbox/logconf_web.yml +15 -2
  125. cmdbox/version.py +3 -2
  126. cmdbox/web/agent.html +263 -0
  127. cmdbox/web/assets/cmdbox/agent.js +338 -0
  128. cmdbox/web/assets/cmdbox/common.js +1111 -1020
  129. cmdbox/web/assets/cmdbox/main.js +17 -3
  130. cmdbox/web/assets/cmdbox/signin.js +4 -4
  131. cmdbox/web/assets/filer/filer.js +4 -2
  132. {cmdbox-0.5.4.dist-info → cmdbox-0.6.0.1.dist-info}/METADATA +69 -26
  133. {cmdbox-0.5.4.dist-info → cmdbox-0.6.0.1.dist-info}/RECORD +148 -67
  134. /cmdbox/licenses/{LICENSE.charset-normalizer.3.4.1(MIT License).txt → LICENSE.charset-normalizer.3.4.2(MIT License).txt} +0 -0
  135. /cmdbox/licenses/{LICENSE.click.8.1.8(BSD License).txt → LICENSE.click.8.2.0(UNKNOWN).txt} +0 -0
  136. /cmdbox/licenses/{LICENSE.cryptography.44.0.2(Apache Software License; BSD License).txt → LICENSE.cryptography.44.0.3(Apache Software License; BSD License).txt} +0 -0
  137. /cmdbox/licenses/{LICENSE.importlib_metadata.8.7.0(Apache Software License).txt → LICENSE.google-api-core.2.24.2(Apache Software License).txt} +0 -0
  138. /cmdbox/licenses/{LICENSE.greenlet.3.2.1(MIT AND Python-2.0).txt → LICENSE.greenlet.3.2.2(MIT AND Python-2.0).txt} +0 -0
  139. /cmdbox/licenses/{LICENSE.psycopg-binary.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE.psycopg-binary.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt} +0 -0
  140. /cmdbox/licenses/{LICENSE.psycopg.3.2.6(GNU Lesser General Public License v3 (LGPLv3)).txt → LICENSE.psycopg.3.2.7(GNU Lesser General Public License v3 (LGPLv3)).txt} +0 -0
  141. /cmdbox/licenses/{LICENSE.pydantic.2.11.3(MIT License).txt → LICENSE.pydantic.2.11.4(MIT License).txt} +0 -0
  142. /cmdbox/licenses/{LICENSE.pydantic_core.2.33.1(MIT License).txt → LICENSE.pydantic_core.2.33.2(MIT License).txt} +0 -0
  143. /cmdbox/licenses/{LICENSE.redis.5.2.1(MIT License).txt → LICENSE.redis.6.0.0(MIT License).txt} +0 -0
  144. /cmdbox/licenses/{LICENSE.snowballstemmer.2.2.0(BSD License).txt → LICENSE.snowballstemmer.3.0.1(BSD License).txt} +0 -0
  145. {cmdbox-0.5.4.dist-info → cmdbox-0.6.0.1.dist-info}/LICENSE +0 -0
  146. {cmdbox-0.5.4.dist-info → cmdbox-0.6.0.1.dist-info}/WHEEL +0 -0
  147. {cmdbox-0.5.4.dist-info → cmdbox-0.6.0.1.dist-info}/entry_points.txt +0 -0
  148. {cmdbox-0.5.4.dist-info → cmdbox-0.6.0.1.dist-info}/top_level.txt +0 -0
cmdbox/app/common.py CHANGED
@@ -4,6 +4,8 @@ from cmdbox.app.commons import convert, module, loghandler
4
4
  from cryptography.fernet import Fernet
5
5
  from pathlib import Path
6
6
  from pkg_resources import resource_string
7
+ from rich.logging import RichHandler
8
+ from rich.console import Console
7
9
  from tabulate import tabulate
8
10
  from typing import List, Tuple, Dict, Any
9
11
  import asyncio
@@ -91,6 +93,53 @@ def save_yml(yml_path:Path, data:dict) -> None:
91
93
  with open(yml_path, 'w') as f:
92
94
  yaml.dump(data, f, default_flow_style=False, sort_keys=False)
93
95
 
96
+ def reset_logger(name:str, stderr:bool=False, fmt:str='[%(asctime)s] %(levelname)s - %(message)s', datefmt:str='%Y-%m-%d %H:%M:%S') -> None:
97
+ """
98
+ 指定されたロガーのハンドラをクリアし、新しいハンドラを追加します。
99
+ Args:
100
+ name (str): ロガーの名前
101
+ stderr (bool, optional): 標準エラー出力を使用するかどうか. Defaults to False.
102
+ fmt (str, optional): ログフォーマット. Defaults to '[%(asctime)s] %(levelname)s - %(message)s'.
103
+ datefmt (str, optional): 日時フォーマット. Defaults to '%Y-%m-%d %H:%M:%S'.
104
+ """
105
+ logger = logging.getLogger(name)
106
+ logger.handlers.clear()
107
+ logger.propagate = False
108
+ logger.addHandler(create_log_handler(stderr, fmt, datefmt))
109
+
110
+ def create_log_handler(stderr:bool=False, fmt:str='[%(asctime)s] %(levelname)s - %(message)s', datefmt:str='%Y-%m-%d %H:%M:%S') -> logging.Handler:
111
+ """
112
+ ログハンドラを生成します。
113
+
114
+ Args:
115
+ stderr (bool, optional): 標準エラー出力を使用するかどうか. Defaults to False.
116
+ fmt (str, optional): ログフォーマット. Defaults to '[%(asctime)s] %(levelname)s - %(message)s'.
117
+ datefmt (str, optional): 日時フォーマット. Defaults to '%Y-%m-%d %H:%M:%S'.
118
+ Returns:
119
+ logging.Handler: ログハンドラ
120
+ """
121
+ formatter = logging.Formatter(fmt, datefmt)
122
+ #handler = RichHandler(console=Console(stderr=stderr), show_path=False, omit_repeated_times=False,
123
+ # tracebacks_word_wrap=False, log_time_format='[%Y-%m-%d %H:%M]')
124
+ handler = loghandler.ColorfulStreamHandler(sys.stdout if not stderr else sys.stderr)
125
+ handler.setFormatter(formatter)
126
+ return handler
127
+
128
+ def create_console(stderr:bool=False, file=None) -> Console:
129
+ """
130
+ コンソールを生成します。
131
+
132
+ Args:
133
+ stderr (bool, optional): 標準エラー出力を使用するかどうか. Defaults to False.
134
+ file (file, optional): 出力先のファイル. Defaults to None.
135
+ Returns:
136
+ Console: コンソール
137
+ """
138
+ console = Console(height=False,
139
+ soft_wrap=False, stderr=stderr, file=file, log_time=True, log_path=False, log_time_format='[%Y-%m-%d %H:%M:%S]')
140
+ #console = Console(soft_wrap=True, stderr=stderr, file=file, log_time=True, log_path=False, log_time_format='[%Y-%m-%d %H:%M:%S]')
141
+ return console
142
+
94
143
  def default_logger(debug:bool=False, ver=version, webcall:bool=False) -> logging.Logger:
95
144
  """
96
145
  デフォルトのロガーを生成します。
@@ -105,12 +154,11 @@ def default_logger(debug:bool=False, ver=version, webcall:bool=False) -> logging
105
154
  """
106
155
  logger = logging.getLogger(ver.__appid__)
107
156
  if not webcall:
108
- formatter = logging.Formatter('%(levelname)s[%(asctime)s] - %(message)s')
109
- handler = loghandler.ColorfulStreamHandler(sys.stdout)
157
+ handler = create_log_handler()
110
158
  handler.setLevel(logging.DEBUG if debug else logging.INFO)
111
- handler.setFormatter(formatter)
112
159
  logger.addHandler(handler)
113
160
  logger.setLevel(logging.DEBUG if debug else logging.INFO)
161
+ logger.propagate = False
114
162
  return logger
115
163
 
116
164
  def load_config(mode:str, debug:bool=False, data=HOME_DIR, webcall:bool=False, ver=version) -> Tuple[logging.Logger, dict]:
@@ -1,3 +1,6 @@
1
+ from rich.console import Console
2
+ from rich import highlighter
3
+ from rich.theme import Theme
1
4
  import re
2
5
  import logging
3
6
  import logging.handlers
@@ -77,25 +80,71 @@ def colorize_msg(msg) -> str:
77
80
  return msg
78
81
 
79
82
  level_mapping = {
80
- logging.DEBUG: f"{colorize('DEBUG', Colors.Bold, Colors.Cyan)}: ",
81
- logging.INFO: f"{colorize('INFO', Colors.Bold, Colors.Green)}: ",
82
- logging.WARNING: f"{colorize('WARNING', Colors.Bold, Colors.Yellow)}: ",
83
- logging.ERROR: f"{colorize('ERROR', Colors.Bold, Colors.Red)}: ",
84
- logging.CRITICAL:f"{colorize('CRITICAL', Colors.Bold, Colors.LightGray, Colors.BackgroundRed)}: "}
83
+ logging.DEBUG: f"{colorize('DEBUG', Colors.Bold, Colors.Cyan)}",
84
+ logging.INFO: f"{colorize('INFO', Colors.Bold, Colors.Green)} ",
85
+ logging.WARNING: f"{colorize('WARN', Colors.Bold, Colors.Yellow)} ",
86
+ logging.ERROR: f"{colorize('ERROR', Colors.Bold, Colors.Red)}",
87
+ logging.CRITICAL:f"{colorize('FATAL', Colors.Bold, Colors.LightGray, Colors.BackgroundRed)}"}
85
88
 
86
89
  level_mapping_nc = {
87
- logging.DEBUG: f"DEBUG: ",
88
- logging.INFO: f"INFO: ",
89
- logging.WARNING: f"WARNING: ",
90
- logging.ERROR: f"ERROR: ",
91
- logging.CRITICAL:f"CRITICAL: "}
90
+ logging.DEBUG: f"DEBUG",
91
+ logging.INFO: f"INFO ",
92
+ logging.WARNING: f"WARN ",
93
+ logging.ERROR: f"ERROR",
94
+ logging.CRITICAL:f"FATAL"}
95
+
96
+ theme=Theme({
97
+ "repr.log_debug": "bold cyan",
98
+ "repr.log_info": "bold green",
99
+ "repr.log_warn": "bold Yellow",
100
+ "repr.log_error": "bold red",
101
+ "repr.log_fatal": "bold red reverse",
102
+ "repr.log_product": "dodger_blue2 reverse",
103
+ "repr.log_success": "green",})
104
+
105
+ class LogLevelHighlighter(highlighter.ReprHighlighter):
106
+ def __init__(self):
107
+ #self.highlights = []
108
+ self.highlights.append(r"(?P<log_debug>DEBUG)")
109
+ self.highlights.append(r"(?P<log_info>INFO)")
110
+ self.highlights.append(r"(?P<log_warn>WARN|WARNING|WARN|CAUTION|NOTICE|STOP|DISCONNECTED|DENY)")
111
+ self.highlights.append(r"(?P<log_error>ERROR|ALERT|ABORT|FAILED)")
112
+ self.highlights.append(r"(?P<log_fatal>FATAL|CRITICAL)")
113
+ self.highlights.append(r"(?P<log_product>CMDBOX|IINFER|USOUND|GAIAN|GAIC|WITSHAPE)")
114
+ self.highlights.append(r"(?P<log_success>SUCCESS|OK|PASSED|DONE|COMPLETE|START|FINISH|OPEN|CONNECTED|ALLOW|EXEC)")
115
+ """
116
+ self.highlights.append(r"(?P<tag_start><)(?P<tag_name>[-\w.:|]*)(?P<tag_contents>[\w\W]*)(?P<tag_end>>)")
117
+ self.highlights.append(r'(?P<attrib_name>[\w_]{1,50})=(?P<attrib_value>"?[\w_]+"?)?')
118
+ self.highlights.append(r"(?P<brace>[][{}()])")
119
+ self.highlights.append(highlighter._combine_regex(
120
+ r"(?P<ipv4>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})",
121
+ r"(?P<ipv6>([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})",
122
+ r"(?P<eui64>(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})",
123
+ r"(?P<eui48>(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})",
124
+ r"(?P<uuid>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})",
125
+ r"(?P<call>[\w.]*?)\(",
126
+ r"\b(?P<bool_true>True)\b|\b(?P<bool_false>False)\b|\b(?P<none>None)\b",
127
+ r"(?P<ellipsis>\.\.\.)",
128
+ r"(?P<number_complex>(?<!\w)(?:\-?[0-9]+\.?[0-9]*(?:e[-+]?\d+?)?)(?:[-+](?:[0-9]+\.?[0-9]*(?:e[-+]?\d+)?))?j)",
129
+ r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[-+]?\d+?)?\b|0x[0-9a-fA-F]*)",
130
+ r"(?P<path>\B(/[-\w._+]+)*\/)(?P<filename>[-\w._+]*)?",
131
+ r"(?<![\\\w])(?P<str>b?'''.*?(?<!\\)'''|b?'.*?(?<!\\)'|b?\"\"\".*?(?<!\\)\"\"\"|b?\".*?(?<!\\)\")",
132
+ r"(?P<url>(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#~@]*)",
133
+ ))
134
+ """
135
+ self.highlights = [re.compile(h, re.IGNORECASE) for h in self.highlights]
92
136
 
93
137
  class ColorfulStreamHandler(logging.StreamHandler):
138
+ console = Console(soft_wrap=True, height=True, highlighter=LogLevelHighlighter(), theme=theme)
139
+
94
140
  def emit(self, record: logging.LogRecord) -> None:
95
- record.levelname = level_mapping[record.levelno]
141
+ #record.levelname = level_mapping[record.levelno]
96
142
  #record.asctime = colorize(record.asctime, Colors.Bold)
97
- record.msg = colorize_msg(record.msg)
98
- super().emit(record)
143
+ #record.msg = colorize_msg(record.msg)
144
+ #super().emit(record)
145
+ record.levelname = level_mapping_nc[record.levelno]
146
+ record.msg = self.format(record)
147
+ self.console.print(record.msg)
99
148
 
100
149
  class TimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
101
150
  def emit(self, record: logging.LogRecord) -> None:
cmdbox/app/edge.py CHANGED
@@ -1,5 +1,4 @@
1
- from cmdbox.app import common, feature, options, web
2
- from cmdbox.app.auth import signin, signin_saml, azure_signin, azure_signin_saml, github_signin, google_signin
1
+ from cmdbox.app import common, edge_tool, feature, options, web
3
2
  from cmdbox.app.commons import convert
4
3
  from cmdbox.app.options import Options
5
4
  from fastapi import FastAPI, Request, HTTPException
@@ -27,7 +26,7 @@ class Edge(object):
27
26
  self.appcls = appcls
28
27
  self.ver = ver
29
28
  self.options = options.Options.getInstance()
30
- self.tool = Tool(logger, appcls, ver)
29
+ self.tool = edge_tool.Tool(logger, appcls, ver)
31
30
  if self.ver is None:
32
31
  raise ValueError('ver is None')
33
32
  if self.appcls is None:
@@ -298,7 +297,7 @@ class Edge(object):
298
297
  def _job(thevent:threading.Event, pipe_cmd, prevq:queue.Queue):
299
298
  resq:queue.Queue = pipe_cmd['resq']
300
299
  del pipe_cmd['resq']
301
- tool = Tool(self.logger, self.appcls, self.ver)
300
+ tool = edge_tool.Tool(self.logger, self.appcls, self.ver)
302
301
  tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
303
302
  feat:feature.Feature = self.options.get_cmd_attr(pipe_cmd['mode'], pipe_cmd['cmd'], 'feature')
304
303
  while not thevent.is_set():
@@ -355,7 +354,7 @@ class Edge(object):
355
354
  for opt in opts:
356
355
  def mkcmd(opt):
357
356
  def _ex():
358
- tool = Tool(self.logger, self.appcls, self.ver)
357
+ tool = edge_tool.Tool(self.logger, self.appcls, self.ver)
359
358
  tool.set_session(self.session, self.svcert_no_verify, self.endpoint, self.icon_path, self.user_info, self.oauth2, self.saml)
360
359
  feat:feature.Feature = self.options.get_cmd_attr(opt['mode'], opt['cmd'], 'feature')
361
360
  for status, ret in feat.edgerun(opt, tool, self.logger, self.timeout):
@@ -380,7 +379,7 @@ class Edge(object):
380
379
  items = []
381
380
  items.append(pystray.MenuItem('Gui', lambda: self.tool.open_browser('/gui')))
382
381
  for k, op in opens.items():
383
- def mkop(tool:Tool, href):
382
+ def mkop(tool:edge_tool.Tool, href):
384
383
  return lambda: tool.open_browser(href)
385
384
  items.append(pystray.MenuItem(op['html'], mkop(self.tool, op['href'])))
386
385
  return items
@@ -754,170 +753,3 @@ class Edge(object):
754
753
  return 0, dict(success="Signin success.")
755
754
 
756
755
  return 1, dict(warn="unsupported auth_type.")
757
-
758
- class Tool(object):
759
- def __init__(self, logger:logging.Logger, appcls=None, ver=None):
760
- self.logger = logger
761
- self.appcls = appcls
762
- self.ver = ver
763
-
764
- def notify(self, message:dict):
765
- """
766
- 通知メッセージを表示します
767
-
768
- Args:
769
- message (dict): メッセージ
770
- """
771
- if type(message) is list:
772
- message = message[0]
773
- if type(message) is not dict:
774
- message = {"info":str(message)}
775
- if self.logger.level == logging.DEBUG:
776
- self.logger.debug(f"notify: {common.to_str(message, slise=256)}")
777
- try:
778
- if 'success' in message and type(message['success']) == dict:
779
- message = "\n".join([f"{k}:{v}" for k, v in message['success'].items()])
780
- message = f'Success\n{message}'
781
- else:
782
- message = "\n".join([f"{k} : {v}" for k, v in message.items()])
783
- import plyer
784
- if hasattr(self, 'icon_path') and self.icon_path is not None:
785
- plyer.notification.notify(title=self.ver.__title__, message=str(message)[:256], app_icon=str(self.icon_path))
786
- else:
787
- plyer.notification.notify(title=self.ver.__title__, message=str(message)[:256])
788
- except Exception as e:
789
- self.logger.error(f"notify error. {e}", exc_info=True)
790
-
791
- def set_session(self, session:requests.Session, svcert_no_verify:bool, endpoint:str, icon_path:Path, user_info:Dict[str, Any], oauth2:str, saml:str):
792
- """
793
- セッションを設定します
794
-
795
- Args:
796
- session (requests.Session): セッション
797
- svcert_no_verify (bool): サーバー証明書の検証を行わない
798
- endpoint (str): エンドポイント
799
- icon_path (Path): アイコン画像のパス
800
- user_info (Dict[str, Any]): ユーザー情報
801
- oauth2 (str): OAuth2
802
- """
803
- self.session = session
804
- self.svcert_no_verify = svcert_no_verify
805
- self.endpoint = endpoint
806
- self.icon_path = icon_path
807
- self.user = user_info
808
- self.oauth2 = oauth2
809
- self.saml = saml
810
-
811
- def exec_cmd(self, opt:Dict[str, Any], logger:logging.Logger, timeout:int, prevres:Any=None) -> Tuple[int, Dict[str, Any]]:
812
- """
813
- この機能のエッジ側の実行を行います
814
-
815
- Args:
816
- opt (Dict[str, Any]): オプション
817
- logger (logging.Logger): ロガー
818
- timeout (int): タイムアウト時間
819
- prevres (Any): 前コマンドの結果。pipeline実行の実行結果を参照する時に使用します。
820
-
821
- Returns:
822
- Tuple[int, Dict[str, Any], Any]: 終了コード, 結果
823
- """
824
- if logger.level == logging.DEBUG:
825
- logger.debug(f"exec_cmd: {self.endpoint}/exec_cmd/{opt['title']}")
826
- if prevres is not None:
827
- headers = {'content-type':'application/octet-stream'}
828
- prevres = common.to_str(prevres)
829
- res = self.session.post(f"{self.endpoint}/exec_cmd/{opt['title']}", headers=headers, data=prevres,
830
- verify=not self.svcert_no_verify, timeout=timeout, allow_redirects=False)
831
- else:
832
- res = self.session.post(f"{self.endpoint}/exec_cmd/{opt['title']}",
833
- verify=not self.svcert_no_verify, timeout=timeout, allow_redirects=False)
834
-
835
- if res.status_code != 200:
836
- msg = dict(warn=f"Access failed. status_code={res.status_code}")
837
- logger.warning(f"Access failed. status_code={res.status_code}")
838
- return 1, msg
839
- else:
840
- ret = msg = res.json()
841
- if isinstance(msg, list):
842
- if len(msg) == 0:
843
- logger.warning(f"No result.")
844
- return 1, dict(warn="No result.")
845
- msg = msg[0]
846
- if isinstance(msg, dict) and 'success' not in msg:
847
- logger.warning(f"{msg}")
848
- return 1, ret
849
- if logger.level == logging.DEBUG:
850
- logger.debug(f"{common.to_str(ret, slise=255)}")
851
- return 0, ret
852
-
853
- def pub_result(self, title:str, output:str, timeout:int) -> Tuple[int, Dict[str, Any]]:
854
- """
855
- 結果を公開します
856
-
857
- Args:
858
- title (str): タイトル
859
- output (str): 出力
860
- logger (logging.Logger): ロガー
861
- timeout (int): タイムアウト時間
862
-
863
- Returns:
864
- Tuple[int, Dict[str, Any]]: 終了コード, メッセージ
865
- """
866
- output = common.to_str(output)
867
- data = f'title={urllib.parse.quote(title)}&output={urllib.parse.quote(output)}'
868
- headers = {'content-type':'application/x-www-form-urlencoded'}
869
- res = self.session.post(f"{self.endpoint}/result/pub", headers=headers, data=data,
870
- verify=not self.svcert_no_verify, timeout=timeout, allow_redirects=False)
871
- if res.status_code != 200:
872
- msg = dict(warn=f"Access failed. status_code={res.status_code}")
873
- return 1, msg
874
- else:
875
- msg = res.json()
876
- return 0, msg
877
-
878
- def open_browser(self, path:str) -> Tuple[int, Dict[str, str]]:
879
- """
880
- 指定したパスをブラウザで開きます。
881
- この時認証情報を含めて開きます。
882
-
883
- Args:
884
- path (str): パス
885
-
886
- Returns:
887
- Tuple[int, Dict[str, str]]: 終了コード, メッセージ
888
- """
889
- path = f"/{path}" if not path.startswith('/') else path
890
- if not hasattr(self, 'user'):
891
- webbrowser.open(f"{self.endpoint}{path}")
892
- return 0, dict(success="Open browser.")
893
- token = dict(auth_type=self.user['auth_type'])
894
- if self.user['auth_type'] == "noauth":
895
- webbrowser.open(f"{self.endpoint}{path}")
896
- return 0, dict(success="Open browser.")
897
- elif self.user['auth_type'] == "idpw":
898
- hashed = self.user['password'] if self.user['hash']=='plain' else common.hash_password(self.user['password'], self.user['hash'])
899
- token = dict(**token, **dict(user=self.user['name'], token=common.encrypt(path, hashed)))
900
- token = convert.str2b64str(common.to_str(token))
901
- webbrowser.open(f"{self.endpoint}/dosignin_token/{token}{path}")
902
- return 0, dict(success="Open browser.")
903
- elif self.user['auth_type'] == "apikey":
904
- hashed = common.hash_password(self.user['apikey'], 'sha1')
905
- token = dict(**token, **dict(user=self.user['name'], token=common.encrypt(path, hashed)))
906
- token = convert.str2b64str(common.to_str(token))
907
- webbrowser.open(f"{self.endpoint}/dosignin_token/{token}{path}")
908
- return 0, dict(success="Open browser.")
909
- elif self.user['auth_type'] == "oauth2":
910
- if self.oauth2 == 'google':
911
- webbrowser.open(f"{self.endpoint}/oauth2/google/session/{self.user['access_token']}{path}")
912
- return 0, dict(success="Open browser.")
913
- if self.oauth2 == 'github':
914
- webbrowser.open(f"{self.endpoint}/oauth2/github/session/{self.user['access_token']}{path}")
915
- return 0, dict(success="Open browser.")
916
- if self.oauth2 == 'azure':
917
- webbrowser.open(f"{self.endpoint}/oauth2/azure/session/{self.user['access_token']}{path}")
918
- return 0, dict(success="Open browser.")
919
- elif self.user['auth_type'] == "saml":
920
- if self.saml == 'azure':
921
- webbrowser.open(f"{self.endpoint}/saml/azure/session/{self.user['saml_token']}{path}")
922
- return 0, dict(success="Open browser.")
923
- return 1, dict(warn="unsupported auth_type.")
@@ -0,0 +1,177 @@
1
+ from cmdbox.app import common
2
+ from cmdbox.app.commons import convert
3
+ from pathlib import Path
4
+ from typing import Dict, Any, Tuple
5
+ import logging
6
+ import requests
7
+ import webbrowser
8
+ import urllib.parse
9
+ import urllib3
10
+
11
+
12
+ class Tool(object):
13
+ def __init__(self, logger:logging.Logger, appcls=None, ver=None):
14
+ self.logger = logger
15
+ self.appcls = appcls
16
+ self.ver = ver
17
+
18
+ def notify(self, message:dict):
19
+ """
20
+ 通知メッセージを表示します
21
+
22
+ Args:
23
+ message (dict): メッセージ
24
+ """
25
+ if type(message) is list:
26
+ message = message[0]
27
+ if type(message) is not dict:
28
+ message = {"info":str(message)}
29
+ if self.logger.level == logging.DEBUG:
30
+ self.logger.debug(f"notify: {common.to_str(message, slise=256)}")
31
+ try:
32
+ if 'success' in message and type(message['success']) == dict:
33
+ message = "\n".join([f"{k}:{v}" for k, v in message['success'].items()])
34
+ message = f'Success\n{message}'
35
+ else:
36
+ message = "\n".join([f"{k} : {v}" for k, v in message.items()])
37
+ import plyer
38
+ if hasattr(self, 'icon_path') and self.icon_path is not None:
39
+ plyer.notification.notify(title=self.ver.__title__, message=str(message)[:256], app_icon=str(self.icon_path))
40
+ else:
41
+ plyer.notification.notify(title=self.ver.__title__, message=str(message)[:256])
42
+ except Exception as e:
43
+ self.logger.error(f"notify error. {e}", exc_info=True)
44
+
45
+ def set_session(self, session:requests.Session, svcert_no_verify:bool, endpoint:str, icon_path:Path, user_info:Dict[str, Any], oauth2:str, saml:str):
46
+ """
47
+ セッションを設定します
48
+
49
+ Args:
50
+ session (requests.Session): セッション
51
+ svcert_no_verify (bool): サーバー証明書の検証を行わない
52
+ endpoint (str): エンドポイント
53
+ icon_path (Path): アイコン画像のパス
54
+ user_info (Dict[str, Any]): ユーザー情報
55
+ oauth2 (str): OAuth2
56
+ """
57
+ self.session = session
58
+ self.svcert_no_verify = svcert_no_verify
59
+ self.endpoint = endpoint
60
+ self.icon_path = icon_path
61
+ self.user = user_info
62
+ self.oauth2 = oauth2
63
+ self.saml = saml
64
+
65
+ def exec_cmd(self, opt:Dict[str, Any], logger:logging.Logger, timeout:int, prevres:Any=None) -> Tuple[int, Dict[str, Any]]:
66
+ """
67
+ この機能のエッジ側の実行を行います
68
+
69
+ Args:
70
+ opt (Dict[str, Any]): オプション
71
+ logger (logging.Logger): ロガー
72
+ timeout (int): タイムアウト時間
73
+ prevres (Any): 前コマンドの結果。pipeline実行の実行結果を参照する時に使用します。
74
+
75
+ Returns:
76
+ Tuple[int, Dict[str, Any], Any]: 終了コード, 結果
77
+ """
78
+ if logger.level == logging.DEBUG:
79
+ logger.debug(f"exec_cmd: {self.endpoint}/exec_cmd/{opt['title']}")
80
+ if prevres is not None:
81
+ headers = {'content-type':'application/octet-stream'}
82
+ prevres = common.to_str(prevres)
83
+ res = self.session.post(f"{self.endpoint}/exec_cmd/{opt['title']}", headers=headers, data=prevres,
84
+ verify=not self.svcert_no_verify, timeout=timeout, allow_redirects=False)
85
+ else:
86
+ res = self.session.post(f"{self.endpoint}/exec_cmd/{opt['title']}",
87
+ verify=not self.svcert_no_verify, timeout=timeout, allow_redirects=False)
88
+
89
+ if res.status_code != 200:
90
+ msg = dict(warn=f"Access failed. status_code={res.status_code}")
91
+ logger.warning(f"Access failed. status_code={res.status_code}")
92
+ return 1, msg
93
+ else:
94
+ ret = msg = res.json()
95
+ if isinstance(msg, list):
96
+ if len(msg) == 0:
97
+ logger.warning(f"No result.")
98
+ return 1, dict(warn="No result.")
99
+ msg = msg[0]
100
+ if isinstance(msg, dict) and 'success' not in msg:
101
+ logger.warning(f"{msg}")
102
+ return 1, ret
103
+ if logger.level == logging.DEBUG:
104
+ logger.debug(f"{common.to_str(ret, slise=255)}")
105
+ return 0, ret
106
+
107
+ def pub_result(self, title:str, output:str, timeout:int) -> Tuple[int, Dict[str, Any]]:
108
+ """
109
+ 結果を公開します
110
+
111
+ Args:
112
+ title (str): タイトル
113
+ output (str): 出力
114
+ logger (logging.Logger): ロガー
115
+ timeout (int): タイムアウト時間
116
+
117
+ Returns:
118
+ Tuple[int, Dict[str, Any]]: 終了コード, メッセージ
119
+ """
120
+ output = common.to_str(output)
121
+ data = f'title={urllib.parse.quote(title)}&output={urllib.parse.quote(output)}'
122
+ headers = {'content-type':'application/x-www-form-urlencoded'}
123
+ res = self.session.post(f"{self.endpoint}/result/pub", headers=headers, data=data,
124
+ verify=not self.svcert_no_verify, timeout=timeout, allow_redirects=False)
125
+ if res.status_code != 200:
126
+ msg = dict(warn=f"Access failed. status_code={res.status_code}")
127
+ return 1, msg
128
+ else:
129
+ msg = res.json()
130
+ return 0, msg
131
+
132
+ def open_browser(self, path:str) -> Tuple[int, Dict[str, str]]:
133
+ """
134
+ 指定したパスをブラウザで開きます。
135
+ この時認証情報を含めて開きます。
136
+
137
+ Args:
138
+ path (str): パス
139
+
140
+ Returns:
141
+ Tuple[int, Dict[str, str]]: 終了コード, メッセージ
142
+ """
143
+ path = f"/{path}" if not path.startswith('/') else path
144
+ if not hasattr(self, 'user'):
145
+ webbrowser.open(f"{self.endpoint}{path}")
146
+ return 0, dict(success="Open browser.")
147
+ token = dict(auth_type=self.user['auth_type'])
148
+ if self.user['auth_type'] == "noauth":
149
+ webbrowser.open(f"{self.endpoint}{path}")
150
+ return 0, dict(success="Open browser.")
151
+ elif self.user['auth_type'] == "idpw":
152
+ hashed = self.user['password'] if self.user['hash']=='plain' else common.hash_password(self.user['password'], self.user['hash'])
153
+ token = dict(**token, **dict(user=self.user['name'], token=common.encrypt(path, hashed)))
154
+ token = convert.str2b64str(common.to_str(token))
155
+ webbrowser.open(f"{self.endpoint}/dosignin_token/{token}{path}")
156
+ return 0, dict(success="Open browser.")
157
+ elif self.user['auth_type'] == "apikey":
158
+ hashed = common.hash_password(self.user['apikey'], 'sha1')
159
+ token = dict(**token, **dict(user=self.user['name'], token=common.encrypt(path, hashed)))
160
+ token = convert.str2b64str(common.to_str(token))
161
+ webbrowser.open(f"{self.endpoint}/dosignin_token/{token}{path}")
162
+ return 0, dict(success="Open browser.")
163
+ elif self.user['auth_type'] == "oauth2":
164
+ if self.oauth2 == 'google':
165
+ webbrowser.open(f"{self.endpoint}/oauth2/google/session/{self.user['access_token']}{path}")
166
+ return 0, dict(success="Open browser.")
167
+ if self.oauth2 == 'github':
168
+ webbrowser.open(f"{self.endpoint}/oauth2/github/session/{self.user['access_token']}{path}")
169
+ return 0, dict(success="Open browser.")
170
+ if self.oauth2 == 'azure':
171
+ webbrowser.open(f"{self.endpoint}/oauth2/azure/session/{self.user['access_token']}{path}")
172
+ return 0, dict(success="Open browser.")
173
+ elif self.user['auth_type'] == "saml":
174
+ if self.saml == 'azure':
175
+ webbrowser.open(f"{self.endpoint}/saml/azure/session/{self.user['saml_token']}{path}")
176
+ return 0, dict(success="Open browser.")
177
+ return 1, dict(warn="unsupported auth_type.")
cmdbox/app/feature.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from cmdbox import version
2
- from cmdbox.app import edge
3
- from cmdbox.app.commons import redis_client
2
+ from cmdbox.app import common, edge_tool
3
+ from cmdbox.app.commons import convert, redis_client
4
4
  from cmdbox.app.web import Web
5
5
  from fastapi import FastAPI
6
6
  from pathlib import Path
@@ -27,6 +27,7 @@ class Feature(object):
27
27
  self.ver = ver
28
28
  self.appcls = appcls
29
29
  self.default_svname:str = ver.__appid__
30
+ self.default_data:Path = os.environ.get('DATA_DIR', common.HOME_DIR / f".{self.ver.__appid__}")
30
31
 
31
32
  def get_mode(self) -> Union[str, List[str]]:
32
33
  """
@@ -105,13 +106,13 @@ class Feature(object):
105
106
  """
106
107
  raise NotImplementedError
107
108
 
108
- def edgerun(self, opt:Dict[str, Any], tool:edge.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
109
+ def edgerun(self, opt:Dict[str, Any], tool:edge_tool.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
109
110
  """
110
111
  この機能のエッジ側の実行を行います
111
112
 
112
113
  Args:
113
114
  opt (Dict[str, Any]): オプション
114
- tool (edge.Tool): 通知関数などedge側のUI操作を行うためのクラス
115
+ tool (edge_tool.Tool): 通知関数などedge側のUI操作を行うためのクラス
115
116
  logger (logging.Logger): ロガー
116
117
  timeout (int): タイムアウト時間
117
118
  prevres (Any): 前コマンドの結果。pipeline実行の実行結果を参照する時に使用します。
@@ -126,7 +127,7 @@ class OneshotEdgeFeature(Feature):
126
127
  """
127
128
  一度だけ実行するエッジ機能の基底クラス
128
129
  """
129
- def edgerun(self, opt:Dict[str, Any], tool:edge.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
130
+ def edgerun(self, opt:Dict[str, Any], tool:edge_tool.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
130
131
  status, res = tool.exec_cmd(opt, logger, timeout, prevres)
131
132
  yield 1, res
132
133
 
@@ -134,7 +135,7 @@ class OneshotNotifyEdgeFeature(OneshotEdgeFeature):
134
135
  """
135
136
  実行結果の通知を行うエッジ機能の基底クラス
136
137
  """
137
- def edgerun(self, opt:Dict[str, Any], tool:edge.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
138
+ def edgerun(self, opt:Dict[str, Any], tool:edge_tool.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
138
139
  status, res = next(super().edgerun(opt, tool, logger, timeout, prevres))
139
140
  tool.notify(res)
140
141
  yield status, res
@@ -143,7 +144,7 @@ class ResultEdgeFeature(Feature):
143
144
  """
144
145
  実行結果をWebブラウザで表示するエッジ機能の基底クラス
145
146
  """
146
- def edgerun(self, opt:Dict[str, Any], tool:edge.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
147
+ def edgerun(self, opt:Dict[str, Any], tool:edge_tool.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
147
148
  status, res = next(super().edgerun(opt, tool, logger, timeout, prevres))
148
149
  if status == 0:
149
150
  status, res = tool.pub_result(opt['title'], res, timeout)
@@ -155,7 +156,7 @@ class OneshotResultEdgeFeature(ResultEdgeFeature):
155
156
  """
156
157
  一度だけ実行結果をWebブラウザで表示するエッジ機能の基底クラス
157
158
  """
158
- def edgerun(self, opt:Dict[str, Any], tool:edge.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
159
+ def edgerun(self, opt:Dict[str, Any], tool:edge_tool.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
159
160
  status, res = next(super().edgerun(opt, tool, logger, timeout, prevres))
160
161
  yield 1, res
161
162
 
@@ -163,7 +164,7 @@ class UnsupportEdgeFeature(Feature):
163
164
  """
164
165
  サポートされていないエッジ機能の基底クラス
165
166
  """
166
- def edgerun(self, opt:Dict[str, Any], tool:edge.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
167
+ def edgerun(self, opt:Dict[str, Any], tool:edge_tool.Tool, logger:logging.Logger, timeout:int, prevres:Any=None):
167
168
  res = dict(warn=f'Unsupported edgerun. mode="{opt["mode"]}", cmd="{opt["cmd"]}"')
168
169
  tool.notify(res)
169
170
  yield 1, res