Package com.taobao.eclipse.plugin.reviewboard.subclipse.diffoperation

Source Code of com.taobao.eclipse.plugin.reviewboard.subclipse.diffoperation.GeneratePreCommitDiffOperation

/*
* (C) 2007-2011 Alibaba Group Holding Limited
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*
* If you have any question, please contact:千丫 <qianya@taobao.com>
* Authors:智清 <zhiqing.ht@taobao.com>;银时<yinshi.nc@taobao.com>
*
*/
package com.taobao.eclipse.plugin.reviewboard.subclipse.diffoperation;

import static com.taobao.eclipse.plugin.reviewboard.core.constant.ReviewBoardCoreConstants.CHARSET_AUTO;
import static com.taobao.eclipse.plugin.reviewboard.core.constant.ReviewBoardCoreConstants.DIFF_SUFFIX;
import static com.taobao.eclipse.plugin.reviewboard.core.constant.ReviewBoardCoreConstants.EMPTY_STRING;
import static com.taobao.eclipse.plugin.reviewboard.core.constant.ReviewBoardCoreConstants.EOL;
import static com.taobao.eclipse.plugin.reviewboard.core.constant.ReviewBoardCoreConstants.FOLDER_TMP_DIFF;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.tigris.subversion.subclipse.core.ISVNLocalResource;
import org.tigris.subversion.subclipse.core.SVNTeamProvider;
import org.tigris.subversion.subclipse.core.resources.SVNWorkspaceRoot;
import org.tigris.subversion.subclipse.ui.Policy;
import org.tigris.subversion.svnclientadapter.ISVNClientAdapter;
import org.tigris.subversion.svnclientadapter.SVNRevision;

import com.taobao.eclipse.plugin.reviewboard.core.config.RbConfig;
import com.taobao.eclipse.plugin.reviewboard.core.config.RbConfigReader;
import com.taobao.eclipse.plugin.reviewboard.core.util.GuessStreamEncoding;
import com.taobao.eclipse.plugin.reviewboard.core.util.IOUtils;
import com.taobao.eclipse.plugin.reviewboard.subclipse.RbSubclipseMessages;
import com.taobao.eclipse.plugin.reviewboard.subclipse.util.RbSVNUrlUtils;

/**
* 类说明:为pre-commit方式生成diff。支持多文件、跨project
*
* @author 智清
* 创建时间:2010-11-8
*/
@SuppressWarnings( { "unchecked" })
public class GeneratePreCommitDiffOperation implements IRunnableWithProgress {

    private IResource[] resources;
    private IResource[] unaddedAllResourceList;
    private ArrayList newFiles;
    private SVNRevision compareVersion;

    /** ReviewBoard对文件编码的支持还不够好,不得不采用这种方式(当同一次提交的文件包含多种编码时) */
    Map< String, StringBuilder > diffContentSBByCharset = new HashMap< String, StringBuilder >();
    /** 最终生成的diff的文件内容 */
    private File[] fileDiffs;

    public GeneratePreCommitDiffOperation(IResource[] resources, IResource[] unaddedAllResourceList,
            File file, Shell shell, SVNRevision compareVersion) {
        this.resources = resources;
        this.unaddedAllResourceList = unaddedAllResourceList;
        if( null == compareVersion ){
            compareVersion = SVNRevision.BASE;
        }
        this.compareVersion = compareVersion;
    }

    /**
     * Convenience method that maps the given resources to their providers. The
     * returned Hashtable has keys which are ITeamProviders, and values which
     * are Lists of IResources that are shared with that provider.
     *
     * @return a hashtable mapping providers to their resources
     */
    protected Hashtable getProviderMapping(IResource[] resources) {
        Hashtable result = new Hashtable();
        for (int i = 0; i < resources.length; i++) {
            RepositoryProvider provider = RepositoryProvider.getProvider(resources[i].getProject());
            List list = (List) result.get(provider);
            if (list == null) {
                list = new ArrayList();
                result.put(provider, list);
            }
            list.add(resources[i]);
        }
        return result;
    }

    /**
     * @see IRunnableWithProgress#run(IProgressMonitor)
     */
    public void run(IProgressMonitor monitor) throws InvocationTargetException,
            InterruptedException {
       
        try {
            monitor.beginTask("", 500); //$NON-NLS-1$
            monitor.setTaskName(Policy.bind("GenerateSVNDiff.working")); //$NON-NLS-1$

            ISVNLocalResource svnResource = SVNWorkspaceRoot.getSVNResourceFor(resources[0]);

            newFiles = new ArrayList();
            if ( null != unaddedAllResourceList && unaddedAllResourceList.length > 0) {
                for IResource unAddedResourceTmp : unaddedAllResourceList ){
                    for( IResource resourceTmp : resources ){
                        if( unAddedResourceTmp.getLocation().toString().equals(resourceTmp.getLocation().toString()) ){
                            newFiles.add( resourceTmp );
                            break;
                        }
                    }
                }
                if (newFiles.size() > 0) {
                    try {
                        // associate the resources with their respective
                        // RepositoryProvider
                        Hashtable table = getProviderMapping((IResource[]) newFiles.toArray(new IResource[newFiles.size()]));
                        Set keySet = table.keySet();
                        Iterator iterator = keySet.iterator();
                        while (iterator.hasNext()) {
                            IProgressMonitor subMonitor = Policy.subMonitorFor(monitor, 100);
                            SVNTeamProvider provider = (SVNTeamProvider) iterator.next();
                            List list = (List) table.get(provider);
                            IResource[] providerResources = (IResource[]) list.toArray(new IResource[list.size()]);

                            provider.add(providerResources, IResource.DEPTH_INFINITE, subMonitor);
                        }
                    } catch (TeamException e) {
                        throw new InvocationTargetException(e);
                    }
                }
            }

            ISVNClientAdapter svnClient = svnResource.getRepository().getSVNClient();
            Set<IResource> includedResources = new HashSet<IResource>();
            if ( null != resources && resources.length > 0) {
                includedResources.addAll(Arrays.asList(resources));
            }
            //将includedResources按照project进行分组
            Map<IProject, List<IResource>> projectToResources = new HashMap<IProject, List<IResource>>();
            for( IResource resourceTmp : includedResources ){
                IProject project = resourceTmp.getProject();
                List<IResource> resources = projectToResources.get(project);
                if (resources == null) {
                    resources = new ArrayList<IResource>();
                    projectToResources.put(project, resources);
                }
                resources.add(resourceTmp);
            }
           
            //确保所有的project都在同一个Repository Root里(否则,无法正常生成ReviewBoard能够识别的diff)
            if( !RbSVNUrlUtils.isProjectWithSameSVNRepository( projectToResources.keySet() ) ){
                throw new Exception( RbSubclipseMessages.getString("ERROR_PROJECT_NOTSAME_REPOSITORY") );
            }
           
            //再逐个生成resources的diff
            SVNRevision toRevision = SVNRevision.WORKING;
            monitor.worked(200);
            for ( Iterator<Entry<IProject, List<IResource>>> iEntry = projectToResources.entrySet().iterator(); iEntry.hasNext(); ) {
                monitor.worked(100)
                Entry<IProject, List<IResource>> entry = (Entry<IProject, List<IResource>>) iEntry.next();
                IProject project = (IProject) entry.getKey();
                List<IResource> resources = (List<IResource>) entry.getValue();
               
                String repositoryRootUrl = RbSVNUrlUtils.getRepositoryRootUrlForResource( project );
                String projectSVNUrl = RbSVNUrlUtils.getSVNUrlForProject( project );
                if( !repositoryRootUrl.endsWith("/") ){
                    repositoryRootUrl += "/";
                }
                if( !projectSVNUrl.endsWith("/") ){
                    projectSVNUrl += "/";
                }
                String relativeRepositoryRootUrl = projectSVNUrl.replaceFirst( repositoryRootUrl, EMPTY_STRING );
               
                for( IResource resourceTmp : resources ){
                    if( ! (resourceTmp instanceof IFile) ){
                        continue;
                    }
                    File tempDiffFile = IOUtils.generateTmpFile( FOLDER_TMP_DIFF, DIFF_SUFFIX);
                    File resourceFileTmp = ((IFile)resourceTmp).getLocation().toFile();
                    SVNRevision compareVersionReal = compareVersion;
                    //修复版本号
                    if( compareVersionReal instanceof SVNRevision.Number ){
                        compareVersionReal = RbSVNUrlUtils.reviseSVNRevisionAdaptByMaxOrMin( resourceTmp, (SVNRevision.Number)compareVersion, false, null );
                        if( null == compareVersionReal ){
                            compareVersionReal = compareVersion;
                        }
                    }
                    svnClient.diff(resourceFileTmp, compareVersionReal, resourceFileTmp, toRevision,
                            tempDiffFile, false, false, false, false);
                   
                    if( null == tempDiffFile || !tempDiffFile.exists() ){
                        continue;
                    }
                   
                    String charsetName = GuessStreamEncoding.getFileEncoding(tempDiffFile);

                    RbConfig rbConfig = RbConfigReader.getRbConfig(null);
                    if( null != rbConfig.getCharsetEncoding() && !rbConfig.getCharsetEncoding().trim().equals(CHARSET_AUTO) ){
                        charsetName = rbConfig.getCharsetEncoding();
                    }
                   
                    String diffContentTmp = IOUtils.getContentFromFile( tempDiffFile, charsetName );
                    //diffContentTmp = IOUtils.getContentFromFile( tempDiffFile.getAbsolutePath() );
                    tempDiffFile.delete();
                   
                    if( null == diffContentTmp || diffContentTmp.trim().isEmpty()){
                        continue;
                    }
                    //替换为相对路径
                    File releativeFile = resourceTmp.getProject().getLocation().toFile();
                    String relativeFilePathStr = null;
                    //先计算出相对文件的路径。注意,相对路径的方式与unaddedResources保持一致
                    try {
                        relativeFilePathStr = releativeFile.getCanonicalPath();
                    } catch (IOException e1) {
                        relativeFilePathStr = releativeFile.getAbsolutePath();
                    }
                    if(!relativeFilePathStr.endsWith("/")){
                        relativeFilePathStr+= "/";
                    }
                    relativeFilePathStr = relativeFilePathStr.replace('\\', '/');
                   
                    String relativeRepositoryRootUrlCharset = relativeRepositoryRootUrl;
                    try {
                        relativeFilePathStr = new String(relativeFilePathStr.getBytes(), charsetName)
                        relativeRepositoryRootUrlCharset = new String(relativeRepositoryRootUrlCharset.getBytes(), charsetName);
                    } catch (Exception e) {
                    } 
                   
                    diffContentTmp = diffContentTmp.replaceAll("Index: *"+relativeFilePathStr, "Index: "+relativeRepositoryRootUrlCharset);
                    diffContentTmp = diffContentTmp.replaceAll("--- *"+relativeFilePathStr, "--- "+relativeRepositoryRootUrlCharset);
                    diffContentTmp = diffContentTmp.replaceAll("[+][+][+] *"+relativeFilePathStr, "+++ "+relativeRepositoryRootUrlCharset);

                    StringBuilder diffContentSBTmp = diffContentSBByCharset.get(charsetName);
                    if( null == diffContentSBTmp ){
                        diffContentSBTmp = new StringBuilder();
                    }
                    diffContentSBTmp.append( diffContentTmp );
                    diffContentSBTmp.append( EOL );
                    diffContentSBByCharset.put(charsetName, diffContentSBTmp);
                }
            }

            //最后,构造需要上传的diff文件
            this.fileDiffs = new File[ diffContentSBByCharset.size() ];
            int index = 0;
            for( String charsetNameTmp : diffContentSBByCharset.keySet() ){
                StringBuilder diffContentSBTmp = diffContentSBByCharset.get(charsetNameTmp);
                if( null == diffContentSBTmp || diffContentSBTmp.toString().isEmpty() ){
                    continue;
                }
                this.fileDiffs[ index ] = IOUtils.generateTmpFile( FOLDER_TMP_DIFF, DIFF_SUFFIX);
                IOUtils.saveFile(this.fileDiffs[ index ], diffContentSBTmp.toString(), charsetNameTmp);
                index++;
            }

        } catch (Exception e) {
            throw new InterruptedException(e.getMessage());
        } finally {
            if (newFiles.size() > 0) {
                for (int i = 0; i < newFiles.size(); i++) {
                    IResource resource = (IResource) newFiles.get(i);
                    try {
                        SVNWorkspaceRoot.getSVNResourceFor(resource).revert();
                    } catch (Exception e) {
                    }
                }
            }
            monitor.done();
        }
    }

    public File[] getFileDiffs() {
        return fileDiffs;
    }

    public void setFileDiffs(File[] fileDiffs) {
        this.fileDiffs = fileDiffs;
    }

    public Map<String, StringBuilder> getDiffContentSBByCharset() {
        return diffContentSBByCharset;
    }

   
}
TOP

Related Classes of com.taobao.eclipse.plugin.reviewboard.subclipse.diffoperation.GeneratePreCommitDiffOperation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.