/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.netbeans.modules.java.openjdk.project; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.swing.Action; import org.apache.tools.ant.module.api.support.ActionUtils; import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.modules.java.openjdk.common.BuildUtils; import org.netbeans.modules.java.openjdk.common.ShortcutUtils; import org.netbeans.spi.java.classpath.support.ClassPathSupport; import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.ui.support.ProjectSensitiveActions; import org.openide.execution.ExecutorTask; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.modules.InstalledFileLocator; import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.openide.util.Pair; import org.openide.util.Task; import org.openide.util.TaskListener; /** * * @author lahvac */ public class ActionProviderImpl implements ActionProvider { private static final String COMMAND_BUILD_FAST = "build-fast"; private static final String COMMAND_BUILD_GENERIC_FAST = "build-generic-fast"; private static final String COMMAND_SELECT_TOOL = "select.tool"; private static final Map<Pair<String, RootKind>, String[]> command2Targets = new HashMap<Pair<String, RootKind>, String[]>() {{ put(Pair.of(COMMAND_BUILD, RootKind.SOURCE), new String[] {"build"}); put(Pair.of(COMMAND_BUILD, RootKind.TEST), new String[] {"build"}); put(Pair.of(COMMAND_BUILD_FAST, RootKind.SOURCE), new String[] {"build-fast"}); put(Pair.of(COMMAND_BUILD_FAST, RootKind.TEST), new String[] {"build-fast"}); put(Pair.of(COMMAND_CLEAN, RootKind.SOURCE), new String[] {"clean"}); put(Pair.of(COMMAND_CLEAN, RootKind.TEST), new String[] {"clean"}); put(Pair.of(COMMAND_REBUILD, RootKind.SOURCE), new String[] {"clean", "build"}); put(Pair.of(COMMAND_REBUILD, RootKind.TEST), new String[] {"clean", "build"}); put(Pair.of(COMMAND_COMPILE_SINGLE, RootKind.SOURCE), new String[] {"compile-single"}); put(Pair.of(COMMAND_COMPILE_SINGLE, RootKind.TEST), new String[] {"compile-single"}); put(Pair.of(COMMAND_RUN, RootKind.SOURCE), new String[] {"run"}); put(Pair.of(COMMAND_RUN, RootKind.TEST), new String[] {"run"}); put(Pair.of(COMMAND_RUN_SINGLE, RootKind.SOURCE), new String[] {"run-single"}); put(Pair.of(COMMAND_RUN_SINGLE, RootKind.TEST), new String[] {"jtreg"}); // COMMAND_TEST; // COMMAND_TEST_SINGLE; put(Pair.of(COMMAND_DEBUG, RootKind.SOURCE), new String[] {"debug"}); put(Pair.of(COMMAND_DEBUG, RootKind.TEST), new String[] {"debug"}); put(Pair.of(COMMAND_DEBUG_SINGLE, RootKind.SOURCE), new String[] {"debug-single"}); put(Pair.of(COMMAND_DEBUG_SINGLE, RootKind.TEST), new String[] {"debug-jtreg"}); // COMMAND_DEBUG_TEST_SINGLE; // COMMAND_DEBUG_STEP_INTO; put(Pair.of(COMMAND_SELECT_TOOL, RootKind.SOURCE), new String[] {"select-tool"}); put(Pair.of(COMMAND_SELECT_TOOL, RootKind.TEST), new String[] {"select-tool"}); }}; private static final Map<Pair<String, RootKind>, RunSingleConfig> command2Properties = new HashMap<Pair<String, RootKind>, RunSingleConfig>() {{ put(Pair.of(COMMAND_COMPILE_SINGLE, RootKind.SOURCE), new RunSingleConfig("includes", RunSingleConfig.Type.RELATIVE, ",")); put(Pair.of(COMMAND_COMPILE_SINGLE, RootKind.TEST), new RunSingleConfig("includes", RunSingleConfig.Type.RELATIVE, ",")); put(Pair.of(COMMAND_RUN_SINGLE, RootKind.SOURCE), new RunSingleConfig("run.classname", RunSingleConfig.Type.CLASSNAME, null)); put(Pair.of(COMMAND_RUN_SINGLE, RootKind.TEST), new RunSingleConfig("jtreg.tests", RunSingleConfig.Type.RELATIVE, " ")); put(Pair.of(COMMAND_DEBUG_SINGLE, RootKind.SOURCE), new RunSingleConfig("debug.classname", RunSingleConfig.Type.CLASSNAME, null)); put(Pair.of(COMMAND_DEBUG_SINGLE, RootKind.TEST), new RunSingleConfig("jtreg.tests", RunSingleConfig.Type.RELATIVE, " ")); }}; private final JDKProject project; private final FileObject repository; private final FileObject script; private final FileObject genericScript; private final String[] supportedActions; private final String[] genericSupportedActions; public ActionProviderImpl(JDKProject project) { this.project = project; FileObject repo = project.currentModule != null ? project.getProjectDirectory().getParent().getParent() : project.getProjectDirectory().getParent(); repository = repo; File scriptFile = InstalledFileLocator.getDefault().locate("scripts/build-generic.xml", "org.netbeans.modules.java.openjdk.project", false); genericScript = FileUtil.toFileObject(scriptFile); if (project.currentModule != null && project.moduleRepository.isConsolidatedRepo()) { String repoName = ShortcutUtils.getDefault().inferLegacyRepository(project); File fastBuild = InstalledFileLocator.getDefault().locate("scripts/build-" + repoName + "-consol.xml", "org.netbeans.modules.java.openjdk.project", false); if (fastBuild != null && ShortcutUtils.getDefault().shouldUseCustomBuild(repoName, FileUtil.getRelativePath(repo, project.getProjectDirectory()))) { scriptFile = fastBuild; } } else { String repoName = repo.getNameExt(); File fastBuild = InstalledFileLocator.getDefault().locate("scripts/build-" + repoName + ".xml", "org.netbeans.modules.java.openjdk.project", false); if (fastBuild != null && ShortcutUtils.getDefault().shouldUseCustomBuild(repoName, FileUtil.getRelativePath(repo, project.getProjectDirectory()))) { scriptFile = fastBuild; } } script = FileUtil.toFileObject(scriptFile); supportedActions = readSupportedActions(script); genericSupportedActions = readSupportedActions(genericScript); } private String[] readSupportedActions(FileObject from) { String[] supported = new String[0]; try { for (String l : from.asLines("UTF-8")) { if (l.contains("SUPPORTED_ACTIONS:")) { String[] actions = l.substring(l.indexOf(':') + 1).trim().split(","); Set<String> filteredActions = new HashSet<>(); for (Pair<String, RootKind> k : command2Targets.keySet()) { filteredActions.add(k.first()); } filteredActions.retainAll(Arrays.asList(actions)); filteredActions.add(COMMAND_BUILD_GENERIC_FAST); filteredActions.add(COMMAND_PROFILE_TEST_SINGLE); supported = filteredActions.toArray(new String[0]); break; } } } catch (IOException ex) { //??? Exceptions.printStackTrace(ex); } return supported; } @Override public String[] getSupportedActions() { Settings settings = project.getLookup().lookup(Settings.class); return settings.isUseAntBuild() ? supportedActions : genericSupportedActions; } @Override public void invokeAction(String command, Lookup context) throws IllegalArgumentException { if (COMMAND_PROFILE_TEST_SINGLE.equals(command)) { for (ActionProvider ap : Lookup.getDefault().lookupAll(ActionProvider.class)) { if (new HashSet<>(Arrays.asList(ap.getSupportedActions())).contains(COMMAND_PROFILE_TEST_SINGLE) && ap.isActionEnabled(COMMAND_PROFILE_TEST_SINGLE, context)) { ap.invokeAction(COMMAND_PROFILE_TEST_SINGLE, context); return ; } } } FileObject scriptFO = script; Settings settings = project.getLookup().lookup(Settings.class); Properties props = new Properties(); if (settings.isUseAntBuild()) { props.put("langtools.build.location", settings.getAntBuildLocation()); } else { scriptFO = genericScript; if (COMMAND_BUILD_FAST.equals(command)) { command = COMMAND_BUILD_GENERIC_FAST; } } if (COMMAND_BUILD_GENERIC_FAST.equals(command)) { switch (settings.getRunBuildSetting()) { case NEVER: ActionProgress.start(context).finished(true); return; case ALWAYS: default: break; } scriptFO = genericScript; command = COMMAND_BUILD_FAST; //XXX: should only do this if genericScript supports it } FileObject basedirFO = project.currentModule != null ? scriptFO == genericScript ? project.moduleRepository.getJDKRoot() : repository : repository.getParent(); props.put("basedir", FileUtil.toFile(basedirFO).getAbsolutePath()); props.put("CONF", project.configurations.getActiveConfiguration().getLocation().getName()); props.put("nb.jdk.project.target.java.home", BuildUtils.findTargetJavaHome(project.getProjectDirectory()).getAbsolutePath()); RootKind kind = getKind(context); RunSingleConfig singleFileProperty = command2Properties.get(Pair.of(command, kind)); if (singleFileProperty != null) { String srcdir = ""; String moduleName = ""; StringBuilder value = new StringBuilder(); String sep = ""; for (FileObject file : context.lookupAll(FileObject.class)) { value.append(sep); ClassPath sourceCP; switch (kind) { case SOURCE: sourceCP = ClassPath.getClassPath(file, ClassPath.SOURCE); break; case TEST: sourceCP = ClassPathSupport.createClassPath(BuildUtils.getFileObject(project.getProjectDirectory(), "../../test")); break; default: throw new IllegalStateException(kind.name()); } value.append(singleFileProperty.valueType.convert(sourceCP, file)); sep = singleFileProperty.separator; FileObject ownerRoot = sourceCP.findOwnerRoot(file); srcdir = FileUtil.getRelativePath(BuildUtils.getFileObject(project.getProjectDirectory(), "../.."), ownerRoot); moduleName = ownerRoot.getParent().getParent().getNameExt(); } props.put(singleFileProperty.propertyName, value.toString()); props.put("srcdir", srcdir); props.put("module.name", moduleName); } final ActionProgress progress = ActionProgress.start(context); try { ActionUtils.runTarget(scriptFO, command2Targets.get(Pair.of(command, kind)), props) .addTaskListener(new TaskListener() { @Override public void taskFinished(Task task) { progress.finished(((ExecutorTask) task).result() == 0); } }); } catch (IOException ex) { //??? Exceptions.printStackTrace(ex); progress.finished(false); } } @Override public boolean isActionEnabled(String command, Lookup context) throws IllegalArgumentException { RootKind kind = getKind(context); RunSingleConfig singleFileProperty = command2Properties.get(Pair.of(command, kind)); if (singleFileProperty != null) { int fileCount = context.lookupAll(FileObject.class).size(); if (fileCount == 0 || (fileCount > 1 && singleFileProperty.separator == null)) return false; } return true; } private RootKind getKind(Lookup context) { FileObject aFile = context.lookup(FileObject.class); FileObject testDir = BuildUtils.getFileObject(project.getProjectDirectory(), "../../test"); return aFile != null && testDir != null && FileUtil.isParentOf(testDir, aFile) ? RootKind.TEST : RootKind.SOURCE; } private static final class RunSingleConfig { public final String propertyName; public final Type valueType; public final String separator; public RunSingleConfig(String propertyName, Type valueType, String separator) { this.propertyName = propertyName; this.valueType = valueType; this.separator = separator; } enum Type { RELATIVE { @Override public String convert(ClassPath sourceCP, FileObject file) { return sourceCP.getResourceName(file); } }, CLASSNAME { @Override public String convert(ClassPath sourceCP, FileObject file) { return sourceCP.getResourceName(file, '.', false); } }; public abstract String convert(ClassPath sourceCP, FileObject file); } } private enum RootKind { SOURCE, TEST; } //for layer: @Messages("DN_SelectTool=Select Tool (langtools only)") public static Action selectToolAction() { return ProjectSensitiveActions.projectCommandAction(COMMAND_SELECT_TOOL, Bundle.DN_SelectTool(), null); } }