| /******************************************************************************* |
| * Copyright (c) 2000, 2011 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.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.core.ProjectSetCapability; |
| 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 = "cvs"; //$NON-NLS-1$ |
| private final ICVSRepositoryLocation repository; |
| private final IPath path; |
| private final CVSTag tag; |
| private final String revision; |
| private final String projectName; |
| |
| /** |
| * Convert the given URI to a CVSURI. There are three supported formats: the |
| * original opaque format, a newer hierarchical format and a CVS SCM URL |
| * format. |
| * |
| * In the last format, as delimiter you can use either colon ':' or, if you |
| * use a colon for one of the variables (e.g. a windows path), a pipe '|'. |
| * For more information visit http://maven.apache.org/scm/cvs.html. Please |
| * note, that URIs with the pipe separator are currently not supported. |
| * |
| * <ul> |
| * <li>{@literal cvs://[:]method:user[:password]@host:[port]/root/path#project/path[,tagName]}</li> |
| * <li>{@literal cvs://_method_user[_password]~host_[port]!root!path/project/path[?<version,branch,date,revision>=tagName]}</li> |
| * <li>{@literal scm:cvs<delimiter>method<delimiter>[user[<delimiter>password]@]host[<delimiter>port]<delimiter>/root/path<delimiter>project/path[;project="projectName"][;tag=tagName]}</li> |
| * </ul> |
| * @param uri the URI |
| * @return a CVS URI |
| */ |
| public static CVSURI fromUri(URI uri) { |
| try { |
| if (ProjectSetCapability.SCHEME_SCM.equals(uri.getScheme())) { |
| uri = convert(uri); |
| } |
| 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); |
| String projectName = getProjectName(uri); |
| return new CVSURI(repository, path, tag, null, projectName); |
| } |
| } catch (CVSException e) { |
| CVSProviderPlugin.log(e); |
| throw new IllegalArgumentException(NLS.bind(CVSMessages.CVSURI_InvalidURI, new String[] {uri.toString(), e.getMessage()})); |
| } |
| } |
| |
| private static URI convert(URI uri) { |
| StringBuilder sb = new StringBuilder(); |
| String ssp = uri.getSchemeSpecificPart(); |
| int i = ssp.lastIndexOf(':'); |
| sb.append(ssp.substring(0, i)).append('#'); |
| int j = ssp.indexOf(';'); |
| if (j != -1) { |
| sb.append(ssp.substring(i + 1, j)); |
| String[] params = ssp.substring(j).split(";"); //$NON-NLS-1$ |
| String projectName = ""; //$NON-NLS-1$ |
| for (String param : params) { |
| // PDE way of providing tags |
| if (param.startsWith("tag=")) { //$NON-NLS-1$ |
| sb.append(",version="); //$NON-NLS-1$ |
| sb.append(param.substring(param.indexOf('=') + 1)); |
| } else if (param.startsWith("version=")) { //$NON-NLS-1$ |
| sb.append(',').append(param); |
| } else if (param.startsWith("project=")) { //$NON-NLS-1$ |
| projectName = param.substring(param.indexOf('=') + 1); |
| } |
| } |
| sb.append(',').append(projectName); // can be "" |
| } else { |
| sb.append(ssp.substring(i + 1)); |
| } |
| return URI.create(sb.toString()); |
| } |
| |
| private static CVSTag getTag(URI uri) { |
| String query = uri.getQuery(); |
| if (query == null) |
| return null; |
| return getTag(query); |
| } |
| |
| private static CVSTag getTag(String s) { |
| StringTokenizer tokens = new StringTokenizer(s, ","); //$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 == null) |
| return null; |
| if (authority.indexOf('/') != -1) |
| return null; |
| if (authority.indexOf('!') == -1) |
| return null; |
| authority = decodeAuthority(authority); |
| return CVSRepositoryLocation.fromString(authority); |
| } |
| |
| private static String getProjectName(URI uri) { |
| String f = uri.getFragment(); |
| if (f != null) { |
| int i = f.lastIndexOf(','); |
| if (i != -1) { |
| String s = f.substring(i + 1); |
| if (!s.equals("")) //$NON-NLS-1$ |
| return s; |
| } |
| } |
| return null; |
| } |
| |
| private static CVSTag getOldTag(URI uri) { |
| String f = uri.getFragment(); |
| int i = f.indexOf(','); |
| if (i == -1) { |
| return CVSTag.DEFAULT; |
| } |
| CVSTag tag = getTag(f.substring(i + 1)); |
| if (tag != null) |
| return tag; |
| |
| 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, null); |
| } |
| |
| public CVSURI(ICVSRepositoryLocation repository, IPath path, CVSTag tag, String revision) { |
| this(repository, path, tag, revision, null); |
| } |
| |
| public CVSURI(ICVSRepositoryLocation repository, IPath path, CVSTag tag, String revision, String projectName) { |
| this.repository = repository; |
| this.path = path; |
| this.tag = tag; |
| if (revision != null && !revision.equals(ResourceSyncInfo.ADDED_REVISION)) |
| this.revision = revision; |
| else |
| this.revision = null; |
| this.projectName = projectName; |
| } |
| |
| 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$ |
| } |
| } |
| if (projectName != null) { |
| String string = "project=" + projectName; //$NON-NLS-1$ |
| if (query == null) { |
| query = string; |
| } else { |
| query = query + "," + string; //$NON-NLS-1$ |
| } |
| } |
| return new URI(SCHEME_CVS, 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; |
| } |
| |
| public String getProjectName() { |
| return projectName; |
| } |
| } |