Skip to content

Commit

Permalink
Allow architecture specific patches to be selected and stored
Browse files Browse the repository at this point in the history
  • Loading branch information
ddsharpe committed Oct 7, 2024
1 parent 324a049 commit ca44d80
Show file tree
Hide file tree
Showing 27 changed files with 459 additions and 322 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import com.oracle.weblogic.imagetool.cachestore.CacheStore;
import com.oracle.weblogic.imagetool.installer.InstallerType;
import com.oracle.weblogic.imagetool.logging.LoggingFacade;
import com.oracle.weblogic.imagetool.logging.LoggingFactory;
import com.oracle.weblogic.imagetool.util.BuildPlatform;
import com.oracle.weblogic.imagetool.util.Architecture;
import com.oracle.weblogic.imagetool.util.Utils;

/**
Expand All @@ -27,50 +29,40 @@ public class CachedFile {

private final String id;
private final String version;
private final String architecture;
private final Architecture architecture;

/**
* Represents a locally cached file.
*
* @param id cache ID (like installer type or patchId)
* @param version version number for the patch or installer.
* @param architecture the system architecture that this file/installer is applicable
* @param id cache ID (like installer type or patchId)
* @param version version number for the patch or installer.
* @param target the system architecture that this file/installer is applicable
*/
public CachedFile(String id, String version, String architecture) {
public CachedFile(String id, String version, Architecture target) {
Objects.requireNonNull(id, "key for the cached file cannot be null");
logger.entering(id, version, architecture);
logger.entering(id, version, target);
this.id = id;
this.version = version;
this.architecture = architecture;
this.architecture = target;
logger.exiting();
}

/**
* Represents a locally cached file.
*
* @param id cache ID (like installer type or patchId)
* @param version version number for the patch or installer.
* @param id cache ID (like installer type)
* @param version version number for the patch or installer.
* @param target the system architecture that this file/installer is applicable
*/
public CachedFile(String id, String version) {
this(id, version, null);
public CachedFile(InstallerType id, String version, Architecture target) {
this(id.toString(), version, target);
}

/**
* Represents a locally cached file.
*
* @param id cache ID (like installer type)
* @param version version number for the patch or installer.
* @param architecture the system architecture that this file/installer is applicable
*/
public CachedFile(InstallerType id, String version, String architecture) {
this(id.toString(), version, architecture);
}

/**
* Represents a locally cached file.
*
* @param id cache ID (like installer type)
* @param version version number for the patch or installer.
* @param id cache ID (like installer type)
* @param version version number for the patch or installer.
*/
public CachedFile(InstallerType id, String version) {
this(id.toString(), version, null);
Expand All @@ -87,10 +79,14 @@ public static boolean isFileOnDisk(String filePath) {
* @return the key to use for this cache entry, like xxxx_yyyy.
*/
public String getKey() {
return getCacheKey(architecture);
if (architecture == null) {
return getCacheKey(null);
} else {
return getCacheKey(architecture.toString());
}
}

private String getCacheKey(String architecture) {
private String getCacheKey(String arch) {
if (id.contains(CacheStore.CACHE_KEY_SEPARATOR)) {
return id;
}
Expand All @@ -99,13 +95,19 @@ private String getCacheKey(String architecture) {
key.append(id);
key.append(CacheStore.CACHE_KEY_SEPARATOR);
key.append(version);
if (architecture != null) {
if (arch != null) {
key.append(CacheStore.CACHE_KEY_SEPARATOR);
key.append(architecture);
key.append(arch);
}
return key.toString();
}

private List<String> getPossibleKeys(Architecture architecture) {
ArrayList<String> result = new ArrayList<>();
architecture.getAcceptableNames().forEach(name -> result.add(getCacheKey(name)));
return result;
}

/**
* Get the version number for this cache entry/file.
* @return the string version of this cached file.
Expand All @@ -118,7 +120,7 @@ public String getVersion() {
* Get the system architecture name for this cache entry/file.
* @return the system architecture name applicable fo this cached file.
*/
public String getArchitecture() {
public Architecture getArchitecture() {
return architecture;
}

Expand All @@ -136,30 +138,29 @@ public String getArchitecture() {
*/
public String resolve(CacheStore cacheStore) throws IOException {
// check entry exists in cache
String key = getKey();
logger.entering(key);
String filePath = cacheStore.getValueFromCache(key);
if (filePath == null) {
// The KEY for this CachedFile was not found in the local cache.
logger.fine("Unable to find cache entry for {0}", key);
String alternateKey;
if (getArchitecture() == null) {
// The user did not specify an architecture in the KEY and that key was not found in the cache.
// Try adding the local architecture to the key, and look for that entry.
alternateKey = getCacheKey(BuildPlatform.getPlatformName());
logger.fine("Trying local architecture: {0}", alternateKey);
} else {
// The user specified an architecture in the KEY, but that key was not found.
// Try removing the architecture from the key, and look for that entry.
alternateKey = getCacheKey(null);
logger.fine("Trying no-arch/generic architecture: {0}", alternateKey);
logger.entering();
String filePath = null;
List<String> keySearchOrder = new ArrayList<>();
if (getArchitecture() == null) {
// architecture was not specified, search for cache key with no arch first, then look for local arch
keySearchOrder.add(getCacheKey(null));
keySearchOrder.addAll(getPossibleKeys(Architecture.getLocalArchitecture()));
} else {
// architecture was specified, search for cache key with arch first, then look for no arch key
keySearchOrder.addAll(getPossibleKeys(getArchitecture()));
keySearchOrder.add(getCacheKey(null));
}
for (String key: keySearchOrder) {
logger.finer("Trying cache key {0}", key);
filePath = cacheStore.getValueFromCache(key);
if (filePath != null) {
logger.finer("Found cache key {0}", key);
break;
}
// second attempt to find a reasonable cache entry
filePath = cacheStore.getValueFromCache(alternateKey);
}

if (!isFileOnDisk(filePath)) {
throw new FileNotFoundException(Utils.getMessage("IMG-0011", key));
throw new FileNotFoundException(Utils.getMessage("IMG-0011", getKey()));
}

logger.exiting(filePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class AruPatch {
private String product;
private String release;
private String releaseName;
private int platform;
private String psuBundle;
private String downloadHost;
private String downloadPath;
Expand Down Expand Up @@ -95,6 +96,15 @@ public AruPatch releaseName(String value) {
return this;
}

public Integer platform() {
return platform;
}

public AruPatch platform(String value) {
platform = Integer.parseInt(value);
return this;
}

public String psuBundle() {
return psuBundle;
}
Expand Down Expand Up @@ -167,9 +177,9 @@ public boolean isCoherenceFeaturePack() {
* @throws XPathExpressionException if the document is not the expected format from ARU
*/
public static Stream<AruPatch> getPatches(Document patchList) throws XPathExpressionException {
// create list of all patches that apply to the Linux platform
// create list of all patches that apply (platforms 2000=generic, 226=amd64, 541=arm64)
NodeList nodeList = XPathUtil.nodelist(patchList,
"/results/patch[./platform[@id='2000' or @id='226']]");
"/results/patch[./platform[@id='2000' or @id='226' or @id='541']]");
Stream.Builder<AruPatch> result = Stream.builder();
for (int i = 0; i < nodeList.getLength(); i++) {
if (nodeList.item(i).getNodeType() == Node.ELEMENT_NODE) {
Expand All @@ -183,7 +193,8 @@ public static Stream<AruPatch> getPatches(Document patchList) throws XPathExpres
.psuBundle(XPathUtil.string(nodeList.item(i), "./psu_bundle"))
.access(XPathUtil.string(nodeList.item(i), "./access"))
.downloadHost(XPathUtil.string(nodeList.item(i), "./files/file/download_url/@host"))
.downloadPath(XPathUtil.string(nodeList.item(i), "./files/file/download_url/text()"));
.downloadPath(XPathUtil.string(nodeList.item(i), "./files/file/download_url/text()"))
.platform(XPathUtil.string(nodeList.item(i), "./platform/@id"));

int index = patch.downloadPath().indexOf("patch_file=");
if (index < 0) {
Expand All @@ -197,6 +208,7 @@ public static Stream<AruPatch> getPatches(Document patchList) throws XPathExpres
+ " desc:" + patch.description()
+ " rel:" + patch.release()
+ " product:" + patch.product()
+ " platform:" + patch.platform()
+ " relName:" + patch.releaseName()
+ " psu:" + patch.psuBundle()
+ " url:" + patch.downloadUrl());
Expand All @@ -220,16 +232,11 @@ public static Stream<AruPatch> getPatches(Document patchList) throws XPathExpres
*/
public static AruPatch selectPatch(List<AruPatch> patches, String providedVersion, String psuVersion,
String installerVersion)
throws VersionNotFoundException, MultiplePatchVersionsException {
throws VersionNotFoundException, PatchVersionException {

logger.entering(patches, providedVersion, psuVersion, installerVersion);
AruPatch selected = null;

if (patches.size() < 2) {
// 0 or 1 patch, fill in a patch version and just return what have
return selectPatchOffline(patches, providedVersion, psuVersion, installerVersion);
}

Map<String, AruPatch> patchMap = patches.stream().collect(Collectors
.toMap(AruPatch::version, aruPatch -> aruPatch));
// select the correct patch version (priority order: user provided version, PSU version, GA installer version)
Expand All @@ -249,40 +256,22 @@ public static AruPatch selectPatch(List<AruPatch> patches, String providedVersio

logger.exiting(selected);
if (selected == null) {
throw logger.throwing(new MultiplePatchVersionsException(patches.get(0).patchId(), patches));
throw logger.throwing(new PatchVersionException(patches.get(0).patchId(), patches));
} else {
logger.info("IMG-0099", selected.patchId(), selected.version(), selected.description());
return selected;
}
}

private static AruPatch selectPatchOffline(List<AruPatch> patches, String providedVersion, String psuVersion,
String installerVersion) throws VersionNotFoundException {
AruPatch result = null;

if (patches.isEmpty()) {
logger.fine("Patches list is empty");
} else if (patches.size() == 1) {
result = patches.get(0);
// if the version is filled in, we are working online and there is nothing more to do.
if (result.version() == null) {
// no version means the patch is from the cache. Set the version as best we can.
// TODO: this could be improved if the cache was improved to store patch version.
if (providedVersion != null) {
result.version(providedVersion);
} else if (psuVersion != null) {
result.version(psuVersion);
} else {
result.version(installerVersion);
}
} else if (providedVersion != null && !result.version().equals(providedVersion)) {
throw logger.throwing(new VersionNotFoundException(result.patchId(), providedVersion, patches));
} else {
logger.info("IMG-0099", result.patchId(), result.version(), result.description());
}
}
logger.exiting(result);
return result;
/**
* Return true if this patch is applicable to the target platform.
* Patch platform 2000 is generic and applicable to all platforms.
* @param aruPlatform the target ARU platform to check.
* @return true if this patch is applicable to the provided platform.
*/
public boolean isApplicableToTarget(int aruPlatform) {
// if this patch is for platform 2000, always return true, else return true if platforms are equal.
return platform == 2000 || platform == aruPlatform;
}

@Override
Expand Down
Loading

0 comments on commit ca44d80

Please sign in to comment.