Skip to content

Commit

Permalink
Merge branch 'main' into settings-in-code-repo
Browse files Browse the repository at this point in the history
  • Loading branch information
hohwille authored Jan 10, 2025
2 parents 165174c + 8e971e1 commit 80ba24e
Show file tree
Hide file tree
Showing 30 changed files with 72 additions and 36 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Release with new features and bugfixes:

* https://github.com/devonfw/IDEasy/issues/757[#757]: Support to allow settings in code repository
* https://github.com/devonfw/IDEasy/issues/826[#826]: Fix git settings check when settings folder is empty
* https://github.com/devonfw/IDEasy/issues/894[#894]: Fix ide.bat printing for initialization and error output

The full list of changes for this release can be found in https://github.com/devonfw/IDEasy/milestone/18?closed=1[milestone 2025.01.001].

Expand Down
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);
}
50 changes: 33 additions & 17 deletions cli/src/main/java/com/devonfw/tools/ide/io/FileAccessImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -903,52 +904,67 @@ 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> existingPermissions = Files.getPosixFilePermissions(file);

// Add execute permission for all users
Set<PosixFilePermission> executablePermissions = new HashSet<>(existingPermissions);
boolean update = false;
update |= perms.add(PosixFilePermission.OWNER_EXECUTE);
update |= perms.add(PosixFilePermission.GROUP_EXECUTE);
update |= perms.add(PosixFilePermission.OTHERS_EXECUTE);
update |= executablePermissions.add(PosixFilePermission.OWNER_EXECUTE);
update |= executablePermissions.add(PosixFilePermission.GROUP_EXECUTE);
update |= executablePermissions.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"
+ "Changing permissions from " + PosixFilePermissions.toString(existingPermissions) + " to " + PosixFilePermissions.toString(
executablePermissions) + ".\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, executablePermissions);
} 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
15 changes: 10 additions & 5 deletions cli/src/main/package/bin/ide.bat
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,22 @@ if exist "%GIT_CORE%" (

if not "%1%" == "" (
ideasy %IDE_OPTIONS% %*
if not %ERRORLEVEL% == 0 (
echo %_fBRed%Error: IDEasy failed with exit code %ERRORLEVEL% %_RESET%
exit /b %ERRORLEVEL%
)
goto :output_error
)

REM https://stackoverflow.com/questions/61888625/what-is-f-in-the-for-loop-command
for /f "tokens=*" %%i in ('ideasy %IDE_OPTIONS% env') do (
call set %%i
)

if not %ERRORLEVEL% == 0 (
ideasy %IDE_OPTIONS% env>nul

if %ERRORLEVEL% == 0 (
echo IDE environment variables have been set for %IDE_HOME% in workspace %WORKSPACE%
)

:output_error
if not %ERRORLEVEL% == 0 (
echo %_fBRed%Error: IDEasy failed with exit code %ERRORLEVEL% %_RESET%
exit /b %ERRORLEVEL%
)
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
12 changes: 7 additions & 5 deletions documentation/advanced-tooling-generic.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ toc::[]
== Browser Plugins

There are tons of helpful browser plugins out there and it might be a matter of personal taste what you like to have installed.
However, as we are heavily using github we want to promote https://github.com/buunguyen/octotree#octotree[octotree].
The following are explicitly worth to mention:

* https://darkreader.org/[DarkReader] - for developers enjoying dark-mode (and get eye-cancer from white backgrounds)
* https://www.tampermonkey.net/[TamperMonkey] - even though not recommended to be always on for security reasons this is the ultimate swiss-army-knife of every web-developer.
* FF only: https://addons.mozilla.org/en-US/firefox/addon/simple-tab-groups/[Simple Tab Groups] - only for power-users that need to manage 100+ open tabs in multi-tenancy contexts (project A, project B, timetracking, travel, etc.).

For the record: HttpsEverywhere is dead since now there is https://www.eff.org/https-everywhere/set-https-default-your-browser[native browser support for HTTPS only].

== Draw Diagrams

Expand All @@ -21,7 +27,3 @@ Its simplicity allows branching and merging unlike other greedy binary UML data-

If you are looking for a git client that works cross-platform we recommend to use https://git-fork.com/[Fork].

== Tab Grouping For The Web Browser

https://addons.mozilla.org/en-US/firefox/addon/simple-tab-groups/[Simple Tab Groups] is a Firefox plugin that helps to separate tabs e.g. tabs for projekt A, projekt B, travelplanning or hobbies

0 comments on commit 80ba24e

Please sign in to comment.