/******************************************************************************* * Copyright (c) 2004, 2006 * Thomas Hallgren, Kenneth Olwing, Mitch Sonies * Pontus Rydin, Nils Unden, Peer Torngren * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the individual * copyright holders listed above, as Initial Contributors under such license. * The text of such license is available at www.eclipse.org. * * Contributors: * Lorenzo Bettini - https://bugs.eclipse.org/bugs/show_bug.cgi?id=428301 *******************************************************************************/ package org.eclipse.buckminster.cvspkg.internal; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.net.URI; import java.net.URL; import java.util.Date; import java.util.Map; import java.util.StringTokenizer; import org.eclipse.buckminster.core.RMContext; import org.eclipse.buckminster.core.ctype.IComponentType; import org.eclipse.buckminster.core.helpers.MapUtils; import org.eclipse.buckminster.core.metadata.model.Resolution; import org.eclipse.buckminster.core.reader.CatalogReaderType; import org.eclipse.buckminster.core.reader.IComponentReader; import org.eclipse.buckminster.core.reader.ITeamReaderType; import org.eclipse.buckminster.core.reader.IVersionFinder; import org.eclipse.buckminster.core.reader.ReferenceInfo; import org.eclipse.buckminster.core.resolver.NodeQuery; import org.eclipse.buckminster.core.rmap.model.Provider; import org.eclipse.buckminster.core.version.ProviderMatch; import org.eclipse.buckminster.core.version.VersionMatch; import org.eclipse.buckminster.core.version.VersionSelector; import org.eclipse.buckminster.cvspkg.Messages; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.buckminster.runtime.IOUtils; import org.eclipse.buckminster.runtime.MonitorUtils; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.internal.ccvs.core.CVSException; import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin; import org.eclipse.team.internal.ccvs.core.CVSTag; import org.eclipse.team.internal.ccvs.core.CVSTeamProvider; import org.eclipse.team.internal.ccvs.core.ICVSRemoteResource; import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation; import org.eclipse.team.internal.ccvs.core.client.Command; import org.eclipse.team.internal.ccvs.core.client.Session; import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; import org.eclipse.team.internal.ccvs.core.util.KnownRepositories; /** * @author Thomas Hallgren */ @SuppressWarnings("restriction") public class CVSReaderType extends CatalogReaderType implements ITeamReaderType { // The constructors of Command.LocalOption are not public // static class MyLocalOption extends Command.LocalOption { MyLocalOption(String opt) { super(opt); } } public static final String LOCAL_LINE_END = System.getProperty("line.separator"); //$NON-NLS-1$ public static final Command.LocalOption STDOUT = new MyLocalOption("-p"); //$NON-NLS-1$ static CVSTag getCVSTag(VersionMatch match) throws CoreException { CVSTag tag; VersionSelector selector = match.getBranchOrTag(); Date timestamp; if (selector == null && (timestamp = match.getTimestamp()) != null) tag = new CVSTag(timestamp); else tag = getCVSTag(selector); return tag; } static CVSTag getCVSTag(VersionSelector selector) throws CoreException { CVSTag tag; if (selector == null) tag = CVSTag.DEFAULT; else tag = new CVSTag(selector.getName(), selector.getType() == VersionSelector.TAG ? CVSTag.VERSION : CVSTag.BRANCH); return tag; } public static ICVSRepositoryLocation getDemotedLocation(ICVSRepositoryLocation known) throws CVSException { String knownMethod = known.getMethod().getName(); for (ICVSRepositoryLocation wanted : CVSProviderPlugin.getPlugin().getKnownRepositories()) { if (known.getHost().equals(wanted.getHost()) && known.getPort() == wanted.getPort() && known.getRootDirectory().equals(wanted.getRootDirectory())) { String wantedMethod = wanted.getMethod().getName(); String wantedUser = wanted.getUsername(); if (knownMethod.equals(wantedMethod) || ("extssh".equals(knownMethod) && "pserver".equals(wantedMethod))) //$NON-NLS-1$ //$NON-NLS-2$ { if (wantedUser == null || "anonymous".equals(wantedUser) || wantedUser.equals(known.getUsername())) //$NON-NLS-1$ return wanted; } } } return known; } public static CVSRepositoryLocation getLocationFromString(String repo) throws CVSException { CVSRepositoryLocation wanted = CVSRepositoryLocation.fromString(repo); String wantedUser = wanted.getUsername(); for (ICVSRepositoryLocation known : CVSProviderPlugin.getPlugin().getKnownRepositories()) { if (known.getHost().equals(wanted.getHost()) && known.getPort() == wanted.getPort() && known.getRootDirectory().equals(wanted.getRootDirectory())) { String knownMethod = known.getMethod().getName(); String wantedMethod = wanted.getMethod().getName(); if (knownMethod.equals(wantedMethod) || ("extssh".equals(knownMethod) && "pserver".equals(wantedMethod))) //$NON-NLS-1$ //$NON-NLS-2$ { if (wantedUser == null || "anonymous".equals(wantedUser) || wantedUser.equals(known.getUsername())) //$NON-NLS-1$ return (CVSRepositoryLocation) known; } } } KnownRepositories.getInstance().addRepository(wanted, true); return wanted; } /** * Creates an SCMURL reference to the associated source. * * @param repoLocation * @param module * @param projectName * @return project reference string or <code>null</code> if none */ private String asReference(String repoLocation, String module, String projectName, String tagName) { // parse protocol, host, repository root from repoLocation String protocol = null; String host = null; String root = null; int at = repoLocation.indexOf('@'); if (at < 0) { // should be a local protocol if (repoLocation.startsWith(":local:")) { //$NON-NLS-1$ protocol = "local"; //$NON-NLS-1$ root = repoLocation.substring(7); } } else if (at < (repoLocation.length() - 2)) { String serverRoot = repoLocation.substring(at + 1); String protocolUserPass = repoLocation.substring(0, at); int colon = serverRoot.indexOf(':'); if (colon > 0) { host = serverRoot.substring(0, colon); if (colon < (serverRoot.length() - 2)) { root = serverRoot.substring(colon + 1); } if (protocolUserPass.startsWith(":")) { //$NON-NLS-1$ colon = protocolUserPass.indexOf(':', 1); if (colon > 0) { protocol = protocolUserPass.substring(1, colon); } } else { // missing protocol, assume p-server protocol = "pserver"; //$NON-NLS-1$ } } } if (protocol == null || root == null) { return null; // invalid syntax } // use '|' as separator if the root location uses a colon for a Windows // path String sep = ":"; //$NON-NLS-1$ if (root.indexOf(':') >= 0) { sep = "|"; //$NON-NLS-1$ } StringBuffer buffer = new StringBuffer(); buffer.append("scm:cvs"); //$NON-NLS-1$ buffer.append(sep); buffer.append(protocol); buffer.append(sep); if (host != null) { buffer.append(host); buffer.append(sep); } buffer.append(root); buffer.append(sep); buffer.append(module); Path modulePath = new Path(module); if (!modulePath.lastSegment().equals(projectName)) { buffer.append(";project=\""); //$NON-NLS-1$ buffer.append(projectName); buffer.append('"'); } if (tagName != null && !tagName.equals("HEAD")) { //$NON-NLS-1$ buffer.append(";tag="); //$NON-NLS-1$ buffer.append(tagName); } return buffer.toString(); } /** * Return the arguments to be passed to the tag command */ protected String[] buildResourceArguments(IResource[] resources) throws CVSException { String[] arguments = new String[resources.length]; for (int i = 0; i < resources.length; ++i) { IPath cvsPath = resources[i].getFullPath().removeFirstSegments(1); arguments[i] = (cvsPath.segmentCount() == 0) ? Session.CURRENT_LOCAL_FOLDER : cvsPath.toString(); } return arguments; } @Override public String convertFetchFactoryLocator(Map<String, Object> fetchFactoryLocator, String componentName) throws CoreException { String cvsRoot = MapUtils.getString(fetchFactoryLocator, "cvsRoot"); //$NON-NLS-1$ if (cvsRoot == null) throw BuckminsterException.fromMessage(Messages.illegal_fetch_factory_locator); StringBuilder locator = new StringBuilder(cvsRoot); String path = MapUtils.getString(fetchFactoryLocator, "path"); //$NON-NLS-1$ locator.append(','); if (path != null) locator.append(path); else locator.append(componentName); return locator.toString(); } @Override public URL convertToURL(String repositoryLocator, VersionMatch versionMatch) throws CoreException { CVSSession session = null; try { VersionSelector versionSelector = versionMatch.getBranchOrTag(); session = new CVSSession(repositoryLocator); ICVSRepositoryLocation location = session.getLocation(); StringBuilder query = new StringBuilder(); String method = location.getMethod().getName(); if (!method.equals("pserver")) //$NON-NLS-1$ { query.append("method="); //$NON-NLS-1$ query.append(method); } if (versionSelector != null) { if (query.length() > 0) query.append('&'); query.append("version"); //$NON-NLS-1$ query.append(versionSelector.toString()); } String user = location.getUsername(); if ("anonymous".equals(user)) //$NON-NLS-1$ user = null; IPath modulePath = new Path(session.getModuleName()).makeAbsolute(); URI uri = new URI("cvs", user, location.getHost(), -1, location.getRootDirectory(), query.toString(), //$NON-NLS-1$ modulePath.toPortableString()); return uri.toURL(); } catch (Exception e) { throw BuckminsterException.wrap(e); } finally { if (session != null) session.close(); } } @Override public ReferenceInfo extractReferenceInfo(String reference) throws CoreException { StringTokenizer tokenizer = new StringTokenizer(reference, ","); //$NON-NLS-1$ String version = tokenizer.nextToken(); // If this is a newer version, then ignore it if (!version.equals("1.0")) //$NON-NLS-1$ throw BuckminsterException.fromMessage("The cvs reader only understands version PSF project references of version 1.0"); //$NON-NLS-1$ String repositoryLocation = tokenizer.nextToken(); String module = tokenizer.nextToken(); String projectName = tokenizer.nextToken(); VersionSelector selector = null; if (tokenizer.hasMoreElements()) { String branchInfo = tokenizer.nextToken(); if (!(branchInfo.length() == 0 || CVSTag.DEFAULT.toString().equals(branchInfo))) selector = VersionSelector.branch(branchInfo); } return new ReferenceInfo(repositoryLocation + ',' + module, selector, projectName); } @Override public URI getArtifactURL(Resolution resolution, RMContext context) throws CoreException { return null; } @Override public Date getLastModification(File workingCopy, IProgressMonitor monitor) throws CoreException { monitor.beginTask(null, 30); File[] folders = workingCopy.listFiles(); MonitorUtils.worked(monitor, 10); if (folders == null) { // Folder was not a folder after all // monitor.done(); return null; } Date youngest = null; if (folders.length > 0) { IProgressMonitor subMon = MonitorUtils.subMonitor(monitor, 10); subMon.beginTask(null, folders.length * 10); for (File subFolder : folders) { Date ts = getLastModification(subFolder, MonitorUtils.subMonitor(subMon, 10)); if (ts != null && (youngest == null || ts.compareTo(youngest) > 0)) youngest = ts; } subMon.done(); } else MonitorUtils.worked(monitor, 10); File entries = new File(new File(workingCopy, FileSystemCopier.CVS_DIRNAME), FileSystemCopier.ENTRIES); BufferedReader input = null; try { input = new BufferedReader(new FileReader(entries)); String line; while ((line = input.readLine()) != null) { try { ResourceSyncInfo info = new ResourceSyncInfo(line, null); Date ts = info.getTimeStamp(); if (ts != null && (youngest == null || ts.compareTo(youngest) > 0)) youngest = ts; } catch (CVSException e) { } } MonitorUtils.worked(monitor, 10); } catch (FileNotFoundException e) { // No Entries file present in this folder } catch (IOException e) { throw BuckminsterException.wrap(e); } finally { IOUtils.close(input); monitor.done(); } return youngest; } @Override public Date getLastModification(String repositoryLocation, VersionSelector versionSelector, IProgressMonitor monitor) throws CoreException { CVSSession session = null; try { session = new CVSSession(repositoryLocation); RepositoryMetaData metaData = RepositoryMetaData.getMetaData(session, getCVSTag(versionSelector), monitor); return metaData.getLastModification(); } finally { if (session != null) session.close(); } } @Override public IComponentReader getReader(ProviderMatch providerMatch, IProgressMonitor monitor) throws CoreException { MonitorUtils.complete(monitor); return new CVSReader(this, providerMatch); } @Override public String getRemoteLocation(File workingCopy, IProgressMonitor monitor) throws CoreException { IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); IPath location = Path.fromOSString(workingCopy.toString()); IResource resource = wsRoot.getContainerForLocation(location); if (resource == null) resource = wsRoot.getFileForLocation(location); if (resource == null) // // We only support workspace resources at this time // return null; ICVSRemoteResource cvsResource = CVSWorkspaceRoot.getRemoteResourceFor(resource); if (cvsResource == null) return null; return cvsResource.getRepository().getLocation(false) + ',' + cvsResource.getRepositoryRelativePath(); } @Override public String getSourceReference(IResource resource, IProgressMonitor monitor) throws CoreException { ICVSRemoteResource cvsResource = CVSWorkspaceRoot.getRemoteResourceFor(resource); if (cvsResource == null) return null; String tag = null; ResourceSyncInfo syncInfo = cvsResource.getSyncInfo(); if (syncInfo != null) { CVSTag cvsTag = syncInfo.getTag(); if (cvsTag != null) tag = cvsTag.getName(); } ICVSRepositoryLocation repo = cvsResource.getRepository(); repo = getDemotedLocation(repo); return asReference(repo.getLocation(false), cvsResource.getRepositoryRelativePath(), resource.getProject().getName(), tag); } @Override public IVersionFinder getVersionFinder(Provider provider, IComponentType ctype, NodeQuery nodeQuery, IProgressMonitor monitor) throws CoreException { MonitorUtils.complete(monitor); return new VersionFinder(provider, ctype, nodeQuery); } @Override public void shareProject(IProject project, Resolution cr, RMContext context, IProgressMonitor monitor) throws CoreException { // Register the project with the CVSTeamProvider. // String cvsTypeID = CVSProviderPlugin.getTypeId(); RepositoryProvider.map(project, cvsTypeID); ((CVSTeamProvider) RepositoryProvider.getProvider(project, cvsTypeID)) .setWatchEditEnabled(CVSProviderPlugin.getPlugin().isWatchEditEnabled()); } @Override public IStatus tag(RepositoryProvider provider, IResource[] resources, String tag, boolean recurse, IProgressMonitor progress) throws CVSException { CVSWorkspaceRoot root = ((CVSTeamProvider) provider).getCVSWorkspaceRoot(); Command.LocalOption[] commandOptions = Command.NO_LOCAL_OPTIONS; if (!recurse) commandOptions = Command.DO_NOT_RECURSE.addTo(commandOptions); // Build the argument list String[] arguments = buildResourceArguments(resources); // Execute the command progress.beginTask(null, 100); try { Session session = new Session(root.getRemoteLocation(), root.getLocalRoot()); // Opening the session takes 20% of the time session.open(MonitorUtils.subMonitor(progress, 20), true); try { return Command.TAG.execute(session, Command.NO_GLOBAL_OPTIONS, commandOptions, new CVSTag(tag, CVSTag.VERSION), arguments, null, MonitorUtils.subMonitor(progress, 80)); } finally { session.close(); } } finally { progress.done(); } } }