Skip to content

Commit

Permalink
devonfw#881: add self healing feature to add x-flags before running c…
Browse files Browse the repository at this point in the history
…ommand
  • Loading branch information
hohwille committed Dec 20, 2024
1 parent cac095b commit dcc8b81
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 23 deletions.
21 changes: 16 additions & 5 deletions cli/src/main/java/com/devonfw/tools/ide/io/FileAccess.java
Original file line number Diff line number Diff line change
Expand Up @@ -257,18 +257,29 @@ default void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtrac
boolean isEmptyDir(Path dir);

/**
* Makes a file executable. Equivalent of using 'chmod a+x'. Adds execute permissions to current file permissions.
* Makes a file executable (analog to 'chmod a+x').
*
* @param filePath {@link Path} to the file.
* @param file {@link Path} to the file.
*/
void makeExecutable(Path filePath);
default void makeExecutable(Path file) {

makeExecutable(file, false);
}

/**
* Makes a file executable (analog to 'chmod a+x').
*
* @param file {@link Path} to the file.
* @param confirm - {@code true} to get user confirmation before adding missing executable flags, {@code false} otherwise (always set missing flags).
*/
void makeExecutable(Path file, boolean confirm);

/**
* Like the linux touch command this method will update the modification time of the given {@link Path} to the current
* {@link System#currentTimeMillis() system time}. In case the file does not exist, it will be created as empty file. If already the
* {@link Path#getParent() parent folder} does not exist, the operation will fail.
*
* @param filePath the {@link Path} to the file or folder.
* @param file the {@link Path} to the file or folder.
*/
void touch(Path filePath);
void touch(Path file);
}
40 changes: 26 additions & 14 deletions cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -903,16 +903,16 @@ public Path findExistingFile(String fileName, List<Path> searchDirs) {
}

@Override
public void makeExecutable(Path filePath) {
public void makeExecutable(Path file, boolean confirm) {

if (Files.exists(filePath)) {
if (Files.exists(file)) {
if (SystemInfoImpl.INSTANCE.isWindows()) {
this.context.trace("Windows does not have executable flags hence omitting for file {}", filePath);
this.context.trace("Windows does not have executable flags hence omitting for file {}", file);
return;
}
try {
// Read the current file permissions
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(filePath);
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);

// Add execute permission for all users
boolean update = false;
Expand All @@ -921,34 +921,46 @@ public void makeExecutable(Path filePath) {
update |= perms.add(PosixFilePermission.OTHERS_EXECUTE);

if (update) {
this.context.debug("Setting executable flags for file {}", filePath);
if (confirm) {
boolean yesContinue = this.context.question(
"We want to execute " + file.getFileName() + " but this command seems to lack executable permissions!\n"
+ "Most probably the tool vendor did forgot to add x-flags in the binary release package.\n"
+ "Before running the command, we suggest to set executable permissions to the file:\n"
+ file + "\n"
+ "For security reasons we ask for your confirmation so please check this request.\n"
+ "Do you confirm to make the command executable before running it?");
if (!yesContinue) {
return;
}
}
this.context.debug("Setting executable flags for file {}", file);
// Set the new permissions
Files.setPosixFilePermissions(filePath, perms);
Files.setPosixFilePermissions(file, perms);
} else {
this.context.trace("Executable flags already present so no need to set them for file {}", filePath);
this.context.trace("Executable flags already present so no need to set them for file {}", file);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
this.context.warning("Cannot set executable flag on file that does not exist: {}", filePath);
this.context.warning("Cannot set executable flag on file that does not exist: {}", file);
}
}

@Override
public void touch(Path filePath) {
public void touch(Path file) {

if (Files.exists(filePath)) {
if (Files.exists(file)) {
try {
Files.setLastModifiedTime(filePath, FileTime.fromMillis(System.currentTimeMillis()));
Files.setLastModifiedTime(file, FileTime.fromMillis(System.currentTimeMillis()));
} catch (IOException e) {
throw new IllegalStateException("Could not update modification-time of " + filePath, e);
throw new IllegalStateException("Could not update modification-time of " + file, e);
}
} else {
try {
Files.createFile(filePath);
Files.createFile(file);
} catch (IOException e) {
throw new IllegalStateException("Could not create empty file " + filePath, e);
throw new IllegalStateException("Could not create empty file " + file, e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public ProcessResult run(ProcessMode processMode) {
this.executable = systemPath.findBinary(this.executable);
this.processBuilder.environment().put(IdeVariables.PATH.getName(), path);
List<String> args = new ArrayList<>(this.arguments.size() + 4);
String interpreter = addExecutable(this.executable.toString(), args);
String interpreter = addExecutable(args);
args.addAll(this.arguments);
String command = createCommand();
if (this.context.debug().isEnabled()) {
Expand Down Expand Up @@ -297,11 +297,12 @@ private String getSheBang(Path file) {
return null;
}

private String addExecutable(String exec, List<String> args) {
private String addExecutable(List<String> args) {

String interpreter = null;
String fileExtension = FilenameUtil.getExtension(exec);
String fileExtension = FilenameUtil.getExtension(this.executable.getFileName().toString());
boolean isBashScript = "sh".equals(fileExtension);
this.context.getFileAccess().makeExecutable(this.executable, true);
if (!isBashScript) {
String sheBang = getSheBang(this.executable);
if (sheBang != null) {
Expand All @@ -325,7 +326,7 @@ private String addExecutable(String exec, List<String> args) {
args.add(0, "/i");
args.add(0, "msiexec");
}
args.add(exec);
args.add(this.executable.toString());
return interpreter;
}

Expand Down

0 comments on commit dcc8b81

Please sign in to comment.