Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#25: implement tool commandlet for intellij #297

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
13a2b75
#25: implemented install and plugins
ndemirca Feb 23, 2024
b8292b6
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
ndemirca Mar 7, 2024
bcf0e4b
added first windows unittests for intellij
ndemirca Mar 8, 2024
1194c04
tested intellij installation
ndemirca Mar 8, 2024
2213057
adapted test data for intellij commandlet
ndemirca Mar 13, 2024
4329115
Adapted intellij tests
ndemirca Mar 13, 2024
b1f7e9c
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
ndemirca Apr 17, 2024
a1ae18a
adjusted test data
ndemirca Apr 17, 2024
3402cc7
changed test data for mac
ndemirca Apr 17, 2024
2d39454
fixed intellij Unittests
ndemirca Apr 17, 2024
0bd0b42
expanden intellij tool commandlet
ndemirca Apr 17, 2024
1599acb
added javadoc
ndemirca Apr 18, 2024
2dbd602
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
ndemirca Apr 23, 2024
c4ae3cf
added improvements to intellij and optimized tests
ndemirca Apr 23, 2024
e26ce93
cleaned up test data
ndemirca Apr 23, 2024
7b63574
imroved tests
ndemirca Apr 23, 2024
93265c9
fixed mac implementation
ndemirca Apr 24, 2024
dd5b979
added file mode to extractDmg to fix a bug
ndemirca Apr 24, 2024
ab2bedd
improved mac implementation
ndemirca Apr 24, 2024
5f5b2a9
refactoring
ndemirca Apr 24, 2024
a87dde9
adapted tests
ndemirca Apr 24, 2024
ca10f69
fixed unittests for mac
ndemirca Apr 25, 2024
6e46659
fixed unittest
ndemirca Apr 25, 2024
053faed
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
ndemirca Apr 25, 2024
35012f0
small improvements
ndemirca Apr 25, 2024
b9af487
moved open into bin folder
ndemirca Apr 25, 2024
13c526f
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
ndemirca Apr 29, 2024
c9af2b5
fix git merge conflict leftover
ndemirca Apr 29, 2024
7733bfc
Merge branch 'feature/25-Implement-ToolCommandlet-for-Intellij' of ht…
ndemirca Apr 29, 2024
4bbb95b
fixed gitattributes
ndemirca Apr 29, 2024
2c8820a
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
ndemirca Apr 30, 2024
9ed18b4
added gitkeep into gitignore
ndemirca Apr 30, 2024
789f5c7
restover from uninstall commandlet
ndemirca Apr 30, 2024
5463998
refactoring
ndemirca Apr 30, 2024
a3cb929
added CR improvements
ndemirca Apr 30, 2024
1c25fb4
added improvements
ndemirca May 3, 2024
02ce32c
added line endings
ndemirca May 7, 2024
1589f88
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
ndemirca May 7, 2024
9f5d2f7
fixed mac implementation
ndemirca May 7, 2024
1664414
fixed and cleaned up tests
ndemirca May 8, 2024
548357d
manipulated jmc test file
ndemirca May 8, 2024
35c7d63
reverted test step for jmc tests
ndemirca May 8, 2024
480a472
added node_modules into gittignore
ndemirca May 8, 2024
408b8e7
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
ndemirca May 8, 2024
30e4048
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
ndemirca May 17, 2024
20e8710
fixed copy bug in extractdmg
ndemirca May 23, 2024
a45b108
changed binarypath for mac
ndemirca May 27, 2024
bf7fa79
fixed copy method within extractdmg
ndemirca May 27, 2024
26e902f
adapted mac binary path
ndemirca May 27, 2024
3382e54
#347: fixed copy
jan-vcapgemini May 27, 2024
40eb875
Merge branch 'feature/347-Change-copy-method' into feature/25-Impleme…
ndemirca May 27, 2024
30062f3
fixed copy leftover and refactoring
ndemirca May 28, 2024
ad6f549
reverted refactoring
ndemirca May 28, 2024
63793c8
fixed mac tests
ndemirca May 28, 2024
9ca87e3
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
hohwille Jun 13, 2024
920ccfa
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
jan-vcapgemini Jul 1, 2024
2714aa4
Merge branch 'feature/25-Implement-ToolCommandlet-for-Intellij' of gi…
jan-vcapgemini Jul 1, 2024
b59af50
#25: implemented requested changes
jan-vcapgemini Jul 1, 2024
2947503
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
jan-vcapgemini Jul 2, 2024
d9c8268
#25: fixed copy method
jan-vcapgemini Jul 2, 2024
bd487c6
#25: added mac edition handling
jan-vcapgemini Jul 2, 2024
5c956eb
#25: implemented requested change
jan-vcapgemini Jul 2, 2024
3b1fc60
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
jan-vcapgemini Jul 4, 2024
a549382
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
jan-vcapgemini Jul 4, 2024
21be926
Merge branch 'main' into feature/25-Implement-ToolCommandlet-for-Inte…
jan-vcapgemini Jul 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@
*.tar binary
*.bz2 binary
*.gz binary

# special handling for test files
studio64.exe text
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*.bak
.*
!.gitignore
!.gitkeep
!.ide.software.version
!.devon.software.version
!.ide
Expand All @@ -15,6 +16,7 @@
target/
eclipse-target/
generated/
node_modules

# Package Files #
*.jar
Expand Down
105 changes: 57 additions & 48 deletions cli/src/main/java/com/devonfw/tools/ide/io/FileAccess.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.devonfw.tools.ide.io;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;

Expand All @@ -10,34 +14,35 @@
*/
public interface FileAccess {

/** {@link PosixFilePermission}s for "rwxr-xr-x" or 0755. */
Set<PosixFilePermission> RWX_RX_RX = Set.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE,
PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_EXECUTE, PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_EXECUTE);

/**
* Downloads a file from an arbitrary location.
*
* @param url the location of the binary file to download. May also be a local or remote path to copy from.
* @param targetFile the {@link Path} to the target file to download to. Should not already exists. Missing parent
* directories will be created automatically.
* @param targetFile the {@link Path} to the target file to download to. Should not already exists. Missing parent directories will be created automatically.
*/
void download(String url, Path targetFile);

/**
* Creates the entire {@link Path} as directories if not already existing.
*
* @param directory the {@link Path} to
* {@link java.nio.file.Files#createDirectories(Path, java.nio.file.attribute.FileAttribute...) create}.
* @param directory the {@link Path} to {@link java.nio.file.Files#createDirectories(Path, java.nio.file.attribute.FileAttribute...) create}.
*/
void mkdirs(Path directory);

/**
* @param file the {@link Path} to check.
* @return {@code true} if the given {@code file} points to an existing file, {@code false} otherwise (the given
* {@link Path} does not exist or is a directory).
* @return {@code true} if the given {@code file} points to an existing file, {@code false} otherwise (the given {@link Path} does not exist or is a
* directory).
*/
boolean isFile(Path file);

/**
* @param folder the {@link Path} to check.
* @return {@code true} if the given {@code folder} points to an existing directory, {@code false} otherwise (a
* warning is logged in this case).
* @return {@code true} if the given {@code folder} points to an existing directory, {@code false} otherwise (a warning is logged in this case).
*/
boolean isExpectedFolder(Path folder);

Expand All @@ -61,9 +66,9 @@ public interface FileAccess {
void move(Path source, Path targetDir);

/**
* Creates a symbolic link. If the given {@code targetLink} already exists and is a symbolic link or a Windows
* junction, it will be replaced. In case of missing privileges, Windows Junctions may be used as fallback, which must
* point to absolute paths. Therefore, the created link will be absolute instead of relative.
* Creates a symbolic link. If the given {@code targetLink} already exists and is a symbolic link or a Windows junction, it will be replaced. In case of
* missing privileges, Windows Junctions may be used as fallback, which must point to absolute paths. Therefore, the created link will be absolute instead of
* relative.
*
* @param source the source {@link Path} to link to, may be relative or absolute.
* @param targetLink the {@link Path} where the symbolic link shall be created pointing to {@code source}.
Expand All @@ -72,9 +77,9 @@ public interface FileAccess {
void symlink(Path source, Path targetLink, boolean relative);

/**
* Creates a relative symbolic link. If the given {@code targetLink} already exists and is a symbolic link or a
* Windows junction, it will be replaced. In case of missing privileges, Windows Junctions may be used as fallback,
* which must point to absolute paths. Therefore, the created link will be absolute instead of relative.
* Creates a relative symbolic link. If the given {@code targetLink} already exists and is a symbolic link or a Windows junction, it will be replaced. In case
* of missing privileges, Windows Junctions may be used as fallback, which must point to absolute paths. Therefore, the created link will be absolute instead
* of relative.
*
* @param source the source {@link Path} to link to, may be relative or absolute.
* @param targetLink the {@link Path} where the symbolic link shall be created pointing to {@code source}.
Expand All @@ -86,8 +91,8 @@ default void symlink(Path source, Path targetLink) {

/**
* @param source the source {@link Path file or folder} to copy.
* @param target the {@link Path} to copy {@code source} to. See {@link #copy(Path, Path, FileCopyMode)} for details.
* will always ensure that in the end you will find the same content of {@code source} in {@code target}.
* @param target the {@link Path} to copy {@code source} to. See {@link #copy(Path, Path, FileCopyMode)} for details. will always ensure that in the end you
* will find the same content of {@code source} in {@code target}.
*/
default void copy(Path source, Path target) {

Expand All @@ -96,14 +101,13 @@ default void copy(Path source, Path target) {

/**
* @param source the source {@link Path file or folder} to copy.
* @param target the {@link Path} to copy {@code source} to. Unlike the Linux {@code cp} command this method will not
* take the filename of {@code source} and copy that to {@code target} in case that is an existing folder.
* Instead it will always be simple and stupid and just copy from {@code source} to {@code target}. Therefore
* the result is always clear and easy to predict and understand. Also you can easily rename a file to copy.
* While {@code cp my-file target} may lead to a different result than {@code cp my-file target/} this method
* will always ensure that in the end you will find the same content of {@code source} in {@code target}.
* @param fileOnly - {@code true} if {@code fileOrFolder} is expected to be a file and an exception shall be thrown if
* it is a directory, {@code false} otherwise (copy recursively).
* @param target the {@link Path} to copy {@code source} to. Unlike the Linux {@code cp} command this method will not take the filename of {@code source} and
* copy that to {@code target} in case that is an existing folder. Instead it will always be simple and stupid and just copy from {@code source} to
* {@code target}. Therefore the result is always clear and easy to predict and understand. Also you can easily rename a file to copy. While
* {@code cp my-file target} may lead to a different result than {@code cp my-file target/} this method will always ensure that in the end you will find the
* same content of {@code source} in {@code target}.
* @param fileOnly - {@code true} if {@code fileOrFolder} is expected to be a file and an exception shall be thrown if it is a directory, {@code false}
* otherwise (copy recursively).
*/
void copy(Path source, Path target, FileCopyMode fileOnly);

Expand All @@ -119,8 +123,7 @@ default void extract(Path archiveFile, Path targetDir) {
/**
* @param archiveFile the {@link Path} to the archive file to extract.
* @param targetDir the {@link Path} to the directory where to extract the {@code archiveFile}.
* @param postExtractHook the {@link Consumer} to be called after the extraction on the final folder before it is
* moved to {@code targetDir}.
* @param postExtractHook the {@link Consumer} to be called after the extraction on the final folder before it is moved to {@code targetDir}.
*/
default void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtractHook) {

Expand All @@ -130,15 +133,13 @@ default void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtrac
/**
* @param archiveFile the {@link Path} to the archive file to extract.
* @param targetDir the {@link Path} to the directory where to extract the {@code archiveFile}.
* @param postExtractHook the {@link Consumer} to be called after the extraction on the final folder before it is
* moved to {@code targetDir}.
* @param postExtractHook the {@link Consumer} to be called after the extraction on the final folder before it is moved to {@code targetDir}.
* @param extract {@code true} if the {@code archiveFile} should be extracted (default), {@code false} otherwise.
*/
void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtractHook, boolean extract);

/**
* Extracts a ZIP file what is the common archive format on Windows. Initially invented by PKZIP for MS-DOS and also
* famous from WinZIP software for Windows.
* Extracts a ZIP file what is the common archive format on Windows. Initially invented by PKZIP for MS-DOS and also famous from WinZIP software for Windows.
*
* @param file the ZIP file to extract.
* @param targetDir the {@link Path} with the directory to unzip to.
Expand All @@ -153,30 +154,28 @@ default void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtrac
void extractTar(Path file, Path targetDir, TarCompression compression);

/**
* Extracts an Apple DMG (Disk Image) file that is similar to an ISO image. DMG files are commonly used for software
* releases on MacOS. Double-clicking such files on MacOS mounts them and show the application together with a
* symbolic link to the central applications folder and some help instructions. The user then copies the application
* to the applications folder via drag and drop in order to perform the installation.
* Extracts an Apple DMG (Disk Image) file that is similar to an ISO image. DMG files are commonly used for software releases on MacOS. Double-clicking such
* files on MacOS mounts them and show the application together with a symbolic link to the central applications folder and some help instructions. The user
* then copies the application to the applications folder via drag and drop in order to perform the installation.
*
* @param file the DMG file to extract.
* @param targetDir the target directory where to extract the contents to.
*/
void extractDmg(Path file, Path targetDir);

/**
* Extracts an MSI (Microsoft Installer) file. MSI files are commonly used for software releases on Windows that allow
* an installation wizard and easy later uninstallation.
* Extracts an MSI (Microsoft Installer) file. MSI files are commonly used for software releases on Windows that allow an installation wizard and easy later
* uninstallation.
*
* @param file the MSI file to extract.
* @param targetDir the target directory where to extract the contents to.
*/
void extractMsi(Path file, Path targetDir);

/**
* Extracts an Apple PKG (Package) file. PKG files are used instead of {@link #extractDmg(Path, Path) DMG files} if
* additional changes have to be performed like drivers to be installed. Similar to what
* {@link #extractMsi(Path, Path) MSI} is on Windows. PKG files are internally a xar based archive with a specific
* structure.
* Extracts an Apple PKG (Package) file. PKG files are used instead of {@link #extractDmg(Path, Path) DMG files} if additional changes have to be performed
* like drivers to be installed. Similar to what {@link #extractMsi(Path, Path) MSI} is on Windows. PKG files are internally a xar based archive with a
* specific structure.
*
* @param file the PKG file to extract.
* @param targetDir the target directory where to extract the contents to.
Expand All @@ -197,11 +196,10 @@ default void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtrac
void delete(Path path);

/**
* Creates a new temporary directory. ATTENTION: The user of this method is responsible to do house-keeping and
* {@link #delete(Path) delete} it after the work is done.
* Creates a new temporary directory. ATTENTION: The user of this method is responsible to do house-keeping and {@link #delete(Path) delete} it after the work
* is done.
*
* @param name the default name of the temporary directory to create. A prefix or suffix may be added to ensure
* uniqueness.
* @param name the default name of the temporary directory to create. A prefix or suffix may be added to ensure uniqueness.
* @return the {@link Path} to the newly created and unique temporary directory.
*/
Path createTempDir(String name);
Expand All @@ -216,10 +214,9 @@ default void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtrac

/**
* @param dir the {@link Path} to the directory where to list the children.
* @param filter the {@link Predicate} used to {@link Predicate#test(Object) decide} which children to include (if
* {@code true} is returned).
* @return all children of the given {@link Path} that match the given {@link Predicate}. Will be the empty list of
* the given {@link Path} is not an existing directory.
* @param filter the {@link Predicate} used to {@link Predicate#test(Object) decide} which children to include (if {@code true} is returned).
* @return all children of the given {@link Path} that match the given {@link Predicate}. Will be the empty list of the given {@link Path} is not an existing
* directory.
*/
List<Path> listChildren(Path dir, Predicate<Path> filter);

Expand All @@ -234,8 +231,20 @@ default void extract(Path archiveFile, Path targetDir, Consumer<Path> postExtrac

/**
* Checks if the given directory is empty.
*
* @param dir The {@link Path} object representing the directory to check.
* @return {@code true} if the directory is empty, {@code false} otherwise.
*/
boolean isEmptyDir(Path dir);

/**
* Makes the file executable.
*
* @param path Path to the file.
* @throws IOException if an I/O error occurs.
*/
default void makeExecutable(Path path) throws IOException {

Files.setPosixFilePermissions(path, RWX_RX_RX);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,8 @@ public void extractDmg(Path file, Path targetDir) {
if (appPath == null) {
throw new IllegalStateException("Failed to unpack DMG as no MacOS *.app was found in file " + file);
}
copy(appPath, targetDir);

copy(appPath, targetDir, FileCopyMode.COPY_TREE_OVERRIDE_TREE);
pc.addArgs("detach", "-force", mountPath);
pc.run();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public abstract class LocalToolCommandlet extends ToolCommandlet {
* The constructor.
*
* @param context the {@link IdeContext}.
* @param tool the {@link #getName() tool name}.
* @param tool the {@link #getName() tool name}.
* @param tags the {@link #getTags() tags} classifying the tool. Should be created via {@link Set#of(Object) Set.of} method.
*/
public LocalToolCommandlet(IdeContext context, String tool, Set<Tag> tags) {
Expand Down Expand Up @@ -138,7 +138,7 @@ public ToolInstallation installInRepo(VersionIdentifier version, String edition)
* repository without touching the IDE installation.
*
* @param version the {@link VersionIdentifier} requested to be installed. May also be a {@link VersionIdentifier#isPattern() version pattern}.
* @param edition the specific edition to install.
* @param edition the specific edition to install.
* @param toolRepository the {@link ToolRepository} to use.
* @return the {@link ToolInstallation} in the central software repository matching the given {@code version}.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
package com.devonfw.tools.ide.tool.intellij;

import com.devonfw.tools.ide.cli.CliArgument;
import com.devonfw.tools.ide.common.Tag;
import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.io.FileAccess;
import com.devonfw.tools.ide.process.ProcessMode;
import com.devonfw.tools.ide.tool.ide.IdeToolCommandlet;
import com.devonfw.tools.ide.tool.ide.PluginDescriptor;
import com.devonfw.tools.ide.tool.java.Java;
import com.devonfw.tools.ide.version.VersionIdentifier;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Set;

/**
* {@link IdeToolCommandlet} for <a href="https://www.jetbrains.com/idea/">IntelliJ</a>.
*/
public class Intellij extends IdeToolCommandlet {

private static final String IDEA = "idea";

private static final String IDEA64_EXE = IDEA + "64.exe";

private static final String IDEA_BASH_SCRIPT = IDEA + ".sh";

/**
* The constructor.
*
Expand All @@ -23,6 +36,27 @@ public Intellij(IdeContext context) {
super(context, "intellij", Set.of(Tag.INTELLIJ));
}

@Override
public void runTool(ProcessMode processMode, VersionIdentifier toolVersion, String... args) {

install(true);
args = CliArgument.prepend(args, this.context.getWorkspacePath().toString());
super.runTool(processMode, toolVersion, args);
}

@Override
protected String getBinaryName() {

Path toolBinPath = getToolBinPath();
if (this.context.getSystemInfo().isWindows()) {
return toolBinPath.resolve(IDEA64_EXE).toString();
} else if (this.context.getSystemInfo().isLinux()) {
return toolBinPath.resolve(IDEA_BASH_SCRIPT).toString();
} else {
return getToolPath().resolve("IntelliJ IDEA" + generateMacEditionString() + ".app").resolve("Contents").resolve("MacOS").resolve(IDEA).toString();
}
}

@Override
public boolean install(boolean silent) {

Expand All @@ -31,10 +65,37 @@ public boolean install(boolean silent) {
}

@Override
public void installPlugin(PluginDescriptor plugin) {
protected void postInstall() {

super.postInstall();
if (this.context.getSystemInfo().isMac()) {
setMacOsFilePermissions(getToolPath().resolve("IntelliJ IDEA" + generateMacEditionString() + ".app").resolve("Contents").resolve("MacOS").resolve(IDEA));
}
}

private String generateMacEditionString() {

// TODO Auto-generated method stub
String edition = "";
if (getEdition().equals("intellij")) {
edition = " CE";
}
return edition;
}

private void setMacOsFilePermissions(Path binaryFile) {

if (Files.exists(binaryFile)) {
FileAccess fileAccess = this.context.getFileAccess();
try {
fileAccess.makeExecutable(binaryFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

}
@Override
public void installPlugin(PluginDescriptor plugin) {
// TODO: needs to be implemented see: https://github.com/devonfw/IDEasy/issues/433
}
}
Loading
Loading