/* license-start * * Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details, at <http://www.gnu.org/licenses/>. * * Contributors: * Crispico - Initial API and implementation * * license-end */ package org.flowerplatform.web.git; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jgit.api.CloneCommand; import org.eclipse.jgit.api.FetchCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.LsRemoteCommand; import org.eclipse.jgit.api.PushCommand; import org.eclipse.jgit.api.ResetCommand.ResetType; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache; import org.eclipse.jgit.lib.RepositoryCache.FileKey; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.storage.file.FileRepository; import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.TagOpt; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.util.FS; import org.flowerplatform.common.CommonPlugin; import org.flowerplatform.common.util.Pair; import org.flowerplatform.communication.CommunicationPlugin; import org.flowerplatform.communication.command.DisplaySimpleMessageClientCommand; import org.flowerplatform.communication.progress_monitor.ProgressMonitor; import org.flowerplatform.communication.service.InvokeServiceMethodServerCommand; import org.flowerplatform.communication.service.ServiceInvocationContext; import org.flowerplatform.communication.stateful_service.InvokeStatefulServiceMethodServerCommand; import org.flowerplatform.communication.stateful_service.RemoteInvocation; import org.flowerplatform.communication.tree.NodeInfo; import org.flowerplatform.communication.tree.remote.GenericTreeStatefulService; import org.flowerplatform.communication.tree.remote.PathFragment; import org.flowerplatform.web.git.explorer.entity.RefNode; import org.flowerplatform.web.git.explorer.entity.RemoteNode; import org.flowerplatform.web.git.operation.CheckoutOperation; import org.flowerplatform.web.git.operation.CommitOperation; import org.flowerplatform.web.git.operation.MergeOperation; import org.flowerplatform.web.git.operation.PullOperation; import org.flowerplatform.web.git.operation.RebaseOperation; import org.flowerplatform.web.git.operation.ResetOperation; import org.flowerplatform.web.git.remote.OpenGitCredentialsWindowClientCommand; import org.flowerplatform.web.git.remote.dto.CommitPageDto; import org.flowerplatform.web.git.remote.dto.CommitResourceDto; import org.flowerplatform.web.git.remote.dto.ConfigBranchPageDto; import org.flowerplatform.web.git.remote.dto.ConfigFetchPushPageDto; import org.flowerplatform.web.git.remote.dto.GitActionDto; import org.flowerplatform.web.git.remote.dto.GitRef; import org.flowerplatform.web.git.remote.dto.ImportProjectPageDto; import org.flowerplatform.web.git.remote.dto.ProjectDto; import org.flowerplatform.web.git.remote.dto.RemoteConfig; import org.flowerplatform.web.projects.remote.ProjectsService; import org.flowerplatform.web.security.sandbox.FlowerWebPrincipal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Cristina Constantinescu */ public class GitService { private static Logger logger = LoggerFactory.getLogger(GitService.class); private static final String SERVICE_ID = "gitService"; /** * Keeps the {@link InvokeStatefulServiceMethodServerCommand command} that needs authentication data before * in order to be executed. * * <p> * The GIT operations that need authentications are clone/fetch/push. * * @see #openLoginWindow() */ public static final ThreadLocal<InvokeServiceMethodServerCommand> tlCommand = new ThreadLocal<InvokeServiceMethodServerCommand>(); /** * Keeps the repository URI for GIT authentication. * * @see GitUsernamePasswordCredentialsProvider#get() * @see #openLoginWindow() */ public static final ThreadLocal<String> tlURI = new ThreadLocal<String>(); public static GitService getInstance() { return (GitService) CommunicationPlugin.getInstance().getServiceRegistry().getService(SERVICE_ID); } private void dispatchContentUpdate(Object node) { for (GenericTreeStatefulService service : GitPlugin.getInstance().getTreeStatefulServicesDisplayingGitContent()) { service.dispatchContentUpdate(node); } } private void dispatchLabelUpdate(Object node, String nodeType) { for (GenericTreeStatefulService service : GitPlugin.getInstance().getTreeStatefulServicesDisplayingGitContent()) { service.dispatchLabelUpdate(node, nodeType); } } public Repository getRepository(NodeInfo nodeInfo) { if (nodeInfo == null) { return null; } if (nodeInfo.getNode() instanceof File && GitUtils.GIT_REPOSITORIES_NAME.equals(((File) nodeInfo.getNode()).getName())) { return null; } if (nodeInfo.getNode() instanceof Repository) { return (Repository) nodeInfo.getNode(); } return getRepository(nodeInfo.getParent()); } /** * Sends command to client to open the login window * based on the info stored in {@link #tlCommand}. */ public void openLoginWindow() { InvokeServiceMethodServerCommand cmd = tlCommand.get(); cmd.getParameters().remove(0); cmd.getCommunicationChannel().appendOrSendCommand( new OpenGitCredentialsWindowClientCommand( tlURI.get().toString(), cmd)); } @RemoteInvocation public List<Object> getBranches(ServiceInvocationContext context, String repositoryUrl) { tlCommand.set((InvokeServiceMethodServerCommand) context.getCommand()); Repository db = null; try { URIish uri = new URIish(repositoryUrl.trim()); db = new FileRepository(new File("/tmp")); Git git = new Git(db); LsRemoteCommand rc = git.lsRemote(); rc.setRemote(uri.toString()).setTimeout(30); Collection<Ref> remoteRefs = rc.call(); List<GitRef> branches = new ArrayList<GitRef>(); Ref idHEAD = null; for (Ref r: remoteRefs) { if (r.getName().equals(Constants.HEAD)) { idHEAD = r; } } Ref head = null; boolean headIsMaster = false; String masterBranchRef = Constants.R_HEADS + Constants.MASTER; for (Ref r : remoteRefs) { String n = r.getName(); if (!n.startsWith(Constants.R_HEADS)) continue; branches.add(new GitRef(n, Repository.shortenRefName(n))); if (idHEAD == null || headIsMaster) continue; if (r.getObjectId().equals(idHEAD.getObjectId())) { headIsMaster = masterBranchRef.equals(r.getName()); if (head == null || headIsMaster) head = r; } } Collections.sort(branches, new Comparator<GitRef>() { public int compare(GitRef r1, GitRef r2) { return r1.getShortName().compareTo(r2.getShortName()); } }); if (idHEAD != null && head == null) { head = idHEAD; branches.add(0, new GitRef(idHEAD.getName(), Repository.shortenRefName(idHEAD.getName()))); } GitRef headRef = head != null ? new GitRef(head.getName(), Repository.shortenRefName(head.getName())) : null; return Arrays.asList(new Object[] {branches, headRef}); } catch (JGitInternalException | GitAPIException e) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), GitPlugin.getInstance().getMessage("git.cloneWizard.branch.cannotListBranches") + "\n" + e.getCause().getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); } catch (IOException e) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), GitPlugin.getInstance().getMessage("git.cloneWizard.branch.cannotCreateTempRepo"), DisplaySimpleMessageClientCommand.ICON_ERROR)); } catch (URISyntaxException e) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getReason(), DisplaySimpleMessageClientCommand.ICON_ERROR)); } catch (Exception e) { if (GitPlugin.getInstance().getUtils().isAuthentificationException(e)) { openLoginWindow(); return null; } logger.debug(CommonPlugin.getInstance().getMessage("error"), e); } finally { if (db != null) { db.close(); } } return null; } /** * Verifies if repository URL is valid. * @return * <ul> * <li> 1 -> repository already exists * <li> -1 -> repository not OK * <li> 0 -> repository OK * </ul> */ @RemoteInvocation public Object validateRepositoryURL(ServiceInvocationContext context, List<PathFragment> selectedPath, String url) { try { @SuppressWarnings("unchecked") Pair<File, Object> node = (Pair<File, Object>) GenericTreeStatefulService.getNodeByPathFor(selectedPath, null); String repoName = new URIish(url.trim()).getHumanishName(); File gitReposFile = GitPlugin.getInstance().getUtils().getGitRepositoriesFile(node.a); if (new File(gitReposFile, repoName).exists()) { return 1; } } catch (URISyntaxException e) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getReason(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return -1; } return 0; } @RemoteInvocation public boolean cloneRepository(final ServiceInvocationContext context, List<PathFragment> selectedPath, String repositoryUrl, final List<String> selectedBranches, final String remoteName, final boolean cloneAllBranches) { tlCommand.set((InvokeServiceMethodServerCommand) context.getCommand()); final URIish uri; try { uri = new URIish(repositoryUrl.trim()); } catch (URISyntaxException e) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getReason(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } @SuppressWarnings("unchecked") final Pair<File, Object> node = (Pair<File, Object>) GenericTreeStatefulService.getNodeByPathFor(selectedPath, null); File gitReposFile = GitPlugin.getInstance().getUtils().getGitRepositoriesFile(node.a); final File mainRepo = GitPlugin.getInstance().getUtils().getMainRepositoryFile(new File(gitReposFile, uri.getHumanishName()), true); final ProgressMonitor monitor =ProgressMonitor.create( GitPlugin.getInstance().getMessage("git.clone.monitor.title", uri), context.getCommunicationChannel()); monitor.beginTask(GitPlugin.getInstance().getMessage("git.clone.monitor.title", uri), 2); Job job = new Job(MessageFormat.format(GitPlugin.getInstance().getMessage("git.clone.monitor.title", uri), uri)) { @Override protected IStatus run(IProgressMonitor m) { Repository repository = null; try { CloneCommand cloneRepository = Git.cloneRepository(); cloneRepository.setNoCheckout(true); cloneRepository.setDirectory(mainRepo); cloneRepository.setProgressMonitor(new GitProgressMonitor(new SubProgressMonitor(monitor, 1))); cloneRepository.setRemote(remoteName); cloneRepository.setURI(uri.toString()); cloneRepository.setTimeout(30); cloneRepository.setCloneAllBranches(cloneAllBranches); cloneRepository.setCloneSubmodules(false); if (selectedBranches.size() > 0) { cloneRepository.setBranchesToClone(selectedBranches); } Git git = cloneRepository.call(); repository = git.getRepository(); // notify clients about changes dispatchContentUpdate(node); monitor.worked(1); } catch (Exception e) { if (repository != null) repository.close(); GitPlugin.getInstance().getUtils().delete(mainRepo.getParentFile()); if (monitor.isCanceled()) { return Status.OK_STATUS; } if (GitPlugin.getInstance().getUtils().isAuthentificationException(e)) { openLoginWindow(); return Status.OK_STATUS; } logger.debug(GitPlugin.getInstance().getMessage("git.cloneWizard.error", new Object[] {mainRepo.getName()}), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), GitPlugin.getInstance().getMessage("git.cloneWizard.error", new Object[] {mainRepo.getName()}), DisplaySimpleMessageClientCommand.ICON_ERROR)); return Status.CANCEL_STATUS; } finally { monitor.done(); if (repository != null) { repository.close(); } } return Status.OK_STATUS; } }; job.schedule(); return true; } public void deleteRepository(ServiceInvocationContext context, List<PathFragment> selectedNode) { Repository repository = (Repository) GenericTreeStatefulService.getNodeByPathFor(selectedNode, null); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(selectedNode); NodeInfo repositoryNodeInfo = service.getVisibleNodes().get(repository); ProgressMonitor monitor = ProgressMonitor.create( GitPlugin.getInstance().getMessage("git.deleteRepo.monitor.title"), context.getCommunicationChannel()); try { monitor.beginTask(GitPlugin.getInstance().getMessage("git.deleteRepo.monitor.message", new Object[] {GitPlugin.getInstance().getUtils().getRepositoryName(repository)}), 2); repository.getObjectDatabase().close(); repository.getRefDatabase().close(); // delete repositories from cache File[] children = repository.getDirectory().getParentFile().getParentFile().listFiles(); for (File child : children) { Repository repo = GitPlugin.getInstance().getUtils().getRepository(child); RepositoryCache.close(repo); } monitor.worked(1); // delete repository files File repoFile = repository.getDirectory().getParentFile().getParentFile(); if (GitUtils.GIT_REPOSITORIES_NAME.equals(repoFile.getParentFile().getName())) { GitPlugin.getInstance().getUtils().delete(repoFile); } monitor.worked(1); dispatchContentUpdate(repositoryNodeInfo.getParent().getNode()); } catch (Exception e) { logger.debug(GitPlugin.getInstance().getMessage("git.deleteRepo.error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), GitPlugin.getInstance().getMessage("git.deleteRepo.error"), DisplaySimpleMessageClientCommand.ICON_ERROR)); } finally { monitor.done(); } } @RemoteInvocation public GitActionDto getNodeAdditionalData(ServiceInvocationContext context, List<PathFragment> path) { try { RefNode refNode = (RefNode) GenericTreeStatefulService.getNodeByPathFor(path, null); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(path); NodeInfo refNodeInfo = service.getVisibleNodes().get(refNode); Repository repository = getRepository(refNodeInfo); if (repository == null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), "Cannot find repository for node " + refNode, DisplaySimpleMessageClientCommand.ICON_ERROR)); return null; } GitActionDto data = new GitActionDto(); data.setRepository(repository.getDirectory().getAbsolutePath()); data.setBranch(repository.getBranch()); return data; } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), path, e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); } return null; } public boolean merge(ServiceInvocationContext context, String repositoryLocation, String refName, boolean squash) { try { Repository repo = RepositoryCache.open(FileKey.exact(new File(repositoryLocation), FS.DETECTED)); MergeOperation op = new MergeOperation(repo, refName, squash, context.getCommunicationChannel()); op.execute(); String result = GitPlugin.getInstance().getUtils().handleMergeResult(op.getMergeResult()); if (result != null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( GitPlugin.getInstance().getMessage("git.merge.result"), result, DisplaySimpleMessageClientCommand.ICON_INFORMATION)); } return true; } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } public boolean rebase(ServiceInvocationContext context, String repositoryLocation, String refName) { try { Repository repo = RepositoryCache.open(FileKey.exact(new File(repositoryLocation), FS.DETECTED)); if (!repo.getFullBranch().startsWith(Constants.R_HEADS)) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), GitPlugin.getInstance().getMessage("git.rebase.noLocalBranch"), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } RebaseOperation op = new RebaseOperation(repo, refName, context.getCommunicationChannel()); op.execute(); String result = op.handleRebaseResult(); if (result != null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( GitPlugin.getInstance().getMessage("git.rebase.result"), result, DisplaySimpleMessageClientCommand.ICON_INFORMATION)); } return true; } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } @RemoteInvocation public boolean reset(ServiceInvocationContext context, String repositoryLocation, String targetName, int resetType) { try { Repository repo = RepositoryCache.open(FileKey.exact(new File(repositoryLocation), FS.DETECTED)); ResetType type; switch (resetType) { case 0: type = ResetType.SOFT; break; case 1: type = ResetType.MIXED; break; default: type = ResetType.HARD; } new ResetOperation(repo, targetName, type, context.getCommunicationChannel()).execute(); } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } return true; } @RemoteInvocation public boolean configRemote(ServiceInvocationContext context, List<PathFragment> path, RemoteConfig remoteConfig) { try { Object node = GenericTreeStatefulService.getNodeByPathFor(path, null); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(path); NodeInfo nodeInfo = service.getVisibleNodes().get(node); Repository repository = getRepository(nodeInfo); org.eclipse.jgit.transport.RemoteConfig repoConfig = new org.eclipse.jgit.transport.RemoteConfig(repository.getConfig(), remoteConfig.getName()); while (repoConfig.getURIs().size() > 0) { URIish uri = repoConfig.getURIs().get(0); repoConfig.removeURI(uri); } repoConfig.addURI(new URIish(remoteConfig.getUri().trim())); repoConfig.update(repository.getConfig()); repository.getConfig().save(); // notify clients about changes dispatchContentUpdate(node); return true; } catch (URISyntaxException e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), path, e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getReason(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), path, e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } @RemoteInvocation public RemoteConfig getRemoteConfigData(ServiceInvocationContext context, List<PathFragment> path) { try { RemoteNode remoteNode = (RemoteNode) GenericTreeStatefulService.getNodeByPathFor(path, null); Repository repository = remoteNode.getRepository(); if (repository == null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), "Cannot find repository for node " + remoteNode, DisplaySimpleMessageClientCommand.ICON_ERROR)); return null; } org.eclipse.jgit.transport.RemoteConfig repoConfig = new org.eclipse.jgit.transport.RemoteConfig(repository.getConfig(), remoteNode.getRemote()); RemoteConfig result = new RemoteConfig(); result.setName(remoteNode.getRemote()); result.setUri(repoConfig.getURIs().get(0).toString()); List<String> fetchSpecs = new ArrayList<String>(); for (RefSpec refspec : repoConfig.getFetchRefSpecs()) { fetchSpecs.add(refspec.toString()); } result.setFetchMappings(fetchSpecs); List<String> pushSpecs = new ArrayList<String>(); for (RefSpec refspec : repoConfig.getPushRefSpecs()) { pushSpecs.add(refspec.toString()); } result.setPushMappings(pushSpecs); return result; } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), path, e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return null; } } @RemoteInvocation public boolean deleteRemote(ServiceInvocationContext context, List<PathFragment> path) { try { RemoteNode remoteNode = (RemoteNode) GenericTreeStatefulService.getNodeByPathFor(path, null); Repository repository = remoteNode.getRepository(); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(path); NodeInfo remoteNodeInfo = service.getVisibleNodes().get(remoteNode); if (repository == null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), "Cannot find repository for node " + remoteNode, DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } StoredConfig config = repository.getConfig(); config.unsetSection("remote", remoteNode.getRemote()); config.save(); dispatchContentUpdate(remoteNodeInfo.getParent().getNode()); return true; } catch (Exception e) { logger.debug(GitPlugin.getInstance().getMessage("git.deleteRemote.error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), GitPlugin.getInstance().getMessage("git.deleteRemote.error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } @RemoteInvocation public ConfigFetchPushPageDto getFetchPushConfigData(ServiceInvocationContext context, List<PathFragment> path, boolean getFetchData) { try { Repository repository = (Repository) GenericTreeStatefulService.getNodeByPathFor(path, null); ConfigFetchPushPageDto result = new ConfigFetchPushPageDto(); List<RemoteConfig> list = new ArrayList<RemoteConfig>(); List<org.eclipse.jgit.transport.RemoteConfig> remotes = org.eclipse.jgit.transport.RemoteConfig.getAllRemoteConfigs(repository.getConfig()); for (org.eclipse.jgit.transport.RemoteConfig remote : remotes) { RemoteConfig remoteConfig = new RemoteConfig(); remoteConfig.setName(remote.getName()); remoteConfig.setUri(remote.getURIs().get(0).toString()); if (getFetchData) { List<String> fetchSpecs = new ArrayList<String>(); for (RefSpec refspec : remote.getFetchRefSpecs()) { fetchSpecs.add(refspec.toString()); } remoteConfig.setFetchMappings(fetchSpecs); } else { List<String> pushSpecs = new ArrayList<String>(); for (RefSpec refspec : remote.getPushRefSpecs()) { pushSpecs.add(refspec.toString()); } remoteConfig.setPushMappings(pushSpecs); } list.add(remoteConfig); } result.setRemoteConfigs(list); return result; } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), path, e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return null; } } @RemoteInvocation public boolean fetch(ServiceInvocationContext context, List<PathFragment> path, RemoteConfig fetchConfig) { tlCommand.set((InvokeServiceMethodServerCommand) context.getCommand()); ProgressMonitor monitor = ProgressMonitor.create(GitPlugin.getInstance().getMessage("git.fetch.monitor.title"), context.getCommunicationChannel()); try { Object node = GenericTreeStatefulService.getNodeByPathFor(path, null); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(path); NodeInfo nodeInfo = service.getVisibleNodes().get(node); Repository repository = getRepository(nodeInfo); if (repository == null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), "Cannot find repository for node " + node, DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } String remote = null; if (GitNodeType.NODE_TYPE_REMOTE.equals(nodeInfo.getPathFragment().getType())) { remote = ((RemoteNode) node).getRemote(); } GitProgressMonitor gitMonitor = new GitProgressMonitor(monitor); FetchCommand command; if (remote != null) { command = new Git(repository).fetch().setRemote(remote); } else { List<RefSpec> specs = new ArrayList<RefSpec>(); for (String refMapping : fetchConfig.getFetchMappings()) { specs.add(new RefSpec(refMapping)); } command = new Git(repository).fetch().setRemote(new URIish(fetchConfig.getUri()).toPrivateString()).setRefSpecs(specs); } command.setProgressMonitor(gitMonitor); command.setTagOpt(TagOpt.FETCH_TAGS); FetchResult fetchResult = command.call(); dispatchContentUpdate(node); context.getCommunicationChannel().appendOrSendCommand(new DisplaySimpleMessageClientCommand( GitPlugin.getInstance().getMessage("git.fetch.result"), GitPlugin.getInstance().getUtils().handleFetchResult(fetchResult), DisplaySimpleMessageClientCommand.ICON_INFORMATION)); return true; } catch (Exception e) { if (GitPlugin.getInstance().getUtils().isAuthentificationException(e)) { openLoginWindow(); return true; } logger.debug(GitPlugin.getInstance().getMessage("git.fetch.error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } finally { monitor.done(); } } public boolean pushToUpstreamInternal(ServiceInvocationContext context, Repository repository, RemoteConfig pushConfig, String remote) { ProgressMonitor monitor = ProgressMonitor.create(GitPlugin.getInstance().getMessage("git.push.monitor.title"), context.getCommunicationChannel()); try { if (repository == null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), "Cannot find repository " + repository, DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } GitProgressMonitor gitMonitor = new GitProgressMonitor(monitor); PushCommand command; if (remote != null) { command = new Git(repository).push().setRemote(remote); } else { List<RefSpec> specs = new ArrayList<RefSpec>(); for (String refMapping : pushConfig.getPushMappings()) { specs.add(new RefSpec(refMapping)); } command = new Git(repository).push().setRemote(new URIish(pushConfig.getUri()).toPrivateString()).setRefSpecs(specs); } command.setProgressMonitor(gitMonitor); command.setCredentialsProvider(new GitUsernamePasswordCredentialsProvider()); Iterable<PushResult> resultIterable = command.call(); PushResult pushResult = resultIterable.iterator().next(); context.getCommunicationChannel().appendOrSendCommand(new DisplaySimpleMessageClientCommand( GitPlugin.getInstance().getMessage("git.push.result"), GitPlugin.getInstance().getUtils().handlePushResult(pushResult), DisplaySimpleMessageClientCommand.ICON_INFORMATION)); return true; } catch (Exception e) { if (GitPlugin.getInstance().getUtils().isAuthentificationException(e)) { openLoginWindow(); return true; } logger.debug(GitPlugin.getInstance().getMessage("git.push.error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } finally { monitor.done(); } } @RemoteInvocation public boolean push(ServiceInvocationContext context, List<PathFragment> path, RemoteConfig pushConfig) { tlCommand.set((InvokeServiceMethodServerCommand) context.getCommand()); Object node = GenericTreeStatefulService.getNodeByPathFor(path, null); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(path); NodeInfo nodeInfo = service.getVisibleNodes().get(node); Repository repository = getRepository(nodeInfo); String remote = null; if (GitNodeType.NODE_TYPE_REMOTE.equals(nodeInfo.getPathFragment().getType())) { remote = ((RemoteNode) node).getRemote(); } return pushToUpstreamInternal(context, repository, pushConfig, remote); } @RemoteInvocation public boolean pushToUpstream(ServiceInvocationContext context, String repositoryLocation) { tlCommand.set((InvokeServiceMethodServerCommand) context.getCommand()); // push Repository repository = GitPlugin.getInstance().getUtils().getRepository(new File(repositoryLocation)); if (repository == null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), "Cannot find repository " + repository, DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } try { Object[] data = GitPlugin.getInstance().getUtils().getFetchPushUpstreamDataRefSpecAndRemote(repository); RemoteConfig pushConfig = new RemoteConfig(); List<String>refSpecs = new ArrayList<String>(); refSpecs.add(String.format("+%s:%s", data[0], data[1])); pushConfig.setPushMappings(refSpecs); pushConfig.setUri((String) data[2]); return pushToUpstreamInternal(context, repository, pushConfig, null); } catch (Exception e) { logger.debug(GitPlugin.getInstance().getMessage("git.push.error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); } return false; } @RemoteInvocation public boolean checkout(ServiceInvocationContext context, List<PathFragment> path, String name, GitRef upstreamBranch, RemoteConfig remote, boolean rebase) { Object node =GenericTreeStatefulService.getNodeByPathFor(path, null); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(path); NodeInfo nodeInfo = service.getVisibleNodes().get(node); Repository repository = getRepository(nodeInfo); boolean result = new CheckoutOperation(node, repository, name, remote, upstreamBranch, rebase, context.getCommunicationChannel()).execute(); if (result) { for (NodeInfo repoChildNodeInfo : service.getVisibleNodes().get(repository).getChildren()) { if (GitNodeType.NODE_TYPE_LOCAL_BRANCHES.equals(repoChildNodeInfo.getPathFragment().getType()) || GitNodeType.NODE_TYPE_WDIRS.equals(repoChildNodeInfo.getPathFragment().getType()) || GitNodeType.NODE_TYPE_REMOTE_BRANCHES.equals(repoChildNodeInfo.getPathFragment().getType())) { dispatchContentUpdate(repoChildNodeInfo.getNode()); } } } return result; } @RemoteInvocation public ImportProjectPageDto getProjects(ServiceInvocationContext context, List<PathFragment> path) { try { List<String> directories = new ArrayList<String>(); List<File> files = new ArrayList<File>(); @SuppressWarnings("unchecked") Pair<File, String> node = (Pair<File, String>) GenericTreeStatefulService.getNodeByPathFor(path, null); Repository repo = GitPlugin.getInstance().getUtils().getRepository(node.a); GitPlugin.getInstance().getUtils().findProjectFiles(files, repo.getWorkTree(), null); List<ProjectDto> projects = new ArrayList<ProjectDto>(); for (File projectSystemFile : files) { // project path IPath projPath = new Path(projectSystemFile.getParentFile().getCanonicalPath()); String projectName = projPath.lastSegment(); File repoFile = repo.getDirectory().getParentFile().getParentFile(); String projectRelativeLocation = projPath.makeRelativeTo(new Path(repoFile.getAbsolutePath())).toString(); ProjectDto dto = new ProjectDto(); dto.setName(projectName + " (" + projectRelativeLocation + ")"); dto.setLocation(projPath.toString()); projects.add(dto); } ImportProjectPageDto result = new ImportProjectPageDto(); result.setExistingProjects(projects); result.setSelectedFolders(directories); return result; } catch (Exception e) { logger.debug(GitPlugin.getInstance().getMessage("git.page.populate.error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), GitPlugin.getInstance().getMessage("git.page.populate.error"), DisplaySimpleMessageClientCommand.ICON_ERROR)); return null; } } public boolean importProjects(ServiceInvocationContext context, List<ProjectDto> projects) { try { for (ProjectDto dto : projects) { File file = new File(dto.getLocation()); ProjectsService.getInstance().createOrImportProjectFromFile(context, file); } return true; } catch (Exception e) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } @RemoteInvocation public boolean pull(ServiceInvocationContext context, List<PathFragment> path) { tlCommand.set((InvokeServiceMethodServerCommand) context.getCommand()); try { RefNode refNode = (RefNode) GenericTreeStatefulService.getNodeByPathFor(path, null); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(path); NodeInfo refNodeInfo = service.getVisibleNodes().get(refNode); Repository repository = getRepository(refNodeInfo); if (repository == null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), "Cannot find repository for node " + refNode, DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } File mainRepoFile = repository.getDirectory().getParentFile(); File wdirFile = new File(mainRepoFile.getParentFile(), GitUtils.WORKING_DIRECTORY_PREFIX + Repository.shortenRefName(refNode.getRef().getName())); if (!wdirFile.exists()) { return false; } new PullOperation(refNode.getRef(), GitPlugin.getInstance().getUtils().getRepository(wdirFile), context.getCommunicationChannel()).execute(); return true; } catch (Exception e) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } @RemoteInvocation public CommitPageDto getCommitData(ServiceInvocationContext context, List<List<PathFragment>> paths) { List<File> files = new ArrayList<File>(); for (List<PathFragment> path : paths) { @SuppressWarnings("unchecked") Pair<File, String> node = (Pair<File, String>) GenericTreeStatefulService.getNodeByPathFor(path, null); files.add(node.a); } return new CommitOperation(context.getCommunicationChannel(), files).getPageDto(); } @RemoteInvocation public boolean commit(ServiceInvocationContext context, String repositoryLocation, List<CommitResourceDto> files, String author, String committer, String message, boolean amending) { return new CommitOperation(context.getCommunicationChannel()).commit(repositoryLocation, files, author, committer, message, amending); } @RemoteInvocation public List<RemoteConfig> getAllRemotes(ServiceInvocationContext context, List<PathFragment> path) { try { Object node = GenericTreeStatefulService.getNodeByPathFor(path, null); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(path); NodeInfo nodeInfo = service.getVisibleNodes().get(node); Repository repository = getRepository(nodeInfo); List<RemoteConfig> list = new ArrayList<RemoteConfig>(); List<org.eclipse.jgit.transport.RemoteConfig> remotes = org.eclipse.jgit.transport.RemoteConfig.getAllRemoteConfigs(repository.getConfig()); for (org.eclipse.jgit.transport.RemoteConfig remote : remotes) { RemoteConfig remoteConfig = new RemoteConfig(); remoteConfig.setName(remote.getName()); remoteConfig.setUri(remote.getURIs().get(0).toString()); list.add(remoteConfig); } return list; } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), path, e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return null; } } @RemoteInvocation public ConfigBranchPageDto getConfigBranchData(ServiceInvocationContext context, List<PathFragment> path) { try { RefNode node = (RefNode) GenericTreeStatefulService.getNodeByPathFor(path, null); Repository repository = node.getRepository(); StoredConfig config = repository.getConfig(); ConfigBranchPageDto dto = new ConfigBranchPageDto(); Ref branch = (Ref) node.getRef(); dto.setRef(new GitRef(branch.getName(), Repository.shortenRefName(branch.getName()))); List<RemoteConfig> remotes = getAllRemotes(context, path); String branchName = branch.getName().substring(Constants.R_HEADS.length()); String branchConfig = config.getString( ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_MERGE); String remoteConfig = config.getString( ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REMOTE); if (remoteConfig == null) { remoteConfig = ""; } if (remotes != null) { dto.setRemotes(remotes); for (RemoteConfig remote : remotes) { if (remote.getName().equals(remoteConfig)) { List<Object> branches = getBranches(context, remote.getUri()); if (branches != null) { @SuppressWarnings("unchecked") List<GitRef> refs = (List<GitRef>) branches.get(0); for (GitRef ref : refs) { if (ref.getName().equals(branchConfig)) { dto.setSelectedRef(ref); break; } } dto.setRefs(refs); } dto.setSelectedRemote(remote); break; } } } boolean rebaseFlag = config.getBoolean( ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REBASE, false); dto.setRebase(rebaseFlag); return dto; } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), path, e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return null; } } @RemoteInvocation public boolean configBranch(ServiceInvocationContext context, List<PathFragment> path, GitRef upstreamBranch, RemoteConfig remote, boolean rebase) { try { RefNode node = (RefNode) GenericTreeStatefulService.getNodeByPathFor(path, null); Repository repository = node.getRepository(); StoredConfig config = repository.getConfig(); Ref ref; if (node instanceof Ref) { ref = node.getRef(); } else { // get remote branch String dst = Constants.R_REMOTES + remote.getName(); String remoteRefName = dst + "/" + upstreamBranch.getShortName(); ref = repository.getRef(remoteRefName); if (ref == null) { // doesn't exist, fetch it RefSpec refSpec = new RefSpec(); refSpec = refSpec.setForceUpdate(true); refSpec = refSpec.setSourceDestination(upstreamBranch.getName(), remoteRefName); new Git(repository).fetch() .setRemote(new URIish(remote.getUri()).toPrivateString()) .setRefSpecs(refSpec) .call(); ref = repository.getRef(remoteRefName); } } String branchName = node.getRef().getName().substring(Constants.R_HEADS.length()); if (upstreamBranch.getName().length() > 0) { config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_MERGE, upstreamBranch.getName()); } else { config.unset(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_MERGE); } if (remote.getName().length() > 0) { config.setString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REMOTE, remote.getName()); } else { config.unset(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REMOTE); } if (rebase) { config.setBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REBASE, true); } else { config.unset(ConfigConstants.CONFIG_BRANCH_SECTION, branchName, ConfigConstants.CONFIG_KEY_REBASE); } config.save(); return true; } catch (Exception e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), path, e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } @RemoteInvocation public boolean deleteBranch(ServiceInvocationContext context, List<PathFragment> path) { try { RefNode node = (RefNode) GenericTreeStatefulService.getNodeByPathFor(path, null); GenericTreeStatefulService service = GenericTreeStatefulService.getServiceFromPathWithRoot(path); NodeInfo nodeInfo = service.getVisibleNodes().get(node); Repository repository = node.getRepository(); Git git = new Git(repository); git.branchDelete(). setBranchNames(node.getRef().getName()). setForce(true). call(); // delete working directory String branchName = node.getRef().getName().substring(Constants.R_HEADS.length()); File mainRepoFile = repository.getDirectory().getParentFile(); File wdirFile = new File(mainRepoFile.getParentFile(), GitUtils.WORKING_DIRECTORY_PREFIX + branchName); if (wdirFile.exists()) { GitPlugin.getInstance().getUtils().delete(wdirFile); } dispatchContentUpdate(nodeInfo.getParent().getNode()); return true; } catch (GitAPIException e) { logger.debug(CommonPlugin.getInstance().getMessage("error"), path, e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } @RemoteInvocation public boolean openCredentials(ServiceInvocationContext context, List<PathFragment> path) { try { RemoteNode remoteNode = (RemoteNode) GenericTreeStatefulService.getNodeByPathFor(path, null); Repository repository = remoteNode.getRepository(); if (repository == null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), "Cannot find repository for node " + remoteNode, DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } org.eclipse.jgit.transport.RemoteConfig repoConfig = new org.eclipse.jgit.transport.RemoteConfig(repository.getConfig(), remoteNode.getRemote()); URIish uri = repoConfig.getURIs().get(0); List<String> credentials = ((FlowerWebPrincipal) CommunicationPlugin.tlCurrentPrincipal.get()).getUserGitRepositories().get(uri.toString()); context.getCommunicationChannel().appendOrSendCommand( new OpenGitCredentialsWindowClientCommand(uri.toString(), credentials != null ? credentials.get(0) : "")); return true; } catch (Exception e) { logger.debug(GitPlugin.getInstance().getMessage("git.changeCredentials.error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), GitPlugin.getInstance().getMessage("git.changeCredentials.error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } @RemoteInvocation public boolean clearCredentials(ServiceInvocationContext context, List<PathFragment> path) { try { RemoteNode remoteNode = (RemoteNode) GenericTreeStatefulService.getNodeByPathFor(path, null); Repository repository = remoteNode.getRepository(); if (repository == null) { context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), "Cannot find repository for node " + remoteNode, DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } org.eclipse.jgit.transport.RemoteConfig repoConfig = new org.eclipse.jgit.transport.RemoteConfig(repository.getConfig(), remoteNode.getRemote()); URIish uri = repoConfig.getURIs().get(0); ((FlowerWebPrincipal) CommunicationPlugin.tlCurrentPrincipal.get()).getUserGitRepositories().remove(uri.toString()); return true; } catch (Exception e) { logger.debug(GitPlugin.getInstance().getMessage("git.clearCredentials.error"), e); context.getCommunicationChannel().appendOrSendCommand( new DisplaySimpleMessageClientCommand( CommonPlugin.getInstance().getMessage("error"), GitPlugin.getInstance().getMessage("git.clearCredentials.error"), e.getMessage(), DisplaySimpleMessageClientCommand.ICON_ERROR)); return false; } } /** * Stores login information in principal and re-executes the interrupted operation. */ @RemoteInvocation public void login(ServiceInvocationContext context, String uri, String username, String password, InvokeServiceMethodServerCommand command) { changeCredentials(context, uri, username, password); command.setCommunicationChannel(context.getCommunicationChannel()); command.executeCommand(); } @RemoteInvocation public void changeCredentials(ServiceInvocationContext context, String uri, String username, String password) { List<String> info = new ArrayList<String>(); info.add(username); info.add(password); FlowerWebPrincipal principal = (FlowerWebPrincipal) CommunicationPlugin.tlCurrentPrincipal.get(); principal.getUserGitRepositories().put(uri, info); } }