Skip to content

Commit

Permalink
Merge pull request #484 from psmf22/tool_debricked
Browse files Browse the repository at this point in the history
feat: tool debricked commands
  • Loading branch information
psmf22 authored Dec 6, 2023
2 parents 51861c8 + 115cfdf commit 15eee0d
Show file tree
Hide file tree
Showing 21 changed files with 362 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@
import java.security.NoSuchAlgorithmException;
import java.util.Comparator;
import java.util.stream.Stream;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;

// TODO For now, methods provided in this class are only used by the tools module,
// but potentially some methods or the full class could be moved to the common module.
Expand Down Expand Up @@ -95,6 +98,23 @@ public static final void extractZip(File zipFile, Path targetDir) throws IOExcep
}
}

public static final void extractTarGZ(File tgzFile, Path targetDir) throws IOException {
try (InputStream source = Files.newInputStream(tgzFile.toPath());
GZIPInputStream gzip = new GZIPInputStream(source);
TarArchiveInputStream tar = new TarArchiveInputStream(gzip)) {

TarArchiveEntry entry;
while ((entry = tar.getNextEntry()) != null) {
Path extractTo = targetDir.resolve(entry.getName());
if(entry.isDirectory()) {
Files.createDirectories(extractTo);
} else {
Files.copy(tar, extractTo);
}
}
}
}

public static final void deleteRecursive(Path installPath) throws IOException {
try (Stream<Path> walk = Files.walk(installPath)) {
walk.sorted(Comparator.reverseOrder())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ private static enum DigestMismatchAction {
@Override
public final JsonNode getJsonNode() {
String toolName = getToolName();
ToolVersionDownloadDescriptor descriptor = ToolHelper.getToolDownloadDescriptor(toolName).getVersionOrDefault(version);
ToolVersionDownloadDescriptor descriptor = ToolHelper.getToolDownloadDescriptor(toolName).getVersionOrDefault(version, getCpuArchitecture());
return downloadAndInstall(toolName, descriptor);
}

Expand Down Expand Up @@ -118,6 +118,7 @@ protected void install(ToolVersionInstallDescriptor descriptor, File downloadedF
// TODO Clean this up
case COPY: Files.copy(downloadedFile.toPath(), installPath.resolve(StringUtils.substringAfterLast(descriptor.getOriginalDownloadDescriptor().getDownloadUrl(), "/")), StandardCopyOption.REPLACE_EXISTING); break;
case EXTRACT_ZIP: FileUtils.extractZip(downloadedFile, installPath); break;
case EXTRACT_TGZ: FileUtils.extractTarGZ(downloadedFile, installPath); break;
default: throw new RuntimeException("Unknown install type: "+installType.name());
}
downloadedFile.delete();
Expand All @@ -140,6 +141,9 @@ protected Path getBinPath(ToolVersionDownloadDescriptor descriptor) {
protected abstract String getToolName();
protected abstract InstallType getInstallType();
protected abstract void postInstall(ToolVersionInstallDescriptor installDescriptor) throws IOException;
protected String getCpuArchitecture() {
return "";
}

private final void emptyExistingInstallPath(Path installPath) throws IOException {
if ( Files.exists(installPath) && Files.list(installPath).findFirst().isPresent() ) {
Expand Down Expand Up @@ -178,6 +182,6 @@ private static final void updateFilePermissions(Path p) {
}

protected static enum InstallType {
EXTRACT_ZIP, COPY
EXTRACT_ZIP, EXTRACT_TGZ, COPY
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public abstract class AbstractToolUninstallCommand extends AbstractOutputCommand
@Override
public final JsonNode getJsonNode() {
String toolName = getToolName();
ToolVersionCombinedDescriptor descriptor = ToolHelper.loadToolVersionCombinedDescriptor(toolName, version);
ToolVersionCombinedDescriptor descriptor = ToolHelper.loadToolVersionCombinedDescriptor(toolName, version, getCpuArchitecture());
if ( descriptor==null ) {
throw new IllegalArgumentException("Tool installation not found");
}
Expand Down Expand Up @@ -67,4 +67,7 @@ public boolean isSingular() {
}

protected abstract String getToolName();
protected String getCpuArchitecture() {
return "";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
public class ToolDownloadDescriptor {
private String defaultDownloadUrl;
private String defaultVersion;
private String defaultOperatingSystem;
private String defaultCpuArchitecture;
private ToolVersionDownloadDescriptor[] versions;

public final ToolVersionDownloadDescriptor[] getVersions() {
Expand All @@ -37,32 +39,62 @@ public final Stream<ToolVersionDownloadDescriptor> getVersionsStream() {
.map(this::addIsDefaultVersion);
}

public final ToolVersionDownloadDescriptor getVersion(String version) {
public final ToolVersionDownloadDescriptor getVersion(String version, String cpuArchitecture) {
var lookupVersion = (version.replaceFirst("^v", "")+".").replaceFirst("\\.\\.$", ".");
return getVersionsStream()
.filter(v->(v.getVersion()+".").startsWith(lookupVersion))
.findFirst().orElseThrow(()->new IllegalArgumentException("Version "+version+" not defined"));
var osString = getOSString();
var versionResult = getVersionsStream()
.filter(v->(v.getVersion()+".").startsWith(lookupVersion) &&
(v.getCpuArchitecture()==null || v.getCpuArchitecture().equals(cpuArchitecture)) &&
(v.getOperatingSystem()==null || v.getOperatingSystem().equals(osString)))
.findFirst();
if (versionResult.isPresent()) {
return versionResult.get();
} else {
if(cpuArchitecture==null) {
throw new IllegalArgumentException("Version "+version+" not defined");
} else {
throw new IllegalArgumentException("Version "+version+" not defined for architecture "+cpuArchitecture);
}
}
}

public final ToolVersionDownloadDescriptor getVersionOrDefault(String versionName) {
public final ToolVersionDownloadDescriptor getVersionOrDefault(String versionName, String cpuArchitecture) {
if ( StringUtils.isBlank(versionName) || "default".equals(versionName) || "latest".equals(versionName) ) {
versionName = defaultVersion;
}
return getVersion(versionName);
return getVersion(versionName, cpuArchitecture);
}

private final ToolVersionDownloadDescriptor updateDownloadUrl(ToolVersionDownloadDescriptor versionDescriptor) {
if ( StringUtils.isBlank(versionDescriptor.getDownloadUrl()) ) {
versionDescriptor.setDownloadUrl(defaultDownloadUrl);
}
versionDescriptor.setDownloadUrl(versionDescriptor.getDownloadUrl().replaceAll("\\{toolVersion\\}", versionDescriptor.getVersion()));
versionDescriptor.setDownloadUrl(versionDescriptor.getDownloadUrl().replaceAll("\\{operatingSystem\\}", versionDescriptor.getOperatingSystem()));
versionDescriptor.setDownloadUrl(versionDescriptor.getDownloadUrl().replaceAll("\\{cpuArchitecture\\}", versionDescriptor.getCpuArchitecture()));
return versionDescriptor;
}

private final ToolVersionDownloadDescriptor addIsDefaultVersion(ToolVersionDownloadDescriptor versionDescriptor) {
if ( versionDescriptor.getVersion().equals(defaultVersion) ) {
if ( versionDescriptor.getVersion().equals(defaultVersion) &&
(versionDescriptor.getOperatingSystem()==null || versionDescriptor.getOperatingSystem().equals(defaultOperatingSystem)) &&
(versionDescriptor.getCpuArchitecture()==null || versionDescriptor.getCpuArchitecture().equals(defaultCpuArchitecture))) {
versionDescriptor.setIsDefaultVersion("Yes");
}
return versionDescriptor;
}

private final String getOSString() {
String OS = System.getProperty("os.name", "generic").toLowerCase();
if ((OS.indexOf("mac") >= 0) || (OS.indexOf("darwin") >= 0)) {
return "macOS";
} else if (OS.indexOf("win") >= 0) {
return "windows";
} else if (OS.indexOf("nux") >= 0) {
return "linux";
} else {
throw new RuntimeException("Unexpected OS detected: '" + OS + "'");
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ public static final ToolVersionInstallDescriptor loadToolVersionInstallDescripto
return FcliDataHelper.readFile(getInstallDescriptorPath(toolName, version), ToolVersionInstallDescriptor.class, false);
}

public static final ToolVersionCombinedDescriptor loadToolVersionCombinedDescriptor(String toolName, String version) {
version = getToolDownloadDescriptor(toolName).getVersionOrDefault(version).getVersion();
public static final ToolVersionCombinedDescriptor loadToolVersionCombinedDescriptor(String toolName, String version, String cpuArchitecture) {
version = getToolDownloadDescriptor(toolName).getVersionOrDefault(version, cpuArchitecture).getVersion();
ToolVersionInstallDescriptor installDescriptor = loadToolVersionInstallDescriptor(toolName, version);
return installDescriptor==null ? null : new ToolVersionCombinedDescriptor(toolName, getToolDownloadDescriptor(toolName).getVersion(version), installDescriptor);
return installDescriptor==null ? null : new ToolVersionCombinedDescriptor(toolName, getToolDownloadDescriptor(toolName).getVersion(version, cpuArchitecture), installDescriptor);
}

public static final void deleteToolVersionInstallDescriptor(String toolName, String version) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ public Path getBinPath() {
return getPath(ToolVersionInstallDescriptor::getBinPath);
}

public String getOperatingSystem() {
return getDownloadDescriptor().getOperatingSystem();
}

public String getCpuArchitecture() {
return getDownloadDescriptor().getCpuArchitecture();
}

private String getDir(Function<ToolVersionInstallDescriptor, String> f) {
if ( installDescriptor!=null ) {
String dir = f.apply(installDescriptor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public final class ToolVersionDownloadDescriptor {
private String downloadUrl;
private String digest;
private String isDefaultVersion = "No";
private String operatingSystem;
private String cpuArchitecture;

@JsonIgnore
public final String getDigestAlgorithm() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import com.fortify.cli.common.cli.cmd.AbstractContainerCommand;
import com.fortify.cli.tool.bugtracker_utility.cli.cmd.ToolBugTrackerUtilityCommands;
import com.fortify.cli.tool.debricked.cli.cmd.ToolDebrickedCommands;
import com.fortify.cli.tool.fod_uploader.cli.cmd.ToolFoDUploaderCommands;
import com.fortify.cli.tool.sc_client.cli.cmd.ToolSCClientCommands;
import com.fortify.cli.tool.vuln_exporter.cli.cmd.ToolVulnExporterCommands;
Expand All @@ -25,6 +26,7 @@
resourceBundle = "com.fortify.cli.tool.i18n.ToolMessages",
subcommands = {
ToolBugTrackerUtilityCommands.class,
ToolDebrickedCommands.class,
ToolFoDUploaderCommands.class,
ToolSCClientCommands.class,
ToolVulnExporterCommands.class
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright 2021, 2022 Open Text.
*
* The only warranties for products and services of Open Text
* and its affiliates and licensors ("Open Text") are as may
* be set forth in the express warranty statements accompanying
* such products and services. Nothing herein should be construed
* as constituting an additional warranty. Open Text shall not be
* liable for technical or editorial errors or omissions contained
* herein. The information contained herein is subject to change
* without notice.
*******************************************************************************/
package com.fortify.cli.tool.debricked.cli.cmd;

import com.fortify.cli.common.cli.cmd.AbstractContainerCommand;

import picocli.CommandLine.Command;

@Command(
name = ToolDebrickedCommands.TOOL_NAME,
subcommands = {
ToolDebrickedInstallCommand.class,
ToolDebrickedListCommand.class,
ToolDebrickedUninstallCommand.class
}

)
public class ToolDebrickedCommands extends AbstractContainerCommand {
static final String TOOL_NAME = "debricked";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright 2021, 2023 Open Text.
*
* The only warranties for products and services of Open Text
* and its affiliates and licensors ("Open Text") are as may
* be set forth in the express warranty statements accompanying
* such products and services. Nothing herein should be construed
* as constituting an additional warranty. Open Text shall not be
* liable for technical or editorial errors or omissions contained
* herein. The information contained herein is subject to change
* without notice.
*******************************************************************************/
package com.fortify.cli.tool.debricked.cli.cmd;

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

import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins;
import com.fortify.cli.tool._common.cli.cmd.AbstractToolInstallCommand;
import com.fortify.cli.tool._common.helper.ToolVersionInstallDescriptor;

import lombok.Getter;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;

@Command(name = OutputHelperMixins.Install.CMD_NAME)
public class ToolDebrickedInstallCommand extends AbstractToolInstallCommand {
@Getter @Mixin private OutputHelperMixins.Install outputHelper;
@Getter private String toolName = ToolDebrickedCommands.TOOL_NAME;
@Getter @Option(names={"-a", "--cpuArchitecture"}, required = true, descriptionKey="fcli.tool.debricked.install.cpuArchitecture", defaultValue = "x86_64")
private String _cpuArchitecture;

@Override
protected InstallType getInstallType() {
return InstallType.EXTRACT_TGZ;
}

@Override
protected void postInstall(ToolVersionInstallDescriptor descriptor) throws IOException {
Path binPath = descriptor.getBinPath();
Files.createDirectories(binPath);
}

@Override
protected String getCpuArchitecture() {
return _cpuArchitecture;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright 2021, 2023 Open Text.
*
* The only warranties for products and services of Open Text
* and its affiliates and licensors ("Open Text") are as may
* be set forth in the express warranty statements accompanying
* such products and services. Nothing herein should be construed
* as constituting an additional warranty. Open Text shall not be
* liable for technical or editorial errors or omissions contained
* herein. The information contained herein is subject to change
* without notice.
*******************************************************************************/
package com.fortify.cli.tool.debricked.cli.cmd;

import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins;
import com.fortify.cli.tool._common.cli.cmd.AbstractToolListCommand;

import lombok.Getter;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;

@Command(name = OutputHelperMixins.List.CMD_NAME)
public class ToolDebrickedListCommand extends AbstractToolListCommand {
@Getter @Mixin private OutputHelperMixins.List outputHelper;
@Getter private String toolName = ToolDebrickedCommands.TOOL_NAME;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright 2021, 2023 Open Text.
*
* The only warranties for products and services of Open Text
* and its affiliates and licensors ("Open Text") are as may
* be set forth in the express warranty statements accompanying
* such products and services. Nothing herein should be construed
* as constituting an additional warranty. Open Text shall not be
* liable for technical or editorial errors or omissions contained
* herein. The information contained herein is subject to change
* without notice.
*******************************************************************************/
package com.fortify.cli.tool.debricked.cli.cmd;

import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins;
import com.fortify.cli.tool._common.cli.cmd.AbstractToolUninstallCommand;

import lombok.Getter;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;

@Command(name = OutputHelperMixins.Uninstall.CMD_NAME)
public class ToolDebrickedUninstallCommand extends AbstractToolUninstallCommand {
@Getter @Mixin private OutputHelperMixins.Uninstall outputHelper;
@Getter private String toolName = ToolDebrickedCommands.TOOL_NAME;
@Getter @Option(names={"-a", "--cpuArchitecture"}, required = true, descriptionKey="fcli.tool.debricked.uninstall.cpuArchitecture", defaultValue = "x86_64")
private String _cpuArchitecture;

@Override
protected String getCpuArchitecture() {
return _cpuArchitecture;
}
}
Loading

0 comments on commit 15eee0d

Please sign in to comment.