Files
fmviewer3/script/build_fm.py
2026-02-21 17:11:31 +09:00

594 lines
24 KiB
Python

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()
'''