📄 svn-backup-dumps.py
字号:
def open( self ): self.__compressor = bz2.BZ2Compressor() self.__ofd = open( self.get_filename(), "wb" ) def write( self, data ): self.__ofd.write( self.__compressor.compress( data ) ) def close( self ): self.__ofd.write( self.__compressor.flush() ) self.__ofd.close()class SvnBackupException( Exception ): def __init__( self, errortext ): self.errortext = errortext def __str__( self ): return self.errortextclass SvnBackup: def __init__( self, options, args ): # need 3 args: progname, reposname, dumpdir if len(args) != 3: if len(args) < 3: raise SvnBackupException, \ "too few arguments, specify repospath and dumpdir." else: raise SvnBackupException, \ "too many arguments, specify repospath and dumpdir only." self.__repospath = args[1] self.__dumpdir = args[2] # check repospath rpathparts = os.path.split( self.__repospath ) if len( rpathparts[1] ) == 0: # repospath without trailing slash self.__repospath = rpathparts[0] if not os.path.exists( self.__repospath ): raise SvnBackupException, \ "repos '%s' does not exist." % self.__repospath if not os.path.isdir( self.__repospath ): raise SvnBackupException, \ "repos '%s' is not a directory." % self.__repospath for subdir in [ "db", "conf", "hooks" ]: dir = os.path.join( self.__repospath, "db" ) if not os.path.isdir( dir ): raise SvnBackupException, \ "repos '%s' is not a repository." % self.__repospath rpathparts = os.path.split( self.__repospath ) self.__reposname = rpathparts[1] if self.__reposname in [ "", ".", ".." ]: raise SvnBackupException, \ "couldn't extract repos name from '%s'." % self.__repospath # check dumpdir if not os.path.exists( self.__dumpdir ): raise SvnBackupException, \ "dumpdir '%s' does not exist." % self.__dumpdir elif not os.path.isdir( self.__dumpdir ): raise SvnBackupException, \ "dumpdir '%s' is not a directory." % self.__dumpdir # set options self.__rev_nr = options.rev self.__count = options.cnt self.__quiet = options.quiet self.__deltas = options.deltas self.__zip = options.zip self.__overwrite = False self.__overwrite_all = False if options.overwrite > 0: self.__overwrite = True if options.overwrite > 1: self.__overwrite_all = True self.__transfer = None if options.transfer != None: self.__transfer = options.transfer.split( ":" ) if len( self.__transfer ) != 5: if len( self.__transfer ) < 5: raise SvnBackupException, \ "too few fields for transfer '%s'." % self.__transfer else: raise SvnBackupException, \ "too many fields for transfer '%s'." % self.__transfer if self.__transfer[0] not in [ "ftp", "smb" ]: raise SvnBackupException, \ "unknown transfer method '%s'." % self.__transfer[0] def set_nonblock( self, fileobj ): fd = fileobj.fileno() n = fcntl.fcntl( fd, fcntl.F_GETFL ) fcntl.fcntl( fd, fcntl.F_SETFL, n|os.O_NONBLOCK ) def exec_cmd( self, cmd, output=None, printerr=False ): try: proc = Popen( cmd, stdout=PIPE, stderr=PIPE, shell=False ) except: return ( 256, "", "Popen failed (%s ...):\n %s" % ( cmd[0], str(sys.exc_info()[1]) ) ) stdout = proc.stdout stderr = proc.stderr self.set_nonblock( stdout ) self.set_nonblock( stderr ) readfds = [ stdout, stderr ] selres = select.select( readfds, [], [] ) bufout = "" buferr = "" while len( selres[0] ) > 0: for fd in selres[0]: buf = fd.read( 16384 ) if len( buf ) == 0: readfds.remove( fd ) elif fd == stdout: if output: output.write( buf ) else: bufout += buf else: if printerr: print buf, else: buferr += buf if len( readfds ) == 0: break selres = select.select( readfds, [], [] ) rc = proc.wait() if printerr: print "" return ( rc, bufout, buferr ) def get_head_rev( self ): cmd = [ "svnlook", "youngest", self.__repospath ] r = self.exec_cmd( cmd ) if r[0] == 0 and len( r[2] ) == 0: return int( r[1].strip() ) else: print r[2] return -1 def transfer_ftp( self, absfilename, filename ): rc = False try: host = self.__transfer[1] user = self.__transfer[2] passwd = self.__transfer[3] destdir = self.__transfer[4].replace( "%r", self.__reposname ) ftp = FTP( host, user, passwd ) ftp.cwd( destdir ) ifd = open( absfilename, "rb" ) ftp.storbinary( "STOR %s" % filename, ifd ) ftp.quit() rc = len( ifd.read(1) ) == 0 ifd.close() except Exception, e: raise SvnBackupException, \ "ftp transfer failed:\n file: '%s'\n error: %s" % \ ( absfilename, str(e) ) return rc def transfer_smb( self, absfilename, filename ): share = self.__transfer[1] user = self.__transfer[2] passwd = self.__transfer[3] if passwd == "": passwd = "-N" destdir = self.__transfer[4].replace( "%r", self.__reposname ) cmd = ( "smbclient", share, "-U", user, passwd, "-D", destdir, "-c", "put %s %s" % ( absfilename, filename ) ) r = self.exec_cmd( cmd ) rc = r[0] == 0 if not rc: print r[2] return rc def transfer( self, absfilename, filename ): if self.__transfer == None: return elif self.__transfer[0] == "ftp": self.transfer_ftp( absfilename, filename ) elif self.__transfer[0] == "smb": self.transfer_smb( absfilename, filename ) else: print "unknown transfer method '%s'." % self.__transfer[0] def create_dump( self, checkonly, overwrite, fromrev, torev=None ): revparam = "%d" % fromrev r = "%06d" % fromrev if torev != None: revparam += ":%d" % torev r += "-%06d" % torev filename = "%s.%s.svndmp" % ( self.__reposname, r ) absfilename = "%s/%s" % ( self.__dumpdir, filename ) output = None if self.__zip: if self.__zip == "gzip": output = SvnBackupOutputGzip( absfilename ) else: output = SvnBackupOutputBzip2( absfilename ) else: output = SvnBackupOutputPlain( absfilename ) realfilename = output.get_filename() if checkonly: return os.path.exists( realfilename ) elif os.path.exists( realfilename ): if overwrite: print "overwriting " + realfilename else: print "%s already exists." % realfilename return True else: print "writing " + realfilename cmd = [ "svnadmin", "dump", "--incremental", "-r", revparam, self.__repospath ] if self.__quiet: cmd[2:2] = [ "-q" ] if self.__deltas: cmd[2:2] = [ "--deltas" ] output.open() r = self.exec_cmd( cmd, output, True ) output.close() rc = r[0] == 0 if rc: self.transfer( output.get_filename(), filename ) return rc def export_single_rev( self ): return self.create_dump( False, self.__overwrite, self.__rev_nr ) def export( self ): headrev = self.get_head_rev() if headrev == -1: return False if self.__count is None: return self.create_dump( False, self.__overwrite, 0, headrev ) baserev = headrev - ( headrev % self.__count ) rc = True cnt = self.__count fromrev = baserev - cnt torev = baserev - 1 while fromrev >= 0 and rc: if self.__overwrite_all or \ not self.create_dump( True, False, fromrev, torev ): rc = self.create_dump( False, self.__overwrite_all, fromrev, torev ) fromrev -= cnt torev -= cnt else: fromrev = -1 if rc: rc = self.create_dump( False, self.__overwrite, baserev, headrev ) return rc def execute( self ): if self.__rev_nr != None: return self.export_single_rev() else: return self.export()if __name__ == "__main__": usage = "usage: svnbackup.py [options] repospath dumpdir" parser = OptionParser( usage=usage, version="%prog "+__version ) if have_bz2: parser.add_option( "-b", action="store_const", const="bzip2", dest="zip", default=None, help="compress the dump using bzip2." ) parser.add_option( "--deltas", action="store_true", dest="deltas", default=False, help="pass --deltas to svnadmin dump." ) parser.add_option( "-c", action="store", type="int", dest="cnt", default=None, help="count of revisions per dumpfile." ) parser.add_option( "-o", action="store_const", const=1, dest="overwrite", default=0, help="overwrite files." ) parser.add_option( "-O", action="store_const", const=2, dest="overwrite", default=0, help="overwrite all files." ) parser.add_option( "-q", action="store_true", dest="quiet", default=False, help="quiet." ) parser.add_option( "-r", action="store", type="int", dest="rev", default=None, help="revision number for single rev dump." ) parser.add_option( "-t", action="store", type="string", dest="transfer", default=None, help="transfer dumps to another machine "+ "(s.a. --help-transfer)." ) parser.add_option( "-z", action="store_const", const="gzip", dest="zip", help="compress the dump using gzip." ) parser.add_option( "--help-transfer", action="store_true", dest="help_transfer", default=False, help="shows detailed help for the transfer option." ) (options, args) = parser.parse_args( sys.argv ) if options.help_transfer: print "Transfer help:" print "" print " FTP:" print " -t ftp:<host>:<user>:<password>:<dest-path>" print "" print " SMB (using smbclient):" print " -t smb:<share>:<user>:<password>:<dest-path>" print "" sys.exit( 0 ) rc = False try: backup = SvnBackup( options, args ) rc = backup.execute() except SvnBackupException, e: print "svn-backup-dumps.py:", e if rc: print "Everything OK." sys.exit( 0 ) else: print "An error occured!" sys.exit( 1 )# vim:et:ts=4:sw=4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -