pilot.linkstec 0.0.31__py3-none-any.whl → 0.0.90__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.
- pilot/base/__init__.py +0 -0
- pilot/base/ai_call.py +38 -0
- pilot/base/ai_info.py +20 -0
- pilot/base/chage_file_tag_base.py +73 -0
- pilot/base/db_operation_base.py +536 -0
- pilot/base/delete_commnents_base.py +306 -0
- pilot/base/file_operation.py +44 -0
- pilot/base/get_file_encoding.py +14 -0
- pilot/base/make_parsing_java_file_order_base.py +154 -0
- pilot/base/split_file_base.py +256 -0
- pilot/create_python/__init__.py +0 -0
- pilot/create_python/config/__init__.py +0 -0
- pilot/create_python/create_python.py +150 -0
- pilot/create_python/sample/__init__.py +0 -0
- pilot/create_python/sample/child_sample/__init__.py +0 -0
- pilot/create_python/sample/child_sample/job/__init__.py +0 -0
- pilot/create_python/sample/config/__init__.py +0 -0
- pilot/db/__init__.py +0 -0
- pilot/db/create_table.py +34 -0
- pilot/db/db_connect.py +49 -0
- pilot/db/db_main.py +293 -0
- pilot/db/db_util.py +508 -0
- pilot/db/ddl/__init__.py +18 -0
- pilot/db/dml/__init__.py +18 -0
- pilot/db/sql_executor.py +62 -0
- pilot/db/sql_loader.py +233 -0
- pilot/db/sql_service.py +55 -0
- pilot/file_tool/__init__.py +0 -0
- pilot/file_tool/create_prompt_file.py +75 -0
- pilot/file_tool/json_file_tool.py +103 -0
- pilot/job/impl/base_job.py +1 -1
- pilot/prompt/__init__.py +0 -0
- {pilot_linkstec-0.0.31.dist-info → pilot_linkstec-0.0.90.dist-info}/METADATA +1 -1
- pilot_linkstec-0.0.90.dist-info/RECORD +66 -0
- pilot_linkstec-0.0.31.dist-info/RECORD +0 -35
- {pilot_linkstec-0.0.31.dist-info → pilot_linkstec-0.0.90.dist-info}/WHEEL +0 -0
- {pilot_linkstec-0.0.31.dist-info → pilot_linkstec-0.0.90.dist-info}/licenses/LICENSE +0 -0
- {pilot_linkstec-0.0.31.dist-info → pilot_linkstec-0.0.90.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Dict, Tuple
|
|
6
|
+
|
|
7
|
+
from lxml import etree as ET
|
|
8
|
+
|
|
9
|
+
from pilot.job.impl.base_job import BaseJob
|
|
10
|
+
|
|
11
|
+
from base.file_operation import read_file_lines, write_json_file
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SplitFile(BaseJob):
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def split_java_methods(java_code: str):
|
|
18
|
+
"""
|
|
19
|
+
与えられた単一の完全な Java ソースコードから
|
|
20
|
+
1. 各メソッド(コンストラクタ含む)本体(コメント・アノテーション付き)
|
|
21
|
+
2. メソッドを除いた残りのクラスコード
|
|
22
|
+
を抽出し、指示通りの JSON 文字列を返す。
|
|
23
|
+
|
|
24
|
+
【前提】
|
|
25
|
+
* 入力は 1 ファイル分だけ。
|
|
26
|
+
* クラスは 1 つ(内部クラス・列挙型があっても OK)。
|
|
27
|
+
* メソッドはネストしない(ローカルクラス・ローカルメソッドは対象外)。
|
|
28
|
+
* 文字列リテラルやコメント中の波括弧は正規表現だけでは完全に安全に扱えないが、
|
|
29
|
+
本ユーティリティは「実務上よく出会う」コードを対象に設計している。
|
|
30
|
+
必要なら JavaParser 等の本格的パーサに差し替えて下さい。
|
|
31
|
+
|
|
32
|
+
【出力形式】
|
|
33
|
+
JSON 文字列(UTF‑8)で、質問文に書かれたスキーマ通り。
|
|
34
|
+
"""
|
|
35
|
+
# ------------------------------------------------------------------
|
|
36
|
+
# 1️⃣ パッケージ・インポートの取得(無い場合は空文字列)
|
|
37
|
+
# ------------------------------------------------------------------
|
|
38
|
+
package_pat = re.compile(r'^\s*package\s+([\w\.]+)\s*;\s*', re.MULTILINE)
|
|
39
|
+
pkg_match = package_pat.search(java_code)
|
|
40
|
+
package_name = pkg_match.group(1) if pkg_match else ""
|
|
41
|
+
|
|
42
|
+
# ------------------------------------------------------------------
|
|
43
|
+
# 2️⃣ クラス宣言の取得(クラス名だけ抜き出す)
|
|
44
|
+
# ------------------------------------------------------------------
|
|
45
|
+
# class / interface / enum のいずれかが対象。アノテーションや修飾子は無視。
|
|
46
|
+
class_pat = re.compile(
|
|
47
|
+
r'''(?x) # Verbose
|
|
48
|
+
(?:@\w+(?:\s*\([^)]*\))?\s*)* # 前置アノテーション(任意)
|
|
49
|
+
(public|protected|private)?\s* # アクセス修飾子(任意)
|
|
50
|
+
(final|abstract)?\s* # class 修飾子(任意)
|
|
51
|
+
(class|interface|enum)\s+ # キーワード
|
|
52
|
+
(?P<name>\w+) # クラス名(取得対象)
|
|
53
|
+
(?:\s*<[^>]*>)? # ジェネリクス(任意)
|
|
54
|
+
(?:\s+extends\s+[^{]+)? # extends 句(任意)
|
|
55
|
+
(?:\s+implements\s+[^{]+)? # implements 句(任意)
|
|
56
|
+
\s*{ # 開始波括弧
|
|
57
|
+
''')
|
|
58
|
+
class_match = class_pat.search(java_code)
|
|
59
|
+
if not class_match:
|
|
60
|
+
raise ValueError("クラス宣言が見つかりませんでした。")
|
|
61
|
+
class_name = class_match.group('name')
|
|
62
|
+
|
|
63
|
+
# ------------------------------------------------------------------
|
|
64
|
+
# 3️⃣ メソッド(=コンストラクタも含む)全体を抽出
|
|
65
|
+
# ------------------------------------------------------------------
|
|
66
|
+
# 正規表現で「コメント・アノテーション + 修飾子 + 戻り値(またはコンストラクタ) + 名前 + パラメータ + 本体」までを取得。
|
|
67
|
+
# コメントは //, /** */ , /* */ のいずれか。アノテーションは @ で始まる。
|
|
68
|
+
# 本体は波括弧の対称性を数えて取得(re.DOTALL で改行も含める)。
|
|
69
|
+
method_pat = re.compile(
|
|
70
|
+
r'''(?x) # Verbose
|
|
71
|
+
(?:
|
|
72
|
+
(?:/\*\*.*?\*/\s*)? # Javadoc コメント(任意)
|
|
73
|
+
(?:/\*.*?\*/\s*)? # ブロックコメント(任意)
|
|
74
|
+
(?:\/\/[^\n]*\s*)? # 行コメント(任意)
|
|
75
|
+
)*
|
|
76
|
+
(?:@\w+(?:\s*\([^)]*\))?\s*)* # アノテーション(0 個以上)
|
|
77
|
+
(?:public|protected|private|\s)* # アクセス修飾子(任意)
|
|
78
|
+
(?:static\s+)? # static 修飾子(任意)
|
|
79
|
+
(?:final\s+|synchronized\s+|abstract\s+|native\s+)* # 余分な修飾子(任意)
|
|
80
|
+
(?:<[^>]+>\s+)? # メソッドレベルのジェネリクス(任意)
|
|
81
|
+
(?:[\w\<\>\[\]]+\s+)? # 戻り値型(コンストラクタなら無い)
|
|
82
|
+
(?P<name>\w+) # メソッド名(コンストラクタはクラス名)
|
|
83
|
+
\s*\( # パラメータ開始
|
|
84
|
+
[^\)]* # 中身は簡易的に「) まで」スキップ
|
|
85
|
+
\)\s*
|
|
86
|
+
(?:throws\s+[^{]+)? # throws 句(任意)
|
|
87
|
+
\{ # 本体開始
|
|
88
|
+
''')
|
|
89
|
+
|
|
90
|
+
# メソッド本体の波括弧対称性を数えるためのヘルパー
|
|
91
|
+
def extract_body(start_idx: int) -> Tuple[int, str]:
|
|
92
|
+
"""start_idx は '{' の位置。対になる '}' まで走査して全文字列を返す。"""
|
|
93
|
+
depth = 0
|
|
94
|
+
i = start_idx
|
|
95
|
+
while i < len(java_code):
|
|
96
|
+
ch = java_code[i]
|
|
97
|
+
if ch == '{':
|
|
98
|
+
depth += 1
|
|
99
|
+
elif ch == '}':
|
|
100
|
+
depth -= 1
|
|
101
|
+
if depth == 0:
|
|
102
|
+
# i を含めて抜き出す
|
|
103
|
+
return i + 1, java_code[start_idx:i + 1]
|
|
104
|
+
i += 1
|
|
105
|
+
raise ValueError("メソッド本体の終端 '}' が見つかりません。")
|
|
106
|
+
|
|
107
|
+
# すべてのメソッド情報を格納するリスト
|
|
108
|
+
methods: List[Dict] = []
|
|
109
|
+
|
|
110
|
+
# 走査インデックス
|
|
111
|
+
pos = 0
|
|
112
|
+
while True:
|
|
113
|
+
m = method_pat.search(java_code, pos)
|
|
114
|
+
if not m:
|
|
115
|
+
break
|
|
116
|
+
|
|
117
|
+
# メソッド名取得
|
|
118
|
+
method_name = m.group('name')
|
|
119
|
+
# コンストラクタかどうか判定(名前がクラス名と同じならコンストラクタ)
|
|
120
|
+
is_constructor = method_name == class_name
|
|
121
|
+
|
|
122
|
+
# メソッド宣言全体の開始位置(コメント・アノテーションを含むので、直前に遡る)
|
|
123
|
+
decl_start = m.start()
|
|
124
|
+
# ただし上記正規表現はコメント・アノテーションを「0 回以上」含めているので
|
|
125
|
+
# ここで取得した start はすでにそれらを含んだ位置になる。
|
|
126
|
+
|
|
127
|
+
# 本体開始波括弧のインデックス
|
|
128
|
+
brace_idx = java_code.find('{', m.end() - 1)
|
|
129
|
+
if brace_idx == -1:
|
|
130
|
+
raise ValueError("メソッド本体開始 '{' が見つかりません。")
|
|
131
|
+
|
|
132
|
+
# 本体全体を取得
|
|
133
|
+
body_end, body_str = extract_body(brace_idx)
|
|
134
|
+
|
|
135
|
+
# 完全なメソッド文字列(宣言 + 本体)
|
|
136
|
+
method_full = java_code[decl_start:body_end]
|
|
137
|
+
|
|
138
|
+
# 位置情報を保持して後で「残りコード」から除去できるようにする
|
|
139
|
+
methods.append({
|
|
140
|
+
"methodName": method_name,
|
|
141
|
+
"isConstructor": is_constructor,
|
|
142
|
+
"code": method_full,
|
|
143
|
+
"start": decl_start,
|
|
144
|
+
"end": body_end
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
# 次の検索は本体終了位置から続ける
|
|
148
|
+
pos = body_end
|
|
149
|
+
|
|
150
|
+
# ------------------------------------------------------------------
|
|
151
|
+
# 4️⃣ 「残りコード」作成(メソッド領域を空白に置換してからトリム)
|
|
152
|
+
# ------------------------------------------------------------------
|
|
153
|
+
remaining = list(java_code) # 文字列を可変リストに
|
|
154
|
+
for m in methods:
|
|
155
|
+
# メソッド領域はスペースで埋めておく(行番号・インデントを保つため)
|
|
156
|
+
for i in range(m["start"], m["end"]):
|
|
157
|
+
remaining[i] = ' '
|
|
158
|
+
remaining_code = ''.join(remaining)
|
|
159
|
+
|
|
160
|
+
# 余計な空行を削除(ただしクラスの波括弧は残す)
|
|
161
|
+
remaining_code = re.sub(r'\n\s*\n', '\n', remaining_code).strip() + '\n'
|
|
162
|
+
|
|
163
|
+
# ------------------------------------------------------------------
|
|
164
|
+
# 5️⃣ JSON オブジェクト生成
|
|
165
|
+
# ------------------------------------------------------------------
|
|
166
|
+
json_files: List[Dict] = []
|
|
167
|
+
for m in methods:
|
|
168
|
+
file_name = f"{class_name}_{m['methodName']}.txt"
|
|
169
|
+
# エスケープ処理(JSON 用に \ と " をエスケープ)
|
|
170
|
+
escaped_code = m["code"].replace('\\', '\\\\').replace('"', '\\"')
|
|
171
|
+
escaped_remaining = remaining_code.replace('\\', '\\\\').replace('"', '\\"')
|
|
172
|
+
|
|
173
|
+
json_files.append({
|
|
174
|
+
"fileName": file_name,
|
|
175
|
+
"className": class_name,
|
|
176
|
+
"methodName": m["methodName"],
|
|
177
|
+
"package": package_name,
|
|
178
|
+
"code": escaped_code,
|
|
179
|
+
"remainingClassCode": escaped_remaining
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
result = {"files": json_files}
|
|
183
|
+
return json.dumps(result, ensure_ascii=False, indent=2)
|
|
184
|
+
|
|
185
|
+
@staticmethod
|
|
186
|
+
def _extract_statement_nodes(root: ET.Element) -> List[ET.Element]:
|
|
187
|
+
"""返回所有可执行语句的 Element(保留完整节点)。"""
|
|
188
|
+
stmts = []
|
|
189
|
+
for tag in ("select", "insert", "update", "delete"):
|
|
190
|
+
stmts.extend(root.findall(f".//{tag}"))
|
|
191
|
+
return stmts
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def split_mybatis_xml(self, xml_path, out_dir: Path) -> List:
|
|
195
|
+
"""
|
|
196
|
+
把根节点中的每条语句(select/insert/update/delete)按照它们的 id
|
|
197
|
+
写入独立文件。每个子文件只包含单条语句本身(不再包裹 <mapper>)。
|
|
198
|
+
"""
|
|
199
|
+
parser = ET.XMLParser(remove_blank_text=False) # 保留原始缩进、换行
|
|
200
|
+
tree = ET.parse(str(xml_path), parser=parser)
|
|
201
|
+
root = tree.getroot()
|
|
202
|
+
|
|
203
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
204
|
+
|
|
205
|
+
out_put_list = []
|
|
206
|
+
for stmt in self._extract_statement_nodes(root):
|
|
207
|
+
stmt_id = stmt.get("id")
|
|
208
|
+
if not stmt_id: # 没有 id 的语句直接跳过
|
|
209
|
+
continue
|
|
210
|
+
|
|
211
|
+
# 复制一份,防止修改原始树结构
|
|
212
|
+
stmt_copy = copy.deepcopy(stmt)
|
|
213
|
+
|
|
214
|
+
# 生成文件路径(这里仍然使用 .xml,当然你可以改成 .sql、.txt …)
|
|
215
|
+
out_path = out_dir / f"{stmt_id}.xml"
|
|
216
|
+
|
|
217
|
+
# 把单条语句写入文件
|
|
218
|
+
# - xml_declaration=False → 不输出 <?xml …?> 声明
|
|
219
|
+
# - pretty_print=True → 保持原始的缩进格式
|
|
220
|
+
tree = ET.ElementTree(stmt_copy)
|
|
221
|
+
tree.write(
|
|
222
|
+
str(out_path),
|
|
223
|
+
encoding="utf-8",
|
|
224
|
+
xml_declaration=False,
|
|
225
|
+
pretty_print=True
|
|
226
|
+
)
|
|
227
|
+
print(f"✔ 生成 {out_path}")
|
|
228
|
+
out_put_list.append(out_path)
|
|
229
|
+
|
|
230
|
+
return out_put_list
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def run(self):
|
|
234
|
+
try:
|
|
235
|
+
|
|
236
|
+
lines = read_file_lines(self.file_path)
|
|
237
|
+
|
|
238
|
+
str_code = ''.join(lines)
|
|
239
|
+
|
|
240
|
+
remove_file_type = self.__getattribute__('file_type')
|
|
241
|
+
output_file_path = self.__getattribute__('target_file_path')
|
|
242
|
+
match remove_file_type:
|
|
243
|
+
case 'Java':
|
|
244
|
+
_split_result = self.split_java_methods(str_code)
|
|
245
|
+
write_json_file(json.loads(_split_result), output_file_path)
|
|
246
|
+
case 'mybatis':
|
|
247
|
+
_split_file_list = self.split_mybatis_xml(self.file_path, output_file_path)
|
|
248
|
+
setattr(self, 'split_file_list', _split_file_list)
|
|
249
|
+
case _:
|
|
250
|
+
_split_result =None
|
|
251
|
+
|
|
252
|
+
except Exception as e:
|
|
253
|
+
self.logger.error(f"{__name__}異常終了. {e}")
|
|
254
|
+
return
|
|
255
|
+
|
|
256
|
+
super().run()
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import configparser
|
|
2
|
+
import os
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
def generate_code():
|
|
7
|
+
# マインコンバート
|
|
8
|
+
cwd = Path(os.getcwd())
|
|
9
|
+
|
|
10
|
+
config_file_path = os.path.join(cwd, 'config', 'create_file.properties')
|
|
11
|
+
config_dto = read_config_file(config_file_path)
|
|
12
|
+
|
|
13
|
+
target_project_root_path = cwd.parent
|
|
14
|
+
# サンプルファイル作成
|
|
15
|
+
print('CONFIGファイルを作成する')
|
|
16
|
+
sample_config_file_path = os.path.join(cwd, 'sample', 'config', 'properties.txt')
|
|
17
|
+
replacements = {
|
|
18
|
+
"WORK_SPACE": config_dto.work_space,
|
|
19
|
+
"PROJECT_NAME": os.path.basename(target_project_root_path),
|
|
20
|
+
"STEP_NAME": "step_000,step_001,step_002"
|
|
21
|
+
}
|
|
22
|
+
target_project_config_path = os.path.join(target_project_root_path, 'config', config_dto.sub_project_name + '_' + config_dto.sub_source_folder + '_' + config_dto.sub_sub_source_folder_1+'.properties')
|
|
23
|
+
read_replace_create_file(sample_config_file_path, replacements, Path(target_project_config_path))
|
|
24
|
+
|
|
25
|
+
print('Main Jobファイルを作成する')
|
|
26
|
+
# サブファイルコントロール、ジョブ、ユニットファイルの作成
|
|
27
|
+
target_project_sub_project_path = os.path.join(target_project_root_path, 'src', config_dto.sub_project_name, config_dto.sub_source_folder, config_dto.sub_sub_source_folder_1)
|
|
28
|
+
# サンプルサブコントロールファイルの作成
|
|
29
|
+
sample_job_file_path = os.path.join(cwd, 'sample', 'child_sample', 'job.txt')
|
|
30
|
+
replacements_job = {}
|
|
31
|
+
target_project_sub_job_path = os.path.join(target_project_sub_project_path, config_dto.sub_source_folder + '_' + config_dto.sub_sub_source_folder_1 + '_job.py')
|
|
32
|
+
read_replace_create_file(sample_job_file_path, replacements_job, Path(target_project_sub_job_path))
|
|
33
|
+
|
|
34
|
+
print('Main Unitファイルを作成する')
|
|
35
|
+
sample_unit_file_path = os.path.join(cwd, 'sample', 'child_sample', 'unit.txt')
|
|
36
|
+
replacements_unit = {
|
|
37
|
+
"JOB_PACKAGE": 'src.'+ config_dto.sub_project_name + '.'+ config_dto.sub_source_folder + '.' + config_dto.sub_sub_source_folder_1 + '.' + os.path.basename(target_project_sub_job_path).split('.')[0],
|
|
38
|
+
"GYOMU_JOB_PACKAGE_000": 'src.'+ config_dto.sub_project_name + '.' + config_dto.sub_source_folder + '.' + config_dto.sub_sub_source_folder_1 + '.jobs.job_000',
|
|
39
|
+
"GYOMU_JOB_PACKAGE_001": 'src.' + config_dto.sub_project_name + '.' + config_dto.sub_source_folder + '.' + config_dto.sub_sub_source_folder_1 + '.jobs.job_001',
|
|
40
|
+
"GYOMU_JOB_PACKAGE_002": 'src.' + config_dto.sub_project_name + '.' + config_dto.sub_source_folder + '.' + config_dto.sub_sub_source_folder_1 + '.jobs.job_002'
|
|
41
|
+
}
|
|
42
|
+
target_project_unit_path = os.path.join(target_project_sub_project_path, config_dto.sub_source_folder + '_' + config_dto.sub_sub_source_folder_1 + '_unit.py' )
|
|
43
|
+
read_replace_create_file(sample_unit_file_path, replacements_unit, Path(target_project_unit_path))
|
|
44
|
+
|
|
45
|
+
print('Main Controllerファイルを作成する')
|
|
46
|
+
sample_controller_file_path = os.path.join(cwd, 'sample', 'child_sample', 'controller.txt')
|
|
47
|
+
replacements_control = {
|
|
48
|
+
"UNIT_PACKAGE": 'src.'+ config_dto.sub_project_name + '.'+ config_dto.sub_source_folder + '.'+ config_dto.sub_sub_source_folder_1 + '.' + os.path.basename(target_project_unit_path).split('.')[0]
|
|
49
|
+
}
|
|
50
|
+
target_project_sub_controller_path = os.path.join(target_project_sub_project_path, config_dto.sub_source_folder + '_' + config_dto.sub_sub_source_folder_1 + '_control.py')
|
|
51
|
+
read_replace_create_file(sample_controller_file_path, replacements_control, Path(target_project_sub_controller_path))
|
|
52
|
+
|
|
53
|
+
init_file_path = Path(os.path.join(target_project_sub_project_path, '__init__.py'))
|
|
54
|
+
create_file(init_file_path,'')
|
|
55
|
+
|
|
56
|
+
print('業務Job用フォルダを作成する')
|
|
57
|
+
job_file_path = Path(os.path.join(target_project_sub_project_path,'jobs'))
|
|
58
|
+
job_file_path.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
sample_job000_file_path = os.path.join(cwd, 'sample', 'child_sample', 'job' ,'job_000.txt')
|
|
60
|
+
sample_job_sample_file_path = os.path.join(cwd, 'sample', 'child_sample', 'job', 'job_sample.txt')
|
|
61
|
+
replacements_job000 = {
|
|
62
|
+
'JOB_PACKAGE': 'src.'+ config_dto.sub_project_name + '.'+ config_dto.sub_source_folder + '.' + config_dto.sub_sub_source_folder_1 + '.' + os.path.basename(target_project_sub_job_path).split('.')[0]
|
|
63
|
+
}
|
|
64
|
+
target_project_job000_path = os.path.join(target_project_sub_project_path, 'jobs','job_000.py')
|
|
65
|
+
target_project_job001_path = os.path.join(target_project_sub_project_path, 'jobs','job_001.py')
|
|
66
|
+
target_project_job002_path = os.path.join(target_project_sub_project_path, 'jobs', 'job_002.py')
|
|
67
|
+
read_replace_create_file(sample_job000_file_path, replacements_job000, Path(target_project_job000_path))
|
|
68
|
+
replacements_job001 = {
|
|
69
|
+
'JOB_NAME':'Job_001',
|
|
70
|
+
'JOB_PACKAGE': 'src.'+ config_dto.sub_project_name + '.'+ config_dto.sub_source_folder + '.' + config_dto.sub_sub_source_folder_1 + '.' + os.path.basename(target_project_sub_job_path).split('.')[0]
|
|
71
|
+
}
|
|
72
|
+
read_replace_create_file(sample_job_sample_file_path, replacements_job001, Path(target_project_job001_path))
|
|
73
|
+
replacements_job002 = {
|
|
74
|
+
'JOB_NAME': 'Job_002',
|
|
75
|
+
'JOB_PACKAGE': 'src.'+ config_dto.sub_project_name + '.'+ config_dto.sub_source_folder + '.' + config_dto.sub_sub_source_folder_1 + '.' + os.path.basename(target_project_sub_job_path).split('.')[0]
|
|
76
|
+
}
|
|
77
|
+
read_replace_create_file(sample_job_sample_file_path, replacements_job002, Path(target_project_job002_path))
|
|
78
|
+
|
|
79
|
+
init_job_file_path = Path(os.path.join(target_project_sub_project_path, 'jobs', '__init__.py'))
|
|
80
|
+
create_file(init_job_file_path,'')
|
|
81
|
+
|
|
82
|
+
print('Main controllerファイルを作成する')
|
|
83
|
+
# サンプルパス
|
|
84
|
+
sample_main_controller_file_path = os.path.join(cwd, 'sample', 'main_convert.txt')
|
|
85
|
+
# パラメーター
|
|
86
|
+
replacements = {
|
|
87
|
+
"CONTROLLER_PACKAGE": 'src.'+ config_dto.sub_project_name + '.' + config_dto.sub_source_folder + '.' + config_dto.sub_sub_source_folder_1 +'.' + os.path.basename(target_project_sub_controller_path).split('.')[0],
|
|
88
|
+
"PYTHON_CONFIG_PROPERTIES": config_dto.sub_project_name + '_' + config_dto.sub_source_folder + '_' + config_dto.sub_sub_source_folder_1 + '.properties'
|
|
89
|
+
}
|
|
90
|
+
# 目標ファイルパス
|
|
91
|
+
target_project_main_controller_path = Path(os.path.join(target_project_root_path, config_dto.sub_project_name + '_'
|
|
92
|
+
+ config_dto.sub_source_folder + '_' + config_dto.sub_sub_source_folder_1 +'_controller.py'))
|
|
93
|
+
read_replace_create_file(sample_main_controller_file_path, replacements, target_project_main_controller_path)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def read_replace_create_file(sample_file_path:str, replacements, target_file_path):
|
|
97
|
+
file_content = read_file(sample_file_path)
|
|
98
|
+
after_replace_content = replace_template_vars(file_content, replacements)
|
|
99
|
+
|
|
100
|
+
create_file(target_file_path, after_replace_content)
|
|
101
|
+
|
|
102
|
+
def read_file(template_file_path) -> str:
|
|
103
|
+
with open(template_file_path, 'r', encoding='utf-8') as f:
|
|
104
|
+
template_file = f.read()
|
|
105
|
+
return template_file
|
|
106
|
+
|
|
107
|
+
def replace_template_vars(template: str, replacements: dict) -> str:
|
|
108
|
+
result = template
|
|
109
|
+
if replacements:
|
|
110
|
+
for key, value in replacements.items():
|
|
111
|
+
placeholder = f"{{{{{key}}}}}"
|
|
112
|
+
result = result.replace(placeholder, str(value))
|
|
113
|
+
return result
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def create_file(target_path, target_file_content):
|
|
117
|
+
target_path.parent.mkdir(parents=True, exist_ok=True)
|
|
118
|
+
with open(target_path, 'w', encoding='utf-8') as f:
|
|
119
|
+
f.write(target_file_content)
|
|
120
|
+
|
|
121
|
+
def read_config_file(find_config_path):
|
|
122
|
+
config = configparser.ConfigParser()
|
|
123
|
+
config.optionxform = str
|
|
124
|
+
|
|
125
|
+
with open(find_config_path, 'r', encoding='utf-8') as f:
|
|
126
|
+
content = f.read()
|
|
127
|
+
if not content.lstrip().startswith('['):
|
|
128
|
+
content = '[DEFAULT]\n' + content
|
|
129
|
+
config.read_string(content)
|
|
130
|
+
|
|
131
|
+
work_space = config.get('DEFAULT', 'work_space', fallback='.')
|
|
132
|
+
str_sub_project_name = config.get('DEFAULT', 'sub_project_name', fallback='.')
|
|
133
|
+
str_sub_source_folder = config.get('DEFAULT', 'sub_source_folder', fallback='.')
|
|
134
|
+
str_source_folder_1 = config.get('DEFAULT', 'sub_sub_source_folder_1', fallback='.')
|
|
135
|
+
return ConfigDTO(
|
|
136
|
+
work_space=work_space,
|
|
137
|
+
sub_project_name=str_sub_project_name,
|
|
138
|
+
sub_source_folder=str_sub_source_folder,
|
|
139
|
+
sub_sub_source_folder_1=str_source_folder_1
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
@dataclass
|
|
143
|
+
class ConfigDTO:
|
|
144
|
+
work_space: str
|
|
145
|
+
sub_project_name:str
|
|
146
|
+
sub_source_folder:str
|
|
147
|
+
sub_sub_source_folder_1:str
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
generate_code()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
pilot/db/__init__.py
ADDED
|
File without changes
|
pilot/db/create_table.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from db.sql_executor import exec_ddl
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
this_path = Path(__file__).resolve()
|
|
7
|
+
|
|
8
|
+
this_dir = this_path.parent
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
ddl_file_path_list = [
|
|
15
|
+
# this_dir / 'ddl' / 'METHOD_CLASS_INFO.sql',
|
|
16
|
+
# this_dir / 'ddl' / 'METHOD_FILE_INFO.sql',
|
|
17
|
+
this_dir / 'ddl' / 'METHOD_INFO.sql',
|
|
18
|
+
# this_dir / 'ddl' / 'METHOD_PARAMETER_INFO.sql',
|
|
19
|
+
# this_dir / 'ddl' / 'METHOD_PARSING_INFO.sql',
|
|
20
|
+
# this_dir / 'ddl' / 'METHOD_SUB_METHOD_INFO.sql',
|
|
21
|
+
# this_dir / 'ddl' / 'SQL_CONDITION_INFO.sql',
|
|
22
|
+
# this_dir / 'ddl' / 'SQL_CONTENT_INFO.sql',
|
|
23
|
+
# this_dir / 'ddl' / 'SQL_FILE_INFO.sql',
|
|
24
|
+
# this_dir / 'ddl' / 'SQL_TABLE_INFO.sql',
|
|
25
|
+
# this_dir / 'ddl' / 'SQL_PARAMETER_INFO.sql',
|
|
26
|
+
# this_dir / 'ddl' / 'SQL_PARSING_INFO.sql',
|
|
27
|
+
# this_dir / 'ddl' / 'SQL_COLUMN_INFO.sql',
|
|
28
|
+
# this_dir / 'ddl' / 'TABLE_INFO.sql',
|
|
29
|
+
# this_dir / 'ddl' / 'TABLE_COLUMN_INFO.sql'
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
for ddl_file_path in ddl_file_path_list:
|
|
34
|
+
exec_ddl(str(ddl_file_path))
|
pilot/db/db_connect.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import sqlite3
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from contextlib import contextmanager
|
|
4
|
+
from typing import Generator
|
|
5
|
+
|
|
6
|
+
# -------------------- 配置 --------------------
|
|
7
|
+
DB_FILE = Path(__file__).with_name("app.sqlite3") # 默认数据库文件
|
|
8
|
+
# ------------------------------------------------
|
|
9
|
+
|
|
10
|
+
def _create_connection(db_path: Path = DB_FILE) -> sqlite3.Connection:
|
|
11
|
+
"""
|
|
12
|
+
创建并返回一个 SQLite 连接对象。
|
|
13
|
+
- 自动创建文件(如果不存在)。
|
|
14
|
+
- 开启 WAL 模式,提高并发读取性能。
|
|
15
|
+
"""
|
|
16
|
+
conn = sqlite3.connect(db_path, detect_types=sqlite3.PARSE_DECLTYPES)
|
|
17
|
+
# 让查询结果可以像字典一样访问(可选)
|
|
18
|
+
conn.row_factory = sqlite3.Row
|
|
19
|
+
# 开启 Write‑Ahead Logging(一次性设置即可)
|
|
20
|
+
conn.execute("PRAGMA journal_mode=WAL;")
|
|
21
|
+
return conn
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@contextmanager
|
|
25
|
+
def get_connection(db_path: Path = DB_FILE) -> Generator[sqlite3.Connection, None, None]:
|
|
26
|
+
"""
|
|
27
|
+
上下文管理器:自动打开连接、提交事务并在结束时关闭。
|
|
28
|
+
使用方式:
|
|
29
|
+
with get_connection() as conn:
|
|
30
|
+
conn.execute(...)
|
|
31
|
+
"""
|
|
32
|
+
conn = _create_connection(db_path)
|
|
33
|
+
try:
|
|
34
|
+
yield conn
|
|
35
|
+
conn.commit() # 正常退出时提交事务
|
|
36
|
+
except Exception: # 发生异常则回滚
|
|
37
|
+
conn.rollback()
|
|
38
|
+
raise
|
|
39
|
+
finally:
|
|
40
|
+
conn.close()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_raw_connection(db_path: Path = DB_FILE) -> sqlite3.Connection:
|
|
44
|
+
"""
|
|
45
|
+
如果你不想使用上下文管理器,而是自行控制生命周期,
|
|
46
|
+
可以直接调用此函数获取一个 Connection 对象。
|
|
47
|
+
注意:使用完后务必手动 `conn.close()`
|
|
48
|
+
"""
|
|
49
|
+
return _create_connection(db_path)
|