diff --git a/src/main/dig/hdl/BASYS3_Config.xml b/src/main/dig/hdl/BASYS3_Config.xml index a55519d6e..aad7f1eb3 100644 --- a/src/main/dig/hdl/BASYS3_Config.xml +++ b/src/main/dig/hdl/BASYS3_Config.xml @@ -2,7 +2,7 @@ - + vivado vivado/<?=shortname?>.xpr diff --git a/src/main/java/de/neemann/digital/ide/Command.java b/src/main/java/de/neemann/digital/ide/Command.java index f29f81280..ffcda79f8 100644 --- a/src/main/java/de/neemann/digital/ide/Command.java +++ b/src/main/java/de/neemann/digital/ide/Command.java @@ -11,7 +11,6 @@ package de.neemann.digital.ide; public class Command { private final String name; private final boolean filter; - private final boolean gui; private final String requires; private final String[] args; private final int timeout; @@ -32,7 +31,6 @@ public class Command { this.timeout = timeout; this.args = args; this.filter = filter; - this.gui = gui; } /** @@ -70,13 +68,6 @@ public class Command { return filter; } - /** - * @return true if application has a gui - */ - public boolean isGui() { - return gui; - } - /** * @return timeout in seconds */ diff --git a/src/main/java/de/neemann/digital/ide/ConfigCache.java b/src/main/java/de/neemann/digital/ide/ConfigCache.java new file mode 100644 index 000000000..066593888 --- /dev/null +++ b/src/main/java/de/neemann/digital/ide/ConfigCache.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 Helmut Neemann. + * Use of this source code is governed by the GPL v3 license + * that can be found in the LICENSE file. + */ +package de.neemann.digital.ide; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +/** + * Helper to avoid loading a config several times. + */ +class ConfigCache { + private final File initialFile; + private HashMap cache; + + /** + * Creates a new instance + * + * @param initialFile the intial config file + */ + ConfigCache(File initialFile) { + this.initialFile = initialFile; + cache = new HashMap<>(); + } + + /** + * Loads the give config. + * + * @param filename the configs file name + * @return the config + * @throws IOException IOException + */ + Configuration getConfig(String filename) throws IOException { + if (initialFile == null) + throw new IOException("No initial config file given!"); + + + Configuration c = cache.get(filename); + if (c == null) { + c = Configuration.load(new File(initialFile.getParentFile(), filename)); + cache.put(filename, c); + } + return c; + } +} diff --git a/src/main/java/de/neemann/digital/ide/Configuration.java b/src/main/java/de/neemann/digital/ide/Configuration.java index 09bdfaf4f..85b6f33d0 100644 --- a/src/main/java/de/neemann/digital/ide/Configuration.java +++ b/src/main/java/de/neemann/digital/ide/Configuration.java @@ -80,7 +80,6 @@ public final class Configuration { xStream.aliasAttribute(Command.class, "name", "name"); xStream.aliasAttribute(Command.class, "requires", "requires"); xStream.aliasAttribute(Command.class, "filter", "filter"); - xStream.aliasAttribute(Command.class, "gui", "gui"); xStream.aliasAttribute(Command.class, "timeout", "timeout"); xStream.addImplicitCollection(Command.class, "args", "arg", String.class); xStream.alias("file", FileToCreate.class); @@ -160,33 +159,17 @@ public final class Configuration { return menu; } - private void checkFilesToCreate(File fileToExecute, HDLModel hdlModel) throws HGSEvalException, IOException, ParserException { - Context context = createContext(fileToExecute, hdlModel); + private final class ExecuteAction extends AbstractAction { + private final Command command; - if (files != null) - for (FileToCreate f : files) { - context.clearOutput(); - Parser p = new Parser(f.getName()); - p.parse().execute(context); - File filename = new File(fileToExecute.getParent(), context.toString()); - - if (f.isOverwrite() || !filename.exists()) - createFile(filename, resolveFileContent(f), context); - } - } - - private void createFile(File filename, FileToCreate f, Context context) throws IOException, HGSEvalException, ParserException { - Parser p; - String content = f.getContent(); - if (f.isFilter()) { - context.clearOutput(); - p = new Parser(content); - p.parse().execute(context); - content = context.toString(); + private ExecuteAction(Command command) { + super(command.getName()); + this.command = command; } - try (OutputStream out = getIoInterface().getOutputStream(filename)) { - out.write(content.getBytes()); + @Override + public void actionPerformed(ActionEvent actionEvent) { + executeCommand(command, this); } } @@ -249,68 +232,100 @@ public final class Configuration { * * @param command the command */ - void executeCommand(Command command) { + Thread executeCommand(Command command, Action action) { File digFile = filenameProvider.getCurrentFilename(); if (digFile != null) { try { - - HDLModel hdlModel = null; + HDLModel hdlModel; if (command.needsHDL()) hdlModel = writeHDL(command.getHDL(), digFile); + else + hdlModel = null; - checkFilesToCreate(digFile, hdlModel); + if (action != null) + action.setEnabled(false); + Thread t = new Thread(() -> { + try { + checkFilesToCreate(digFile, hdlModel); - String[] args = command.getArgs(); - if (args != null) { - if (command.isFilter()) { - final int argCount = command.getArgs().length; - Context context = createContext(digFile, hdlModel); - for (int i = 0; i < argCount; i++) { - context.clearOutput(); - new Parser(args[i]).parse().execute(context); - args[i] = context.toString(); + String[] args = command.getArgs(); + if (args != null) { + if (command.isFilter()) { + final int argCount = command.getArgs().length; + Context context = createContext(digFile, hdlModel); + for (int i = 0; i < argCount; i++) { + context.clearOutput(); + new Parser(args[i]).parse().execute(context); + args[i] = context.toString(); + } + } + getIoInterface().startProcess(command, digFile.getParentFile(), args); } + } catch (Exception e) { + getIoInterface().showError(command, e); + } finally { + if (action != null) + SwingUtilities.invokeLater(() -> action.setEnabled(true)); } - getIoInterface().startProcess(command, digFile.getParentFile(), command.isGui(), args); - } + }); + t.setDaemon(true); + t.start(); + return t; } catch (Exception e) { getIoInterface().showError(command, e); } } + return null; } - private FileToCreate resolveFileContent(FileToCreate f) throws IOException { + private void checkFilesToCreate(File fileToExecute, HDLModel hdlModel) throws HGSEvalException, IOException, ParserException { + Context context = createContext(fileToExecute, hdlModel); + + if (files != null) { + ConfigCache configCache = new ConfigCache(origin); + for (FileToCreate f : files) { + context.clearOutput(); + Parser p = new Parser(f.getName()); + p.parse().execute(context); + File filename = new File(fileToExecute.getParent(), context.toString()); + + if (f.isOverwrite() || !filename.exists()) + createFile(filename, resolveFileContent(f, configCache), context); + } + } + } + + private void createFile(File filename, FileToCreate f, Context context) throws IOException, HGSEvalException, ParserException { + Parser p; + String content = f.getContent(); + if (f.isFilter()) { + context.clearOutput(); + p = new Parser(content); + p.parse().execute(context); + content = context.toString(); + } + + try (OutputStream out = getIoInterface().getOutputStream(filename)) { + out.write(content.getBytes()); + } + } + + + private FileToCreate resolveFileContent(FileToCreate f, ConfigCache configCache) throws IOException { if (f.hasContent()) return f; - if (origin == null) - throw new IOException("no origin file given"); - - Configuration c = Configuration.load(new File(origin.getParentFile(), f.getReferenceFilename())); - return c.getFileById(f.getReferenceId()); + Configuration c = configCache.getConfig(f.getReferenceFilename()); + return c.getFileById(f.getReferenceId(), configCache); } - private FileToCreate getFileById(String referenceId) throws IOException { + private FileToCreate getFileById(String referenceId, ConfigCache configCache) throws IOException { for (FileToCreate f : files) if (referenceId.equals(f.getId())) - return resolveFileContent(f); + return resolveFileContent(f, configCache); throw new IOException("no file with id " + referenceId + " given"); } - private final class ExecuteAction extends AbstractAction { - private final Command command; - - private ExecuteAction(Command command) { - super(command.getName()); - this.command = command; - } - - @Override - public void actionPerformed(ActionEvent actionEvent) { - executeCommand(command); - } - } - ArrayList getCommands() { return commands; } @@ -374,11 +389,10 @@ public final class Configuration { * * @param command the command started * @param dir the folder to start the process in - * @param gui true if app has a gui * @param args the arguments * @throws IOException IOException */ - void startProcess(Command command, File dir, boolean gui, String[] args) throws IOException; + void startProcess(Command command, File dir, String[] args) throws IOException; /** * Shows an error message @@ -402,29 +416,17 @@ public final class Configuration { } @Override - public void startProcess(Command command, File dir, boolean gui, String[] args) throws IOException { - OSExecute os = new OSExecute(args) + public void startProcess(Command command, File dir, String[] args) throws IOException { + String consoleOut = new OSExecute(args) .setTimeOutSec(command.getTimeout()) - .setWorkingDir(dir); - if (gui) - os.startInThread(new OSExecute.ProcessCallback() { - @Override - public void processTerminated(String consoleOut) { - LOGGER.info("process '" + command.getName() + "' says:\n" + consoleOut); - } - - @Override - public void exception(Exception e) { - showError(command, e); - } - }); - else - os.startAndWait(); + .setWorkingDir(dir) + .startAndWait(); + LOGGER.info("process '" + command.getName() + "' says:\n" + consoleOut); } @Override public void showError(Command command, Exception e) { - new ErrorMessage(Lang.get("msg_errorStartCommand_N", command.getName())).addCause(e).show(); + SwingUtilities.invokeLater(new ErrorMessage(Lang.get("msg_errorStartCommand_N", command.getName())).addCause(e)); } } diff --git a/src/test/java/de/neemann/digital/ide/ConfigurationTest.java b/src/test/java/de/neemann/digital/ide/ConfigurationTest.java index 344844aa7..28d2d7625 100644 --- a/src/test/java/de/neemann/digital/ide/ConfigurationTest.java +++ b/src/test/java/de/neemann/digital/ide/ConfigurationTest.java @@ -19,7 +19,7 @@ import java.util.HashMap; public class ConfigurationTest extends TestCase { - public void testStart() throws IOException, ElementNotFoundException, PinException, NodeException { + public void testStart() throws IOException, ElementNotFoundException, PinException, NodeException, InterruptedException { String xml = "\n" + " \n" + " \n" + @@ -44,7 +44,7 @@ public class ConfigurationTest extends TestCase { ArrayList commands = c.getCommands(); assertEquals(2, commands.size()); - c.executeCommand(commands.get(0)); + c.executeCommand(commands.get(0), null).join(); assertEquals(1, fileWriter.files.size()); assertTrue(fileWriter.files.containsKey("z/test.v")); @@ -54,7 +54,7 @@ public class ConfigurationTest extends TestCase { assertEquals("[make]", Arrays.toString(fileWriter.commands.get(0).args)); fileWriter.clear(); - c.executeCommand(commands.get(1)); + c.executeCommand(commands.get(1), null).join(); assertEquals(1, fileWriter.files.size()); assertTrue(fileWriter.files.containsKey("z/test.v")); @@ -64,7 +64,7 @@ public class ConfigurationTest extends TestCase { assertEquals("[make, z/test.v]", Arrays.toString(fileWriter.commands.get(0).args)); } - public void testFileWriter() throws IOException, ElementNotFoundException, PinException, NodeException { + public void testFileWriter() throws IOException, ElementNotFoundException, PinException, NodeException, InterruptedException { String xml = "\n" + " \n" + " \n" + @@ -96,7 +96,7 @@ public class ConfigurationTest extends TestCase { ArrayList commands = c.getCommands(); assertEquals(1, commands.size()); - c.executeCommand(commands.get(0)); + c.executeCommand(commands.get(0), null).join(); assertEquals(4, fileWriter.files.size()); assertEquals("deal with ", fileWriter.files.get("z/file1").toString()); @@ -117,7 +117,7 @@ public class ConfigurationTest extends TestCase { } @Override - public void startProcess(Command command, File dir, boolean gui, String[] args) { + public void startProcess(Command command, File dir, String[] args) { commands.add(new StartedCommand(dir, args)); } diff --git a/src/test/java/de/neemann/digital/ide/ReferenceTest.java b/src/test/java/de/neemann/digital/ide/ReferenceTest.java index 38b8bef99..ebbc04dcb 100644 --- a/src/test/java/de/neemann/digital/ide/ReferenceTest.java +++ b/src/test/java/de/neemann/digital/ide/ReferenceTest.java @@ -17,7 +17,7 @@ import java.io.IOException; public class ReferenceTest extends TestCase { - public void testRef() throws IOException, ElementNotFoundException, PinException, NodeException { + public void testRef() throws IOException, ElementNotFoundException, PinException, NodeException, InterruptedException { File f = new File(Resources.getRoot(),"ide/main.xml"); ToBreakRunner br = new ToBreakRunner(new File(Resources.getRoot(), "dig/hdl/negSimple.dig")); Configuration c = Configuration.load(f) @@ -26,7 +26,7 @@ public class ReferenceTest extends TestCase { .setCircuitProvider(br::getCircuit); final ConfigurationTest.TestIOInterface ioInterface = new ConfigurationTest.TestIOInterface(); c.setIoInterface(ioInterface); - c.executeCommand(c.getCommands().get(0)); + c.executeCommand(c.getCommands().get(0),null).join(); assertEquals("Test content", ioInterface.getFiles().get("z/test1.txt").toString()); assertEquals("deep content", ioInterface.getFiles().get("z/test2.txt").toString());