cannect 1.0.0__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.
- cannect/__init__.py +30 -0
- cannect/api/__init__.py +0 -0
- cannect/config.py +114 -0
- cannect/core/__init__.py +0 -0
- cannect/core/ascet/__init__.py +3 -0
- cannect/core/ascet/amd.py +698 -0
- cannect/core/ascet/formula.py +33 -0
- cannect/core/ascet/oid.py +29 -0
- cannect/core/ascet/ws.py +154 -0
- cannect/core/can/__init__.py +2 -0
- cannect/core/can/ascet/__init__.py +3 -0
- cannect/core/can/ascet/_db2code.py +344 -0
- cannect/core/can/ascet/_db2elem.py +399 -0
- cannect/core/can/ascet/comdef.py +256 -0
- cannect/core/can/ascet/comrx.py +139 -0
- cannect/core/can/ascet/diag.py +691 -0
- cannect/core/can/db/__init__.py +4 -0
- cannect/core/can/db/reader.py +148 -0
- cannect/core/can/db/schema.py +269 -0
- cannect/core/can/db/specification/__init__.py +0 -0
- cannect/core/can/db/specification/message.py +230 -0
- cannect/core/can/db/specification/styles.py +81 -0
- cannect/core/can/db/specification/wrapper.py +161 -0
- cannect/core/can/db/vcs.py +104 -0
- cannect/core/can/rule.py +229 -0
- cannect/core/can/testcase/__init__.py +0 -0
- cannect/core/can/testcase/unitcase/__init__.py +0 -0
- cannect/core/can/testcase/unitcase/asw2can.py +48 -0
- cannect/core/can/testcase/unitcase/decode.py +63 -0
- cannect/core/can/testcase/unitcase/diagnosis.py +479 -0
- cannect/core/can/testcase/unitcase/encode.py +60 -0
- cannect/core/ir/__init__.py +2 -0
- cannect/core/ir/changehistory.py +310 -0
- cannect/core/ir/delivereables.py +71 -0
- cannect/core/ir/diff.py +97 -0
- cannect/core/ir/ir.py +581 -0
- cannect/core/ir/sdd.py +148 -0
- cannect/core/mdf.py +66 -0
- cannect/core/subversion.py +136 -0
- cannect/core/testcase/__init__.py +3 -0
- cannect/core/testcase/plotter.py +181 -0
- cannect/core/testcase/style.py +981 -0
- cannect/core/testcase/testcase.py +160 -0
- cannect/core/testcase/unitcase.py +227 -0
- cannect/errors.py +20 -0
- cannect/schema/__init__.py +5 -0
- cannect/schema/candb.py +226 -0
- cannect/schema/datadictionary.py +60 -0
- cannect/utils/__init__.py +3 -0
- cannect/utils/excel.py +29 -0
- cannect/utils/logger.py +81 -0
- cannect/utils/ppt.py +236 -0
- cannect/utils/tools.py +207 -0
- cannect-1.0.0.dist-info/METADATA +214 -0
- cannect-1.0.0.dist-info/RECORD +58 -0
- cannect-1.0.0.dist-info/WHEEL +5 -0
- cannect-1.0.0.dist-info/licenses/LICENSE +21 -0
- cannect-1.0.0.dist-info/top_level.txt +1 -0
cannect/core/ir/ir.py
ADDED
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
from cannect.config import env
|
|
2
|
+
from cannect.core.ascet import Amd, WorkspaceIO
|
|
3
|
+
from cannect.core.ir.delivereables import Deliverables
|
|
4
|
+
from cannect.core.ir.sdd import SddRW
|
|
5
|
+
from cannect.core.ir.diff import AmdDiff
|
|
6
|
+
from cannect.core.subversion import Subversion
|
|
7
|
+
from cannect.errors import SVNError
|
|
8
|
+
from cannect.utils import tools
|
|
9
|
+
from cannect.utils.logger import Logger
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from pandas import DataFrame, Series
|
|
13
|
+
from typing import List, Iterator
|
|
14
|
+
import pandas as pd
|
|
15
|
+
import warnings, os, time, stat
|
|
16
|
+
|
|
17
|
+
warnings.filterwarnings("ignore")
|
|
18
|
+
SCHEMA: List[str] = [
|
|
19
|
+
"FunctionName", "FunctionVersion", "SCMName", "SCMRev",
|
|
20
|
+
"DSMName", "DSMRev",
|
|
21
|
+
"BSWName", "BSWRev",
|
|
22
|
+
"SDDName", "SDDRev",
|
|
23
|
+
"ChangeHistoryName", "ChangeHistoryRev",
|
|
24
|
+
"ElementDeleted", "ElementAdded",
|
|
25
|
+
"User", "Date", "Comment",
|
|
26
|
+
"Empty",
|
|
27
|
+
"PolyspaceName", "PolyspaceRev"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class IntegrationRequest:
|
|
32
|
+
logger: Logger = Logger()
|
|
33
|
+
_space: int = 0
|
|
34
|
+
|
|
35
|
+
def __new__(cls, *models):
|
|
36
|
+
for model in models:
|
|
37
|
+
if os.path.isfile(model):
|
|
38
|
+
cls._space = max(cls._space, len(os.path.basename(model).replace(".main.amd", "").replace(".zip", "")))
|
|
39
|
+
else:
|
|
40
|
+
cls._space = max(cls._space, len(model))
|
|
41
|
+
# SVN 최신화
|
|
42
|
+
Subversion.logger = cls.logger
|
|
43
|
+
Subversion.update(env.SVN_MODEL)
|
|
44
|
+
Subversion.update(env.SVN_SDD)
|
|
45
|
+
Subversion.update(env.SVN_CONF)
|
|
46
|
+
Subversion.update(env.SVN_UNECE)
|
|
47
|
+
return super().__new__(cls)
|
|
48
|
+
|
|
49
|
+
def __init__(self, *models):
|
|
50
|
+
|
|
51
|
+
# Attributes
|
|
52
|
+
self._change_history = ''
|
|
53
|
+
self._comment = ''
|
|
54
|
+
self._date = datetime.today().strftime('%Y-%m-%d')
|
|
55
|
+
self._user = ''
|
|
56
|
+
self._parameters = []
|
|
57
|
+
self._deliverables = None
|
|
58
|
+
|
|
59
|
+
# 기본 테이블 생성
|
|
60
|
+
self.ws = ws = WorkspaceIO()
|
|
61
|
+
# self._models = models = model_path(*models, logger=self.logger)
|
|
62
|
+
self.table = DataFrame(columns=SCHEMA)
|
|
63
|
+
|
|
64
|
+
self.logger(f'[INITIALIZE]')
|
|
65
|
+
for n, name in enumerate(models):
|
|
66
|
+
self.resolve_model(ws[name])
|
|
67
|
+
self.table["Date"] = self._date
|
|
68
|
+
self.p_table = self.table.copy()
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
def __iter__(self) -> Iterator[Series]:
|
|
72
|
+
for n in self.table.index:
|
|
73
|
+
yield self.table.loc[n]
|
|
74
|
+
|
|
75
|
+
def __str__(self) -> str:
|
|
76
|
+
return str(self.table[SCHEMA])
|
|
77
|
+
|
|
78
|
+
def __repr__(self):
|
|
79
|
+
return repr(self.table[SCHEMA])
|
|
80
|
+
|
|
81
|
+
def _repr_html_(self):
|
|
82
|
+
return getattr(self.table, '_repr_html_')()
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def deliverables(self) -> Deliverables:
|
|
86
|
+
"""
|
|
87
|
+
산출물 경로
|
|
88
|
+
"""
|
|
89
|
+
return self._deliverables
|
|
90
|
+
|
|
91
|
+
@deliverables.setter
|
|
92
|
+
def deliverables(self, path: str):
|
|
93
|
+
"""
|
|
94
|
+
산출물 경로 설정
|
|
95
|
+
"""
|
|
96
|
+
self._deliverables = Deliverables(path)
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def parameters(self) -> List[DataFrame]:
|
|
100
|
+
return self._parameters
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def Comment(self) -> str:
|
|
104
|
+
return self._comment
|
|
105
|
+
|
|
106
|
+
@Comment.setter
|
|
107
|
+
def Comment(self, comment: str):
|
|
108
|
+
self.table["Comment"] = comment
|
|
109
|
+
self._comment = comment
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def User(self) -> str:
|
|
113
|
+
return self._user
|
|
114
|
+
|
|
115
|
+
@User.setter
|
|
116
|
+
def User(self, user: str):
|
|
117
|
+
self.table["User"] = user
|
|
118
|
+
self._user = user
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def ChangeHistory(self) -> str:
|
|
122
|
+
return self._change_history
|
|
123
|
+
|
|
124
|
+
@ChangeHistory.setter
|
|
125
|
+
def ChangeHistory(self, change: str):
|
|
126
|
+
self.table["ChangeHistoryName"] = change
|
|
127
|
+
self._change_history = change
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def _column_selector(key: str) -> str:
|
|
131
|
+
"""
|
|
132
|
+
keyword @key 입력 시 자동 column 이름(*Name) 식별 기능
|
|
133
|
+
|
|
134
|
+
@key: [str] 선택하고자 하는 column의 키워드
|
|
135
|
+
"""
|
|
136
|
+
if key == '':
|
|
137
|
+
return key
|
|
138
|
+
if "func" in key.lower():
|
|
139
|
+
key = "SCMName"
|
|
140
|
+
for schema in SCHEMA:
|
|
141
|
+
if key.lower() in schema.lower():
|
|
142
|
+
if schema.endswith("Rev") and schema.replace("Rev", "Name") in SCHEMA:
|
|
143
|
+
return schema.replace("Rev", "Name")
|
|
144
|
+
return schema
|
|
145
|
+
raise KeyError
|
|
146
|
+
|
|
147
|
+
def commit_all(self, message:str):
|
|
148
|
+
if not message:
|
|
149
|
+
raise SVNError('COMMIT MESSAGE NOT SPECIFIED')
|
|
150
|
+
for row in self:
|
|
151
|
+
name = row['FunctionName']
|
|
152
|
+
self.logger.hold(f">>> %{name: <{self._space}}: ")
|
|
153
|
+
Subversion.commit(self.ws[f'{name}.zip'], message)
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
def compare_model(self, prev: str = '', post: str = '', exclude_imported: bool = True):
|
|
157
|
+
self.logger("[COMPARE ELEMENTS]")
|
|
158
|
+
if not prev:
|
|
159
|
+
prev = self.deliverables.Model / "Prev"
|
|
160
|
+
if not post:
|
|
161
|
+
post = self.deliverables.Model / "Post"
|
|
162
|
+
for n, row in enumerate(self):
|
|
163
|
+
name = row['FunctionName']
|
|
164
|
+
prev_amd = tools.find_file(prev, f'{name}.main.amd')
|
|
165
|
+
post_amd = tools.find_file(post, f'{name}.main.amd')
|
|
166
|
+
if not os.path.exists(post_amd):
|
|
167
|
+
continue
|
|
168
|
+
if not os.path.exists(prev_amd):
|
|
169
|
+
amd = Amd(post_amd).main.dataframe('Element')
|
|
170
|
+
dat = Amd(post_amd).data.dataframe('DataEntry')
|
|
171
|
+
self.table.loc[n, 'ElementAdded'] = ", ".join(amd["name"])
|
|
172
|
+
self.logger(
|
|
173
|
+
f">>> %{name: <{self._space}}: NEW ELEMENT / ADDED ={len(amd): >3}")
|
|
174
|
+
params = AmdDiff.parameters2table(amd, dat)
|
|
175
|
+
if not params.empty:
|
|
176
|
+
self._parameters.append(params)
|
|
177
|
+
continue
|
|
178
|
+
diff = AmdDiff(prev_amd, post_amd, exclude_imported=exclude_imported)
|
|
179
|
+
self.table.loc[n, 'ElementDeleted'] = ', '.join(diff.deleted)
|
|
180
|
+
self.table.loc[n, 'ElementAdded'] = ", ".join(diff.added)
|
|
181
|
+
params = diff.added_parameters
|
|
182
|
+
if not params.empty:
|
|
183
|
+
self._parameters.append(params)
|
|
184
|
+
|
|
185
|
+
self.logger(f">>> %{name: <{self._space}}: DELETED ={len(diff.deleted): >3} / ADDED ={len(diff.added): >3}")
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
def copy_model_to_svn(
|
|
189
|
+
self,
|
|
190
|
+
src_path:str='',
|
|
191
|
+
):
|
|
192
|
+
"""
|
|
193
|
+
SVN 경로 상 모델(.zip)을 동일 경로에 압축 해제 후 압축 파일 삭제
|
|
194
|
+
@local_path에 개발된 모델(*.amd) 파일을 SVN 경로로 복사(덮어쓰기) 후 압축
|
|
195
|
+
|
|
196
|
+
ASCET-SCM 미사용, 직접 commit 시 *.amd 파일 덮어쓰기 목적
|
|
197
|
+
|
|
198
|
+
@param local_path: svn으로 복사(commit)할 모델이 있는 경로
|
|
199
|
+
"""
|
|
200
|
+
if not src_path:
|
|
201
|
+
src_path = self.deliverables.Model / "Post"
|
|
202
|
+
|
|
203
|
+
self.logger(f'[COPY MODELS FROM "{tools.path_abbreviate(src_path)}" TO SVN]')
|
|
204
|
+
for row in self:
|
|
205
|
+
name = row['FunctionName']
|
|
206
|
+
self.logger.hold(f">>> %{name: <{self._space}}: UNZIP -> ")
|
|
207
|
+
|
|
208
|
+
model = self.ws[f'{name}.zip']
|
|
209
|
+
mpath = os.path.dirname(model)
|
|
210
|
+
tools.unzip(model, mpath)
|
|
211
|
+
try:
|
|
212
|
+
os.chmod(model, stat.S_IWRITE)
|
|
213
|
+
os.remove(model)
|
|
214
|
+
self.logger.hold("SUCCESS | ")
|
|
215
|
+
except Exception as e:
|
|
216
|
+
self.logger.log("FAILED")
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
self.logger.hold("OVERWRITE -> ")
|
|
220
|
+
try:
|
|
221
|
+
local_md = tools.find_file(str(src_path), f'{name}.main.amd')
|
|
222
|
+
tools.copy_to(local_md, mpath)
|
|
223
|
+
tools.copy_to(local_md.replace(".main", ".implementation"), mpath)
|
|
224
|
+
tools.copy_to(local_md.replace(".main", ".data"), mpath)
|
|
225
|
+
tools.copy_to(local_md.replace(".main", ".specification"), mpath)
|
|
226
|
+
self.logger.hold("SUCCESS | ")
|
|
227
|
+
except Exception as e:
|
|
228
|
+
self.logger.log("FAILED")
|
|
229
|
+
continue
|
|
230
|
+
|
|
231
|
+
self.logger.hold("ZIP -> ")
|
|
232
|
+
try:
|
|
233
|
+
tools.zip(mpath)
|
|
234
|
+
self.logger.hold("SUCCESS")
|
|
235
|
+
except Exception as e:
|
|
236
|
+
self.logger.log("FAILED")
|
|
237
|
+
continue
|
|
238
|
+
|
|
239
|
+
try:
|
|
240
|
+
for f in os.listdir(mpath):
|
|
241
|
+
if f.endswith('.amd'):
|
|
242
|
+
os.remove(os.path.join(mpath, f))
|
|
243
|
+
time.sleep(1)
|
|
244
|
+
self.logger.log("")
|
|
245
|
+
except Exception as e:
|
|
246
|
+
self.logger.log(" | FAILED WHILE CLEAN-UP")
|
|
247
|
+
continue
|
|
248
|
+
return
|
|
249
|
+
|
|
250
|
+
def copy_resource(self, key: str, dst: str, versioning: bool = True, unzip: bool = True):
|
|
251
|
+
col = self._column_selector(key)
|
|
252
|
+
|
|
253
|
+
self.logger(f'[COPY "{col[:-4]}" RESOURCE FROM SVN -> {self._path_abbr(dst)}]')
|
|
254
|
+
if col.startswith("SCM"):
|
|
255
|
+
path = env["MODEL"]
|
|
256
|
+
elif col.startswith("DSM"):
|
|
257
|
+
path = env["CONF"]
|
|
258
|
+
elif col.startswith("SDD"):
|
|
259
|
+
path = env["SDD"]
|
|
260
|
+
elif col.startswith("Poly"):
|
|
261
|
+
path = env["POLYSPACE"]
|
|
262
|
+
else:
|
|
263
|
+
raise KeyError()
|
|
264
|
+
|
|
265
|
+
for row in self:
|
|
266
|
+
self.logger.hold(f'>>> {row["FunctionName"]: <{self._space}} ')
|
|
267
|
+
file = path[f'{row[col]}.zip' if col.startswith("SCM") else row[col]]
|
|
268
|
+
if not os.path.exists(file):
|
|
269
|
+
self.logger.log(f'| NOT FOUND IN SVN')
|
|
270
|
+
continue
|
|
271
|
+
|
|
272
|
+
try:
|
|
273
|
+
tools.copy_to(file, dst)
|
|
274
|
+
self.logger.hold(f'| "{os.path.basename(file)}" COPIED')
|
|
275
|
+
except (Exception, FileNotFoundError, OSError):
|
|
276
|
+
self.logger.hold(f'| "{os.path.basename(file)}" FAILED TO COPY')
|
|
277
|
+
|
|
278
|
+
copied = os.path.join(dst, os.path.basename(file))
|
|
279
|
+
os.chmod(copied, stat.S_IWRITE)
|
|
280
|
+
if unzip:
|
|
281
|
+
tools.unzip(file, dst)
|
|
282
|
+
if versioning:
|
|
283
|
+
try:
|
|
284
|
+
ver = row[col.replace("Name", "Rev")]
|
|
285
|
+
os.rename(copied, copied.replace(".zip", f"-{ver}.zip").replace(".7z", f"-{ver}.7z"))
|
|
286
|
+
except (Exception, FileExistsError, FileNotFoundError):
|
|
287
|
+
pass
|
|
288
|
+
self.logger.log()
|
|
289
|
+
return
|
|
290
|
+
|
|
291
|
+
def exclude(self, *funcs):
|
|
292
|
+
self.table = self.table[~self.table["FunctionName"].isin(funcs)]
|
|
293
|
+
self.p_table = self.p_table[~self.p_table["FunctionName"].isin(funcs)]
|
|
294
|
+
self.table.reset_index(inplace=True)
|
|
295
|
+
self.p_table.reset_index(inplace=True)
|
|
296
|
+
return
|
|
297
|
+
|
|
298
|
+
def resolve_model(self, model: str):
|
|
299
|
+
"""
|
|
300
|
+
모델 정보를 @self.table에 추가 (SVN Revision 제외)
|
|
301
|
+
추가 항목: FunctionName, SCMName, DSMName, SDDName, PolyspaceName
|
|
302
|
+
|
|
303
|
+
@model : [str] ASCET 모델 경로(*.main.amd 또는 *.amd 파일이 포함된 *.zip)
|
|
304
|
+
"""
|
|
305
|
+
if not os.path.isfile(model):
|
|
306
|
+
model = self.ws[model]
|
|
307
|
+
amd = Amd(model)
|
|
308
|
+
# self.logger.hold(f'>>> %{amd.name: <{self._space}} ')
|
|
309
|
+
|
|
310
|
+
data = dict(zip(SCHEMA, [''] * len(SCHEMA)))
|
|
311
|
+
data["FunctionName"] = name = amd.name
|
|
312
|
+
data["SCMName"] = "\\".join(amd.main["nameSpace"][1:].split("/") + [name])
|
|
313
|
+
|
|
314
|
+
elements = amd.main.dataframe('Element')
|
|
315
|
+
if not elements[
|
|
316
|
+
elements['name'].str.contains('DEve') |
|
|
317
|
+
elements['name'].str.contains('Fid')
|
|
318
|
+
].empty:
|
|
319
|
+
data["DSMName"] = conf = f'{name.lower()}_confdata.xml'
|
|
320
|
+
# self.logger.hold(f'| {conf: <{self._space + 13}} ')
|
|
321
|
+
else:
|
|
322
|
+
# self.logger.hold(f'| {"DSM NO USE": <{self._space + 13}} ')
|
|
323
|
+
pass
|
|
324
|
+
|
|
325
|
+
data["SDDName"] = sdd = f'{amd.main["OID"][1:]}.zip'
|
|
326
|
+
# self.logger.hold(f'| {sdd} ')
|
|
327
|
+
|
|
328
|
+
data["PolyspaceName"] = poly = f"BF_Result_{name}.7z"
|
|
329
|
+
# self.logger.hold(f'| {poly}')
|
|
330
|
+
|
|
331
|
+
if self._user:
|
|
332
|
+
data["User"] = self._user
|
|
333
|
+
if self._date:
|
|
334
|
+
data["Date"] = self._date
|
|
335
|
+
if self._comment:
|
|
336
|
+
data["Comment"] = self._comment
|
|
337
|
+
|
|
338
|
+
self.table = pd.concat([self.table, DataFrame(data=data, index=[0])], ignore_index=True)
|
|
339
|
+
self.p_table = self.table.copy()
|
|
340
|
+
# self.logger.log()
|
|
341
|
+
return
|
|
342
|
+
|
|
343
|
+
def resolve_svn_version(self, col: str = ''):
|
|
344
|
+
def _get_log(_file: str) -> str:
|
|
345
|
+
try:
|
|
346
|
+
_ver = Subversion.log(str(_file)).iloc[0, 0][1:]
|
|
347
|
+
self.logger.hold(f"-> {_ver} ")
|
|
348
|
+
return _ver
|
|
349
|
+
except (OSError, Exception):
|
|
350
|
+
self.logger.hold(f"-> ERROR ")
|
|
351
|
+
return ''
|
|
352
|
+
|
|
353
|
+
col = self._column_selector(col)
|
|
354
|
+
self.logger(f'[RESOLVE SVN VERSION]{f": {col}" if col else ""}')
|
|
355
|
+
for n, row in enumerate(self):
|
|
356
|
+
self.logger.hold(f">>> %{row['FunctionName']: <{self._space}} ")
|
|
357
|
+
if col == '' or col == 'SCMName':
|
|
358
|
+
self.table.loc[n, 'SCMRev'] = _get_log(env.SVN_MODEL / f'{row["SCMName"]}.zip')
|
|
359
|
+
if col == '' or col == 'DSMName':
|
|
360
|
+
if pd.isna(row["DSMName"]) or (row["DSMName"] == ''):
|
|
361
|
+
self.logger.hold(f'|{" " * (self._space + 13 + 11)}')
|
|
362
|
+
else:
|
|
363
|
+
self.logger.hold(f'| {row["DSMName"]: <{self._space + 13}} ')
|
|
364
|
+
self.table.loc[n, 'DSMRev'] = _get_log(env.SVN_CONF / f'{row["DSMName"]}')
|
|
365
|
+
if col == '' or col == 'SDDName':
|
|
366
|
+
self.logger.hold(f'| {row["SDDName"]} ')
|
|
367
|
+
self.table.loc[n, 'SDDRev'] = _get_log(env.SVN_SDD / f'{row["SDDName"]}')
|
|
368
|
+
if col == '' or col == 'PolyspaceName':
|
|
369
|
+
self.logger.hold(f'| {row["PolyspaceName"]: <{self._space + 13}} ')
|
|
370
|
+
self.table.loc[n, 'PolyspaceRev'] = _get_log(env.SVN_UNECE / f'{row["PolyspaceName"]}')
|
|
371
|
+
self.logger.log()
|
|
372
|
+
return
|
|
373
|
+
|
|
374
|
+
def resolve_sdd_version(self):
|
|
375
|
+
temp = os.path.join(env.TEMP, '~cannect')
|
|
376
|
+
os.makedirs(temp, exist_ok=True)
|
|
377
|
+
|
|
378
|
+
self.logger(f'[RESOLVE SDD VERSION]')
|
|
379
|
+
for n, row in enumerate(self):
|
|
380
|
+
self.logger.hold(f'>>> {row["FunctionName"]: <{self._space}} @{row["SDDName"]} ')
|
|
381
|
+
file = env.SVN_SDD / row["SDDName"]
|
|
382
|
+
if not os.path.exists(file):
|
|
383
|
+
self.logger.log('-> NOT FOUND IN SVN')
|
|
384
|
+
continue
|
|
385
|
+
tools.unzip(file, temp)
|
|
386
|
+
|
|
387
|
+
sdd = SddRW(os.path.join(temp, row["SDDName"].replace(".zip", "")))
|
|
388
|
+
ver = sdd.version_doc
|
|
389
|
+
self.table.loc[n, 'FunctionVersion'] = ver
|
|
390
|
+
self.logger.hold(f"-> {ver}")
|
|
391
|
+
if sdd.version_doc != sdd.version_log:
|
|
392
|
+
self.logger.hold(f'(version mismatch on sdd)')
|
|
393
|
+
self.logger.log()
|
|
394
|
+
|
|
395
|
+
if temp.endswith('~cannect'):
|
|
396
|
+
tools.clear(temp, leave_path=True)
|
|
397
|
+
return
|
|
398
|
+
|
|
399
|
+
def select_previous_svn_version(self, mode: str = 'auto'):
|
|
400
|
+
"""
|
|
401
|
+
@mode: [str] {'auto', 'latest', 'select'}
|
|
402
|
+
"""
|
|
403
|
+
# 산출물 경로가 존재하는 경우 모델 과거 버전 조회 이력 확인 후 재 사용
|
|
404
|
+
if self.deliverables is not None and os.listdir(self.deliverables.Model / "Prev"):
|
|
405
|
+
prev = self.deliverables.Model / "Prev"
|
|
406
|
+
models = self.p_table["FunctionName"].tolist()
|
|
407
|
+
for model in os.listdir(prev):
|
|
408
|
+
if not model.endswith('.zip'):
|
|
409
|
+
continue
|
|
410
|
+
name, rev = model.split('-')
|
|
411
|
+
rev = rev.replace('.zip', '')
|
|
412
|
+
if name in models:
|
|
413
|
+
self.p_table.loc[models.index(name), "SCMRev"] = rev
|
|
414
|
+
for n, row in enumerate(self):
|
|
415
|
+
if self.p_table.loc[n, "SCMRev"] == '' or pd.isna(self.p_table.loc[n, "SCMRev"]):
|
|
416
|
+
self.p_table.loc[n, "SCMRev"] = '-'
|
|
417
|
+
return
|
|
418
|
+
|
|
419
|
+
if not mode.lower() in ['auto', 'latest']:
|
|
420
|
+
self.logger(f'[SELECT PREVIOUS MODEL VERSION]')
|
|
421
|
+
for n, row in enumerate(self):
|
|
422
|
+
file = self.ws[row["FunctionName"]]
|
|
423
|
+
history = Subversion.log(file)
|
|
424
|
+
if mode.lower() in ['auto', 'latest']:
|
|
425
|
+
try:
|
|
426
|
+
i = 1 if mode.lower() == 'auto' else 0
|
|
427
|
+
self.p_table.loc[n, "SCMRev"] = rev = history["revision"].values[i][1:]
|
|
428
|
+
if self.deliverables is not None:
|
|
429
|
+
Subversion.save_revision_to(file, rev, self.deliverables.Model / "Prev")
|
|
430
|
+
except IndexError:
|
|
431
|
+
self.p_table.loc[n, "SCMRev"] = '-'
|
|
432
|
+
continue
|
|
433
|
+
|
|
434
|
+
self.logger.hold(f'>>> SELECT VERSION FOR %{row["FunctionName"]}\n')
|
|
435
|
+
self.logger.log(str(history))
|
|
436
|
+
time.sleep(0.5)
|
|
437
|
+
selected = str(input(">>> (select revision): "))
|
|
438
|
+
if not selected or (selected == '-'):
|
|
439
|
+
self.p_table.loc[n, "SCMRev"] = '-'
|
|
440
|
+
continue
|
|
441
|
+
if not selected.startswith('r'):
|
|
442
|
+
selected = f'r{selected}'
|
|
443
|
+
if not selected in history["revision"].values:
|
|
444
|
+
raise KeyError(f'{selected} NOT FOUND')
|
|
445
|
+
self.p_table.loc[n, "SCMRev"] = rev = selected[1:]
|
|
446
|
+
if self.deliverables is not None:
|
|
447
|
+
Subversion.save_revision(file, rev, self.deliverables.Model / "Prev")
|
|
448
|
+
for file in os.listdir(self.deliverables.Model / "Prev"):
|
|
449
|
+
path = os.path.join(self.deliverables.Model / "Prev", file)
|
|
450
|
+
tools.unzip(path, self.deliverables.Model / "Prev")
|
|
451
|
+
return
|
|
452
|
+
|
|
453
|
+
def update_sdd(self, comment: str = ''):
|
|
454
|
+
"""
|
|
455
|
+
@self.table의 "SDDName" 항목을 @path에서 찾아 자동 업데이트,
|
|
456
|
+
파일이 없는 경우 신규로 간주, 00.00.001 버전으로 신규 생성
|
|
457
|
+
|
|
458
|
+
@param comment: [str] SDD 노트 기입 내용
|
|
459
|
+
"""
|
|
460
|
+
if self.deliverables is None:
|
|
461
|
+
path = env.DOWNLOADS
|
|
462
|
+
else:
|
|
463
|
+
path = self.deliverables.Resources / "SDD"
|
|
464
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
465
|
+
|
|
466
|
+
if not comment:
|
|
467
|
+
comment = self.Comment
|
|
468
|
+
|
|
469
|
+
temp = os.path.join(env.TEMP, '~cannect')
|
|
470
|
+
os.makedirs(temp, exist_ok=True)
|
|
471
|
+
|
|
472
|
+
self.logger(f"[UPDATE SDD NOTE AND SAVE TO'{tools.path_abbreviate(path)}']")
|
|
473
|
+
for n, row in enumerate(self):
|
|
474
|
+
name = row['FunctionName']
|
|
475
|
+
self.logger.hold(f">>> %{name: <{self._space}}: ")
|
|
476
|
+
if row["SDDName"].replace(".zip", "") in os.listdir(path):
|
|
477
|
+
self.logger.log('ALREADY UPDATED')
|
|
478
|
+
continue
|
|
479
|
+
try:
|
|
480
|
+
tools.unzip(env.SVN_SDD / row["SDDName"], temp)
|
|
481
|
+
except (Exception, FileExistsError, FileNotFoundError):
|
|
482
|
+
self.logger.log('NOT FOUND IN SVN')
|
|
483
|
+
continue
|
|
484
|
+
|
|
485
|
+
file = os.path.join(temp, row['SDDName'].replace('.zip', ''))
|
|
486
|
+
os.chmod(file, stat.S_IWRITE)
|
|
487
|
+
|
|
488
|
+
sdd = SddRW(file)
|
|
489
|
+
self.logger.hold(f"v{sdd.version_doc}")
|
|
490
|
+
if sdd.version_doc != sdd.version_log:
|
|
491
|
+
self.logger.hold(f'(version mismatch on sdd)')
|
|
492
|
+
|
|
493
|
+
status = sdd.update(log=comment)
|
|
494
|
+
if status:
|
|
495
|
+
self.logger.log(f' -> v{status}')
|
|
496
|
+
else:
|
|
497
|
+
self.logger.log(f' -> v{sdd.version_doc}')
|
|
498
|
+
tools.copy_to(file, path)
|
|
499
|
+
tools.clear(temp, leave_path=True)
|
|
500
|
+
return
|
|
501
|
+
|
|
502
|
+
# def copy_sdd_to_svn(
|
|
503
|
+
# self,
|
|
504
|
+
# local_path:str='',
|
|
505
|
+
# ):
|
|
506
|
+
# # TODO
|
|
507
|
+
# path = local_path if local_path else os.path.join(self.root_path, r"09_Others\SDD")
|
|
508
|
+
# path_name = path if len(path) < 50 else f'{path[:20]} ... {path[-20:]}'
|
|
509
|
+
#
|
|
510
|
+
# tic = time.perf_counter()
|
|
511
|
+
# self.logger(f">>> COPY SDD NOTE FROM '{path_name}' TO SVN: ")
|
|
512
|
+
# for n, row in enumerate(self):
|
|
513
|
+
# name = row['FunctionName']
|
|
514
|
+
# sdd = row['SDDName']
|
|
515
|
+
# try:
|
|
516
|
+
# file = os.path.join(path, sdd)
|
|
517
|
+
# except (FileExistsError, FileNotFoundError):
|
|
518
|
+
# self.logger(f">>> ... %{name: <{self._space}} -> NOT EXIST")
|
|
519
|
+
# continue
|
|
520
|
+
# def commit_sdd(self, log:str):
|
|
521
|
+
# # TODO
|
|
522
|
+
# return
|
|
523
|
+
|
|
524
|
+
def to_clipboard(self, **kwargs):
|
|
525
|
+
return self.table[SCHEMA].to_clipboard(**kwargs)
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
if __name__ == "__main__":
|
|
529
|
+
from pandas import set_option
|
|
530
|
+
|
|
531
|
+
set_option('display.expand_frame_repr', False)
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
ir = IntegrationRequest(
|
|
536
|
+
# r"E:\TEMP\CanCNG\CanCNG.main.amd", # 신규 모델은 전체 경로 사용
|
|
537
|
+
# r"E:\TEMP\CanEMS_CNG\CanEMS_CNG.main.amd", # 신규 모델은 전체 경로 사용
|
|
538
|
+
# r"E:\TEMP\CanEMSM_CNG\CanEMSM_CNG.main.amd", # 신규 모델은 전체 경로 사용
|
|
539
|
+
"CanCVVDD",
|
|
540
|
+
"CanNOXD"
|
|
541
|
+
)
|
|
542
|
+
ir.deliverables = r'D:\Archive\00_프로젝트\2017 통신개발-\2026\DS0119 CR10787034 DTC별 IUMPR 표출 조건 변경 HEV'
|
|
543
|
+
ir.User = "이제혁"
|
|
544
|
+
ir.Comment = "VCDM CR10787034 HEV/CANFD DTC별 IUMPR 표출 조건 변경"
|
|
545
|
+
# ir.select_previous_svn_version(mode='select')
|
|
546
|
+
# ir.select_previous_svn_version(mode='latest')
|
|
547
|
+
|
|
548
|
+
# POST-ACTION
|
|
549
|
+
# ir.update_sdd(comment=ir.Comment)
|
|
550
|
+
|
|
551
|
+
# COMMIT
|
|
552
|
+
# ir.copy_model_to_svn(local_path='')
|
|
553
|
+
# ir.commit_model(log=f'[{env["NAME"]}] CR10785930 IUMPR Exception') # 반드시 영문 표기, "[", "]" 외 특수문자 불가
|
|
554
|
+
# ir.copy_sdd_to_svn(local_path='') # TODO
|
|
555
|
+
# ir.commit_sdd(log='') # TODO
|
|
556
|
+
|
|
557
|
+
# ir.resolve_svn_version('POLYSPACE')
|
|
558
|
+
# ir.resolve_svn_version()
|
|
559
|
+
# ir.resolve_sdd_version()
|
|
560
|
+
# ir.compare_model(prev='', post='', exclude_imported=False)
|
|
561
|
+
|
|
562
|
+
# 변경내역서 작성
|
|
563
|
+
# ppt = ChangeHistoryManager(
|
|
564
|
+
# path=ir.deliverables["0000_CNGPIO_통신_인터페이스_개발_CANFD"],
|
|
565
|
+
# logger=ir.logger
|
|
566
|
+
# )
|
|
567
|
+
# ppt.title = "[CAN] 송출 신호 음수 범위 미표출 오류 개선"
|
|
568
|
+
# ppt.developer = "이제혁"
|
|
569
|
+
# ppt.function = ir.table["FunctionName"]
|
|
570
|
+
# ppt.issue = "VCDM CR10787115"
|
|
571
|
+
# ppt.lcr = "자체 개선"
|
|
572
|
+
# ppt.problem = "CF_Ems_DecelReq_Can 신호 음수 범위 표출 불가"
|
|
573
|
+
# ppt.prev_model_description = ir.p_table # .select_previous_svn_version() 후행
|
|
574
|
+
# ppt.post_model_description = ir.table
|
|
575
|
+
# ppt.set_model_slides(ir.table)
|
|
576
|
+
# ppt.prev_model_details = ir.p_table # .select_previous_svn_version() 후행
|
|
577
|
+
# ppt.post_model_details = ir.table
|
|
578
|
+
# ppt.parameters = ir.parameters # .compare_model()의 후행
|
|
579
|
+
|
|
580
|
+
print(ir)
|
|
581
|
+
# ir.to_clipboard(index=False)
|