-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Manually search for executables under POSIX when the PATH is overriden
- Loading branch information
Greg Gibeling
committed
Mar 4, 2025
1 parent
2187e1d
commit 31449dc
Showing
4 changed files
with
123 additions
and
27 deletions.
There are no files selected for viewing
61 changes: 61 additions & 0 deletions
61
ax-command/src/main/java/com/g2forge/alexandria/command/clireport/HCLIReport.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,61 @@ | ||
package com.g2forge.alexandria.command.clireport; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
import java.net.URL; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.nio.file.attribute.PosixFilePermission; | ||
import java.util.EnumSet; | ||
|
||
import com.g2forge.alexandria.java.close.ICloseableSupplier; | ||
import com.g2forge.alexandria.java.io.HBinaryIO; | ||
import com.g2forge.alexandria.java.io.RuntimeIOException; | ||
import com.g2forge.alexandria.java.platform.HPlatform; | ||
|
||
public class HCLIReport { | ||
public static final String CLIREPORT_VERSION = "v0.0.1"; | ||
|
||
public static final String CLIREPORT_FILENAME = "clireport"; | ||
|
||
public static final String CLIREPORT_DOWNLOADFORMAT = "https://github.com/g2forge/clireport/releases/download/%1$s/%2$s"; | ||
|
||
public static ICloseableSupplier<Path> download(Path directory) { | ||
final String filename = HPlatform.getPlatform().getExeSpecs()[0].fromBase(CLIREPORT_FILENAME); | ||
final Path path = directory == null ? Paths.get(filename) : directory.resolve(filename); | ||
if (!Files.exists(path)) { | ||
final String url = String.format(CLIREPORT_DOWNLOADFORMAT, CLIREPORT_VERSION, path.getFileName().toString()); | ||
try (final InputStream input = new URL(url).openStream(); final OutputStream output = Files.newOutputStream(path)) { | ||
HBinaryIO.copy(input, output); | ||
} catch (IOException e) { | ||
throw new RuntimeIOException("Failed to download clireport", e); | ||
} | ||
if (!Files.exists(path)) throw new RuntimeException(String.format("Failed to download %1$s to %2$s", url, path)); | ||
try { | ||
Files.setPosixFilePermissions(path, EnumSet.allOf(PosixFilePermission.class)); | ||
} catch (UnsupportedOperationException exception) { | ||
// Ignore this - it's not required on platforms where it's not supported | ||
} catch (IOException exception) { | ||
throw new RuntimeIOException(String.format("Failed to mark %1$s executable", path), exception); | ||
} | ||
if (!Files.isExecutable(path)) throw new RuntimeException(String.format("%1$s is not executable", path)); | ||
} | ||
return new ICloseableSupplier<Path>() { | ||
@Override | ||
public void close() { | ||
try { | ||
Files.deleteIfExists(path); | ||
} catch (IOException e) { | ||
throw new RuntimeException("Failed to delete downloaded " + CLIREPORT_FILENAME, e); | ||
} | ||
} | ||
|
||
@Override | ||
public Path get() { | ||
return path; | ||
} | ||
}; | ||
} | ||
} |
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
43 changes: 43 additions & 0 deletions
43
...rc/main/java/com/g2forge/alexandria/command/invocation/runner/PosixPathCommandRunner.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,43 @@ | ||
package com.g2forge.alexandria.command.invocation.runner; | ||
|
||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
import com.g2forge.alexandria.command.invocation.CommandInvocation; | ||
import com.g2forge.alexandria.command.invocation.environment.SystemEnvironment; | ||
import com.g2forge.alexandria.java.core.marker.ISingleton; | ||
import com.g2forge.alexandria.java.platform.HPlatform; | ||
|
||
public class PosixPathCommandRunner implements ICommandRunner, ISingleton { | ||
protected static final PosixPathCommandRunner INSTANCE = new PosixPathCommandRunner(); | ||
|
||
public static PosixPathCommandRunner create() { | ||
return INSTANCE; | ||
} | ||
|
||
private PosixPathCommandRunner() {} | ||
|
||
@Override | ||
public <I, O> CommandInvocation<I, O> wrap(CommandInvocation<I, O> invocation) { | ||
final String pathAsString = invocation.getEnvironment().apply(HPlatform.PATH); | ||
// If the invocation PATH and system PATH are the same, then we can delegate to the underlying JVM code | ||
if (Objects.equals(SystemEnvironment.create().apply(HPlatform.PATH), pathAsString)) return invocation; | ||
|
||
// Since the user is overriding the PATH, let's search that PATH for the executable | ||
// We have to do this here because the JVM doesn't allow us to do this down at the process builder level | ||
final String[] pathAsArray = HPlatform.getPlatform().getPathSpec().splitPaths(pathAsString); | ||
for (String directory : pathAsArray) { | ||
final Path resolved = Paths.get(directory).resolve(invocation.getArguments().get(0)); | ||
if (Files.exists(resolved) && Files.isExecutable(resolved)) { | ||
final List<String> arguments = new ArrayList<>(invocation.getArguments()); | ||
arguments.set(0, resolved.toString()); | ||
return invocation.toBuilder().clearArguments().arguments(arguments).build(); | ||
} | ||
} | ||
return invocation; | ||
} | ||
} |
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