备受折腾的一次相关svn的文件提交
话题:提交Jenkins编译结果到svn
具体描述:Jenkins创建的是流水线任务,Jenkins所在服务器没有资源并且不能联网通过yum install subversion -y 安装svn,下载离线svn安装包,安装失败
题记:分析可得3中处理方式
第一话:java代码实现——想通过打成jar包执行,从Linux服务器提交文件到svn
import java.io.*; import org.tmatesoft.svn.core.SVNCommitInfo; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory; import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory; import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl; import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.SVNRepositoryFactory; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNUpdateClient; import org.tmatesoft.svn.core.wc.SVNWCUtil; public class SvnDeal { private SVNClientManager clientManager; private ISVNAuthenticationManager authManager; private SVNRepository repository; /** * * @param svnUrl svn地址 * @param svnUsername svn用户名称 * @param svnPasswd svn用户密码 * @throws SVNException 异常信息 */ public SvnDeal(String svnUrl, String svnUsername, String svnPasswd)throws SVNException{ try { this.createDefaultAuthenticationManager(svnUsername, svnPasswd); this.authSvn(svnUrl); } catch (SVNException e) { throw new RuntimeException(e.getMessage()); } } /** * 通过不同的协议初始化版本库 */ private void setupLibrary() { DAVRepositoryFactory.setup(); SVNRepositoryFactoryImpl.setup(); FSRepositoryFactory.setup(); } /** * * @param username svn用户名称 * @param password svn用户密码 * @throws SVNException 异常信息 */ private void createDefaultAuthenticationManager(String username, String password)throws SVNException{ try { // 身份验证 authManager = SVNWCUtil.createDefaultAuthenticationManager(username, password); } catch (Exception e) { throw new RuntimeException("SVN身份认证失败:" + e.getMessage()); } } /** * 验证登录svn * @param svnUrl 用户svn的仓库地址 * @throws SVNException 异常信息 */ private void authSvn(String svnUrl) throws SVNException { // 初始化版本库 setupLibrary(); try { repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(svnUrl)); } catch (SVNException e) { throw new RuntimeException("SVN创建库连接失败:" + e.getMessage()); } // 创建身份验证管理器 repository.setAuthenticationManager(authManager); DefaultSVNOptions options = SVNWCUtil.createDefaultOptions(true); try { //创建SVN实例管理器 clientManager = SVNClientManager.newInstance(options,authManager); } catch (Exception e) { throw new RuntimeException("SVN实例管理器创建失败:" + e.getMessage()); } } /** * 添加文件和目录到版本控制下 * @param wcPath 工作区路径 * @throws SVNException 异常信息 */ private void addEntry(File wcPath) throws SVNException{ try { clientManager.getWCClient().doAdd(new File[] { wcPath }, true, false, false, SVNDepth.INFINITY, false, false, true); } catch (SVNException e) { throw new RuntimeException("SVN添加文件到版本控制下失败:" + e.getMessage()); } } /** * 将工作副本提交到svn * @param wcPath 被提交的工作区路径 * @param keepLocks 是否在SVN仓库中打开或不打开文件 * @param commitMessage 提交信息 * @return 返回信息 * @throws SVNException 异常信息 */ private SVNCommitInfo commit(File wcPath, boolean keepLocks, String commitMessage) throws SVNException { try { System.out.println("wcPath:" + wcPath + "\ncommitMessage:" + commitMessage + "\nSVNDepth.INFINITY:" + SVNDepth.INFINITY); return clientManager.getCommitClient().doCommit( new File[] { wcPath }, keepLocks, commitMessage, null, null, false, false, SVNDepth.INFINITY); } catch (SVNException e) { throw new RuntimeException("SVN提交失败:" + e.getMessage()); } } /** * 确定path是否是一个工作空间 * @param path 文件路径 * @return 返回信息 * @throws SVNException 异常信息 */ private boolean isWorkingCopy(File path) throws SVNException{ if(!path.exists()){ return false; } try { if(null == SVNWCUtil.getWorkingCopyRoot(path, false)){ return false; } } catch (SVNException e) { throw new RuntimeException("确定path是否是一个工作空间 失败:" + e.getMessage()); } return true; } /** * 确定一个URL在SVN上是否存在 * @param url svn访问地址 * @return 返回信息 * @throws SVNException 异常信息 */ private boolean isURLExist(SVNURL url) throws SVNException{ try { SVNRepository svnRepository = SVNRepositoryFactory.create(url); svnRepository.setAuthenticationManager(authManager); SVNNodeKind nodeKind = svnRepository.checkPath("", -1); return nodeKind == SVNNodeKind.NONE ? false : true; } catch (SVNException e) { throw new RuntimeException("确定一个URL在SVN上是否存在失败:" + e.getMessage()); } } /** * 递归检查不在版本控制的文件,并add到svn * @param wc 检查的文件 * @throws SVNException 异常信息 */ private void checkVersiondDirectory(File wc) throws SVNException{ if(!SVNWCUtil.isVersionedDirectory(wc)){ this.addEntry(wc); } if(wc.isDirectory()){ for(File sub:wc.listFiles()){ if(sub.isDirectory() && sub.getName().equals(".svn")){ continue; } checkVersiondDirectory(sub); } } } /** * 删除目录(文件夹)以及目录下的文件 * @param sPath 被删除目录的文件 * @return 目录删除成功返回true,否则返回false */ private boolean deleteDirectory(String sPath) { //如果sPath不以文件分隔符结尾,自动添加文件分隔符 if (!sPath.endsWith(File.separator)) { sPath = sPath + File.separator; } File dirFile = new File(sPath); //如果dir对应的文件不存在,或者不是一个目录,则退出 if (!dirFile.exists() || !dirFile.isDirectory()) { return false; } boolean flag = true; //删除文件夹下的所有文件(包括子目录) File[] files = dirFile.listFiles(); for (int i = 0; i < files.length; i++) { //删除子文件 if (files[i].isFile()) { flag = deleteFile(files[i].getAbsolutePath()); if (!flag) break; } //删除子目录 else { flag = deleteDirectory(files[i].getAbsolutePath()); if (!flag) break; } } if (!flag) return false; //删除当前目录 if (dirFile.delete()) { return true; } else { return false; } } /** * 删除单个文件 * @param sPath 被删除文件的文件 * @return 单个文件删除成功返回true,否则返回false */ private boolean deleteFile(String sPath) { boolean flag = false; File file = new File(sPath); // 路径为文件且不为空则进行删除 if (file.isFile() && file.exists()) { file.delete(); flag = true; } return flag; } /** * 根据路径删除指定的目录或文件,无论存在与否 *@param sPath 要删除的目录或文件 *@return 删除成功返回 true,否则返回 false。 */ @SuppressWarnings("unused") private boolean DeleteFolder(String sPath) { boolean flag = false; File file = new File(sPath); // 判断目录或文件是否存在 if (!file.exists()) { // 不存在返回 false return flag; } else { // 判断是否为文件 if (file.isFile()) { // 为文件时调用删除文件方法 return deleteFile(file.getAbsolutePath()); } else { // 为目录时调用删除目录方法 return deleteDirectory(file.getAbsolutePath()); } } } /** * 更新SVN工作区 * @param wcPath 工作区路径 * @param updateToRevision 更新版本 * @param depth update的深度:目录、子目录、文件 * @return 返回信息 * @throws SVNException 异常信息 */ private long update(File wcPath,SVNRevision updateToRevision, SVNDepth depth) throws SVNException{ SVNUpdateClient updateClient = clientManager.getUpdateClient(); updateClient.setIgnoreExternals(false); try { return updateClient.doUpdate(wcPath, updateToRevision,depth, false, false); } catch (SVNException e) { throw new RuntimeException("更新SVN工作区失败:" + e.getMessage()); } } /** * SVN仓库文件检出 * @param url 文件url * @param revision 检出版本 * @param destPath 目标路径 * @param depth checkout的深度,目录、子目录、文件 * @return 返回信息 * @throws SVNException 异常信息 */ private long checkout(SVNURL url, SVNRevision revision, File destPath, SVNDepth depth) throws SVNException{ SVNUpdateClient updateClient = clientManager.getUpdateClient(); updateClient.setIgnoreExternals(false); try { return updateClient.doCheckout(url, destPath, revision, revision,depth, false); } catch (SVNException e) { throw new RuntimeException("检出SVN仓库失败:" + e.getMessage()); } } /** * @param svnUrl svn地址 * @param workspace 工作区 * @param filepath 上传的文件地址 * @param filename 文件名称 * @throws SVNException 异常信息 */ private void checkWorkCopy(String svnUrl,String workspace,String filepath,String filename)throws SVNException{ SVNURL repositoryURL = null; try { repositoryURL = SVNURL.parseURIEncoded(svnUrl); } catch (SVNException e) { throw new RuntimeException("解析svnUrl失败:" + e.getMessage()); } String fPath = ""; if(filepath.indexOf("/") != -1) { fPath = filepath.substring(0,filepath.lastIndexOf("/")); } File wc = new File(workspace+"/"+fPath); File wc_project = new File( workspace + "/" + fPath); SVNURL projectURL = null; try { projectURL = repositoryURL.appendPath(filename, false); } catch (SVNException e) { throw new RuntimeException("解析svnUrl文件失败:" + e.getMessage()); } if(!this.isWorkingCopy(wc)){ if(!this.isURLExist(projectURL)){ this.checkout(repositoryURL, SVNRevision.HEAD, wc, SVNDepth.EMPTY); }else{ this.checkout(projectURL, SVNRevision.HEAD, wc_project, SVNDepth.INFINITY); } }else{ this.update(wc, SVNRevision.HEAD, SVNDepth.INFINITY); } } /** * 循环删除.svn目录 * @param spath */ private void deletePointSVN(String spath){ File wc = new File(spath); for(File sub:wc.listFiles()){ if(sub.isDirectory() && sub.getName().equals(".svn")){ this.deleteDirectory(sub.getAbsolutePath()); continue; } if(sub.isDirectory()){ deletePointSVN(sub.getAbsolutePath()); } } } /** * * @param svnUrl svn地址 * @param workspace 工作区 * @param filepath 上传的文件地址 * @param filename 上传的文件名称 * @param isOverwrite 是否覆盖 * @throws SVNException 异常信息 */ @SuppressWarnings("deprecation") public void upload(String svnUrl,String workspace,String filepath,String filename,Boolean isOverwrite)throws SVNException{ String svnfilePath = svnUrl+"/"+filename; //开始前删除以前的.svn文件目录 deletePointSVN(workspace); boolean flag = this.isURLExist(SVNURL.parseURIDecoded(svnfilePath)); if(flag){ if(isOverwrite){ this.uploadFile(svnUrl, workspace, filepath,filename); } }else{ this.uploadFile(svnUrl, workspace, filepath,filename); } //结束后删除当前的.svn文件目录 deletePointSVN(workspace); } /** * * @param svnUrl svn地址 * @param workspace 工作区 * @param filepath 上传的文件地址 * @param filename 文件名称 * @throws SVNException 异常信息 */ private void uploadFile(String svnUrl,String workspace,String filepath,String filename)throws SVNException{ this.checkWorkCopy(svnUrl, workspace, filepath,filename); File file = new File(workspace+"/"+filepath); this.checkVersiondDirectory(file); System.out.println("file路径:" + file); this.commit(file, false, "commit file:"+file); } public static void main(String[] args) throws SVNException { try { String svnUrl = "http://xxx.xxx.xxx.xxx:8080/svn路径"; String username = "svn用户"; String passwd = "密码"; String workspace = "D://本地路径"; String upfile = "a.txt,b.txt"; //被提交到svn文件 Boolean isOverwrite = true; SvnDeal svnDeal = new SvnDeal(svnUrl,username, passwd); String [] fileArray = upfile.split(","); for(int i=0;i<fileArray.length;i++){ String filePath = fileArray[i]; String filename = ""; if (filePath.indexOf("/") != -1) { filename = filePath.substring(filePath.lastIndexOf("/")); } else { filename = filePath; } svnDeal.upload(svnUrl, workspace, filePath, filename,isOverwrite); } } catch (Exception e) { e.printStackTrace(); } } }
此段代码来自:https://blog.csdn.net/yxf771hotmail/article/details/88311508
引用的包:
不幸的是:只是add添加成功,提交文件的时候就报错了,暂时没有找到解决方法,但是在本地目录继续提交,文件是可以被提交成功的
不幸+菜,只能搁置此方法,待解决
第二话:shell脚本实现
脚本一:在Jenkins所在服务器执行
#/bin/bash echo "====================== Start ======================" svnname=zhs #svn用户名 svnpwd=zhs666 #svn用户名对应的密码 myFile="compileResult" #被提交的目录名 commit_dir=/home/jenkins #服务器本地路径 target_svn_dir=svn://XXX.XXX.XXX.XXX/Sources/compileResult #svn路径 subsvn_file="/home/jenkins/jenkinshome/workspace/*/*/*/*/*/*/compileResult/*.java" #被提交文件所在目录 #检出文件夹,如果存在进入该目录 if [ ! -d "$myFile" ]; then svn checkout $target_svn_dir --username $svnname --password $svnpwd else cd $commit_dir/$myFile fi #更新项目 svn update -username $svnname --password $svnpwd #复制文件到提交目录 for var in $subsvn_file do echo "==++++== $var ==++++==" temp_dir_N="$var" array=(${temp_dir_N//// }) temp_dir=$commit_dir/$myFile/${array[5]}/${array[6]}/${array[8]}/ echo "==++++== $temp_dir ==++++==" if [!-d "$temp_dir" ]; then mkdir -p $temp_dir fi cp -a $var $temp_dir done #增加项目 svn add $commit_dir/$myFile/* #上传项目 svn commit -m "cormit file $myFile" $commit_dir/$myFile/* --username $svnname --password $svnpwd echo "====================== End ======================"
前提是:Jenkins所在主机要有svn命令,如果没有可以点击链接:https://www.cnblogs.com/ZhaoHS/p/12336168.html,自行下载资源安装部署,当然如果主机支持yum安装是最好的,执行命令:yum install subversion y
脚本二:在安装了svn的服务器上执行
#/bin/bash echo "====================== Start ======================" svnname=zhs #svn用户名 svnpwd=zhs666 #svn用户名对应的密码 myFile="compileResult" #被提交的目录名 hostname=root hostpwd=rootpwd commit_dir=/home/jenkins #服务器本地路径 target_svn_dir=svn://XXX.XXX.XXX.XXX/Sources/compileResult #svn路径 subsvn_file="/home/jenkins/jenkinshome/workspace/*/*/*/*/*/*/compileResult/*.java" #被提交文件所在目录 #检出文件夹,如果存在进入该目录 if [ ! -d "$myFile" ]; then svn checkout $target_svn_dir --username $svnname --password $svnpwd else cd $commit_dir/$myFile fi #更新项目 svn update -username $svnname --password $svnpwd #复制文件到提交目录 for var in $subsvn_file do echo "==++++== $var ==++++==" temp_dir_N="$var" array=(${temp_dir_N//// }) temp_dir=$commit_dir/$myFile/${array[5]}/${array[6]}/${array[8]}/ echo "==++++== $temp_dir ==++++==" if [!-d "$temp_dir" ]; then mkdir -p $temp_dir fi scp -r $hostname@xx.xx.xx.xxx:$var $temp_dir done #增加项目 svn add $commit_dir/$myFile/* #上传项目 syn commit -m "cormit file $myFile" $commit_dir/$myFile/* --username $svnname --password $svnpwd echo "====================== End ======================"
不完美的是:1.通配符"*"在截取的时候没有展示出具体文件夹名字;2.scp命令没有找到传密码的方式,不能实现定时自动执行
脚本参考:https://blog.csdn.net/weixin_30387663/article/details/99740077
脚本三:针对脚本二的方法改良,并且解决之前两个问题
#/bin/bash find /home/jenkins/jenkinshome/workspace/*/*/*/*/*/*/compileResult/ -mtime 0 >/home/jenkins/filename #查询当天该路径下修改的文件并输出到filename中 scp /home/jenkins/filename root@10.64.3.222:/root/home/filename scp /home/jenkins/afa build/svn_commit.sh root@10.64.3.222:/root/home/svn_commit.sh ssh root@10.64.3.222 << remotessh sh /root/home/svn_commit.sh remotessh
#/bin/bash date > /root/home/svn_log.log #输出打印日志到log文件 echo "====================== Start ======================" >> /root/home/svn_log.log svnname=zhs #svn用户名 svnpwd=zhs666 #svn用户名对应的密码 myFile="compileResult" #被提交的目录名 hostname=root hostpwd=rootpwd commit_dir=/home/jenkins #服务器本地路径 target_svn_dir=svn://XXX.XXX.XXX.XXX/Sources/compileResult #svn路径 #检出文件夹,如果存在进入该目录 if [ ! -d "$myFile" ]; then svn checkout $target_svn_dir --username $svnname --password $svnpwd >> /root/home/svn_log.log else cd $commit_dir/$myFile fi #更新项目 svn update -username $svnname --password $svnpwd >> /root/home/svn_log.log #复制文件到提交目录 for var in `cat filename` do echo "==++++== $var ==++++==" >> /root/home/svn_log.log temp_dir_N="$var" array=(${temp_dir_N//// }) temp_dir=$commit_dir/$myFile/${array[5]}/${array[6]}/${array[8]}/ echo "==++++== $temp_dir ==++++==" >> /root/home/svn_log.log if [!-d "$temp_dir" ]; then mkdir -p $temp_dir fi scp -r $hostname@xx.xx.xx.xxx:$var $temp_dir done #增加项目 cd $commit_dir/$myFile/ svn st | grep '^\?' | tr '^\?' ' ' | sed 's/[ ]*//' | sed 's/[ ]/\\ /g' | xargs svn add >> /root/home/svn_log.log #一次添加所有未添加的文件 #上传项目 syn commit -m "cormit file $myFile" $commit_dir/$myFile/* --username $svnname --password $svnpwd >> /root/home/svn_log.log echo "====================== End ======================" >> /root/home/svn_log.log
优化之路还需前行,仅仅提交文件到svn就花费近30分钟
注:脚本二、脚本三要想执行需要先建立两台Linux的ssh连接,具体操作如:https://www.cnblogs.com/ZhaoHS/p/12193402.html,在脚本一可以执行svn命令后,效率是最好的
第三话:Jenkins插件svn提交文件
比较尴尬的是这个模式没有找到适合的解决方法,并且自己对这块不了解,因此待增进个人能力
ps:学而识之不亦说乎,有朋指教兮不亦乐乎。欢迎各位指点!