Skip to content

Commit

Permalink
Allow simple ranges in package deps
Browse files Browse the repository at this point in the history
  • Loading branch information
dappnodedev committed Aug 12, 2024
1 parent bafd376 commit 4f7c653
Showing 1 changed file with 65 additions and 17 deletions.
82 changes: 65 additions & 17 deletions packages/installer/src/dappGet/fetch/DappGetFetcher.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Dependencies } from "@dappnode/types";
import { validRange, satisfies, valid } from "semver";
import { Dependencies, InstalledPackageData } from "@dappnode/types";
import { validRange, satisfies, valid, Range } from "semver";
import { DappnodeInstaller } from "../../dappnodeInstaller.js";
import { listPackageNoThrow } from "@dappnode/dockerapi";
import { listPackages } from "@dappnode/dockerapi";

export class DappGetFetcher {
/**
Expand All @@ -17,21 +17,11 @@ export class DappGetFetcher {
): Promise<Dependencies> {
const manifest = await dappnodeInstaller.getManifestFromDir(name, version);
const dependencies = manifest.dependencies || {};
const optionalDependencies = manifest.optionalDependencies || {};
const installedPackages = await listPackages();

const optionalDependencies = manifest.optionalDependencies;
if (optionalDependencies) {
// Iterate over optional dependencies and inject them if installed
for (const [
optionalDependencyName,
optionalDependencyVersion,
] of Object.entries(optionalDependencies)) {
const optionalDependency = await listPackageNoThrow({
dnpName: optionalDependencyName,
});
if (!optionalDependency) continue;
dependencies[optionalDependencyName] = optionalDependencyVersion;
}
}
this.mergeOptionalDependencies(dependencies, optionalDependencies, installedPackages);
this.filterSatisfiedDependencies(dependencies, installedPackages);

return dependencies;
}
Expand Down Expand Up @@ -81,4 +71,62 @@ export class DappGetFetcher {
// Case 3. unvalid semver version ("/ipfs/Qmre4..."): Asume it's the only version
return [versionRange];
}

private mergeOptionalDependencies(
dependencies: Dependencies,
optionalDependencies: Dependencies,
installedPackages: InstalledPackageData[]
): void {
for (const [optionalDepName, optionalDepVersion] of Object.entries(optionalDependencies)) {
const isInstalled = installedPackages.some(
(installedPackage) => installedPackage.dnpName === optionalDepName
);

if (isInstalled) {
dependencies[optionalDepName] = optionalDepVersion;
}
}
}

private filterSatisfiedDependencies(
dependencies: Dependencies,
installedPackages: InstalledPackageData[]
): void {
for (const [depName, depVersion] of Object.entries(dependencies)) {
const installedPackage = installedPackages.find(
(pkg) => pkg.dnpName === depName
);

if (!validRange(depVersion))
throw new Error(`Invalid semver notation for dependency ${depName}: ${depVersion}`);

if (depVersion.includes('||') || depVersion.includes(' ')) {
throw new Error(`Unsupported version range for dependency ${depName}: ${depVersion}. Only simple ranges are supported`);
}

if (installedPackage && satisfies(installedPackage.version, depVersion)) {
console.log(
`Dependency ${depName} is already installed with version ${installedPackage.version}`
);
// Remove the dependency if the installed version satisfies the required version
delete dependencies[depName];
} else {

// Use "*" (latest) if the dependency is not installed and version is >... or >=...
if (!installedPackage && /^>=?\d+\.\d+\.\d+$/.test(depVersion)) {
dependencies[depName] = '*';

// Use x.x.x if the dependency is not installed and version is ^x.x.x or ~x.x.x
} else if (!installedPackage && /^[\^~]\d+\.\d+\.\d+$/.test(depVersion)) {

// Remove the operator prefix and use the defined version
dependencies[depName] = depVersion.slice(1);

} else {

throw new Error(`Unsupported version range for dependency ${depName}: ${depVersion}. Only simle ranges with operators ^, ~, > and >= are supported`);
}
}
}
}
}

0 comments on commit 4f7c653

Please sign in to comment.