在一次需求开发中,需要在python3的环境下,操作SVN,在SVN仓库上实现如下操作:创建SVN目录、拉取SVN文件内容、将文件推送到SVN仓库。
经过不断的探索尝试,最终实现了这些功能,这里将这些功能实现记录下来。
关于python3在linux环境下的安装,可以参考:在Linux系统上安装Python3。
下载安装svn相关python库:https://pypi.org/
根据python版本选择合适的whl库
安装完之后测试:
$ python3
>>> import stat,os,shutil,time,platform
>>> import svn, svn.remote
# 如果SVN仓库上的子目录不存在,就创建出来
def createSubDirOnSVNReportIfNotExists(svn_base_url, svn_username, svn_password, subDir):
subDirs = subDir.split("/")
createDirFlag = False
current_svn_base_url = svn_base_url
for oneSubDir in subDirs:
svnClient = svn.remote.RemoteClient(current_svn_base_url,username=svn_username, password=svn_password)
current_svn_base_url += "/" + oneSubDir
# 查询svn当前目录下的所有子目录
subAll = svnClient.list()
findFlag = False
for subName in subAll:
if oneSubDir in subName:
findFlag=True
break
if not findFlag:
createDirFlag = True
break
# 子目录不存在,创建子目录
if createDirFlag:
svnClient = svn.remote.RemoteClient(svn_base_url, username=svn_username, password=svn_password)
# 执行创建SVN 子目录的命令
svn_sub_command = 'mkdir'
command_args = ["--parents", "-m", "python程序创建svn子目录:"+subDir, str(svn_base_url+"/"+subDir).replace(' ', '%20')]
svnClient.run_command(svn_sub_command, command_args)
return svn_base_url+"/"+subDir
# 判断本地文件是否存在
def isFileAndExists(filePath):
if os.path.exists(filePath) and os.path.isfile(filePath):
return True
else:
return False
# 执行提交操作
def commitSVNReportFile(svnUrl, target_localfilePath, svn_username, svn_password):
# 如果本地文件不存在,就不用提交了
if not isFileAndExists(target_localfilePath):
raise Exception('要向SVN仓库提交的本地文件不存在');
# 提交SVN报告
svnUrl = svnUrl.replace(' ', '%20')
svnClient = svn.remote.RemoteClient(svnUrl, username=svn_username, password=svn_password)
# 先执行add操作
svn_sub_command_add = 'add'
command_args_add = ["--force", target_localfilePath]
svnClient.run_command(svn_sub_command_add, command_args_add)
# 再执行commit操作
svn_sub_command_commit = 'commit'
command_args_commit = [target_localfilePath, '-m', 'python3程序提交文件:'+os.path.split(target_localfilePath)[-1]]
svnClient.run_command(svn_sub_command_commit, command_args_commit)
# 如果目录不存在就创建目录
def createDirIfNotExists(dirPath):
if not os.path.exists(dirPath) or not os.path.isdir(dirPath):
os.makedirs(dirPath)
# checkout svn 文件
def checkoutSVNFile(local_base_dir, svn_base_url, svn_username, svn_password, svn_subdir):
# 在本地创建一个SVN临时目录
svn_local_temp_dir = os.path.join(local_base_dir, 'svn_reports', str(int(time.time())))
# 创建目录
createDirIfNotExists(svn_local_temp_dir)
# 在svn上创建子目录,如果子目录不存在
svnUrl = createSubDirOnSVNReportIfNotExists(svn_base_url, svn_username, svn_password, svn_subdir)
svnUrl = svnUrl.replace(' ', '%20')
# 将目录checkout下来
svnClient = svn.remote.RemoteClient(svnUrl, username=svn_username, password=svn_password)
svnClient.checkout(svn_local_temp_dir)
return svn_local_temp_dir
# 递归删除
def deleteDirsRecursion(dirPath):
if not isDirAndExists(dirPath):
return
if platform.system().lower()=='windows':
shutil.rmtree(dirPath, onerror=remove_readonly)
else:
shutil.rmtree(dirPath)
# 解决: shutil.rmtree 在Windows 上删除只读文件报错问题
def remove_readonly(func, path, _):
os.chmod(path, stat.S_IWRITE)
func(path)
# 更新svn仓库的文件
def updateSVNFile(update_filepath, svn_subdir, svn_base_url, svn_username, svn_password):
if not isFileAndExists(update_filepath):
raise Exception('要更新的SVN文件不存在: %s' % update_filepath)
# 在本地创建一个SVN临时目录
svn_local_temp_dir = os.path.join(local_base_dir, 'svn_reports', str(int(time.time())))
# 创建目录
createDirIfNotExists(svn_local_temp_dir)
# 在svn上创建子目录,如果子目录不存在
svnUrl = createSubDirOnSVNReportIfNotExists(svn_base_url, svn_username, svn_password, svn_subdir)
svnUrl = svnUrl.replace(' ', '%20')
# 将目录checkout下来
svnClient = svn.remote.RemoteClient(svnUrl, username=svn_username, password=svn_password)
svnClient.checkout(svn_local_temp_dir)
# 获取要更新的文件名
target_localfilePath = os.path.join(svn_local_temp_dir, os.path.split(update_filepath)[-1])
# 拷贝文件内容
shutil.copyfile(update_filepath, target_localfilePath)
# 向SVN仓库提交文件
commitSVNReportFile(svnUrl, target_localfilePath, svn_username, svn_password)
# sleep
time.sleep(3)
# 删除临时目录
deleteDirsRecursion(svn_local_temp_dir)