00001 """CMS TagCollector Python API 00002 """ 00003 00004 __author__ = "Miguel Ojeda" 00005 __copyright__ = "Copyright 2010-2011, CERN CMS" 00006 __credits__ = ["Miguel Ojeda"] 00007 __license__ = "Unknown" 00008 __maintainer__ = "Miguel Ojeda" 00009 __email__ = "mojedasa@cern.ch" 00010 __status__ = "Staging" 00011 00012 _tagcollector_url = 'https://cmstags.cern.ch/tc/' 00013 00014 import urllib 00015 import urllib2 00016 import cookielib 00017 import json 00018 import getpass 00019 00020 class TagCollector(object): 00021 """CMS TagCollector Python API""" 00022 00023 def __init__(self): 00024 self._url = _tagcollector_url 00025 self._cj = cookielib.CookieJar() 00026 self._opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self._cj)) 00027 00028 def _open(self, page, params = None, data = None): 00029 url = self._url + page + '?' 00030 if params: 00031 url += urllib.urlencode(params) 00032 if data: 00033 data = urllib.urlencode(data) 00034 try: 00035 return self._opener.open(url, data).read() 00036 except urllib2.HTTPError as e: 00037 raise Exception(e.read().strip()) 00038 00039 def _openjson(self, page, params = None, data = None): 00040 return json.loads(self._open(page, params, data)) 00041 00042 def signIn(self, username, password): 00043 """Sign in to TagCollector.""" 00044 self._open('CmsTCLogin', data = {'username': username, 'password': password}) 00045 00046 def signInInteractive(self): 00047 """Sign in to TagCollector, asking for the username and password.""" 00048 username = raw_input('Username: ') 00049 password = getpass.getpass() 00050 self.signIn(username, password) 00051 00052 def signOut(self): 00053 """Sign out of TagCollector.""" 00054 self._open('signOut') 00055 00056 def getPackageTags(self, package): 00057 """Get the tags published in TagCollector for a package. 00058 Note: TagCollector's published tags are a subset of CVS' tags.""" 00059 return self._openjson('py_getPackageTags', {'package': package}) 00060 00061 def getPackageTagDescriptionFirstLine(self, package, tag): 00062 """Get the first line of the descriptions of a tag.""" 00063 return self._openjson('py_getPackageTagDescriptionFirstLine', {'package': package, 'tag': tag}) 00064 00065 def getPackageTagReleases(self, package, tag): 00066 """Get the releases where a tag is.""" 00067 return self._openjson('py_getPackageTagReleases', {'package': package, 'tag': tag}) 00068 00069 def getReleasesTags(self, releases, diff = False): 00070 """Get the tags of one or more release. 00071 Optionally, return only the tags that differ between releases.""" 00072 releases = json.dumps(releases) 00073 diff = json.dumps(diff) 00074 return self._openjson('py_getReleasesTags', {'releases': releases, 'diff': diff}) 00075 00076 def getReleaseTags(self, release): 00077 """Get the tags of one release.""" 00078 return self.getReleasesTags((release, )) 00079 00080 def getTagsetTags(self, tagset): 00081 """Get the tags of one tagset.""" 00082 return self._openjson('py_getTagsetTags', {'tagset': tagset}) 00083 00084 def getTagsetInformation(self, tagset): 00085 """Get the information of one tagset.""" 00086 return self._openjson('py_getTagsetInformation', {'tagset': tagset}) 00087 00088 def getPendingApprovalTags(self, args, allow_multiple_tags = False): 00089 """Prints Pending Approval tags of one or more releases, 00090 one or more tagsets, or both (i.e. it joins all the tags). 00091 Prints an error if several tags appear for a single package. 00092 Suitable for piping to addpkg (note: at the moment, 00093 addpkg does not read from stdin, use "-f" instead).""" 00094 args = json.dumps(args) 00095 allow_multiple_tags = json.dumps(allow_multiple_tags) 00096 return self._openjson('py_getPendingApprovalTags', {'args': args, 'allow_multiple_tags': allow_multiple_tags}) 00097 00098 def commentTagsets(self, tagset_ids, comment): 00099 """Comment one or more tagsets. 00100 Requirement: Signed in.""" 00101 tagset_ids = json.dumps(tagset_ids) 00102 if len(comment) < 1: 00103 raise Exception("Error: Expected a comment.") 00104 self._open('commentTagsets', {'tagset_ids': tagset_ids, 'comment': comment}) 00105 00106 def signTagsets(self, tagset_ids, comment = ''): 00107 """Sign one or more tagsets. 00108 Requirement: Signed in as a L2.""" 00109 tagset_ids = json.dumps(tagset_ids) 00110 self._open('signTagsets', {'tagset_ids': tagset_ids, 'comment': comment}) 00111 00112 def signTagsetsAll(self, tagset_ids, comment = ''): 00113 """Sign all one or more tagsets. 00114 Requirement: Signed in as a top-level admin.""" 00115 tagset_ids = json.dumps(tagset_ids) 00116 self._open('signTagsetsAll', {'tagset_ids': tagset_ids, 'comment': comment}) 00117 00118 def rejectTagsetsPendingSignatures(self, tagset_ids, comment = ''): 00119 """Reject one or more tagsets Pending Signatures. 00120 Requirement: Signed in as a L2s or as a Release Manager 00121 for the tagset's release or as the author of the tagset.""" 00122 tagset_ids = json.dumps(tagset_ids) 00123 self._open('rejectTagsetsPendingSignatures', {'tagset_ids': tagset_ids, 'comment': comment}) 00124 00125 def approveTagsets(self, tagset_ids, comment = ''): 00126 """Approve one or more tagsets. 00127 Requirement: Signed in as a Release Manager for each tagset's release.""" 00128 tagset_ids = json.dumps(tagset_ids) 00129 self._open('approveTagsets', {'tagset_ids': tagset_ids, 'comment': comment}) 00130 00131 def bypassTagsets(self, tagset_ids, comment = ''): 00132 """Bypass one or more tagsets. 00133 Requirement: Signed in as a Release Manager for each tagset's release.""" 00134 tagset_ids = json.dumps(tagset_ids) 00135 self._open('bypassTagsets', {'tagset_ids': tagset_ids, 'comment': comment}) 00136 00137 def rejectTagsetsPendingApproval(self, tagset_ids, comment = ''): 00138 """Reject one or more tagsets Pending Approval. 00139 Requirement: Signed in as a Release Manager.""" 00140 tagset_ids = json.dumps(tagset_ids) 00141 self._open('rejectTagsetsPendingApproval', {'tagset_ids': tagset_ids, 'comment': comment}) 00142 00143 def removeTagsets(self, tagset_ids, comment = ''): 00144 """Remove one or more tagsets from the History (i.e. stack of the release). 00145 Requirement: Signed in as a Release Manager.""" 00146 tagset_ids = json.dumps(tagset_ids) 00147 self._open('removeTagsets', {'tagset_ids': tagset_ids, 'comment': comment}) 00148 00149 def getPackagesPendingApproval(self): 00150 """Get New Package Requests which are Pending Approval.""" 00151 return self._openjson('py_getPackagesPendingApproval') 00152 00153 def getPackageManagersRequested(self, package): 00154 """Get the Package Managers (administrators and developers) requested in a New Package Request.""" 00155 return self._openjson('py_getPackageManagersRequested', {'package': package}) 00156 00157 def search(self, term): 00158 """Searches for releases, packages, tagsets, users and categories. 00159 Requirement: Signed in.""" 00160 return self._openjson('search', {'term': term}) 00161 00162 def approvePackage(self, package): 00163 """Approve a New Package Request. 00164 Requirement: Signed in as a Creator (i.e. people in the top-level .admin/developers file). 00165 Warning: This does *not* create the package in CVS.""" 00166 self._open('approveNewPackageRequest', {'package_name': package}) 00167 00168 def getIBs(self, filt = '', limit = 10): 00169 """Get the name and creation date of Integration Builds. 00170 By default, it only returns the latest 10 IBs. 00171 Optionally, filter by name.""" 00172 return self._openjson('py_getIBs', {'filt': filt, 'limit': limit}) 00173