| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.ui.wizards; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceProxy; |
| 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; |
| import org.eclipse.dltk.core.DLTKContentTypeManager; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.IBuildpathEntry; |
| import org.eclipse.dltk.core.IDLTKLanguageToolkit; |
| import org.eclipse.dltk.internal.core.BuildpathEntry; |
| import org.eclipse.dltk.launching.ScriptRuntime; |
| import org.eclipse.dltk.ui.wizards.IBuildpathDetector; |
| |
| import com.ibm.icu.text.Collator; |
| |
| /** |
| */ |
| public class BuildpathDetector implements IBuildpathDetector { |
| private HashMap<IPath, List<IPath>> fSourceFolders; |
| // private List fSourceFiles; |
| private HashSet<IPath> fZIPFiles; |
| private IProject fProject; |
| private IBuildpathEntry[] fResultBuildpath; |
| private IProgressMonitor fMonitor; |
| private IDLTKLanguageToolkit fToolkit; |
| |
| private static class BPSorter implements Comparator<IBuildpathEntry> { |
| private Collator fCollator = Collator.getInstance(); |
| |
| @Override |
| public int compare(IBuildpathEntry e1, IBuildpathEntry e2) { |
| return fCollator.compare(e1.getPath().toString(), |
| e2.getPath().toString()); |
| } |
| } |
| |
| public BuildpathDetector(IProject project, IDLTKLanguageToolkit toolkit) { |
| fSourceFolders = new HashMap<>(); |
| fZIPFiles = new HashSet<>(10); |
| // fSourceFiles = new ArrayList(100); |
| fProject = project; |
| fResultBuildpath = null; |
| fToolkit = toolkit; |
| } |
| |
| private boolean isNested(IPath path, Iterator<IPath> iter) { |
| while (iter.hasNext()) { |
| IPath other = iter.next(); |
| if (other.isPrefixOf(path)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Method detectBuildpath. |
| * |
| * @param monitor |
| * The progress monitor (not null) |
| * @throws CoreException |
| */ |
| @Override |
| public void detectBuildpath(IProgressMonitor monitor) throws CoreException { |
| if (monitor == null) { |
| monitor = new NullProgressMonitor(); |
| } |
| try { |
| monitor.beginTask(Messages.BuildpathDetector_detectingBuildpath, |
| 120); |
| fMonitor = monitor; |
| final List<IFile> correctFiles = new ArrayList<>(); |
| fProject.accept( |
| proxy -> BuildpathDetector.this.visit(proxy, correctFiles), |
| IResource.NONE); |
| monitor.worked(10); |
| SubProgressMonitor sub = new SubProgressMonitor(monitor, 80); |
| processSources(correctFiles, sub); |
| sub.done(); |
| ArrayList<IBuildpathEntry> cpEntries = new ArrayList<>(); |
| detectSourceFolders(cpEntries); |
| if (monitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| monitor.worked(10); |
| if (monitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| monitor.worked(10); |
| detectLibraries(cpEntries); |
| if (monitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| monitor.worked(10); |
| addInterpreterContainer(cpEntries); |
| if (cpEntries.size() == 1) { |
| IBuildpathEntry entry = cpEntries.get(0); |
| if (entry.getEntryKind() == IBuildpathEntry.BPE_CONTAINER) { |
| cpEntries.add(0, |
| DLTKCore.newSourceEntry(fProject.getFullPath())); |
| } |
| |
| } |
| if (cpEntries.isEmpty() /* && fSourceFiles.isEmpty() */) { |
| return; |
| } |
| |
| IBuildpathEntry[] entries = cpEntries |
| .toArray(new IBuildpathEntry[cpEntries.size()]); |
| if (!BuildpathEntry |
| .validateBuildpath(DLTKCore.create(fProject), entries) |
| .isOK()) { |
| return; |
| } |
| fResultBuildpath = entries; |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| protected void processSources(List<IFile> correctFiles, |
| SubProgressMonitor sub) { |
| } |
| |
| protected void addInterpreterContainer( |
| ArrayList<IBuildpathEntry> cpEntries) { |
| cpEntries.add(DLTKCore.newContainerEntry( |
| new Path(ScriptRuntime.INTERPRETER_CONTAINER))); |
| } |
| |
| private void detectLibraries(ArrayList<IBuildpathEntry> cpEntries) { |
| if (this.fToolkit.languageSupportZIPBuildpath()) { |
| ArrayList<IBuildpathEntry> res = new ArrayList<>(); |
| Set<IPath> sourceFolderSet = fSourceFolders.keySet(); |
| for (Iterator<IPath> iter = fZIPFiles.iterator(); iter.hasNext();) { |
| IPath path = iter.next(); |
| if (isNested(path, sourceFolderSet.iterator())) { |
| continue; |
| } |
| IBuildpathEntry entry = DLTKCore.newLibraryEntry(path); |
| res.add(entry); |
| } |
| Collections.sort(res, new BPSorter()); |
| cpEntries.addAll(res); |
| } |
| } |
| |
| private void detectSourceFolders(ArrayList<IBuildpathEntry> resEntries) { |
| ArrayList<IBuildpathEntry> res = new ArrayList<>(); |
| Set<IPath> sourceFolderSet = fSourceFolders.keySet(); |
| for (Iterator<IPath> iter = sourceFolderSet.iterator(); iter |
| .hasNext();) { |
| IPath path = iter.next(); |
| // ArrayList excluded = new ArrayList(); |
| boolean primary = true; |
| for (Iterator<IPath> inner = sourceFolderSet.iterator(); inner |
| .hasNext();) { |
| IPath other = inner.next(); |
| if (!path.equals(other) && other.isPrefixOf(path)) { |
| primary = false; |
| break; |
| } |
| } |
| if (primary) { |
| boolean isHidden = false; |
| // Hidden file filtering. |
| for (int i = 0; i < path.segmentCount(); i++) { |
| if (path.segment(i).startsWith(".")) { //$NON-NLS-1$ |
| isHidden = true; |
| break; |
| } |
| } |
| if (!isHidden) { |
| IBuildpathEntry entry = DLTKCore.newSourceEntry(path); |
| res.add(entry); |
| } |
| } |
| } |
| Collections.sort(res, new BPSorter()); |
| resEntries.addAll(res); |
| } |
| |
| private void addToMap(HashMap<IPath, List<IPath>> map, IPath folderPath, |
| IPath relPath) { |
| List<IPath> list = map.get(folderPath); |
| if (list == null) { |
| list = new ArrayList<>(50); |
| map.put(folderPath, list); |
| } |
| list.add(relPath); |
| } |
| |
| // private IPath getFolderPath(IPath packPath, IPath relpath) { |
| // int remainingSegments = packPath.segmentCount() |
| // - relpath.segmentCount(); |
| // if (remainingSegments >= 0) { |
| // IPath common = packPath.removeFirstSegments(remainingSegments); |
| // if (common.equals(relpath)) { |
| // return packPath.uptoSegment(remainingSegments); |
| // } |
| // } |
| // return null; |
| // } |
| |
| private boolean hasExtension(String name, String ext) { |
| return name.endsWith(ext) && (ext.length() != name.length()); |
| } |
| |
| public boolean visit(IResourceProxy proxy, List<IFile> files) { |
| if (fMonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| if (proxy.getType() == IResource.FILE) { |
| String name = proxy.getName(); |
| IFile res = (IFile) proxy.requestResource(); |
| if (visitSourceModule(res)) { |
| files.add(res); |
| } else if (res.getType() == IResource.FILE |
| && hasExtension(name, ".zip")) { //$NON-NLS-1$ |
| fZIPFiles.add(proxy.requestFullPath()); |
| } |
| return false; |
| } |
| return true; |
| } |
| |
| protected boolean visitSourceModule(IFile file) { |
| if (DLTKContentTypeManager.isValidResourceForContentType(fToolkit, |
| file)) { |
| IPath packPath = file.getParent().getFullPath(); |
| String cuName = file.getName(); |
| addToMap(fSourceFolders, packPath, new Path(cuName)); |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public IBuildpathEntry[] getBuildpath() { |
| return fResultBuildpath; |
| } |
| } |