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

#451: mac gatekeeper #453

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ public String getId() {
public VersionIdentifier resolveVersion(String tool, String edition, VersionIdentifier version) {

UrlMetadata metadata = this.context.getUrls();
UrlVersion urlVersion = metadata.getVersionFolder(tool, edition, version);
UrlVersion urlVersion = metadata.getResolvedVersion(tool, edition, version);
return urlVersion.getVersionIdentifier();
}

@Override
protected UrlDownloadFileMetadata getMetadata(String tool, String edition, VersionIdentifier version) {

UrlMetadata metadata = this.context.getUrls();
UrlVersion urlVersion = metadata.getVersionFolder(tool, edition, version);
UrlVersion urlVersion = metadata.getResolvedVersion(tool, edition, version);
SystemInfo sys = this.context.getSystemInfo();
UrlDownloadFile urls = urlVersion.getMatchingUrls(sys.getOs(), sys.getArchitecture());
return urls;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Set;

import com.devonfw.tools.ide.common.Tag;
import com.devonfw.tools.ide.context.AbstractIdeContext;
import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.io.FileAccess;
import com.devonfw.tools.ide.io.FileCopyMode;
Expand Down Expand Up @@ -73,16 +74,17 @@ protected boolean doInstall(boolean silent) {
VersionIdentifier installedVersion = getInstalledVersion();
Step step = this.context.newStep(silent, "Install " + this.tool, configuredVersion);
try {
// install configured version of our tool in the software repository if not already installed
ToolInstallation installation = installInRepo(configuredVersion);
// check if we already have this version installed (linked) locally in IDE_HOME/software
VersionIdentifier resolvedVersion = installation.resolvedVersion();
if (resolvedVersion.equals(installedVersion) && !installation.newInstallation()) {
ToolRepository repository = this.context.getDefaultToolRepository();
String edition = getConfiguredEdition();
VersionIdentifier resolvedVersion = repository.resolveVersion(this.tool, edition, configuredVersion);
if (resolvedVersion.equals(installedVersion)) {
IdeLogLevel level = silent ? IdeLogLevel.DEBUG : IdeLogLevel.INFO;
this.context.level(level).log("Version {} of tool {} is already installed", installedVersion, getToolWithEdition());
step.success();
return false;
}
// install configured version of our tool in the software repository if not already installed
ToolInstallation installation = installInRepo(resolvedVersion, edition, repository);
// we need to link the version or update the link.
Path toolPath = getToolPath();
FileAccess fileAccess = this.context.getFileAccess();
Expand Down Expand Up @@ -158,17 +160,20 @@ public ToolInstallation installInRepo(VersionIdentifier version, String edition,
FileAccess fileAccess = this.context.getFileAccess();
if (Files.isDirectory(toolPath)) {
if (Files.exists(toolVersionFile)) {
if (this.context.isForceMode()) {
fileAccess.delete(toolPath);
} else {
this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion, getToolWithEdition(this.tool, edition), toolPath);
return createToolInstallation(toolPath, resolvedVersion, toolVersionFile);
}
this.context.debug("Version {} of tool {} is already installed at {}", resolvedVersion, getToolWithEdition(this.tool, edition), toolPath);
return createToolInstallation(toolPath, resolvedVersion, toolVersionFile);
} else {
this.context.warning("Deleting corrupted installation at {}", toolPath);
fileAccess.delete(toolPath);
this.context.warning("Archiving corrupted installation at {}", toolPath);
fileAccess.backup(toolPath);
}
}

if (Files.exists(this.dependency.getDependencyJsonPath(getConfiguredEdition()))) {
installDependencies(resolvedVersion);
} else {
this.context.trace("No Dependencies file found");
}

Path target = toolRepository.download(this.tool, edition, resolvedVersion);
fileAccess.mkdirs(toolPath.getParent());
boolean extract = isExtract();
Expand Down Expand Up @@ -291,13 +296,39 @@ private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier
if (Files.isDirectory(binFolder)) {
binDir = binFolder;
}
if (linkDir != rootDir) {
if (newInstallation && (linkDir != rootDir)) {
assert (!linkDir.equals(rootDir));
this.context.getFileAccess().copy(toolVersionFile, linkDir, FileCopyMode.COPY_FILE_OVERRIDE);
if (this.context.getSystemInfo().isMac() && !((AbstractIdeContext) this.context).isTest()) {
Path macApp = findMacApp(linkDir);
if (macApp != null) {
ProcessContext pc = this.context.newProcess();
pc.executable("sudo").addArgs("xattr", "-d", "com.apple.quarantine", macApp);
pc.run();
Comment on lines +303 to +307
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move to MacOsHelper class?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major problem is that this approach does not yet work. Maybe we need to do this for all files recursively. Still looking for a better solution to the problem. After all MacOS Settings will do some magic and there should be some command to automate this "magic".
But I fully aggree that this should go to MacOsHelper following SoC.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no documentation from Apple about such features. Maybe this meta-attribute needs to be set on the executable(s) rather than on the *.all folder. We would need more analysis on this to come up with a real solution.
I will change this PR back to draft to make this clear.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would actually need somebody to analyze this on a real mac with Gatekeeper and try various such xattr commands for different folders and files until we know what does the magic trick.
Additionally someone must implement #415
Only after both things are addressed, we can actually implement/finish this #451 story.

}
}
}
return new ToolInstallation(rootDir, linkDir, binDir, resolvedVersion, newInstallation);
}

private Path findMacApp(Path path) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't this be moved to the MacOsHelper class?


while (path != null) {
Path fileName = path.getFileName();
if (fileName == null) {
return null;
}
String filename = fileName.toString();
if (filename.endsWith(".app")) {
return path;
} else if (filename.equals(IdeContext.FOLDER_CONTENTS)) {
return path.getParent();
}
path = path.getParent();
}
return null;
}

private ToolInstallation createToolInstallation(Path rootDir, VersionIdentifier resolvedVersion, Path toolVersionFile) {

return createToolInstallation(rootDir, resolvedVersion, toolVersionFile, false);
Expand Down
15 changes: 7 additions & 8 deletions cli/src/main/java/com/devonfw/tools/ide/tool/ToolCommandlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -278,22 +278,21 @@ public void setVersion(String version) {
public void setVersion(VersionIdentifier version, boolean hint) {

String edition = getConfiguredEdition();
this.context.getUrls()
.getVersionFolder(this.tool, edition, version); // CliException is thrown if the version is not existing

EnvironmentVariables variables = this.context.getVariables();
EnvironmentVariables settingsVariables = variables.getByType(EnvironmentVariablesType.SETTINGS);
String name = EnvironmentVariables.getToolVersionVariable(this.tool);
VersionIdentifier resolvedVersion = this.context.getUrls().getVersion(this.tool, edition, version);
String versionVariableName = EnvironmentVariables.getToolVersionVariable(this.tool);
VersionIdentifier resolvedVersion = this.context.getUrls().getResolvedVersion(this.tool, edition, version).getVersionIdentifier();
if (version.isPattern()) {
this.context.debug("Resolved version {} to {} for tool {}/{}", version, resolvedVersion, this.tool, edition);
}
settingsVariables.set(name, resolvedVersion.toString(), false);
settingsVariables.set(versionVariableName, version.toString(), false);
settingsVariables.save();
this.context.info("{}={} has been set in {}", name, version, settingsVariables.getSource());
EnvironmentVariables declaringVariables = variables.findVariable(name);
this.context.info("{}={} has been set in {}", versionVariableName, version, settingsVariables.getSource());
EnvironmentVariables declaringVariables = variables.findVariable(versionVariableName);
if ((declaringVariables != null) && (declaringVariables != settingsVariables)) {
this.context.warning("The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.", name,
this.context.warning("The variable {} is overridden in {}. Please remove the overridden declaration in order to make the change affect.",
versionVariableName,
declaringVariables.getSource());
}
if (hint) {
Expand Down
2 changes: 1 addition & 1 deletion cli/src/main/java/com/devonfw/tools/ide/tool/mvn/Mvn.java
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ private Set<String> findVariables(String content) {
@Override
public void installPlugin(PluginDescriptor plugin) {

Path mavenPlugin = this.getToolPath().resolve("lib/ext/" + plugin.getName() + ".jar");
Path mavenPlugin = getToolPath().resolve("lib/ext/" + plugin.getName() + ".jar");
this.context.getFileAccess().download(plugin.getUrl(), mavenPlugin);
if (Files.exists(mavenPlugin)) {
this.context.success("Successfully added {} to {}", plugin.getName(), mavenPlugin.toString());
Expand Down
47 changes: 24 additions & 23 deletions cli/src/main/java/com/devonfw/tools/ide/url/model/UrlMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,14 @@ public UrlMetadata(IdeContext context) {
*/
public UrlEdition getEdition(String tool, String edition) {

UrlTool urlTool = this.repository.getOrCreateChild(tool);
UrlEdition urlEdition = urlTool.getOrCreateChild(edition);
UrlTool urlTool = this.repository.getChild(tool);
if (urlTool == null) {
throw new CliException("Could not find tool '" + tool + "' in ide-urls metadata!");
}
UrlEdition urlEdition = urlTool.getChild(edition);
if (urlEdition == null) {
throw new CliException("Could not find edition '" + edition + "' for tool '" + tool + "' in ide-urls metadata!");
}
return urlEdition;
}

Expand Down Expand Up @@ -101,41 +107,36 @@ private List<VersionIdentifier> computeSortedVersions(String tool, String editio
* latest version.
* @return the latest matching {@link VersionIdentifier} for the given {@code tool} and {@code edition}.
*/
public VersionIdentifier getVersion(String tool, String edition, VersionIdentifier version) {
public UrlVersion getResolvedVersion(String tool, String edition, VersionIdentifier version) {

if (version == null) {
version = VersionIdentifier.LATEST;
}
if (!version.isPattern()) {
return version;
UrlEdition urlEdition = getEdition(tool, edition);
VersionIdentifier resolvedVersion = version;
if (version.isPattern()) {
resolvedVersion = resolveVersion(tool, edition, version);
}
UrlVersion urlVersion = urlEdition.getChild(resolvedVersion.toString());
if (urlVersion == null) {
throw new CliException("Version " + version + " for tool " + tool + " does not exist in edition " + edition + ".");
}
return urlVersion;
}

private VersionIdentifier resolveVersion(String tool, String edition, VersionIdentifier version) {

List<VersionIdentifier> versions = getSortedVersions(tool, edition);
for (VersionIdentifier vi : versions) {
if (version.matches(vi)) {
this.context.debug("Resolved version pattern {} to version {}", version, vi);
return vi;
}
}
// TODO properly consider edition (needs list-versions commandlet enhancement to also support edition)
throw new CliException(
"Could not find any version matching '" + version + "' for tool '" + tool + "' - potentially there are " + versions.size() + " version(s) available in "
+ getEdition(tool, edition).getPath() + " but none matched!");
}

/**
* @param tool the name of the {@link UrlTool}.
* @param edition the name of the {@link UrlEdition}.
* @param version the {@link VersionIdentifier} to match. May be a {@link VersionIdentifier#isPattern() pattern}, a specific version or {@code null} for the
* latest version.
* @return the latest matching {@link UrlVersion} for the given {@code tool} and {@code edition}.
*/
public UrlVersion getVersionFolder(String tool, String edition, VersionIdentifier version) {

VersionIdentifier resolvedVersion = getVersion(tool, edition, version);
UrlVersion urlVersion = getEdition(tool, edition).getChild(resolvedVersion.toString());
if (urlVersion == null) {
throw new CliException("Version " + version + " for tool " + tool + " does not exist in edition " + edition + ".");
}
return urlVersion;
+ getEdition(tool, edition).getPath() + " but none matched! You can get the list of available versions with the following command:\nide list-versions " + tool);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.junit.jupiter.api.Test;

import com.devonfw.tools.ide.context.AbstractIdeContextTest;
import com.devonfw.tools.ide.context.IdeContext;
import com.devonfw.tools.ide.context.IdeTestContext;
import com.devonfw.tools.ide.log.IdeLogLevel;

Expand All @@ -18,17 +17,18 @@ public class EditionSetCommandletTest extends AbstractIdeContextTest {
public void testEditionSetCommandletRun() {

// arrange
IdeContext context = newContext(PROJECT_BASIC);
IdeTestContext context = newContext(PROJECT_BASIC);
EditionSetCommandlet editionSet = context.getCommandletManager().getCommandlet(EditionSetCommandlet.class);
editionSet.tool.setValueAsString("mvn", context);
editionSet.edition.setValueAsString("setEdition", context);
editionSet.tool.setValueAsString("docker", context);
editionSet.edition.setValueAsString("rancher", context);
assertThat(context.getVariables().getToolEdition("docker")).isEqualTo("docker");

// act
editionSet.run();

// assert
List<String> logs = ((IdeTestContext) context).level(IdeLogLevel.WARNING).getMessages();
assertThat(logs).containsExactly("Edition setEdition seems to be invalid");
assertThat(context.getVariables().getToolEdition("docker")).isEqualTo("rancher");
assertLogMessage(context, IdeLogLevel.INFO, "DOCKER_EDITION=rancher has been set in SETTINGS@", true);
Path settingsIdeProperties = context.getSettingsPath().resolve("ide.properties");
assertThat(settingsIdeProperties).hasContent("""
#********************************************************************************
Expand All @@ -49,6 +49,6 @@ public void testEditionSetCommandletRun() {
TEST_ARGS9=settings9
TEST_ARGSb=${TEST_ARGS10} settingsb ${TEST_ARGSa} ${TEST_ARGSb}
TEST_ARGSc=${TEST_ARGSc} settingsc
MVN_EDITION=setEdition""");
DOCKER_EDITION=rancher""");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://desktop.docker.com/mac/main/arm64/Docker.dmg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://desktop.docker.com/mac/main/amd64/Docker.dmg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://github.com/rancher-sandbox/rancher-desktop/releases/download/v1.14.2/rancher-desktop-linux-v1.14.2.zip
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2d304d3fe0dbf5efe987c2d583feeb607ce9ef507753fcf0a6b1a6b9b2128d1e
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://github.com/rancher-sandbox/rancher-desktop/releases/download/v1.14.2/Rancher.Desktop-1.14.2-mac.aarch64.zip
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0ce7cf58fecbf4ea99541f51401f95ba70053b390b51ae98b16265d1a450a517
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://github.com/rancher-sandbox/rancher-desktop/releases/download/v1.14.2/Rancher.Desktop-1.14.2.x86_64.dmg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
e764e335d1475f8bceb3fb6d1d1892b09d3c2bee3f34355ddab8a7e157c87452
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://github.com/rancher-sandbox/rancher-desktop/releases/download/v1.14.2/Rancher.Desktop.Setup.1.14.2.msi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
01f52b7a1ebcddeda01b6979ce3505b895fdcde2c5b57f18e4f8c4a593618f3f
Loading