first commit

This commit is contained in:
2026-02-21 17:11:31 +09:00
commit 18b4338361
4001 changed files with 365464 additions and 0 deletions

Binary file not shown.

3
script/build.bat Normal file
View File

@@ -0,0 +1,3 @@
ECHO OFF
CLS
python build_fm.py

594
script/build_fm.py Normal file
View File

@@ -0,0 +1,594 @@
import re,subprocess
import os
from pathlib import Path
import shutil
import time
from datetime import datetime
from pro_svn_version import *
from subprocess import check_output
# 압축 필요 없음
skip_zip = False
# Model Info
model_info = { 'AN6000' : 'viewer.exe',
'TB4000' : 'viewer.exe',
'EMT_KOR1' : 'viewer.exe'}
# TODO dll 의존성 확인
# dumpbin /IMPORTS avutil-55.dll
# CRASH REPORT 생성용
keep_pdbs = [] #'TB4000', 'RD_40', 'CS_F362FW'
''' USB 인증서로 변경됨
# 인증서 저장 폴더
sign_folder = 'C:\\home\\fmviewer3\\project\\signs'
# 인증 데이터
sign_model = { 'AN6000' : {'cert': '20220607-387020_mtekvision_com_chain.pfx',
'pw' : 'XIMKAS',
'desc' : 'AN6000 Viewer'},
'MH9000' : {'cert': 'keiyo_pw_Keiyo4684.pfx',
'pw' : 'Keiyo4684',
'desc' : '4LensViewer'},
}
'''
# USB 인증모델 : 인증서명
sign_model = {'EMT_KOR1' : {'name' : 'emtomega', 'pw' : '0000'}}
# signtool.exe sign /f "C:\home\roadmovie\project\signs\20220607-387020_mtekvision_com_chain.pfx" /d "mtekvision" /p XIMKAS "C:\home\roadmovie\project\build-fm_viewer-Qt_5_5-Release\release\viewer.exe"
reg_file_type_section = '[Registry]\n Root: HKCR; Subkey: ".tb4"; ValueData: "{#MyAppName}"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""\n \
Root: HKCR; Subkey: "{#MyAppName}"; ValueData: "Program {#MyAppName}"; Flags: uninsdeletekey; ValueType: string; ValueName: ""\n \
Root: HKCR; Subkey: "{#MyAppName}\\DefaultIcon"; ValueData: "{app}\\{#MyAppExeName},0"; ValueType: string; ValueName: ""\n \
Root: HKCR; Subkey: "{#MyAppName}\\shell\\open\\command"; ValueData: """{app}\\{#MyAppExeName}"" ""%1"""; ValueType: string; ValueName: ""\n'
script_info = {'EMT_KOR1' : {'name' : 'NEXIAN Viewer',
'install_file' : 'NEXIAN_Viewer',
'short_name' : 'NEXIAN Viewer',
'short_dir' : 'NEXIAN_Viewer',
'publisher' : 'MediaHills Inc.',
'exe' : 'viewer.exe',
'group_short' : 'NEXIAN Viewer',
'dir_name' : '\\NEXIAN Viewer',
'group_long' : '\\NEXIAN Viewer',
'icon' : 'C:\\home\\fmviewer3\\project\\fm_viewer\\res\\emt_kr\\emt_kr.ico',
'app_id' : '7F35092D-5CF6-4BCB-AB0F-6C314521F6B1',
'trash' : 'C:\\home\\fmviewer3\\project\\fm_viewer\\res\\emt_kr\\trash.ico',
'language' : 'Name: "korean"; MessagesFile: "compiler:Languages\\Korean.isl"',
'reg_file_type' : 'no',
'printer_section' : '',
'registry_section' : '',
'doc' : 'NEXIAN'},
'AN6000' : {'name' : 'YAWATA WiFiCAM Viewer',
'install_file' : 'YAWATA_WiFiCAM_Viewer',
'short_name' : 'YAWATA_WiFiCAM_Viewer',
'short_dir' : 'YAWATA_WiFiCAM_Viewer',
'publisher' : 'YAWATA',
'exe' : 'Viewer.exe',
'group_short' : 'YAWATA',
'dir_name' : '\\YAWATA',
'group_long' : '\\YAWATA',
'icon' : 'C:\\home\\fmviewer3\\project\\fm_viewer\\res\\mtek\\an6000.ico',
'app_id' : '4D8FFB28-75A7-4880-B78C-055F0E2D8CBB',
'trash' : 'C:\\home\\fmviewer3\\project\\fm_viewer\\res\\mtek\\trash.ico',
'language' : 'Name: "japanese"; MessagesFile: "compiler:Languages\\Japanese.isl"',
'reg_file_type' : 'no',
'printer_section' : '',
'registry_section' : '',
'doc' : 'ViewerDoc'},
'TB4000' : {'name' : 'TB4000',
'install_file' : 'TB4000',
'short_name' : 'TB4000',
'short_dir' : 'TB4000',
'publisher' : 'Telebit Inc.',
'exe' : 'Viewer.exe',
'group_short' : 'TB4000',
'dir_name' : '\\TB4000',
'group_long' : '\\TB4000',
'icon' : 'C:\\home\\fmviewer3\\project\\fm_viewer\\res\\keiyo\\keiyo.ico',
'app_id' : '2B678C5F-5F0C-4689-9CD3-F01F6E6556E0',
'trash' : 'C:\\home\\fmviewer3\\project\\fm_viewer\\res\\keiyo\\trash.ico',
'language' : 'Name: "korean"; MessagesFile: "compiler:Languages\\Korean.isl"',
'reg_file_type' : 'yes',
'registry_section' : reg_file_type_section,
'printer_section' : 'Source: "{#SRCFolder}\\printsupport\\*"; DestDir: "{app}\\printsupport"; Flags: ignoreversion recursesubdirs createallsubdirs',
'doc' : 'TB4000'},
}
# INNO SETUP 설치 스크립트를 직접 생성
# [Languages]
# $language
# Name: en; MessagesFile: "compiler:Default.isl"
# Name: "japanese"; MessagesFile: "compiler:Languages\Japanese.isl"
install_script = '''
#define MyAppName "$name"
#define MyAppShortName "$short_name"
#define MyAppPublisher "$publisher"
#define MyAppExeName "$exe"
#define MyAppGroup "$group_short"
#define MyAppGroupLong "$group_long"
#define SRCFolder "C:\\home\\fmviewer3\\project\\_build_fm\\release"
#define MyAppVersion GetVersionNumbersString(SRCFolder + '\\' + MyAppExeName)
[Setup]
AppId={{$app_id}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={commonpf}$dir_name
DisableDirPage=no
DefaultGroupName={code:GetGroupName}
;DisableProgramGroupPage=no
OutputBaseFilename=install_$install_file_ver_{#MyAppVersion}
Compression=lzma
SolidCompression=yes
ChangesAssociations=$reg_file_type
SetupIconFile=$icon
UninstallDisplayIcon={app}\\{#MyAppExeName}
UninstallDisplayName="$name"
DirExistsWarning=no
VersionInfoCompany=""
VersionInfoCopyright=""
VersionInfoDescription=""
VersionInfoProductName=""
[Languages]
$language
[Tasks]
;Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checked
[Files]
Source: "{#SRCFolder}\\*"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#SRCFolder}\\iconengines\\*"; DestDir: "{app}\\iconengines"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "{#SRCFolder}\\imageformats\\*"; DestDir: "{app}\\imageformats"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "{#SRCFolder}\\platforms\\*"; DestDir: "{app}\\platforms"; Flags: ignoreversion recursesubdirs createallsubdirs
$printer_section
Source: "$trash"; DestDir: "{app}"; Flags: ignoreversion
[Icons]
Name: "{userprograms}\\{#MyAppGroupLong}\\{#MyAppShortName}"; Filename: "{app}\\{#MyAppExeName}";
Name: "{userprograms}\\{#MyAppGroupLong}\\uninstall ({#MyAppShortName})"; Filename: "{uninstallexe}"; IconFilename: "{app}\\trash.ico";
Name: "{commondesktop}\\{#MyAppName}"; Filename: "{app}\\{#MyAppExeName}"
Name: "{app}\\Uninstall.exe"; Filename: "{app}\\unins000.exe"; IconFilename: "{app}\\trash.ico"
[UninstallDelete]
Type: files; Name: "{commondocs}\\$doc\\viewersetup\\conf.ini"
Type: files; Name: "{userdocs}\\$doc\\viewersetup\\conf.ini"
Type: files; Name: "{userprograms}\\{#MyAppGroupLong}\\{#MyAppShortName}"
Type: files; Name: "{userprograms}\\{#MyAppGroupLong}\\uninstall ({#MyAppShortName})"
$registry_section
[Code]
function InitializeUninstall(): Boolean;
var ErrorCode: Integer;
begin
ShellExec('open','taskkill.exe','/f /im {#MyAppExeName}','',SW_HIDE,ewNoWait,ErrorCode);
ShellExec('open','tskill.exe',' {#MyAppName}','',SW_HIDE,ewNoWait,ErrorCode);
result := True;
end;
function GetGroupName(Param: String): String;
var
Version: TWindowsVersion;
begin
GetWindowsVersionEx(Version);
if (Version.Major > 6) or ((Version.Major = 6) and (Version.Minor >= 2)) then begin
Result := '{#MyAppGroup}';
end else begin
Result := '{#MyAppGroup}' + '\\$short_dir';
end;
end;
'''
japan_address_src = 'C:\\home\\fmviewer3\\script\\jpaddr\\20210120_jp_addr.bin'
japan_address_db = ['XLDR_88']
# QT Project path
project_root = 'C:\\home\\fmviewer3\\project\\'
project_src = project_root + 'fm_viewer\\fm_viewer.pro'
build_dest = project_root + '_build_fm'
build_release = build_dest + '\\release'
install_dest = 'C:\\home\\build_fm'
zip7_path = '"C:\\Program Files\\7-Zip\\7z.exe"'
# SVN 폴더의 버전 정보를 확인한다
def svnversion(src_path):
p = subprocess.Popen('svnversion ' + src_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = p.communicate()
# eg. 546:556M
return int(stdout.decode('cp949').split(':')[0])
# QT PRO 파일에서 DEFINES += RM_MODEL_SVN_VERSION=656 버전 번호를 확인한다.
def proversion(src_path):
with open(src_path,mode='r',encoding='utf-8') as f:
for line in f:
if 'RM_MODEL_SVN_VERSION' in line:
print(line)
#if 'RM_MODEL_SVN_VERSION' in f.read():
#return 1
return 0
# TXT 파일에서 XXX= 라인을 확인하여 리턴
def get_txt_string(src,query):
with open(src,mode='r',encoding='utf-8') as f:
for line in f:
if query in line:
return line
return None
# YN 확인
def askyn(message):
ret = input(message + ' (Y/n) :') or 'y'
return ret == 'y' or ret == 'Y'
# subprocess 에서 발생한 os environment 를 보존한다
def run_bat_with_env(cmd):
cmd = cmd + ' && echo ~~~~START_ENVIRONMENT_HERE~~~~ && set'
env = (subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
.stdout
.read()
.decode('utf-8')
.splitlines())
record = False
for e in env:
if record:
e = e.strip().split('=')
os.environ[e[0]] = e[1]
elif e.strip() == '~~~~START_ENVIRONMENT_HERE~~~~':
record = True
#print(os.environ)
# 환경설정 확인해서 없으면 추가 => python running 중에만 동작함
def check_path():
#MSVC 추가 (environment variable 을 보존)
msvc_bat = '"C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\vcvarsall.bat" x86'
run_bat_with_env(msvc_bat)
# PATH 추가 되어 있지않으면 추가
required_path_list = [ 'C:\\PROGRAM FILES (X86)\\INNO SETUP 6',
'C:\\QT\\5.5\\MSVC2010\\BIN',
'C:\\QT\\QT515\\TOOLS\\QTCREATOR\\BIN',
'C:\\QT\\QTCREATOR-4.3.1\\BIN',
'C:\\QT\\TOOLS\\QTCREATOR\\BIN',
'C:\\QT\\TOOLS\\QTCREATOR\\BIN\\JOM',
'C:\\PROGRAM FILES (X86)\\MICROSOFT VISUAL STUDIO 10.0\\VC\\BIN',
'C:\\PROGRAM FILES (X86)\\MICROSOFT SDKS\\WINDOWS\\V7.0A\\BIN',
'C:\\Program Files (x86)\\NSIS']
# 존재하지 않는 경로 제거
required_path_list = [each_path for each_path in required_path_list if exists(each_path)]
# 이미 PATH 환경 변수에 포함된 경로 제거
path_list = os.environ['PATH'].split(';')
for each_path in path_list:
#print(each_path.upper())
if each_path.upper() in required_path_list:
required_path_list.remove(each_path.upper())
if len(required_path_list) > 0:
append = ';'.join(required_path_list)
full_path = append + ';' + os.environ['PATH'];
#print('APPEND:\t' + append)
os.environ['PATH'] = full_path
#print(os.environ['PATH'])
# 폴더에서 모든 확장자 파일 삭제
def delete_all(path,extension):
files = os.listdir( path )
for item in files:
if item.upper().endswith(extension.upper()):
os.remove( os.path.join( path, item ) )
# 폴더에서 prefix 로 검색해서 파일명 리턴 -> 이전 파일 가져오는 문제로 사용금지
def get_file_from_prefix(path,prefix):
files = os.listdir( path )
for item in files:
if item.upper().startswith(prefix.upper()):
return item
return None
def get_exe_version(path):
command_string = 'wmic datafile where name="' + path + '" get Version /value'
#subprocess.call(command_string, shell=True)
#out = check_output(['wmic','datafile','where','name',path,'get','Version','/value'])
out = check_output(command_string)
out = out.strip().decode('utf-8')
if 'Version=' in out:
out = out.split('=')[1]
return out
# ISS 파일 생성
def create_iss(model, dest):
if os.path.exists(dest):
os.remove(dest)
info = script_info[model]
iss = install_script
replace_list = list(info.keys())
for each_item in replace_list:
iss = iss.replace('$' + each_item,info[each_item])
with open(dest,mode='w+t',encoding='utf-8') as f:
f.write(iss)
# 모델 빌드 (compile + innosetup + zip)
def build_model(model):
start_dir = os.getcwd()
# 존재할 경우 전체 삭제 후 다시 생성
clean_dir()
Path(build_dest).mkdir(parents=True, exist_ok=True)
# 폴더 이동
os.chdir(build_dest)
command_string = 'qmake.exe ' + project_src + ' -spec win32-msvc2010 "CONFIG+=Release" "DEFINES+=' + model + '" && jom.exe qmake_all'
#print(command_string)
subprocess.call(command_string, shell=True)
subprocess.call('jom.exe', shell=True)
subprocess.call('jom.exe clean', shell=True)
# 처리후에도 xxx.pdb 파일은 남아 있음 -> 제거
if model not in keep_pdbs:
delete_all(build_release,'.pdb')
# DLL 추가
exe_name = model_info[model]
windeploy_cmd = 'windeployqt.exe --force --release --no-quick-import --no-translations ' + build_release + '//' + exe_name
subprocess.call(windeploy_cmd, shell=True)
vr_copy_cmd = 'copy /Y ' + project_root + 'vcredist_2010\\*.dll ' + build_release
subprocess.call(vr_copy_cmd, shell=True)
if model == 'TB4000' or model == 'TB5000':
ffmpeg_copy_cmd = 'copy /Y ' + project_root + 'ffmpeg_dll_compact_348_telebit_enc\\bin\\av*.dll ' + build_release
subprocess.call(ffmpeg_copy_cmd, shell=True)
ffmpeg_copy_cmd = 'copy /Y ' + project_root + 'ffmpeg_dll_compact_348_telebit_enc\\bin\\sw*.dll ' + build_release
subprocess.call(ffmpeg_copy_cmd, shell=True)
ffmpeg_copy_cmd = 'copy /Y ' + project_root + 'ffmpeg_dll_compact_348_telebit_enc\\bin\\libcrypt_tb.dll ' + build_release
subprocess.call(ffmpeg_copy_cmd, shell=True)
vr_copy_cmd = 'copy /Y ' + project_root + 'vcredist_2019\\*.dll ' + build_release
subprocess.call(vr_copy_cmd, shell=True)
ssl_copy_cmd = 'copy /Y ' + project_root + 'libeay\\*.dll ' + build_release
subprocess.call(ssl_copy_cmd, shell=True)
tb5000_cmd = 'copy /Y ' + project_root + 'tb5000_lib\\*.dll ' + build_release
subprocess.call(tb5000_cmd, shell=True)
else:
ffmpeg_copy_cmd = 'copy /Y ' + project_root + 'ffmpeg_dll_compact_348\\bin\\av*.dll ' + build_release
subprocess.call(ffmpeg_copy_cmd, shell=True)
ffmpeg_copy_cmd = 'copy /Y ' + project_root + 'ffmpeg_dll_compact_348\\bin\\sw*.dll ' + build_release
subprocess.call(ffmpeg_copy_cmd, shell=True)
ssl_copy_cmd = 'copy /Y ' + project_root + 'libeay\\*.dll ' + build_release
subprocess.call(ssl_copy_cmd, shell=True)
portaudio_copy_cmd = 'copy /Y ' + project_root + 'portaudio_197\\bin\\portaudio_x86*.dll ' + build_release
subprocess.call(portaudio_copy_cmd, shell=True)
webview2_copy_cmd = 'copy /Y ' + project_root + 'webview2\\webview2\\*.dll ' + build_release
subprocess.call(webview2_copy_cmd, shell=True)
# 일본 주소 DB 포함
if model in japan_address_db:
address_copy_cmd = 'copy /Y ' + japan_address_src + ' ' + build_release + '\\jpaddr.bin'
#print(address_copy_cmd)
subprocess.call(address_copy_cmd, shell=True)
# 버전 정보 필요
exe_path = build_release + '\\' + exe_name
exe_path = exe_path.replace('\\','\\\\') # wmic 커맨드로 처리해야 하여 \\ 로 경로 전달해야함
version_string = get_exe_version(exe_path)
# 필요시 SVN COMMIT
svn_commit_if_needed(f'rel:{model}_{version_string}')
# 인증모델 (실행파일 인증)
# 구 파일 인증 방식
'''
if model in sign_model:
# Microsoft SDKs 경로에 signtool.exe 존재
sign_info = sign_model[model]
sign_cmd = f'signtool.exe sign /f "{sign_folder}\\{sign_info["cert"]}" /d "{sign_info["desc"]}" /p {sign_info["pw"]} "{build_release}\\{model_info[model]}"'
print(f'CODESIGN {model} CMD:{sign_cmd}')
subprocess.call(sign_cmd, shell=True)
'''
if model in sign_model:
sign_name = sign_model[model]['name']
#sign_pw = sign_model[model]['pw'] /p 옵션은 파일형식에서만 사용가능
sign_cmd = f'signtool.exe sign /n "{sign_name}" /fd sha256 /tr http://timestamp.globalsign.com/tsa/r6advanced1 /td sha256 "{build_release}\\{model_info[model]}"'
subprocess.call(sign_cmd, shell=True)
# INNOSETUP
# "C:\Program Files (x86)\Inno Setup 6\iscc.exe" /OC:\home\build C:\home\roadmovie\project\CS_360FH.iss
# ISS 파일 생성 모델
if model in script_info:
innosetup_script = install_dest + '\\' + model + '.iss'
create_iss(model,innosetup_script)
else:
innosetup_script = project_root + model + '.iss'
innosetup_cmd = 'iscc.exe /O' + install_dest + ' ' + innosetup_script
subprocess.call(innosetup_cmd, shell=True)
# 인증모델 (설치파일 인증)
'''
if model in sign_model:
# Microsoft SDKs 경로에 signtool.exe 존재
sign_info = sign_model[model]
# 생성된 설치파일 경로 확인
install_file_prefix = get_txt_string(innosetup_script,'OutputBaseFilename')
install_file_prefix = install_file_prefix.split('=')[1].split('{')[0]
#install_file_name = get_file_from_prefix(install_dest,install_file_prefix)
install_file_name = install_file_prefix + version_string + '.exe'
sign_cmd = f'signtool.exe sign /f "{sign_folder}\\{sign_info["cert"]}" /d "{sign_info["desc"]}" /p {sign_info["pw"]} "{install_dest}\\{install_file_name}"'
subprocess.call(sign_cmd, shell=True)
'''
if model in sign_model:
sign_name = sign_model[model]['name']
#sign_pw = sign_model[model]['pw']
install_file_prefix = get_txt_string(innosetup_script,'OutputBaseFilename')
install_file_prefix = install_file_prefix.split('=')[1].split('{')[0]
#install_file_name = get_file_from_prefix(install_dest,install_file_prefix)
install_file_name = install_file_prefix + version_string + '.exe'
sign_cmd = f'signtool.exe sign /n "{sign_name}" /fd sha256 /tr http://timestamp.globalsign.com/tsa/r6advanced1 /td sha256 "{install_dest}\\{install_file_name}"'
subprocess.call(sign_cmd, shell=True)
# ISS 파일 삭제
#...
if skip_zip == False:
install_file_prefix = get_txt_string(innosetup_script,'OutputBaseFilename')
# OutputBaseFilename=install_Cellstar_CS-61FH_Viewer_ver_{#MyAppVersion}
install_file_prefix = install_file_prefix.split('=')[1].split('{')[0]
#install_file_name = get_file_from_prefix(install_dest,install_file_prefix)
install_file_name = install_file_prefix + version_string + '.exe'
# Compress zip
date_string = datetime.now().strftime("%Y%m%d")
zip_file_name = install_dest + '\\' + date_string + '_' + install_file_name.replace('.exe','.zip')
zip_cmd = zip7_path + ' a ' + zip_file_name + ' ' + install_dest + '\\' + install_file_name
subprocess.call(zip_cmd, shell=True)
# Clean
# 현재 py src 폴더로 이동
os.chdir(start_dir)
#print('current dir:' + os.getcwd())
clean_dir()
return
# 디렉토리 전체 삭제
def clean_dir():
if not os.path.exists(install_dest):
Path(install_dest).mkdir(parents=True, exist_ok=True)
if os.path.exists(build_dest):
#print('clean dir:' + build_dest)
shutil.rmtree(build_dest)
# 빌드할 모델 선택
def build_menu():
print('-------------------------')
print(' FM Builder ver. 0.1')
print(' 2020/10/05 fmproject')
print('-------------------------')
print('Select a model no. to build\n')
# 모델명 정렬
models = list(model_info.keys())
models.sort()
# 선택 모델리스트 표시 + 전체빌드
for each_model in models:
print(str(models.index(each_model)).rjust(4,' ') + ' : ' + each_model)
print(' A : BUILD ALL')
model_no = input("Enter number:") or exit()
# 전체빌드
if model_no == 'A' or model_no == 'a':
if askyn('start?') == False:
print('exit')
exit()
start_time = time.time()
for selected_model in models:
build_model(selected_model)
elapsed_time = time.time() - start_time
elapsed_time_string = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))
print('Process done:' + elapsed_time_string)
elif ',' in model_no:
model_no_list = model_no.split(',')
if askyn('start?') == False:
print('exit')
exit()
for each_model_no in model_no_list:
model_index = int(each_model_no)
selected_model = models[model_index]
print('Start building.... ' + selected_model)
build_model(selected_model)
else: # 모델별 빌드
try:
model_index = int(model_no)
except ValueError:
print('#ERR. input number only')
exit()
if len(models) <= model_index or model_index < 0:
print('#ERR. invalid model number')
exit()
selected_model = models[model_index]
print('Start building.... ' + selected_model)
if askyn('start?') == False:
print('exit')
exit()
start_time = time.time()
build_model(selected_model)
elapsed_time = time.time() - start_time
elapsed_time_string = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))
print('Process done:' + elapsed_time_string)
# 폴더 열기
open_cmd = 'explorer "' + install_dest + '"'
subprocess.Popen(open_cmd)
check_path()
build_menu()
'''
# MAIN
svn_path = 'C:\\home\\fmviewer3'
svn_version = svnversion(svn_path)
print('SVN:'+str(svn_version))
pro_path = 'C:\\home\\fmviewer3\\project\\chunho_viewer\\chunho_viewer.pro'
pro_version = proversion(pro_path)
print(pro_version)
src_path = 'C:\\home\\fmviewer3'
#print('svn info ' + src_path)
svn_info = subprocess.check_output('svn info ' + src_path).decode('cp949') #utf-8
#print(svn_info)
revisionNum = re.search("Revision:\s\d+", svn_info)
print(revisionNum)
#print (re.search(ur"Revision:\s\d+", svn_info)).group()
'''

67
script/pro_svn_version.py Normal file
View File

@@ -0,0 +1,67 @@
import os
import re,subprocess
from os.path import exists
import sys
from subprocess import check_output
# Qt PRO 파일에서 SVN 버전 정보 확인
def get_pro_svn_version(path):
# RM_MODEL_SVN_VERSION=812
with open(path,'r', encoding='utf8') as f:
for line in f:
res = re.search('SVN_VERSION=[0-9]{1,4}',line)
if res:
f.close()
return res.group().replace('SVN_VERSION=','').strip()
f.close()
return None
# EVB 파일에서 이전 버전을 확인하고 신규로 교체하여 임시 EVB 파일 생성
def replace_evb_version(path,version,dest):
# ZDR09_811 ->
with open(path,'r', encoding='utf8') as f:
text = f.read()
# ZDR09_811
#old_version_object = re.search('ZDR[0-9]{2,3}_[0-9]{1,4}',text)
# BYD01_917
#old_version_object = re.search('CB_R_[0-9]{1,4}|ZDR[0-9]{2,3}_[0-9]{1,4}|ELUT[0-9]{2,3}_[0-9]{1,4}',text)
old_version_object = re.search('KZR[0-9]{2,3}_[0-9]{1,4}|CB_R_[0-9]{1,4}|ZDR[0-9]{2,3}EN_[0-9]{1,4}|ZDR[0-9]{2,3}_[0-9]{1,4}|ELUT[0-9]{2,3}_[0-9]{1,4}|BYD[0-9]{2,3}_[0-9]{1,4}|MBJ_[0-9]{1,4}|ADR_S10_[0-9]{1,4}',text)
if old_version_object:
old_version = old_version_object.group()
new_version_object = re.search('CB_R|ZDR[0-9]{2,3}EN|ZDR[0-9]{2,3}|KZR[0-9]{2,3}|ELUT[0-9]{2,3}|BYD[0-9]{2,3}|MBJ|ADR_S10',old_version)
new_version = new_version_object.group() + '_' + version
#print('old_version:',old_version,'new_version:',new_version)
#print(new_version)
text = text.replace(old_version,new_version)
if exists(dest):
os.remove(dest)
with open(dest,'w', encoding='utf8') as fw:
fw.write(text)
fw.close()
f.close
return True
f.close()
return False
# SVN 커밋
def svn_commit_if_needed(message):
root = 'C:\\home\\roadmovie'
out = check_output(['svn', 'status', root])
out = out.strip().decode('utf-8')
lines = out.splitlines()
if any((line.startswith('M') or line.startswith('A')) for line in lines):
command_string = f'svn commit {root} -m"{message}"'
subprocess.call(command_string, shell=True)
#print(command_string)
#print('COMMIT')
else:
print('NO UPDATES')
if __name__ == "__main__":
svn_commit_if_needed('test')
#svn_version = get_pro_svn_version('C:\\home\\roadmovie\\project\\roadmovie\\roadmovie.pro')
#if svn_version:
# replace_evb_version('C:\\home\\roadmovie\\project\\install_script\\ZDR09.evb',svn_version,'C:\\home\\roadmovie\\project\\install_script\\test.evb')

View File

@@ -0,0 +1,155 @@
import sys
import os
from os import listdir
from os.path import isfile, join
from PIL import Image, ImageEnhance, ImageDraw
#from PIL import
import shutil
# 0:NORMAL, 1:HOVER, 2:PRESSED, 3:DISABLED
TYPE_BUTTON = 0
TYPE_STATIC = 1
TYPE_STATIC2 = 2 # NORMAL 2 가 존재함
TYPE_STATIC3 = 3 # NORMAL-> ALPHA DISABLE (3) 생성
#src_path = 'C:\\home\\roadmovie\\project\\fm_viewer\\res\\fmproject\\guide.jpg'
src_path_guide = 'C:\\home\\temp\\image\\nexian_src\\nexian_guide.png'
src_path_normal = 'C:\\home\\temp\\image\\nexian_src\\nexian_normal.png'
src_path_normal2 = 'C:\\home\\temp\\image\\nexian_src\\nexian_normal2.png'
src_path_focused = 'C:\\home\\temp\\image\\nexian_src\\nexian_focused.png'
src_path_pressed = 'C:\\home\\temp\\image\\nexian_src\\nexian_selected.png'
src_path_disabled = 'C:\\home\\temp\\image\\nexian_src\\nexian_disable.png'
target_path = 'C:\\home\\temp\\image\\nexian\\'
#target_path = r'C:\home\roadmovie\project\fm_viewer\res\emt_kr'
crop_info = [ ('title_bg',(0,0,1,42),TYPE_STATIC),
('title_logo',(8,5,145,33),TYPE_STATIC),
('title_report',(736,3,36,36),TYPE_BUTTON),
('title_split',(774,3,36,36),TYPE_BUTTON),
('title_capture',(812,3,36,36 ),TYPE_BUTTON),
('title_map',(850,3,36,36 ),TYPE_BUTTON),
('title_setup',(888,3,36,36),TYPE_BUTTON),
('title_info',(926,3,36,36),TYPE_BUTTON),
('title_minimize',(974,3,36,36),TYPE_BUTTON),
('title_close',(1012,3,36,36),TYPE_BUTTON),
('title_maximize',(661,3,36,36),TYPE_BUTTON),
('title_seperator',(966,3,5,36),TYPE_STATIC),
('title_normal',(698,3,36,36),TYPE_BUTTON),
('title_video_front',(5,51,107,20),TYPE_STATIC),
('title_video_rear',(699,51,107,20),TYPE_STATIC),
('vt_swap',(547,48,30,26),TYPE_BUTTON),
('vt_flip_h',(583,48,30,26),TYPE_BUTTON),
('vt_flip_v',(620,48,30,26),TYPE_BUTTON),
('vt_fullscreen',(656,48,30,26),TYPE_BUTTON),
('vt_fullscreen_checked',(511,48,30,26),TYPE_BUTTON),
('vt_ch3',(475,48,30,26),TYPE_BUTTON),
('vt_ch3_checked',(869,48,30,26),TYPE_BUTTON),
('vt_360wide',(438,48,30,26),TYPE_BUTTON),
('vt_360normal',(402,48,30,26),TYPE_BUTTON),
('logo_front_big',(189,117,320,320),TYPE_STATIC2),
('logo_rear_small',(746,135,260,95),TYPE_STATIC),
('logo_rear_big',(189,117,320,320),TYPE_STATIC2),
('logo_front_small',(746,135,260,95),TYPE_STATIC),
('title_list',(699,312,136,22),TYPE_STATIC),
('backup',(1001,311,44,24),TYPE_BUTTON),
('type_all',(710,337,49,26),TYPE_STATIC3),
('type_normal',(787,337,31 ,26),TYPE_STATIC3),
('type_manual',(854,337,31,26),TYPE_STATIC3),
('type_event',(906,337,59,26),TYPE_STATIC3),
('type_park',(973,337,66,26),TYPE_STATIC3),
('slider_knob',(365,466,8,18),TYPE_BUTTON),
('slider_knob_small',(92,583,4,14),TYPE_BUTTON),
('v_constrast',(12,575,30,30),TYPE_BUTTON),
('v_brightness',(177,575,30,30),TYPE_BUTTON),
('v_volume',(340,575,30,30),TYPE_BUTTON),
('v_volume_checked',(340,545,30,30),TYPE_BUTTON),
('v_speed',(503,575,30,30),TYPE_BUTTON),
('sensor_x',(94,497,30,25),TYPE_BUTTON),
('sensor_y',(94,522,30,25),TYPE_BUTTON),
('sensor_z',(94,547,30,25),TYPE_BUTTON),
('speed_kmh',(6,548,87,23),TYPE_BUTTON),
('speed_mph',(6,525,87,23),TYPE_BUTTON),
('graph_up',(663,498,28,36),TYPE_BUTTON),
('graph_down',(663,535,28,36),TYPE_BUTTON),
('graph_seperator',(663,533,28,3),TYPE_STATIC),
('play_bg',(5,605,1,71),TYPE_STATIC),
('play_stop',(22,611,62,62),TYPE_BUTTON), # 1
('play_play',(94,611,62,62),TYPE_BUTTON), # 2
('play_previous',(166,611,62,62),TYPE_BUTTON), # 3
('play_backward',(238,611,62,62),TYPE_BUTTON), # 4
('play_play_checked',(310,611,62,62),TYPE_BUTTON), # 5
('play_forward',(382,611,62,62),TYPE_BUTTON), # 6
('play_next',(454,611,62,62),TYPE_BUTTON), # 7
('play_seperator',(570,606,3,70),TYPE_STATIC),
('open',(572,606,121,70),TYPE_BUTTON),
]
def cropImages():
src_normal = Image.open(src_path_normal)
src_normal2 = Image.open(src_path_normal2)
src_focused = Image.open(src_path_focused)
src_pressed = Image.open(src_path_pressed)
src_disabled = Image.open(src_path_disabled)
#print(src)
#images = list(crop_info.keys())
for each_image in crop_info:
title = each_image[0]
#print(each_image,crop_info[each_image])
crop = each_image[1]
control_type = each_image[2]
if control_type == TYPE_STATIC2:
im = src_normal2.crop((crop[0],crop[1],crop[0]+crop[2],crop[1]+crop[3]))
else:
im = src_normal.crop((crop[0],crop[1],crop[0]+crop[2],crop[1]+crop[3]))
# libpng warning: iCCP: known incorrect sRGB profile 에러 제거?
#im.info.pop('icc_profile', None)
dest_path = join(target_path, title + '.png')
print(dest_path)
im.save(dest_path,'PNG',icc_profile=None)
if control_type == TYPE_STATIC3:
im3 = im.copy()
alpha = im3.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(0.5)
im3.putalpha(alpha)
dest_path = join(target_path, title + '_3.png')
im3.save(dest_path,'PNG',icc_profile=None)
continue
if control_type != TYPE_BUTTON:
continue
im = src_focused.crop((crop[0],crop[1],crop[0]+crop[2],crop[1]+crop[3]))
im.save(join(target_path, title + '_1.png'),'PNG',icc_profile=None)
im = src_pressed.crop((crop[0],crop[1],crop[0]+crop[2],crop[1]+crop[3]))
im.save(join(target_path, title + '_2.png'),'PNG',icc_profile=None)
im = src_disabled.crop((crop[0],crop[1],crop[0]+crop[2],crop[1]+crop[3]))
im.save(join(target_path, title + '_3.png'),'PNG',icc_profile=None)
return
def guideImages():
src = Image.open(src_path_guide)
draw = ImageDraw.Draw(src, "RGBA")
for each_image in crop_info:
#title = each_image[0]
crop = each_image[1]
control_type = each_image[2]
if control_type is TYPE_BUTTON:
line_color = (255,0,255)
else:
line_color = (0,255,255)
draw.rectangle(((crop[0], crop[1]),(crop[0]+crop[2]-1, crop[1]+crop[3]-1)),outline=line_color,width=1,fill=(None))
dest_path = join(r'C:\home\temp\image\nexian_src','guide_processed.png')
src.save(dest_path,'PNG')
cropImages()
#guideImages()