/******************************************************************************* * Copyright (c) 2014 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.orion.server.cf.utils; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.HashMap; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileInfo; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.URIUtil; import org.eclipse.jgit.ignore.IgnoreNode; import org.eclipse.orion.server.core.IOUtilities; /** * Utility class responsible for compressing application * contents according to the .cfignore rules. */ public class Packager { protected static String CF_IGNORE_FILE = ".cfignore"; //$NON-NLS-1$ /** * Reusing jgit ignore utilities. * TODO: Consider a trie structure instead * of the hash map in order to reduce memory usage. */ protected HashMap<URI, IgnoreNode> cfIgnore; protected IFileStore base; public Packager(IFileStore base) { cfIgnore = new HashMap<URI, IgnoreNode>(); this.base = base; } protected boolean isIgnored(IFileStore source, IPath path, boolean isDirectory) throws CoreException { return isIgnored(source, path, isDirectory, false); } protected boolean isIgnored(IFileStore source, IPath path, boolean isDirectory, boolean negatePrevious) throws CoreException { /* look for inherited rules up to the base node */ if (!base.isParentOf(source) && !base.equals(source)) return false; IgnoreNode node = cfIgnore.get(source.toURI()); if (node != null) { IFileStore pathStore = base.getFileStore(path); URI relativeURI = URIUtil.makeRelative(pathStore.toURI(), source.toURI()); switch (node.isIgnored(relativeURI.toString(), isDirectory, negatePrevious)) { case IGNORED : return true; case NOT_IGNORED : return false; case CHECK_PARENT: negatePrevious = false; break; case CHECK_PARENT_NEGATE_FIRST_MATCH: negatePrevious = true; break; } } return isIgnored(source.getParent(), path, isDirectory, negatePrevious); } protected void writeZip(IFileStore source, IPath path, ZipOutputStream zos) throws CoreException, IOException { /* load .cfignore if present */ IFileStore cfIgnoreFile = source.getChild(CF_IGNORE_FILE); if (cfIgnoreFile.fetchInfo().exists()) { IgnoreNode node = new IgnoreNode(); InputStream is = null; try { is = cfIgnoreFile.openInputStream(EFS.NONE, null); node.parse(is); cfIgnore.put(source.toURI(), node); } finally { if (is != null) is.close(); } } IFileInfo info = source.fetchInfo(EFS.NONE, null); if (info.isDirectory()) { if (!isIgnored(source, path, true)) for (IFileStore child : source.childStores(EFS.NONE, null)) writeZip(child, path.append(child.getName()), zos); } else { if (!isIgnored(source, path, false)) { ZipEntry entry = new ZipEntry(path.toString()); zos.putNextEntry(entry); IOUtilities.pipe(source.openInputStream(EFS.NONE, null), zos, true, false); } } } /** * Compresses the given source to .zip format according to .cfignore rules. * @param source Source store which has to be compressed. * @param zos Zip output stream used as the compress destination. * @throws IOException * @throws CoreException */ public void writeZip(IFileStore source, ZipOutputStream zos) throws CoreException, IOException { writeZip(source, Path.EMPTY, zos); } }