/*******************************************************************************
* Copyright (c) 2014 Bruno Medeiros and other Contributors.
* 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:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package com.googlecode.goclipse.tooling;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertFail;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;
import com.googlecode.goclipse.tooling.env.GoWorkspaceLocation;
import melnorme.utilbox.collections.Collection2;
import melnorme.utilbox.collections.HashSet2;
import melnorme.utilbox.collections.LinkedHashMap2;
import melnorme.utilbox.misc.Location;
public abstract class GoPackagesVisitor {
protected final Location sourceRoot;
protected final LinkedHashMap2<GoPackageName, Path> modules = new LinkedHashMap2<>();
protected final HashSet2<Path> moduleFiles = new HashSet2<>();
public GoPackagesVisitor(GoWorkspaceLocation goWorkspace, Location directoryToVisit) {
this.sourceRoot = goWorkspace.getSrcLocation();
if(!directoryToVisit.startsWith(sourceRoot)) {
return;
}
try {
visitFolder(directoryToVisit);
} catch (IOException e) {
throw assertFail("Should not happen, file visit should not throw exception");
}
}
protected abstract FileVisitResult handleFileVisitException(Path file, IOException exc);
protected void visitFolder(final Location startingDir) throws IOException {
if(!startingDir.toFile().exists()) {
return;
}
Files.walkFileTree(startingDir.toPath(),
EnumSet.of(FileVisitOption.FOLLOW_LINKS),
Integer.MAX_VALUE,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
assertTrue(dir.startsWith(startingDir.path));
Location dirLoc = Location.create_fromValid(dir);
String fileName = dir.getFileName().toString();
if(isIgnoredName(fileName)) {
return FileVisitResult.SKIP_SUBTREE;
}
if(isDirectoryAValidGoPackage(dir)) {
GoPackageName goPackageName = GoPackageName.fromPath(sourceRoot.relativize(dirLoc));
addEntry(goPackageName, dir);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return handleFileVisitException(file, exc);
}
});
}
protected boolean isIgnoredName(String fileName) {
return fileName.startsWith("_") || fileName.startsWith(".");
}
protected boolean isDirectoryAValidGoPackage(final Path goPackageDir) throws IOException {
CheckDirectoryHasGoSourceFiles checkSourceFiles = new CheckDirectoryHasGoSourceFiles();
Files.walkFileTree(goPackageDir, EnumSet.of(FileVisitOption.FOLLOW_LINKS), 1, checkSourceFiles);
return checkSourceFiles.hasGoSourceFiles;
}
public class CheckDirectoryHasGoSourceFiles extends SimpleFileVisitor<Path> {
public boolean hasGoSourceFiles = false;
@Override
public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) throws IOException {
String fileName = filePath.getFileName().toString();
if(!attrs.isDirectory() && fileName.endsWith(".go") && !isIgnoredName(fileName)) {
this.hasGoSourceFiles = true;
return FileVisitResult.TERMINATE;
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return handleFileVisitException(file, exc);
}
}
protected void addEntry(GoPackageName packageName, Path fullPath) {
assertNotNull(packageName);
if(packageName.getFullNameAsString().isEmpty()) {
// ignore
return;
}
modules.put(packageName, fullPath);
moduleFiles.add(fullPath);
}
public HashSet2<Path> getModuleFiles() {
return moduleFiles;
}
public Collection2<GoPackageName> getModuleNames() {
return modules.getKeysView();
}
}