java实现svn,svnkit框架的简单应用

SvnKit
地址:https://svnkit.com/download.php

项目需要做了个简单的demo,可以进行基础操作。demo可以运行,但是更多高级更多实现需要自己在扩展。因为这个项目已经进入Thread.sleep :( ,开展新项目了 :(

功能
1.实现了几个基础操作
2.提供了日志操作

项目结构

这里写图片描述

首先我们先创建3个对象来为后面服务

package com.svn.model;
/**
 * Svn账号信息
 * 
 * @author Allen 
 * @date 2016年8月8日
 */
public class SvnAccountPojo implements java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String svnAccount;// svn账号
    private String svnPassword;// svn密码

    protected SvnAccountPojo() {
        // TODO Auto-generated constructor stub
    }

    public SvnAccountPojo(String svnAccount, String svnPassword) {
        super();
        this.svnAccount = svnAccount;
        this.svnPassword = svnPassword;
    }

    public String getSvnAccount() {
        return svnAccount;
    }

    public void setSvnAccount(String svnAccount) {
        this.svnAccount = svnAccount;
    }

    public String getSvnPassword() {
        return svnPassword;
    }

    public void setSvnPassword(String svnPassword) {
        this.svnPassword = svnPassword;
    }

}
package com.svn.model;

/**
 * Svn链接状态信息
 * 
 * @author Allen 
 * @date 2016年8月8日
 */
public class SvnLinkPojo extends SvnAccountPojo {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String repoPath;// 库链接路径

    public SvnLinkPojo(String repoPath, String svnAccount, String svnPassword) {
        super(svnAccount, svnPassword);
        this.repoPath = repoPath;
    }

    public SvnLinkPojo(String svnAccount, String svnPassword) {
        super(svnAccount, svnPassword);
    }

    public String getRepoPath() {
        return repoPath;
    }

    public void setRepoPath(String repoPath) {
        this.repoPath = repoPath;
    }

}
package com.svn.model;

import java.util.Date;

/**
 * SVN资源库对象
 * 
 * @author Allen 
 * @date 2016年8月8日
 */
public class SvnRepoPojo implements java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String commitMessage; // 提交信息
    private Date date; // 提交日期
    private String kind; // 提交方式 dir目录 file文件 none空 unknown 未知
    private String name;// 目录名
    private String repositoryRoot; // 资源库路径
    private long revision; // 提交的svn版本号
    private long size; // 提交的文件数
    private String url; // 更变的目录地址
    private String author;// 作者
    private String state;// 状态

    public String getCommitMessage() {
        return commitMessage;
    }

    public void setCommitMessage(String commitMessage) {
        this.commitMessage = commitMessage;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getKind() {
        return kind;
    }

    public void setKind(String kind) {
        this.kind = kind;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRepositoryRoot() {
        return repositoryRoot;
    }

    public void setRepositoryRoot(String repositoryRoot) {
        this.repositoryRoot = repositoryRoot;
    }

    public long getRevision() {
        return revision;
    }

    public void setRevision(long revision) {
        this.revision = revision;
    }

    public long getSize() {
        return size;
    }

    public void setSize(long size) {
        this.size = size;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

}

创建svn基础服务接口

package com.svn.inf.service;

/**
 * svn主服务创建
 * 
 * @author Allen
 * @date 2016年8月8日
 */
public interface ISvnService {

    /**
     * 创建SNV版本库服务
     * 
     * @author Allen
     * @date 2016年8月11日
     */
    public void createSVNRepository();

    /**
     * 关闭版本库容器,便于刷新重连等
     * 
     * @author Allen
     * @date 2016年8月11日
     */
    public void closeRepo();

    /**
     * 创建svn客户操作服务
     * 
     * @author Allen
     * @date 2016年8月11日
     */
    public void createSVNClientManager();
}

建立主功能接口

package com.svn.inf;

import java.io.File;
import java.util.List;

import com.svn.inf.service.ISvnDbLog;
import com.svn.inf.service.ISvnService;
import com.svn.model.SvnRepoPojo;

/**
 * svn操作大全
 * 
 * @author Allen
 * @date 2016年8月8日
 */
public interface ISvn extends ISvnService {

    /**
     * 获取目标路径下版本库数据信息
     * 
     * @param openPath
     *            需要查看的版本库路径
     * @return 版本库列表 {@link SvnRepoPojo}
     * @author Allen
     * @date 2016年8月11日
     */
    public List<SvnRepoPojo> getRepoCatalog(String openPath);

    /**
     * 检出到目录
     * 
     * @param checkUrl
     *            检出目标URL
     * @param savePath
     *            检出到本地路径
     * @return true|false
     * @author Allen
     * @date 2016年8月11日
     */
    public boolean checkOut(String checkUrl, String savePath);

    /**
     * 添加到版本库
     * 
     * @see 先添加文件夹再添加文件
     * @param paths
     *            提交文件路径
     * @param message
     *            提交信息
     * @param uLocks
     *            是否解锁
     * @param isvnLog
     *            数据持久化接口 {@link ISvnDbLog}
     * @return trun|false
     * @author Allen
     * @date 2016年8月11日
     */
    public <T> boolean add(String[] paths, String message, boolean uLocks, ISvnDbLog<? extends T> isvnLog);

    /**
     * 提交到版本库(所有写操作已在内部调用过COMMIT,自行调用则需要手动同步到DbLog)
     * 
     * @param files
     *            提交的文件路径
     * @param message
     *            提交信息
     * @param uLocks
     *            是否解锁
     * @return 返回提交后版本号-1为提交失败
     * @author Allen
     * @date 2016年8月11日
     */
    public Long commit(File[] files, String message, boolean uLocks);

    /**
     * 删除到版本库
     * 
     * @see 先删除文件再删除文件夹
     * @param paths
     *            提交文件路径
     * @param localDelete
     *            <ul>
     *            <li>如果是true则在本地也删除此文件,false则只删除版本库中的此文件</li>
     *            <li>删除实体文件时要注意</li>
     *            <li>删除文件夹时其目录下所有内容都要提交到<b>参数paths</b>中,否则无法删除实体文件</li>
     *            </ul>
     * @param message
     *            提交内容解释
     * @param uLock
     *            是否解锁
     * @param isvnLog
     *            数据持久化接口 {@link ISvnDbLog}
     * @return true|false
     * @author Allen
     * @date 2016年8月11日
     */
    public <T> boolean delete(String[] paths, boolean localDelete, String message, boolean uLock, ISvnDbLog<? extends T> isvnLog);

    /**
     * 更新到版本库
     * 
     * @param path
     *            要更新的文件目录
     * @param message
     *            提交内容解释
     * @param uLock
     *            是否解锁
     * @param isvnLog
     *            数据持久化接口 {@link ISvnDbLog}
     * @return true|false
     * @author Allen
     * @date 2016年8月11日
     */
    public <T> boolean update(String path, String message, boolean uLock, ISvnDbLog<? super T> isvnLog);

    /**
     * 比对目录下内容信息
     * 
     * @see 返回delete,update文件列表
     * @param file
     *            待比对的目标文件路径
     * @return 返回有差异的文件路径否则为null
     * @author Allen
     * @date 2016年8月11日
     */
    public List<String> diffPath(File file);

    /**
     * 清理目录
     * 
     * @param file
     *            待清理目录
     * @return true|false
     * @author Allen
     * @date 2016年8月17日
     */
    public boolean cleanUp(File file);

    public boolean doLock();

    public boolean unLock();
}

当然我们还有通用的工具接口

package com.svn.inf.service;

import java.io.File;
import java.util.List;

/**
 * Svn功能组件
 * 
 * @author Allen
 * @date 2016年8月12日
 *
 */
public interface ISvnCommon {
    /**
     * 组装file[]分离文件与文件夹
     * 
     * @param files
     *            待重组的文件列表
     * @return 文件容器组</br>index:0 文件夹</br> index:1 文件
     * @author Allen
     * @date 2016年8月11日
     */
    public List<List<File>> bindFile(File[] files);

    /**
     * 排序</br> 父级 ->子级
     * 
     * @param files
     *            待排序文件数组
     * @return 排序后文件数组
     * @author Allen
     * @date 2016年8月11日
     */
    public File[] sortF_S(File[] files);

    /**
     * 排序</br> 子级 ->父级
     * 
     * @param files
     *            待排序文件数组
     * @return 排序后文件数组
     * @author Allen
     * @date 2016年8月11日
     */
    public File[] sortS_F(File[] files);

    /**
     * 检查文件路径信息并组装到文件容器
     * 
     * @param paths
     *            待组装文件路径
     * @return 文件数组
     * @throws Exception
     *             文件路径中有寻找不到的地址
     * @author Allen
     * @date 2016年8月11日
     */
    public File[] checkFilePaths(String[] paths) throws Exception;
}

为了满足上级要求我们提供了db接口

package com.svn.inf.service;

import java.io.File;
import java.util.Date;
import java.util.List;

import com.svn.conf.SvnConfig;

/**
 * 记录svn操作人
 * 
 * @author Allen
 * @date 2016年8月8日
 */
public interface ISvnDbLog<T> {
    /**
     * 添加日志
     * 
     * @param name
     *            操作人账号
     * @param dbType
     *            数据类型{@link SvnConfig} 
     * @param versionId
     *            版本号
     * @param files
     *            操作的文件组
     * @return true|false
     * @author Allen
     * @date 2016年8月11日
     */
    public boolean addLog(String name, SvnConfig dbType, long versionId, File[] files);

    /**
     * 获取日志
     * 
     * @param name
     *            操作人账号
     * @param startTime
     *            日志开始时间
     * @param endTime
     *            日志结束时间
     * @return T 类型列表
     * @author Allen
     * @date 2016年8月11日
     */
    public List<? super T> getLog(String name, Date startTime, Date endTime);
}

到上面为止我们的接口全部做好。这是一个java项目是希望做为一个工具jar的存在,demo中只做了一套基础的实现,按照这个思路根据不同需求可以慢慢扩展


工具类
其实这里自己写了个简单的错误匹配,主要是针对svnkit的errorCode转义,当然也可以用log4j等开源日志。不过毕竟是demo么 :)

package com.svn.tools;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * 控制台输出log信息
 * 
 * @author Allen
 * @date 2016年8月8日
 */
public class ConsoleLog {
    protected boolean log = false;
    /**
     * 错误编码
     */
    private String[] errorCode = { "E155010", "E200005", "E204899", "E200009", "E155015","E155004" };
    /**
     * 编码解释
     */
    private String[] errorInfo = { "找不到文件或文件夹,其所在目录未被纳入版本控制的", "文件没有被纳入版本控制", "无法访问的目录", "文件没有被纳入版本控制", "svn冲突!","文件被锁定,可能是因为上次操作意外中断导致,请执行cleanup" };

    /**
     * 输出log到console
     * 
     * @param msg
     *            输出信息
     */
    protected void log(String msg, String... content) {
        if (log) {
            StackTraceElement stack[] = (new Throwable()).getStackTrace();
            String time = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
            System.out.println(new StringBuffer("[").append(time).append("]").append(stack[1].getClassName()).append(".").append(stack[1].getMethodName()).append("  line:")
                    .append(stack[1].getLineNumber()));
            System.out.println(new StringBuffer("[").append(time).append("]").append(msg));
        }
    }

    protected void log(Exception e) {
        StringBuffer sbf = new StringBuffer("【SVN-ERROR】");
        for (int i = 0; i < errorCode.length; i++) {
            if (e.getMessage().indexOf(errorCode[i]) != -1)
                this.log(sbf.append(errorInfo[i]).toString());
        }
    }

}

这里主要是输出文本比对时差异信息
说实话版本冲突这里我svn是可以对列表进行更新或写操作的时候,批量返回错误信息,而svn提供的cmd入口及svnkit对其cmd命令的实现,都是提供的单条问题抛出,譬如我update一个文件目录,在第3,第5个文件会出现冲突,则接口在第三个文件直接就exception了,无法往下进行了。当然你可以递归从第四条再更新执行,最后把结果合并显示 :)

package com.svn.tools;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

/**
 * Output输出到字符串
 * 
 * @author Allen
 * @date 2016年8月11日
 *
 */
public final class StringOutputSteam extends OutputStream {

    public List<String> s;

    public StringOutputSteam(List<String> s) {
        this.s = s;
    }

    @Override
    public void write(int b) throws IOException {
    }

    @Override
    public void write(byte b[], int off, int len) throws IOException {
        String temp = new String(b);
        String[] temps = temp.split("\r\n");
        //System.out.println(temp);
        boolean flag = false;
        for (int i = 0; i < temps.length; i++) {
            // 根据svn命令返回Index: xxxx(path)获取所有包含delete update的path获取
            if (temps[i].split(" ")[0].equalsIgnoreCase("Index:")) {
                String p = temps[i].substring(7, temps[i].length());
                if (s.indexOf(p) == -1) {
                    s.add(p);
                    flag = true;
                    continue;
                }
            }
            // 以Index:为开始点来判定svn diff返回的Log信息
            // LogFormat:
            // Index: path
            // =============================
            // xxxxxxx
            // Index: path
            // =============================
            // xxxxxxx
            if (flag) {
                String state = "";
                for (int j = i; j < temps.length; j++) {
                    if (temps[j].split(" ")[0].equalsIgnoreCase("Index:"))
                        break;
                    if (temps[j].split(" ")[0].equalsIgnoreCase("---"))
                        state = "冲突";
                    else if (state.equals(""))
                        state = "删除";
                } 
                s.add(state);
                flag = false;
            }
        }
    }
}

这里是自定义的错误信息

package com.svn.conf;

/**
 * 错误信息库
 * 
 * @author Allen
 * @date 2016年8月8日
 *
 */
public final class ErrorVal {

    public final static String SVNRepository_is_null = "版本库未被创建";
    public final static String SVNClientManager = "";
    public final static String SVNRepository_is_having = "版本库已存在 ,可以调用closeRepo进行[库服务清理]";
    public final static String ISVNAuthenticationManager_is_null = "身份验证器还未被创建";
    public final static String Path_no_having = "目标地址路径不存在";
    public final static String Url_no_having = "目标库路径 不存在";
    public final static String File_not_exist_repo = "文件所在目录没有被svn版本控制";
    public final static String SvnConfig_is_null = "错误的配置";
    public final static String Commit_error = "提交错误[==请确认文件是否已有其他版本操作,请检查文件是否不存在==]";
    public final static String AddDbLog_error = "添加到数据日志错误";
    public final static String File_Repo_no_having = "文件不存在版本库中";
    public final static String Repo_Status_error = "版本状态错误";
    public final static String Update_no_change = "没有变化的更新";
    public final static String File_is_not_directory = "File不是一个目录";
}

这里不仅为小工厂提供了选项,还提供了对抽象db日志的数据设置

package com.svn.conf;

/**
 * 系统参数设置
 * 
 * @see 外部通过<b>SvnConfig.xx</b>来一个<b>SvnConfig</b>类型传入不同的配置
 * @see 外部通过<b>SvnConfig.xx.get</b>来以<b>String</b>类型得到不同的配置
 * @author Allen
 * @date 2016年8月8日
 * 
 */
public class SvnConfig {
    /**
     * 选择非日志模式
     */
    public static final SvnConfig normal = new SvnConfig("normal");
    /**
     * 选择console日志模式
     */
    public static final SvnConfig log = new SvnConfig("log");
    /**
     * 数据存储类型Add
     */
    public static final SvnConfig add = new SvnConfig("add");
    /**
     * 数据存储类型Update
     */
    public static final SvnConfig update = new SvnConfig("update");
    /**
     * 数据存储类型Delete
     */
    public static final SvnConfig delete = new SvnConfig("delete");
    private String val;

    public String getVal() {
        return val;
    }

    private SvnConfig() {
    }

    private SvnConfig(String val) {
        this.val = val;

    }
}

实现类来了。。。拦不住的implements
提供了对通用工具接口的实现,为什么要那么复杂呢。因为例如add接口,必须要先提交最底层的文件夹目录从深层提交到高层,然后再提交其文件,以此类推,说白了就是你没有文件夹时无法建立文件的。

package com.svn.impl.service;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.svn.conf.ErrorVal;
import com.svn.inf.service.ISvnCommon;
import com.svn.tools.ConsoleLog;

/**
 * {@link ISvnCommon}
 * 
 * @author Allen
 * @date 2016年8月12日
 *
 */
public class SvnCommonImpl extends ConsoleLog implements ISvnCommon {

    @Override
    public List<List<File>> bindFile(File[] files) {
        List<List<File>> fileList = new ArrayList<List<File>>(1);
        fileList.add(new ArrayList<File>());
        fileList.add(new ArrayList<File>());
        for (File f : files) {
            if (f.isDirectory())
                // 0是文件目录,先提交文件目录让再提交文件
                fileList.get(0).add(f);
            else
                fileList.get(1).add(f);
        }
        for (int i = 0; i < fileList.size(); i++) {
            if (fileList.get(i).size() == 0)
                fileList.remove(i);
        }
        return fileList;
    }

    @Override
    public File[] sortF_S(File[] files) {
        Arrays.sort(files);
        return files;
    }

    @Override
    public File[] sortS_F(File[] files) {
        files = sortF_S(files);
        File[] f = new File[files.length];
        for (int i = 0; i < files.length;) {
            f[i] = files[files.length - (++i)];
        }
        return f;
    }

    @Override
    public File[] checkFilePaths(String[] paths) throws Exception {
        if (paths == null | paths.length == 0)
            throw new Exception(ErrorVal.Path_no_having);
        File[] files = new File[paths.length];
        for (int i = 0; i < paths.length; i++) {
            if (!(files[i] = new File(paths[i])).exists())
                throw new Exception(ErrorVal.Path_no_having);
        }
        return files;
    }

}

服务接口实现类,快乐的建立库容器
因为整个项目保持开闭原则,让你用的你随便用,不让你用的你就老实点:)
一次创建整个实例都能在开闭原则下快乐的使用各种创建好的实例/各种服务类

package com.svn.impl.service;

import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
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.SVNWCUtil;

import com.svn.conf.ErrorVal;
import com.svn.inf.service.ISvnService;

/**
 * {@link ISvnService}
 * 
 * @author Allen
 * @date 2016年8月8日
 */
public class SvnServiceImpl extends SvnCommonImpl implements ISvnService {

    protected String svnAccount; // svn账号
    protected String svnPassword;// svn密码
    protected String svnRepoPath;// svn版本库根目录
    protected boolean logStatus = false;// 日志状态
    protected SVNRepository repository = null;// 版本库服务
    protected ISVNAuthenticationManager authManager;// 身份验证器
    protected SVNClientManager clientManager;// svn客户操作服务

    /**
     * 
     * @param account
     *            账号
     * @param password
     *            密码
     * @param logStatus
     *            是否开启日志状态(默认false)
     * @param repoPath
     *            svn库根目录
     * 
     */
    public SvnServiceImpl(String account, String password, boolean logStatus, String repoPath) {
        this.svnAccount = account;
        this.svnPassword = password;
        this.svnRepoPath = repoPath;
        super.log = logStatus;
    }

    @Override
    public void createSVNRepository() {
        try {
            if (repository != null)
                throw new Exception(ErrorVal.SVNRepository_is_having);
            // 创建库连接
            SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(this.svnRepoPath));
            super.log("创建版本库连接");
            // 身份验证
            this.authManager = SVNWCUtil.createDefaultAuthenticationManager(this.svnAccount, this.svnPassword.toCharArray());
            super.log("创建身份验证");
            // 创建身份验证管理器
            repository.setAuthenticationManager(authManager);
            this.repository = repository;
            super.log("设置版本库身份验证");
        } catch (SVNException e) {
            super.log(e);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void closeRepo() {
        if (repository == null)
            try {
                throw new NullPointerException(ErrorVal.SVNRepository_is_null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        else {
            repository.closeSession();
            repository = null;
            super.log("关闭版本库");
        }
    }

    @Override
    public void createSVNClientManager() {
        if (authManager == null)
            try {
                throw new NullPointerException(ErrorVal.ISVNAuthenticationManager_is_null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        clientManager = SVNClientManager.newInstance(SVNWCUtil.createDefaultOptions(true), authManager);
        super.log("创建svn客户操作服务");
    }

}

其实这里本来还想写个池服务。。不过时间关系就没写。毕竟demo没有后续跟进计划了。以后有机会再补

package com.svn.impl.service;

import com.svn.impl.service.SvnCommonImpl;
import com.svn.inf.service.ISvnService;

/**
 * {@link ISvnService} 池的实现
 * 
 * @author Allen
 * @date 2016年8月8日
 */
public class SvnServicePoolImpl extends SvnCommonImpl implements ISvnService {

    @Override
    public void createSVNRepository() {
        // TODO Auto-generated method stub

    }

    @Override
    public void closeRepo() {
        // TODO Auto-generated method stub

    }

    @Override
    public void createSVNClientManager() {
        // TODO Auto-generated method stub

    }
}

这里..这里就是业务实现了,其实就是对svnkit进行了一个封装,让他更符合项目要求

package com.svn.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc.SVNDiffClient;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNStatus;
import org.tmatesoft.svn.core.wc.SVNStatusType;
import org.tmatesoft.svn.core.wc.SVNUpdateClient;

import com.svn.conf.ErrorVal;
import com.svn.conf.SvnConfig;
import com.svn.impl.service.SvnServiceImpl;
import com.svn.inf.ISvn;
import com.svn.inf.service.ISvnDbLog;
import com.svn.inf.service.ISvnService;
import com.svn.model.SvnRepoPojo;
import com.svn.tools.StringOutputSteam;

/**
 * 
 * {@link ISvnService}
 * 
 * @author Allen
 * @date 2016年8月8日
 *
 */
public class SvnBaseImpl extends SvnServiceImpl implements ISvn {

    public SvnBaseImpl(String account, String password, boolean logStatus, String repoPath) {
        super(account, password, logStatus, repoPath);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<SvnRepoPojo> getRepoCatalog(String openPath) {
        try {
            if (repository == null)
                throw new Exception(ErrorVal.SVNRepository_is_null);
            Collection<SVNDirEntry> entries = repository.getDir(openPath, -1, null, (Collection<SVNDirEntry>) null);
            List<SvnRepoPojo> svns = new ArrayList<SvnRepoPojo>();
            Iterator<SVNDirEntry> it = entries.iterator();
            while (it.hasNext()) {
                SVNDirEntry entry = it.next();
                SvnRepoPojo svn = new SvnRepoPojo();
                svn.setCommitMessage(entry.getCommitMessage());
                svn.setDate(entry.getDate());
                svn.setKind(entry.getKind().toString());
                svn.setName(entry.getName());
                svn.setRepositoryRoot(entry.getRepositoryRoot().toString());
                svn.setRevision(entry.getRevision());
                svn.setSize(entry.getSize() / 1024);
                svn.setUrl(openPath.equals("") ? new StringBuffer("/").append(entry.getName()).toString() : new StringBuffer(openPath).append("/").append(entry.getName()).toString());
                svn.setAuthor(entry.getAuthor());
                svn.setState(svn.getKind() == "file" ? null : "closed");
                svns.add(svn);
            }
            super.log("获得版本库文件信息");
            return svns;
        } catch (SVNException e) {
            super.log(e);
            e.printStackTrace();
            return null;
        } catch (Exception e) {
            super.log(e);
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public boolean checkOut(String checkUrl, String savePath) {
        SVNUpdateClient updateClient = clientManager.getUpdateClient();
        updateClient.setIgnoreExternals(false);
        try {
            if (savePath == null || savePath.trim().equals(""))
                throw new Exception(ErrorVal.Path_no_having);
            else if (checkUrl == null || checkUrl.trim().equals(""))
                throw new Exception(ErrorVal.Url_no_having);
            File save = new File(savePath);
            if (!save.isDirectory())
                save.mkdir();
            updateClient.doCheckout(SVNURL.parseURIEncoded(checkUrl), save, SVNRevision.HEAD, SVNRevision.HEAD, SVNDepth.INFINITY, false);
            super.log("检出版本库信息");
            return true;
        } catch (SVNException e) {
            super.log(e);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 此实现自动对Add后的数据进行提交
     */
    @Override
    public <T> boolean add(String[] paths, String message, boolean uLocks, ISvnDbLog<? extends T> isvnLog) {
        try {
            File[] files = checkFilePaths(paths);
            files = sortF_S(files);
            SVNStatus status;
            List<File> targetList = new ArrayList<File>();
            List<List<File>> fileList = bindFile(files);
            for (int i = 0; i < fileList.size(); i++) {
                for (File f : fileList.get(i)) {
                    if ((status = clientManager.getStatusClient().doStatus(f, true, true)) != null && status.getContentsStatus() != SVNStatusType.STATUS_UNVERSIONED
                            && status.getContentsStatus() != (SVNStatusType.STATUS_NONE))
                        continue;
                    else if (f.isFile()) {
                        clientManager.getWCClient().doAdd(f, true, false, true, SVNDepth.fromRecurse(true), false, false, true);
                        targetList.add(f);
                        super.log("添加文件到提交队列");
                    } else if (f.isDirectory()) {
                        // SVNDepth.empty 保证不递归文件夹下文件
                        clientManager.getWCClient().doAdd(f, false, false, false, SVNDepth.EMPTY, false, false, false);
                        targetList.add(f);
                        super.log("添加文件夹到提交队列");
                    }
                }
            }
            long versionId = commit(targetList.toArray(new File[targetList.size()]), message, uLocks);
            if (versionId == -1)
                throw new Exception(ErrorVal.Commit_error);
            if (!isvnLog.addLog(this.svnAccount, SvnConfig.add, versionId, files))
                throw new Exception(ErrorVal.AddDbLog_error);
            return true;
        } catch (SVNException e) {
            super.log(e);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Long commit(File[] files, String message, boolean uLocks) {
        try {
            if (files.length == 0) {
                super.log("无效的提交信息");
                return -1l;
            }
            long versionId = clientManager.getCommitClient().doCommit(files, uLocks, message, null, null, false, false, SVNDepth.INFINITY).getNewRevision();
            super.log("提交队列中预处理的操作操作  => 版本号: " + versionId);
            return versionId;
        } catch (SVNException e) {
            super.log(e);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1l;
    }

    @Override
    public <T> boolean delete(String[] paths, boolean localDelete, String message, boolean uLock, ISvnDbLog<? extends T> isvnLog) {
        try {
            File[] files = checkFilePaths(paths);
            files = sortS_F(files);
            SVNStatus status = null;
            {
                List<File> targetList = new ArrayList<File>();
                List<List<File>> fileList = bindFile(files);
                for (int i = fileList.size() - 1; i >= 0; i--) {
                    for (File f : fileList.get(i)) {
                        if ((status = clientManager.getStatusClient().doStatus(f, true, true)) == null)
                            throw new Exception(ErrorVal.File_Repo_no_having);
                        else if (status.getContentsStatus() != SVNStatusType.STATUS_NORMAL)
                            throw new Exception(ErrorVal.Repo_Status_error + status.getContentsStatus().toString());
                        else {
                            clientManager.getWCClient().doDelete(f, false, localDelete, false);
                            if (f.isFile())
                                super.log("添加文件到删除队列");
                            else
                                super.log("添加文件夹到删除队列");
                            targetList.add(f);
                        }
                    }
                }
                long versionId = commit(targetList.toArray(new File[targetList.size()]), message, uLock);
                if (versionId == -1)
                    throw new Exception(ErrorVal.Commit_error);
                if (!isvnLog.addLog(this.svnAccount, SvnConfig.delete, versionId, files))
                    throw new Exception(ErrorVal.AddDbLog_error);
            }
            return true;
        } catch (SVNException e) {
            super.log(e);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public <T> boolean update(String path, String message, boolean uLocks, ISvnDbLog<? super T> isvnLog) {
        try {
            File[] files = checkFilePaths(new String[] { path });
            // diffPath(files);
            long[] l = clientManager.getUpdateClient().doUpdate(files, SVNRevision.HEAD, SVNDepth.INFINITY, true, false);
            super.log("更新文件到操作队列");
            long versionId = l[0];// commit(files, message, uLocks);
            if (versionId == -1)
                throw new Exception(ErrorVal.Update_no_change);
            if (!isvnLog.addLog(this.svnAccount, SvnConfig.update, versionId, files))
                throw new Exception(ErrorVal.AddDbLog_error);
        } catch (SVNException e) {
            super.log(e);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public List<String> diffPath(File file) {
        try {
            if (file == null || !file.exists())
                throw new Exception(ErrorVal.Path_no_having);
            // 获取SVNDiffClient
            SVNDiffClient diffClient = clientManager.getDiffClient();
            diffClient.setIgnoreExternals(false);
            StringOutputSteam os = new StringOutputSteam(new ArrayList<String>());
            diffClient.doDiff(new File[] { file }, SVNRevision.HEAD, SVNRevision.BASE, null, SVNDepth.INFINITY, true, os, null);
            super.log("比对库路径");
            return os.s;
        } catch (SVNException e) {
            super.log(e);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }

    @Override
    public boolean cleanUp(File file) {
        try {
            if (!file.exists())
                throw new Exception(ErrorVal.Path_no_having);
            else if (!file.isDirectory())
                throw new Exception(ErrorVal.File_is_not_directory);
            clientManager.getWCClient().doCleanup(file, false, false, false, true, true, true);
            super.log("清理完成");
        } catch (SVNException e) {
            super.log(e);
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    @Override
    public boolean doLock() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean unLock() {
        // TODO Auto-generated method stub
        return false;
    }

}

实现代码比较多。不要慌
仔细看看加断点看看
加锁解锁还有一些接口的高级应用并没有深入去写,因为毕竟是demo。上级觉得技术上是可以搞定这个功能的,虽然因为其他原因项目阉割了 :( 所以也没有后续进行深层开发
https://svnkit.com/documentation.html 这个是svnkit 文档,不过文档比svnkit.jar版本要老 :((


关于参数中

ISvnDbLog<? super T> isvnLog

可以让使用者提供一个ISvnDbLog的实现,来进行日志保存,无论是db还是file

最后我们提供一个简单纺织小工厂

package com.svn.factory;

import com.svn.conf.ErrorVal;
import com.svn.conf.SvnConfig;
import com.svn.impl.SvnBaseImpl;
import com.svn.inf.ISvn;
import com.svn.model.SvnLinkPojo;

/**
 * DemoSvn主体
 * 
 * @author Allen
 * @date 2016年8月8日
 */
public final class DemoSvn {

    SvnLinkPojo svnLink;

    public SvnLinkPojo getSvnLink() {
        return svnLink;
    }

    /**
     * 私有构造
     */
    public DemoSvn() {
    }

    public DemoSvn(String svnAccount, String svnPassword, String repoPath) {
        this.svnLink = new SvnLinkPojo(repoPath, svnAccount, svnPassword);
    }

    /**
     * 获取SVN操作
     * 
     * @param val
     *            default 不设置日志状态 log 开启console日志状态
     * @throws 没有操作匹配
     * @return {@link ISvn}
     */
    public ISvn execute(SvnConfig val) throws Exception {
        ISvn is = null;
        if (val == null)
            throw new Exception(ErrorVal.SvnConfig_is_null);
        switch (val.getVal()) {
        case "normal":
            is = new SvnBaseImpl(svnLink.getSvnAccount(), svnLink.getSvnPassword(), false, svnLink.getRepoPath());
            break;
        case "log":
            is = new SvnBaseImpl(svnLink.getSvnAccount(), svnLink.getSvnPassword(), true, svnLink.getRepoPath());
            break;
        default:
            throw new Exception(ErrorVal.SvnConfig_is_null);
        }
        return is;
    }
}

来一个测试函数吧
其实创建版本库,操作对象,初始化实例,close都可以做的更简洁,然后做到事务中,切面管理.. :)

package com.svn;

import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Date;

import com.svn.conf.SvnConfig;
import com.svn.factory.DemoSvn;
import com.svn.inf.ISvn;
import com.svn.inf.service.ISvnDbLog;
import com.svn.model.SvnRepoPojo;

/**
 * 测试类
 * 
 * @author Allen
 * @date 2016年8月8日
 */
public class exmple {
    String account = "allen";
    String password = "123456";
    String path = "http://192.168.1.xx/svn/abc";
    String targetHead = "e:/测试";
    ISvn svn;

    /**
     * 样例
     * 
     * @throws Exception
     * @author Allen
     * @date 2016年8月12日
     */

    private void testCore() throws Exception {
        // 初始化实例
        DemoSvn ts = new DemoSvn(account, password, path);
        // 获得操作对象
        this.svn = ts.execute(SvnConfig.log);
        // 得到版本库信息
        svn.createSVNRepository();
        // 得到基础操作对象
        svn.createSVNClientManager();
        /** 测试--Start-- **/
        testGetRepo();
        testCheckOut();
        testAdd();
        testDel();
        testCleanUp();
        testUpdate();
        testDiff();
        /** 测试 --End-- **/
        // 关闭库容器
        svn.closeRepo();

    }

    /**
     * 获得版本路径文件信息
     * 
     * @author Allen
     * @date 2016年8月12日
     */
    private void testGetRepo() {
        print(svn.getRepoCatalog(""));
    }

    /**
     * 检出到本地路径
     * 
     * @author Allen
     * @date 2016年8月12日
     */

    private void testCheckOut() {
        svn.checkOut("xxx", targetHead);
    }

    /**
     * 添加文件到svn
     * 
     * @author Allen
     * @date 2016年8月12日
     */

    private void testAdd() {
        String[] strs = new String[] { targetHead + "/4/a/", targetHead + "/4/", targetHead + "/4/a/b/", targetHead + "/4/a/b/b.txt" };
        svn.add(strs, "haha", false, new ISvnDbLog<String>() {
            @Override
            public boolean addLog(String name, SvnConfig dbType, long versionId, File[] files) {
                System.out.println("Add 到 DB 了");
                return true;
            }

            @Override
            public List<String> getLog(String name, Date startTime, Date endTime) {
                System.out.println("get 到 log 了");
                return null;
            }
        });
    }

    /**
     * 删除文件到svn
     * 
     * @author Allen
     * @date 2016年8月12日
     */

    private void testDel() {
        String[] strs = new String[] { targetHead + "/4/a/", targetHead + "/4/", targetHead + "/4/a/b/", targetHead + "/4/a/b/b.txt" };
        svn.delete(strs, true, "haha", false, new ISvnDbLog<String>() {
            @Override
            public boolean addLog(String name, SvnConfig dbType, long versionId, File[] files) {
                System.out.println("del 到 DB 了");
                return true;
            }

            @Override
            public List<String> getLog(String name, Date startTime, Date endTime) {
                System.out.println("get 到 log 了");
                return null;
            }
        });
    }

    /**
     * 更新文件到svn
     * 
     * @author Allen
     * @date 2016年8月12日
     */

    private void testUpdate() {
        String strs = targetHead + "/4/a/b/";
        svn.update(strs, "哈哈", false, new ISvnDbLog<String>() {
            @Override
            public boolean addLog(String name, SvnConfig dbType, long versionId, File[] files) {
                System.out.println("update 到 DB 了");
                return true;
            }

            @Override
            public List<String> getLog(String name, Date startTime, Date endTime) {
                System.out.println("get 到 log 了");
                return null;
            }
        });
    }

    /**
     * 测试库比对
     * 
     * @author Allen
     * @date 2016年8月12日
     */

    private void testDiff() {
        String[] strs = new String[] { targetHead + "/4/a/b/" };
        List<String> s = svn.diffPath(new File(strs[0]));
        for (String t : s)
            System.out.println(t);
    }

    private void testCleanUp() {
        String[] strs = new String[] { targetHead + "/4/a/b/" };
        svn.cleanUp(new File(strs[0]));
    }

    /**
     * 打印当前版本库路径目录
     */
    private void print(List<SvnRepoPojo> paramList) {
        System.out.print("commitMessage ");
        System.out.print("\t\t  date \t  ");
        System.out.print("\t   kind \t  ");
        System.out.print("\t name \t  ");
        System.out.print("\t repositoryRoot \t  ");
        System.out.print("\t revision \t  ");
        System.out.print("\t size \t  ");
        System.out.print("\t url \t  ");
        System.out.print("\t author \t  ");
        System.out.println("\t state \t  ");
        Collections.sort(paramList, new Comparator<SvnRepoPojo>() {
            @Override
            public int compare(SvnRepoPojo o1, SvnRepoPojo o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        for (SvnRepoPojo pojo : paramList) {
            System.out.print("\t" + pojo.getCommitMessage() + "\t");
            System.out.print("\t" + pojo.getDate().getTime() + "\t");
            System.out.print("\t" + pojo.getKind() + "\t");
            System.out.print("\t" + pojo.getName() + "\t");
            System.out.print("\t" + pojo.getRepositoryRoot() + "\t");
            System.out.print("\t" + pojo.getRevision() + "\t");
            System.out.print("\t" + pojo.getSize() + "\t");
            System.out.print("\t" + pojo.getUrl() + "\t");
            System.out.print("\t" + pojo.getAuthor() + "\t");
            System.out.print("\t" + pojo.getState() + "\t");
            System.out.print("\r\n");
        }
    }

    public static void main(String[] args) throws Exception {
         new exmple().testCore(); 
    }
}

就这样吧。demo而已看个用法和思路。具体优化及细节也没有时间去做了,毕竟是demo :)

下载地址
http://download.csdn.net/detail/crazyzxljing0621/9755958

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章