# HG changeset patch # User Omair Majid # Date 1379621888 14400 # Node ID 9f8cb76cec1da5841420346ba03d52f6296c3cef # Parent ae64ab3629cae8f5e0e1c5ba44dc75d99844c145 Add a user-specific plugins directory Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-September/008215.html diff -r ae64ab3629ca -r 9f8cb76cec1d config/src/main/java/com/redhat/thermostat/shared/config/Configuration.java --- a/config/src/main/java/com/redhat/thermostat/shared/config/Configuration.java Wed Sep 18 10:17:35 2013 +0200 +++ b/config/src/main/java/com/redhat/thermostat/shared/config/Configuration.java Thu Sep 19 16:18:08 2013 -0400 @@ -171,6 +171,10 @@ /* Specific files and directories. All these methods should use the directories defined above */ + public File getUserPluginRoot() throws InvalidConfigurationException { + return new File(getUserPersistentDataDirectory(), "plugins"); + } + public File getUserStorageDirectory() throws InvalidConfigurationException { return new File(getUserPersistentDataDirectory(), "db"); } diff -r ae64ab3629ca -r 9f8cb76cec1d config/src/test/java/com/redhat/thermostat/shared/config/ConfigurationTest.java --- a/config/src/test/java/com/redhat/thermostat/shared/config/ConfigurationTest.java Wed Sep 18 10:17:35 2013 +0200 +++ b/config/src/test/java/com/redhat/thermostat/shared/config/ConfigurationTest.java Thu Sep 19 16:18:08 2013 -0400 @@ -102,6 +102,9 @@ config.getUserStoragePidFile().getCanonicalPath()); Assert.assertEquals(userHome + s + "logs" + s + "db.log", config.getUserStorageLogFile().getCanonicalPath()); + + Assert.assertEquals(userHome + s + "data" + s + "plugins", + config.getUserPluginRoot().getCanonicalPath()); } @Test @@ -120,6 +123,8 @@ Assert.assertEquals("/var/lib/thermostat/db", config.getUserStorageDirectory().getCanonicalPath()); Assert.assertEquals("/var/run/thermostat/db.pid", config.getUserStoragePidFile().getAbsolutePath()); Assert.assertEquals("/var/log/thermostat/db.log", config.getUserStorageLogFile().getCanonicalPath()); + + Assert.assertEquals("/var/lib/thermostat/plugins", config.getUserPluginRoot().getCanonicalPath()); } @Test @@ -140,7 +145,10 @@ Assert.assertEquals(prefix + "/var/lib/thermostat/db", config.getUserStorageDirectory().getCanonicalPath()); Assert.assertEquals(prefix + "/var/run/thermostat/db.pid", config.getUserStoragePidFile().getAbsolutePath()); Assert.assertEquals(prefix + "/var/log/thermostat/db.log", config.getUserStorageLogFile().getCanonicalPath()); + + Assert.assertEquals(prefix + "/var/lib/thermostat/plugins", config.getUserPluginRoot().getCanonicalPath()); } + @Test public void instantiationThrowsException() { try { diff -r ae64ab3629ca -r 9f8cb76cec1d integration-tests/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java --- a/integration-tests/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java Wed Sep 18 10:17:35 2013 +0200 +++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/IntegrationTest.java Thu Sep 19 16:18:08 2013 -0400 @@ -93,7 +93,7 @@ return "../distribution/target/image"; } - public static String getPluginHome() { + public static String getSystemPluginHome() { return getThermostatHome() + "/plugins"; } diff -r ae64ab3629ca -r 9f8cb76cec1d integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java --- a/integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java Wed Sep 18 10:17:35 2013 +0200 +++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/PluginTest.java Thu Sep 19 16:18:08 2013 -0400 @@ -51,21 +51,27 @@ public class PluginTest extends IntegrationTest { - private static final String PLUGIN_HOME = getPluginHome(); + private static final String PLUGIN_HOME = getSystemPluginHome(); - private static NewCommandPlugin newPlugin = new NewCommandPlugin(PLUGIN_HOME + File.separator + "new"); + private static NewCommandPlugin fooPlugin = new NewCommandPlugin("foo", "provides foo command", PLUGIN_HOME + File.separator + "new"); + private static NewCommandPlugin userPlugin = new NewCommandPlugin( + "user", + "a plugin that is provided by the user", + getUserThermostatHome() + File.separator + "data" + File.separator + "plugins" + File.separator + "user"); private static UnknownExtendsPlugin unknownExtension = new UnknownExtendsPlugin(PLUGIN_HOME + File.separator + "unknown"); @BeforeClass public static void setUpOnce() { - newPlugin.install(); + fooPlugin.install(); + userPlugin.install(); unknownExtension.install(); } @AfterClass public static void tearDownOnce() { unknownExtension.uninstall(); - newPlugin.uninstall(); + userPlugin.uninstall(); + fooPlugin.uninstall(); } @Test @@ -82,8 +88,10 @@ assertTrue(stdOut.contains("ping")); assertTrue(stdOut.contains("shell")); - assertTrue(stdOut.contains(newPlugin.command)); - assertTrue(stdOut.contains(newPlugin.description)); + assertTrue(stdOut.contains(fooPlugin.command)); + assertTrue(stdOut.contains(fooPlugin.description)); + + assertTrue(stdOut.contains(userPlugin.command)); assertFalse(stdOut.contains(unknownExtension.command)); @@ -99,16 +107,16 @@ private final String command; private final String description; - public NewCommandPlugin(String pluginLocation) { + public NewCommandPlugin(String command, String description, String pluginLocation) { this.pluginHome = pluginLocation; - this.command = "foo"; - this.description = "foo plugin to foo bar"; + this.command = command; + this.description = description; } private void install() { File home = new File(pluginHome); - if (!home.isDirectory() && !home.mkdir()) { + if (!home.isDirectory() && !home.mkdirs()) { throw new AssertionError("could not create directory: " + pluginHome); } diff -r ae64ab3629ca -r 9f8cb76cec1d launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java --- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java Wed Sep 18 10:17:35 2013 +0200 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/Activator.java Thu Sep 19 16:18:08 2013 -0400 @@ -84,7 +84,8 @@ CommandInfoSource builtInCommandSource = new BuiltInCommandInfoSource(commandsDir, config.getSystemLibRoot().toString()); CommandInfoSource pluginCommandSource = new PluginCommandInfoSource( - config.getSystemLibRoot().toString(), config.getSystemPluginRoot().toString()); + config.getSystemLibRoot().toString(), config.getSystemPluginRoot().toString(), + config.getUserPluginRoot().toString()); CommandInfoSource commands = new CompoundCommandInfoSource(builtInCommandSource, pluginCommandSource); cmdInfoReg = context.registerService(CommandInfoSource.class, commands, null); diff -r ae64ab3629ca -r 9f8cb76cec1d launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java --- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java Wed Sep 18 10:17:35 2013 +0200 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java Thu Sep 19 16:18:08 2013 -0400 @@ -39,6 +39,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -77,20 +78,19 @@ private Map allNewCommands = new HashMap<>(); private Map> additionalBundlesForExistingCommands = new HashMap<>(); - public PluginCommandInfoSource(String internalJarRoot, String pluginRootDir) { - this(new File(internalJarRoot), new File(pluginRootDir), new PluginConfigurationParser(), new UsageStringBuilder()); + public PluginCommandInfoSource(String internalJarRoot, String systemPluginRootDir, String userPluginRootDir) { + this(new File(internalJarRoot), new File(systemPluginRootDir), new File(userPluginRootDir), new PluginConfigurationParser(), new UsageStringBuilder()); } - PluginCommandInfoSource(File internalJarRoot, File pluginRootDir, PluginConfigurationParser parser, UsageStringBuilder usageBuilder) { + PluginCommandInfoSource(File internalJarRoot, File systemPluginRootDir, File userPluginRootDir, PluginConfigurationParser parser, UsageStringBuilder usageBuilder) { this.usageBuilder = usageBuilder; - File[] pluginDirs = pluginRootDir.listFiles(); - if (pluginDirs == null) { - logger.log(Level.SEVERE, "plugin root dir " + pluginRootDir + " does not exist"); - return; - } + List pluginDirectories = new ArrayList<>(); - for (File pluginDir : pluginDirs) { + addPluginDirectory(pluginDirectories, systemPluginRootDir); + addPluginDirectory(pluginDirectories, userPluginRootDir); + + for (File pluginDir : pluginDirectories) { try { File configurationFile = new File(pluginDir, PLUGIN_CONFIG_FILE); PluginConfiguration pluginConfig = parser.parse(configurationFile); @@ -111,8 +111,14 @@ combineCommands(); } + private void addPluginDirectory(List allPluginDirectories, File aPluginRoot) { + File[] pluginDirs = aPluginRoot.listFiles(); + + if (pluginDirs != null) { + allPluginDirectories.addAll(Arrays.asList(pluginDirs)); + } + } - private void loadNewAndExtendedCommands(File coreJarRoot, File pluginDir, PluginConfiguration pluginConfig) { diff -r ae64ab3629ca -r 9f8cb76cec1d launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java --- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java Wed Sep 18 10:17:35 2013 +0200 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/ActivatorTest.java Thu Sep 19 16:18:08 2013 -0400 @@ -120,8 +120,8 @@ PluginCommandInfoSource source2 = mock(PluginCommandInfoSource.class); when(source2.getCommandInfos()).thenReturn(new ArrayList()); whenNew(PluginCommandInfoSource.class) - .withParameterTypes(String.class, String.class) - .withArguments(anyString(), anyString()) + .withParameterTypes(String.class, String.class, String.class) + .withArguments(anyString(), anyString(), anyString()) .thenReturn(source2); CompoundCommandInfoSource commands = mock(CompoundCommandInfoSource.class); diff -r ae64ab3629ca -r 9f8cb76cec1d launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java --- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java Wed Sep 18 10:17:35 2013 +0200 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java Thu Sep 19 16:18:08 2013 -0400 @@ -72,7 +72,8 @@ private Path testRoot; private Path jarRootDir; - private Path pluginRootDir; + private Path sysPluginRootDir; + private Path userPluginRootDir; private PluginConfigurationParser parser; private PluginConfiguration parserResult; private UsageStringBuilder usageBuilder; @@ -85,8 +86,10 @@ usageBuilder = mock(UsageStringBuilder.class); testRoot = Files.createTempDirectory("thermostat"); - pluginRootDir = testRoot.resolve("plugins"); - Files.createDirectory(pluginRootDir); + sysPluginRootDir = testRoot.resolve("plugins"); + Files.createDirectory(sysPluginRootDir); + userPluginRootDir = testRoot.resolve("plugins-user"); + Files.createDirectory(userPluginRootDir); jarRootDir = testRoot.resolve("libs"); Files.createDirectories(jarRootDir); } @@ -114,14 +117,14 @@ @Test public void verifyParserIsInvokedOnAllConfigurationFiles() throws IOException, PluginConfigurationValidatorException { Path[] pluginDirs = new Path[] { - pluginRootDir.resolve("plugin1"), - pluginRootDir.resolve("plugin2"), + sysPluginRootDir.resolve("plugin1"), + sysPluginRootDir.resolve("plugin2"), }; for (Path pluginDir : pluginDirs) { Files.createDirectory(pluginDir); } - new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); + new PluginCommandInfoSource(jarRootDir.toFile(), sysPluginRootDir.toFile(), userPluginRootDir.toFile(), parser, usageBuilder); ArgumentCaptor configFilesCaptor = ArgumentCaptor.forClass(File.class); verify(parser, times(pluginDirs.length)).parse(configFilesCaptor.capture()); @@ -137,12 +140,12 @@ public void verifyMissingConfigurationFileIsHandledCorrectly() throws FileNotFoundException, PluginConfigurationValidatorException { when(parser.parse(isA(File.class))).thenThrow(new FileNotFoundException("test")); - new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); + new PluginCommandInfoSource(jarRootDir.toFile(), sysPluginRootDir.toFile(), userPluginRootDir.toFile(), parser, usageBuilder); } @Test(expected = CommandInfoNotFoundException.class) public void verifyMissingCommandInfo() { - PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); + PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), sysPluginRootDir.toFile(), userPluginRootDir.toFile(), parser, usageBuilder); source.getCommandInfo("TEST"); } @@ -151,7 +154,7 @@ public void verifyCommandInfoObjectsToExtendExistingCommandsAreCreated() throws IOException { BundleInformation bundleInfo = new BundleInformation("plugin-bundle", "0.1"); - Path pluginDir = pluginRootDir.resolve("plugin1"); + Path pluginDir = sysPluginRootDir.resolve("plugin1"); Files.createDirectory(pluginDir); CommandExtensions extensions = mock(CommandExtensions.class); @@ -160,7 +163,7 @@ when(parserResult.getExtendedCommands()).thenReturn(Arrays.asList(extensions)); - PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); + PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), sysPluginRootDir.toFile(), userPluginRootDir.toFile(), parser, usageBuilder); CommandInfo info = source.getCommandInfo("command-name"); assertEquals("command-name", info.getName()); @@ -177,7 +180,7 @@ final Set ENVIRONMENTS = EnumSet.of(Environment.SHELL); BundleInformation bundleInfo = new BundleInformation("plugin-bundle", "0.1"); - Path pluginDir = pluginRootDir.resolve("plugin1"); + Path pluginDir = sysPluginRootDir.resolve("plugin1"); Files.createDirectory(pluginDir); NewCommand cmd = mock(NewCommand.class); @@ -190,7 +193,7 @@ when(parserResult.getNewCommands()).thenReturn(Arrays.asList(cmd)); - PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); + PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), sysPluginRootDir.toFile(), userPluginRootDir.toFile(), parser, usageBuilder); CommandInfo result = source.getCommandInfo(NAME);