-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
446 additions
and
238 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
src/main/java/com/github/frimtec/libraries/jpse/AbstractPowerShellExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package com.github.frimtec.libraries.jpse; | ||
|
||
import java.io.*; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
import static java.nio.charset.StandardCharsets.UTF_16LE; | ||
import static java.nio.charset.StandardCharsets.UTF_8; | ||
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; | ||
|
||
abstract class AbstractPowerShellExecutor implements PowerShellExecutor { | ||
|
||
private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder(); | ||
|
||
private static final int INITIAL_STREAM_BUFFER_SIZE = 1000; | ||
private static final String JPSE_GLOBBER_THREAD_NAME = "JPSE-Gobbler"; | ||
|
||
private final String executionCommand; | ||
private final Path tempPath; | ||
|
||
AbstractPowerShellExecutor(Path tempPath, String executionCommand) { | ||
this.tempPath = tempPath; | ||
this.executionCommand = executionCommand; | ||
if (tempPath != null && !Files.exists(tempPath)) { | ||
try { | ||
Files.createDirectories(tempPath); | ||
} catch (IOException e) { | ||
throw new UncheckedIOException("Cannot create given temp folder: " + tempPath.toAbsolutePath(), e); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public ExecutionResult execute(String command) { | ||
String encodedCommand = BASE64_ENCODER.encodeToString(command.getBytes(UTF_16LE)); | ||
return execute(createProcessBuilder(Arrays.asList(this.executionCommand, "-EncodedCommand", encodedCommand))); | ||
} | ||
|
||
@Override | ||
public ExecutionResult execute(Path script, Map<String, String> arguments) { | ||
List<String> commandLine = new ArrayList<>(Arrays.asList(this.executionCommand, "-File", script.toString())); | ||
commandLine.addAll(arguments.entrySet() | ||
.stream() | ||
.flatMap(entry -> Stream.of("-" + entry.getKey(), "\"" + entry.getValue() + "\"")) | ||
.collect(Collectors.toList())); | ||
return execute(createProcessBuilder(commandLine)); | ||
} | ||
|
||
@Override | ||
public ExecutionResult execute(InputStream script, Map<String, String> arguments) { | ||
try { | ||
String prefix = "java-power-shell-"; | ||
String suffix = ".ps1"; | ||
Path tempFile = this.tempPath != null ? Files.createTempFile(this.tempPath, prefix, suffix) : Files.createTempFile(prefix, suffix); | ||
try { | ||
Files.write(tempFile, readStream(script).getBytes(UTF_8), TRUNCATE_EXISTING); | ||
return execute(tempFile, arguments); | ||
} finally { | ||
Files.deleteIfExists(tempFile); | ||
} | ||
} catch (IOException e) { | ||
throw new UncheckedIOException("Cannot handle script", e); | ||
} | ||
} | ||
|
||
@Override | ||
public Optional<Version> version() { | ||
try { | ||
String[] versionParts = execute("'' + $PSVersionTable.PSVersion.Major + '.' + $PSVersionTable.PSVersion.Minor").getStandardOutput().split("\\."); | ||
return Optional.of(new Version( | ||
Integer.parseInt(versionParts[0]), | ||
Integer.parseInt(versionParts[1]) | ||
)); | ||
} catch (Exception e) { | ||
return Optional.empty(); | ||
} | ||
} | ||
|
||
protected ProcessBuilder createProcessBuilder(List<String> commandLine) { | ||
return new ProcessBuilder(commandLine); | ||
} | ||
|
||
private ExecutionResult execute(ProcessBuilder processBuilder) { | ||
StringWriter outputStringWriter = new StringWriter(INITIAL_STREAM_BUFFER_SIZE); | ||
StringWriter errorStringWriter = new StringWriter(INITIAL_STREAM_BUFFER_SIZE); | ||
PrintWriter outputBuffer = new PrintWriter(outputStringWriter); | ||
PrintWriter errorBuffer = new PrintWriter(errorStringWriter); | ||
try { | ||
Process process = processBuilder.start(); | ||
StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), outputBuffer::println); | ||
StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), errorBuffer::println); | ||
List<Thread> threads = Arrays.asList( | ||
new Thread(outputGobbler, JPSE_GLOBBER_THREAD_NAME), | ||
new Thread(errorGobbler, JPSE_GLOBBER_THREAD_NAME) | ||
); | ||
threads.forEach(thread -> { | ||
thread.setDaemon(true); | ||
thread.start(); | ||
}); | ||
for (StreamGobbler gobbler : Arrays.asList(outputGobbler, errorGobbler)) { | ||
gobbler.waitTillFinished(); | ||
} | ||
return new ExecutionResultImpl(process.waitFor(), getOutputFromWriter(outputStringWriter), getOutputFromWriter(errorStringWriter)); | ||
} catch (InterruptedException e) { | ||
Thread.currentThread().interrupt(); | ||
throw new RuntimeException("Wait for process termination interrupted", e); | ||
} catch (IOException e) { | ||
throw new UncheckedIOException("Powershell cannot be executed", e); | ||
} | ||
} | ||
|
||
private String getOutputFromWriter(StringWriter outputStringWriter) { | ||
return outputStringWriter.getBuffer().toString().trim(); | ||
} | ||
|
||
private String readStream(InputStream inputStream) { | ||
return new BufferedReader(new InputStreamReader(inputStream, UTF_8)) | ||
.lines() | ||
.collect(Collectors.joining("\n")); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/main/java/com/github/frimtec/libraries/jpse/LinuxPowerShellExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.github.frimtec.libraries.jpse; | ||
|
||
import java.nio.file.Path; | ||
|
||
class LinuxPowerShellExecutor extends AbstractPowerShellExecutor { | ||
|
||
private static final String POWER_SHELL_CMD = "pwsh"; | ||
|
||
LinuxPowerShellExecutor(Path tempPath) { | ||
super(tempPath, POWER_SHELL_CMD); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 34 additions & 28 deletions
62
src/main/java/com/github/frimtec/libraries/jpse/UnsupportedOsPowerShellExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,34 @@ | ||
package com.github.frimtec.libraries.jpse; | ||
|
||
import java.io.InputStream; | ||
import java.nio.file.Path; | ||
import java.util.Map; | ||
|
||
final class UnsupportedOsPowerShellExecutor implements PowerShellExecutor { | ||
private final String osName; | ||
|
||
UnsupportedOsPowerShellExecutor(String osName) { | ||
this.osName = osName; | ||
} | ||
|
||
@Override | ||
public ExecutionResult execute(String command) { | ||
throw new UnsupportedOperationException("Not supported on OS " + this.osName); | ||
} | ||
|
||
@Override | ||
public ExecutionResult execute(Path script, Map<String, String> arguments) { | ||
throw new UnsupportedOperationException("Not supported on OS " + this.osName); | ||
} | ||
|
||
@Override | ||
public ExecutionResult execute(InputStream script, Map<String, String> arguments) { | ||
throw new UnsupportedOperationException("Not supported on OS " + this.osName); | ||
} | ||
} | ||
package com.github.frimtec.libraries.jpse; | ||
|
||
import java.io.InputStream; | ||
import java.nio.file.Path; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
final class UnsupportedOsPowerShellExecutor implements PowerShellExecutor { | ||
private final String osName; | ||
|
||
UnsupportedOsPowerShellExecutor(String osName) { | ||
this.osName = osName; | ||
} | ||
|
||
@Override | ||
public ExecutionResult execute(String command) { | ||
throw new UnsupportedOperationException("Not supported on OS " + this.osName); | ||
} | ||
|
||
@Override | ||
public ExecutionResult execute(Path script, Map<String, String> arguments) { | ||
throw new UnsupportedOperationException("Not supported on OS " + this.osName); | ||
} | ||
|
||
@Override | ||
public ExecutionResult execute(InputStream script, Map<String, String> arguments) { | ||
throw new UnsupportedOperationException("Not supported on OS " + this.osName); | ||
} | ||
|
||
@Override | ||
public Optional<Version> version() { | ||
return Optional.empty(); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
src/main/java/com/github/frimtec/libraries/jpse/Version.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package com.github.frimtec.libraries.jpse; | ||
|
||
/** | ||
* Power shell version. | ||
* | ||
* @see PowerShellExecutor#version() | ||
* @since 1.3.0 | ||
*/ | ||
public final class Version { | ||
private final int major; | ||
private final int minor; | ||
|
||
Version(int major, int minor) { | ||
this.major = major; | ||
this.minor = minor; | ||
} | ||
|
||
/** | ||
* Major version. | ||
* | ||
* @return major | ||
*/ | ||
public int getMajor() { | ||
return this.major; | ||
} | ||
|
||
/** | ||
* Minor version. | ||
* | ||
* @return major | ||
*/ | ||
public int getMinor() { | ||
return this.minor; | ||
} | ||
|
||
/** | ||
* Version string in the format "{@code <major>.<minor>}". | ||
* | ||
* @return version string | ||
*/ | ||
@Override | ||
public String toString() { | ||
return String.format("%d.%d", this.major, this.minor); | ||
} | ||
} |
Oops, something went wrong.