All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nflabs.zeppelin.zan.ZAN Maven / Gradle / Ivy

The newest version!
package com.nflabs.zeppelin.zan;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.log4j.Logger;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.CreateBranchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.StatusCommand;
import org.eclipse.jgit.api.SubmoduleInitCommand;
import org.eclipse.jgit.api.SubmoduleStatusCommand;
import org.eclipse.jgit.api.SubmoduleUpdateCommand;
import org.eclipse.jgit.api.errors.CheckoutConflictException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.submodule.SubmoduleStatus;
import org.eclipse.jgit.submodule.SubmoduleStatusType;

public class ZAN {
	Logger logger = Logger.getLogger(ZAN.class);
	private String localPath;
	private String remotePath;
	private FileSystem dfs;
	private String zanRepo;


	/**
	 * Initialize ZAN with localRepository on local file system
	 * @param localPath
	 */
	public ZAN(String zanRepo, String localPath){
		this(zanRepo, localPath, null, null);
	}
	
	
	/**
	 * Initialize ZAN with localRepository at localPath and syncwith remote path dfsPath
	 * @param zanRepo ZAN catalog repository url. 
	 * @param localPath local path to install zan library
	 * @param remotePath  dfs path to sync, nullable
	 */
	public ZAN(String zanRepo, String localPath, String remotePath, FileSystem dfs){
		this.zanRepo = zanRepo;
		this.localPath = localPath;
		this.remotePath = remotePath;
		this.dfs = dfs;
	}
	
	public void init(ZANProgressMonitor progressListener) throws ZANException{
		String branch = "master";
		String commit = "HEAD";
		File lp = new File(localPath);

		try {
			if (lp.exists()==false) {
				logger.info("Init");
				CloneCommand clone = Git.cloneRepository();
				clone.setURI(zanRepo);
				clone.setDirectory(lp);
				clone.setBranch(branch);
				clone.setNoCheckout(true);
				if(progressListener!=null){
					clone.setProgressMonitor(progressListener);
				}
				
				clone.call();
	
				Git git = Git.open(lp);
				
				// fetch
				git.fetch().call();
	
				git.checkout().setName(branch)
							  .setCreateBranch(true)
							  .setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.SET_UPSTREAM)
							  .setStartPoint("origin/"+branch)
							  .call();
				
				git.reset().setRef(commit)
						   .setMode(ResetType.HARD)
						   .call();
				git.close();
			}
		} catch (GitAPIException e) {
			throw new ZANException(e);
		} catch (IOException e) {
			throw new ZANException(e);
		}
	}
	
	
	public void install(String libraryName, ZANProgressMonitor progressListener) throws ZANException{
		init(null);
		File lp = getLocalLibraryPath(libraryName);
		if (lp.exists()) {
			throw new ZANException(libraryName+" already installed");
		}

		Git git;
		try {
			logger.info("install "+libraryName);
			git = Git.open(new File(localPath));
			SubmoduleInitCommand init = git.submoduleInit();
			init.addPath(libraryName);
			init.call();

			SubmoduleUpdateCommand submoduleUpdate = git.submoduleUpdate();
			submoduleUpdate.addPath(libraryName);
			if(progressListener!=null){
				submoduleUpdate.setProgressMonitor(progressListener);
			}
			Collection ret = submoduleUpdate.call();
			git.close();

			if ( ret==null || ret.isEmpty() || lp.exists()==false) {
				throw new ZANException("Can't update submodule "+libraryName);
			}
			sync(libraryName);
		} catch (Exception e) {
			throw new ZANException(e);
		}
	}
	
	/**
	 * Get information of the library
	 * @param libraryName
	 * @return
	 * @throws ZANException
	 */
	public Info info(String libraryName) throws ZANException{
		init(null);
		Git git;
		try {
			git = Git.open(new File(localPath));

			// git status libraryName
			StatusCommand sc = git.status();
			sc.addPath(libraryName);
			Status st = sc.call();

			boolean updateAvailable = false;

			if(st.getModified().size()>0 ||
			   st.getChanged().size()>0 ||
			   st.getAdded().size()>0 ||
			   st.getRemoved().size()>0){
				updateAvailable = true;
			}

			// git submodule status libraryName
			SubmoduleStatusCommand ssc = git.submoduleStatus();
			ssc.addPath(libraryName);
			Map status = ssc.call();
			if ( status==null || status.size()!=1 ){
				// not in git
				File libDir = new File(localPath, libraryName);
				if (libDir.isDirectory()==false) {
					return null;
				} else {
					return new Info(libraryName, libDir.getAbsolutePath());
				}
			} else {	
				// construct info
				SubmoduleStatus ss = status.get(libraryName);
				boolean installed = (ss.getType()==SubmoduleStatusType.INITIALIZED || ss.getType()==SubmoduleStatusType.REV_CHECKED_OUT) ? true : false;
				String commit = ss.getIndexId().getName();
				String path = ss.getPath();
				git.close();
				Info info = new Info(libraryName, path, installed, updateAvailable, commit);	
				return info;
			}
		} catch (IOException e) {
			throw new ZANException(e);
		} catch (GitAPIException e) {
			throw new ZANException(e);
		}
	}
	
	public List list() throws ZANException{
		init(null);
		List infos = new LinkedList();
		
		Git git;
		try {
			git = Git.open(new File(localPath));
			
			SubmoduleStatusCommand sc = git.submoduleStatus();
			Map status = sc.call();
			
			Set libNames = new HashSet(status.keySet());
			File[] files = new File(localPath).listFiles();
			if (files!=null) {
				for (File file : files) {
					if (file.isDirectory() == false ) continue;
					String name = file.getName();
					if (name==null || name.startsWith(".") ) continue;					
					if (libNames.contains(name) == false ) {
						libNames.add(name);
					}
				}
			}
		
			for(String k : libNames) {
				infos.add(info(k));
			}
			git.close();
		} catch (IOException e) {
			throw new ZANException(e);
		} catch (GitAPIException e) {
			throw new ZANException(e);
		}
		return infos;
	}
	
	public void upgrade(String libraryName, ZANProgressMonitor progressListener) throws ZANException {
		init(null);
		File lp = getLocalLibraryPath(libraryName);
		if (lp.exists() == false) {
			throw new ZANException(libraryName + " not installed");
		}

		Git git;
		try {
			logger.info("upgrade "+libraryName);
			git = Git.open(new File(localPath));
			SubmoduleInitCommand init = git.submoduleInit();
			init.addPath(libraryName);
			init.call();

			SubmoduleUpdateCommand submoduleUpdate = git.submoduleUpdate();
			submoduleUpdate.addPath(libraryName);
			if(progressListener!=null){
				submoduleUpdate.setProgressMonitor(progressListener);
			}
			Collection ret = submoduleUpdate.call();
			git.close();

			if ( ret==null || ret.isEmpty() || lp.exists()==false) {
				throw new ZANException("Can't update submodule "+libraryName);
			}
			sync(libraryName);
		} catch (Exception e) {
			throw new ZANException(e);
		}
	}

	/**
	 * Remove library
	 * @param libraryName
	 * @throws ZANException
	 */
	public void uninstall(String libraryName) throws ZANException{
		init(null);
		logger.info("uninstall "+libraryName);
		File lp = getLocalLibraryPath(libraryName);
		if (lp.exists()==false) {
			throw new ZANException("library "+libraryName+" not installed");
		}
		
		deleteRecursive(lp);
		sync(libraryName);
	}


	/**
	 * Update zan repository catalog
	 * @throws ZANException 
	 */
	public void update() throws ZANException{
		update(null);
	}
	
	/**
	 * Update zan repository catalog
	 * @throws ZANException 
	 */
	public void update(ZANProgressMonitor progressListener) throws ZANException{
		String branch = "master";
		File lp = new File(localPath);
		try {
			logger.info("update");
			if (lp.exists()==false) {
				init(null);
			} else {
				Git git = Git.open(lp);

				// fetch
				git.fetch().setRemote("origin").call();
				git.rebase().setUpstream("origin/"+branch)
						    .call();
				git.close();
				/*
				git.reset().setRef(commit)
						   .setMode(ResetType.HARD)
						   .call();
						   */
			}
		} catch (GitAPIException e) {
			throw new ZANException(e);
		} catch (IOException e) {
			throw new ZANException(e);
		}			
	}
	
	
	
	private void deleteRecursive(File f){
		if(f.isDirectory()){
			for(File c : f.listFiles()){
				deleteRecursive(c);
			}
			
			f.delete();
		} else if(f.isFile()){
			f.delete();
		}
	}
	
	private File getLocalLibraryPath(String libraryName){
		return new File(localPath+"/"+libraryName);
	}
	
	private Path getRemoteLibraryPath(String libraryName){
		return new Path(remotePath+"/"+libraryName);
	}
	
	public Map> sync(String libraryName) throws ZANException{
		return sync(libraryName, "/");
	}
	
	private Map> sync(String libraryName, String relativePath) throws ZANException{
		Map> changes = new HashMap>();
		changes.put("added", new LinkedList());
		changes.put("modified", new LinkedList());
		changes.put("removed", new LinkedList());
		
		if (syncDfs()==false) return changes;
		
		File local = getLocalLibraryPath(libraryName+relativePath);
		Path remote = getRemoteLibraryPath(libraryName+relativePath);
		try {
			if (local.exists()==false) { // local not exists, delete remote, too				
				if (dfs.exists(remote)) {
					dfs.delete(remote, true);
					changes.get("removed").add(remote.toString());
				}
			} else if (local.isFile()) { // file
				if (dfs.exists(remote) && dfs.isFile(remote)==false) { // remote is dir
					dfs.delete(remote, true);
					changes.get("removed").add(remote.toString());
				}
				
				if (dfs.exists(remote)) {
					FileStatus remoteStatus = dfs.getFileStatus(remote);
					if(local.length() != remoteStatus.getLen() ||
					   local.lastModified() != remoteStatus.getModificationTime()){
						dfs.delete(remote, true);
						changes.get("modified").add(remote.toString());
						dfs.copyFromLocalFile(new Path(local.getAbsolutePath()), remote);
					}
				} else {
					changes.get("added").add(remote.toString());
					dfs.copyFromLocalFile(new Path(local.getAbsolutePath()), remote);					
				}				
			} else { // directory
				if (dfs.exists(remote)) {
					if (dfs.isFile(remote)) {
						dfs.delete(remote, true);
						changes.get("removed").add(remote.toString());
					}
				} else {
					changes.get("added").add(remote.toString());
					dfs.mkdirs(remote);
				}
				
				File[] files = local.listFiles();
				if(files==null) return changes;
				for(File f : files){
					if(f.getName().startsWith(".")) continue;
					Map> ch = sync(libraryName, relativePath+"/"+f.getName());
					changes.get("added").addAll(ch.get("added"));
					changes.get("removed").addAll(ch.get("removed"));
					changes.get("modified").addAll(ch.get("modified"));
				}
	
				// delete removed files
				FileStatus[] dfsFiles = dfs.listStatus(remote);
				if (dfsFiles!=null) {
					for (FileStatus dfsFile : dfsFiles) {
						boolean delete = true;
						if (files!=null) {
							for (File f : files) {
								if (f.getName().equals(dfsFile.getPath().getName())) {
									delete = false;
								}
							}
						}
						if(delete==true){
							dfs.delete(dfsFile.getPath(), true);
							changes.get("removed").add(dfsFile.toString());
						}
					}
				}
					
			}
		} catch (IOException e) {
			throw new ZANException(e);
		}
		return changes;
	}
	
	public boolean syncDfs(){
		return (dfs!=null && remotePath!=null);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy