blob: 8cc5ccc67b9fa3cfc364c43c168696bab7d9e048 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ccvs.core.filesystem;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.StringTokenizer;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.team.internal.ccvs.core.*;
import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation;
import org.eclipse.team.internal.ccvs.core.resources.RemoteFile;
import org.eclipse.team.internal.ccvs.core.resources.RemoteFolder;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
public class CVSURI {
private static final String SCHEME = "cvs"; //$NON-NLS-1$
private final ICVSRepositoryLocation repository;
private final IPath path;
private final CVSTag tag;
private final String revision;
/**
* Convert the given URI to a CVSURI. There are two supported formats: the
* original opaque format and a newer hierarchical format.
* <ul>
* <li>cvs://[:]method:user[:password]@host:[port]/root/path#project/path[,tagName]</li>
* <li>cvs://:method:user[:password]@host:[port]!root!path/project/path[?<version,branch,date,revision>=tagName]</li>
* </ul>
* @param uri the URI
* @return a CVS URI
*/
public static CVSURI fromUri(URI uri) {
try {
ICVSRepositoryLocation repository = getRepository(uri);
if (repository != null) {
IPath path = new Path(null, uri.getPath());
CVSTag tag = getTag(uri);
String revision = getRevision(uri);
return new CVSURI(repository, path, tag, revision);
} else {
repository = getOldRepository(uri);
IPath path = getOldPath(uri);
CVSTag tag = getOldTag(uri);
return new CVSURI(repository, path, tag);
}
} catch (CVSException e) {
CVSProviderPlugin.log(e);
throw new IllegalArgumentException(NLS.bind(CVSMessages.CVSURI_InvalidURI, new String[] {uri.toString(), e.getMessage()}));
}
}
private static CVSTag getTag(URI uri) {
String query = uri.getQuery();
if (query == null)
return null;
StringTokenizer tokens = new StringTokenizer(query, ","); //$NON-NLS-1$
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
int index = token.indexOf('=');
if (index != -1) {
String type = token.substring(0, index);
String value = token.substring(index + 1);
if (value.length() > 0) {
int tagType = getTagType(type);
if (tagType != -1)
return new CVSTag(value, tagType);
}
}
}
return null;
}
private static String getRevision(URI uri) {
String query = uri.getQuery();
if (query == null)
return null;
StringTokenizer tokens = new StringTokenizer(query, ","); //$NON-NLS-1$
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
int index = token.indexOf('=');
if (index != -1) {
String type = token.substring(0, index);
String value = token.substring(index + 1);
if (type.equals("revision") && isValidRevision(value)) { //$NON-NLS-1$
return value;
}
}
}
return null;
}
private static boolean isValidRevision(String value) {
return value.matches("\\d+\\.\\d+(?:\\.\\d+)*"); //$NON-NLS-1$
}
private static int getTagType(String type) {
if (type.equalsIgnoreCase("version")) //$NON-NLS-1$
return CVSTag.VERSION;
if (type.equalsIgnoreCase("branch")) //$NON-NLS-1$
return CVSTag.BRANCH;
if (type.equalsIgnoreCase("date")) //$NON-NLS-1$
return CVSTag.DATE;
return -1;
}
private static ICVSRepositoryLocation getRepository(URI uri) throws CVSException {
String authority = uri.getAuthority();
if (authority.indexOf('/') != -1)
return null;
if (authority.indexOf('!') == -1)
return null;
authority = decodeAuthority(authority);
return CVSRepositoryLocation.fromString(authority);
}
private static CVSTag getOldTag(URI uri) {
String f = uri.getFragment();
int i = f.indexOf(',');
if (i == -1) {
return CVSTag.DEFAULT;
}
return CVSTag.DEFAULT;//just use HEAD for now (name, CVSTag.BRANCH);
}
private static IPath getOldPath(URI uri) {
String path = uri.getFragment();
int i = path.indexOf(',');
if (i != -1) {
path = path.substring(0, i);
}
return new Path(path);
}
private static ICVSRepositoryLocation getOldRepository(URI uri) throws CVSException {
String ssp = uri.getSchemeSpecificPart();
if (!ssp.startsWith(":")) { //$NON-NLS-1$
ssp = ":" + ssp; //$NON-NLS-1$
}
return CVSRepositoryLocation.fromString(ssp);
}
public CVSURI(ICVSRepositoryLocation repository, IPath path, CVSTag tag) {
this(repository, path, tag, null);
}
public CVSURI(ICVSRepositoryLocation repository, IPath path, CVSTag tag, String revision) {
this.repository = repository;
this.path = path;
this.tag = tag;
if (revision != null && !revision.equals(ResourceSyncInfo.ADDED_REVISION))
this.revision = revision;
else
this.revision = null;
}
public CVSURI append(String name) {
return new CVSURI(repository, path.append(name), tag);
}
public CVSURI append(IPath childPath) {
return new CVSURI(repository, path.append(childPath), tag);
}
public String getLastSegment() {
return path.lastSegment();
}
public URI toURI() {
try {
String authority = repository.getLocation(false);
authority = ensureRegistryBasedAuthority(authority);
String pathString = path.toString();
if (!pathString.startsWith("/")) { //$NON-NLS-1$
pathString = "/" + pathString; //$NON-NLS-1$
}
String query = null;
if (tag != null && tag.getType() != CVSTag.HEAD) {
query = getQueryType(tag) + "=" + tag.getName(); //$NON-NLS-1$
}
if (revision != null) {
String string = "revision=" + revision; //$NON-NLS-1$
if (query == null) {
query = string;
} else {
query = query + "," + string; //$NON-NLS-1$
}
}
return new URI(SCHEME, authority, pathString, query, null);
} catch (URISyntaxException e) {
CVSProviderPlugin.log(IStatus.ERROR, NLS.bind("An error occurred while creating a URI for {0} {1}", repository, path), e); //$NON-NLS-1$
throw new IllegalStateException(e.getMessage());
}
}
/*
* Ensure that the authority will not be confused with a
* server based authority. To do this, we need to convert
* any /, : and @ to another form.
*/
private String ensureRegistryBasedAuthority(String authority) {
// Encode / so the authority doesn't conflict with the path
authority = encode('/', '!', authority);
// Encode @ to avoid URI interpreting the authority as a server based authority
authority = encode('@', '~', authority);
// Encode : to avoid URI interpreting the authority as a server based authority
authority = encode(':', '_', authority);
return authority;
}
private static String decodeAuthority(String authority) {
authority = decode('/', '!', authority);
authority = decode('@', '~', authority);
authority = decode(':', '_', authority);
return authority;
}
private String encode(char charToEncode, char encoding, String string) {
// First, escape any occurrences of the encoding character
String result = string.replaceAll(new String(new char[] { encoding }), new String(new char[] { encoding, encoding }));
// Convert / to ! to avoid URI parsing part of the authority as the path
return result.replace(charToEncode, encoding);
}
private static String decode(char encodedChar, char encoding, String string) {
// Convert the encoded char back
String reuslt = string.replace(encoding, encodedChar);
// Convert any double occurrences of the encoded char back to the encoding
return reuslt.replaceAll(new String(new char[] { encodedChar, encodedChar }), new String(new char[] { encoding }));
}
private static String getQueryType(CVSTag tag) {
switch (tag.getType()) {
case CVSTag.BRANCH:
return "branch"; //$NON-NLS-1$
case CVSTag.DATE:
return "date"; //$NON-NLS-1$
}
return "version"; //$NON-NLS-1$
}
public boolean isRepositoryRoot() {
return path.segmentCount() == 0;
}
public CVSURI removeLastSegment() {
return new CVSURI(repository, path.removeLastSegments(1), tag);
}
public ICVSRemoteFolder getParentFolder() {
return removeLastSegment().toFolder();
}
public String getRepositoryName() {
return repository.toString();
}
public CVSURI getProjectURI(){
return new CVSURI(repository, path.uptoSegment(1), tag);
}
public ICVSRemoteFolder toFolder() {
return new RemoteFolder(null, repository, path.toString(), tag);
}
public ICVSRemoteFile toFile() {
// TODO: What about keyword mode?
return RemoteFile.create(path.toString(), repository, tag, revision);
}
public String toString() {
return "[Path: "+this.path.toString()+" Tag: "+tag.getName()+ " Repo: " +repository.getRootDirectory() +"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
public IPath getPath(){
return path;
}
public IPath getProjectStrippedPath() {
if (path.segmentCount() > 1)
return path.removeFirstSegments(1);
return path;
}
public ICVSRepositoryLocation getRepository() {
return repository;
}
public CVSTag getTag() {
return tag;
}
public String getRevision() {
return revision;
}
}