81""" Internal function to allow overloading, you must override _setoutput.
+ 82 """
+ 83# the output is automatically converted to ascii before any treatment
+ 84ifisinstance(output,unicode):
+ 85self._output_str=output.encode('ascii','replace')
+ 86else:
+ 87self._output_str=output.decode('ascii','ignore')
+ 88_logger.debug("output ---->")
+ 89forlineinself._output_str.splitlines():
+ 90_logger.debug(line)
+ 91_logger.debug("<----")
+ 92self._setoutput(self._output_str)
+
485
+ 486CHECKOUT_LOG_RULES=[[r'^Derive failed for',logging.ERROR],
+ 487[r'^Serious:',logging.ERROR],
+ 488[r'^Warning: .* failed.',logging.ERROR],
+ 489[r'^Warning:',logging.WARNING],]
+ 490
+ 491UPDATE_LOG_RULES=[[r'^Update failed.',logging.ERROR],
+ 492[r'^Serious:',logging.ERROR],
+ 493[r'^\s+Failed to',logging.ERROR],
+ 494[r'^\d+ failures to',logging.ERROR],
+ 495[r"^Warning: This work area '.+' cannot be reused",logging.ERROR],
+ 496[r'^Rebind of .* failed',logging.ERROR],
+ 497[r'^Warning: .* failed.',logging.ERROR],
+ 498[r'^Skipping \'.*\'\. You do not have permission to modify this project.',logging.ERROR],
+ 499[r'^Work area conflict exists for file',logging.ERROR],
+ 500[r'^Warning: No candidates found for directory entry',logging.ERROR],
+ 501[r'^Warning:',logging.WARNING],]
+ 502
+ 503CONFLICTS_LOG_RULES=[[r'^\w+#\d+\s+Implicit',logging.WARNING],
+ 504[r'^(.*)\s+(\w+#\d+)\s+(.+)',logging.ERROR],]
+ 505
+ 506SYNC_LOG_RULES=[[r'^\s+0\s+Conflict\(s\) for project',logging.INFO],
+ 507[r'^\s+\d+\s+Conflict\(s\) for project',logging.ERROR],
+ 508[r'^Project \'.*\' does not maintain a workarea.',logging.ERROR],
+ 509[r'^Work area conflict exists for file',logging.ERROR],
+ 510[r'^Warning: Conflicts detected during synchronization. Check your logs.',logging.ERROR],
+ 511[r'^Warning:',logging.WARNING],]
+ 512
+
574""" Object factory, this is the toolkit entry point to create objects from
+ 575 four part names. Objects are stored into a dictionary, so you have
+ 576 only one wrapper per synergy object.
+ 577 """
+ 578result=re.search(r"^(?P<project>.+)-(?P<version>[^:]+?)$",fpn)
+ 579ifresult!=None:
+ 580matches=result.groupdict()
+ 581fpn="%s-%s:project:%s#1"%(matches['project'],matches['version'],self.database())
+ 582_logger.debug("session.create('%s')"%fpn)
+ 583ofpn=FourPartName(fpn)
+ 584ifnotself.__ccm_objects.has_key(str(fpn)):
+ 585obj=None
+ 586ifofpn.type=='project':
+ 587obj=Project(self,fpn)
+ 588elifofpn.type=='dir':
+ 589obj=Dir(self,fpn)
+ 590elifofpn.type=='task':
+ 591obj=Task(self,fpn)
+ 592elifofpn.type=='folder':
+ 593obj=Folder(self,fpn)
+ 594elifofpn.type=='releasedef':
+ 595obj=Releasedef(self,fpn)
+ 596else:
+ 597obj=File(self,fpn)
+ 598self.__ccm_objects[str(fpn)]=obj
+ 599returnself.__ccm_objects[str(fpn)]
+
602""" Return a dictionary containing workarea info from directory dir.
+ 603 """
+ 604if(notos.path.exists(dir_)):
+ 605raiseCCMException("Error retrieving work_area info for the directory '%s' (doesn't exists)"%dir_)
+ 606path=os.path.abspath(os.path.curdir)
+ 607path_ccmwaid=os.path.join(dir_,"_ccmwaid.inf");
+ 608if(notos.path.exists(path_ccmwaid)):
+ 609raiseCCMException("No work area in '%s'"%dir_)
+ 610os.chdir(dir_)
+ 611result=self.execute("wa -show",WorkAreaInfoResult(self))
+ 612os.chdir(path)
+ 613ifresult.output==None:
+ 614raiseCCMException("Error retrieving work_area info for the directory '%s'"%dir_)
+ 615returnresult.output
+
622""" method to be override by child class else property accession is not working properly. """
+ 623iflen(role)==0orrole==None:
+ 624raiseCCMException("You must provide a role.")
+ 625result=self.execute("set role %s"%role)
+ 626ifre.match(r'^Warning:',result.output,re.M)!=None:
+ 627raiseCCMException("Error switching to role %s: %s"%(role,result.output.strip()))
+
639iflen(home)==0orhome==None:
+ 640raiseCCMException("You must provide a home.")
+ 641result=self.execute("set Home %s"%home)
+ 642ifre.match(r'^Warning:',result.output,re.M)!=None:
+ 643raiseCCMException("Error switching to Home %s: %s"%(home,result.output.strip()))
+
852""" This object wrap a synergy query, it takes a query as input as well as the
+ 853 attribute you want as output, and get them translated using the model configuration.
+ 854 e.g
+ 855 Query(session, "type='task' and release='test/next'", ['objectname', 'task_synopsis'], ['ccmobject', 'string'])
+ 856
+ 857 This will return a list of hash: [{'objectname': Task(xxx), 'task_synopsis': 'xxx'}, ...]
+ 858 """
+ 859
+
928""" Returns the objectname of the object. """
+ 929if(self.type=='releasedef'):
+ 930return"%s:%s:%s:%s"%(self.name,self.version,self.type,self.instance)
+ 931return"%s-%s:%s:%s"%(self.name,self.version,self.type,self.instance)
+
944""" Returns True if the ccmobject is part of the same family (=same name, type and version) as self. """
+ 945assertisinstance(ccmobject,FourPartName)
+ 946return(self.name==ccmobject.nameandself.type==ccmobject.typeandself.instance==ccmobject.instance)
+
952""" Returns True if object four parts name are identical. """
+ 953ifccmobject==None:
+ 954returnFalse
+ 955assertisinstance(ccmobject,FourPartName)
+ 956return(self.name==ccmobject.nameandself.version==ccmobject.versionandself.type==ccmobject.typeandself.instance==ccmobject.instance)
+
959""" Returns True if object four parts name are different. """
+ 960ifccmobject==None:
+ 961returnTrue
+ 962assertisinstance(ccmobject,FourPartName)
+ 963return(self.name!=ccmobject.nameorself.version!=ccmobject.versionorself.type!=ccmobject.typeorself.instance!=ccmobject.instance)
+
967""" Check if a given string represents a valid four part name.
+ 968 """
+ 969return(re.match(r"^(.+)-(.+?):(\S+):(\S+)|(.+):(.+?):releasedef:(\S+)$",fpn)!=None)
+
973""" Update a CCM output string to a valid four part name. This is due to the f$*@ing inconsistent
+ 974 output of CM/Synergy that will probably never get fixed as it would require they hire humains
+ 975 and not apes to core their CLI.
+ 976 """
+ 977fpn=fpn.strip()
+ 978ifFourPartName.is_valid(fpn):
+ 979returnfpn
+ 980result=re.search(r"^(?P<type>Task|Folder)\s+(?P<instance>\w+)#(?P<id>\d+)$",fpn)
+ 981ifresult!=None:
+ 982matches=result.groupdict()
+ 983ifmatches["type"]=="Task":
+ 984return"task%s-1:task:%s"%(matches["id"],matches["instance"])
+ 985elifmatches["type"]=="Folder":
+ 986return"%s-1:folder:%s"%(matches['id'],matches['instance'])
+ 987else:
+ 988result=re.search(r"^(?P<project>\S+)/(?P<version>\S+)$",fpn)
+ 989ifresult!=None:
+ 990matches=result.groupdict()
+ 991return"%s:%s:releasedef:1"%(matches['project'],matches['version'])
+ 992else:
+ 993# Check the name doesn't contains any of the following character: " :-"
+ 994result=re.search(r"^[^\s^:^-]+$",fpn)
+ 995ifresult!=None:
+ 996return"none:%s:releasedef:1"%(fpn)
+ 997raiseInvalidFourPartNameException(fpn)
+
1020""" Check if an the object exists in the database. """
+1021return(len(self._session.execute("query \"name='%s' and version='%s' and type='%s' and instance='%s'\" -u -f \"%%objectname\""%(self.name,self.version,self.type,self.instance),ObjectListResult(self._session)).output)==1)
+
1059""" The list of supported Synergy attributes. """
+1060result=self._session.execute("attribute -la \"%s\""%self,AttributeNameListResult(self._session))
+1061returnresult.output
+
1125""" Tries to find where an object is used. """
+1126result=self._session.execute("finduse \"%s\""%self,FinduseResult(self))
+1127returnresult.output
+
1220""" Wrapper method to return the folder list from the update properties - please use the folders attribute to access it. """
+1221result=self._session.execute("up -show folders \"%s\" -u -f \"%%objectname\""%self,ObjectListResult(self._session))
+1222returnresult.output
+
1225""" Wrapper method to return the subprojects list - please use the subprojects attribute to access it. """
+1226result=self._session.execute("query -t project \"recursive_is_member_of('%s', none)\" -u -f \"%%objectname\""%self.objectname,ObjectListResult(self._session))
+1227returnresult.output
+
1239""" Get the release of the current object. Returns a Releasedef object. """
+1240self._release=Releasedef(self._session,self['release'])
+1241returnself._release
+
1253""" Get the baseline of the current project. """
+1254ifself._baseline==None:
+1255result=self._session.execute("up -show baseline_project \"%s\" -f \"%%displayname\" -u"%self.objectname)
+1256ifresult.output.strip().endswith('does not have a baseline project.'):
+1257returnNone
+1258self._baseline=self._session.create(result.output)
+1259_logger.debug('baseline: %s'%self._baseline)
+1260returnself._baseline
+
1263""" Set project baseline. raise a CCMException in case or error. """
+1264args=""
+1265ifrecurse:
+1266args+=" -r"
+1267self._baseline=None
+1268result=self._session.execute("up -mb \"%s\" %s \"%s\""%(baseline,args,self.objectname))
+1269ifresult.status!=Noneandresult.status!=0:
+1270raiseCCMException("Error setting basline of project '%s'\n%s"%(self.objectname,result.output))
+
1273""" Set the update method for the project (and subproject if recurse is True). """
+1274assertname!=None,"name must not be None."
+1275assertlen(name)>0,"name must not be an empty string."
+1276args="-ru %s"%name
+1277ifrecurse:
+1278args+=" -r"
+1279result=self._session.execute("up %s \"%s\""%(args,self))
+1280ifresult.status!=Noneandresult.status!=0:
+1281raiseCCMException("Error setting reconfigure properties to %s for project '%s'\nStatus: %s\n%s"%(name,self.objectname,result.status,result.output))
+
1302""" Take a snapshot of the project. """
+1303assert(targetdir!=None,"targetdir must be defined.")
+1304ifrecursive:
+1305recursive="-recurse"
+1306else:
+1307recursive=""
+1308result=self._session.execute("wa_snapshot -path \"%s\" %s \"%s\""%(os.path.normpath(targetdir),recursive,self.objectname))
+1309forlineinresult.output.splitlines():
+1310ifre.match(r"^Creation of snapshot work area complete.|Copying to file system complete\.\s*$",line):
+1311returnresult.output
+1312raiseCCMException("Error creation snapshot of %s,\n%s"%(self.objectname,result.output),result)
+
1315""" Create a checkout of this project.
+1316
+1317 This will only checkout the project in Synergy. It does not create a work area.
+1318
+1319 :param release: The Synergy release tag to use.
+1320 :param version: The new version to use for the project. This is applied to all subprojects.
+1321 :param purpose: The purpose of the checkout. Determines automatically the role from the purpose
+1322 and switch it automatically (Could be any role from the DB).
+1323 """
+1324assertrelease!=None,"Release object must be defined."
+1325ifnotrelease.exists():
+1326raiseCCMException("Release '%s' must exist in the database."%release)
+1327
+1328args=''
+1329ifversion!=None:
+1330args+='-to "%s"'%version
+1331role=None
+1332ifpurpose:
+1333self._session.role=get_role_for_purpose(self._session,purpose)
+1334args+=" -purpose \"%s\""%purpose
+1335ifsubprojects:
+1336args+=" -subprojects"
+1337result=self._session.execute("checkout -project \"%s\" -release \"%s\" -no_wa %s" \
+1338%(self,release['displayname'],args),ProjectCheckoutResult(self._session,self.objectname))
+1339ifrole:
+1340self._session.role=role
+1341ifresult.project==None:
+1342raiseCCMException("Error checking out project %s,\n%s"%(self.objectname,result.output),result)
+1343returnresult
+
1392""" Reconcile the project to force the work area to match the database. """
+1393args=""
+1394ifupdatewa:
+1395args+=" -update_wa "
+1396ifrecurse:
+1397args+=" -recurse "
+1398ifconsideruncontrolled:
+1399args+=" -consider_uncontrolled "
+1400ifmissingwafile:
+1401args+=" -missing_wa_file "
+1402ifreport:
+1403args+=" -report reconcile.txt "
+1404result=self._session.execute("reconcile %s -project %s"%(args,self.objectname),Result(self._session))
+1405ifre.search(r"There are no conflicts in the Work Area",result.output)==Noneandre.search(r"Reconcile completed",result.output)==None:
+1406raiseCCMException("Error reconciling %s,\n%s"%(self.objectname,result.output),result)
+1407returnresult.output
+
1419""" Synchronize project content. By default it is not been done recusively. (Not unittested)"""
+1420args=""
+1421ifrecurse:
+1422args+=" -recurse"
+1423ifstatic:
+1424args+=" -static"
+1425result=self._session.execute("sync %s -project \"%s\""%(args,self.objectname))
+1426ifresult.status!=Noneandresult.status!=0:
+1427raiseCCMException("Error during synchronization of %s: %s."%(self.objectname,result.output))
+1428returnresult.output
+
1489""" Get the mode used by the folder. """
+1490result=self._session.execute("folder -show mode \"%s\""%self.objectname)
+1491returnresult.output.strip()
+
1494""" Get the query that populate the folder. """
+1495ifself.mode.lower()=="query":
+1496result=self._session.execute("folder -show query \"%s\""%self.objectname)
+1497returnresult.output.strip()
+1498else:
+1499raiseCCMException("%s is not a query base folder."%(self.objectname))
+
1518""" Associate an object to a task """
+1519classAddTaskException(CCMException):
+1520def__init__(self,reason,task,result):
+1521CCMException.__init__(self,reason,result)
+1522self.task=task
+
1529""" Copy the contents of existing_folder into this folder.
+1530
+1531 This appends to the destination folder by default.
+1532
+1533 :param existing_folder: The destination Folder object.
+1534 """
+1535result=self._session.execute("folder -copy %s -existing %s -append"%(self.objectname,existing_folder),FolderCopyResult(self._session))
+1536returnresult.output
+
1558""" Associate an object to a task """
+1559classAddObjectException(CCMException):
+1560def__init__(self,comment,ccm_object):
+1561CCMException.__init__(self,comment)
+1562self.ccm_object=ccm_object
+
1578assertrelease_tag.type=="releasedef","release_tag must be a CCM object wrapper of releasedef type"
+1579result=session.execute("task -create -synopsis \"%s\" -release \"%s\""%(synopsis,release_tag['displayname']),CreateNewTaskResult(session))
+1580returnresult.output
+
1585# TODO: use optimised query that makes only 1 ccm query with suitable format
+1586ifself.__unicode_str_text==None:
+1587self.__unicode_str_text=u'%s: %s'%(self['displayname'],self['task_synopsis'])
+1588returnself.__unicode_str_text
+
1618""" Query all projects for this UpdateTemplate. """
+1619result=self._releasedef.session.execute("ut -sh baseline_projects \"%s\""%self.objectname(),ObjectListResult(self._releasedef.session))
+1620printresult.output
+1621returnresult.output
+
1637""" Read data from a ccmwaid file. This method is an helper to retreive a project from a physical location. """
+1638ccmwaid=open(filename,'r')
+1639# first line: database
+1640dbpath=os.path.dirname(ccmwaid.readline().strip())
+1641database=os.path.basename(dbpath)
+1642# 2nd line should be a timestamp
+1643ccmwaid.readline().strip()
+1644# 3rd line is the objectname
+1645objectref=ccmwaid.readline().strip()
+1646ccmwaid.close()
+1647return{'dbpath':dbpath,'database':database,'objectname':objectref}
+
1663"""Provides a Session object.
+1664
+1665 Attempts to return a Session, based either on existing Synergy
+1666 sessions or by creating a new one.
+1667
+1668 - If a .netrc file can be found on the user's personal drive,
+1669 that will be read to obtain Synergy login information if it
+1670 is defined there. This will be used to fill in any missing
+1671 parameters not passed in the call to open_session().
+1672
+1673 The format of the .netrc file entries should be:
+1674
+1675 machine synergy login USERNAME password foobar account DATABASE_PATH@SERVER
+1676
+1677 If the details refer to a specific database, the machine can be the database name,
+1678 instead of "synergy".
+1679 - If an existing session is running that matches the supplied
+1680 parameters, it will reuse that.
+1681
+1682 """
+1683# See if a .netrc file can be used
+1684ifCCM_BIN==None:
+1685raiseCCMException("Could not find CM/Synergy executable in the path.")
+1686ifpassword==Noneorusername==Noneorengine==Noneordbpath==None:
+1687ifsys.platform=="win32":
+1688os.environ['HOME']="H:"+os.sep
+1689_logger.debug('Opening .netrc file')
+1690try:
+1691netrc_file=netrc.netrc()
+1692netrc_info=None
+1693# If settings for a specific database
+1694ifdatabase!=None:
+1695netrc_info=netrc_file.authenticators(database)
+1696
+1697# if not found just try generic one
+1698ifnetrc_info==None:
+1699netrc_info=netrc_file.authenticators('synergy')
+1700
+1701ifnetrc_info!=None:
+1702(n_username,n_account,n_password)=netrc_info
+1703ifusername==None:
+1704username=n_username
+1705ifpassword==None:
+1706password=n_password
+1707ifn_account!=None:
+1708(n_dbpath,n_engine)=n_account.split('@')
+1709ifdbpath==Noneandn_dbpathisnotNone:
+1710_logger.info('Database path set using .netrc (%s)'%n_dbpath)
+1711dbpath=n_dbpath
+1712ifengine==Noneandn_engineisnotNone:
+1713_logger.info('Database engine set using .netrc (%s)'%n_engine)
+1714engine=n_engine
+1715exceptIOError:
+1716_logger.debug('Error accessing .netrc file')
+1717
+1718# last chance...
+1719ifusername==None:
+1720username=os.environ['USERNAME']
+1721
+1722# looking for dbpath using GSCM database
+1723ifdbpath==Noneanddatabase!=None:
+1724_logger.info('Database path set using the GSCM database.')
+1725dbpath=nokia.gscm.get_db_path(database)
+1726
+1727# looking for engine host using GSCM database
+1728ifengine==Noneanddatabase!=None:
+1729_logger.info('Database engine set using the GSCM database.')
+1730engine=nokia.gscm.get_engine_host(database)
+1731
+1732_sessions=[]
+1733# See if any currently running sessions can be used, only if no password submitted, else use a brand new session!
+1734ifpassword==Noneandreuse:
+1735_logger.debug('Querying for existing Synergy sessions')
+1736command="%s status"%(CCM_BIN)
+1737pipe=os.popen(command,'r')
+1738result=pipe.read()
+1739pipe.close()
+1740_logger.debug('ccm status result: '+result)
+1741formatchinre.finditer(r'(?P<ccmaddr>\w+:\d+:\d+.\d+.\d+.\d+(:\d+.\d+.\d+.\d+)?)(?P<current_session>\s+\(current\s+session\))?\nDatabase:\s*(?P<dbpath>\S+)',result,re.M):
+1742d=match.groupdict()
+1743_logger.debug(d['ccmaddr'])
+1744_logger.debug(os.environ['COMPUTERNAME'])
+1745_logger.debug(d['current_session'])
+1746ifd['ccmaddr'].lower().startswith(os.environ['COMPUTERNAME'].lower()):
+1747# These session objects should not close the session on deletion,
+1748# because they did not initially create the session
+1749existing_session=Session(username,engine,d['dbpath'],d['ccmaddr'],close_on_exit=False)
+1750_logger.debug('Existing session found: %s'%existing_session)
+1751_sessions.append(existing_session)
+1752# looking for session using dbpath
+1753forsessionin_sessions:
+1754ifsession.dbpath==dbpath:
+1755returnsession
+1756else:
+1757# looking for router address using GSCM database
+1758router_address=None
+1759ifdatabase==Noneanddbpath!=None:
+1760database=os.path.basename(dbpath)
+1761
+1762lock=fileutils.Lock(CCM_SESSION_LOCK)
+1763try:
+1764lock.lock(wait=True)
+1765# if we have the database name we can switch to the correct Synergy router
+1766ifdatabase!=None:
+1767_logger.info('Getting router address.')
+1768router_address=nokia.gscm.get_router_address(database)
+1769ifsys.platform=="win32"androuter_address!=None:
+1770routerfile=open(os.path.join(os.path.dirname(CCM_BIN),"../etc/_router.adr"),'r')
+1771current_router=routerfile.read().strip()
+1772routerfile.close()
+1773ifcurrent_router!=router_address.strip():
+1774_logger.info('Updating %s'%(os.path.normpath(os.path.join(os.path.dirname(CCM_BIN),"../etc/_router.adr"))))
+1775routerfile=open(os.path.join(os.path.dirname(CCM_BIN),"../etc/_router.adr"),"w+")
+1776routerfile.write("%s\n"%router_address)
+1777routerfile.close()
+1778
+1779# If no existing sessions were available, start a new one
+1780_logger.info('Opening session.')
+1781new_session=Session.start(username,password,engine,dbpath)
+1782lock.unlock()
+1783returnnew_session
+1784finally:
+1785lock.unlock()
+1786raiseCCMException("Cannot open session for user '%s'"%username)
+
1790""" return role needed to modify project with checkout for purpose. """
+1791purposes=session.purposes()
+1792ifpurposeinpurposes:
+1793ifpurposes[purpose]['status']=='prep':
+1794return'build_mgr'
+1795else:
+1796raiseCCMException("Could not find purpose '%s' in the database.\n Valid purpose are: %s."%(purpose,','.join(purposes.keys())))
+1797return'developer'
+
1800""" return role needed to modify project with a specific status. """
+1801ifstatus=='prep':
+1802return'build_mgr'
+1803elifstatus=='working':
+1804return'developer'
+1805else:
+1806raiseCCMException("Unknow status '%s'"%status)
+
1809""" Return the list of synergy session currently available on the local machine.
+1810 If database is given then it tries to update the router address.
+1811 """
+1812_logger.debug('Querying for existing Synergy sessions')
+1813ifCCM_BIN==None:
+1814raiseCCMException("Could not find CM/Synergy executable in the path.")
+1815command="%s status"%(CCM_BIN)
+1816
+1817lock=fileutils.Lock(CCM_SESSION_LOCK)
+1818result=""
+1819output=[]
+1820try:
+1821# if we have the database name we can switch to the correct Synergy router
+1822ifdatabase!=None:
+1823lock.lock(wait=True)
+1824_logger.info('Updating router address.')
+1825router_address=nokia.gscm.get_router_address(database)
+1826ifsys.platform=="win32"androuter_address!=None:
+1827routerfile=open(os.path.join(os.path.dirname(CCM_BIN),"../etc/_router.adr"),'r')
+1828current_router=routerfile.read().strip()
+1829routerfile.close()
+1830ifcurrent_router!=router_address.strip():
+1831_logger.info('Updating %s'%(os.path.normpath(os.path.join(os.path.dirname(CCM_BIN),"../etc/_router.adr"))))
+1832routerfile=open(os.path.join(os.path.dirname(CCM_BIN),"../etc/_router.adr"),"w+")
+1833routerfile.write("%s\n"%router_address)
+1834routerfile.close()
+1835
+1836_logger.debug('Command: '+command)
+1837(result,status)=_execute(command)
+1838ifdatabase!=None:
+1839lock.unlock()
+1840if(status!=0):
+1841raiseCCMException("Ccm status execution returned an error.")
+1842_logger.debug('ccm status result: '+result)
+1843formatchinre.finditer(r'Command Interface\s+@\s+(?P<ccmaddr>\w+:\d+:\d+.\d+.\d+.\d+(:\d+.\d+.\d+.\d+)*)(?P<current_session>\s+\(current\s+session\))?\s+Database:\s*(?P<dbpath>\S+)',result,re.M):
+1844data=match.groupdict()
+1845_logger.debug(data['ccmaddr'])
+1846_logger.debug(os.environ['COMPUTERNAME'])
+1847_logger.debug(data['current_session'])
+1848ifdata['ccmaddr'].lower().startswith(os.environ['COMPUTERNAME'].lower()):
+1849# These session objects should not close the session on deletion,
+1850# because they did not initially create the session
+1851existing_session=Session(None,None,data['dbpath'],data['ccmaddr'],close_on_exit=False)
+1852_logger.debug('Existing session found: %s'%existing_session)
+1853output.append(existing_session)
+1854finally:
+1855ifdatabase!=None:
+1856lock.unlock()
+1857returnoutput
+
1865
+1866# The location of the ccm binary must be located to know where the _router.adr file is, to support
+1867# switching databases.
+1868CCM_BIN=fileutils.which("ccm")
+1869ifsys.platform=="win32":
+1870CCM_BIN=fileutils.which("ccm.exe")
+1871
+