first commit
This commit is contained in:
BIN
script/__pycache__/pro_svn_version.cpython-313.pyc
Normal file
BIN
script/__pycache__/pro_svn_version.cpython-313.pyc
Normal file
Binary file not shown.
3
script/build.bat
Normal file
3
script/build.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
ECHO OFF
|
||||
CLS
|
||||
python build_fm.py
|
||||
594
script/build_fm.py
Normal file
594
script/build_fm.py
Normal 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
67
script/pro_svn_version.py
Normal 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')
|
||||
|
||||
155
script/uitools/image_crop_nexian.py
Normal file
155
script/uitools/image_crop_nexian.py
Normal 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()
|
||||
Reference in New Issue
Block a user