blob: c78467b606511e08907f881bc64d580bdf7db4ea [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ccvs.ui.repo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSStatus;
import org.eclipse.team.internal.ccvs.core.CVSTag;
import org.eclipse.team.internal.ccvs.core.ICVSFolder;
import org.eclipse.team.internal.ccvs.core.ICVSRemoteFile;
import org.eclipse.team.internal.ccvs.core.ICVSRemoteFolder;
import org.eclipse.team.internal.ccvs.core.ICVSRemoteResource;
import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation;
import org.eclipse.team.internal.ccvs.core.ICVSResource;
import org.eclipse.team.internal.ccvs.core.ILogEntry;
import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin;
import org.eclipse.team.internal.ccvs.ui.Policy;
import org.eclipse.team.internal.ccvs.ui.XMLWriter;
public class RepositoryRoot extends PlatformObject {
public static final String[] DEFAULT_AUTO_REFRESH_FILES = { ".project", ".vcm_meta" }; //$NON-NLS-1$ //$NON-NLS-2$
private static final String DEFINED_MODULE_PREFIX = "module:"; //$NON-NLS-1$
ICVSRepositoryLocation root;
String name;
// Map of String (remote folder path) -> Set (CVS tags)
Map knownTags = new HashMap();
// Map of String (remote folder path) -> Set (file paths that are project relative)
Map autoRefreshFiles = new HashMap();
// Map of String (module name) -> ICVSRemoteFolder (that is a defined module)
Map modulesCache;
public RepositoryRoot(ICVSRepositoryLocation root) {
this.root = root;
}
/**
* Returns the name.
* @return String
*/
public String getName() {
return name;
}
/**
* Method getRemoteFolder.
* @param path
* @param tag
* @return ICVSRemoteFolder
*/
public ICVSRemoteFolder getRemoteFolder(String path, CVSTag tag, IProgressMonitor monitor) throws CVSException {
if (isDefinedModuleName(path)) {
return getDefinedModule(getDefinedModuleName(path), tag, monitor);
} else {
return root.getRemoteFolder(path, tag);
}
}
static boolean isDefinedModuleName(String path) {
return path.startsWith(DEFINED_MODULE_PREFIX);
}
static String getDefinedModuleName(String path) {
return path.substring(DEFINED_MODULE_PREFIX.length());
}
static String asDefinedModulePath(String path) {
return DEFINED_MODULE_PREFIX + path;
}
/**
* Method getDefinedModule.
* @param path
* @param tag
* @param monitor
* @return ICVSRemoteFolder
*/
private ICVSRemoteFolder getDefinedModule(String path, CVSTag tag, IProgressMonitor monitor) throws CVSException {
Map cache = getDefinedModulesCache(tag, monitor);
ICVSRemoteFolder folder = (ICVSRemoteFolder)cache.get(path);
if (folder != null) {
folder = (ICVSRemoteFolder)folder.forTag(tag);
}
return folder;
}
private Map getDefinedModulesCache(CVSTag tag, IProgressMonitor monitor) throws CVSException {
if (modulesCache == null) {
modulesCache = new HashMap();
try {
ICVSRemoteResource[] folders = root.members(CVSTag.DEFAULT, true, monitor);
for (int i = 0; i < folders.length; i++) {
ICVSRemoteResource resource = folders[i];
modulesCache.put(resource.getName(), resource);
}
} catch (CVSException e) {
// we could't fetch the modules. Log the problem and continue
CVSUIPlugin.log(e);
}
}
return modulesCache;
}
public ICVSRemoteResource[] getDefinedModules(CVSTag tag, IProgressMonitor monitor) throws CVSException {
Map cache = getDefinedModulesCache(tag, monitor);
return (ICVSRemoteResource[]) cache.values().toArray(new ICVSRemoteResource[cache.size()]);
}
public static String getRemotePathFor(ICVSResource resource) throws CVSException {
if (resource.isFolder()) {
if (resource instanceof ICVSRemoteFolder) {
ICVSRemoteFolder remoteFolder = (ICVSRemoteFolder) resource;
if (remoteFolder.isDefinedModule()) {
return asDefinedModulePath(remoteFolder.getName());
}
}
FolderSyncInfo info = ((ICVSFolder)resource).getFolderSyncInfo();
if (info == null)
throw new CVSException(Policy.bind("RepositoryRoot.folderInfoMissing", resource.getName())); //$NON-NLS-1$
return info.getRepository();
} else {
FolderSyncInfo info = resource.getParent().getFolderSyncInfo();
if (info == null)
throw new CVSException(Policy.bind("RepositoryRoot.folderInfoMissing", resource.getParent().getName())); //$NON-NLS-1$
String path = new Path(info.getRepository()).append(resource.getName()).toString();
return path;
}
}
/**
* Returns the root.
* @return ICVSRepositoryLocation
*/
public ICVSRepositoryLocation getRoot() {
return root;
}
/**
* Sets the name.
* @param name The name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* Accept the tags for any remote path that represents a folder. However, for the time being,
* the given version tags are added to the list of known tags for the
* remote ancestor of the resource that is a direct child of the remote root.
*
* It is the reponsibility of the caller to ensure that the given remote path is valid.
*/
public void addTags(String remotePath, CVSTag[] tags) {
// Get the name to cache the version tags with
String name = getCachePathFor(remotePath);
// Make sure there is a table for the ancestor that holds the tags
Set set = (Set)knownTags.get(name);
if (set == null) {
set = new HashSet();
knownTags.put(name, set);
}
// Store the tag with the appropriate ancestor
for (int i = 0; i < tags.length; i++) {
set.add(tags[i]);
}
}
/**
* Remove the given tags from the receiver
* @param remotePath
* @param tags
*/
public void removeTags(String remotePath, CVSTag[] tags) {
// Get the name to cache the version tags with
String name = getCachePathFor(remotePath);
// Make sure there is a table for the ancestor that holds the tags
Set set = (Set)knownTags.get(name);
if (set == null) {
return;
}
// Store the tag with the appropriate ancestor
for (int i = 0; i < tags.length; i++) {
set.remove(tags[i]);
}
}
/**
* Returns the absolute paths of the auto refresh files relative to the
* repository.
*
* @return String[]
*/
public String[] getAutoRefreshFiles(String remotePath) {
String name = getCachePathFor(remotePath);
Set files = (Set)autoRefreshFiles.get(name);
if (files == null || files.isEmpty()) {
// convert the default relative file paths to full paths
if (isDefinedModuleName(remotePath)) {
return new String[0];
}
List result = new ArrayList();
for (int i = 0; i < DEFAULT_AUTO_REFRESH_FILES.length; i++) {
String relativePath = DEFAULT_AUTO_REFRESH_FILES[i];
result.add(new Path(remotePath).append(relativePath).toString());
}
return (String[]) result.toArray(new String[result.size()]);
} else {
return (String[]) files.toArray(new String[files.size()]);
}
}
/**
* Sets the auto refresh files for the given remote path to the given
* string values which are absolute file paths (relative to the receiver).
*
* @param autoRefreshFiles The autoRefreshFiles to set
*/
public void setAutoRefreshFiles(String remotePath, String[] autoRefreshFiles) {
Set newFiles = new HashSet(Arrays.asList(autoRefreshFiles));
// Check to see if the auto-refresh files are the default files
if (autoRefreshFiles.length == DEFAULT_AUTO_REFRESH_FILES.length) {
boolean isDefault = true;
for (int i = 0; i < DEFAULT_AUTO_REFRESH_FILES.length; i++) {
String filePath = DEFAULT_AUTO_REFRESH_FILES[i];
if (!newFiles.contains(new Path(remotePath).append(filePath).toString())) {
isDefault = false;
break;
}
}
if (isDefault) {
this.autoRefreshFiles.remove(getCachePathFor(remotePath));
return;
}
}
this.autoRefreshFiles.put(getCachePathFor(remotePath), newFiles);
}
/**
* Fetches tags from auto-refresh files.
*/
public void refreshDefinedTags(String remotePath, boolean replace, IProgressMonitor monitor) throws TeamException {
String[] filesToRefresh = getAutoRefreshFiles(remotePath);
monitor.beginTask(null, filesToRefresh.length * 10); //$NON-NLS-1$
try {
List tags = new ArrayList();
for (int i = 0; i < filesToRefresh.length; i++) {
ICVSRemoteFile file = root.getRemoteFile(filesToRefresh[i], CVSTag.DEFAULT);
tags.addAll(Arrays.asList(fetchTags(file, Policy.subMonitorFor(monitor, 5))));
}
if (!tags.isEmpty()) {
addTags(remotePath, (CVSTag[]) tags.toArray(new CVSTag[tags.size()]));
}
} finally {
monitor.done();
}
}
/*
* Method clearTags.
*/
private void clearTags(String remotePath) {
String name = getCachePathFor(remotePath);
knownTags.remove(name);
}
/**
* Returns Branch and Version tags for the given files
*/
private CVSTag[] fetchTags(ICVSRemoteFile file, IProgressMonitor monitor) throws TeamException {
try {
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]);
} catch (TeamException e) {
IStatus status = e.getStatus();
if (status.getCode() == CVSStatus.SERVER_ERROR && status.isMultiStatus()) {
IStatus[] children = status.getChildren();
if (children.length == 1 && children[0].getCode() == CVSStatus.DOES_NOT_EXIST) {
return new CVSTag[0];
}
}
throw e;
}
}
private String getCachePathFor(String remotePath) {
String root = new Path(remotePath).segment(0);
if (isDefinedModuleName(remotePath)) {
return asDefinedModulePath(root);
}
return root;
}
/**
* Write out the state of the receiver as XML on the given XMLWriter.
*
* @param writer
* @throws IOException
*/
public void writeState(XMLWriter writer) throws IOException {
HashMap attributes = new HashMap();
attributes.clear();
attributes.put(RepositoriesViewContentHandler.ID_ATTRIBUTE, root.getLocation());
if (name != null) {
attributes.put(RepositoriesViewContentHandler.NAME_ATTRIBUTE, name);
}
String readLocation = ((CVSRepositoryLocation)root).getReadLocation();
if (readLocation != null) {
attributes.put(RepositoriesViewContentHandler.READ_ID_ATTRIBUTE, readLocation);
}
String writeLocation = ((CVSRepositoryLocation)root).getWriteLocation();
if (writeLocation != null) {
attributes.put(RepositoriesViewContentHandler.WRITE_ID_ATTRIBUTE, writeLocation);
}
writer.startTag(RepositoriesViewContentHandler.REPOSITORY_TAG, attributes, true);
// Gather all the modules that have tags and/or auto-refresh files
// for each module, write the moduel, tags and auto-refresh files.
String[] paths = getKnownRemotePaths();
for (int i = 0; i < paths.length; i++) {
String path = paths[i];
attributes.clear();
String name = path;
if (isDefinedModuleName(path)) {
name = getDefinedModuleName(path);
attributes.put(RepositoriesViewContentHandler.TYPE_ATTRIBUTE, RepositoriesViewContentHandler.DEFINED_MODULE_TYPE);
}
attributes.put(RepositoriesViewContentHandler.PATH_ATTRIBUTE, name);
writer.startTag(RepositoriesViewContentHandler.MODULE_TAG, attributes, true);
Set tagSet = (Set)knownTags.get(path);
if (tagSet != null) {
Iterator tagIt = tagSet.iterator();
while (tagIt.hasNext()) {
CVSTag tag = (CVSTag)tagIt.next();
attributes.clear();
attributes.put(RepositoriesViewContentHandler.NAME_ATTRIBUTE, tag.getName());
attributes.put(RepositoriesViewContentHandler.TYPE_ATTRIBUTE, RepositoriesViewContentHandler.TAG_TYPES[tag.getType()]);
writer.startAndEndTag(RepositoriesViewContentHandler.TAG_TAG, attributes, true);
}
}
Set refreshSet = (Set)autoRefreshFiles.get(path);
if (refreshSet != null) {
Iterator filenameIt = refreshSet.iterator();
while (filenameIt.hasNext()) {
String filename = (String)filenameIt.next();
attributes.clear();
attributes.put(RepositoriesViewContentHandler.FULL_PATH_ATTRIBUTE, filename);
writer.startAndEndTag(RepositoriesViewContentHandler.AUTO_REFRESH_FILE_TAG, attributes, true);
}
}
writer.endTag(RepositoriesViewContentHandler.MODULE_TAG);
}
writer.endTag(RepositoriesViewContentHandler.REPOSITORY_TAG);
}
/**
* Method getKnownTags.
* @param remotePath
* @return CVSTag[]
*/
public CVSTag[] getKnownTags(String remotePath) {
Set tagSet = (Set)knownTags.get(getCachePathFor(remotePath));
if (tagSet == null) return new CVSTag[0];
return (CVSTag[]) tagSet.toArray(new CVSTag[tagSet.size()]);
}
public String[] getKnownRemotePaths() {
Set paths = new HashSet();
paths.addAll(knownTags.keySet());
paths.addAll(autoRefreshFiles.keySet());
return (String[]) paths.toArray(new String[paths.size()]);
}
/**
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (ICVSRepositoryLocation.class.equals(adapter)) return getRoot();
return super.getAdapter(adapter);
}
public ICVSRemoteResource[] filterResources(ICVSRemoteResource[] resource) {
List result = new ArrayList();
for (int i = 0; i < resource.length; i++) {
ICVSRemoteResource remoteResource = resource[i];
if (remoteResource instanceof ICVSRemoteFolder) {
ICVSRemoteFolder folder = (ICVSRemoteFolder) remoteResource;
if (tagIsKnown(remoteResource)) {
result.add(folder);
}
}
}
return (ICVSRemoteResource[]) result.toArray(new ICVSRemoteResource[result.size()]);
}
/**
* Method tagIsKnown.
* @param remoteResource
* @return boolean
*/
public boolean tagIsKnown(ICVSRemoteResource remoteResource) {
if (remoteResource instanceof ICVSRemoteFolder) {
ICVSRemoteFolder folder = (ICVSRemoteFolder) remoteResource;
String path = getCachePathFor(folder.getRepositoryRelativePath());
CVSTag[] tags = getKnownTags(path);
CVSTag tag = folder.getTag();
for (int i = 0; i < tags.length; i++) {
CVSTag knownTag = tags[i];
if (knownTag.equals(tag)) return true;
}
}
return false;
}
/**
* This method is invoked whenever the refresh button in the
* RepositoriesView is pressed.
*/
void clearCache() {
modulesCache = null;
}
/**
* Sets the root.
* @param root The root to set
*/
void setRepositoryLocation(ICVSRepositoryLocation root) {
this.root = root;
}
}