/******************************************************************************* * Copyright (c) 2007, 2014 Wind River Systems, Inc. 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: * Markus Schorn - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.URI; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashSet; import java.util.Map; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexLocationConverter; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.LanguageManager; import org.eclipse.cdt.internal.core.CCoreInternals; import org.eclipse.cdt.internal.core.pdom.dom.PDOMProjectIndexLocationConverter; import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences; import org.eclipse.cdt.internal.core.resources.ResourceLookup; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IWorkspaceRunnable; 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.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubProgressMonitor; public class TeamPDOMExportOperation implements IWorkspaceRunnable { /** * Option constant (value:1) to indicate that a resource snapshot * should be saved along with the exported PDOM. * @since 5.2 */ public static int EXPORT_OPTION_RESOURCE_SNAPSHOT = 1; private static final String RESOURCE_PREFIX = "res-"; //$NON-NLS-1$ private static final String CDT_PREFIX = "cdt-"; //$NON-NLS-1$ private static final String RESOURCE_SNAP_EXTENSION = "snap.zip"; //$NON-NLS-1$ private ICProject fProject; private String fTargetLocation; private File fTargetLocationFile; private MessageDigest fMessageDigest; private int fOptions; public TeamPDOMExportOperation(ICProject project) { fProject= project; } public void setTargetLocation(String location) { fTargetLocation= location; } public void setOptions(int options) { fOptions = options; } public void setAlgorithm(MessageDigest md) { fMessageDigest= md; } @Override public void run(IProgressMonitor monitor) throws CoreException { getMessageDigest(); getTargetLocation(); File tmpPDOM= null; File tmpChecksums= null; try { tmpPDOM = File.createTempFile("tmp", ".pdom"); //$NON-NLS-1$//$NON-NLS-2$ tmpChecksums= File.createTempFile("checksums", ".dat"); //$NON-NLS-1$ //$NON-NLS-2$ } catch (IOException e) { throw new CoreException(CCorePlugin.createStatus(Messages.TeamPDOMExportOperation_errorCreatingTempFile, e)); } try { PDOMManager pdomManager= CCoreInternals.getPDOMManager(); // wait for indexer monitor.beginTask("", 100); //$NON-NLS-1$ pdomManager.joinIndexer(Integer.MAX_VALUE, subMonitor(monitor, 1)); checkMonitor(monitor); // create index IIndexLocationConverter converter= new PDOMProjectIndexLocationConverter(fProject.getProject(), true); pdomManager.exportProjectPDOM(fProject, tmpPDOM, converter, monitor); checkMonitor(monitor); monitor.worked(5); // create checksums PDOM pdom= new PDOM(tmpPDOM, converter, LanguageManager.getInstance().getPDOMLinkageFactoryMappings()); pdom.acquireReadLock(); try { monitor.setTaskName(Messages.Checksums_taskComputeChecksums); createChecksums(fProject, pdom, tmpChecksums, subMonitor(monitor, 94)); pdom.db.setExclusiveLock(); // The tmpPDOM is all ours. pdom.close(); } finally { pdom.releaseReadLock(); } // create archive createArchive(tmpPDOM, tmpChecksums); // store preferences monitor.setTaskName(Messages.TeamPDOMExportOperation_taskExportIndex); IndexerPreferences.setIndexImportLocation(fProject.getProject(), fTargetLocation.toString()); // store resource snapshot if ((fOptions & EXPORT_OPTION_RESOURCE_SNAPSHOT) != 0) { IPath p = Path.fromOSString(fTargetLocationFile.getAbsolutePath()); p = computeSnapshotPath(p); URI snapURI = URIUtil.toURI(p); fProject.getProject().saveSnapshot(IProject.SNAPSHOT_TREE | /*Project.SNAPSHOT_SET_AUTOLOAD*/2, snapURI, null); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } finally { if (tmpPDOM != null) { tmpPDOM.delete(); } if (tmpChecksums != null) { tmpChecksums.delete(); } } } private IPath computeSnapshotPath(IPath p) { final String fileName = p.lastSegment(); if (fileName.startsWith(CDT_PREFIX)) { return p.removeLastSegments(1).append(RESOURCE_PREFIX + fileName.substring(4)); } return p.removeFileExtension().addFileExtension(RESOURCE_SNAP_EXTENSION); } private void getTargetLocation() throws CoreException { fTargetLocationFile= TeamPDOMImportOperation.expandLocation(fProject.getProject(), fTargetLocation); } private void getMessageDigest() throws CoreException { if (fMessageDigest == null) { try { fMessageDigest= Checksums.getDefaultAlgorithm(); } catch (NoSuchAlgorithmException e) { throw new CoreException(CCorePlugin.createStatus(e.getMessage(), e)); } } } private void createChecksums(ICProject cproject, PDOM pdom, File target, IProgressMonitor monitor) throws CoreException { HashSet<String> fullPaths= new HashSet<String>(); try { pdom.acquireReadLock(); } catch (InterruptedException e) { throw new OperationCanceledException(); } try { IIndexFile[] ifiles= pdom.getAllFiles(); for (IIndexFile ifile : ifiles) { String fullPath= ifile.getLocation().getFullPath(); if (fullPath != null) { fullPaths.add(fullPath); } } } finally { pdom.releaseReadLock(); } int i=0; IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot(); IFile[] files= new IFile[fullPaths.size()]; for (String fullPath : fullPaths) { files[i++]= root.getFile(new Path(fullPath)); } Map<String, Object> map= Checksums.createChecksumMap(files, fMessageDigest, monitor); writeChecksums(map, target); } private void writeChecksums(Map<?, ?> map, File target) throws CoreException { ObjectOutputStream out= null; try { out= new ObjectOutputStream(new FileOutputStream(target)); out.writeObject(map); } catch (IOException e) { throw new CoreException(CCorePlugin.createStatus(Messages.TeamPDOMExportOperation_errorWriteTempFile, e)); } finally { close(out); } } private void close(InputStream in) { try { if (in != null) { in.close(); } } catch (IOException e) { CCorePlugin.log(e); } } private void close(OutputStream out) { try { if (out != null) { out.close(); } } catch (IOException e) { CCorePlugin.log(e); } } private void createArchive(File tmpPDOM, File tmpChecksums) throws CoreException { fTargetLocationFile.delete(); ZipOutputStream out= null; try { fTargetLocationFile.getParentFile().mkdirs(); out= new ZipOutputStream(new FileOutputStream(fTargetLocationFile)); out.setLevel(Deflater.BEST_COMPRESSION); writeEntry(out, TeamPDOMImportOperation.INDEX_NAME, tmpPDOM); writeEntry(out, TeamPDOMImportOperation.CHECKSUMS_NAME, tmpChecksums); } catch (IOException e) { throw new CoreException(CCorePlugin.createStatus(Messages.TeamPDOMExportOperation_errorCreateArchive, e)); } finally { close(out); } IFile[] wsResource= ResourceLookup.findFilesForLocation(new Path(fTargetLocationFile.getAbsolutePath())); for (IFile file : wsResource) { file.refreshLocal(0, new NullProgressMonitor()); } } private void writeEntry(ZipOutputStream out, String name, File input) throws IOException { ZipEntry e= new ZipEntry(name); out.putNextEntry(e); int read= 0; byte[] buffer= new byte[4096]; InputStream in= new FileInputStream(input); try { while ((read= in.read(buffer)) >= 0) { out.write(buffer, 0, read); } out.closeEntry(); } finally { close(in); } } private SubProgressMonitor subMonitor(IProgressMonitor monitor, int ticks) { return new SubProgressMonitor(monitor, ticks); } private void checkMonitor(IProgressMonitor monitor) { if (monitor.isCanceled()) { throw new OperationCanceledException(); } } }