Пример #1
0
  private void buildFile(
      BuildContext context, List<IBuildParticipant> participants, IProgressMonitor monitor)
      throws CoreException {
    if (CollectionsUtil.isEmpty(participants)) {
      return;
    }

    SubMonitor sub = SubMonitor.convert(monitor, 2 * participants.size());
    for (IBuildParticipant participant : participants) {
      long startTime = System.nanoTime();
      participant.buildFile(context, sub.newChild(1));
      if (traceParticipantsEnabled) {
        double endTime = ((double) System.nanoTime() - startTime) / 1000000;
        IdeLog.logTrace(
            BuildPathCorePlugin.getDefault(),
            MessageFormat.format(
                "Executed build participant ''{0}'' on ''{1}'' in {2} ms.",
                participant.getName(), context.getURI(), endTime),
            IDebugScopes.BUILDER_PARTICIPANTS); // $NON-NLS-1$
      }

      // stop building if it has been canceled
      if (sub.isCanceled()) {
        break;
      }
    }
    updateMarkers(context, sub.newChild(participants.size()));
    sub.done();
  }
Пример #2
0
  private void doBuildFiles(
      List<IBuildParticipant> participants, Collection<IFile> files, IProgressMonitor monitor)
      throws CoreException {
    if (CollectionsUtil.isEmpty(files)) {
      return;
    }

    SubMonitor sub = SubMonitor.convert(monitor, 15 * files.size());
    for (IFile file : files) {
      BuildContext context = new BuildContext(file);
      sub.worked(1);

      IBuildParticipantManager manager = getBuildParticipantManager();
      if (manager == null) {
        return;
      }
      List<IBuildParticipant> filteredParticipants =
          manager.filterParticipants(participants, context.getContentType());
      sub.worked(2);

      buildFile(context, filteredParticipants, sub.newChild(12));

      // stop building if canceled
      if (sub.isCanceled()) {
        break;
      }
    }
    sub.done();
  }
Пример #3
0
  private void buildFiles(
      List<IBuildParticipant> participants, Collection<IFile> files, IProgressMonitor monitor)
      throws CoreException {
    if (CollectionsUtil.isEmpty(participants) || CollectionsUtil.isEmpty(files)) {
      return;
    }
    SubMonitor sub = SubMonitor.convert(monitor, 100);

    // Filter
    files = filterFiles(files, sub.newChild(10));

    // Then build
    doBuildFiles(participants, files, sub.newChild(90));

    sub.done();
  }
Пример #4
0
  public IStatus unstageFiles(Collection<ChangedFile> unstageFiles) {
    if (CollectionsUtil.isEmpty(unstageFiles)) {
      // no-op, return OK
      return Status.OK_STATUS;
    }

    StringBuilder input = new StringBuilder();
    for (ChangedFile file : unstageFiles) {
      input.append(file.indexInfo());
    }

    IStatus result =
        repository.executeWithInput(
            input.toString(),
            "update-index",
            "-z",
            "--index-info"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    if (result == null) {
      return new Status(
          IStatus.ERROR,
          GitPlugin.PLUGIN_ID,
          "Failed to unstage files. Process failed to run."); //$NON-NLS-1$
    }
    if (!result.isOK()) {
      IdeLog.logError(
          GitPlugin.getDefault(),
          MessageFormat.format("Failed to stage files: {0}", result.getMessage()),
          IDebugScopes.DEBUG); // $NON-NLS-1$
      return result;
    }

    // Update the staged/unstaged flags in the passed in copy of changed files, and our internal
    // list of changed
    // files.
    ArrayList<ChangedFile> preFiles = new ArrayList<ChangedFile>(unstageFiles.size());
    for (ChangedFile file : unstageFiles) {
      preFiles.add(new ChangedFile(file));

      synchronized (this.changedFilesLock) {
        if (this.changedFiles != null) {
          int index = Collections.binarySearch(this.changedFiles, file);
          if (index >= 0) {

            ChangedFile orig = this.changedFiles.get(index);
            orig.hasUnstagedChanges = true;
            orig.hasStagedChanges = false;
          }
        }
      }

      file.hasUnstagedChanges = true;
      file.hasStagedChanges = false;
    }
    preFiles.trimToSize();

    postIndexChange(preFiles, unstageFiles);
    return result;
  }
Пример #5
0
  public IStatus stageFiles(Collection<ChangedFile> stageFiles) {
    if (CollectionsUtil.isEmpty(stageFiles)) {
      // no-op
      return Status.OK_STATUS;
    }

    StringBuffer input =
        new StringBuffer(stageFiles.size() * stageFiles.iterator().next().getPath().length());
    for (ChangedFile file : stageFiles) {
      input.append(file.getPath()).append('\n');
    }

    @SuppressWarnings("nls")
    IStatus result =
        repository.executeWithInput(
            input.toString(), "update-index", "--add", "--remove", "--stdin");
    if (result == null) {
      return new Status(
          IStatus.ERROR,
          GitPlugin.PLUGIN_ID,
          "Failed to stage files. Process failed to run."); //$NON-NLS-1$;
    }
    if (!result.isOK()) {
      IdeLog.logError(
          GitPlugin.getDefault(),
          MessageFormat.format("Failed to stage files: {0}", result.getMessage()),
          IDebugScopes.DEBUG); // $NON-NLS-1$
      return result;
    }

    ArrayList<ChangedFile> preFiles = new ArrayList<ChangedFile>(stageFiles.size());
    // Update the staged/unstaged flags in the passed in copy of changed files, and our internal
    // list of changed
    // files.
    for (ChangedFile file : stageFiles) {
      preFiles.add(new ChangedFile(file));
      synchronized (changedFilesLock) {
        if (this.changedFiles != null) {
          int index = Collections.binarySearch(this.changedFiles, file);
          if (index >= 0) {

            ChangedFile orig = this.changedFiles.get(index);
            orig.hasUnstagedChanges = false;
            orig.hasStagedChanges = true;
          }
        }
      }

      file.hasUnstagedChanges = false;
      file.hasStagedChanges = true;
    }
    preFiles.trimToSize();

    postIndexChange(preFiles, stageFiles);
    return result;
  }
 /** Mark the downloaded paths to be deleted on exit. */
 protected void deleteDownloadedPaths() {
   if (!CollectionsUtil.isEmpty(downloadedPaths)) {
     for (IPath f : downloadedPaths) {
       File toDelete = f.toFile();
       if (toDelete.exists()) {
         toDelete.deleteOnExit();
       }
     }
   }
 }
Пример #7
0
  /**
   * FIXME This is a holy hell of a mess! We map from IFiles to IFileStores, then filter on that,
   * then map back! Can't we make the IIndexFilterParticipants also operate on IFiles? It seems like
   * the only impl does anyways.
   *
   * @return
   */
  private Collection<IFile> filterFiles(Collection<IFile> files, IProgressMonitor monitor) {
    SubMonitor sub = SubMonitor.convert(monitor, 100);
    // First filter out files that don't exist, are derived, or are team-private
    files =
        CollectionsUtil.filter(
            files,
            new IFilter<IFile>() {
              public boolean include(IFile item) {
                return !ResourceUtil.shouldIgnore(item);
              }
            });
    sub.worked(10);

    // Next map IFiles to IFileStores for filter participants' sake
    Set<IFileStore> fileStores =
        new HashSet<IFileStore>(
            CollectionsUtil.map(
                files,
                new IMap<IFile, IFileStore>() {

                  public IFileStore map(IFile item) {
                    IPath path = item.getLocation();
                    return (path == null) ? null : EFS.getLocalFileSystem().getStore(path);
                  }
                }));
    sub.worked(15);

    if (!CollectionsUtil.isEmpty(fileStores)) {
      // Now let filters run
      IndexManager manager = getIndexManager();
      if (manager != null) {
        for (IIndexFilterParticipant filterParticipant : manager.getFilterParticipants()) {
          fileStores = filterParticipant.applyFilter(fileStores);
        }
      }
      sub.worked(60);

      // Now we need to map back to IFiles again. UGH!
      return CollectionsUtil.map(
          fileStores,
          new IMap<IFileStore, IFile>() {

            public IFile map(IFileStore fileStore) {
              IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
              IFile[] iFiles = workspaceRoot.findFilesForLocationURI(fileStore.toURI());
              if (ArrayUtil.isEmpty(iFiles)) {
                return null;
              }
              return iFiles[0];
            }
          });
    }

    return files;
  }
Пример #8
0
 private void buildStarting(
     List<IBuildParticipant> participants, int kind, IProgressMonitor monitor) {
   if (CollectionsUtil.isEmpty(participants)) {
     return;
   }
   SubMonitor sub = SubMonitor.convert(monitor, participants.size());
   for (IBuildParticipant participant : participants) {
     participant.buildStarting(getProjectHandle(), kind, sub.newChild(1));
   }
   sub.done();
 }
Пример #9
0
  private void deleteFile(
      BuildContext context, List<IBuildParticipant> participants, IProgressMonitor monitor) {
    if (CollectionsUtil.isEmpty(participants)) {
      return;
    }

    SubMonitor sub = SubMonitor.convert(monitor, participants.size());
    for (IBuildParticipant participant : participants) {
      participant.deleteFile(context, sub.newChild(1));
    }
    sub.done();
  }
Пример #10
0
 protected boolean hasUnresolvedMergeConflicts() {
   List<ChangedFile> changedFiles = changedFiles();
   if (CollectionsUtil.isEmpty(changedFiles)) {
     return false;
   }
   for (ChangedFile changedFile : changedFiles) {
     if (changedFile.hasUnmergedChanges() && changedFile.hasUnstagedChanges()) {
       return true;
     }
   }
   return false;
 }
Пример #11
0
 public Set<IResource> getChangedResources() {
   Set<IResource> resources = new HashSet<IResource>();
   List<ChangedFile> changedFiles = changedFiles();
   if (!CollectionsUtil.isEmpty(changedFiles)) {
     for (ChangedFile changedFile : changedFiles) {
       IResource resource = getResourceForChangedFile(changedFile);
       if (resource != null) {
         resources.add(resource);
       }
     }
   }
   return resources;
 }
Пример #12
0
 private void addMarkers(
     Collection<IProblem> items, String markerType, IFile file, IProgressMonitor monitor)
     throws CoreException {
   if (CollectionsUtil.isEmpty(items)) {
     return;
   }
   SubMonitor sub = SubMonitor.convert(monitor, items.size() * 2);
   for (IProblem item : items) {
     IMarker marker = file.createMarker(markerType);
     sub.worked(1);
     marker.setAttributes(item.createMarkerAttributes());
     sub.worked(1);
   }
   sub.done();
 }
Пример #13
0
    public IStatus call() throws Exception {
      // index vs filesystem
      List<String> args = CollectionsUtil.newList("diff-files", "-z"); // $NON-NLS-1$ //$NON-NLS-2$
      if (!CollectionsUtil.isEmpty(filePaths)) {
        args.add("--"); // $NON-NLS-1$
        args.addAll(filePaths);
      }

      IStatus result =
          repo.execute(GitRepository.ReadWrite.READ, args.toArray(new String[args.size()]));
      if (result != null && result.isOK()) {
        readUnstagedFiles(result.getMessage());
      }
      return Status.OK_STATUS;
    }
Пример #14
0
  protected ChangedFile getChangedFileForResource(IResource resource) {
    if (resource == null || resource.getLocationURI() == null) {
      return null;
    }

    IPath resourcePath = resource.getLocation();
    List<ChangedFile> changedFiles = changedFiles();
    if (!CollectionsUtil.isEmpty(changedFiles)) {
      for (ChangedFile changedFile : changedFiles) {
        IPath fullPath = workingDirectory().append(changedFile.getPath());
        if (resourcePath.equals(fullPath)) {
          return changedFile;
        }
      }
    }
    return null;
  }
Пример #15
0
  /**
   * For use in telling if a given resource is a changed file, or is a folder containing changes
   * underneath it.
   *
   * @param resource
   * @return
   */
  protected boolean resourceOrChildHasChanges(IResource resource) {
    List<ChangedFile> changedFiles = changedFiles();
    if (CollectionsUtil.isEmpty(changedFiles)) {
      return false;
    }

    IPath workingDirectory = repository.workingDirectory();
    IPath resourcePath = resource.getLocation();
    for (ChangedFile changedFile : changedFiles) {
      IPath fullPath = workingDirectory.append(changedFile.getPath()).makeAbsolute();
      if (resourcePath.isPrefixOf(fullPath)) {
        return true;
      }
    }

    return false;
  }
  /**
   * toSource
   *
   * @param printer
   */
  public void toSource(SourcePrinter printer) {
    printer.printIndent();

    // print any annotations
    if (!this.isInstanceProperty()) {
      printer.print("static "); // $NON-NLS-1$
    }
    if (this.isInternal()) {
      printer.print("internal "); // $NON-NLS-1$
    }
    if (this.isConstructor()) {
      printer.print("constructor "); // $NON-NLS-1$
    }
    if (this.isMethod()) {
      printer.print("method "); // $NON-NLS-1$
    }

    // print name
    printer.print(this.getName());

    // print parameter types
    printer
        .print('(')
        .print(StringUtil.join(JSTypeConstants.PARAMETER_DELIMITER, this.getParameterTypes()))
        .print(')');

    // print return types
    List<String> returnTypes = this.getReturnTypeNames();

    printer.print(JSTypeConstants.FUNCTION_SIGNATURE_DELIMITER);

    if (!CollectionsUtil.isEmpty(returnTypes)) {
      printer.print(StringUtil.join(JSTypeConstants.RETURN_TYPE_DELIMITER, returnTypes));
    } else {
      printer.print(JSTypeConstants.UNDEFINED_TYPE);
    }

    // print exceptions
    if (this.hasExceptions()) {
      printer
          .print(" throws ")
          .print(StringUtil.join(", ", this.getExceptionTypes())); // $NON-NLS-1$ //$NON-NLS-2$
    }
  }
Пример #17
0
    public IStatus call() throws Exception {
      // index vs working tree (HEAD?)
      List<String> args =
          CollectionsUtil.newList(
              "ls-files",
              "--others", //$NON-NLS-1$ //$NON-NLS-2$
              "--exclude-standard",
              "-z"); //$NON-NLS-1$ //$NON-NLS-2$
      if (!CollectionsUtil.isEmpty(filePaths)) {
        args.add("--"); // $NON-NLS-1$
        args.addAll(filePaths);
      }

      IStatus result =
          repo.execute(GitRepository.ReadWrite.READ, args.toArray(new String[args.size()]));
      if (result != null && result.isOK()) {
        readOtherFiles(result.getMessage());
      }
      return Status.OK_STATUS;
    }
Пример #18
0
  /**
   * getContributedFiles
   *
   * @param container
   * @return
   */
  protected Set<IFileStore> getContributedFiles(URI container) {
    // FIXME This shoves all contributed files into the same index as the project!
    // We want the notion of a project referring to build path entries that are maintained in their
    // own indices,
    // which we can share across projects!
    Set<IFileStore> result = new HashSet<IFileStore>();

    IndexManager manager = getIndexManager();
    if (manager != null) {
      for (IIndexFileContributor contributor : manager.getFileContributors()) {
        Set<IFileStore> files = contributor.getFiles(container);

        if (!CollectionsUtil.isEmpty(files)) {
          result.addAll(files);
        }
      }
    }

    return result;
  }
Пример #19
0
  /**
   * Gets the list of changed files that are underneath the given container.
   *
   * @param container
   * @return
   */
  protected List<ChangedFile> getChangedFilesForContainer(IContainer container) {
    if (container == null || container.getLocationURI() == null) {
      return Collections.emptyList();
    }

    List<ChangedFile> changedFiles = changedFiles();
    if (CollectionsUtil.isEmpty(changedFiles)) {
      return Collections.emptyList();
    }

    IPath resourcePath = container.getLocation();
    List<ChangedFile> filtered = new ArrayList<ChangedFile>();
    IPath workingDirectory = repository.workingDirectory();
    for (ChangedFile changedFile : changedFiles) {
      IPath fullPath = workingDirectory.append(changedFile.getPath()).makeAbsolute();
      if (resourcePath.isPrefixOf(fullPath)) {
        filtered.add(changedFile);
      }
    }

    return filtered;
  }
Пример #20
0
  private void updateMarkers(BuildContext context, IProgressMonitor monitor) {
    final IFile file = context.getFile();
    final Map<String, Collection<IProblem>> itemsByType = context.getProblems();
    if (CollectionsUtil.isEmpty(itemsByType)) {
      return;
    }
    // Performance fix: schedules the error handling as a single workspace update so that we don't
    // trigger a
    // bunch of resource updated events while problem markers are being added to the file.
    IWorkspaceRunnable runnable =
        new IWorkspaceRunnable() {
          public void run(IProgressMonitor monitor) {
            updateMarkers(file, itemsByType, monitor);
          }
        };

    try {
      ResourcesPlugin.getWorkspace()
          .run(runnable, getMarkerRule(file), IWorkspace.AVOID_UPDATE, monitor);
    } catch (CoreException e) {
      IdeLog.logError(BuildPathCorePlugin.getDefault(), "Error updating markers", e); // $NON-NLS-1$
    }
  }
Пример #21
0
  private void removeFiles(
      List<IBuildParticipant> participants,
      Set<IFile> filesToRemoveFromIndex,
      IProgressMonitor monitor)
      throws CoreException {
    if (CollectionsUtil.isEmpty(filesToRemoveFromIndex)) {
      return;
    }

    SubMonitor sub = SubMonitor.convert(monitor, 16 * filesToRemoveFromIndex.size());
    for (IFile file : filesToRemoveFromIndex) {
      BuildContext context = new BuildContext(file);
      sub.worked(1);
      IBuildParticipantManager manager = getBuildParticipantManager();
      if (manager == null) {
        return;
      }
      List<IBuildParticipant> filteredParticipants =
          manager.filterParticipants(participants, context.getContentType());
      sub.worked(5);
      deleteFile(context, filteredParticipants, sub.newChild(10));
    }
    sub.done();
  }
Пример #22
0
  /**
   * If the filePaths is empty, do batch operations!
   *
   * @param notify
   * @param filePaths
   * @param monitor
   * @return
   */
  IStatus refresh(boolean notify, Collection<IPath> filePaths, IProgressMonitor monitor) {
    SubMonitor sub = SubMonitor.convert(monitor, 100);
    if (sub.isCanceled()) {
      return Status.CANCEL_STATUS;
    }
    this.notify = notify;

    final Set<String> filePathStrings =
        new HashSet<String>(
            CollectionsUtil.map(
                filePaths,
                new IMap<IPath, String>() {
                  public String map(IPath location) {
                    return location.toPortableString();
                  }
                }));

    // If we don't run this, we end up showing files as unstaged when they're no longer modified!
    IStatus result;
    synchronized (this) {
      repository.forceWrite(); // Do we only want to try the lock if we're in UI thread?
      result =
          GitExecutable.instance()
              .runInBackground(
                  repository.workingDirectory(),
                  "update-index",
                  "-q", //$NON-NLS-1$ //$NON-NLS-2$
                  "--unmerged",
                  "--ignore-missing",
                  "--refresh"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      repository.exitWriteProcess();
    }
    if (result == null) // couldn't even execute!
    {
      return new Status(
          IStatus.ERROR,
          GitPlugin.getPluginId(),
          "Failed to execute git update-index"); //$NON-NLS-1$
    }
    if (!result.isOK()) {
      IdeLog.logError(
          GitPlugin.getDefault(),
          "Unable to run update-index: " + result.getMessage()); // $NON-NLS-1$
      return result;
    }

    Set<Callable<IStatus>> jobs = new HashSet<Callable<IStatus>>(3);
    jobs.add(new UntrackedFilesRefreshJob(this, filePathStrings));
    jobs.add(new UnstagedFilesRefreshJob(this, filePathStrings));
    jobs.add(new StagedFilesRefreshJob(this, filePathStrings));

    // Last chance to cancel...
    if (monitor != null && monitor.isCanceled()) {
      return Status.CANCEL_STATUS;
    }

    // Now create a new temporary list so we can build it up...
    this.files = Collections.synchronizedList(new ArrayList<ChangedFile>());

    // Schedule all the jobs
    MultiStatus errors =
        new MultiStatus(
            GitPlugin.PLUGIN_ID,
            1,
            "Errors occurred while grabbing changed file listings",
            null); //$NON-NLS-1$
    try {
      List<Future<IStatus>> futures = es.invokeAll(jobs);

      // Now wait for them to finish
      for (Future<IStatus> future : futures) {
        while (!future.isDone()) {
          if (monitor != null && monitor.isCanceled()) {
            future.cancel(true);
          }
          Thread.yield();
        }

        // When done, get their result
        try {
          IStatus futureResult = future.get();
          if (!futureResult.isOK()) {
            errors.merge(futureResult);
          }
        } catch (CancellationException ce) {
          // ignore
        } catch (ExecutionException e) {
          Throwable t = e.getCause();
          errors.merge(new Status(IStatus.ERROR, GitPlugin.PLUGIN_ID, t.getMessage(), t));
        }
      }
    } catch (InterruptedException e) {
      IdeLog.logError(GitPlugin.getDefault(), e);
    }

    // Copy the last full list of changed files we built up on refresh. Used to pass along the delta
    // FIXME I think the values here may have already changed! I saw a file that had staged changes
    // but no unstaged
    // prior to commit
    // but here it showed true for both (which should have only gotten modified by a pre-commit
    // hook)
    Collection<ChangedFile> preRefresh;
    synchronized (this.changedFilesLock) {
      if (this.changedFiles != null) {
        preRefresh = new ArrayList<ChangedFile>(this.changedFiles.size());
        for (ChangedFile file : this.changedFiles) {
          preRefresh.add(new ChangedFile(file));
        }
      } else {
        preRefresh = new ArrayList<ChangedFile>(0);
      }

      // Now wipe any existing ChangedFile entries for any of the filePaths and add the ones we
      // generated in
      // dictionary
      if (CollectionsUtil.isEmpty(filePathStrings)) {
        this.changedFiles = new ArrayList<ChangedFile>();
      } else {
        this.changedFiles =
            CollectionsUtil.filter(
                this.changedFiles,
                new IFilter<ChangedFile>() {
                  public boolean include(ChangedFile item) {
                    return !filePathStrings.contains(item.portablePath);
                  }
                });
      }
      if (!CollectionsUtil.isEmpty(this.files)) {
        this.changedFiles.addAll(this.files);
      }
    }

    // Don't hold onto temp list in memory!
    this.files = null;

    postIndexChange(preRefresh, this.changedFiles);
    sub.done();
    if (!errors.isOK()) {
      return errors;
    }
    return Status.OK_STATUS;
  }
 /**
  * hasParameters
  *
  * @return
  */
 public boolean hasParameters() {
   return !CollectionsUtil.isEmpty(_parameters);
 }
Пример #24
0
  /**
   * Do the PYTHON installation.
   *
   * @param progressMonitor
   * @return A status indication of the process success or failure.
   */
  protected IStatus install(IProgressMonitor progressMonitor) {
    if (CollectionsUtil.isEmpty(downloadedPaths)) {
      String failureMessge = Messages.InstallProcessor_couldNotLocateInstaller;
      String err = NLS.bind(Messages.InstallProcessor_failedToInstall, PYTHON);
      displayMessageInUIThread(
          MessageDialog.ERROR,
          Messages.InstallProcessor_installationErrorTitle,
          err + ' ' + failureMessge);
      return new Status(IStatus.ERROR, PortalUIPlugin.PLUGIN_ID, err + ' ' + failureMessge);
    }
    SubMonitor subMonitor =
        SubMonitor.convert(
            progressMonitor,
            Messages.InstallProcessor_installerProgressInfo,
            IProgressMonitor.UNKNOWN);
    final Map<String, Object> installationAttributes = new HashMap<String, Object>();
    try {
      subMonitor.beginTask(
          NLS.bind(Messages.InstallProcessor_installingTaskName, PYTHON), IProgressMonitor.UNKNOWN);
      final String[] installDir = new String[1];
      Job installPythonDialog = new UIJob("Python installer options") // $NON-NLS-1$
          {
            @Override
            public IStatus runInUIThread(IProgressMonitor monitor) {
              PythonInstallerOptionsDialog dialog = new PythonInstallerOptionsDialog();
              if (dialog.open() == Window.OK) {
                installationAttributes.putAll(dialog.getAttributes());
                return Status.OK_STATUS;
              }
              return Status.CANCEL_STATUS;
            }
          };
      installPythonDialog.schedule();
      try {
        installPythonDialog.join();
      } catch (InterruptedException e) {
      }
      IStatus result = installPythonDialog.getResult();
      if (!result.isOK()) {
        return result;
      }

      IStatus status = installPYTHON(installationAttributes);
      if (!status.isOK()) {
        return status;
      }
      IdeLog.logInfo(
          PortalUIPlugin.getDefault(),
          MessageFormat.format(
              "Successfully installed PYTHON into {0}. PYTHON installation completed.",
              installDir[0])); // $NON-NLS-1$
      // note that we called the finalizeInstallation from the installPYTHON Job.
      return Status.OK_STATUS;
    } catch (Exception e) {
      IdeLog.logError(
          PortalUIPlugin.getDefault(), "Error while installing PYTHON", e); // $NON-NLS-1$
      return new Status(
          IStatus.ERROR,
          PortalUIPlugin.PLUGIN_ID,
          NLS.bind(Messages.InstallProcessor_errorWhileInstalling, PYTHON));
    } finally {
      subMonitor.done();
    }
  }
 /**
  * hasExceptions
  *
  * @return
  */
 public boolean hasExceptions() {
   return !CollectionsUtil.isEmpty(_exceptions);
 }