由于是刚接触python不久,所以很多都不是很熟练,只能是用到什么查点什么。所以如果有什么bug或者不严谨的语法或其他,希望各位看客指正。

鉴于公司的平台研发部门需求想直接把svn中的差异代码导出并打包自动上传到指定的服务器上,然后在从指定的服务器上进行一个发布更新。由于我们开发和发布服务器的环境很特殊,中间牵扯到很多网络代理。所以才这么麻烦。

要求如下:

1、自动导出指定版本之间的差异文件

2、根据给定的选项过滤出指定的文件夹以及文件;例如给定选项 a ,那就导出的文件中只保留admin的内容

3、自动打包这些内容并按照当前的时间命名

4、以FTP模式上传到指定的服务器


主要还是在windows下操作这些,实在想不出什么好的方法,于是网络搜索求助。网络真是个神奇的东西,当然我还是没有搜到任何结果。于是加了一些脚本的群,随机的找一个管理员问下有没有相关的脚本或思路。真是天无绝人之路。第一个请教的哥们就给了我一个回答。python可以搞定(当然给的指导肯定不止这些)。

于是当下又在学习python,顺便就用这个来实现(其实是不知道用什么来操作的)


在多次google、baidu之后。写了以下的脚本,目前测试是能满足基本需求的:

python的环境需求:py32-pysvn, python-3.2

pysvn下载官网:http://pysvn.tigris.org/

python的官网就不用提供了吧。

使用方法:

    在windows下dos里切换到脚本存放目录,然后使用脚本内给的用法进行脚本导出。导出的文件夹是相对脚本存放路径来的。

下面贴出代码:

#-*- coding: utf-8 -*-
#!/usr/bin/env python

# ====================================================================
#
# svnchanged_export.py
#
# Export Files in a revision Range
# Usage: python SCRIPT_NAME.py -r beginRev:endRev [ --username user --password passwd ] svnurl site_version(a | s | p)
# site_version: a [admin] s [static] p [platform]
#
# ====================================================================

import pysvn # http://pysvn.tigris.org/
import getopt, time, string, sys, shutil
import os, urllib, tarfile, getpass
import unicodedata
from urllib.parse import urlparse
from ftplib import FTP

# Options by default
date_folder=time.strftime(r"%Y%m%d%H%M%S", time.localtime())
#site_version="p"
#targetPath = "." 	# Current directory
export_dir="xxxx"	# Change into a folder you want to export, The store path relative to the script
username = ""
password = ""
url = ""
ftp_host="xxx.xxx.xxx.xxx"
ftp_port=xxx
ftp_user='xxxx'
ftp_pass='xxxx'

revision_min = pysvn.Revision( pysvn.opt_revision_kind.number, 0 )
revision_max = pysvn.Revision( pysvn.opt_revision_kind.head )
hasRevision = False

current_dir = os.getcwd()
os.chdir(r'%s/%s' %(os.getcwd(),export_dir))
os.makedirs(r'%s' %(date_folder))
os.chdir('../')
targetPath=(r"%s\%s") % (export_dir,date_folder)

try:
    optlist, args = getopt.getopt (sys.argv[1:], "r:u:p:",
                                   ["revision=", "username=", "password="])
    if len(args) == 1 or len(args) == 2:
        url = args[0]
        if len(args) == 2:
            #targetPath = args[1]
            site_version = args[1]
    else:
        raise Exception ("Input URL [site_version]")
        
    for option, value in optlist:
        if option == "--username" or option == "-u":
            username = value            
        elif option == "--password" or option == "-p":
            password = value
        elif option == "--revision" or option == "-r":
            revision = value
            if str.find(value, ":") >= 0:
                (revision_min0, revision_max0) = str.split(value, ":")
                revision_min = pysvn.Revision( pysvn.opt_revision_kind.number, int(revision_min0) )
                if revision_max0 != "HEAD":
                    revision_max = pysvn.Revision( pysvn.opt_revision_kind.number, int(revision_max0) )
                hasRevision = True
            else:
                raise Exception ("Please Input revision range " + str(option))
        else:
            raise Exception ("Unknown option " + str(option))
            
    if hasRevision == False:
        raise Exception ("Please Input Revision Range -r min:max")
        
    #urlObject = urlparse(url)
    #if urlObject.scheme == 'http' or urlObject.scheme == 'https':
    #    url = urlObject.scheme+"://"+urlObject.netloc+urllib.quote(urlObject.path.decode(sys.stdin.encoding).encode('utf8'))
    #else:
        #url = unicode(url, sys.stdin.encoding)
    #print (sys.stdin.encoding)
    # print(url)
    if not url.endswith("/"):
        url = url + "/"        
        
except getopt.error as reason:
 raise Exception("Usage: " + sys.argv[0] + ": " + str(reason))

f_list=[]
f_list=os.listdir(targetPath)
 
for f in f_list:
    f_path=os.path.join(targetPath, f)
    if os.path.isfile(f_path):
        os.remove(f_path)
        print (f_path+" removed.")
    else:
        shutil.rmtree(f_path)
        print (f_path+ " removed.")

print (targetPath+" is already empty.")
    

def get_login(realm,user,may_save):
    return True, username, password, False
   
print ("SVN Path:"+url+'   '+"Diff file path:"+targetPath)

client = pysvn.Client()
if username != "" and password != "":
    client.callback_get_login = get_login

summary = client.diff_summarize(url, revision_min, url, revision_max)
#print summary
for changed in summary:
    #path, summarize_kind, node_kind, prop_changed
    #for key in changed.iterkeys():
    #    print key 
    
    if pysvn.diff_summarize_kind.delete == changed['summarize_kind']:
      fullPath = targetPath+"/"+changed['path']   
      if os.path.exists(fullPath):
        os.remove(fullPath)
    
    if pysvn.diff_summarize_kind.added == changed['summarize_kind'] or pysvn.diff_summarize_kind.modified == changed['summarize_kind']:
        print (changed['summarize_kind'], changed['path'])

        if changed['node_kind'] == pysvn.node_kind.file:
            
            #uniPath = changed['path'].decode('utf8').encode()
            file_text = client.cat(url+urllib.parse.quote(changed['path'].encode('utf8')), revision_max)
            
            fullPath = targetPath+"/"+changed['path']    
            dirPath = fullPath[0:fullPath.rfind("/")]
            if not os.path.exists(dirPath):
                os.makedirs(dirPath)
                        
            f = open(fullPath,'wb')
            f.write(file_text)
            f.close
	    #f = open(fullPath,'wb')
	    #f.write(file_text)
            #f.close

#f_tar="./"+os.path.basename(targetPath)+".tar"
#if os.path.exists(f_tar):
#    os.remove(f_tar)
#    print (os.path.basename(f_tar)+" is removed.")
#else:
#    print (os.path.basename(f_tar)+" is not exists.")


# Folder filter regulation
os.chdir((r"%s") % targetPath)
p_list = a_list = s_list = os.listdir(os.getcwd())
p_outer_list = list(filter(lambda x:x != "website" and x != "framework", p_list))
a_outer_list = list(filter(lambda x:x != "website" and x != "framework" and x != "service", a_list))
s_outer_list = list(filter(lambda x:x != "website", s_list))

os.chdir((r"%s\website") % targetPath)
p_inner_list = a_inner_list = s_inner_list = os.listdir(os.getcwd())
p_inner_list = list(filter(lambda x:x != "platform", p_inner_list))
a_inner_list = list(filter(lambda x:x != "admin" and x != "union", a_inner_list))
s_inner_list = list(filter(lambda x:x != "static", s_inner_list))


def inner_filter(list_op):
    for i in list_op:
        shutil.rmtree((r"%s\website\%s") % (targetPath,i))
    os.chdir((r"%s") % t_path)
    print (os.listdir(os.getcwd()))

def filter_site(site_op):
    if site_version == "p":
        for p_o in p_outer_list:
            shutil.rmtree((r"%s\%s") % (targetPath,p_o))
        inner_filter(p_inner_list)

    elif site_version == "a":
        for a_o in a_outer_list:
            shutil.rmtree((r"%s\%s") % (targetPath,a_o))
        inner_filter(a_inner_list)

    elif site_version == "s":
        for s_o in s_outer_list:
            shutil.rmtree((r"%s\%s") % (targetPath,s_o))
        inner_filter(s_inner_list)

    else:
        raise Exception (("Unknown site_option: %s") % site_op)

filter_site(site_version)


print (("export file: %s_%s"+'.tar') % (site_version,date_folder))			

def make_tar(folder_to_tar,dst_folder):
    fold_name = os.path.basename(folder_to_tar)
    dst_name = "%s_%s.tar" %(site_version,fold_name)
    dst_path = os.path.join(dst_folder, dst_name)	
    tar = tarfile.TarFile.open(dst_path, 'w')
    tar.add(folder_to_tar, fold_name)
    tar.close()
    return dst_path
	
dst_file = make_tar(targetPath,'./')
# print (dst_file)

def upload_file(localfile):
    ftp=FTP()
    ftp.connect(ftp_host,ftp_port)
    ftp.login(ftp_user,ftp_pass)
    ftp.cwd('./')
    file=open(localfile,'rb')
    ftp.storbinary('STOR %s' % os.path.basename(localfile),file)
    ftp.retrlines('LIST')
    file.close()
    ftp.close()
    ftp.quit

upload_file(dst_file)
print ('File Upload Successful.')


代码就是如上这么多,中间肯定有很多语法的不严谨和bug,大家多多指正。如有需要的可以直接拿去对应的改改基本上也是可以用的。