| /******************************************************************************* |
| * Copyright (c) 2000, 2006 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.team.internal.ccvs.core.resources; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.NoSuchElementException; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.team.core.TeamException; |
| import org.eclipse.team.internal.ccvs.core.*; |
| import org.eclipse.team.internal.ccvs.core.client.*; |
| import org.eclipse.team.internal.ccvs.core.client.Command.LocalOption; |
| import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo; |
| |
| public class RemoteModule extends RemoteFolder { |
| |
| private String label; |
| private ICVSRemoteResource[] referencedModules; |
| private LocalOption[] localOptions; |
| private boolean expandable; |
| |
| public static RemoteModule[] getRemoteModules(ICVSRepositoryLocation repository, CVSTag tag, IProgressMonitor monitor) throws TeamException { |
| monitor = Policy.monitorFor(monitor); |
| monitor.beginTask(CVSMessages.RemoteModule_getRemoteModules, 100); |
| try { |
| RemoteModule[] modules; |
| Session s = new Session(repository, getRemoteRootFolder(repository), false); |
| s.open(Policy.subMonitorFor(monitor, 10), false /* read-only */); |
| try { |
| modules = Command.CHECKOUT.getRemoteModules(s, tag, Policy.subMonitorFor(monitor, 90)); |
| } finally { |
| s.close(); |
| } |
| return modules; |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| private static ICVSFolder getRemoteRootFolder(ICVSRepositoryLocation repository) { |
| return new RemoteFolder(null, repository, "/", null); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Create a set of RemoteModules from the provided module definition strings returned from the server |
| * |
| * At the moment, we are very restrictive on the types of modules we support. |
| */ |
| public static RemoteModule[] createRemoteModules(String[] moduleDefinitionStrings, ICVSRepositoryLocation repository, CVSTag tag) { |
| |
| Map modules = new HashMap(); |
| Map referencedModulesTable = new HashMap(); |
| Map moduleAliases = new HashMap(); |
| |
| // First pass: Create the remote module instances based on remote mapping |
| for (int i = 0; i < moduleDefinitionStrings.length; i++) { |
| |
| // Read the module name |
| StringTokenizer tokenizer = new StringTokenizer(moduleDefinitionStrings[i]); |
| String moduleName = tokenizer.nextToken(); |
| List<LocalOption> localOptionsList; |
| String next; |
| try { |
| // Read the options associated with the module |
| localOptionsList = new ArrayList<>(); |
| next = tokenizer.nextToken(); |
| while (next.charAt(0) == '-') { |
| switch (next.charAt(1)) { |
| case 'a': // alias |
| localOptionsList.add(Checkout.ALIAS); |
| break; |
| case 'l': // don't recurse |
| localOptionsList.add(Command.DO_NOT_RECURSE); |
| break; |
| case 'd': // directory |
| localOptionsList.add(Checkout.makeDirectoryNameOption(tokenizer.nextToken())); |
| break; |
| case 'e': |
| case 'i': |
| case 'o': |
| case 't': |
| case 'u': // Ignore any programs |
| tokenizer.nextToken(); |
| break; |
| case 's': // status |
| localOptionsList.add(Checkout.makeStatusOption(tokenizer.nextToken())); |
| break; |
| default: // unanticipated option. Ignore it and go on |
| } |
| next = tokenizer.nextToken(); |
| } |
| } catch (NoSuchElementException e) { |
| // There is an invalid entry in the modules file. Log it and continue |
| CVSProviderPlugin.log(IStatus.WARNING, NLS.bind(CVSMessages.RemoteModule_invalidDefinition, new String[] { moduleDefinitionStrings[i], repository.getLocation(true) }), null); |
| continue; |
| } |
| LocalOption[] localOptions = (LocalOption[]) localOptionsList.toArray(new LocalOption[localOptionsList.size()]); |
| |
| if (Checkout.ALIAS.isElementOf(localOptions)) { |
| |
| if (localOptions.length > 1) { |
| // XXX This is an error condition that needs to be reported |
| } |
| |
| // An alias expands to one or more modules or paths |
| List expansions = new ArrayList(10); |
| expansions.add(next); |
| while (tokenizer.hasMoreTokens()) |
| expansions.add(tokenizer.nextToken()); |
| |
| moduleAliases.put(moduleName, expansions.toArray(new String[expansions.size()])); |
| modules.put(moduleName, new RemoteModule(moduleName, null, repository, null, localOptions, tag, true)); |
| |
| } else { |
| |
| // The module definition may have a leading directory which can be followed by some files |
| if (!(next.charAt(0) == '&')) { |
| String directory = next; |
| List files = new ArrayList(); |
| while (tokenizer.hasMoreTokens() && (next.charAt(0) != '&')) { |
| next = tokenizer.nextToken() ; |
| if ((next.charAt(0) != '&')) |
| files.add(next); |
| } |
| RemoteModule remoteModule = new RemoteModule(moduleName, null, repository, directory, localOptions, tag, ! files.isEmpty()); |
| modules.put(moduleName, remoteModule); |
| if ( ! files.isEmpty()) { |
| ICVSRemoteResource[] children = new ICVSRemoteResource[files.size()]; |
| for (int j = 0; j < children.length; j++) { |
| children[j] = new RemoteFile(remoteModule, Update.STATE_NONE, (String)files.get(j), null, null, tag); |
| remoteModule.setChildren(children); |
| } |
| } |
| } else { |
| modules.put(moduleName, new RemoteModule(moduleName, null, repository, null, localOptions, tag, true)); |
| } |
| |
| // Record any referenced modules so that can be cross-referenced below |
| if (next.charAt(0) == '&') { |
| List<String> children = new ArrayList<>(10); |
| children.add(next); |
| while (tokenizer.hasMoreTokens()) |
| children.add(tokenizer.nextToken()); |
| referencedModulesTable.put(moduleName, children.toArray(new String[children.size()])); |
| } |
| } |
| } |
| |
| // Second pass: Cross reference aliases to modules |
| // XXX Aliases can reference other aliases which confuses the expansion! |
| Iterator iter = moduleAliases.keySet().iterator(); |
| while (iter.hasNext()) { |
| String moduleName = (String)iter.next(); |
| RemoteModule module = (RemoteModule)modules.get(moduleName); |
| String[] expansion = (String[])moduleAliases.get(moduleName); |
| List referencedFolders = new ArrayList(); |
| boolean expandable = true; |
| for (int i = 0; i < expansion.length; i++) { |
| if (expansion[i].charAt(0) == '!') { |
| // XXX Unsupported for now |
| expandable = false; |
| } else { |
| IPath path = new Path(null, expansion[i]); |
| if (path.segmentCount() > 1) { |
| // XXX Unsupported for now |
| expandable = false; |
| } else { |
| RemoteModule child = (RemoteModule)modules.get(expansion[i]); |
| if (child == null) { |
| referencedFolders.add(new RemoteFolder(null, repository, path.toString(), tag)); |
| } else { |
| // Need to check if the child is a module alias |
| if (child.isAlias()) { |
| // XXX Unsupported for now |
| expandable = false; |
| } else { |
| referencedFolders.add(child); |
| } |
| } |
| } |
| } |
| } |
| if (expandable) { |
| //TODO: Make module static?? |
| module.setChildren((ICVSRemoteResource[]) referencedFolders.toArray(new ICVSRemoteResource[referencedFolders.size()])); |
| } else { |
| module.setExpandable(false); |
| } |
| } |
| |
| // Third pass: Cross reference remote modules where necessary |
| iter = modules.keySet().iterator(); |
| while (iter.hasNext()) { |
| String moduleName = (String)iter.next(); |
| String[] children = (String[])referencedModulesTable.get(moduleName); |
| if (children != null) { |
| RemoteModule module = (RemoteModule)modules.get(moduleName); |
| List<RemoteModule> referencedFolders = new ArrayList<>(); |
| boolean expandable = true; |
| for (int i = 0; i < children.length; i++) { |
| RemoteModule child = (RemoteModule)modules.get(children[i].substring(1)); |
| if (child == null) { |
| // invalid module definition |
| expandable = false; |
| } else if (child.isAlias()) { |
| // Include alias children in-line |
| expandable = false; |
| // referencedFolders.addAll(Arrays.asList(child.getChildren())); |
| } else { |
| // XXX not expandable if child has local directory option (-d) |
| if (Command.findOption(child.getLocalOptions(), "-d") != null) { //$NON-NLS-1$ |
| expandable = false; |
| } else { |
| referencedFolders.add(child); |
| } |
| } |
| } |
| if (expandable) { |
| module.setReferencedModules((ICVSRemoteResource[]) referencedFolders.toArray(new ICVSRemoteResource[referencedFolders.size()])); |
| } else { |
| module.setExpandable(false); |
| } |
| } |
| } |
| |
| return (RemoteModule[])modules.values().toArray(new RemoteModule[modules.size()]); |
| } |
| |
| public RemoteModule(String label, RemoteFolder parent, ICVSRepositoryLocation repository, String repositoryRelativePath, LocalOption[] localOptions, CVSTag tag, boolean isStatic) { |
| super(parent, |
| label, |
| repository, |
| repositoryRelativePath == null ? FolderSyncInfo.VIRTUAL_DIRECTORY : repositoryRelativePath, |
| tag, |
| isStatic); |
| this.localOptions = localOptions; |
| this.label = label; |
| this.expandable = true; |
| } |
| |
| public LocalOption[] getLocalOptions() { |
| return localOptions; |
| } |
| /* |
| * Override of inherited getMembers in order to combine the physical members with any referenced modules |
| */ |
| public ICVSRemoteResource[] getMembers(CVSTag tagName, IProgressMonitor monitor) throws CVSException { |
| |
| if ( ! expandable) return new ICVSRemoteResource[0]; |
| |
| ICVSRemoteResource[] physicalChildren; |
| if ( folderInfo.getIsStatic()) { |
| physicalChildren = getChildren(); |
| } else { |
| physicalChildren = super.getMembers(tagName, monitor); |
| } |
| ICVSRemoteResource[] allChildren; |
| if (referencedModules != null && referencedModules.length > 0) { |
| if (physicalChildren == null) { |
| allChildren = referencedModules; |
| } else { |
| // Combine two sets of children |
| allChildren = new ICVSRemoteResource[physicalChildren.length + referencedModules.length]; |
| for (int i = 0; i < physicalChildren.length; i++) { |
| allChildren[i] = physicalChildren[i]; |
| } |
| for (int i = 0; i < referencedModules.length; i++) { |
| allChildren[i + physicalChildren.length] = referencedModules[i]; |
| } |
| } |
| } else if (physicalChildren != null) { |
| allChildren = physicalChildren; |
| } else { |
| allChildren = new ICVSRemoteResource[0]; |
| } |
| return allChildren; |
| } |
| |
| private void setReferencedModules(ICVSRemoteResource[] referencedModules) { |
| this.referencedModules = referencedModules; |
| } |
| |
| public boolean isAlias() { |
| return Checkout.ALIAS.isElementOf(localOptions); |
| } |
| |
| /** |
| * @see ICVSRemoteFolder#isExpandable() |
| */ |
| public boolean isExpandable() { |
| return expandable; |
| } |
| |
| private void setExpandable(boolean expandable) { |
| this.expandable = expandable; |
| } |
| |
| /** |
| * @see ICVSRemoteFolder#forTag(CVSTag) |
| */ |
| public ICVSRemoteResource forTag(ICVSRemoteFolder parent, CVSTag tagName) { |
| RemoteModule r = new RemoteModule(label, (RemoteFolder)parent, getRepository(), folderInfo.getRepository(), localOptions, tagName, folderInfo.getIsStatic()); |
| r.setExpandable(expandable); |
| if (folderInfo.getIsStatic()) { |
| ICVSRemoteResource[] children = getChildren(); |
| if (children != null) { |
| List taggedChildren = new ArrayList(children.length); |
| for (int i = 0; i < children.length; i++) { |
| ICVSRemoteResource resource = children[i]; |
| taggedChildren.add(((RemoteResource)resource).forTag(r, tagName)); |
| } |
| r.setChildren((ICVSRemoteResource[]) taggedChildren.toArray(new ICVSRemoteResource[taggedChildren.size()])); |
| } |
| } |
| if (referencedModules != null) { |
| List taggedModules = new ArrayList(referencedModules.length); |
| for (int i = 0; i < referencedModules.length; i++) { |
| RemoteModule module = (RemoteModule)referencedModules[i]; |
| taggedModules.add(module.forTag(r, tagName)); |
| } |
| r.setReferencedModules((ICVSRemoteResource[]) taggedModules.toArray(new ICVSRemoteResource[taggedModules.size()])); |
| } |
| return r; |
| } |
| |
| /** |
| * @see org.eclipse.team.internal.ccvs.core.ICVSRemoteFolder#isDefinedModule() |
| */ |
| public boolean isDefinedModule() { |
| return true; |
| } |
| /** |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| public boolean equals(Object arg0) { |
| if (arg0 instanceof RemoteModule) { |
| RemoteModule module = (RemoteModule) arg0; |
| return (getName().equals(module.getName()) && super.equals(module)); |
| } |
| return false; |
| } |
| |
| /** |
| * @see java.lang.Object#hashCode() |
| */ |
| public int hashCode() { |
| return super.hashCode() | getName().hashCode(); |
| } |
| |
| /** |
| * @see org.eclipse.team.internal.ccvs.core.ICVSFolder#getChild(java.lang.String) |
| */ |
| public ICVSResource getChild(String path) throws CVSException { |
| if (path.equals(Session.CURRENT_LOCAL_FOLDER) || path.length() == 0) |
| return this; |
| // If the path is one segment and it's a referenced module, return the module |
| // Note: the overriden method will extract the first segment from a multi segment |
| // path and re-invoke this method so we only need to check for one segment here |
| // and use the inherited method in the other cases |
| if (referencedModules != null) { |
| if (path.indexOf(Session.SERVER_SEPARATOR) == -1) { |
| for (int i=0;i<referencedModules.length;i++) { |
| if (referencedModules[i].getName().equals(path)) |
| return referencedModules[i]; |
| } |
| } |
| } |
| return super.getChild(path); |
| } |
| |
| } |