From af989cc324f7e16c1812b69927792bc3452543c5 Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Wed, 14 Jan 2026 10:56:14 +0100 Subject: [PATCH] oci: defaultPlatform function Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- __tests__/oci/oci.test.ts | 24 +++++++++++++++++++- src/oci/oci.ts | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/__tests__/oci/oci.test.ts b/__tests__/oci/oci.test.ts index 803db122..684f88fe 100644 --- a/__tests__/oci/oci.test.ts +++ b/__tests__/oci/oci.test.ts @@ -14,14 +14,17 @@ * limitations under the License. */ -import {afterEach, describe, expect, test} from '@jest/globals'; +import {afterEach, describe, expect, jest, test} from '@jest/globals'; import fs from 'fs'; import os from 'os'; import path from 'path'; import * as rimraf from 'rimraf'; +import osm = require('os'); import {OCI} from '../../src/oci/oci'; +import {Platform} from '../../src/types/oci/descriptor'; + const fixturesDir = path.join(__dirname, '..', '.fixtures'); const tmpDir = fs.mkdtempSync(path.join(process.env.TEMP || os.tmpdir(), 'oci-oci-')); @@ -29,6 +32,25 @@ afterEach(function () { rimraf.sync(tmpDir); }); +describe('defaultPlatform', () => { + test.each([ + ['win32', 'x64', {architecture: 'amd64', os: 'windows'}], + ['win32', 'arm64', {architecture: 'arm64', os: 'windows'}], + ['darwin', 'x64', {architecture: 'amd64', os: 'darwin'}], + ['darwin', 'arm64', {architecture: 'arm64', os: 'darwin'}], + ['linux', 'ia32', {architecture: '386', os: 'linux'}], + ['linux', 'x64', {architecture: 'amd64', os: 'linux'}], + ['linux', 'arm64', {architecture: 'arm64', os: 'linux'}], + ['linux', 'ppc64', {architecture: 'ppc64le', os: 'linux'}], + ['linux', 's390x', {architecture: 's390x', os: 'linux'}] + ])('default platform for %s/%s', async (os: string, arch: string, expected: Platform) => { + jest.spyOn(osm, 'platform').mockImplementation(() => os as NodeJS.Platform); + jest.spyOn(osm, 'arch').mockImplementation(() => arch); + const res = OCI.defaultPlatform(); + expect(res).toEqual(expected); + }); +}); + describe('loadArchive', () => { // prettier-ignore test.each(fs.readdirSync(path.join(fixturesDir, 'oci-archive')).filter(file => { diff --git a/src/oci/oci.ts b/src/oci/oci.ts index dd9a83b2..da888b48 100644 --- a/src/oci/oci.ts +++ b/src/oci/oci.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import fs from 'fs'; +import os from 'os'; import gunzip from 'gunzip-maybe'; import * as path from 'path'; import {Readable} from 'stream'; @@ -21,12 +22,59 @@ import * as tar from 'tar-stream'; import {Archive, LoadArchiveOpts} from '../types/oci/oci'; import {Index} from '../types/oci'; +import {Platform} from '../types/oci/descriptor'; import {Manifest} from '../types/oci/manifest'; import {Image} from '../types/oci/config'; import {IMAGE_BLOBS_DIR_V1, IMAGE_INDEX_FILE_V1, IMAGE_LAYOUT_FILE_V1, ImageLayout} from '../types/oci/layout'; import {MEDIATYPE_IMAGE_INDEX_V1, MEDIATYPE_IMAGE_MANIFEST_V1} from '../types/oci/mediatype'; export class OCI { + public static defaultPlatform(): Platform { + const nodePlatform = os.platform(); + const nodeArch = os.arch(); + + const goosMap: Record = { + win32: 'windows', + sunos: 'solaris' + // others (linux, darwin, freebsd, openbsd, netbsd, aix, android) match Go already + }; + + const goArchMap: Record = { + x64: 'amd64', + ia32: '386', + arm: 'arm', + arm64: 'arm64', + ppc64: 'ppc64le', + s390x: 's390x', + riscv64: 'riscv64', + loong64: 'loong64', + mips: 'mips', + mipsel: 'mipsle', + mips64: 'mips64', + mips64el: 'mips64le' + }; + + const goos = goosMap[nodePlatform] ?? nodePlatform; + const goarch = goArchMap[nodeArch] ?? nodeArch; + + let variant: string | undefined; + if (goarch === 'arm') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const armVersionRaw = (process.config.variables as any)?.arm_version; + const armVersion = Number(armVersionRaw); + // Go only recognizes v5/v6/v7 for GOARM. Do not emit v8+ (that would be arm64). + if ([5, 6, 7].includes(armVersion)) { + variant = `v${armVersion}`; + } + } + + return { + architecture: goarch, + os: goos, + variant: variant + }; + } + public static loadArchive(opts: LoadArchiveOpts): Promise { return new Promise((resolve, reject) => { const tarex: tar.Extract = tar.extract();