Changes:
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / obfuscator / export / ObfuscatorExportOperation.java
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/obfuscator/export/ObfuscatorExportOperation.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/obfuscator/export/ObfuscatorExportOperation.java
new file mode 100644 (file)
index 0000000..f8e50dc
--- /dev/null
@@ -0,0 +1,640 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpeclipse.obfuscator.export;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpeclipse.obfuscator.ObfuscatorIgnores;
+import net.sourceforge.phpeclipse.obfuscator.ObfuscatorPass1Exporter;
+import net.sourceforge.phpeclipse.obfuscator.ObfuscatorPass2Exporter;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+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.MultiStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.operation.ModalContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.IOverwriteQuery;
+
+/**
+ *     Operation for exporting the contents of a resource to the local file system.
+ */
+/*package*/
+class ObfuscatorExportOperation implements IRunnableWithProgress {
+  private IPath fPath;
+  private IProgressMonitor fMonitor;
+  private ObfuscatorPass1Exporter fExporter1 = null;
+  private ObfuscatorPass2Exporter fExporter2 = null;
+  private HashMap fCurrentIdentifierMap = null;
+  private HashMap fProjectMap = null;
+  private String fCurrentProjectName = "";
+
+  private List fResourcesToExport;
+  private IOverwriteQuery fOverwriteCallback;
+  private IResource fResource;
+  private List errorTable = new ArrayList(1);
+
+  //The constants for the overwrite 3 state
+  private static final int OVERWRITE_NOT_SET = 0;
+  private static final int OVERWRITE_NONE = 1;
+  private static final int OVERWRITE_ALL = 2;
+  private int overwriteState = OVERWRITE_NOT_SET;
+
+  //  private boolean createLeadupStructure = true;
+  private boolean createContainerDirectories = true;
+  /**
+   *  Create an instance of this class.  Use this constructor if you wish to
+   *  export specific resources without a common parent resource
+   */
+  //  public ObfuscatorExportOperation(List resources, String destinationPath, IOverwriteQuery overwriteImplementor) {
+  //    super();
+  //
+  //    exporter1 = new ObfuscatorPass1Exporter(new Scanner(false, false), identifierMap);
+  //           exporter2 = new ObfuscatorPass2Exporter(new Scanner(true, true), identifierMap);
+  //           identifierMap = null;
+  //           
+  //    // Eliminate redundancies in list of resources being exported
+  //    Iterator elementsEnum = resources.iterator();
+  //    while (elementsEnum.hasNext()) {
+  //      IResource currentResource = (IResource) elementsEnum.next();
+  //      if (isDescendent(resources, currentResource))
+  //        elementsEnum.remove(); //Remove currentResource
+  //    }
+  //
+  //    resourcesToExport = resources;
+  //    path = new Path(destinationPath);
+  //    overwriteCallback = overwriteImplementor;
+  //  }
+  /**
+   *  Create an instance of this class.  Use this constructor if you wish to
+   *  recursively export a single resource
+   */
+  public ObfuscatorExportOperation(IResource res, String destinationPath, IOverwriteQuery overwriteImplementor) {
+    super();
+
+    fResource = res;
+    fPath = new Path(destinationPath);
+    fOverwriteCallback = overwriteImplementor;
+  }
+  /**
+   *  Create an instance of this class.  Use this constructor if you wish to
+   *  export specific resources with a common parent resource (affects container
+   *  directory creation)
+   */
+  public ObfuscatorExportOperation(IResource res, List resources, String destinationPath, IOverwriteQuery overwriteImplementor) {
+    this(res, destinationPath, overwriteImplementor);
+    fResourcesToExport = resources;
+  }
+  /**
+   * Add a new entry to the error table with the passed information
+   */
+  protected void addError(String message, Throwable e) {
+    errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, message, e));
+  }
+  /**
+   *  Answer the total number of file resources that exist at or below self in the
+   *  resources hierarchy.
+   *
+   *  @return int
+   *  @param resource org.eclipse.core.resources.IResource
+   */
+  protected int countChildrenOf(IResource resource) throws CoreException {
+    if (resource.getType() == IResource.FILE)
+      return 1;
+
+    int count = 0;
+    if (resource.isAccessible()) {
+      IResource[] children = ((IContainer) resource).members();
+      for (int i = 0; i < children.length; i++)
+        count += countChildrenOf(children[i]);
+    }
+
+    return count;
+  }
+  /**
+   *   Answer a boolean indicating the number of file resources that were
+   *   specified for export
+   *
+   *   @return int
+   */
+  protected int countSelectedResources() throws CoreException {
+    int result = 0;
+    Iterator resources = fResourcesToExport.iterator();
+
+    while (resources.hasNext())
+      result += countChildrenOf((IResource) resources.next());
+
+    return result;
+  }
+  /**
+   *  Create the directories required for exporting the passed resource,
+   *  based upon its container hierarchy
+   *
+   *  @param resource org.eclipse.core.resources.IResource
+   */
+  protected void createLeadupDirectoriesFor(IResource resource) {
+    IPath resourcePath = resource.getFullPath().removeLastSegments(1);
+
+    for (int i = 0; i < resourcePath.segmentCount(); i++) {
+      fPath = fPath.append(resourcePath.segment(i));
+      fExporter2.createFolder(fPath);
+    }
+  }
+  /**
+   *   Recursively export the previously-specified resource
+   */
+  protected void exportAllResources1() throws InterruptedException {
+    if (fResource.getType() == IResource.FILE) {
+      exportFile1((IFile) fResource, fPath);
+    } else {
+      try {
+        setExporters(fResource);
+        exportChildren1(((IContainer) fResource).members(), fPath);
+      } catch (CoreException e) {
+        // not safe to show a dialog
+        // should never happen because the file system export wizard ensures that the
+        // single resource chosen for export is both existent and accessible
+        errorTable.add(e);
+      }
+    }
+  }
+  /**
+   *   Recursively export the previously-specified resource
+   */
+  protected void exportAllResources2() throws InterruptedException {
+    if (fResource.getType() == IResource.FILE) {
+      exportFile2((IFile) fResource, fPath);
+    } else {
+      try {
+        setExporters(fResource);
+        exportChildren2(((IContainer) fResource).members(), fPath);
+      } catch (CoreException e) {
+        // not safe to show a dialog
+        // should never happen because the file system export wizard ensures that the
+        // single resource chosen for export is both existent and accessible
+        errorTable.add(e);
+      }
+    }
+  }
+  /**
+   *   Export all of the resources contained in the passed collection
+   *
+   *   @param children java.util.Enumeration
+   *   @param currentPath IPath
+   */
+  protected void exportChildren1(IResource[] children, IPath currentPath) throws InterruptedException {
+    for (int i = 0; i < children.length; i++) {
+      IResource child = children[i];
+      if (!child.isAccessible())
+        continue;
+
+      if (child.getType() == IResource.FILE)
+        exportFile1((IFile) child, currentPath);
+      else {
+        IPath destination = currentPath.append(child.getName());
+        fExporter1.createFolder(destination);
+        try {
+          exportChildren1(((IContainer) child).members(), destination);
+        } catch (CoreException e) {
+          // not safe to show a dialog
+          // should never happen because:
+          // i. this method is called recursively iterating over the result of #members,
+          //           which only answers existing children
+          // ii. there is an #isAccessible check done before #members is invoked
+          errorTable.add(e.getStatus());
+        }
+      }
+    }
+  }
+
+  /**
+   *   Export all of the resources contained in the passed collection
+   *
+   *   @param children java.util.Enumeration
+   *   @param currentPath IPath
+   */
+  protected void exportChildren2(IResource[] children, IPath currentPath) throws InterruptedException {
+    for (int i = 0; i < children.length; i++) {
+      IResource child = children[i];
+      if (!child.isAccessible())
+        continue;
+
+      if (child.getType() == IResource.FILE)
+        exportFile2((IFile) child, currentPath);
+      else {
+        IPath destination = currentPath.append(child.getName());
+        fExporter2.createFolder(destination);
+        try {
+          exportChildren2(((IContainer) child).members(), destination);
+        } catch (CoreException e) {
+          // not safe to show a dialog
+          // should never happen because:
+          // i. this method is called recursively iterating over the result of #members,
+          //           which only answers existing children
+          // ii. there is an #isAccessible check done before #members is invoked
+          errorTable.add(e.getStatus());
+        }
+      }
+    }
+  }
+
+  protected void exportFile1(IFile file, IPath location) throws InterruptedException {
+    IPath fullPath = location.append(file.getName());
+    fMonitor.subTask(file.getFullPath().toString());
+    String properPathString = fullPath.toOSString();
+    File targetFile = new File(properPathString);
+
+    //    if (targetFile.exists()) {
+    //      if (!targetFile.canWrite()) {
+    //        errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.cannotOverwrite", //$NON-NLS-1$
+    //        new Object[] { targetFile.getAbsolutePath()}), null));
+    //        monitor.worked(1);
+    //        return;
+    //      }
+    //
+    //      if (overwriteState == OVERWRITE_NONE)
+    //        return;
+    //
+    //      if (overwriteState != OVERWRITE_ALL) {
+    //        String overwriteAnswer = overwriteCallback.queryOverwrite(properPathString);
+    //
+    //        if (overwriteAnswer.equals(IOverwriteQuery.CANCEL))
+    //          throw new InterruptedException();
+    //
+    //        if (overwriteAnswer.equals(IOverwriteQuery.NO)) {
+    //          monitor.worked(1);
+    //          return;
+    //        }
+    //
+    //        if (overwriteAnswer.equals(IOverwriteQuery.NO_ALL)) {
+    //          monitor.worked(1);
+    //          overwriteState = OVERWRITE_NONE;
+    //          return;
+    //        }
+    //
+    //        if (overwriteAnswer.equals(IOverwriteQuery.ALL))
+    //          overwriteState = OVERWRITE_ALL;
+    //      }
+    //    }
+
+    try {
+      setExporters(file);
+      fExporter1.write(file, fullPath);
+    } catch (IOException e) {
+      errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
+      new Object[] { fullPath, e.getMessage()}), e));
+    } catch (CoreException e) {
+      errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
+      new Object[] { fullPath, e.getMessage()}), e));
+    }
+
+    fMonitor.worked(1);
+    ModalContext.checkCanceled(fMonitor);
+  }
+  /**
+   *  Export the passed file to the specified location
+   *
+   *  @param file org.eclipse.core.resources.IFile
+   *  @param location org.eclipse.core.runtime.IPath
+   */
+  protected void exportFile2(IFile file, IPath location) throws InterruptedException {
+    IPath fullPath = location.append(file.getName());
+    fMonitor.subTask(file.getFullPath().toString());
+    String properPathString = fullPath.toOSString();
+    File targetFile = new File(properPathString);
+
+    if (targetFile.exists()) {
+      if (!targetFile.canWrite()) {
+        errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.cannotOverwrite", //$NON-NLS-1$
+        new Object[] { targetFile.getAbsolutePath()}), null));
+        fMonitor.worked(1);
+        return;
+      }
+
+      if (overwriteState == OVERWRITE_NONE)
+        return;
+
+      if (overwriteState != OVERWRITE_ALL) {
+        String overwriteAnswer = fOverwriteCallback.queryOverwrite(properPathString);
+
+        if (overwriteAnswer.equals(IOverwriteQuery.CANCEL))
+          throw new InterruptedException();
+
+        if (overwriteAnswer.equals(IOverwriteQuery.NO)) {
+          fMonitor.worked(1);
+          return;
+        }
+
+        if (overwriteAnswer.equals(IOverwriteQuery.NO_ALL)) {
+          fMonitor.worked(1);
+          overwriteState = OVERWRITE_NONE;
+          return;
+        }
+
+        if (overwriteAnswer.equals(IOverwriteQuery.ALL))
+          overwriteState = OVERWRITE_ALL;
+      }
+    }
+
+    try {
+      setExporters(file);
+      fExporter2.write(file, fullPath);
+    } catch (IOException e) {
+      errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
+      new Object[] { fullPath, e.getMessage()}), e));
+    } catch (CoreException e) {
+      errorTable.add(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, ObfuscatorExportMessages.format("ObfuscatorTransfer.errorExporting", //$NON-NLS-1$
+      new Object[] { fullPath, e.getMessage()}), e));
+    }
+
+    fMonitor.worked(1);
+    ModalContext.checkCanceled(fMonitor);
+  }
+
+  protected void exportSpecifiedResources1() throws InterruptedException {
+    Iterator resources = fResourcesToExport.iterator();
+    IPath initPath = (IPath) fPath.clone();
+
+    while (resources.hasNext()) {
+      IResource currentResource = (IResource) resources.next();
+      if (!currentResource.isAccessible())
+        continue;
+      setExporters(currentResource);
+      fPath = initPath;
+
+      if (fResource == null) {
+        // No root resource specified and creation of containment directories
+        // is required.  Create containers from depth 2 onwards (ie.- project's
+        // child inclusive) for each resource being exported.
+        //        if (createLeadupStructure)
+        //          createLeadupDirectoriesFor(currentResource);
+
+      } else {
+        // Root resource specified.  Must create containment directories
+        // from this point onwards for each resource being exported
+        IPath containersToCreate =
+          currentResource.getFullPath().removeFirstSegments(fResource.getFullPath().segmentCount()).removeLastSegments(1);
+
+        for (int i = 0; i < containersToCreate.segmentCount(); i++) {
+          fPath = fPath.append(containersToCreate.segment(i));
+          fExporter1.createFolder(fPath);
+        }
+      }
+
+      if (currentResource.getType() == IResource.FILE)
+        exportFile1((IFile) currentResource, fPath);
+      else {
+        if (createContainerDirectories) {
+          fPath = fPath.append(currentResource.getName());
+          fExporter1.createFolder(fPath);
+        }
+
+        try {
+          exportChildren1(((IContainer) currentResource).members(), fPath);
+        } catch (CoreException e) {
+          // should never happen because #isAccessible is called before #members is invoked,
+          // which implicitly does an existence check
+          errorTable.add(e.getStatus());
+        }
+      }
+    }
+  }
+  /**
+   *   Export the resources contained in the previously-defined
+   *   resourcesToExport collection
+   */
+  protected void exportSpecifiedResources2() throws InterruptedException {
+    Iterator resources = fResourcesToExport.iterator();
+    IPath initPath = (IPath) fPath.clone();
+
+    while (resources.hasNext()) {
+      IResource currentResource = (IResource) resources.next();
+      if (!currentResource.isAccessible())
+        continue;
+      setExporters(currentResource);
+
+      fPath = initPath;
+
+      if (fResource == null) {
+        // No root resource specified and creation of containment directories
+        // is required.  Create containers from depth 2 onwards (ie.- project's
+        // child inclusive) for each resource being exported.
+        //        if (createLeadupStructure)
+        //          createLeadupDirectoriesFor(currentResource);
+
+      } else {
+        // Root resource specified.  Must create containment directories
+        // from this point onwards for each resource being exported
+        IPath containersToCreate =
+          currentResource.getFullPath().removeFirstSegments(fResource.getFullPath().segmentCount()).removeLastSegments(1);
+
+        for (int i = 0; i < containersToCreate.segmentCount(); i++) {
+          fPath = fPath.append(containersToCreate.segment(i));
+          fExporter2.createFolder(fPath);
+        }
+      }
+
+      if (currentResource.getType() == IResource.FILE)
+        exportFile2((IFile) currentResource, fPath);
+      else {
+        if (createContainerDirectories) {
+          fPath = fPath.append(currentResource.getName());
+          fExporter2.createFolder(fPath);
+        }
+
+        try {
+          exportChildren2(((IContainer) currentResource).members(), fPath);
+        } catch (CoreException e) {
+          // should never happen because #isAccessible is called before #members is invoked,
+          // which implicitly does an existence check
+          errorTable.add(e.getStatus());
+        }
+      }
+    }
+  }
+  /**
+   * Returns the status of the export operation.
+   * If there were any errors, the result is a status object containing
+   * individual status objects for each error.
+   * If there were no errors, the result is a status object with error code <code>OK</code>.
+   *
+   * @return the status
+   */
+  public IStatus getStatus() {
+    IStatus[] errors = new IStatus[errorTable.size()];
+    errorTable.toArray(errors);
+    return new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, errors, ObfuscatorExportMessages.getString("ObfuscatorExportOperation.problemsExporting"), //$NON-NLS-1$
+    null);
+  }
+  /**
+   *  Answer a boolean indicating whether the passed child is a descendent
+   *  of one or more members of the passed resources collection
+   *
+   *  @return boolean
+   *  @param resources java.util.List
+   *  @param child org.eclipse.core.resources.IResource
+   */
+  protected boolean isDescendent(List resources, IResource child) {
+    if (child.getType() == IResource.PROJECT)
+      return false;
+
+    IResource parent = child.getParent();
+    if (resources.contains(parent))
+      return true;
+
+    return isDescendent(resources, parent);
+  }
+
+  private void setExporters(IResource resource) {
+    if (fCurrentIdentifierMap == null) {
+      if (fProjectMap == null) {
+        fProjectMap = new HashMap();
+      }
+      createExporters(resource);
+    } else {
+      IProject project = resource.getProject();
+      if (!fCurrentProjectName.equals(project.getName())) {
+        HashMap temp = (HashMap) fProjectMap.get(project.getName());
+        if (temp != null) {
+          fCurrentProjectName = project.getName();
+          fCurrentIdentifierMap = temp;
+          fExporter1 = new ObfuscatorPass1Exporter(new Scanner(false, false), fCurrentIdentifierMap);
+          fExporter2 = new ObfuscatorPass2Exporter(new Scanner(true, true), fCurrentIdentifierMap);
+          return;
+        }
+        createExporters(resource);
+      }
+    }
+  }
+
+  private void createExporters(IResource resource) {
+    IProject project = resource.getProject();
+    IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
+    ObfuscatorIgnores ignore = new ObfuscatorIgnores(project);
+    fCurrentIdentifierMap = ignore.getIdentifierMap();
+    fCurrentProjectName = project.getName();
+    fProjectMap.put(fCurrentProjectName, fCurrentIdentifierMap);
+    fExporter1 = new ObfuscatorPass1Exporter(new Scanner(false, false), fCurrentIdentifierMap);
+    fExporter2 = new ObfuscatorPass2Exporter(new Scanner(true, true), fCurrentIdentifierMap);
+  }
+  /**
+   *   Export the resources that were previously specified for export
+   *   (or if a single resource was specified then export it recursively)
+   */
+  public void run(IProgressMonitor monitor) throws InterruptedException {
+    this.fMonitor = monitor;
+    final IPath tempPath = (IPath) fPath.clone();
+    if (fResource != null) {
+      setExporters(fResource);
+      //      if (createLeadupStructure)
+      //        createLeadupDirectoriesFor(resource);
+
+      if (createContainerDirectories && fResource.getType() != IResource.FILE) {
+        // ensure it's a container
+        fPath = fPath.append(fResource.getName());
+        fExporter2.createFolder(fPath);
+      }
+    }
+
+    try {
+       // reset variables for this run:
+       fCurrentIdentifierMap = null;
+       fProjectMap = null;
+       fCurrentProjectName = "";
+       
+       // count number of files
+      int totalWork = IProgressMonitor.UNKNOWN;
+      try {
+        if (fResourcesToExport == null) {
+          totalWork = countChildrenOf(fResource);
+        } else {
+          totalWork = countSelectedResources();
+        }
+      } catch (CoreException e) {
+        // Should not happen
+        errorTable.add(e.getStatus());
+      }
+      monitor.beginTask(ObfuscatorExportMessages.getString("ObfuscatorTransfer.exportingTitle1"), totalWork); //$NON-NLS-1$
+      if (fResourcesToExport == null) {
+        exportAllResources1();
+      } else {
+        exportSpecifiedResources1();
+      }
+
+      //      try {
+      //        if (resourcesToExport == null)
+      //          totalWork = countChildrenOf(resource);
+      //        else
+      //          totalWork = countSelectedResources();
+      //      } catch (CoreException e) {
+      //        // Should not happen
+      //        errorTable.add(e.getStatus());
+      //      }
+
+      // reset path:
+      fPath = tempPath;
+      monitor.beginTask(ObfuscatorExportMessages.getString("ObfuscatorTransfer.exportingTitle2"), totalWork); //$NON-NLS-1$
+      if (fResourcesToExport == null) {
+        exportAllResources2();
+      } else {
+        exportSpecifiedResources2();
+      }
+    } finally {
+      monitor.done();
+    }
+  }
+  /**
+   *   Set this boolean indicating whether a directory should be created for
+   *   Folder resources that are explicitly passed for export
+   *
+   *   @param value boolean
+   */
+  //  public void setCreateContainerDirectories(boolean value) {
+  //    createContainerDirectories = value;
+  //  }
+  /**
+   *   Set this boolean indicating whether each exported resource's complete path should
+   *   include containment hierarchies as dictated by its parents
+   *
+   *   @param value boolean
+   */
+  //  public void setCreateLeadupStructure(boolean value) {
+  //    createLeadupStructure = value;
+  //  }
+  /**
+   *   Set this boolean indicating whether exported resources should automatically
+   *   overwrite existing files when a conflict occurs. If not
+   *   query the user.
+   *
+   *   @param value boolean
+   */
+  public void setOverwriteFiles(boolean value) {
+    if (value)
+      overwriteState = OVERWRITE_ALL;
+  }
+}