📄 granny.cgi
字号:
#!/usr/bin/python# -*- Mode: python -*-"""Granny.py - display CVS annotations in HTMLwith lines colored by code age in days.Original Perl version by J. Gabriel Foster (gabe@sgrail.com) Posted to info-cvs on 02/27/1997 You can still get the original shell archive here: http://www.geocrawler.com/archives/3/382/1997/2/0/2103824/Perl modifications for NT by Marc Paquette (marcpa@cam.org)Python port and CGI modifications by Brian Lenihan (brianl@real.com) From the original granny.pl README:--What is Granny? Why do I care? Granny is a tool for viewing cvs annotation information graphically. Using Netscape, granny indicates the age of lines by color. Red lines are new, blue lines are old. This information can be very useful in determining what lines are 'hot'. New lines are more likely to contain bugs, and this is an easy way to visualize that information. Requirements: Netscape (version 2.0 or better) Perl5 CVS 1.9 (1.8 should work, but I have not tried it.) Installation: Put granny somewhere in your path. You may need to edit the first line to point to your perl5 binary and libraries. What to do: Run granny just like you would 'cvs annotate' for a single file. granny thefile.C To find out who is to blame for that new 'feature'. granny -U thefile.C For all your options: granny -h Questions, Comments, Assertions? send e-mail to the author: Gabe Foster (gabe@sgrail.com) Notes: I'm not the first person to try this sort of display, I just read about it in a magazine somewhere and decided that cvs had all the information I needed. To whomever first had this idea, it's a great one. Granny is free, please use it as you see fit. I give no warranties. As a courtesy, I ask that you tell me about any modifications you have made, and also ask that you acknowledge my work if you use Granny in your own software.--Granny.py:granny.py [-h][-d days][-i input][-o output][-DUV] file-h: Get this help display.-i: Specify the input file. (Use - for stdin.)-o: Specify the output file. (Use - for stdout.)-d: Specify the day range for the coloring.\n-r: Specify the cvs revision of the file.-D: Display the date the line was last edited.-U Display the user that last edited the line.-V: Display the version the line was last edited.By default, granny.py executes cvs annotate on a FILE andruns netscape to display the graphic.It is assumed that cvs and Netscape (for command line version) arein your path.If granny.py is placed in the cgi-bin directory of your Webserver, it will act as a CGI script. The working directorydefaults to /usr/tmp, but it can be overridden in the classconstructor: A = CGIAnnotate(tempdir='/tmp')Required fields:root The full path to the cvs root directory.Name The module/filename of the annotated file.Optional fields:rev The cvs revision number to use. (default HEAD).Set the following fields to display extra info:showUser Display the user that last edited the line.showVersion Display version that the line was last edited in.showDate Display the date the line was last edited.http://yourserver.yourdomain.com/cgi-bin/granny.py?root=/cvsroot&Name=module/fileTODO:Add support for determining the MIME type of files and/or a binary check. - easily done by parsing Apache (mime.conf) or Roxen (extensions) MIME files.Consider adding buttons to HTML for optional display fields.Add support for launching other browsers."""import osimport sysimport stringimport reimport timeimport getoptimport cStringIOimport tempfileimport tracebackmonth_num = { 'Jan' : 1, 'Feb' : 2, 'Mar' : 3, 'Apr' : 4, 'May' : 5, 'Jun' : 6, 'Jul' : 7, 'Aug' : 8, 'Sep' : 9, 'Oct' : 10, 'Nov' : 11, 'Dec' : 12}class Annotate: def __init__(self): self.day_range = 365 self.counter = 0 self.color_table = {} self.user = {} self.version = {} self.rtime = {} self.source = {} self.tmp = None self.tmpfile = None self.revision = '' self.showUser = 0 self.showDate = 0 self.showVersion = 0 self.set_today() def run(self): try: self.process_args() self.parse_raw_annotated_file() self.write_annotated_html_file() if self.tmp: self.display_annotated_html_file() finally: if sys.exc_info()[0] is not None: traceback.print_exc() self.cleanup() def cleanup(self): if self.tmp: self.tmp.close() os.unlink(self.tmpfile) sys.exit(0) def getoutput(self, cmd): """ Get stdin and stderr from cmd and return exit status and captured output """ if os.name == 'nt': # os.popen is broken on win32, but seems to work so far... pipe = os.popen('%s 2>&1' % cmd, 'r') else: pipe = os.popen('{ %s ; } 2>&1' % cmd, 'r') text = pipe.read() sts = pipe.close() if sts == None: sts = 0 if text[:-1] == '\n': text = text[-1:] return sts, text def set_today(self): """ compute the start of this day """ (year,mon,day,hour,min,sec,dow,doy,dst) = time.gmtime(time.time()) self.today = time.mktime((year,mon,day,0,0,0,0,0,0)) def get_today(self): return self.today # entify stuff which breaks HTML display # this was lifted from some Zope Code in # StructuredText.py # # XXX try it with string.replace and run it in the profiler def html_quote(self,v, character_entities=((re.compile('&'), '&'), (re.compile("<"), '<' ), (re.compile(">"), '>' ), (re.compile('"'), '"'))): gsub = re.sub text=str(v) for regexp,name in character_entities: text=gsub(regexp,name,text) return text def display_annotated_html_file(self): if os.name == 'nt': path = '"C:\\Program Files\\Netscape\\Communicator'\ '\\Program\\Netscape"' if os.system('%s %s' % (path, self.tmpfile)) != 0: sys.stderr.write('%s: Unable to start Netscape' % sys.argv[0]) sys.exit(1) else: if os.system('netscape -remote openFile\(%s\)' % self.tmpfile) != 0: sys.stderr.write('%s: Trying to run netscape, please wait\n' % sys.argv[0]) if os.system('netscape &') == 0: for i in range(10): time.sleep(1) if os.system('netscape -remote openFile\(%s\)' % self.tmpfile) == 0: break if i == 10: sys.stderr.write('%s:Unable to start netscape\n' % sys.argv[0]) else: sys.stderr.write('%s:Unable to start netscape\n' % sys.argv[0]) # give Netscape time to read the file # XXX big files may raise an OSError exception on NT # if the sleep is too short. time.sleep(5) def get_opts(self): opt_dict = {} if not len(sys.argv[1:]) > 0: self.usage() opts, args = getopt.getopt(sys.argv[1:], 'DUVhi:o:d:r:') for k,v in opts: opt_dict[k] = v return opt_dict def process_args(self):
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -