버전 넘버(빌드 넘버)은 잘 관리할 필요가 있다. 버전을 올리는 작업은 자동 업데이트 서버를 위한 version.xml 파일과, 실행화일, 설치폴더에 놓이는 local 버전파일, 셋업파일의 버전, about창에 노출되는 버전 표기 등 여러군데를 수정하여야 한다. 수 작업으로 수정할 경우 실수의 가능성도 있는데 최악의 경우 자동 업데이트 체크가 되지 않는 수도 생긴다. 버전 올리는 작업은 스크립트를 이용해서 자동화하는 것이 중요하다.
*.rc 파일에 버전을 자동으로 증가 시켜주면서
_version.h : about창에 노출되는 버전
_version.nsh : NSIS 셋업에 노출되는 버전
_version.bat : 빌드 스크립트에서 파일명 생성에 사용
version.xml : local설치폴더, 서버 업데이트체크를 위한 파일
파일을 자동으로 생성한다.
루비를 배우고 있기에 루비를 이용해서 스크립트를 만들었다.
auto_incre_version.rb :
option = {}
# cmdline option parse
p ARGV.length
ARGV.each { |o|
k,v = o.split('=')
option [k] = v;
#p o
}
# target rc
path = option["/rc"]
synconly = option["/synconly"]
filecontent = File.readlines(path)
new_filecontent = []
new_version = ''
# const
FILEVERSION = " FILEVERSION "
PRODUCTVERSION = " PRODUCTVERSION "
VALUE_FILEVERSION = ' VALUE "FileVersion", '
VALUE_PRODUCTVERSION = ' VALUE "ProductVersion", '
filecontent.each do |line|
if line.start_with?(FILEVERSION) || line.start_with?(PRODUCTVERSION)
#p line
index = line.rindex(' ')
left = line[0..index]
right = line[index+1 .. -1]
version = right.strip.split(',')
if synconly == nil
version[3] = (version.last.to_i + 1) . to_s
end
right = "%s,%s,%s,%s\n" % version
line = left + right
new_version = "%s.%s.%s.%s" % version
end
if line.start_with?(VALUE_FILEVERSION) || line.start_with?(VALUE_PRODUCTVERSION)
#p line
index = line.rindex(' "')
left = line[0..index]
right = line[index+2 .. -1]
#p right
version = right.split(',')
version.map { |a| a.strip! }
version[3] = (version.last.to_i + 1) . to_s
#p version
right = "\"%s, %s, %s, %s\"\n" % version
#p right
line = left + right
#p line
end
new_filecontent.push(line)
end
#write new .rc
if synconly == nil
File.write(path+"", new_filecontent.join() );
p "now new version is #{new_version}"
else
p "current version is #{new_version}"
end
url = "http://mdiwebma.com/easyregistry/"
nsh = option["/nsh"]
bat = option["/bat"]
h = option["/h"]
xml = option["/xml"]
if nsh != nil then
File.write(nsh, "!define _APP_VERSION \"#{new_version}\"\n")
p nsh
end
if bat != nil then
File.write(bat, "set PROJ_VERSION=#{new_version}\n")
p bat
end
if h != nil then
File.write(h, "#pragma once\n#define PROJ_VERSION \"#{new_version}\"\n")
p h
end
if xml != nil then
File.write(xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>\n<version>#{new_version}</version>\n<url>%s</url>\n</root>" % url)
p xml
end
rb파일을 실행하는 bat 파일
auto_incre_version.cmd:
".\ruby200\bin\ruby.exe" auto_incre_version.rb "/rc=%cd%\..\src\EasyRegistry\EasyRegistry.rc" "/nsh=%cd%\_version.nsh" "/bat=%cd%\_version.bat" "/xml=%cd%\version.xml" "/h=%cd%\..\src\EasyRegistry\_version.h" "%1%"
실행결과는
D:\NewProject\SDP_for_win32\build>".\ruby200\bin\ruby.exe" auto_incre_version.r
b "/rc=D:\NewProject\SDP_for_win32\build\..\src\EasyRegistry\EasyRegistry.rc" "
/nsh=D:\NewProject\SDP_for_win32\build\_version.nsh" "/bat=D:\NewProject\SDP_fo
r_win32\build\_version.bat" "/xml=D:\NewProject\SDP_for_win32\build\version.xml"
"/h=D:\NewProject\SDP_for_win32\build\..\src\EasyRegistry\_version.h" ""
6
"now new version is 1.0.0.2"
"D:\\NewProject\\SDP_for_win32\\build\\_version.nsh"
"D:\\NewProject\\SDP_for_win32\\build\\_version.bat"
"D:\\NewProject\\SDP_for_win32\\build\\..\\src\\EasyRegistry\\_version.h"
"D:\\NewProject\\SDP_for_win32\\build\\version.xml"
생성되는 결과물은 아래와 같다.
_version.bat
set PROJ_VERSION=1.0.0.2
_version.nsh
!define _APP_VERSION "1.0.0.2"
version.xml
</root>
_version.h
#pragma once
#define PROJ_VERSION "1.0.0.2"
xml이 파싱해야 하는 부담이 있어서, 경우에 따라서는 ini 파일을 생성하는 옵션을 간단히 추가하는 것도 가능하다.
예전에는 이 기능을 exe 파일을 이용하여 직접 구현을 했었고, 파이선을 배울때는 파이선을 이용하여 구현하여 웹마 프로젝트에서 아직도 사용하고 있다.
incre_build.py
#
# rc파일에서 build를 넘버를 증가시킨다.
#
import os
import sys
import shutil
import time
FILEVERSION = " FILEVERSION "
PRODUCTVERSION = " PRODUCTVERSION "
VALUE_FILEVERSION = ' VALUE "FileVersion", '
VALUE_PRODUCTVERSION = ' VALUE "ProductVersion", '
def touchrc(rcpath, rcout) :
new_version = ''
tlb_found = 0
try :
f = open(rcpath)
lines = f.readlines()
f.close()
f = open(rcout, 'w')
for l in lines :
if l.find('1 TYPELIB "WebMaP.tlb"') == 0 :
tlb_found = 1
if l.find(FILEVERSION) == 0 or l.find(PRODUCTVERSION) == 0 :
tokens = l.split(',')
i = len(tokens)-1
num = int(tokens[i])
num += 1
tokens[i] = str(num)+'\n'
l = ','.join(tokens)
v_list = l.split(' ')
new_version = v_list [ len(v_list)-1]
new_version = new_version.rstrip('\n')
new_version = new_version.replace(',','.')
if l.find(VALUE_FILEVERSION)==0 or l.find(VALUE_PRODUCTVERSION)==0:
tokens = l.split('.')
i = len(tokens)-1
t_list = tokens[i].split('"')
num = int ( t_list[0] )
num += 1
tokens[i] = str(num) + '"\n'
l = '.'.join(tokens)
f.write(l)
f.close()
except Exception, e:
print e
return ''
if tlb_found == 0 :
print 'tlb file not found !! '
sys.exit(1)
return new_version
def main(rc, h, nsh) :
#rc파일의 버전을 올린다.
rcpath = os.path.abspath(rc)
rcout = rcpath + ".incre"
ver = touchrc( rcpath, rcout )
if ver == '':
print 'build incrment failed !!'
sys.exit(1)
bakdir = os.path.abspath('.rcbak')
if not os.path.exists(bakdir) :
os.mkdir(bakdir)
timestr = str(time.localtime())
timestr = timestr.lstrip('(');
timestr = timestr.rstrip(')');
timestr= timestr.replace(', ','_')
filename = 'WebmaP4(%s).rc.' % timestr
shutil.copy(rcpath, os.path.abspath('.rcbak')+"\\" + filename )
shutil.move(rcout,rcpath)
#헤더파일을 쓴다.
try :
f = open( os.path.abspath(h), 'w')
f.write('#define MY_VERSION _T("%s")\n' % ver)
f.close()
#ver = ver.replace('.', '_')
f = open( os.path.abspath( nsh ), 'w')
f.write ( '!define _VERSION "%s"' % ver)
f.close()
f = open( os.path.abspath( '_version.bat' ), 'w')
f.write ( 'set WMVERSION=%s' % ver)
f.close()
except Exception, e:
print e
sys.exit(1)
print '[ OK ] Buil bumber increment : %s' % ver
if __name__ == "__main__" :
if len(sys.argv) != 4 :
print 'parameter error : rcfile headerfile nshfile'
print 'len(argv) %d' % len(sys.argv)
print sys.argv
sys.exit(1)
main(sys.argv[1], sys.argv[2], sys.argv[3])
sys.exit(0) # Succ!!
프로젝트 소스코드:
http://dev.naver.com/projects/sdp
다음에는 이것을 이용해서 자동 업데이트 체크를 구현해 보겠다.