• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 14171621716

31 Mar 2025 12:32PM UTC coverage: 67.422% (-0.2%) from 67.602%
14171621716

push

github

web-flow
#1171: improve ProcessContext with convenience run methods (#1193)

3042 of 4942 branches covered (61.55%)

Branch coverage included in aggregate %.

7844 of 11204 relevant lines covered (70.01%)

3.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

14.29
cli/src/main/java/com/devonfw/tools/ide/process/ProcessContext.java
1
package com.devonfw.tools.ide.process;
2

3
import com.devonfw.tools.ide.log.IdeSubLogger;
4

5
import java.nio.file.Path;
6
import java.util.List;
7
import java.util.Objects;
8

9
/**
10
 * Wrapper for {@link ProcessBuilder} to simplify its usage and avoid common mistakes and pitfalls.
11
 */
12
public interface ProcessContext extends EnvironmentContext {
13

14
  /**
15
   * @param handling the desired {@link ProcessErrorHandling}.
16
   * @return this {@link ProcessContext} for fluent API calls.
17
   */
18
  ProcessContext errorHandling(ProcessErrorHandling handling);
19

20
  /**
21
   * @param directory the {@link Path} to the working directory from where to execute the command.
22
   * @return this {@link ProcessContext} for fluent API calls.
23
   */
24
  ProcessContext directory(Path directory);
25

26
  /**
27
   * Sets the executable command to be {@link #run()}.
28
   *
29
   * @param executable the {@link Path} to the command to be executed by {@link #run()}. Depending on your operating system and the extension of the executable
30
   * or OS specific conventions. So e.g. a *.cmd or *.bat file will be called via CMD shell on windows while a *.sh file will be called via Bash, etc.
31
   * @return this {@link ProcessContext} for fluent API calls.
32
   */
33
  ProcessContext executable(Path executable);
34

35
  /**
36
   * Sets the executable command to be {@link #run()}.
37
   *
38
   * @param executable the command to be executed by {@link #run()}.
39
   * @return this {@link ProcessContext} for fluent API calls.
40
   * @see #executable(Path)
41
   */
42
  default ProcessContext executable(String executable) {
43

44
    return executable(Path.of(executable));
7✔
45
  }
46

47
  /**
48
   * Adds a single argument for {@link #executable(Path) command}.
49
   *
50
   * @param arg the next argument for {@link #executable(Path) command} to be added.
51
   * @return this {@link ProcessContext} for fluent API calls.
52
   */
53
  ProcessContext addArg(String arg);
54

55
  /**
56
   * Adds a single argument for {@link #executable(Path) command}.
57
   *
58
   * @param arg the next argument for {@link #executable(Path) command} to be added.
59
   * @return this {@link ProcessContext} for fluent API calls.
60
   */
61
  default ProcessContext addArg(Object arg) {
62

63
    Objects.requireNonNull(arg);
3✔
64
    return addArg(arg.toString());
5✔
65
  }
66

67
  /**
68
   * Adds the given arguments for {@link #executable(Path) command}. E.g. for {@link #executable(Path) command} "mvn" the arguments "clean" and "install" may be
69
   * added here to run "mvn clean install". If this method would be called again with "-Pmyprofile" and "-X" before {@link #run()} gets called then "mvn clean
70
   * install -Pmyprofile -X" would be run.
71
   *
72
   * @param args the arguments for {@link #executable(Path) command} to be added.
73
   * @return this {@link ProcessContext} for fluent API calls.
74
   */
75
  default ProcessContext addArgs(String... args) {
76

77
    for (String arg : args) {
16✔
78
      addArg(arg);
4✔
79
    }
80
    return this;
2✔
81
  }
82

83
  /**
84
   * Adds the given arguments for {@link #executable(Path) command} as arbitrary Java objects. It will add the {@link Object#toString() string representation}
85
   * of these arguments to the command.
86
   *
87
   * @param args the arguments for {@link #executable(Path) command} to be added.
88
   * @return this {@link ProcessContext} for fluent API calls.
89
   */
90
  default ProcessContext addArgs(Object... args) {
91

92
    for (Object arg : args) {
×
93
      addArg(arg);
×
94
    }
95
    return this;
×
96
  }
97

98
  /**
99
   * Adds the given arguments for {@link #executable(Path) command} as arbitrary Java objects. It will add the {@link Object#toString() string representation}
100
   * of these arguments to the command.
101
   *
102
   * @param args the {@link List} of arguments for {@link #executable(Path) command} to be added.
103
   * @return this {@link ProcessContext} for fluent API calls.
104
   */
105
  default ProcessContext addArgs(List<?> args) {
106

107
    for (Object arg : args) {
×
108
      addArg(arg);
×
109
    }
×
110
    return this;
×
111
  }
112

113
  @Override
114
  ProcessContext withEnvVar(String key, String value);
115

116
  @Override
117
  ProcessContext withPathEntry(Path path);
118

119
  /**
120
   * Runs the previously configured {@link #executable(Path) command} with the configured {@link #addArgs(String...) arguments}. Will reset the
121
   * {@link #addArgs(String...) arguments} but not the {@link #executable(Path) command} for sub-sequent calls.
122
   *
123
   * @return the exit code. Will be {@link ProcessResult#SUCCESS} on successful completion of the {@link Process}.
124
   */
125
  default int run() {
126

127
    return run(ProcessMode.DEFAULT).getExitCode();
5✔
128
  }
129

130
  /**
131
   * Runs the given {@code executable} with the given {@code arguments}.
132
   *
133
   * @param executable the executable program.
134
   * @param arguments the program arguments.
135
   * @throws IllegalStateException if the command failed.
136
   */
137
  default void run(String executable, String... arguments) {
138

139
    executable(executable).addArgs(arguments).errorHandling(ProcessErrorHandling.THROW_ERR).run();
×
140
  }
×
141

142
  /**
143
   * Runs the given {@code executable} with the given {@code arguments} and returns the expected single line from its
144
   * {@link ProcessResult#getOut() standard output}.
145
   *
146
   * @param executable the executable program.
147
   * @param arguments the program arguments.
148
   * @return the single line printed from the command.
149
   * @throws IllegalStateException if the command failed or did not print a single line as expected.
150
   */
151
  default String runAndGetSingleOutput(String executable, String... arguments) {
152

153
    return runAndGetSingleOutput(null, executable, arguments);
×
154
  }
155

156
  /**
157
   * Runs the given {@code executable} with the given {@code arguments} and returns the expected single line from its
158
   * {@link ProcessResult#getOut() standard output}.
159
   *
160
   * @param logger the {@link IdeSubLogger} used to log errors instead of throwing an exception.
161
   * @param executable the executable program.
162
   * @param arguments the program arguments.
163
   * @return the single line printed from the command.
164
   * @throws IllegalStateException if the command did not print a single line as expected.
165
   */
166
  default String runAndGetSingleOutput(IdeSubLogger logger, String executable, String... arguments) {
167

168
    String errorMessage;
169
    executable(executable).addArgs(arguments);
×
170
    if (logger == null) {
×
171
      errorHandling(ProcessErrorHandling.THROW_ERR);
×
172
    }
173
    ProcessResult result = run(ProcessMode.DEFAULT_CAPTURE);
×
174
    if (result.isSuccessful()) {
×
175
      List<String> out = result.getOut();
×
176
      int size = out.size();
×
177
      if (size == 1) {
×
178
        return out.get(0);
×
179
      } else if (size == 0) {
×
180
        errorMessage = "No output received from " + result.getCommand();
×
181
      } else {
182
        StringBuilder sb = new StringBuilder();
×
183
        sb.append("Expected single line of output but received ");
×
184
        sb.append(size);
×
185
        sb.append(" lines from ");
×
186
        sb.append(result.getCommand());
×
187
        sb.append(":");
×
188
        for (String line : out) {
×
189
          sb.append("\n");
×
190
          sb.append(line);
×
191
        }
×
192
        errorMessage = sb.toString();
×
193
      }
194
    } else {
×
195
      errorMessage = "Command " + result.getCommand() + " failed with exit code " + result.getExitCode();
×
196
    }
197
    if (logger == null) {
×
198
      throw new IllegalStateException(errorMessage);
×
199
    } else {
200
      logger.log(errorMessage);
×
201
      return null;
×
202
    }
203
  }
204

205
  /**
206
   * Runs the previously configured {@link #executable(Path) command} with the configured {@link #addArgs(String...) arguments}. Will reset the
207
   * {@link #addArgs(String...) arguments} but not the {@link #executable(Path) command} for sub-sequent calls.
208
   *
209
   * @param processMode {@link ProcessMode}
210
   * @return the {@link ProcessResult}.
211
   */
212
  ProcessResult run(ProcessMode processMode);
213

214
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc