Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jrubyscripting] Check if gems are installed before installing them #13151

Merged
merged 2 commits into from
Aug 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bundles/org.openhab.automation.jrubyscripting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Alternatively, JRuby configuration parameters may be set by creating a `jruby.cf
| org.openhab.automation.jrubyscripting:local_variables | transient | Defines how variables are shared between Ruby and Java. See [this](https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options) for options and details |
| org.openhab.automation.jrubyscripting:gems | | A comma separated list of [Ruby Gems](https://rubygems.org/) to install. |
| org.openhab.automation.jrubyscripting:require | | A comma separated list of script names to be required by the JRuby Scripting Engine at the beginning of user scripts. |
| org.openhab.automation.jrubyscripting:check_update | true | Check RubyGems for updates to the above gems when OpenHAB starts or JRuby settings are changed. Otherwise it will try to fulfil the requirements with locally installed gems, and you can manage them yourself with an external Ruby by setting the same GEM_HOME. |

## Ruby Gems

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class JRubyScriptEngineConfiguration {
private static final String RUBYLIB = "rubylib";
private static final String GEMS = "gems";
private static final String REQUIRE = "require";
private static final String CHECK_UPDATE = "check_update";

// Map of configuration parameters
private static final Map<String, OptionalConfigurationElement> CONFIGURATION_PARAMETERS = Map.ofEntries(
Expand All @@ -74,7 +75,10 @@ public class JRubyScriptEngineConfiguration {
Map.entry(GEMS, new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.GEM).build()),

Map.entry(REQUIRE,
new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.REQUIRE).build()));
new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.REQUIRE).build()),

Map.entry(CHECK_UPDATE,
new OptionalConfigurationElement.Builder(OptionalConfigurationElement.Type.CHECK_UPDATE).build()));

private static final Map<OptionalConfigurationElement.Type, List<OptionalConfigurationElement>> CONFIGURATION_TYPE_MAP = CONFIGURATION_PARAMETERS
.values().stream().collect(Collectors.groupingBy(v -> v.type));
Expand Down Expand Up @@ -153,12 +157,19 @@ private synchronized void configureGems(ScriptEngine engine) {
if (gemsConfigElement == null || !gemsConfigElement.getValue().isPresent()) {
return;
}
boolean checkUpdate = true;
OptionalConfigurationElement updateConfigElement = CONFIGURATION_PARAMETERS.get(CHECK_UPDATE);
if (updateConfigElement != null && updateConfigElement.getValue().isPresent()) {
checkUpdate = updateConfigElement.getValue().get().equals("true");
}

String[] gems = gemsConfigElement.getValue().get().split(",");
String gemCommand = "require 'bundler/inline'\nrequire 'openssl'\n\ngemfile(" + checkUpdate + ") do\n"
+ " source 'https://rubygems.org/'\n";
int validGems = 0;
for (String gem : gems) {
gem = gem.trim();
String version = "";
String gemCommand;
if (gem.contains("=")) {
String[] gemParts = gem.split("=");
gem = gemParts[0].trim();
Expand All @@ -167,23 +178,29 @@ private synchronized void configureGems(ScriptEngine engine) {

if (gem.isEmpty()) {
continue;
} else if (version.isEmpty()) {
gemCommand = "Gem.install('" + gem + "')\n";
} else {
gemCommand = "Gem.install('" + gem + "', '" + version + "')\n";
}

try {
logger.debug("Installing Gem: {}", gem);
logger.trace("Gem install code:\n{}\n", gemCommand);
engine.eval(gemCommand);
} catch (ScriptException e) {
logger.warn("Error installing Gem: {}", e.getMessage());
} catch (BootstrapMethodError e) {
logger.warn("Error while checking/installing gems: {}. You may need to restart OpenHAB",
e.getMessage());
logger.debug("Error in configureGems", e);
gemCommand += " gem '" + gem + "'";
if (!version.isEmpty()) {
gemCommand += ", '" + version + "'";
}
gemCommand += ", require: false\n";
validGems += 1;
}
if (validGems == 0) {
return;
}
gemCommand += "end\n";

try {
logger.debug("Installing Gems");
logger.trace("Gem install code:\n{}", gemCommand);
engine.eval(gemCommand);
} catch (ScriptException e) {
logger.warn("Error installing Gems: {}", e.getMessage());
} catch (BootstrapMethodError e) {
logger.warn("Error while checking/installing gems: {}. You may need to restart OpenHAB", e.getMessage());
logger.debug("Error in configureGems", e);
}
}

Expand Down Expand Up @@ -310,7 +327,8 @@ private enum Type {
SYSTEM_PROPERTY,
RUBY_ENVIRONMENT,
GEM,
REQUIRE
REQUIRE,
CHECK_UPDATE,
}

private static class Builder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,21 @@

<parameter name="gems" type="text" required="false" groupName="gems">
<label>Ruby Gems</label>
<description>A comma separated list of Ruby Gems to install.</description>
<description><![CDATA[A comma separated list of Ruby Gems to install. Versions may be constrained by separating with an
<tt>=</tt> and then the standard RubyGems version constraint, such as "<tt>openhab-scripting=~>4.0</tt>".
]]></description>
</parameter>

<parameter name="check_update" type="boolean" required="true" groupName="gems">
<label>Check for Gem Updates</label>
<description>Check RubyGems for updates to the above gems when OpenHAB starts or JRuby settings are changed.
Otherwise it will try to fulfill the requirements with locally installed gems, and you can manage them yourself with
an external Ruby by setting the same GEM_HOME.</description>
<options>
<option value="true">Check For Updates</option>
<option value="false">Do Not Check For Updates</option>
</options>
<default>true</default>
ccutrer marked this conversation as resolved.
Show resolved Hide resolved
</parameter>

<parameter name="require" type="text" required="false" groupName="gems">
Expand All @@ -34,20 +48,22 @@

<parameter name="gem_home" type="text" required="false" groupName="environment">
<label>GEM_HOME</label>
<description>Location Ruby Gems will be installed and loaded, directory will be created if missing and gem installs
are specified. Defaults to "OPENHAB_CONF/scripts/lib/ruby/gem_home" when not specified.</description>
<description><![CDATA[Location Ruby Gems will be installed and loaded, directory will be created if missing and gem
installs are specified. Defaults to "<tt>OPENHAB_CONF/scripts/lib/ruby/gem_home</tt>" when not specified.
]]></description>
</parameter>

<parameter name="rubylib" type="text" required="false" groupName="environment">
<label>RUBYLIB</label>
<description>Search path for user libraries. Separate each path with a colon (semicolon in Windows). Defaults to
"OPENHAB_CONF/automation/lib/ruby" when not specified.</description>
<description><![CDATA[Search path for user libraries. Separate each path with a colon (semicolon in Windows). Defaults to
"<tt>OPENHAB_CONF/automation/lib/ruby</tt>" when not specified.]]></description>
</parameter>

<parameter name="local_context" type="text" required="false" groupName="system">
<label>Context Instance Type</label>
<description>The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See
https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type for options and details.</description>
<description><![CDATA[The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See
<a href="https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type">the documentation</a> for options and details.
]]></description>
<default>singlethread</default>
<options>
<option value="singleton">Singleton</option>
Expand All @@ -60,8 +76,9 @@

<parameter name="local_variable" type="text" required="false" groupName="system">
<label>Local Variable Behavior</label>
<description>Defines how variables are shared between Ruby and Java. See
https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options for options and details.</description>
<description><![CDATA[Defines how variables are shared between Ruby and Java. See
<a href="https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options">the documentation</a> for options and details.
]]></description>
<default>transient</default>
<options>
<option value="transient">Transient</option>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
automation.config.jruby.check_update.label = Check for Gem Updates
automation.config.jruby.check_update.description = Check RubyGems for updates to the above gems when OpenHAB starts or JRuby settings are changed. Otherwise it will try to fulfill the requirements with locally installed gems, and you can manage them yourself with an external Ruby by setting the same GEM_HOME.
automation.config.jruby.check_update.option.true = Check For Updates
automation.config.jruby.check_update.option.false = Do Not Check For Updates
automation.config.jruby.gem_home.label = GEM_HOME
automation.config.jruby.gem_home.description = Location Ruby Gems will be installed and loaded, directory will be created if missing and gem installs are specified. Defaults to "OPENHAB_CONF/scripts/lib/ruby/gem_home" when not specified.
automation.config.jruby.gem_home.description = Location Ruby Gems will be installed and loaded, directory will be created if missing and gem installs are specified. Defaults to "<tt>OPENHAB_CONF/scripts/lib/ruby/gem_home</tt>" when not specified.
automation.config.jruby.gems.label = Ruby Gems
automation.config.jruby.gems.description = A comma separated list of Ruby Gems to install.
automation.config.jruby.gems.description = A comma separated list of Ruby Gems to install. Versions may be constrained by separating with an <tt>=</tt> and then the standard RubyGems version constraint, such as "<tt>openhab-scripting=~>4.0</tt>".
automation.config.jruby.group.environment.label = Ruby Environment
automation.config.jruby.group.environment.description = This group defines Ruby's environment.
automation.config.jruby.group.gems.label = Ruby Gems
automation.config.jruby.group.gems.description = This group defines the list of Ruby Gems to install.
automation.config.jruby.group.system.label = System Properties
automation.config.jruby.group.system.description = This group defines JRuby system properties.
automation.config.jruby.local_context.label = Context Instance Type
automation.config.jruby.local_context.description = The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type for options and details.
automation.config.jruby.local_context.description = The local context holds Ruby runtime, name-value pairs for sharing variables between Java and Ruby. See <a href="https://github.com/jruby/jruby/wiki/RedBridge#Context_Instance_Type">the documentation</a> for options and details.
automation.config.jruby.local_context.option.singleton = Singleton
automation.config.jruby.local_context.option.threadsafe = ThreadSafe
automation.config.jruby.local_context.option.singlethread = SingleThread
automation.config.jruby.local_context.option.concurrent = Concurrent
automation.config.jruby.local_variable.label = Local Variable Behavior
automation.config.jruby.local_variable.description = Defines how variables are shared between Ruby and Java. See https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options for options and details.
automation.config.jruby.local_variable.description = Defines how variables are shared between Ruby and Java. See <a href="https://github.com/jruby/jruby/wiki/RedBridge#local-variable-behavior-options">the documentation</a> for options and details.
automation.config.jruby.local_variable.option.transient = Transient
automation.config.jruby.local_variable.option.persistent = Persistent
automation.config.jruby.local_variable.option.global = Global
automation.config.jruby.require.label = Require Scripts
automation.config.jruby.require.description = A comma separated list of script names to be required by the JRuby Scripting Engine before running user scripts.
automation.config.jruby.rubylib.label = RUBYLIB
automation.config.jruby.rubylib.description = Search path for user libraries. Separate each path with a colon (semicolon in Windows). Defaults to "OPENHAB_CONF/automation/lib/ruby" when not specified.
automation.config.jruby.rubylib.description = Search path for user libraries. Separate each path with a colon (semicolon in Windows). Defaults to "<tt>OPENHAB_CONF/automation/lib/ruby</tt>" when not specified.

# service

Expand Down