pilot.linkstec 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (33) hide show
  1. pilot_linkstec-0.0.1/LICENSE +19 -0
  2. pilot_linkstec-0.0.1/PKG-INFO +20 -0
  3. pilot_linkstec-0.0.1/README.md +4 -0
  4. pilot_linkstec-0.0.1/pyproject.toml +20 -0
  5. pilot_linkstec-0.0.1/setup.cfg +4 -0
  6. pilot_linkstec-0.0.1/src/pilot/__init__.py +0 -0
  7. pilot_linkstec-0.0.1/src/pilot/config/__init__.py +0 -0
  8. pilot_linkstec-0.0.1/src/pilot/config/config_reader.py +89 -0
  9. pilot_linkstec-0.0.1/src/pilot/control/__init__.py +0 -0
  10. pilot_linkstec-0.0.1/src/pilot/control/control_interface.py +6 -0
  11. pilot_linkstec-0.0.1/src/pilot/control/impl/__init__.py +0 -0
  12. pilot_linkstec-0.0.1/src/pilot/control/impl/base_controller.py +29 -0
  13. pilot_linkstec-0.0.1/src/pilot/conver/__init__.py +0 -0
  14. pilot_linkstec-0.0.1/src/pilot/conver/converfileEncodding.py +77 -0
  15. pilot_linkstec-0.0.1/src/pilot/conver/nkf_converter.py +28 -0
  16. pilot_linkstec-0.0.1/src/pilot/generater/__init__.py +0 -0
  17. pilot_linkstec-0.0.1/src/pilot/generater/vertexai.py +66 -0
  18. pilot_linkstec-0.0.1/src/pilot/job/__init__.py +0 -0
  19. pilot_linkstec-0.0.1/src/pilot/job/impl/__init__.py +0 -0
  20. pilot_linkstec-0.0.1/src/pilot/job/impl/base_job.py +288 -0
  21. pilot_linkstec-0.0.1/src/pilot/job/job_interface.py +6 -0
  22. pilot_linkstec-0.0.1/src/pilot/splitters/__init__.py +0 -0
  23. pilot_linkstec-0.0.1/src/pilot/splitters/cobolsplitter.py +128 -0
  24. pilot_linkstec-0.0.1/src/pilot/unit/__init__.py +0 -0
  25. pilot_linkstec-0.0.1/src/pilot/unit/impl/__init__.py +0 -0
  26. pilot_linkstec-0.0.1/src/pilot/unit/impl/base_unit.py +39 -0
  27. pilot_linkstec-0.0.1/src/pilot/unit/unit_interface.py +10 -0
  28. pilot_linkstec-0.0.1/src/pilot/util/__init__.py +0 -0
  29. pilot_linkstec-0.0.1/src/pilot/util/files.py +45 -0
  30. pilot_linkstec-0.0.1/src/pilot.linkstec.egg-info/PKG-INFO +20 -0
  31. pilot_linkstec-0.0.1/src/pilot.linkstec.egg-info/SOURCES.txt +31 -0
  32. pilot_linkstec-0.0.1/src/pilot.linkstec.egg-info/dependency_links.txt +1 -0
  33. pilot_linkstec-0.0.1/src/pilot.linkstec.egg-info/top_level.txt +1 -0
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2018 The Python Packaging Authority
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: pilot.linkstec
3
+ Version: 0.0.1
4
+ Summary: pilot of the ship, a tool for managing and deploying Python projects.
5
+ Author-email: wanglr <wanglr1980@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/nighter1980/pilot
8
+ Project-URL: Issues, https://github.com/nighter1980/pilot/issues
9
+ Keywords: python,project management,deployment
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Dynamic: license-file
16
+
17
+ # pilot
18
+
19
+ This is a simple example package. You can use
20
+ to write your content.
@@ -0,0 +1,4 @@
1
+ # pilot
2
+
3
+ This is a simple example package. You can use
4
+ to write your content.
@@ -0,0 +1,20 @@
1
+ [project]
2
+ name = "pilot.linkstec"
3
+ version = "0.0.1"
4
+ authors = [
5
+ { name="wanglr", email="wanglr1980@gmail.com" },
6
+ ]
7
+ description = "pilot of the ship, a tool for managing and deploying Python projects."
8
+ keywords = ["python", "project management", "deployment"]
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ classifiers = [
12
+ "Programming Language :: Python :: 3",
13
+ "Operating System :: OS Independent",
14
+ ]
15
+ license = "MIT"
16
+ license-files = ["LICEN[CS]E*"]
17
+
18
+ [project.urls]
19
+ Homepage = "https://github.com/nighter1980/pilot"
20
+ Issues = "https://github.com/nighter1980/pilot/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
File without changes
@@ -0,0 +1,89 @@
1
+ import configparser
2
+ import os
3
+ import inspect
4
+ from dataclasses import dataclass
5
+ from typing import List
6
+
7
+ @dataclass
8
+ class ConfigDTO:
9
+ work_space: str
10
+ threads: int
11
+ project: str
12
+ steps: list[str]
13
+ skipsteps: list[str]
14
+
15
+
16
+
17
+ class ConfigReader:
18
+ def __init__(self, filename = None):
19
+ filepath = None
20
+ if filename is None:
21
+ filepath = self.find_config_path()
22
+
23
+ if filename is not None:
24
+ cwd = os.getcwd()
25
+ filepath = os.path.join(cwd, 'config', filename)
26
+ if not os.path.exists(filepath):
27
+ raise FileNotFoundError(f"Configuration file not found: {filepath}")
28
+
29
+ self.config = configparser.ConfigParser()
30
+ self.config.optionxform = str
31
+
32
+ with open(filepath, 'r', encoding='utf-8') as f:
33
+ content = f.read()
34
+ if not content.lstrip().startswith('['):
35
+ content = '[DEFAULT]\n' + content
36
+ self.config.read_string(content)
37
+
38
+ @classmethod
39
+ def find_config_path(cls):
40
+ cwd = os.getcwd()
41
+ candidate_path = os.path.join(cwd, 'config', 'control.properties')
42
+ if os.path.exists(candidate_path):
43
+ return candidate_path
44
+
45
+ stack = inspect.stack()
46
+ for frame in stack:
47
+ caller_file = frame.filename
48
+ caller_dir = os.path.dirname(os.path.abspath(caller_file))
49
+ possible_path = os.path.abspath(os.path.join(caller_dir, '..', '..', 'config', 'control.properties'))
50
+ if os.path.exists(possible_path):
51
+ return possible_path
52
+
53
+ base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
54
+ fallback_path = os.path.join(base_dir, 'config', 'control.properties')
55
+ if os.path.exists(fallback_path):
56
+ return fallback_path
57
+
58
+ raise FileNotFoundError("control.properties not found in expected locations")
59
+
60
+ def get(self, section, option, fallback=None, cast_type=str):
61
+ try:
62
+ if cast_type == bool:
63
+ return self.config.getboolean(section, option)
64
+ elif cast_type == int:
65
+ return self.config.getint(section, option)
66
+ elif cast_type == float:
67
+ return self.config.getfloat(section, option)
68
+ else:
69
+ return self.config.get(section, option)
70
+ except (configparser.NoSectionError, configparser.NoOptionError):
71
+ return fallback
72
+
73
+ def get_dto(self) -> ConfigDTO:
74
+ input_path = self.get('DEFAULT', 'input_path', fallback='.')
75
+ work_space = self.get('DEFAULT', 'work_space', fallback='.')
76
+ threads = int(self.get('DEFAULT', 'threads', fallback=1))
77
+ project = self.get('DEFAULT', 'project', fallback='')
78
+ steps_str = self.get('DEFAULT', 'steps', fallback='')
79
+ steps = [s.strip() for s in steps_str.split(',')] if steps_str else []
80
+ skipsteps_str = self.get('DEFAULT', 'skipsteps', fallback='')
81
+ skipsteps = [s.strip() for s in skipsteps_str.split(',')] if skipsteps_str else []
82
+
83
+ return ConfigDTO(
84
+ work_space=work_space,
85
+ threads=threads,
86
+ project=project,
87
+ steps=steps,
88
+ skipsteps=skipsteps
89
+ )
File without changes
@@ -0,0 +1,6 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ class ControlInterface(ABC):
4
+ @abstractmethod
5
+ def run(self):
6
+ pass
@@ -0,0 +1,29 @@
1
+ from concurrent.futures import ThreadPoolExecutor
2
+
3
+ from generater.vertexai import VertexAISingleton
4
+ from src.pilot.control.control_interface import ControlInterface
5
+ from src.pilot.unit.impl.base_unit import BaseUnit
6
+ from src.pilot.config.config_reader import ConfigReader
7
+
8
+
9
+ class BaseController(ControlInterface):
10
+
11
+ def __init__(self):
12
+ vertexai: VertexAISingleton = VertexAISingleton.get_instance()
13
+
14
+ def _init_unit(self):
15
+ return BaseUnit()
16
+
17
+ def run(self):
18
+ import time
19
+ config_dto = ConfigReader().get_dto()
20
+ def worker():
21
+ unit = self._init_unit()
22
+ unit.run()
23
+ with ThreadPoolExecutor(max_workers=config_dto.threads) as executor:
24
+ futures = []
25
+ for _ in range(config_dto.threads):
26
+ futures.append(executor.submit(worker))
27
+ time.sleep(0.2)
28
+ for future in futures:
29
+ future.result()
File without changes
@@ -0,0 +1,77 @@
1
+ import subprocess
2
+ import sys
3
+ import os
4
+
5
+ def nkf_convert(file_path, nkf_args):
6
+ """
7
+ nkf を使ってファイルの文字コード変換を行う
8
+
9
+ :param file_path: 変換対象のファイルパス
10
+ :param nkf_args: nkf に渡す引数のリスト(例: ['-w'])
11
+ """
12
+ # nkfコマンドの引数にファイルパスを追加
13
+ #cmd = ['nkf'] + nkf_args + [file_path]
14
+
15
+ cmd = ['nkf32'] + nkf_args + file_path
16
+
17
+
18
+ try:
19
+ # nkfを実行し標準出力を取得
20
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
21
+ print(f"nkfの実行完了しました: {file_path}")
22
+ except subprocess.CalledProcessError as e:
23
+ print(f"nkfの実行でエラーが発生しました: {e.stderr.decode()}", file=sys.stderr)
24
+ return None
25
+
26
+ # nkfの変換結果(バイト列)を返す
27
+ return result.stdout
28
+
29
+
30
+ #if __name__ == "__main__":
31
+ # 処理対象のルートフォルダパスを指定(適宜変更してください)
32
+ # root_folder = r"d:\work2\src"
33
+ # nkf_convert(root_folder, ['-v'])
34
+
35
+
36
+
37
+ #if __name__ == "__main__":
38
+ # if len(sys.argv) < 3:
39
+ # print(f"使い方: python {sys.argv[0]} <ファイルパス> <nkf引数...>", file=sys.stderr)
40
+ # print(f"例: python {sys.argv[0]} test.txt -w --overwrite", file=sys.stderr)
41
+ # sys.exit(1)
42
+
43
+ # file_path = [r"D:\test\CHKCONST.cpy"]
44
+ # nkf_args = ['-w','--overwrite']
45
+ #nkf_args = ['-g']
46
+ # output = nkf_convert(file_path, nkf_args)
47
+
48
+
49
+ if __name__ == "__main__":
50
+
51
+
52
+ target_dir = r'D:\work\fullsource'
53
+ nkf_args = ['-w', '--overwrite']
54
+ #extensions = (
55
+ # '.cfc', '.cfm', '.cob', '.cobol', '.cpy', '.csh', '.css', '.ctl',
56
+ # '.htm', '.html', '.js', '.sh', '.sql', '.tpl', '.txt'
57
+ #)
58
+ extensions = ('.cnd','.cng','int')
59
+ for root, dirs, files in os.walk(target_dir):
60
+ for file in files:
61
+ if file.lower().endswith(extensions):
62
+ filepath = os.path.join(root, file)
63
+ output = nkf_convert([filepath], nkf_args)
64
+
65
+
66
+ #if output is not None:
67
+ # 結果を標準出力にバイナリのまま書き出す場合
68
+ # sys.stdout.buffer.write(output)
69
+
70
+ # あるいはUTF-8等に応じてデコードして表示する場合
71
+ # 一旦utf-8デコードを試みる例(必要に応じて変更してください)
72
+ # try:
73
+ # decoded_output = output.decode('utf-8')
74
+ # print(decoded_output)
75
+ # except UnicodeDecodeError:
76
+ # print("utf-8へのデコードに失敗しました。バイナリデータとして出力します。", file=sys.stderr)
77
+ # sys.stdout.buffer.write(output)
@@ -0,0 +1,28 @@
1
+ import subprocess
2
+ import sys
3
+
4
+ class NkfConverter:
5
+ def __init__(self, nkf_args=None):
6
+ """
7
+ コンストラクタ
8
+ :param nkf_args: nkf に渡す引数のリスト(例: ['-w', '--overwrite'])
9
+ 指定しない場合はデフォルト値を使用
10
+ """
11
+ if nkf_args is None:
12
+ nkf_args = ['-w', '--overwrite']
13
+ self.nkf_args = nkf_args
14
+
15
+ def convert(self, file_path):
16
+ """
17
+ nkf を使ってファイルの文字コード変換を行う
18
+ :param file_path: 変換対象のファイルパス
19
+ :return: nkfの変換結果のバイト列、失敗したらNone
20
+ """
21
+ cmd = ['nkf32'] + self.nkf_args + [file_path]
22
+ try:
23
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
24
+ print(f"nkfの実行完了しました: {file_path}")
25
+ except subprocess.CalledProcessError as e:
26
+ print(f"nkfの実行でエラーが発生しました: {e.stderr.decode()}", file=sys.stderr)
27
+ return None
28
+ return result.stdout
File without changes
@@ -0,0 +1,66 @@
1
+ import threading
2
+ from typing import Dict, Any, Optional
3
+
4
+ import tiktoken
5
+ from vertexai.preview.generative_models import GenerativeModel, ChatSession
6
+ from transformers import AutoTokenizer
7
+ import os
8
+
9
+ class VertexAISingleton:
10
+ _instance: Optional['VertexAISingleton'] = None
11
+ _lock = threading.Lock()
12
+ _tokenizer_cache = {}
13
+ encoding = None
14
+
15
+ def __new__(cls, model_name: str = "gemini-2.5-pro"):
16
+ if cls._instance is None:
17
+ with cls._lock:
18
+ if cls._instance is None:
19
+ cls._instance = super(VertexAISingleton, cls).__new__(cls)
20
+ cls._instance._initialized = False
21
+ return cls._instance
22
+
23
+ def __init__(self, model_name: str = "gemini-2.5-pro"):
24
+ if not self._initialized:
25
+ with self._lock:
26
+ if not self._initialized:
27
+ self.model = GenerativeModel(model_name)
28
+ os.environ["TIKTOKEN_CACHE_DIR"] = r"D:\api"
29
+ self.encoding = tiktoken.get_encoding("cl100k_base")
30
+ self._initialized = True
31
+
32
+ def generate_content(self, prompt: str) -> Dict[str, Any]:
33
+ """複数スレッドから安全に呼び出し可能"""
34
+ try:
35
+ response = self.model.generate_content(prompt)
36
+ return {
37
+ "prompt": prompt,
38
+ "response": response.text,
39
+ "success": True,
40
+ "error": None
41
+ }
42
+ except Exception as e:
43
+ return {
44
+ "prompt": prompt,
45
+ "response": None,
46
+ "success": False,
47
+ "error": str(e)
48
+ }
49
+
50
+ def start_chat(self) -> ChatSession:
51
+ """新しいチャットセッションを開始"""
52
+ return self.model.start_chat()
53
+
54
+ def count_tokens(self, text: str) -> int:
55
+ """与えられたテキストのトークン数を返す(bert-base-uncasedのみ使用)"""
56
+ try:
57
+ tokens = self.encoding.encode(text)
58
+ return len(tokens)
59
+ except Exception as e:
60
+ print(f"トークン計算失敗: {e}")
61
+ return 0
62
+
63
+ @classmethod
64
+ def get_instance(cls, model_name: str = "gemini-2.5-pro") -> 'VertexAISingleton':
65
+ """インスタンスを取得"""
66
+ return cls(model_name)
File without changes
File without changes
@@ -0,0 +1,288 @@
1
+ import os
2
+ import shutil
3
+
4
+ from pilot.job.job_interface import JobInterface
5
+ from pilot.config.config_reader import ConfigReader
6
+
7
+
8
+ class BaseJob(JobInterface):
9
+ def __init__(self):
10
+ self.config_dto = ConfigReader().get_dto()
11
+ self._current_step = None
12
+ self._file_path = None
13
+ self._step_index = None
14
+ self._next_step = None
15
+ self._next_step_file_path = None
16
+ self._content = None
17
+
18
+ @property
19
+ def current_step(self):
20
+ return self._current_step
21
+
22
+ @current_step.setter
23
+ def current_step(self, value):
24
+ self._current_step = value
25
+
26
+ @property
27
+ def file_path(self):
28
+ return self._file_path
29
+
30
+ @file_path.setter
31
+ def file_path(self, value):
32
+ self._file_path = value
33
+ self._content = None # ファイルパスが変わったらキャッシュクリア
34
+
35
+ @property
36
+ def step_index(self):
37
+ return self._step_index
38
+
39
+ @step_index.setter
40
+ def step_index(self, value):
41
+ self._step_index = value
42
+ self._next_step = None # step_indexが変わったらnext_stepをリセット
43
+
44
+ @property
45
+ def next_step(self):
46
+ if self._next_step is None and self._step_index is not None:
47
+ steps_list = self.config_dto.steps
48
+ if self._step_index + 1 < len(steps_list):
49
+ self._next_step = steps_list[self._step_index + 1]
50
+ else:
51
+ self._next_step = None
52
+ return self._next_step
53
+
54
+ @next_step.setter
55
+ def next_step(self, value):
56
+ self._next_step = value
57
+
58
+
59
+ @property
60
+ def current_trg_file_path(self):
61
+ return self._trg_file_path
62
+
63
+ @current_trg_file_path.setter
64
+ def current_trg_file_path(self, value):
65
+ self._trg_file_path = value
66
+
67
+
68
+
69
+
70
+ def run(self):
71
+ pass
72
+
73
+ def get_file_content(self):
74
+ if self._content is None and self._file_path:
75
+ with open(self._file_path, 'r', encoding='utf-8') as f:
76
+ self._content = f.read()
77
+ return self._content
78
+
79
+ def get_current_step_relative_path(self):
80
+ if not self._file_path:
81
+ return self._file_path
82
+
83
+ try:
84
+ base_dir = os.path.join(self.config_dto.work_space, self.current_step)
85
+ return os.path.relpath(self._file_path, base_dir)
86
+ except ValueError:
87
+ return self._file_path
88
+
89
+ def get_current_step_count(self):
90
+ if not self._file_path:
91
+ return self.config_dto.work_space
92
+ try:
93
+ relative_path = self.get_current_step_relative_path()
94
+ return os.path.relpath(self.config_dto.work_space, relative_path)
95
+ except ValueError:
96
+ return self.config_dto.work_space
97
+
98
+ def _copy_file_to_step_dir(self, src_path, base_dir, step_dir):
99
+ """指定したsrc_pathをbase_dirからの相対パスをごとstep_dir配下にコピーする。
100
+ すでにコピー先に同名ファイルがあればNoneを返し、存在しなければコピー先ファイルパスを返す。
101
+ """
102
+ if not src_path:
103
+ return None
104
+
105
+ rel_path = os.path.relpath(os.path.dirname(src_path), base_dir)
106
+ dest_dir = os.path.join(step_dir, rel_path)
107
+ base_file_name = os.path.basename(src_path)
108
+ dest_file_path = os.path.join(dest_dir, base_file_name)
109
+
110
+ if os.path.exists(dest_file_path):
111
+ self._next_step_file_path = dest_file_path
112
+ return None
113
+
114
+ os.makedirs(dest_dir, exist_ok=True)
115
+ shutil.copy(src_path, dest_file_path)
116
+ self._next_step_file_path = dest_file_path
117
+ return dest_file_path
118
+
119
+
120
+ def copy_current_file_to_next_step(self):
121
+ if not self._file_path or not self.next_step:
122
+ return None
123
+ base_dir = os.path.join(self.config_dto.work_space, self.current_step)
124
+ step_dir = os.path.join(self.config_dto.work_space, self.next_step)
125
+ return self._copy_file_to_step_dir(self._file_path, base_dir, step_dir)
126
+
127
+
128
+ # 共通化メソッド
129
+ def _create_next_step_trigger_file(self, ext):
130
+ if self._next_step_file_path:
131
+ trg_file = self._next_step_file_path + ".trg"
132
+ end_file = self._next_step_file_path + ".end"
133
+ begin_file = self._next_step_file_path + ".begin"
134
+ target_file = self._next_step_file_path + ext
135
+ if not (os.path.exists(trg_file) or os.path.exists(end_file) or os.path.exists(begin_file)):
136
+ open(target_file, 'w', encoding='utf-8').close()
137
+ return trg_file
138
+ return None
139
+
140
+ def create_next_step_todo_trg_file(self):
141
+ return self._create_next_step_trigger_file(".trg")
142
+
143
+ def create_next_step_end_trg_file(self):
144
+ return self._create_next_step_trigger_file(".end")
145
+
146
+ def create_next_step_begin_trg_file(self):
147
+ return self._create_next_step_trigger_file(".begin")
148
+
149
+
150
+ def change_current_trg_to_end(self):
151
+ if os.path.exists(self.current_trg_file_path):
152
+ file_path, file_extension = os.path.splitext(self.current_trg_file_path)
153
+ if file_extension == ".trg" or file_extension == ".begin":
154
+ try:
155
+ os.rename(self.current_trg_file_path, file_path + ".end")
156
+ return True
157
+ except Exception:
158
+ # 例外が発生した場合は False を返す
159
+ print("!!!!!!!!!!!!!!!!!!!!change_current_trg_to_end erro")
160
+ return False
161
+ # trgファイルが存在しなければ何もしないので、そのままreturn
162
+ return False
163
+
164
+ def change_current_trg_to_begin(self):
165
+ if os.path.exists(self.current_trg_file_path):
166
+ file_path, file_extension = os.path.splitext(self.current_trg_file_path)
167
+ if file_extension == ".trg":
168
+ try:
169
+ os.rename(self.current_trg_file_path, file_path + ".begin")
170
+ self.current_trg_file_path = os.path.join(file_path + ".begin")
171
+ return True
172
+ except Exception:
173
+ # 例外が発生した場合は False を返す
174
+ return False
175
+ return False
176
+
177
+ def copy_input_file_to_next_step(self, input_file_path):
178
+ """
179
+ input_file_pathで指定されたファイルを、next stepフォルダにコピーする。
180
+ コピー先に同名ファイルがあればNone、存在しなければコピー先ファイルパスを返す。
181
+ """
182
+ if not input_file_path or not self.next_step:
183
+ return None
184
+ base_dir = os.path.join(self.config_dto.work_space, self.current_step)
185
+ step_dir = os.path.join(self.config_dto.work_space, self.next_step)
186
+ return self._copy_file_to_step_dir(input_file_path, base_dir, step_dir)
187
+
188
+ def create_next_step_todo_trg_file_from_input(self, input_file_path):
189
+ """
190
+ input_file_pathで指定されたファイルをnext stepフォルダにコピーし、.trgファイルを生成する。
191
+ ファイルが既に存在する場合でも.trgファイルの作成を試行する。
192
+ """
193
+ if not input_file_path or not self.next_step:
194
+ return None
195
+
196
+ # ファイルをコピー(既存の場合はNoneが返される)
197
+ copied_file_path = self.copy_input_file_to_next_step(input_file_path)
198
+
199
+ # コピーが成功しなかった場合でも、対象ファイルパスを取得
200
+ if not copied_file_path:
201
+ base_dir = os.path.join(self.config_dto.work_space, self.current_step)
202
+ step_dir = os.path.join(self.config_dto.work_space, self.next_step)
203
+ rel_path = os.path.relpath(os.path.dirname(input_file_path), base_dir)
204
+ dest_dir = os.path.join(step_dir, rel_path)
205
+ base_file_name = os.path.basename(input_file_path)
206
+ copied_file_path = os.path.join(dest_dir, base_file_name)
207
+
208
+ # .trgファイルを作成
209
+ trg_file = copied_file_path + ".trg"
210
+ end_file = copied_file_path + ".end"
211
+ begin_file = copied_file_path + ".begin"
212
+
213
+ if not (os.path.exists(trg_file) or os.path.exists(end_file) or os.path.exists(begin_file)):
214
+ # 空ファイルとして.trgファイルを生成
215
+ open(trg_file, 'w', encoding='utf-8').close()
216
+ return trg_file
217
+
218
+ return None
219
+
220
+ def create_current_step_end_trg_file_from_input(self, input_file_path):
221
+ """
222
+ input_file_pathで指定されたファイルに対して.endファイルを生成する。
223
+ """
224
+ if not input_file_path:
225
+ return None
226
+
227
+ trg_file = input_file_path + ".trg"
228
+ end_file = input_file_path + ".end"
229
+ begin_file = input_file_path + ".begin"
230
+
231
+ # マーカーファイルが存在しない場合のみ.endファイルを作成
232
+ if not (os.path.exists(trg_file) or os.path.exists(end_file) or os.path.exists(begin_file)):
233
+ # 空ファイルとして.endファイルを生成
234
+ open(end_file, 'w', encoding='utf-8').close()
235
+ return end_file
236
+ return None
237
+
238
+
239
+ def create_trg_file_in_file_path_dir(self, file_name):
240
+ """
241
+ file_pathのディレクトリ配下に指定されたファイル名の.trgファイルを作成する。
242
+ 既に.trg, .end, .beginファイルが存在する場合は何もしない。
243
+ """
244
+ if not self._file_path or not file_name:
245
+ return None
246
+ dir_path = os.path.dirname(self._file_path)
247
+ base_path = os.path.join(dir_path, file_name)
248
+ trg_file = base_path + ".trg"
249
+ end_file = base_path + ".end"
250
+ begin_file = base_path + ".begin"
251
+ if not (os.path.exists(trg_file) or os.path.exists(end_file) or os.path.exists(begin_file)):
252
+ # 空ファイルとして.trgファイルを生成
253
+ open(trg_file, 'w', encoding='utf-8').close()
254
+ return trg_file
255
+ return None
256
+
257
+ def get_work_space(self):
258
+ """
259
+ config_dtoからwork_spaceを取得するメソッド
260
+ """
261
+ return self.config_dto.work_space
262
+
263
+ def copy_file_todo_trg_to_next_step(self, result_file):
264
+ self.create_current_step_end_trg_file_from_input(result_file)
265
+ next_step_file = self.copy_input_file_to_next_step(result_file)
266
+ self.create_next_step_todo_trg_file_from_input(next_step_file)
267
+
268
+ def change_trg_file_to_end_in_file(self, file_name):
269
+ """
270
+ file_pathのディレクトリ配下に指定されたファイル名の.trgまたは.beginファイルが存在すれば、.endにリネームする。
271
+ 成功時 True、失敗時 False を返す。
272
+ """
273
+ if not self._file_path or not file_name:
274
+ return False
275
+ dir_path = os.path.dirname(self._file_path)
276
+ base_path = os.path.join(dir_path, file_name)
277
+ trg_file = base_path + ".trg"
278
+ begin_file = base_path + ".begin"
279
+ end_file = base_path + ".end"
280
+ # .trgまたは.beginが存在すれば.endにリネーム
281
+ if os.path.exists(begin_file):
282
+ try:
283
+ os.rename(trg_file, end_file)
284
+ return True
285
+ except Exception:
286
+ print(f"change_trg_file_to_end_in_file error: {trg_file}")
287
+ return False
288
+ return False
@@ -0,0 +1,6 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ class JobInterface(ABC):
4
+ @abstractmethod
5
+ def run(self):
6
+ pass
File without changes
@@ -0,0 +1,128 @@
1
+ import re
2
+ import os
3
+ import logging
4
+
5
+ class CobolSplitter:
6
+ def __init__(self, input_file):
7
+ self.input_file = input_file
8
+ self.identification_div = []
9
+ self.environment_div = []
10
+ self.data_div = []
11
+ self.procedure_div = [] # list of tuples: (line_text, line_number)
12
+ self.paragraphs = {}
13
+ logging.basicConfig(
14
+ level=logging.DEBUG,
15
+ format="%(asctime)s [%(levelname)s] %(message)s"
16
+ )
17
+ logging.debug(f"Initialized CobolSplitter for file: {input_file}")
18
+ @staticmethod
19
+ def normalize_whitespace(s):
20
+ return re.sub(r'\s+', ' ', s).strip().upper()
21
+
22
+ @classmethod
23
+ def line_starts_with_division(cls, line, division_name):
24
+ line_norm = cls.normalize_whitespace(line)
25
+ division_norm = cls.normalize_whitespace(division_name)
26
+ return line_norm.startswith(division_norm)
27
+
28
+ def read_file(self):
29
+ logging.debug(f"Reading file: {self.input_file}")
30
+ with open(self.input_file, 'r', encoding='utf-8') as f:
31
+ lines = f.readlines()
32
+
33
+ div = None
34
+ for idx, line in enumerate(lines, 1): # 行番号は1始まり
35
+ if self.line_starts_with_division(line, "IDENTIFICATION DIVISION"):
36
+ div = "IDENTIFICATION"
37
+ logging.debug(f"Found IDENTIFICATION DIVISION at line {idx}")
38
+ elif self.line_starts_with_division(line, "ENVIRONMENT DIVISION"):
39
+ div = "ENVIRONMENT"
40
+ logging.debug(f"Found ENVIRONMENT DIVISION at line {idx}")
41
+ elif self.line_starts_with_division(line, "DATA DIVISION"):
42
+ div = "DATA"
43
+ logging.debug(f"Found DATA DIVISION at line {idx}")
44
+ elif self.line_starts_with_division(line, "PROCEDURE DIVISION"):
45
+ div = "PROCEDURE"
46
+ logging.debug(f"Found PROCEDURE DIVISION at line {idx}")
47
+ elif line.strip() == ".":
48
+ div = None
49
+ logging.debug(f"Division end at line {idx}")
50
+
51
+ if div == "IDENTIFICATION":
52
+ self.identification_div.append(line)
53
+ elif div == "ENVIRONMENT":
54
+ self.environment_div.append(line)
55
+ elif div == "DATA":
56
+ self.data_div.append(line)
57
+ elif div == "PROCEDURE":
58
+ self.procedure_div.append( (line, idx) ) # タプルで行テキストと行番号を保持
59
+ else:
60
+ self.identification_div.append(line)
61
+ logging.debug("Finished reading and splitting divisions.")
62
+
63
+ def split_paragraphs(self):
64
+ logging.debug("Splitting PROCEDURE DIVISION into paragraphs.")
65
+ procedure_lines = self.procedure_div[:]
66
+ if procedure_lines and self.line_starts_with_division(procedure_lines[0][0], "PROCEDURE DIVISION"):
67
+ procedure_lines.pop(0)
68
+
69
+ para_header_re = re.compile(r"^\s*([A-Z0-9\-]+)\.\s*$", re.I)
70
+
71
+ current_para = None
72
+ current_lines = []
73
+
74
+ for line, lineno in procedure_lines:
75
+ m = para_header_re.match(line)
76
+ if m:
77
+ if current_para:
78
+ self.paragraphs[current_para] = current_lines
79
+ logging.debug(f"Paragraph '{current_para}' ends at line {lineno}")
80
+ current_para = m.group(1)
81
+ current_lines = [(line, lineno)]
82
+ logging.debug(f"Paragraph '{current_para}' starts at line {lineno}")
83
+ else:
84
+ if current_para:
85
+ current_lines.append((line, lineno))
86
+ else:
87
+ current_para = "MAIN"
88
+ current_lines = [(line, lineno)]
89
+ if current_para:
90
+ self.paragraphs[current_para] = current_lines
91
+ logging.debug(f"Paragraph '{current_para}' ends at last line.")
92
+ logging.debug(f"Total paragraphs found: {len(self.paragraphs)}")
93
+
94
+ def write_files(self):
95
+ logging.debug("Writing split paragraphs to files.")
96
+ created_files = []
97
+
98
+ base_name = os.path.splitext(os.path.basename(self.input_file))[0]
99
+ input_dir = os.path.dirname(self.input_file)
100
+ outdir = os.path.join(input_dir, base_name)
101
+ os.makedirs(outdir, exist_ok=True)
102
+ logging.debug(f"Output directory created: {outdir}")
103
+
104
+ for para, lines_para in self.paragraphs.items():
105
+ # パラグラフの開始行番号を取得
106
+ start_line = lines_para[0][1] if lines_para else 0
107
+ outfname = os.path.join(outdir, f"{base_name}_{para}_{start_line}.cbl")
108
+
109
+ with open(outfname, "w", encoding="utf-8") as f:
110
+ # パラグラフの内容のみを出力(行番号コメントなし)
111
+ for line, lineno in lines_para:
112
+ f.write(line)
113
+ if not line.endswith("\n"):
114
+ f.write("\n")
115
+
116
+ created_files.append(outfname)
117
+ logging.info(f"Created: {outfname}")
118
+
119
+ logging.debug("All paragraph files written.")
120
+ return created_files
121
+
122
+ def run(self):
123
+ logging.info("CobolSplitter run started.")
124
+ self.read_file()
125
+ self.split_paragraphs()
126
+ created_files = self.write_files()
127
+ logging.info("CobolSplitter run finished.")
128
+ return created_files
File without changes
File without changes
@@ -0,0 +1,39 @@
1
+ import os
2
+
3
+ from src.pilot.unit.unit_interface import UnitInterface
4
+ from src.pilot.job.impl.base_job import BaseJob
5
+ from src.pilot.config.config_reader import ConfigReader
6
+
7
+ class BaseUnit(UnitInterface):
8
+ config_dto = None
9
+ joblist = []
10
+
11
+ def __init__(self):
12
+ self.config_dto = ConfigReader().get_dto()
13
+
14
+
15
+ def _init_job(self,step):
16
+ return BaseJob()
17
+
18
+ def run(self):
19
+ steps = self.config_dto.steps
20
+ skipsteps = self.config_dto.skipsteps
21
+ for index, step in enumerate(steps):
22
+ if step in skipsteps:
23
+ continue
24
+ self._run_jobs_in_step_dir(self.config_dto.work_space+ "/" +step,step,index)
25
+
26
+ def _run_jobs_in_step_dir(self, current_step_dir, step,index):
27
+ for dirpath, _, filenames in os.walk(current_step_dir):
28
+ for filename in filenames:
29
+ file_path = os.path.join(dirpath, filename)
30
+ job = self._init_job(step)
31
+ job.current_step = step
32
+ job.step_index = index
33
+ job.file_path = file_path
34
+ if self.job_need_run(job,filename,index):
35
+ job.run()
36
+
37
+
38
+ def job_need_run(self, job:BaseJob,filename: str,index):
39
+ return True
@@ -0,0 +1,10 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ class UnitInterface(ABC):
4
+ @abstractmethod
5
+ def run(self):
6
+ pass
7
+
8
+ def job_not_run(self):
9
+ pass
10
+
File without changes
@@ -0,0 +1,45 @@
1
+ import os
2
+ import csv
3
+
4
+ class FileUtil:
5
+ @staticmethod
6
+ def exists(path: str) -> bool:
7
+ return os.path.exists(path)
8
+
9
+ @staticmethod
10
+ def read(path: str, encoding: str = "utf-8") -> str:
11
+ with open(path, "r", encoding=encoding) as f:
12
+ return f.read()
13
+
14
+ @staticmethod
15
+ def write(path: str, data: str, encoding: str = "utf-8") -> None:
16
+ with open(path, "w", encoding=encoding) as f:
17
+ f.write(data)
18
+
19
+ @staticmethod
20
+ def export_files_to_csv(folder: str, csv_path: str) -> None:
21
+ import re
22
+ rows = []
23
+ max_depth = 0
24
+ file_infos = []
25
+ for root, _, files in os.walk(folder):
26
+ for file in files:
27
+ rel_path = os.path.relpath(os.path.join(root, file), folder)
28
+ parts = rel_path.split(os.sep)
29
+ file_infos.append((parts, rel_path, root))
30
+ if len(parts) > max_depth:
31
+ max_depth = len(parts)
32
+ headers = ["No", "file", "ext", "folder_rel_path", "prefix_before_number"] + [f"fold{i + 1}" for i in range(max_depth - 1)]
33
+ for idx, (parts, rel_path, folder_full_path) in enumerate(file_infos, 1):
34
+ file_name = parts[-1]
35
+ ext = os.path.splitext(file_name)[1][1:]
36
+ folders = parts[:-1]
37
+ folder_rel_path = os.path.relpath(folder_full_path, folder)
38
+ match = re.match(r"([^\d]*)(\d.*)?", file_name)
39
+ prefix_before_number = match.group(1) if match and match.group(2) else ""
40
+ row = [idx, file_name, ext, folder_rel_path, prefix_before_number] + folders + [""] * (max_depth - 1 - len(folders))
41
+ rows.append(row)
42
+ with open(csv_path, "w", newline="", encoding="utf-8") as f:
43
+ writer = csv.writer(f)
44
+ writer.writerow(headers)
45
+ writer.writerows(rows)
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: pilot.linkstec
3
+ Version: 0.0.1
4
+ Summary: pilot of the ship, a tool for managing and deploying Python projects.
5
+ Author-email: wanglr <wanglr1980@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/nighter1980/pilot
8
+ Project-URL: Issues, https://github.com/nighter1980/pilot/issues
9
+ Keywords: python,project management,deployment
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Dynamic: license-file
16
+
17
+ # pilot
18
+
19
+ This is a simple example package. You can use
20
+ to write your content.
@@ -0,0 +1,31 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/pilot/__init__.py
5
+ src/pilot.linkstec.egg-info/PKG-INFO
6
+ src/pilot.linkstec.egg-info/SOURCES.txt
7
+ src/pilot.linkstec.egg-info/dependency_links.txt
8
+ src/pilot.linkstec.egg-info/top_level.txt
9
+ src/pilot/config/__init__.py
10
+ src/pilot/config/config_reader.py
11
+ src/pilot/control/__init__.py
12
+ src/pilot/control/control_interface.py
13
+ src/pilot/control/impl/__init__.py
14
+ src/pilot/control/impl/base_controller.py
15
+ src/pilot/conver/__init__.py
16
+ src/pilot/conver/converfileEncodding.py
17
+ src/pilot/conver/nkf_converter.py
18
+ src/pilot/generater/__init__.py
19
+ src/pilot/generater/vertexai.py
20
+ src/pilot/job/__init__.py
21
+ src/pilot/job/job_interface.py
22
+ src/pilot/job/impl/__init__.py
23
+ src/pilot/job/impl/base_job.py
24
+ src/pilot/splitters/__init__.py
25
+ src/pilot/splitters/cobolsplitter.py
26
+ src/pilot/unit/__init__.py
27
+ src/pilot/unit/unit_interface.py
28
+ src/pilot/unit/impl/__init__.py
29
+ src/pilot/unit/impl/base_unit.py
30
+ src/pilot/util/__init__.py
31
+ src/pilot/util/files.py