Skip to content

Commit bc335d7

Browse files
committed
Experimental integration for external system run configurations
Fixes #38
1 parent d28e5be commit bc335d7

File tree

8 files changed

+109
-7
lines changed

8 files changed

+109
-7
lines changed

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning].
44

5+
## Unreleased
6+
7+
### Added
8+
9+
- Experimental integration for external system run configurations (such as Gradle) ([#38])
10+
511
## 3.1.2 - 2019-05-21
612

713
### Fixed
@@ -40,7 +46,7 @@ This project adheres to [Semantic Versioning].
4046

4147
### Fixed
4248

43-
- Unicode sequence handling in `.env` files [(#38)]
49+
- Unicode sequence handling in `.env` files [(#32)]
4450
- Backslash being removed from values in `.env` files ([#52])
4551
- White text on white background when `Light` theme is used ([#61])
4652

@@ -97,6 +103,7 @@ This project adheres to [Semantic Versioning].
97103
- Initial Release
98104

99105
[#16]: https://github.com/Ashald/EnvFile/issues/16
106+
[#38]: https://github.com/Ashald/EnvFile/issues/32
100107
[#38]: https://github.com/Ashald/EnvFile/issues/38
101108
[#52]: https://github.com/Ashald/EnvFile/issues/52
102109
[#61]: https://github.com/Ashald/EnvFile/issues/61

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ version of the product.
6060
<li><em>Arquillian TestNG</em></li>
6161
<li><em>CloudBees Server</em></li>
6262
<li><em>Cucumber Java</em></li>
63+
<li>Gradle (requires "Enable Experimental Integrations")</li>
6364
<li><em>GWT Configuration</em></li>
6465
<li>
6566
<em>Geronimo Server</em>
@@ -202,19 +203,31 @@ Restart IDE.
202203
1) Switch to <kbd>EnvFile</kbd> tab
203204
2) Select <kbd>Enable EnvFile</kbd> checkbox
204205
3) Select <kbd>Substitute Environment Variables</kbd> checkbox (if needed)
205-
4) Click on <kbd>+</kbd> to add a file
206-
5) Adjust order as needed
206+
4) Select <kbd>Process JetBrains path macro references</kbd> checkbox (if needed)
207+
5) Select <kbd>Ignore missing files</kbd> checkbox (if needed)
208+
6) Select <kbd>Enable experimental integrations</kbd> checkbox (if needed)
209+
7) Click on <kbd>+</kbd> to add a file
210+
8) Adjust order as needed
207211
6) Even variables defined within run configuration can be processed, ordered and substituted
208212

209213
![Read from file](./docs/example.png)
210214

211215
### Caveats
212216

217+
#### Hidden files
213218
Hidden files (starting with a dot) are not displayed in Finder on `macOS` by default. To toggle
214219
hidden files in the Open dialog, press <kbd>COMMAND</kbd> + <kbd>SHIFT</kbd> + <kbd>.</kbd>.
215220
Alternatively, one can either tweak `macOS` to show hidden files or select any file using
216221
standard Finder dialog and then manually edit path by double-clicking on the entry in the table.
217222

223+
#### Experimental Integrations
224+
Not all run configurations available in IDEA-based IDEs are implemented similarly. Some of them differ significantly.
225+
In certain cases (so far, only `Gradle` has been confirmed) the implementation exposes interfaces to integrate the EnvFile UI
226+
but doesn't provide interfaces for it to actually make its work. Luckily, it was possible to make few assumptions about
227+
IDEA's internal implementation and make it work. Such integration is very fragile and it's not immediately clear if it
228+
will affect any existing integrations and when it will break. For that reason there is a special option to
229+
`Enable Experimental Integrations` that can be enabled when desired and should prevent other integrations from breaking.
230+
218231
### Examples
219232

220233
#### .env

docs/example.png

4.03 KB
Loading
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package net.ashald.envfile.utils;
2+
3+
import java.util.*;
4+
5+
public class ReadOnceMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {
6+
7+
private Map<K, V> firstRead;
8+
private Map<K, V> otherReads;
9+
10+
private boolean wasRead = false;
11+
12+
public ReadOnceMap(Map<K, V> first, Map<K, V> rest) {
13+
firstRead = first;
14+
otherReads = rest;
15+
}
16+
17+
@Override
18+
public int size() {
19+
return getSource(false).size();
20+
}
21+
22+
@Override
23+
public Set<Entry<K, V>> entrySet() {
24+
return getSource(true).entrySet();
25+
}
26+
27+
private Map<K, V> getSource(boolean consume) {
28+
Map<K ,V> source;
29+
synchronized (this) {
30+
if (wasRead) {
31+
source = otherReads;
32+
} else {
33+
if (consume) {
34+
wasRead = true;
35+
}
36+
source = firstRead;
37+
}
38+
}
39+
return source == null ? Collections.emptyMap() : source;
40+
}
41+
}

modules/platform/src/main/java/net/ashald/envfile/platform/EnvFileSettings.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,23 @@ public class EnvFileSettings {
99
private final boolean envVarsSubstitutionEnabled;
1010
private final boolean pathMacroSupported;
1111
private final boolean ignoreMissing;
12+
private final boolean enableExperimentalIntegrations;
1213
private final List<EnvFileEntry> entries;
1314

14-
public EnvFileSettings(boolean isEnabled, boolean substituteVars, boolean pathMacroSupported, List<EnvFileEntry> envFileEntries, boolean ignoreMissing) {
15+
public EnvFileSettings(
16+
boolean isEnabled,
17+
boolean substituteVars,
18+
boolean pathMacroSupported,
19+
List<EnvFileEntry> envFileEntries,
20+
boolean ignoreMissing,
21+
boolean experimentalInegrations
22+
) {
1523
pluginEnabled = isEnabled;
1624
envVarsSubstitutionEnabled = substituteVars;
1725
this.pathMacroSupported = pathMacroSupported;
1826
this.ignoreMissing = ignoreMissing;
1927
entries = envFileEntries;
28+
enableExperimentalIntegrations = experimentalInegrations;
2029
}
2130

2231
public boolean isEnabled() {
@@ -35,6 +44,10 @@ public boolean isIgnoreMissing() {
3544
return ignoreMissing;
3645
}
3746

47+
public boolean isEnableExperimentalIntegrations() {
48+
return enableExperimentalIntegrations;
49+
}
50+
3851
public List<EnvFileEntry> getEntries() {
3952
return Collections.unmodifiableList(entries);
4053
}

modules/platform/src/main/java/net/ashald/envfile/platform/ui/EnvFileConfigurationEditor.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class EnvFileConfigurationEditor<T extends RunConfigurationBase> extends
3535
@NonNls private static final String FIELD_SUBSTITUTE_VARS = "IS_SUBST";
3636
@NonNls private static final String FIELD_PATH_MACRO_VARS = "IS_PATH_MACRO_SUPPORTED";
3737
@NonNls private static final String FIELD_IGNORE_MISSING = "IS_IGNORE_MISSING_FILES";
38+
@NonNls private static final String FIELD_EXPERIMENTAL_INTEGRATIONS = "IS_ENABLE_EXPERIMENTAL_INTEGRATIONS";
3839
@NonNls private static final String FIELD_PATH = "PATH";
3940
@NonNls private static final String FIELD_PARSER = "PARSER";
4041

@@ -80,6 +81,9 @@ public static void readExternal(@NotNull RunConfigurationBase configuration, @No
8081
String ignoreMissingStr = JDOMExternalizerUtil.readField(element, FIELD_IGNORE_MISSING, "false");
8182
boolean ignoreMissing = Boolean.parseBoolean(ignoreMissingStr);
8283

84+
String experimentalIntegrationsStr = JDOMExternalizerUtil.readField(element, FIELD_EXPERIMENTAL_INTEGRATIONS, "false");
85+
boolean experimentalIntegrations = Boolean.parseBoolean(experimentalIntegrationsStr);
86+
8387
List<EnvFileEntry> entries = new ArrayList<EnvFileEntry>();
8488

8589
final Element entriesElement = element.getChild(ELEMENT_ENTRY_LIST);
@@ -110,7 +114,7 @@ public static void readExternal(@NotNull RunConfigurationBase configuration, @No
110114
}
111115
// For a while to migrate old users - end
112116

113-
EnvFileSettings state = new EnvFileSettings(isEnabled, envVarsSubstEnabled, pathMacroSupported, entries, ignoreMissing);
117+
EnvFileSettings state = new EnvFileSettings(isEnabled, envVarsSubstEnabled, pathMacroSupported, entries, ignoreMissing, experimentalIntegrations);
114118
configuration.putUserData(USER_DATA_KEY, state);
115119
}
116120

@@ -121,6 +125,7 @@ public static void writeExternal(@NotNull RunConfigurationBase configuration, @N
121125
JDOMExternalizerUtil.writeField(element, FIELD_SUBSTITUTE_VARS, Boolean.toString(state.isSubstituteEnvVarsEnabled()));
122126
JDOMExternalizerUtil.writeField(element, FIELD_PATH_MACRO_VARS, Boolean.toString(state.isPathMacroSupported()));
123127
JDOMExternalizerUtil.writeField(element, FIELD_IGNORE_MISSING, Boolean.toString(state.isIgnoreMissing()));
128+
JDOMExternalizerUtil.writeField(element, FIELD_EXPERIMENTAL_INTEGRATIONS, Boolean.toString(state.isEnableExperimentalIntegrations()));
124129

125130
final Element entriesElement = new Element(ELEMENT_ENTRY_LIST);
126131
for (EnvFileEntry entry : state.getEntries()) {
@@ -176,6 +181,11 @@ public static void validateConfiguration(@NotNull RunConfigurationBase configura
176181
}
177182
}
178183

184+
public static boolean isEnableExperimentalIntegrations(@NotNull RunConfigurationBase configuration) {
185+
EnvFileSettings state = configuration.getUserData(USER_DATA_KEY);
186+
return state != null && state.isEnableExperimentalIntegrations();
187+
}
188+
179189
@NotNull
180190
@Contract(pure = true)
181191
public static String getSerializationId() {

modules/platform/src/main/java/net/ashald/envfile/platform/ui/EnvFileConfigurationPanel.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class EnvFileConfigurationPanel<T extends RunConfigurationBase> extends JPanel {
4444
private final JCheckBox substituteEnvVarsCheckBox;
4545
private final JCheckBox supportPathMacroCheckBox;
4646
private final JCheckBox ignoreMissingCheckBox;
47+
private final JCheckBox experimentalIntegrationsCheckBox;
4748
private final ListTableModel<EnvFileEntry> envFilesModel;
4849
private final TableView<EnvFileEntry> envFilesTable;
4950

@@ -86,6 +87,7 @@ public void actionPerformed(ActionEvent e) {
8687
substituteEnvVarsCheckBox.addActionListener(e -> envFilesModel.getItems().forEach(envFileEntry -> envFileEntry.setSubstitutionEnabled(substituteEnvVarsCheckBox.isSelected())));
8788
supportPathMacroCheckBox = new JCheckBox("Process JetBrains path macro references ($PROJECT_DIR$)");
8889
ignoreMissingCheckBox = new JCheckBox("Ignore missing files");
90+
experimentalIntegrationsCheckBox = new JCheckBox("Enable experimental integrations (e.g. Gradle) - may break any time!");
8991

9092
// TODO: come up with a generic approach for this
9193
envFilesModel.addRow(new EnvFileEntry(runConfig, "runconfig", null, true, substituteEnvVarsCheckBox.isSelected()));
@@ -131,6 +133,7 @@ public boolean isEnabled(AnActionEvent e) {
131133
optionsPanel.add(substituteEnvVarsCheckBox);
132134
optionsPanel.add(supportPathMacroCheckBox);
133135
optionsPanel.add(ignoreMissingCheckBox);
136+
optionsPanel.add(experimentalIntegrationsCheckBox);
134137

135138
// Compose UI
136139
JPanel checkboxPanel = new JPanel();
@@ -250,7 +253,8 @@ EnvFileSettings getState() {
250253
substituteEnvVarsCheckBox.isSelected(),
251254
supportPathMacroCheckBox.isSelected(),
252255
envFilesModel.getItems(),
253-
ignoreMissingCheckBox.isSelected()
256+
ignoreMissingCheckBox.isSelected(),
257+
experimentalIntegrationsCheckBox.isSelected()
254258
);
255259
}
256260

@@ -259,11 +263,13 @@ void setState(EnvFileSettings state) {
259263
substituteEnvVarsCheckBox.setSelected(state.isSubstituteEnvVarsEnabled());
260264
supportPathMacroCheckBox.setSelected(state.isPathMacroSupported());
261265
ignoreMissingCheckBox.setSelected(state.isIgnoreMissing());
266+
experimentalIntegrationsCheckBox.setSelected(state.isEnableExperimentalIntegrations());
262267

263268
envFilesTable.setEnabled(state.isEnabled());
264269
substituteEnvVarsCheckBox.setEnabled(state.isEnabled());
265270
supportPathMacroCheckBox.setEnabled(state.isEnabled());
266271
ignoreMissingCheckBox.setEnabled(state.isEnabled());
272+
experimentalIntegrationsCheckBox.setEnabled(state.isEnabled());
267273

268274
envFilesModel.setItems(new ArrayList<>(state.getEntries()));
269275
}

modules/products/idea/src/main/java/net/ashald/envfile/products/idea/IdeaRunConfigurationExtension.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
import com.intellij.execution.configurations.JavaParameters;
77
import com.intellij.execution.configurations.RunConfigurationBase;
88
import com.intellij.execution.configurations.RunnerSettings;
9+
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration;
910
import com.intellij.openapi.options.SettingsEditor;
10-
import com.intellij.openapi.projectRoots.JdkUtil;
1111
import com.intellij.openapi.util.InvalidDataException;
1212
import com.intellij.openapi.util.WriteExternalException;
1313
import net.ashald.envfile.platform.ui.EnvFileConfigurationEditor;
14+
import net.ashald.envfile.utils.ReadOnceMap;
1415
import org.jdom.Element;
1516
import org.jetbrains.annotations.NotNull;
1617
import org.jetbrains.annotations.Nullable;
@@ -72,6 +73,17 @@ public <T extends RunConfigurationBase> void updateJavaParameters(T configuratio
7273
// there is a chance that env is an immutable map,
7374
// that is why it is safer to replace it instead of updating it
7475
params.setEnv(newEnv);
76+
77+
// The code below works based on assumptions about internal implementation of
78+
// ExternalSystemExecuteTaskTask and ExternalSystemExecutionSettings and therefore may break any time may it change
79+
// It seems to be the only way to get things working for run configurations such as Gradle, at least for now
80+
if (EnvFileConfigurationEditor.isEnableExperimentalIntegrations(configuration)) {
81+
if (configuration instanceof ExternalSystemRunConfiguration) {
82+
ExternalSystemRunConfiguration ext = (ExternalSystemRunConfiguration) configuration;
83+
84+
ext.getSettings().setEnv(new ReadOnceMap<>(newEnv, ext.getSettings().getEnv()));
85+
}
86+
}
7587
}
7688

7789
//

0 commit comments

Comments
 (0)