| package org.eclipse.team.internal.ccvs.ui; |
| |
| /* |
| * (c) Copyright IBM Corp. 2000, 2002. |
| * All Rights Reserved. |
| */ |
| |
| import java.io.DataInputStream; |
| import java.io.DataOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.team.ccvs.core.CVSProviderPlugin; |
| import org.eclipse.team.ccvs.core.CVSTag; |
| import org.eclipse.team.ccvs.core.CVSTeamProvider; |
| import org.eclipse.team.ccvs.core.ICVSListener; |
| import org.eclipse.team.ccvs.core.ICVSProvider; |
| import org.eclipse.team.ccvs.core.ICVSRemoteFile; |
| import org.eclipse.team.ccvs.core.ICVSRemoteResource; |
| import org.eclipse.team.ccvs.core.ICVSRepositoryLocation; |
| import org.eclipse.team.ccvs.core.ILogEntry; |
| import org.eclipse.team.core.ITeamProvider; |
| import org.eclipse.team.core.TeamException; |
| import org.eclipse.team.core.TeamPlugin; |
| import org.eclipse.team.core.sync.IRemoteResource; |
| import org.eclipse.team.core.sync.IRemoteSyncElement; |
| import org.eclipse.team.internal.ccvs.core.client.Command; |
| import org.eclipse.team.internal.ccvs.core.client.NullCopyHandler; |
| import org.eclipse.team.internal.ccvs.core.client.ResponseHandler; |
| import org.eclipse.team.internal.ccvs.ui.model.BranchTag; |
| |
| /** |
| * This class is repsible for maintaining the UI's list of known repositories, |
| * and a list of known tags within each of those repositories. |
| * |
| * It also provides a number of useful methods for assisting in repository operations. |
| */ |
| public class RepositoryManager { |
| private static final String STATE_FILE = ".repositoryManagerState"; |
| |
| // Map ICVSRepositoryLocation -> List of Tags |
| Hashtable branchTags = new Hashtable(); |
| // Map ICVSRepositoryLocation -> Hashtable of (Project name -> Set of CVSTags) |
| Hashtable versionTags = new Hashtable(); |
| |
| List listeners = new ArrayList(); |
| |
| // The previously remembered comment |
| private static String previousComment = ""; |
| |
| /** |
| * Answer an array of all known remote roots. |
| */ |
| public ICVSRepositoryLocation[] getKnownRoots() { |
| return getCVSProvider().getKnownRepositories(); |
| } |
| |
| private ICVSProvider getCVSProvider() { |
| return CVSProviderPlugin.getProvider(); |
| } |
| |
| /** |
| * Get the list of known branch tags for a given remote root. |
| */ |
| public BranchTag[] getKnownBranchTags(ICVSRepositoryLocation root) { |
| Set set = (Set)branchTags.get(root); |
| if (set == null) return new BranchTag[0]; |
| return (BranchTag[])set.toArray(new BranchTag[0]); |
| } |
| /** |
| * Get the list of known version tags for a given project. |
| * |
| * This list includes: |
| * -All manually defined or auto-defined version tags |
| * -All tags for the .vcm_meta file, if one exists |
| * |
| * A server hit is incurred on each call to ensure up-to-date results. |
| */ |
| public CVSTag[] getKnownVersionTags(ICVSRemoteResource resource, IProgressMonitor monitor) throws TeamException { |
| // Find tags in .vcm_meta file, optimization for Eclipse users |
| Set result = new HashSet(); |
| ICVSRemoteFile vcmMeta = getVCMMeta(resource); |
| if (vcmMeta != null) { |
| CVSTag[] tags = getTags(vcmMeta, new NullProgressMonitor()); |
| for (int i = 0; i < tags.length; i++) { |
| if (tags[i].getType() == CVSTag.VERSION) { |
| result.add(tags[i]); |
| } |
| } |
| } |
| |
| Hashtable table = (Hashtable)versionTags.get(resource.getRepository()); |
| if (table == null) { |
| return (CVSTag[])result.toArray(new CVSTag[result.size()]); |
| } |
| Set set = (Set)table.get(resource.getName()); |
| if (set == null) { |
| return (CVSTag[])result.toArray(new CVSTag[result.size()]); |
| } |
| result.addAll(set); |
| return (CVSTag[])result.toArray(new CVSTag[0]); |
| } |
| private ICVSRemoteFile getVCMMeta(ICVSRemoteResource resource) throws TeamException { |
| // There should be a better way of doing this. |
| IRemoteResource[] resources = resource.members(new NullProgressMonitor()); |
| for (int i = 0; i < resources.length; i++) { |
| if (resources[i] instanceof ICVSRemoteFile && resources[i].getName().equals(".vcm_meta")) { |
| return (ICVSRemoteFile)resources[i]; |
| } |
| } |
| return null; |
| } |
| /** |
| * Add the given branch tags to the list of known tags for the given |
| * remote root. |
| */ |
| public void addBranchTags(ICVSRepositoryLocation root, BranchTag[] tags) { |
| Set set = (Set)branchTags.get(root); |
| if (set == null) { |
| set = new HashSet(); |
| branchTags.put(root, set); |
| } |
| for (int i = 0; i < tags.length; i++) { |
| set.add(tags[i]); |
| } |
| Iterator it = listeners.iterator(); |
| while (it.hasNext()) { |
| IRepositoryListener listener = (IRepositoryListener)it.next(); |
| listener.branchTagsAdded(tags, root); |
| } |
| } |
| /** |
| * A repository root has been added. Notify any listeners. |
| */ |
| public void rootAdded(ICVSRepositoryLocation root) { |
| Iterator it = listeners.iterator(); |
| while (it.hasNext()) { |
| IRepositoryListener listener = (IRepositoryListener)it.next(); |
| listener.repositoryAdded(root); |
| } |
| } |
| |
| /** |
| * A repository root has been removed. |
| * Remove the tags defined for this root and notify any listeners |
| */ |
| public void rootRemoved(ICVSRepositoryLocation root) { |
| BranchTag[] branchTags = getKnownBranchTags(root); |
| Hashtable vTags = (Hashtable)this.versionTags.get(root); |
| this.branchTags.remove(root); |
| this.versionTags.remove(root); |
| Iterator it = listeners.iterator(); |
| while (it.hasNext()) { |
| IRepositoryListener listener = (IRepositoryListener)it.next(); |
| listener.branchTagsRemoved(branchTags, root); |
| if (vTags != null) { |
| Iterator keyIt = vTags.keySet().iterator(); |
| while (keyIt.hasNext()) { |
| String projectName = (String)keyIt.next(); |
| Set tagSet = (Set)vTags.get(projectName); |
| CVSTag[] versionTags = (CVSTag[])tagSet.toArray(new CVSTag[0]); |
| listener.versionTagsRemoved(versionTags, root); |
| } |
| } |
| listener.repositoryRemoved(root); |
| } |
| } |
| |
| /** |
| * Add the given version tags to the list of known tags for the given |
| * remote project. |
| */ |
| public void addVersionTags(ICVSRemoteResource resource, CVSTag[] tags) { |
| String name = resource.getName(); |
| Hashtable table = (Hashtable)versionTags.get(resource.getRepository()); |
| if (table == null) { |
| table = new Hashtable(); |
| versionTags.put(resource.getRepository(), table); |
| } |
| Set set = (Set)table.get(name); |
| if (set == null) { |
| set = new HashSet(); |
| table.put(name, set); |
| } |
| for (int i = 0; i < tags.length; i++) { |
| set.add(tags[i]); |
| } |
| Iterator it = listeners.iterator(); |
| while (it.hasNext()) { |
| IRepositoryListener listener = (IRepositoryListener)it.next(); |
| listener.versionTagsAdded(tags, resource.getRepository()); |
| } |
| } |
| /** |
| * Remove the given branch tag from the list of known tags for the |
| * given remote root. |
| */ |
| public void removeBranchTag(ICVSRepositoryLocation root, BranchTag[] tags) { |
| Set set = (Set)branchTags.get(root); |
| if (set == null) return; |
| for (int i = 0; i < tags.length; i++) { |
| set.remove(tags[i]); |
| } |
| Iterator it = listeners.iterator(); |
| while (it.hasNext()) { |
| IRepositoryListener listener = (IRepositoryListener)it.next(); |
| listener.branchTagsRemoved(tags, root); |
| } |
| } |
| /** |
| * Remove the given tags from the list of known tags for the |
| * given remote root. |
| */ |
| public void removeVersionTags(ICVSRemoteResource resource, CVSTag[] tags) { |
| Hashtable table = (Hashtable)versionTags.get(resource.getRepository()); |
| if (table == null) return; |
| Set set = (Set)table.get(resource.getName()); |
| if (set == null) return; |
| for (int i = 0; i < tags.length; i++) { |
| set.remove(tags[i]); |
| } |
| Iterator it = listeners.iterator(); |
| while (it.hasNext()) { |
| IRepositoryListener listener = (IRepositoryListener)it.next(); |
| listener.versionTagsRemoved(tags, resource.getRepository()); |
| } |
| } |
| |
| public void startup() throws TeamException { |
| loadState(); |
| CVSProviderPlugin.getProvider().addRepositoryListener(new ICVSListener() { |
| public void repositoryAdded(ICVSRepositoryLocation root) { |
| rootAdded(root); |
| } |
| public void repositoryRemoved(ICVSRepositoryLocation root) { |
| rootRemoved(root); |
| } |
| }); |
| } |
| |
| public void shutdown() throws TeamException { |
| saveState(); |
| } |
| |
| private void loadState() throws TeamException { |
| IPath pluginStateLocation = CVSUIPlugin.getPlugin().getStateLocation().append(STATE_FILE); |
| File file = pluginStateLocation.toFile(); |
| if (file.exists()) { |
| try { |
| DataInputStream dis = new DataInputStream(new FileInputStream(file)); |
| try { |
| readState(dis); |
| } finally { |
| dis.close(); |
| } |
| } catch (IOException e) { |
| throw new TeamException(new Status(Status.ERROR, CVSUIPlugin.ID, TeamException.UNABLE, Policy.bind("RepositoryManager.ioException"), e)); |
| } |
| } |
| } |
| |
| private void saveState() throws TeamException { |
| IPath pluginStateLocation = CVSUIPlugin.getPlugin().getStateLocation(); |
| File tempFile = pluginStateLocation.append(STATE_FILE + ".tmp").toFile(); |
| File stateFile = pluginStateLocation.append(STATE_FILE).toFile(); |
| try { |
| DataOutputStream dos = new DataOutputStream(new FileOutputStream(tempFile)); |
| try { |
| writeState(dos); |
| } finally { |
| dos.close(); |
| } |
| if (stateFile.exists()) { |
| stateFile.delete(); |
| } |
| boolean renamed = tempFile.renameTo(stateFile); |
| if (!renamed) { |
| throw new TeamException(new Status(Status.ERROR, CVSUIPlugin.ID, TeamException.UNABLE, Policy.bind("RepositoryManager.rename", tempFile.getAbsolutePath()), null)); |
| } |
| } catch (IOException e) { |
| throw new TeamException(new Status(Status.ERROR, CVSUIPlugin.ID, TeamException.UNABLE, Policy.bind("RepositoryManager.save",stateFile.getAbsolutePath()), e)); |
| } |
| } |
| private void writeState(DataOutputStream dos) throws IOException { |
| // Write the repositories |
| Collection repos = Arrays.asList(getKnownRoots()); |
| dos.writeInt(repos.size()); |
| Iterator it = repos.iterator(); |
| while (it.hasNext()) { |
| ICVSRepositoryLocation root = (ICVSRepositoryLocation)it.next(); |
| dos.writeUTF(root.getLocation()); |
| BranchTag[] branchTags = getKnownBranchTags(root); |
| dos.writeInt(branchTags.length); |
| for (int i = 0; i < branchTags.length; i++) { |
| dos.writeUTF(branchTags[i].getTag().getName()); |
| dos.writeInt(branchTags[i].getTag().getType()); |
| } |
| // write number of projects for which there are tags in this root |
| Hashtable table = (Hashtable)versionTags.get(root); |
| if (table == null) { |
| dos.writeInt(0); |
| } else { |
| dos.writeInt(table.size()); |
| // for each project, write the name of the project, number of tags, and each tag. |
| Iterator projIt = table.keySet().iterator(); |
| while (projIt.hasNext()) { |
| String name = (String)projIt.next(); |
| dos.writeUTF(name); |
| Set tagSet = (Set)table.get(name); |
| dos.writeInt(tagSet.size()); |
| Iterator tagIt = tagSet.iterator(); |
| while (tagIt.hasNext()) { |
| CVSTag tag = (CVSTag)tagIt.next(); |
| dos.writeUTF(tag.getName()); |
| } |
| } |
| } |
| } |
| } |
| private void readState(DataInputStream dis) throws IOException, TeamException { |
| int repoSize = dis.readInt(); |
| for (int i = 0; i < repoSize; i++) { |
| ICVSRepositoryLocation root = CVSProviderPlugin.getProvider().getRepository(dis.readUTF()); |
| int tagsSize = dis.readInt(); |
| BranchTag[] branchTags = new BranchTag[tagsSize]; |
| for (int j = 0; j < tagsSize; j++) { |
| String tagName = dis.readUTF(); |
| int tagType = dis.readInt(); |
| branchTags[j] = new BranchTag(new CVSTag(tagName, tagType), root); |
| } |
| addBranchTags(root, branchTags); |
| // read the number of projects for this root that have version tags |
| int projSize = dis.readInt(); |
| if (projSize > 0) { |
| Hashtable projTable = new Hashtable(); |
| versionTags.put(root, projTable); |
| for (int j = 0; j < projSize; j++) { |
| String name = dis.readUTF(); |
| Set tagSet = new HashSet(); |
| projTable.put(name, tagSet); |
| int numTags = dis.readInt(); |
| for (int k = 0; k < numTags; k++) { |
| tagSet.add(new CVSTag(dis.readUTF(), CVSTag.VERSION)); |
| } |
| Iterator it = listeners.iterator(); |
| while (it.hasNext()) { |
| IRepositoryListener listener = (IRepositoryListener)it.next(); |
| listener.versionTagsAdded((CVSTag[])tagSet.toArray(new CVSTag[0]), root); |
| } |
| } |
| } |
| } |
| } |
| |
| public void addRepositoryListener(IRepositoryListener listener) { |
| listeners.add(listener); |
| } |
| |
| public void removeRepositoryListener(IRepositoryListener listener) { |
| listeners.remove(listener); |
| } |
| |
| /** |
| * Add the given resources to their associated providers. |
| * This schedules the resources for addition; they still need to be committed. |
| */ |
| public void add(IResource[] resources, IProgressMonitor monitor) throws TeamException { |
| Hashtable table = getProviderMapping(resources); |
| Set keySet = table.keySet(); |
| monitor.beginTask("", keySet.size() * 1000); |
| monitor.setTaskName(Policy.bind("RepositoryManager.adding")); |
| Iterator iterator = keySet.iterator(); |
| while (iterator.hasNext()) { |
| IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1000); |
| CVSTeamProvider provider = (CVSTeamProvider)iterator.next(); |
| provider.setComment(previousComment); |
| List list = (List)table.get(provider); |
| IResource[] providerResources = (IResource[])list.toArray(new IResource[list.size()]); |
| provider.add(providerResources, IResource.DEPTH_ZERO, subMonitor); |
| } |
| } |
| |
| /** |
| * Delete the given resources from their associated providers. |
| * This schedules the resources for deletion; they still need to be committed. |
| */ |
| public void delete(IResource[] resources, IProgressMonitor monitor) throws TeamException { |
| Hashtable table = getProviderMapping(resources); |
| Set keySet = table.keySet(); |
| monitor.beginTask("", keySet.size() * 1000); |
| monitor.setTaskName(Policy.bind("RepositoryManager.deleting")); |
| Iterator iterator = keySet.iterator(); |
| while (iterator.hasNext()) { |
| IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1000); |
| CVSTeamProvider provider = (CVSTeamProvider)iterator.next(); |
| provider.setComment(previousComment); |
| List list = (List)table.get(provider); |
| IResource[] providerResources = (IResource[])list.toArray(new IResource[list.size()]); |
| provider.delete(providerResources, subMonitor); |
| } |
| } |
| public void update(IResource[] resources, Command.LocalOption[] options, boolean createBackups, IProgressMonitor monitor) throws TeamException { |
| Hashtable table = getProviderMapping(resources); |
| Set keySet = table.keySet(); |
| monitor.beginTask("", keySet.size() * 1000); |
| monitor.setTaskName(Policy.bind("RepositoryManager.updating")); |
| Iterator iterator = keySet.iterator(); |
| while (iterator.hasNext()) { |
| IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1000); |
| CVSTeamProvider provider = (CVSTeamProvider)iterator.next(); |
| List list = (List)table.get(provider); |
| IResource[] providerResources = (IResource[])list.toArray(new IResource[list.size()]); |
| ResponseHandler handler = null; |
| if (!createBackups) { |
| handler = new NullCopyHandler(); |
| } |
| provider.update(providerResources, options, null, handler, subMonitor); |
| } |
| } |
| /** |
| * Mark the files as merged. |
| */ |
| public void merged(IRemoteSyncElement[] elements) throws TeamException { |
| Hashtable table = getProviderMapping(elements); |
| Set keySet = table.keySet(); |
| Iterator iterator = keySet.iterator(); |
| while (iterator.hasNext()) { |
| CVSTeamProvider provider = (CVSTeamProvider)iterator.next(); |
| provider.setComment(previousComment); |
| List list = (List)table.get(provider); |
| IRemoteSyncElement[] providerElements = (IRemoteSyncElement[])list.toArray(new IRemoteSyncElement[list.size()]); |
| provider.merged(providerElements); |
| } |
| } |
| /** |
| * Return the entered comment or null. |
| * Persist the entered release comment for the next caller. |
| */ |
| public String promptForComment(final Shell shell) { |
| final int[] result = new int[1]; |
| shell.getDisplay().syncExec(new Runnable() { |
| public void run() { |
| ReleaseCommentDialog dialog = new ReleaseCommentDialog(shell); |
| dialog.setComment(previousComment); |
| result[0] = dialog.open(); |
| if (result[0] != ReleaseCommentDialog.OK) return; |
| previousComment = dialog.getComment(); |
| } |
| }); |
| if (result[0] != ReleaseCommentDialog.OK) return null; |
| return previousComment; |
| } |
| /** |
| * Commit the given resources to their associated providers. |
| * |
| * @param resources the resources to commit |
| * @param monitor the progress monitor |
| */ |
| public void commit(IResource[] resources, String comment, IProgressMonitor monitor) throws TeamException { |
| Hashtable table = getProviderMapping(resources); |
| Set keySet = table.keySet(); |
| monitor.beginTask("", keySet.size() * 1000); |
| monitor.setTaskName(Policy.bind("RepositoryManager.committing")); |
| Iterator iterator = keySet.iterator(); |
| while (iterator.hasNext()) { |
| IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1000); |
| CVSTeamProvider provider = (CVSTeamProvider)iterator.next(); |
| provider.setComment(comment); |
| List list = (List)table.get(provider); |
| IResource[] providerResources = (IResource[])list.toArray(new IResource[list.size()]); |
| provider.checkin(providerResources, IResource.DEPTH_INFINITE, subMonitor); |
| } |
| } |
| |
| /** |
| * Helper method. Return a hashtable mapping provider to a list of resources |
| * shared with that provider. |
| */ |
| private Hashtable getProviderMapping(IResource[] resources) { |
| Hashtable result = new Hashtable(); |
| for (int i = 0; i < resources.length; i++) { |
| ITeamProvider provider = TeamPlugin.getManager().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; |
| } |
| /** |
| * Helper method. Return a hashtable mapping provider to a list of IRemoteSyncElements |
| * shared with that provider. |
| */ |
| private Hashtable getProviderMapping(IRemoteSyncElement[] elements) { |
| Hashtable result = new Hashtable(); |
| for (int i = 0; i < elements.length; i++) { |
| ITeamProvider provider = TeamPlugin.getManager().getProvider(elements[i].getLocal().getProject()); |
| List list = (List)result.get(provider); |
| if (list == null) { |
| list = new ArrayList(); |
| result.put(provider, list); |
| } |
| list.add(elements[i]); |
| } |
| return result; |
| } |
| |
| /** |
| * Returns Branch and Version tags for the given files |
| */ |
| public CVSTag[] getTags(ICVSRemoteFile file, IProgressMonitor monitor) throws TeamException { |
| ICVSRepositoryLocation root = file.getRepository(); |
| Set tagSet = new HashSet(); |
| ILogEntry[] entries = file.getLogEntries(monitor); |
| for (int j = 0; j < entries.length; j++) { |
| CVSTag[] tags = entries[j].getTags(); |
| for (int k = 0; k < tags.length; k++) { |
| tagSet.add(tags[k]); |
| } |
| } |
| return (CVSTag[])tagSet.toArray(new CVSTag[0]); |
| } |
| |
| /** |
| * Auto-define version and branch tags for the given files. |
| */ |
| public void autoDefineTags(ICVSRemoteFile[] files, IProgressMonitor monitor) throws TeamException { |
| for (int i = 0; i < files.length; i++) { |
| ICVSRemoteFile file = files[i]; |
| ICVSRepositoryLocation root = file.getRepository(); |
| CVSTag[] tags = getTags(file, monitor); |
| |
| // Break tags up into version tags and branch tags. |
| List branchTags = new ArrayList(); |
| List versionTags = new ArrayList(); |
| for (int j = 0; j < tags.length; j++) { |
| CVSTag tag = tags[j]; |
| if (tag.getType() == CVSTag.BRANCH) { |
| branchTags.add(new BranchTag(tag, root)); |
| } else { |
| versionTags.add(tag); |
| } |
| } |
| if (branchTags.size() > 0) { |
| addBranchTags(root, (BranchTag[])branchTags.toArray(new BranchTag[0])); |
| } |
| if (versionTags.size() > 0) { |
| // Current behaviour for version tags is to match the behaviour in VCM 1.0, |
| // which is to attach them to the top-most folder in CVS. This may change in the future |
| // to allow a more flexible scheme of attaching 'project' semantics to arbitrary |
| // cvs folders. Get the top-most folder now to optimize. |
| ICVSRemoteResource current = file.getRemoteParent(); |
| ICVSRemoteResource next = current.getRemoteParent(); |
| while (next != null && next.getRemoteParent() != null) { |
| current = next; |
| next = current.getRemoteParent(); |
| } |
| addVersionTags(current, (CVSTag[])versionTags.toArray(new CVSTag[0])); |
| } |
| } |
| } |
| } |