- class로 바꾸었음 (중간 중간 다른 일 하면서 작성해서 구성은 개선점이 많음)
- 이전 base/partial과 build id 기준 왔다갔다 하면서 동작 가능
- command-line interface 추가 및 pyinstaller를 이용한 실행파일 작성
- P4 관련 내용은 삭제
- qb를 여러개 사용하여 여러 branch 동시 빌드 가능하도록 수정
* 아래 comment 참고해서 xml을 위한 file access를 없애자.
==================================================
import time
import re
import requests
from xml.etree.ElementTree import ElementTree as ETR
from xml.etree.ElementTree import Element as ET
from xml.etree.ElementTree import parse
BUILD_XML = 'build_data.xml'
BUILDINFOXML = 'buildinfo.xml'
QB_URL = 'https://android.qb.sec.samsung.net/rest/'
QB_TOKENRQ = 'https://android.qb.sec.samsung.net/signin?1-1.IFormSubmitListener-form'
QB_CONFPATH = 'ids?configuration_path='
QB_BUILDRQ = 'build_requests'
QB_BUILDS = 'builds/'
class QB:
def __init__(self):
self.__qb_cookies = dict()
def qblogin(self, user, password, reflash=False):
if len(self.__qb_cookies) != 0:
return self.session, self.__qb_cookies
token_url = QB_TOKENRQ
token_data = {'userName': user, 'password': password}
self.session = requests.session()
self.session.post(token_url, token_data)
self.__qb_cookies = requests.utils.dict_from_cookiejar(self.session.cookies)
if len(self.__qb_cookies) < 3:
print('Quickbuild login failed ...\n')
time.sleep(1)
return self.session, self.__qb_cookies
def qb_getconfid(self, path):
if len(self.__qb_cookies) == 0:
print('quickbuild has not been logged ...')
return 0
txt = requests.get(QB_URL + QB_CONFPATH + path, cookies=self.__qb_cookies, verify=True).text
time.sleep(1)
return txt
def qb_getbuild(self, bid:str):
if len(self.__qb_cookies) == 0:
print('quickbuild has not been logged ...')
return 0
txt = requests.get(QB_URL + QB_BUILDS + bid, cookies=self.__qb_cookies, verify=True).text
# string을 그냥 return하는 것으로 변경...
with open(BUILDINFOXML, 'wt', encoding='utf-8') as f:
n = f.write(txt)
return n
def qb_getclinfo(self):
base = ''
partials = ''
# string을 받아 tree.getroot()대신 바로 ElementTree.fromstring()으로 root 획득
with open(BUILDINFOXML, 'rt', encoding='utf-8') as f:
tree = parse(BUILDINFOXML)
root = tree.getroot()
sav = root.find('secretAwareVariableValues')
entlist = sav.getchildren()
for ent in entlist:
l = ent.getchildren()
if l[0].text == 'CL_SYNC':
base = l[1].getchildren()[0].text
if l[0].text == 'CL_PARTIAL' :
sublist = l[1].getchildren()
if len(sublist) != 0:
partials = l[1].getchildren()[0].text
return base, partials
def __qb_entry(self, vname, vval):
ent = ET('entry')
name = ET('string')
name.text = vname
ent.append(name)
val = ET('string')
val.text = vval
ent.append(val)
return ent
def qb_data(self, confid, base, partials, usermode=True, csc=None):
if type(confid) != str or type(base) != str or (partials != None and type(partials) != str):
raise TypeError
breq = ET('com.pmease.quickbuild.BuildRequest')
cid = ET('configurationId')
cid.text = confid
breq.append(cid)
variables = ET('variables')
if usermode==True:
variables.append(self.__qb_entry('DEFAULT_BUILD_MODE', 'USER_BUILD_DEFAULT_OPTIONS'))
else:
variables.append(self.__qb_entry('DEFAULT_BUILD_MODE', 'ENG_BUILD_DEFAULT_OPTIONS'))
variables.append(self.__qb_entry('CL_SYNC', base))
variables.append(self.__qb_entry('CL_PARTIAL', partials))
variables.append(self.__qb_entry('CL_SHELVE', ''))
if csc!=None:
variables.append(self.__qb_entry('BUILD_CSC', csc))
breq.append(variables)
# ETR(breq).tostring()을 이용해서 string을 return
ETR(breq).write(BUILD_XML, encoding='utf-8', method='xml', xml_declaration=True)
def qb_build(self, confid, base, partials, usermode=True):
qb_header = {'Content-Type': 'text/xml', 'charset': 'utf-8'}
self.qb_data(confid, base, partials, usermode)
# xml을 string으로 받아 바로 data에 설정하는 것으로 변경
rtn = requests.post(QB_URL + QB_BUILDRQ, data=open(BUILD_XML, 'rt', encoding='utf-8').read().replace('\n', ''), cookies=self.__qb_cookies, headers = qb_header)
time.sleep(1)
return rtn
CLLIST = 'cl_list.txt'
CHKCL = 'checkcl.txt'
CLFORM = re.compile(r'\d+')
ENC = 'utf-8'
ENC2 = 'euc-kr'
ENC3 = 'cp949'
#################################################################################
class CL:
qb = None
def reset(self):
self.refmode = 0 # 0 : use base and partial, 1 : user build-id
self.kormode = 0
self.rbid = self.cbid = ''
self.e = self.k = self.a = self.s = self.m = self.orgstr = self.errmsg = self.basecl = self.qb_base = self.qb_partials = ''
self.eurclset = set()
self.korclset = set()
self.addclset = set()
self.subclset = set()
self.mustset = set()
self.diff1 = set()
self.diff2 = set()
self.resultlist = []
self.mustlist = []
self.underlist = []
self.newlist = []
self.config = []
self.confid = dict()
def setfile(self, fn):
self.filename = fn
def __init__(self, qbinst=None, fn=None):
self.qb = qbinst if qbinst != None else None
self.setfile(CLLIST if fn==None else fn)
self.reset()
def setqb(qbinst):
self.qb = qbinst
def str2set(self, cls):
CL = re.compile(r'\w+')
clset = set()
#
for match in CL.finditer(cls):
cl = match.group()
clset.add(cl)
return clset
def set2str(self, clset):
clstr = ''
for cl in clset:
clstr += str(cl)
clstr += ','
return clstr[:-1]
def set2str2(self, clset, chkset):
clstr = ''
for cl in clset:
clstr += str(cl)
if cl in chkset:
clstr += '*'
clstr += ','
return clstr[:-1]
def __match_comment(self, line):
temp = re.findall('^\s*#(.*)', line)
if temp != []:
return True
return False
def __matchcls(self, base, matchstr, line):
match = False
temp = re.findall('^\s*'+matchstr+'\s*=', line)
if len(temp) > 0:
match = True
temp = re.findall('^\s*'+matchstr+'\s*=\s*([\d,\s]*)#{0,1}', line)
if temp != []:
if base != '':
base += ','
base += temp[0].replace(' ','').replace('\n','')
return match, base
def __getcls(self):
self.reset()
with open(self.filename, mode='rt', encoding='utf-8') as f:
#
ln = 0
while(1):
line = f.readline()
ln += 1
self.orgstr += line
if line == '' or line[:13] == '# end of data':
break
temp = []
#
temp = re.findall('\s*', line)
if temp[0] == line:
continue
temp = re.findall('^qb\s*=\s*([\w/]+)', line)
if temp != []:
self.config.append(temp[0])
continue
temp = re.findall('^ref_buildid\s*=\s*([\d]+)', line)
if temp != []:
self.rbid = temp[0]
try:
self.qb.qb_getbuild(self.rbid)
self.basecl, self.e = self.qb.qb_getclinfo()
except:
print('Error occured !!! : ref - self.basecl = %s, self.e = %s' % (self.basecl, self.e))
self.refmode = 1
continue
temp = re.findall('^cur_buildid', line)
if temp != []:
temp = re.findall('^cur_buildid\s*=\s*([\d]+)', line)
if temp != []:
self.cbid = temp[0]
try:
self.qb.qb_getbuild(self.cbid)
tempbase, self.k = self.qb.qb_getclinfo()
except:
print('Error occured !!! : cur - tempbase = %s, self.k = %s' % (tempbase, self.k))
if tempbase != self.basecl:
print("Warning !!! ... current base is not the same one as ref base's ")
self.kormode = 1
continue
if(self.refmode == 0):
temp = re.findall('^base\s*=\s*([\d]+)', line)
if temp != []:
self.basecl = temp[0]
continue
#
match = mt = False
if(self.refmode == 0):
mt, self.e = self.__matchcls(self.e, 'ref_partials', line)
match |= mt
if(self.kormode == 0):
mt, self.k = self.__matchcls(self.k, 'cur_partials', line)
match |= mt
mt, self.a = self.__matchcls(self.a, 'add_partials', line)
match |= mt
mt, self.s = self.__matchcls(self.s, 'sub_partials', line)
match |= mt
mt, self.m = self.__matchcls(self.m, 'must_partials', line)
match |= mt
match |= self.__match_comment(line)
if match == False :
print('Error in line #%d' % ln)
self.errmsg += 'Error in line #'
self.errmsg += str(ln)
self.errmsg += '\n'
self.eurclset = self.str2set(self.e)
self.korclset = self.str2set(self.k)
self.addclset = self.str2set(self.a)
self.subclset = self.str2set(self.s)
self.mustset = self.str2set(self.m)
def __putcls(self):
result_str = '------------------------------------------\n' + \
self.errmsg + '\n' \
'1. REF - CUR : \n' + \
self.set2str2(self.diff1, self.subclset) + '\n\n' + \
'2. CUR - REF : (Please check whether to add or not!) \n' + \
self.set2str2(self.diff2, self.addclset) + '\n\n' + \
'3. New CL list = REF + ADD CL - SUB CL (' + str(len(self.newcllist)) + ' CLs)\n\n' + 'Base : ' + str(self.basecl) + '\nPartial : \n' + \
str([int(x) for x in self.newcllist]).replace(', ',',')[1:-1] + '\n\n' + \
'***** CLs below the Base *****\n' + \
str([int(x) for x in self.underlist]).replace(', ',',')[1:-1] + '\n'
#
with open(self.filename, mode='wt+', encoding='utf-8') as f:
f.write(self.orgstr)
f.write(result_str)
#
def update(self):
print('##### process CL list "%s" ... #####' % self.filename)
self.reset()
self.__getcls()
self.diff1 = self.eurclset - self.korclset # - subclset
self.diff2 = self.korclset - self.eurclset # - addclset
# self.korclset = self.korclset.union(eurclset)
# self.korclset = self.korclset.union(addclset)
self.korclset = self.eurclset | self.addclset # korclset에 넣어둔 CL때문에 잘못 나오는 것이 있어 로직 변경
self.resultlist = list(self.korclset - self.subclset)
self.mustlist = list(self.mustset)
self.underlist = [ x for x in self.resultlist if int(x) < int(self.basecl) ]
self.newcllist = [ x for x in self.resultlist if int(x) > int(self.basecl) ]
self.underlist.sort()
self.newcllist.sort()
self.mustlist.sort()
for cl in self.mustlist:
if cl not in self.newcllist:
self.newcllist.append(cl)
self.__putcls()
print('##### Completed #####\n')
# prepare variables to build
self.qb_base = str(self.basecl)
self.qb_partials = str([int(x) for x in self.newcllist]).replace(', ',',')[1:-1]
##################################################################
class Release:
def __init__(self):
self.qb = QB()
self.cl = CL(self.qb, CLLIST)
def update(self):
self.cl.update()
def build(self, target='all'):
for x in self.cl.config:
print(' Triggering build for %s ...\n' % x)
cid = self.cl.confid.get(x, self.qb.qb_getconfid(x))
if target=='user':
self.qb.qb_build(x, self.cl.qb_base, self.cl.qb_partials, True)
if target=='eng' :
self.qb.qb_build(x, self.cl.qb_base, self.cl.qb_partials, False)
if target=='all' :
self.qb.qb_build(x, self.cl.qb_base, self.cl.qb_partials, True)
time.sleep(2)
self.qb.qb_build(x, self.cl.qb_base, self.cl.qb_partials, False)
time.sleep(2)
##################################################################
# release = Release()
# update = lambda : release.u()
# build = lambda : release.b()
##################################################################
class ReleaseUI:
user = ''
password = ''
def __qblogin(self):
if self.user == '' or self.password == '':
print('You should enter login information agian.\nMenu login finished.')
print('Quickbuild log-in ...\n')
self.release.qb.qblogin(self.user, self.password)
def doLogin(self):
if self.user == '':
self.user = input('userName cannot be null.\nPlease enter userName : ')
if self.password == '':
self.password = input('password cannot be null.\nPlease enter password : ')
self.__qblogin()
def doReLogin(self):
self.user = input('Please enter userName : ')
self.password = input('Please tner password : ')
self.doLogin()
def __init__(self):
print('Release Tool v1.0\n' + '-'*10 + '\n')
print('Please be sure to place "cl_list.txt" at the same folder with this Program !!! \n')
self.release = Release()
self.doReLogin()
def doUpdate(self):
self.release.update()
def doBuild(self, target='all'):
if target == 'all' or target == 'user' or target == 'eng':
self.release.build(target)
else:
print('Cannot recognize build option : %s' % target)
def doHelp(self):
print('Release Tool v1.0\n' + '-'*10 + '\n')
print('Please be sure to place "cl_list.txt" at the same folder with this Program !!! \n')
print('commands')
print('- help or ? : this screen')
print('- update : update cl_list.txt')
print('- login : login on Quickbuild server')
print('- relogin : login on Quickbuild server with new user and password')
print('- build : build with respect to the CLs on cl_list.txt')
print(' build or build all - build user and eng binary')
print(' build user - build user binary')
print(' build eng - build eng binary')
print('- exit : Exit from menu')
def __call__(self):
while True:
instr = input('Enter command ? ')
command = re.findall(r'([\w]+|\?)', instr)
cmd = [x.lower() for x in command]
if len(cmd) == 0:
continue
if cmd[0] == 'update':
self.doUpdate()
elif cmd[0] == 'login':
self.doLogin()
elif cmd[0] == 'relogin':
self.doReLogin()
elif cmd[0] == 'build' :
if len(cmd) > 1:
self.doBuild(target=cmd[1])
else:
self.doBuild()
elif cmd[0] == 'help' or cmd[0] == '?':
self.doHelp()
elif cmd[0] == 'exit':
break;
else:
print('Invalid command : %s' % command[0])
if __name__ == '__main__':
try:
with open(CLLIST, 'rt') as f:
pass
R = ReleaseUI()
R()
except:
print('Please be sure to place "cl_list.txt" at the same folder with this Program !!! \n')
댓글 없음:
댓글 쓰기