package org.codehaus.groovy.eclipse.dsl.checker; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintStream; import org.codehaus.groovy.eclipse.dsl.GroovyDSLCoreActivator; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; 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.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.jdt.core.JavaCore; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.application.WorkbenchAdvisor; import org.eclipse.ui.internal.Workbench; public class StaticCheckerApplication implements IApplication { class CheckerJob extends Job { public CheckerJob() { super("Checker Job"); } @Override protected IStatus run(IProgressMonitor monitor) { // now ensure that the classpath containers and variables are initialized try { JavaCore.initializeAfterLoad(new NullProgressMonitor()); } catch (CoreException e) { e.printStackTrace(); } // create the project if required try { createProject(); } catch (CoreException e) { System.err.println("Failed to create project " + projectName + " at location " + projectFolderPath); e.printStackTrace(); return e.getStatus(); } // ensure project is open IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); try { project.open(null); } catch (CoreException e) { System.err.println("Failed to open project " + projectName); e.printStackTrace(); return e.getStatus(); } // Add the extra dslds to the workspace inside of the target project addExtraDslds(); // Ensure that dslds are all available GroovyDSLCoreActivator.getDefault().getContextStoreManager().initialize(project, true); System.out.println("Performing static type checking on project " + projectName); boolean success = false; try { IStaticCheckerHandler handler = new SysoutStaticCheckerHandler(resultFile == null ? System.out : createOutStream(resultFile)); ResourceTypeChecker checker = new ResourceTypeChecker(handler, projectName, inclusionFilters, exclusionFilters, assertionsOnly); success = checker.doCheck(null); } catch (Exception e) { e.printStackTrace(); } finally { removeExtraDslds(); } display.asyncExec(new Runnable() { public void run() { Workbench.getInstance().close(); } }); // FIXADE Is this OK to do? System.exit(success ? 0 : -1); // won't get here return Status.OK_STATUS; } } /** * * @author andrew * @created Aug 31, 2011 */ public class CheckerWorkbenchAdvisor extends WorkbenchAdvisor { @Override public String getInitialWindowPerspectiveId() { return null; } @Override public void postStartup() { CheckerJob checkerJob = new CheckerJob(); checkerJob.schedule(); } @Override public void postShutdown() { super.postShutdown(); } } private String projectName; private char[][] inclusionFilters; private char[][] exclusionFilters; private boolean assertionsOnly; private String[] extraDslds; private IFile[] extraDsldFiles; private String projectFolderPath; Display display; private String resultFile; public Object start(IApplicationContext context) throws Exception { processCommandLine((String[]) context.getArguments().get(IApplicationContext.APPLICATION_ARGS)); try { display = createDisplay(); } catch (Exception e) { e.printStackTrace(); throw e; } WorkbenchAdvisor advisor = new CheckerWorkbenchAdvisor(); return PlatformUI.createAndRunWorkbench(display, advisor); } public PrintStream createOutStream(String fileName) throws FileNotFoundException { return new PrintStream(new File(fileName)); } public void stop() { removeExtraDslds(); } private void addExtraDslds() { if (extraDslds != null) { extraDsldFiles = new IFile[extraDslds.length]; for (int i = 0; i < extraDslds.length; i++) { File file = new File(extraDslds[i]); if (file.exists()) { IFile linkedFile = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName).getFile(file.getName()); if (linkedFile.exists() && linkedFile.isLinked()) { try { linkedFile.delete(true, null); } catch (CoreException e) { e.printStackTrace(); } } if (!linkedFile.exists()) { try { System.out.println("Adding " + file.toURI()); linkedFile.createLink(file.toURI(), IResource.NONE, null); extraDsldFiles[i] = linkedFile; } catch (CoreException e) { e.printStackTrace(); } } } else { System.err.println("Warning: DSLD file " + extraDslds[i] + " doesn't exist. Ignoring."); } } } } private void createProject() throws CoreException { if (projectFolderPath == null) { // nothing to do return; } IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); if (project.exists()) { if (project.getLocation().toOSString().equals(projectFolderPath)) { // project already exists do nothing return; } else { // delete existing project from workspace, but not the filesystem project.delete(IResource.NEVER_DELETE_PROJECT_CONTENT | IResource.FORCE, null); } } IPath dotProjectPath = new Path(projectFolderPath).append(".project"); IProjectDescription description = ResourcesPlugin.getWorkspace().loadProjectDescription(dotProjectPath); description.setName(projectName); project.create(description, null); } private void processCommandLine(String[] args) { boolean doHelp = false; String excludes = null; String includes = null; if (args.length < 1) { printUsage(true); Workbench.getInstance().close(); return; } projectName = args[args.length - 1]; for (int i = 0; i < args.length; i++) { String arg = args[i]; if (arg.equals("-h") || arg.equals("--help")) { doHelp = true; break; } else if (arg.equals("--assertions_only")) { assertionsOnly = true; } else if (arg.equals("--excludes")) { if (i == args.length-1) { System.err.println("Missing --excludes argument"); doHelp = true; break; } excludes = args[++i]; } else if (arg.equals("--includes")) { if (i == args.length-1) { System.err.println("Missing --includes argument"); doHelp = true; break; } includes = args[++i]; } else if (arg.equals("--extra_dslds")) { if (i == args.length-1) { System.err.println("Missing --extraDslds argument"); doHelp = true; break; } extraDslds = args[++i].split("\\|"); } else if (arg.equals("--project_path")) { if (i == args.length-1) { System.err.println("Missing --project_path argument"); doHelp = true; break; } projectFolderPath = args[++i]; } else if (arg.equals("--result_file")) { if (i == args.length-1) { System.err.println("Missing --result_file argument"); doHelp = true; break; } resultFile = args[++i]; } } inclusionFilters = convertToCharChar(includes); exclusionFilters = convertToCharChar(excludes); if (doHelp) { printUsage(false); Workbench.getInstance().close(); } } private char[][] convertToCharChar(String str) { if (str == null) { return null; } String[] splits = str.split("\\|"); char[][] chars = new char[splits.length][]; for (int i = 0; i < splits.length; i++) { chars[i] = ("/" + projectName + "/" + splits[i]).toCharArray(); } return chars; } private void printUsage(boolean isInvalid) { if (isInvalid) { System.out.println("Invalid command line."); } System.out.println("Usage:"); System.out.println("eclipse -application org.codehause.groovy.eclipse.staticCheck [--help] [-h] [--extra_dslds <FILES>] [--assertions_only] [--excludes <PATH>] [--includes <PATH>] [--project_path <PATH>] <PROJECT_NAME>"); System.out.println("where:"); System.out.println("\t--help OR -h Print this message and exit."); System.out.println("\t--extra_dslds list of extra dsld files to be included in this check. Use '|' as a file separator."); System.out.println("\t--assertions_only Don't report unknown types. Only look for type assertions"); System.out.println("\t--excludes Project-relative exclusion filters."); System.out.println("\t--includes Project-relative inclusion filters."); System.out.println("\t--project_path File system path to the project to check (only required if project is not already in workspace)."); System.out.println("\t--result_file File to send static checking results to. If not specified, then results sent to sysout."); System.out.println("\t<PROJECT_NAME> Name of a project to type check. If not already in workspace, then must also use '--project_path'."); System.out.println(); System.out.println("Ant style filters are allowed. Eg, src/org/codehaus/groovy/**/*.groovy means all files with groovy extensions in the org.codehaus.groovy package or below will be ex/included Filters can be concentenated using '|'."); } private void removeExtraDslds() { if (extraDsldFiles != null) { for (IFile file : extraDsldFiles) { if (file != null && file.exists()) { try { System.out.println("\nRemoving " + file.getLocation().toFile().toURI()); file.delete(true, null); } catch (CoreException e) { e.printStackTrace(); } } } } } /** * Creates the display used by the application. * * @return the display used by the application */ protected Display createDisplay() { return PlatformUI.createDisplay(); } }