备受折腾的一次相关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:学而识之不亦说乎,有朋指教兮不亦乐乎。欢迎各位指点!

posted @ 2020-01-13 17:50  借你耳朵说爱你  阅读(473)  评论(0编辑  收藏  举报