package org.tmatesoft.svn.core.internal.wc2.remote; import java.io.File; import java.io.OutputStream; import java.util.Map; import org.tmatesoft.svn.core.SVNCancelException; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.SVNProperties; import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNCancellableEditor; import org.tmatesoft.svn.core.internal.wc.SVNCancellableOutputStream; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc.SVNEventFactory; import org.tmatesoft.svn.core.internal.wc.SVNExportEditor; import org.tmatesoft.svn.core.internal.wc.SVNExternal; import org.tmatesoft.svn.core.internal.wc.SVNFileType; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc.admin.SVNTranslator; import org.tmatesoft.svn.core.internal.wc17.db.Structure; import org.tmatesoft.svn.core.internal.wc2.SvnRemoteOperationRunner; import org.tmatesoft.svn.core.internal.wc2.SvnRepositoryAccess.RepositoryInfo; import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration; import org.tmatesoft.svn.core.io.ISVNReporter; import org.tmatesoft.svn.core.io.ISVNReporterBaton; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.wc.ISVNOptions; import org.tmatesoft.svn.core.wc.SVNEventAction; import org.tmatesoft.svn.core.wc2.SvnExport; import org.tmatesoft.svn.core.wc2.SvnTarget; import org.tmatesoft.svn.util.SVNLogType; public class SvnRemoteExport extends SvnRemoteOperationRunner<Long, SvnExport> { @Override public boolean isApplicable(SvnExport operation, SvnWcGeneration wcGeneration) throws SVNException { // remote source if (!operation.getSource().isLocal()) { return true; } return false; } @Override protected Long run() throws SVNException { SvnTarget exportSource = getOperation().getSource(); Structure<RepositoryInfo> repositoryInfo = getRepositoryAccess().createRepositoryFor(exportSource, getOperation().getRevision(), exportSource.getResolvedPegRevision(), exportSource.getFile()); final long revNumber = repositoryInfo.lng(RepositoryInfo.revision); SVNRepository repository = repositoryInfo.<SVNRepository>get(RepositoryInfo.repository); repositoryInfo.release(); File dstPath = getOperation().getFirstTarget().getFile(); SVNDepth depth = getOperation().getDepth(); boolean force = getOperation().isForce(); boolean expandKeywords = getOperation().isExpandKeywords(); String eolStyle = getOperation().getEolStyle(); boolean ignoreExternals = getOperation().isIgnoreExternals(); ISVNOptions options = getOperation().getOptions(); SVNNodeKind dstKind = repository.checkPath("", revNumber); if (dstKind == SVNNodeKind.DIR) { SVNExportEditor editor = new SVNExportEditor(this, repository.getLocation().toString(), dstPath, force, eolStyle, expandKeywords, repository.getRepositoryRoot(true).toString(), options); repository.update(revNumber, null, depth, false, new ISVNReporterBaton() { public void report(ISVNReporter reporter) throws SVNException { reporter.setPath("", null, revNumber, SVNDepth.INFINITY, true); reporter.finishReport(); } }, SVNCancellableEditor.newInstance(editor, this, null)); SVNFileType fileType = SVNFileType.getType(dstPath); if (fileType == SVNFileType.NONE) { editor.openRoot(revNumber); } if (!ignoreExternals && depth == SVNDepth.INFINITY) { Map<String,String> externals = editor.getCollectedExternals(); handleExternals(externals, repository.getLocation(), dstPath, repository.getRepositoryRoot(true)); } } else if (dstKind == SVNNodeKind.FILE) { String url = repository.getLocation().toString(); String repositoryRoot = expandKeywords ? repository.getRepositoryRoot(true).toString() : null; if (dstPath.isDirectory()) { dstPath = new File(dstPath, SVNEncodingUtil.uriDecode(SVNPathUtil.tail(url))); } if (dstPath.exists()) { if (!force) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, "Path ''{0}'' already exists", dstPath); SVNErrorManager.error(err, SVNLogType.WC); } } else { dstPath.getParentFile().mkdirs(); } SVNProperties properties = new SVNProperties(); OutputStream os = null; File tmpFile = SVNFileUtil.createUniqueFile(dstPath.getParentFile(), ".export", ".tmp", false); try { os = SVNFileUtil.openFileForWriting(tmpFile); try { repository.getFile("", revNumber, properties, new SVNCancellableOutputStream(os, this)); } finally { SVNFileUtil.closeFile(os); } if (force && dstPath.exists()) { SVNFileUtil.deleteAll(dstPath, this); } if (!expandKeywords) { properties.put(SVNProperty.MIME_TYPE, "application/octet-stream"); } String mimeType = properties.getStringValue(SVNProperty.MIME_TYPE); boolean binary = SVNProperty.isBinaryMimeType(mimeType); String charset = SVNTranslator.getCharset(properties.getStringValue(SVNProperty.CHARSET), mimeType, url, options); Map<String, byte[]> keywords = SVNTranslator.computeKeywords(properties.getStringValue(SVNProperty.KEYWORDS), url, repositoryRoot, properties.getStringValue(SVNProperty.LAST_AUTHOR), properties .getStringValue(SVNProperty.COMMITTED_DATE), properties.getStringValue(SVNProperty.COMMITTED_REVISION), options); byte[] eols = null; if (SVNProperty.EOL_STYLE_NATIVE.equals(properties.getStringValue(SVNProperty.EOL_STYLE))) { eols = SVNTranslator.getEOL(eolStyle != null ? eolStyle : properties.getStringValue(SVNProperty.EOL_STYLE), options); } else if (properties.containsName(SVNProperty.EOL_STYLE)) { eols = SVNTranslator.getEOL(properties.getStringValue(SVNProperty.EOL_STYLE), options); } if (binary) { charset = null; eols = null; keywords = null; } SVNTranslator.translate(tmpFile, dstPath, charset, eols, keywords, properties.getStringValue(SVNProperty.SPECIAL) != null, true); } finally { SVNFileUtil.deleteFile(tmpFile); } if (properties.getStringValue(SVNProperty.EXECUTABLE) != null) { SVNFileUtil.setExecutable(dstPath, true); } handleEvent(SVNEventFactory.createSVNEvent(dstPath, SVNNodeKind.FILE, null, SVNRepository.INVALID_REVISION, SVNEventAction.UPDATE_ADD, null, null, null)); } else { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "URL ''{0}'' doesn't exist", repository.getLocation()); SVNErrorManager.error(err, SVNLogType.WC); } handleEvent(SVNEventFactory.createSVNEvent(dstPath, SVNNodeKind.NONE, null, revNumber, SVNEventAction.UPDATE_COMPLETED, null, null, null)); return revNumber; } private void handleExternals(Map<String, String> externals, SVNURL fromUrl, File toPath, SVNURL reposRootUrl) throws SVNException { for (String relativePath : externals.keySet()) { File dirPath = new File(toPath, relativePath); String externalValue = externals.get(relativePath); SVNExternal[] exts = SVNExternal.parseExternals(dirPath, externalValue); SVNURL directoryUrl = fromUrl.appendPath(relativePath, false); for (int i = 0; i < exts.length; i++) { File externalDirectory = new File(dirPath, exts[i].getPath()); File parentDirectory = SVNFileUtil.getParentFile(externalDirectory); if (parentDirectory != null) { SVNFileUtil.ensureDirectoryExists(parentDirectory); } exts[i].resolveURL(reposRootUrl, directoryUrl); SVNURL externalUrl = exts[i].getResolvedURL(); SvnExport export = getOperation().getOperationFactory().createExport(); export.setSource(SvnTarget.fromURL(externalUrl, exts[i].getPegRevision())); export.setSingleTarget(SvnTarget.fromFile(externalDirectory)); export.setDepth(SVNDepth.INFINITY); export.setExpandKeywords(getOperation().isExpandKeywords()); export.setEolStyle(getOperation().getEolStyle()); export.setRevision(exts[i].getRevision()); export.setForce(true); export.setIgnoreExternals(false); export.setSleepForTimestamp(false); try { export.run(); } catch (SVNCancelException e) { throw e; } catch (SVNException e) { handleEvent(SVNEventFactory.createSVNEvent(externalDirectory, SVNNodeKind.NONE, null, -1, SVNEventAction.FAILED_EXTERNAL, SVNEventAction.UPDATE_EXTERNAL_REMOVED, e.getErrorMessage(), null)); } } } } }