PKb4Ɓ55EGG-INFO/entry_points.txt[console_scripts] subzilla = subzilla.subzilla:main PKb4%&[[EGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: subzilla Version: 0.1 Summary: Subzilla will post a patch from a Subversion tree to a Bugzilla bug, apply a patch from a Bugzilla bug to a Subversion tree, or close a Bugzilla bug. Home-page: http://svn.osafoundation.org/sandbox/jeffrey/subzilla/README.txt Author: Jeffrey Harris Author-email: UNKNOWN License: UNKNOWN Description: Development has focused on connecting to OSAF's Bugzilla instance, but it ought to work with reasonable Bugzilla instances. Platform: UNKNOWN Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Console Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Python Software Foundation License Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Bug Tracking PKb45= EGG-INFO/requires.txttwill>=0.8.0PKb4_~EGG-INFO/SOURCES.txtREADME.txt setup.py subzilla/__init__.py subzilla/subzilla.py subzilla.egg-info/PKG-INFO subzilla.egg-info/SOURCES.txt subzilla.egg-info/entry_points.txt subzilla.egg-info/requires.txt subzilla.egg-info/top_level.txt PKb4+E EGG-INFO/top_level.txtsubzilla PKb4EGG-INFO/zip-safePKb4subzilla/__init__.pyPKb4jMX߆subzilla/__init__.pyc; Dc@sdS(N((((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/__init__.pys?sPKb442%_2_2subzilla/subzilla.py#!/usr/bin/env python """subzilla, a utility for working with Subversion and Bugzilla. subzilla requires that twill be installed, and that svn and patch be in your path. """ import twill, os, StringIO import ConfigParser, getpass from optparse import OptionParser import re version = '0.1' class Options(object): def add(self, otherOptions, override=False): for key, val in otherOptions.__dict__.iteritems(): if override or not hasattr(self, key): setattr(self, key, val) default = Options() default.cookie_file = "~/.subzilla_cookie" default.ini_file = "~/.subzilla" # OSAF's bugzilla should be the default, but we want to prompt # once to use it, so name it default.defaulturl, not default.url default.defaulturl = "https://bugzilla.osafoundation.org/" options = Options() def main(): global browser, state, attachment_page, initial_url, description if not getOptions(): return attachment_page = "attachment.cgi" show_bug_page = "show_bug.cgi" if options.apply or options.close: initial_url="%s%s?id=%s" % (options.url, show_bug_page, bug_number) else: initial_url="%s%s?bugid=%s&action=enter" % (options.url, attachment_page, bug_number) browser = twill.browser.TwillBrowser() state = browser._browser # twill wants to print a whole bunch of information, don't let it if not options.verbose: twill.browser.OUT = os.tmpfile() if options.post: # before going to the network, check if there's anything to do if options.restrict is not None: restrict = options.restrict elif options.use_current: restrict = os.getcwd() else: restrict = options.subversion_root diff = get_diff(options.subversion_root, restrict) if diff is None: print "no local changes in %s" % restrict return # go to the first page start(initial_url) if options.apply: apply_patch(get_patch(), options.subversion_root) elif options.post: # post a diff while description == "": description = raw_input("Patch description (cannot be blank): ") comment = raw_input("Patch comment (optional): ") reviewer = raw_input("Request review from (optional): ") if options.verbose: print "Submitting patch for bug %s" % bug_number if options.obsolete: print "Obsoleting any existing patches" post_patch('Subzilla_%s.diff' % bug_number, diff, description, comment, options.obsolete, reviewer) elif options.close: close_bug() def start(initial_url): try: browser.load_cookies(os.path.expanduser(options.cookie_file)) if options.verbose: print "using cookies" except IOError: pass browser.go(initial_url) def getName(name): return browser.get_form_field(state.form, name) def login(): # find the appropriate form, for now just assume it's form 0 controls = state.forms()[0].controls controls[0].value = options.username controls[1].value = options.password browser.submit(None) browser.save_cookies(os.path.expanduser(options.cookie_file)) def close_bug(): # find the appropriate form, for now just assume it's form 0 state.form = state.forms()[0] # we may have been logged in via cookie, if not, login if state.form.controls[0].name == "Bugzilla_login": login() state.form = state.forms()[0] rev = get_revision(options.subversion_root) if rev is not None: default = "Fixed in r%s." % rev else: default = "Fixed." comment = raw_input("Close comment [default: %s]: " % default) if comment == '': comment = default getName('knob').get('resolve').selected = True getName('resolution').get('FIXED').selected = True getName('comment').value = comment browser.submit(None) print print "Bug closed." def post_patch(filename, filestream, description, comment=None, obsolete_old = True, reviewer = ''): # find the appropriate form, for now just assume it's form 0 state.form = state.forms()[0] # we may have been logged in via cookie, if not, login if state.form.controls[0].name == "Bugzilla_login": login() state.form = state.forms()[0] # set patch, file, and description fields getName('ispatch').items[0].selected = True getName('data').add_file(filestream, filename=filename) getName('description').value = description if comment is not None: getName('comment').value = comment if obsolete_old: try: for i in getName('obsolete').items: i.selected = True except: pass if reviewer != '': getName('flag_type-2').get('?').selected = True getName('requestee_type-2').value = reviewer browser.submit(None) print print "Patch posted." def get_diff(svn_root, path): path = os.path.abspath(os.path.expanduser(path)) svn_root = os.path.normpath(os.path.expanduser(svn_root)) if options.verbose: print "Using %s for svn_root" % svn_root print "Getting diff from %s" % path if path.find(svn_root) != 0: # path isn't in svn_root return None # after norm_path, svn_root will not contain a trailing slash # so chop off one more character than len(svn_root) rel_path = path[len(svn_root) + 1:] diff_cmd = "cd %s; svn diff %s" % (svn_root, rel_path) diff = StringIO.StringIO(os.popen(diff_cmd).read()) if diff.read(1) == "": return None else: diff.seek(0) return diff def get_revision(svn_root): info_cmd = "cd %s; svn info" % svn_root info = StringIO.StringIO(os.popen(info_cmd).read()) for line in info.readlines(): if line.startswith('Revision'): return line.split()[-1] return None link_pat = re.compile('attachment\.cgi\?id=\d*$') def get_patch(): links = [l for l in state.links() if link_pat.match(l.url)] if len(links) == 0: print "No attachments found for bug %s, quitting" % bug_number else: position = options.patch_number browser.follow_link(links[position]) return browser.get_html() def apply_patch(patch, path): patch_cmd = "cd %s; patch -up0" % path input, info = os.popen4(patch_cmd) input.write(patch) input.close() for line in info.readlines(): print line def inSVN(path): info_cmd = "cd %s; svn info" % path # use popen4 to read in stderr input, info = os.popen4(info_cmd) for line in info.readlines(): if line[:4] == "URL:": return True return False def getOptions(): ##### Configuration options ##### global bug_number, description usage = "usage: %prog [options] bug [description]" parser = OptionParser(usage=usage, version=version) parser.set_description( "subzilla will post a patch from a Subversion tree " "to a Bugzilla bug, apply a patch from a Bugzilla " "bug to a Subversion tree, or close the given bug.") parser.set_defaults(verbose=False, apply=False, post=False, close=False, prompt=False, obsolete=True) parser.add_option("-a", "--apply", dest="apply", action="store_true", help="apply a patch from bug [default: True]") parser.add_option("-p", "--post", dest="post", action="store_true", help="post the current Subversion diff") parser.add_option("-c", "--close", dest="close", action="store_true", help="close the bug") parser.add_option("-d", "--use-current-dir", dest="use_current", default=False, action="store_true", help="restrict posted diff to the current directory") parser.add_option("-r", "--restrict-diff", dest="restrict", help="restrict posteddiff to the given directory or file " "(overrides -d)") parser.add_option("--patch-number", dest="patch_number", default=-1, type='int', help="which patch should be applied " "(the default, -1, means last)") parser.add_option("-f", "--file", dest="ini_file", default=default.ini_file, metavar="FILE", help="read configuration from FILE [default: %default]") parser.add_option("-v", "--verbose", default=False, action="store_true", dest="verbose") parser.add_option("-j", "--project", dest="project", help="read options from PROJECT in the config file") parser.add_option("--force-prompt", dest="prompt", action="store_true", help="force prompt to input options and overwrite " "config file") parser.add_option("--preserve", dest="obsolete", default=True, action="store_false", help="don't obsolete existing patches") (cmdline_options, args) = parser.parse_args() if len(args) < 1: print "error: too few arguments given" print print parser.format_help() return False bug_number = args[0] if len(args) > 1: description = args[1] else: description = '' if not cmdline_options.close and not cmdline_options.post: cmdline_options.apply = True cfg = ConfigParser.SafeConfigParser() cfg.read(os.path.expanduser(cmdline_options.ini_file)) cfg_options = Options() section_used = None project = getattr(cmdline_options, 'project', None) for section in cfg.sections(): if project is not None: if project == section: section_used = section elif cfg.has_option(section, 'subversion_root'): expanded = os.path.expanduser(cfg.get(section, 'subversion_root')) root = os.path.normpath(expanded) if os.path.commonprefix([root, os.getcwd()]) == root: section_used = section if section_used is not None: for key, val in cfg.items(section): if cmdline_options.verbose: if key == 'password': print "Loading %s as: %s" % (key, '****') else: print "Loading %s as: %s" % (key, val) setattr(cfg_options, key, val) break options.add(cmdline_options) options.add(cfg_options) options.add(default) if project is None and not inSVN(os.getcwd()): print "error: not in a subversion tree and no project given" print print parser.format_help() return False ##### Prompt the user for options, if appropriate ##### prompted = Options() if options.prompt or not hasattr(options, 'url'): prompted.url = raw_input( "Base Bugzilla URL [default %s]:\n" % options.defaulturl) if prompted.url == '': prompted.url = options.defaulturl if options.prompt or not hasattr(options, 'username'): prompted.username = raw_input("Username: ") if options.prompt or not hasattr(options, 'password'): prompted.password = getpass.getpass() if options.prompt or not hasattr(options, 'subversion_root'): current = os.getcwd() prompted.subversion_root = raw_input("Subversion home [%s]: " % current) if prompted.subversion_root == '': prompted.subversion_root = current if options.prompt or len(prompted.__dict__) > 0: msg ="Save project to %s [y]/n (password will be stored in plaintext)? " should_save = raw_input(msg % options.ini_file) if should_save.lower() in ("", "y"): project_name = raw_input("Project name: ").lower() if not cfg.has_section(project_name): cfg.add_section(project_name) for key, val in prompted.__dict__.iteritems(): cfg.set(project_name, key, val) f = file(os.path.expanduser(cmdline_options.ini_file), 'w') cfg.write(f) f.close() options.add(prompted, override=True) # make sure the base url is terminated with a slash character if options.url[-1] != '/': options.url += '/' return True if __name__ == "__main__": try: main() except KeyboardInterrupt: print "Aborted" PKb4qn6n6subzilla/subzilla.pyc; Dc@sQdZdkZdkZdkZdkZdkZdklZdkZdZ de fdYZ e Z de _ de _de _e Zd Zd Zd Zd Zd ZeeddZdZdZeidZdZdZdZdZ e!djo*y eWqMe"j o dGHqMXndS(ssubzilla, a utility for working with Subversion and Bugzilla. subzilla requires that twill be installed, and that svn and patch be in your path. N(s OptionParsers0.1sOptionscBstZedZRS(NcCsPxI|iiD]8\}}|pt|| ot|||qqWdS(N( s otherOptionss__dict__s iteritemsskeysvalsoverrideshasattrsselfssetattr(sselfs otherOptionssoverridesvalskey((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pysadds (s__name__s __module__sFalsesadd(((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pysOptionsss~/.subzilla_cookies ~/.subzillas#https://bugzilla.osafoundation.org/cCst odSndad}tiptiodti|tfandtittfat i i a t i a ti otit i _ntiottitj o ti}n$tioti}n ti}tti|}|tjod|GHdSqntttiotttintioxtdjotdaqRWtd}td }tio d tGHti!o d GHqnt"d t|t|ti!|ntio t#ndS( Nsattachment.cgis show_bug.cgis %s%s?id=%ss%s%s?bugid=%s&action=entersno local changes in %sss%Patch description (cannot be blank): sPatch comment (optional): s Request review from (optional): sSubmitting patch for bug %ssObsoleting any existing patchessSubzilla_%s.diff($s getOptionssattachment_pages show_bug_pagesoptionssapplysclosesurls bug_numbers initial_urlstwillsbrowsers TwillBrowsers_browsersstatesverbosesosstmpfilesOUTspostsrestrictsNones use_currentsgetcwdssubversion_rootsget_diffsdiffsstarts apply_patchs get_patchs descriptions raw_inputscommentsreviewersobsoletes post_patchs close_bug(srestrictsdiffsreviewerscomments show_bug_page((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pysmainsN                     cCsZy3titiititio dGHnWntj onXti |dS(Ns using cookies( sbrowsers load_cookiessosspaths expandusersoptionss cookie_filesverbosesIOErrorsgos initial_url(s initial_url((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pysstartZs  cCstiti|SdS(N(sbrowsersget_form_fieldsstatesformsname(sname((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pysgetNamecscCs`tidi}ti|d_ti|d_tit ti t i i tidS(Nii(sstatesformsscontrolssoptionssusernamesvaluespasswordsbrowserssubmitsNones save_cookiessosspaths expandusers cookie_file(scontrols((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pysloginfs  cCstidt_tiididjottidt_ntti}|t j od|}nd}t d|}|djo |}nttdid_ttd id _|td _tit Hd GHdS( NisBugzilla_logins Fixed in r%s.sFixed.sClose comment [default: %s]: ssknobsresolves resolutionsFIXEDscomments Bug closed.(sstatesformssformscontrolssnameslogins get_revisionsoptionsssubversion_rootsrevsNonesdefaults raw_inputscommentsTruesgetNamesgetsselectedsvaluesbrowserssubmit(scommentsdefaultsrev((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pys close_bugns"    scCs4tidt_tiididjottidt_nttdid_ tdi |d||td_|tj o|td_n|o5y'x tdiD]}t|_ qWWqqXn|d jo+ttd id _ |td _ntitHd GHdS(NisBugzilla_loginsispatchsdatasfilenames descriptionscommentsobsoletess flag_type-2s?srequestee_type-2s Patch posted.(sstatesformssformscontrolssnamesloginsTruesgetNamesitemssselectedsadd_files filestreamsfilenames descriptionsvaluescommentsNones obsolete_oldsisreviewersgetsbrowserssubmit(sfilenames filestreams descriptionscomments obsolete_oldsreviewersi((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pys post_patchs,   cCstiitii|}tiitii|}tiod|GHd|GHn|i|djot Sn|t |d}d||f}t i ti|i}|iddjot Sn|id|SdS(NsUsing %s for svn_rootsGetting diff from %siiscd %s; svn diff %ss(sosspathsabspaths expandusersnormpathssvn_rootsoptionssverbosesfindsNoneslensrel_pathsdiff_cmdsStringIOspopensreadsdiffsseek(ssvn_rootspathsrel_pathsdiffsdiff_cmd((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pysget_diffs    cCsid|}titi|i}x6|iD](}|i do|i dSq5q5Wt SdS(Nscd %s; svn infosRevisioni( ssvn_rootsinfo_cmdsStringIOsosspopensreadsinfos readlinesslines startswithssplitsNone(ssvn_rootsinfosinfo_cmdsline((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pys get_revisions  sattachment\.cgi\?id=\d*$cCsgi}tiD]'}ti|io||qq~}t|djo dt GHn%t i }t i||t iSdS(Nis)No attachments found for bug %s, quitting(sappends_[1]sstateslinksslslink_patsmatchsurlslens bug_numbersoptionss patch_numberspositionsbrowsers follow_linksget_html(slinkssls_[1]sposition((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pys get_patchs D  cCsVd|}ti|\}}|i||ix|i D] }|GHqCWdS(Nscd %s; patch -up0( spaths patch_cmdsosspopen4sinputsinfoswritespatchscloses readlinessline(spatchspathsinfos patch_cmdsinputsline((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pys apply_patchs    cCsWd|}ti|\}}x-|iD]}|d djotSq,q,Wt SdS(Nscd %s; svn infoisURL:( spathsinfo_cmdsosspopen4sinputsinfos readlinesslinesTruesFalse(spathsinfosinfo_cmdsinputsline((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pysinSVNs   c Csd} td| dt}|id|idtdtdtdtd td t|id d d ddddd|iddd ddddd|iddd ddddd|iddd ddtdddd|iddd ddd |id!d d"dd#d$d%dd&|id'd(d d)dt i d*d+dd,|id-d.dtddd d|id/d0d d1dd2|id3d d dddd4|id5d d dtdd6dd7|i \}} t| d8jod9GHH|iGHtSn| d:at| d8jo| d8and;a|i o|i o t|_nti}|itii|i t}t}t |d1t}x1|i"D]#}|tj o||jo |}q^nw|i$|d<octii|i%|d<}tii'|}tii)|ti*g|jo |}q^n|tj orxj|i+|D]Y\}}|i.o3|d=jod>|d?fGHqd>||fGHnt/|||q{WPqqWt0i1|t0i1|t0i1t |tjot2ti* od@GHH|iGHtSnt}t0i4pt5t0dA o:t6dBt0i7|_8|i8d;jot0i7|_8qnt0i4pt5t0dC ot6dD|_9nt0i4pt5t0d= ot:i:|_;nt0i4pt5t0d< o@ti*} t6dE| |_=|i=d;jo | |_=qWnt0i4pt|i>d:jodF} t6| t0i }|iAd;dGfjot6dHiA} |iC|  o|iD| nxi|i>iED]T\}}|iF| ||tGtii|i dI}|iI||iqWqMnt0i1|dJtt0i8d#dKjot0i8dK7_8ntSdS(LNs(usage: %prog [options] bug [description]susagesversionssubzilla will post a patch from a Subversion tree to a Bugzilla bug, apply a patch from a Bugzilla bug to a Subversion tree, or close the given bug.sverbosesapplyspostsclosespromptsobsoletes-as--applysdestsactions store_trueshelps&apply a patch from bug [default: True]s-ps--posts post the current Subversion diffs-cs--closes close the bugs-ds--use-current-dirs use_currentsdefaults-restrict posted diff to the current directorys-rs--restrict-diffsrestrictsArestrict posteddiff to the given directory or file (overrides -d)s--patch-numbers patch_numberistypesints;which patch should be applied (the default, -1, means last)s-fs--filesini_filesmetavarsFILEs0read configuration from FILE [default: %default]s-vs --verboses-js --projectsprojects,read options from PROJECT in the config files--force-prompts7force prompt to input options and overwrite config files --preserves store_falsesdon't obsolete existing patchesiserror: too few arguments givenisssubversion_rootspasswordsLoading %s as: %ss****s4error: not in a subversion tree and no project givensurls Base Bugzilla URL [default %s]: susernames Username: sSubversion home [%s]: sASave project to %s [y]/n (password will be stored in plaintext)? sysProject name: swsoverrides/(Jsusages OptionParsersversionsparsersset_descriptions set_defaultssFalsesTrues add_optionsdefaultsini_files parse_argsscmdline_optionssargsslens format_helps bug_numbers descriptionsclosespostsapplys ConfigParsersSafeConfigParserscfgsreadsosspaths expandusersOptionss cfg_optionssNones section_usedsgetattrsprojectssectionsssections has_optionsgetsexpandedsnormpathsroots commonprefixsgetcwdsitemsskeysvalsverbosessetattrsoptionssaddsinSVNspromptedspromptshasattrs raw_inputs defaulturlsurlsusernamesgetpassspasswordscurrentssubversion_roots__dict__smsgs should_saveslowers project_names has_sections add_sections iteritemsssetsfilesfswrite(spromptedscfgsparsers section_useds cfg_optionssvals should_savessectionscmdline_optionsscurrentsusages project_namesargssmsgskeysfsrootsexpandedsproject((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pys getOptionss                   %        !      s__main__sAborted(#s__doc__stwillsossStringIOs ConfigParsersgetpasssoptparses OptionParsersresversionsobjectsOptionssdefaults cookie_filesini_files defaulturlsoptionssmainsstartsgetNameslogins close_bugsNonesTrues post_patchsget_diffs get_revisionscompileslink_pats get_patchs apply_patchsinSVNs getOptionss__name__sKeyboardInterrupt(sgetpasss get_revisions getOptionssresgetNamesstartsversionsget_diffsmains OptionParsers apply_patchstwills close_bugsOptionss ConfigParsers get_patchsStringIOsdefaults post_patchsinSVNslink_patsloginsossoptions((s6build/bdist.darwin-8.6.1-i386/egg/subzilla/subzilla.pys?s:        ;        PKb4Ɓ55EGG-INFO/entry_points.txtPKb4%&[[lEGG-INFO/PKG-INFOPKb45= EGG-INFO/requires.txtPKb4_~5EGG-INFO/SOURCES.txtPKb4+E @EGG-INFO/top_level.txtPKb4}EGG-INFO/zip-safePKb4subzilla/__init__.pyPKb4jMX߆subzilla/__init__.pycPKb442%_2_2subzilla/subzilla.pyPKb4qn6n6(9subzilla/subzilla.pycPK o