|
21 | 21 | import java.nio.charset.StandardCharsets;
|
22 | 22 | import java.nio.file.Files;
|
23 | 23 | import java.util.List;
|
| 24 | +import java.util.Map; |
24 | 25 | import java.util.Objects;
|
25 | 26 | import java.util.regex.Pattern;
|
26 | 27 | import java.util.stream.Collectors;
|
27 | 28 | import java.util.stream.Stream;
|
28 | 29 |
|
29 | 30 | import javax.annotation.CheckForNull;
|
| 31 | +import javax.annotation.Nonnull; |
30 | 32 | import javax.annotation.Nullable;
|
31 | 33 |
|
32 | 34 | import org.slf4j.Logger;
|
|
40 | 42 |
|
41 | 43 | public final class IdeaStep {
|
42 | 44 |
|
| 45 | + public static final String NAME = "IDEA"; |
| 46 | + |
43 | 47 | private static final Logger LOGGER = LoggerFactory.getLogger(IdeaStep.class);
|
44 | 48 |
|
45 | 49 | private IdeaStep() {}
|
46 | 50 |
|
47 |
| - public static FormatterStep create() { |
48 |
| - return create(true); |
| 51 | + public static IdeaStepBuilder create() { |
| 52 | + return new IdeaStepBuilder(); |
49 | 53 | }
|
50 | 54 |
|
51 |
| - public static FormatterStep create(boolean withDefaults) { |
52 |
| - return create(withDefaults, null); |
| 55 | + private static FormatterStep create(@Nonnull IdeaStepBuilder builder) { |
| 56 | + Objects.requireNonNull(builder); |
| 57 | + return FormatterStep.createLazy(NAME, |
| 58 | + () -> createState(builder), |
| 59 | + state -> state); |
53 | 60 | }
|
54 | 61 |
|
55 |
| - public static FormatterStep create(boolean withDefaults, |
56 |
| - @Nullable String binaryPath) { |
57 |
| - return create(withDefaults, binaryPath, null); |
| 62 | + private static State createState(@Nonnull IdeaStepBuilder builder) { |
| 63 | + return new State(Objects.requireNonNull(builder)); |
58 | 64 | }
|
59 | 65 |
|
60 |
| - public static FormatterStep create(boolean withDefaults, |
61 |
| - @Nullable String binaryPath, @Nullable String codeStyleSettingsPath) { |
62 |
| - return FormatterStep.createLazy("IDEA", |
63 |
| - () -> createState(withDefaults, binaryPath, codeStyleSettingsPath), |
64 |
| - state -> state); |
65 |
| - } |
| 66 | + public static final class IdeaStepBuilder { |
| 67 | + private static final String DEFAULT_IDEA = "idea"; |
| 68 | + |
| 69 | + private boolean useDefaults = true; |
| 70 | + @Nonnull |
| 71 | + private String binaryPath = DEFAULT_IDEA; |
| 72 | + @Nullable |
| 73 | + private String codeStyleSettingsPath; |
| 74 | + |
| 75 | + public IdeaStepBuilder setUseDefaults(boolean useDefaults) { |
| 76 | + this.useDefaults = useDefaults; |
| 77 | + return this; |
| 78 | + } |
| 79 | + |
| 80 | + public IdeaStepBuilder setBinaryPath(@Nonnull String binaryPath) { |
| 81 | + this.binaryPath = Objects.requireNonNull(binaryPath); |
| 82 | + return this; |
| 83 | + } |
| 84 | + |
| 85 | + public IdeaStepBuilder setCodeStyleSettingsPath(@Nullable String codeStyleSettingsPath) { |
| 86 | + this.codeStyleSettingsPath = codeStyleSettingsPath; |
| 87 | + return this; |
| 88 | + } |
66 | 89 |
|
67 |
| - private static State createState(boolean withDefaults, |
68 |
| - @Nullable String binaryPath, @Nullable String codeStyleSettingsPath) { |
69 |
| - return new State(withDefaults, binaryPath, codeStyleSettingsPath); |
| 90 | + public FormatterStep build() { |
| 91 | + return create(this); |
| 92 | + } |
70 | 93 | }
|
71 | 94 |
|
72 | 95 | private static class State
|
73 | 96 | implements FormatterFunc.NeedsFile, Serializable {
|
74 | 97 |
|
75 | 98 | private static final long serialVersionUID = -1825662355363926318L;
|
76 |
| - private static final String DEFAULT_IDEA = "idea"; |
77 | 99 |
|
78 | 100 | private String binaryPath;
|
79 | 101 | @Nullable
|
80 | 102 | private String codeStyleSettingsPath;
|
81 | 103 | private boolean withDefaults;
|
82 | 104 |
|
83 |
| - private State(boolean withDefaults, @Nullable String binaryPath, |
84 |
| - @Nullable String codeStyleSettingsPath) { |
85 |
| - this.withDefaults = withDefaults; |
86 |
| - this.codeStyleSettingsPath = codeStyleSettingsPath; |
87 |
| - this.binaryPath = Objects.requireNonNullElse(binaryPath, DEFAULT_IDEA); |
| 105 | + private State(@Nonnull IdeaStepBuilder builder) { |
| 106 | + this.withDefaults = builder.useDefaults; |
| 107 | + this.codeStyleSettingsPath = builder.codeStyleSettingsPath; |
| 108 | + this.binaryPath = builder.binaryPath; |
88 | 109 | resolveFullBinaryPathAndCheckVersion();
|
89 | 110 | }
|
90 | 111 |
|
@@ -113,10 +134,38 @@ private String pathToExe() {
|
113 | 134 | if (binaryPath == null) {
|
114 | 135 | throw new IllegalStateException("binaryPath is not set");
|
115 | 136 | }
|
116 |
| - if (new File(binaryPath).exists()) { |
117 |
| - return binaryPath; |
| 137 | + return macOsFix(binaryPath); |
| 138 | + } |
| 139 | + |
| 140 | + @CheckForNull |
| 141 | + private static String macOsFix(String binaryPath) { |
| 142 | + if (!isMacOs()) { |
| 143 | + if (new File(binaryPath).exists()) { |
| 144 | + return binaryPath; |
| 145 | + } |
| 146 | + return null; // search in PATH |
| 147 | + } |
| 148 | + // on macOS, the binary is located in the .app bundle which might be invisible to the user |
| 149 | + // we try need to append the path to the binary |
| 150 | + File binary = new File(binaryPath); |
| 151 | + if (!binary.exists()) { |
| 152 | + // maybe it is bundle path without .app? (might be hidden by os) |
| 153 | + binary = new File(binaryPath + ".app"); |
| 154 | + if (!binary.exists()) { |
| 155 | + return binaryPath; // fallback: do nothing |
| 156 | + } |
| 157 | + } |
| 158 | + if (binaryPath.endsWith(".app") || binary.isDirectory()) { |
| 159 | + binary = new File(binary, "Contents/MacOS/idea"); |
118 | 160 | }
|
119 |
| - return null; // search in PATH |
| 161 | + if (binary.isFile() && binary.canExecute()) { |
| 162 | + return binary.getPath(); |
| 163 | + } |
| 164 | + return binaryPath; // fallback: do nothing |
| 165 | + } |
| 166 | + |
| 167 | + private static boolean isMacOs() { |
| 168 | + return System.getProperty("os.name").toLowerCase().contains("mac"); |
120 | 169 | }
|
121 | 170 |
|
122 | 171 | @Override
|
|
0 commit comments