mirror of
https://github.com/podman-desktop/podman-desktop
synced 2026-04-21 17:47:22 +00:00
chore: use podman v5 installer by default
no more v4/v5 installation path, only v5 Also updates the airgapped archive to include the v5 one and not the v4 fixes https://github.com/containers/podman-desktop/issues/6360 Signed-off-by: Florent Benoit <fbenoit@redhat.com>
This commit is contained in:
parent
3c015df03e
commit
0b77cf2d6b
10 changed files with 80 additions and 464 deletions
|
|
@ -101,10 +101,10 @@ const config = {
|
|||
context.packager.config.extraResources.push('extensions/podman/assets/podman-*.exe');
|
||||
}
|
||||
if (context.arch === Arch.x64 && context.electronPlatformName === 'win32') {
|
||||
context.packager.config.extraResources.push('extensions/podman/assets/podman-image-x64.tar.xz');
|
||||
context.packager.config.extraResources.push('extensions/podman/assets/podman-image-x64.tar.zst');
|
||||
}
|
||||
if (context.arch === Arch.arm64 && context.electronPlatformName === 'win32') {
|
||||
context.packager.config.extraResources.push('extensions/podman/assets/podman-image-arm64.tar.xz');
|
||||
context.packager.config.extraResources.push('extensions/podman/assets/podman-image-arm64.tar.zst');
|
||||
}
|
||||
},
|
||||
afterPack: async context => {
|
||||
|
|
|
|||
|
|
@ -51,11 +51,6 @@
|
|||
"default": "",
|
||||
"description": "Custom path to Podman binary (Default is blank)"
|
||||
},
|
||||
"podman.experimental.install.v5": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable podman v5 installation support (experimental)"
|
||||
},
|
||||
"podman.machine.cpus": {
|
||||
"type": "number",
|
||||
"format": "cpu",
|
||||
|
|
|
|||
|
|
@ -19,11 +19,7 @@
|
|||
|
||||
import { PodmanDownload } from './podman-download';
|
||||
|
||||
import * as podman4JSON from '../src/podman4.json';
|
||||
import * as podman5JSON from '../src/podman5.json';
|
||||
|
||||
const podman4Download = new PodmanDownload(podman4JSON, true);
|
||||
await podman4Download.downloadBinaries();
|
||||
|
||||
const podman5Download = new PodmanDownload(podman5JSON, true);
|
||||
await podman5Download.downloadBinaries();
|
||||
|
|
|
|||
|
|
@ -20,40 +20,36 @@ import { afterEach } from 'node:test';
|
|||
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
import {
|
||||
DownloadAndCheck,
|
||||
Podman5DownloadFedoraImage,
|
||||
Podman5DownloadMachineOS,
|
||||
PodmanDownload,
|
||||
PodmanDownloadFcosImage,
|
||||
PodmanDownloadFedoraImage,
|
||||
ShaCheck,
|
||||
} from './podman-download';
|
||||
import * as podman4JSON from '../src/podman4.json';
|
||||
import * as podman5JSON from '../src/podman5.json';
|
||||
import nock from 'nock';
|
||||
import { WriteStream, appendFileSync, createWriteStream, existsSync, mkdirSync } from 'node:fs';
|
||||
import { appendFileSync, existsSync, mkdirSync } from 'node:fs';
|
||||
import { Octokit } from 'octokit';
|
||||
import { PassThrough, Readable, Writable } from 'node:stream';
|
||||
import { WritableStream, WritableStreamDefaultWriter } from 'stream/web';
|
||||
import path from 'node:path';
|
||||
import { tmpdir } from 'node:os';
|
||||
import exp from 'node:constants';
|
||||
import { Readable, Writable } from 'node:stream';
|
||||
import { WritableStream } from 'stream/web';
|
||||
|
||||
const mockedPodman4 = {
|
||||
version: '4.5.0',
|
||||
const mockedPodman5 = {
|
||||
version: '5.0.0',
|
||||
platform: {
|
||||
win32: {
|
||||
version: 'v4.5.0',
|
||||
fileName: 'podman-4.5.0-setup.exe',
|
||||
version: 'v5.0.0',
|
||||
fileName: 'podman-5.0.0-setup.exe',
|
||||
},
|
||||
darwin: {
|
||||
version: 'v4.5.0',
|
||||
version: 'v5.0.0',
|
||||
arch: {
|
||||
x64: {
|
||||
fileName: 'podman-installer-macos-amd64-v4.5.0.pkg',
|
||||
fileName: 'podman-installer-macos-amd64-v5.0.0.pkg',
|
||||
},
|
||||
arm64: {
|
||||
fileName: 'podman-installer-macos-aarch64-v4.5.0.pkg',
|
||||
fileName: 'podman-installer-macos-aarch64-v5.0.0.pkg',
|
||||
},
|
||||
universal: {
|
||||
fileName: 'podman-installer-macos-universal-v4.5.0.pkg',
|
||||
fileName: 'podman-installer-macos-universal-v5.0.0.pkg',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -61,12 +57,12 @@ const mockedPodman4 = {
|
|||
};
|
||||
|
||||
class TestPodmanDownload extends PodmanDownload {
|
||||
public getPodmanDownloadFcosImage(): PodmanDownloadFcosImage {
|
||||
return super.getPodmanDownloadFcosImage();
|
||||
public getPodman5DownloadFedoraImage(): Podman5DownloadFedoraImage {
|
||||
return super.getPodman5DownloadFedoraImage();
|
||||
}
|
||||
|
||||
public getPodmanDownloadFedoraImage(): PodmanDownloadFedoraImage {
|
||||
return super.getPodmanDownloadFedoraImage();
|
||||
public getPodman5DownloadMachineOS(): Podman5DownloadMachineOS {
|
||||
return super.getPodman5DownloadMachineOS();
|
||||
}
|
||||
|
||||
public getShaCheck(): ShaCheck {
|
||||
|
|
@ -100,17 +96,17 @@ describe('macOS platform', () => {
|
|||
});
|
||||
|
||||
test('PodmanDownload with real json', async () => {
|
||||
const podmanDownload = new TestPodmanDownload(podman4JSON, true);
|
||||
const podmanDownload = new TestPodmanDownload(podman5JSON, true);
|
||||
|
||||
// mock downloadAndCheckSha
|
||||
const downloadCheck = podmanDownload.getDownloadAndCheck();
|
||||
const downloadAndCheckShaSpy = vi.spyOn(downloadCheck, 'downloadAndCheckSha');
|
||||
downloadAndCheckShaSpy.mockResolvedValue();
|
||||
|
||||
// mock podmanDownloadFcosImage
|
||||
const podmanDownloadFcosImage = podmanDownload.getPodmanDownloadFcosImage();
|
||||
const podmanDownloadFcosImageSpy = vi.spyOn(podmanDownloadFcosImage, 'download');
|
||||
podmanDownloadFcosImageSpy.mockResolvedValue();
|
||||
// mock podman5DownloadMachineOS
|
||||
const podman5DownloadMachineOS = podmanDownload.getPodman5DownloadMachineOS();
|
||||
const podman5DownloadMachineOSSpy = vi.spyOn(podman5DownloadMachineOS, 'download');
|
||||
podman5DownloadMachineOSSpy.mockResolvedValue();
|
||||
|
||||
// add env file
|
||||
process.env.AIRGAP_DOWNLOAD = 'yes';
|
||||
|
|
@ -118,28 +114,26 @@ describe('macOS platform', () => {
|
|||
await podmanDownload.downloadBinaries();
|
||||
|
||||
// check called 2 times
|
||||
expect(downloadAndCheckShaSpy).toHaveBeenCalledTimes(2);
|
||||
expect(downloadAndCheckShaSpy).toHaveBeenCalledTimes(3);
|
||||
|
||||
// check called with the correct parameters
|
||||
expect(downloadAndCheckShaSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('v4.'),
|
||||
expect.stringContaining('v5.'),
|
||||
expect.stringContaining('podman-installer-macos-amd64'),
|
||||
'podman-installer-macos-amd64.pkg',
|
||||
);
|
||||
expect(downloadAndCheckShaSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('v4.'),
|
||||
expect.stringContaining('v5.'),
|
||||
expect.stringContaining('podman-installer-macos-aarch64'),
|
||||
'podman-installer-macos-arm64.pkg',
|
||||
);
|
||||
|
||||
// check airgap download
|
||||
expect(podmanDownloadFcosImageSpy).toHaveBeenCalled();
|
||||
expect(podmanDownloadFcosImageSpy).toHaveBeenCalledWith('arm64');
|
||||
expect(podmanDownloadFcosImageSpy).toHaveBeenCalledWith('x64');
|
||||
expect(podman5DownloadMachineOSSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('PodmanDownload with mocked json', async () => {
|
||||
const podmanDownload = new TestPodmanDownload(mockedPodman4, false);
|
||||
const podmanDownload = new TestPodmanDownload(mockedPodman5, false);
|
||||
|
||||
// mock downloadAndCheckSha
|
||||
const downloadCheck = podmanDownload.getDownloadAndCheck();
|
||||
|
|
@ -154,20 +148,20 @@ describe('macOS platform', () => {
|
|||
// check called with the correct parameters
|
||||
expect(downloadAndCheckShaSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'v4.5.0',
|
||||
'podman-installer-macos-amd64-v4.5.0.pkg',
|
||||
'v5.0.0',
|
||||
'podman-installer-macos-amd64-v5.0.0.pkg',
|
||||
'podman-installer-macos-amd64.pkg',
|
||||
);
|
||||
expect(downloadAndCheckShaSpy).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'v4.5.0',
|
||||
'podman-installer-macos-aarch64-v4.5.0.pkg',
|
||||
'v5.0.0',
|
||||
'podman-installer-macos-aarch64-v5.0.0.pkg',
|
||||
'podman-installer-macos-arm64.pkg',
|
||||
);
|
||||
expect(downloadAndCheckShaSpy).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
'v4.5.0',
|
||||
'podman-installer-macos-universal-v4.5.0.pkg',
|
||||
'v5.0.0',
|
||||
'podman-installer-macos-universal-v5.0.0.pkg',
|
||||
'podman-installer-macos-universal.pkg',
|
||||
);
|
||||
});
|
||||
|
|
@ -192,7 +186,7 @@ describe('windows platform', () => {
|
|||
});
|
||||
|
||||
test('PodmanDownload with real data', async () => {
|
||||
const podmanDownload = new TestPodmanDownload(podman4JSON, true);
|
||||
const podmanDownload = new TestPodmanDownload(podman5JSON, true);
|
||||
|
||||
// mock downloadAndCheckSha
|
||||
const downloadCheck = podmanDownload.getDownloadAndCheck();
|
||||
|
|
@ -203,9 +197,9 @@ describe('windows platform', () => {
|
|||
process.env.AIRGAP_DOWNLOAD = 'yes';
|
||||
|
||||
// mock podmanDownloadFedoraImage
|
||||
const podmanDownloadFedoraImage = podmanDownload.getPodmanDownloadFedoraImage();
|
||||
const podmanDownloadFedoraImageSpy = vi.spyOn(podmanDownloadFedoraImage, 'download');
|
||||
podmanDownloadFedoraImageSpy.mockResolvedValue();
|
||||
const podman5DownloadFedoraImage = podmanDownload.getPodman5DownloadFedoraImage();
|
||||
const podman5DownloadFedoraImageSpy = vi.spyOn(podman5DownloadFedoraImage, 'download');
|
||||
podman5DownloadFedoraImageSpy.mockResolvedValue();
|
||||
|
||||
await podmanDownload.downloadBinaries();
|
||||
|
||||
|
|
@ -214,27 +208,27 @@ describe('windows platform', () => {
|
|||
|
||||
// check called with the correct parameters
|
||||
expect(downloadAndCheckShaSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('v4.'),
|
||||
expect.stringContaining('v5.'),
|
||||
expect.stringContaining('-setup.exe'),
|
||||
expect.stringContaining('-setup.exe'),
|
||||
);
|
||||
|
||||
// check airgap download
|
||||
expect(podmanDownloadFedoraImageSpy).toHaveBeenCalled();
|
||||
expect(podmanDownloadFedoraImageSpy).toHaveBeenCalledWith('podman-wsl-fedora', 'x64');
|
||||
expect(podmanDownloadFedoraImageSpy).toHaveBeenCalledWith('podman-wsl-fedora-arm', 'arm64');
|
||||
expect(podman5DownloadFedoraImageSpy).toHaveBeenCalled();
|
||||
expect(podman5DownloadFedoraImageSpy).toHaveBeenCalledWith('x64');
|
||||
expect(podman5DownloadFedoraImageSpy).toHaveBeenCalledWith('arm64');
|
||||
});
|
||||
|
||||
test('PodmanDownload with mocked json', async () => {
|
||||
const podmanDownload = new TestPodmanDownload(mockedPodman4, false);
|
||||
const podmanDownload = new TestPodmanDownload(mockedPodman5, false);
|
||||
|
||||
// mock downloadAndCheckSha
|
||||
const downloadCheck = podmanDownload.getDownloadAndCheck();
|
||||
const downloadAndCheckShaSpy = vi.spyOn(downloadCheck, 'downloadAndCheckSha');
|
||||
downloadAndCheckShaSpy.mockResolvedValue();
|
||||
|
||||
const podmanDownloadFedoraImage = podmanDownload.getPodmanDownloadFedoraImage();
|
||||
const podmanDownloadFedoraImageSpy = vi.spyOn(podmanDownloadFedoraImage, 'download');
|
||||
const podman5DownloadFedoraImage = podmanDownload.getPodman5DownloadFedoraImage();
|
||||
const podmanDownloadFedoraImageSpy = vi.spyOn(podman5DownloadFedoraImage, 'download');
|
||||
|
||||
await podmanDownload.downloadBinaries();
|
||||
|
||||
|
|
@ -244,9 +238,9 @@ describe('windows platform', () => {
|
|||
// check called with the correct parameters
|
||||
expect(downloadAndCheckShaSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'v4.5.0',
|
||||
'podman-4.5.0-setup.exe',
|
||||
'podman-4.5.0-setup.exe',
|
||||
'v5.0.0',
|
||||
'podman-5.0.0-setup.exe',
|
||||
'podman-5.0.0-setup.exe',
|
||||
);
|
||||
|
||||
// check no airgap download
|
||||
|
|
|
|||
|
|
@ -30,15 +30,11 @@ export class PodmanDownload {
|
|||
#podmanVersion: string;
|
||||
|
||||
#downloadAndCheck: DownloadAndCheck;
|
||||
#podmanDownloadFcosImage: PodmanDownloadFcosImage;
|
||||
#podmanDownloadFedoraImage: PodmanDownloadFedoraImage;
|
||||
#podman5DownloadFedoraImage: Podman5DownloadFedoraImage | undefined;
|
||||
#podman5DownloadMachineOS: Podman5DownloadMachineOS | undefined;
|
||||
#podman5DownloadFedoraImage: Podman5DownloadFedoraImage;
|
||||
#podman5DownloadMachineOS: Podman5DownloadMachineOS;
|
||||
|
||||
#shaCheck: ShaCheck;
|
||||
|
||||
#httpsDownloader: HttpsDownloader;
|
||||
|
||||
#octokit: Octokit;
|
||||
#platform: string;
|
||||
#assetsFolder: string;
|
||||
|
|
@ -108,46 +104,34 @@ export class PodmanDownload {
|
|||
}
|
||||
}
|
||||
this.#shaCheck = new ShaCheck();
|
||||
this.#httpsDownloader = new HttpsDownloader();
|
||||
this.#podmanDownloadFcosImage = new PodmanDownloadFcosImage(
|
||||
this.#httpsDownloader,
|
||||
this.#shaCheck,
|
||||
this.#assetsFolder,
|
||||
);
|
||||
this.#podmanDownloadFedoraImage = new PodmanDownloadFedoraImage(
|
||||
this.#octokit,
|
||||
this.#httpsDownloader,
|
||||
this.#assetsFolder,
|
||||
);
|
||||
|
||||
this.#downloadAndCheck = new DownloadAndCheck(this.#octokit, this.#shaCheck, this.#assetsFolder);
|
||||
if (!fs.existsSync(this.#assetsFolder)) {
|
||||
fs.mkdirSync(this.#assetsFolder);
|
||||
}
|
||||
|
||||
if (podmanJSON.version.startsWith('5.')) {
|
||||
// grab only first 2 digits from the version
|
||||
const majorMinorVersion = podmanJSON.version.split('.').slice(0, 2).join('.');
|
||||
// grab only first 2 digits from the version
|
||||
const majorMinorVersion = podmanJSON.version.split('.').slice(0, 2).join('.');
|
||||
|
||||
this.#podman5DownloadFedoraImage = new Podman5DownloadFedoraImage(
|
||||
majorMinorVersion,
|
||||
this.#octokit,
|
||||
this.#downloadAndCheck,
|
||||
);
|
||||
this.#podman5DownloadFedoraImage = new Podman5DownloadFedoraImage(
|
||||
majorMinorVersion,
|
||||
this.#octokit,
|
||||
this.#downloadAndCheck,
|
||||
);
|
||||
|
||||
this.#podman5DownloadMachineOS = new Podman5DownloadMachineOS(
|
||||
majorMinorVersion,
|
||||
this.#shaCheck,
|
||||
this.#assetsFolder,
|
||||
);
|
||||
}
|
||||
this.#podman5DownloadMachineOS = new Podman5DownloadMachineOS(
|
||||
majorMinorVersion,
|
||||
this.#shaCheck,
|
||||
this.#assetsFolder,
|
||||
);
|
||||
}
|
||||
|
||||
protected getPodmanDownloadFcosImage(): PodmanDownloadFcosImage {
|
||||
return this.#podmanDownloadFcosImage;
|
||||
protected getPodman5DownloadFedoraImage(): Podman5DownloadFedoraImage {
|
||||
return this.#podman5DownloadFedoraImage;
|
||||
}
|
||||
protected getPodmanDownloadFedoraImage(): PodmanDownloadFedoraImage {
|
||||
return this.#podmanDownloadFedoraImage;
|
||||
|
||||
protected getPodman5DownloadMachineOS(): Podman5DownloadMachineOS {
|
||||
return this.#podman5DownloadMachineOS;
|
||||
}
|
||||
|
||||
protected getShaCheck(): ShaCheck {
|
||||
|
|
@ -178,14 +162,7 @@ export class PodmanDownload {
|
|||
|
||||
await this.#podman5DownloadFedoraImage?.download('x64');
|
||||
await this.#podman5DownloadFedoraImage?.download('arm64');
|
||||
|
||||
await this.#podmanDownloadFedoraImage.download('podman-wsl-fedora', 'x64');
|
||||
await this.#podmanDownloadFedoraImage.download('podman-wsl-fedora-arm', 'arm64');
|
||||
} else if (this.#platform === 'darwin') {
|
||||
// download the fedora core os images for both arches
|
||||
await this.#podmanDownloadFcosImage.download('x64');
|
||||
await this.#podmanDownloadFcosImage.download('arm64');
|
||||
|
||||
// download the podman 5 machines OS
|
||||
await this.#podman5DownloadMachineOS?.download();
|
||||
}
|
||||
|
|
@ -199,180 +176,6 @@ export class ShaCheck {
|
|||
}
|
||||
}
|
||||
|
||||
export class HttpsDownloader {
|
||||
// grab the JSON from the given URL
|
||||
async downloadJson(url): Promise<unknown> {
|
||||
return new Promise((resolve, reject) => {
|
||||
https.get(url, res => {
|
||||
let body = '';
|
||||
|
||||
res.on('data', chunk => {
|
||||
body += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const json = JSON.parse(body);
|
||||
resolve(json);
|
||||
} catch (error) {
|
||||
reject(error.message);
|
||||
}
|
||||
});
|
||||
|
||||
res.on('error', error => {
|
||||
reject(error.message);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// download the file from the given URL and store the content in destFile
|
||||
async downloadFile(url, destFile): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = https.get(url, async res => {
|
||||
// handle url redirect
|
||||
if (res.statusCode === 302) {
|
||||
await this.downloadFile(res.headers.location, destFile);
|
||||
resolve();
|
||||
}
|
||||
|
||||
res.on('data', data => {
|
||||
fs.appendFileSync(destFile, data);
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error.message);
|
||||
}
|
||||
});
|
||||
|
||||
res.on('error', error => {
|
||||
reject(error.message);
|
||||
});
|
||||
});
|
||||
request.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class PodmanDownloadFcosImage {
|
||||
#downloadAttempt = 0;
|
||||
#httpsDownloader: HttpsDownloader;
|
||||
#shaCheck: ShaCheck;
|
||||
#assetsFolder: string;
|
||||
|
||||
readonly MAX_DOWNLOAD_ATTEMPT = 3;
|
||||
|
||||
constructor(
|
||||
readonly httpsDownloader: HttpsDownloader,
|
||||
readonly shaCheck: ShaCheck,
|
||||
readonly assetsFolder: string,
|
||||
) {
|
||||
this.#httpsDownloader = httpsDownloader;
|
||||
this.#shaCheck = shaCheck;
|
||||
this.#assetsFolder = assetsFolder;
|
||||
}
|
||||
|
||||
// For macOS, grab the qemu image from Fedora CoreOS
|
||||
async download(arch: string): Promise<void> {
|
||||
if (this.#downloadAttempt >= this.MAX_DOWNLOAD_ATTEMPT) {
|
||||
console.error('Max download attempt reached, exiting...');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// download the JSON of testing Fedora CoreOS images at https://builds.coreos.fedoraproject.org/streams/testing.json
|
||||
const data = await this.#httpsDownloader.downloadJson(
|
||||
'https://builds.coreos.fedoraproject.org/streams/testing.json',
|
||||
);
|
||||
|
||||
// get the file to download
|
||||
const qemuArch = arch === 'x64' ? 'x86_64' : 'aarch64';
|
||||
const qemuData = data?.['architectures'][qemuArch]['artifacts']['qemu'];
|
||||
|
||||
// get disk object
|
||||
const disk = qemuData.formats['qcow2.xz'].disk;
|
||||
|
||||
// get the disk location
|
||||
const diskLocation = disk.location;
|
||||
|
||||
// get the sha2556
|
||||
const sha256 = disk.sha256;
|
||||
|
||||
const filename = `podman-image-${arch}.qcow2.xz`;
|
||||
const destFile = path.resolve(this.#assetsFolder, filename);
|
||||
if (!fs.existsSync(destFile)) {
|
||||
// download the file from diskLocation
|
||||
console.log(`⚡️ Downloading Podman package from ${diskLocation}`);
|
||||
await this.httpsDownloader.downloadFile(diskLocation, destFile);
|
||||
console.log(`📔 Downloaded to ${destFile}`);
|
||||
} else {
|
||||
console.log(`⏭️ Skipping podman image (already downloaded to ${filename})`);
|
||||
}
|
||||
|
||||
if (!(await this.#shaCheck.checkFile(destFile, sha256))) {
|
||||
console.warn(`❌ Invalid checksum for downloaded ${destFile} is not matching, downloading again...`);
|
||||
fs.rmSync(destFile);
|
||||
this.#downloadAttempt++;
|
||||
// call the loop again
|
||||
await this.download(arch);
|
||||
} else {
|
||||
console.log(`✅ Valid checksum for ${filename}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class PodmanDownloadFedoraImage {
|
||||
readonly MAX_DOWNLOAD_ATTEMPT = 3;
|
||||
#downloadAttempt = 0;
|
||||
#octokit: Octokit;
|
||||
#assetsFolder: string;
|
||||
|
||||
#httpsDownloader: HttpsDownloader;
|
||||
|
||||
constructor(
|
||||
readonly octokit: Octokit,
|
||||
readonly httpsDownloader: HttpsDownloader,
|
||||
readonly assetsFolder: string,
|
||||
) {
|
||||
this.#octokit = octokit;
|
||||
this.#httpsDownloader = httpsDownloader;
|
||||
this.#assetsFolder = assetsFolder;
|
||||
}
|
||||
|
||||
// For Windows binaries, grab the latest release from GitHub repository
|
||||
async download(repo: string, arch: string): Promise<void> {
|
||||
if (this.#downloadAttempt >= this.MAX_DOWNLOAD_ATTEMPT) {
|
||||
console.error('Max download attempt reached, exiting...');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// now, grab the files
|
||||
const release = await this.#octokit.request('GET /repos/{owner}/{repo}/releases/latest', {
|
||||
owner: 'containers',
|
||||
repo,
|
||||
});
|
||||
|
||||
const artifactRelease = release.data.assets.find(asset => asset.name === 'rootfs.tar.xz');
|
||||
|
||||
if (!artifactRelease) {
|
||||
throw new Error(`Can't find assets to download and verify for podman image from repository ${repo}`);
|
||||
}
|
||||
|
||||
const filename = `podman-image-${arch}.tar.xz`;
|
||||
const destFile = path.resolve(this.#assetsFolder, filename);
|
||||
if (!fs.existsSync(destFile)) {
|
||||
// download the file from diskLocation
|
||||
console.log(`⚡️ Downloading Podman package from ${artifactRelease.browser_download_url}`);
|
||||
await this.#httpsDownloader.downloadFile(artifactRelease.browser_download_url, destFile);
|
||||
console.log(`📔 Downloaded to ${destFile}`);
|
||||
} else {
|
||||
console.log(`⏭️ Skipping Windows podman image for ${arch} (already downloaded to ${filename})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class DownloadAndCheck {
|
||||
readonly MAX_DOWNLOAD_ATTEMPT = 3;
|
||||
#downloadAttempt = 0;
|
||||
|
|
@ -680,7 +483,7 @@ export class Podman5DownloadMachineOS {
|
|||
);
|
||||
await this.downloadZstdFromManifest(
|
||||
`${manifestUrl} for amd64`,
|
||||
'podman-image-amd64.zst',
|
||||
'podman-image-x64.zst',
|
||||
amd64ZstdManifest.layers[0],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -404,12 +404,12 @@ test('verify error contains name, message and stderr if creation fails', async (
|
|||
).rejects.toThrowError('name\ndescription\nerror\n');
|
||||
});
|
||||
|
||||
test('verify create command called with embedded image if using podman v4', async () => {
|
||||
test('verify create command called with embedded image if using podman v5', async () => {
|
||||
vi.mocked(isMac).mockReturnValue(true);
|
||||
vi.mocked(getAssetsFolder).mockReturnValue('fake');
|
||||
vi.mocked(fs.existsSync).mockReturnValue(true);
|
||||
vi.mocked(extensionApi.process.exec).mockResolvedValueOnce({
|
||||
stdout: 'podman version 4.0.0',
|
||||
stdout: 'podman version 5.0.0',
|
||||
} as extensionApi.RunResult);
|
||||
|
||||
await extension.createMachine(
|
||||
|
|
@ -434,42 +434,7 @@ test('verify create command called with embedded image if using podman v4', asyn
|
|||
expect(vi.mocked(extensionApi.process.exec)).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
getPodmanCli(),
|
||||
expect.arrayContaining([expect.stringContaining('.qcow2.xz')]),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
test('verify create command not called with embedded image if using podman v4', async () => {
|
||||
vi.mocked(isMac).mockReturnValue(true);
|
||||
vi.mocked(getAssetsFolder).mockReturnValue('fake');
|
||||
vi.mocked(fs.existsSync).mockReturnValue(true);
|
||||
vi.mocked(extensionApi.process.exec).mockResolvedValueOnce({
|
||||
stdout: 'podman version 5.0.0',
|
||||
} as extensionApi.RunResult);
|
||||
|
||||
await extension.createMachine(
|
||||
{
|
||||
'podman.factory.machine.cpus': '2',
|
||||
'podman.factory.machine.memory': '1048000000',
|
||||
'podman.factory.machine.diskSize': '250000000000',
|
||||
'podman.factory.machine.now': true,
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
|
||||
// check telemetry is called with telemetryRecords.imagePath
|
||||
await vi.waitFor(() => {
|
||||
expect(telemetryLogger.logUsage).toBeCalledWith(
|
||||
'podman.machine.init',
|
||||
expect.not.objectContaining({ imagePath: 'embedded' }),
|
||||
);
|
||||
});
|
||||
|
||||
expect(vi.mocked(extensionApi.process.exec)).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
getPodmanCli(),
|
||||
expect.not.arrayContaining([expect.stringContaining('.qcow2.xz')]),
|
||||
expect.arrayContaining([expect.stringContaining('.zst')]),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import type { InstalledPodman } from './podman-cli';
|
|||
import { getPodmanCli, getPodmanInstallation } from './podman-cli';
|
||||
import { PodmanConfiguration } from './podman-configuration';
|
||||
import { PodmanInfoHelper } from './podman-info-helper';
|
||||
import { PODMAN5_EXPERIMENTAL_MODE_CONFIG_FULLKEY, PodmanInstall } from './podman-install';
|
||||
import { PodmanInstall } from './podman-install';
|
||||
import { QemuHelper } from './qemu-helper';
|
||||
import { RegistrySetup } from './registry-setup';
|
||||
import { appConfigDir, appHomeDir, getAssetsFolder, isLinux, isMac, isWindows, LoggerDelegator } from './util';
|
||||
|
|
@ -907,13 +907,6 @@ export async function initCheckAndRegisterUpdate(
|
|||
};
|
||||
await checkForUpdate();
|
||||
|
||||
// if configuration key change, check for update again
|
||||
extensionApi.configuration.onDidChangeConfiguration(async e => {
|
||||
if (e.affectsConfiguration(PODMAN5_EXPERIMENTAL_MODE_CONFIG_FULLKEY)) {
|
||||
await checkForUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
// register onDidUpdateVersion
|
||||
provider.onDidUpdateVersion(async () => {
|
||||
await checkForUpdate();
|
||||
|
|
@ -1727,14 +1720,16 @@ export async function createMachine(
|
|||
if (isWindows()) {
|
||||
suffix = `-${process.arch}.tar.xz`;
|
||||
} else if (isMac()) {
|
||||
suffix = `-${process.arch}.qcow2.xz`;
|
||||
suffix = `-${process.arch}.zst`;
|
||||
}
|
||||
|
||||
const assetImagePath = path.resolve(getAssetsFolder(), `podman-image${suffix}`);
|
||||
|
||||
const podmanInstallation = await getPodmanInstallation();
|
||||
|
||||
// check if the file exists and if it does, use it
|
||||
if (fs.existsSync(assetImagePath) && podmanInstallation.version.startsWith('4.')) {
|
||||
// Use embedded image only for Podman 5 and onwards
|
||||
if (fs.existsSync(assetImagePath) && podmanInstallation.version.startsWith('5.')) {
|
||||
console.log('using embedded image path');
|
||||
parameters.push('--image-path');
|
||||
parameters.push(assetImagePath);
|
||||
telemetryRecords.imagePath = 'embedded';
|
||||
|
|
|
|||
|
|
@ -666,89 +666,10 @@ test('expect winWSL2 command to be registered as disposable', async () => {
|
|||
});
|
||||
|
||||
describe('getBundledPodmanVersion', () => {
|
||||
test('should return the podman 4 version if flag is not enabled', async () => {
|
||||
test('should return the podman 5 version', async () => {
|
||||
const version = getBundledPodmanVersion();
|
||||
expect(version.startsWith('4')).toBeTruthy();
|
||||
expect(version.startsWith('5')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should return the podman 5 version if experimental podman 5 flag is enabled', async () => {
|
||||
vi.mocked(extensionApi.configuration.getConfiguration).mockReset();
|
||||
const getMock = vi.fn();
|
||||
getMock.mockReturnValue(true);
|
||||
|
||||
vi.mocked(extensionApi.configuration.getConfiguration).mockReturnValue({
|
||||
get: getMock,
|
||||
has: vi.fn(),
|
||||
update: vi.fn(),
|
||||
});
|
||||
const version = getBundledPodmanVersion();
|
||||
expect(version.startsWith('4')).toBeFalsy();
|
||||
expect(version.startsWith('5')).toBeTruthy();
|
||||
|
||||
// check first argument of the call to getMock
|
||||
expect(getMock).toHaveBeenCalled();
|
||||
// should have called the get with the property for experimental install
|
||||
expect(getMock).toHaveBeenCalledWith('experimental.install.v5');
|
||||
});
|
||||
|
||||
test('should return the podman 5 version if experimental podman 5 flag is not enabled but first install', async () => {
|
||||
vi.mocked(extensionApi.configuration.getConfiguration).mockReset();
|
||||
const getMock = vi.fn();
|
||||
getMock.mockReturnValue(false);
|
||||
|
||||
// exist sync is false
|
||||
vi.mock('node:fs');
|
||||
vi.mocked(fs.existsSync).mockReturnValue(false);
|
||||
|
||||
vi.mocked(extensionApi.configuration.getConfiguration).mockReturnValue({
|
||||
get: getMock,
|
||||
has: vi.fn(),
|
||||
update: vi.fn(),
|
||||
});
|
||||
const version = getBundledPodmanVersion();
|
||||
expect(version.startsWith('4')).toBeFalsy();
|
||||
expect(version.startsWith('5')).toBeTruthy();
|
||||
|
||||
// check existSync has been called
|
||||
expect(vi.mocked(fs.existsSync)).toHaveBeenCalled();
|
||||
|
||||
// check first argument of the call to getMock
|
||||
expect(getMock).toHaveBeenCalled();
|
||||
// should have called the get with the property for experimental install
|
||||
expect(getMock).toHaveBeenCalledWith('experimental.install.v5');
|
||||
});
|
||||
|
||||
test('should return the podman 4 version if there is some airgapped images (fresh install)', async () => {
|
||||
vi.mocked(extensionApi.configuration.getConfiguration).mockReset();
|
||||
const getMock = vi.fn();
|
||||
getMock.mockReturnValue(false);
|
||||
|
||||
// exist sync is false
|
||||
vi.mock('node:fs');
|
||||
// no qemu folders
|
||||
vi.mocked(fs.existsSync).mockReturnValueOnce(false);
|
||||
vi.mocked(fs.existsSync).mockReturnValueOnce(false);
|
||||
// but we have some images
|
||||
vi.mocked(fs.existsSync).mockReturnValueOnce(true);
|
||||
vi.mocked(fs.readdirSync).mockReturnValue(['podman-image-foo.tar.gz'] as unknown as fs.Dirent[]);
|
||||
|
||||
vi.mocked(extensionApi.configuration.getConfiguration).mockReturnValue({
|
||||
get: getMock,
|
||||
has: vi.fn(),
|
||||
update: vi.fn(),
|
||||
});
|
||||
const version = getBundledPodmanVersion();
|
||||
expect(version.startsWith('4')).toBeTruthy();
|
||||
expect(version.startsWith('5')).toBeFalsy();
|
||||
|
||||
// check existSync has been called
|
||||
expect(vi.mocked(fs.existsSync)).toHaveBeenCalled();
|
||||
|
||||
// check first argument of the call to getMock
|
||||
expect(getMock).toHaveBeenCalled();
|
||||
// should have called the get with the property for experimental install
|
||||
expect(getMock).toHaveBeenCalledWith('experimental.install.v5');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import { PodmanCleanupMacOS } from './podman-cleanup-macos';
|
|||
import { PodmanCleanupWindows } from './podman-cleanup-windows';
|
||||
import type { InstalledPodman } from './podman-cli';
|
||||
import { getPodmanCli, getPodmanInstallation } from './podman-cli';
|
||||
import * as podman4JSON from './podman4.json';
|
||||
import * as podman5JSON from './podman5.json';
|
||||
import { getAssetsFolder, normalizeWSLOutput } from './util';
|
||||
import { WslHelper } from './wsl-helper';
|
||||
|
|
@ -48,40 +47,8 @@ import { WslHelper } from './wsl-helper';
|
|||
const readFile = promisify(fs.readFile);
|
||||
const writeFile = promisify(fs.writeFile);
|
||||
|
||||
const PODMAN5_EXPERIMENTAL_MODE_CONFIG_KEY = 'experimental.install.v5';
|
||||
export const PODMAN5_EXPERIMENTAL_MODE_CONFIG_FULLKEY = `podman.${PODMAN5_EXPERIMENTAL_MODE_CONFIG_KEY}`;
|
||||
|
||||
export function getBundledPodmanVersion(): string {
|
||||
const podman5ExperimentalModeEnabled = extensionApi.configuration
|
||||
.getConfiguration('podman')
|
||||
.get<boolean>(PODMAN5_EXPERIMENTAL_MODE_CONFIG_KEY);
|
||||
|
||||
// also check if the user has never installed podman (for example there is no configuration folder for Podman)
|
||||
// no ~/.config/containers/podman and ~/.local/share/containers/podman folders on Windows or macOS
|
||||
let noPreviousPodmanInstallation = false;
|
||||
if (extensionApi.env.isWindows || extensionApi.env.isMac) {
|
||||
noPreviousPodmanInstallation =
|
||||
!fs.existsSync(path.resolve(os.homedir(), '.config/containers/podman')) &&
|
||||
!fs.existsSync(path.resolve(os.homedir(), '.local/share/containers/podman'));
|
||||
}
|
||||
|
||||
// air gapped mode check.
|
||||
const assetImagePath = path.resolve(getAssetsFolder());
|
||||
let airGappedMode = false;
|
||||
// check if we have some podman-image files
|
||||
if (fs.existsSync(assetImagePath)) {
|
||||
const podmanImageFiles = fs.readdirSync(assetImagePath).filter(file => file.startsWith('podman-image'));
|
||||
if (podmanImageFiles.length > 0) {
|
||||
airGappedMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
// default to v5 if experimental mode is enabled or if there is no previous installation (and not using airgapped mode)
|
||||
if (podman5ExperimentalModeEnabled || (noPreviousPodmanInstallation && !airGappedMode)) {
|
||||
return podman5JSON.version;
|
||||
}
|
||||
|
||||
return podman4JSON.version;
|
||||
return podman5JSON.version;
|
||||
}
|
||||
|
||||
export interface PodmanInfo {
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"version": "4.9.4",
|
||||
"platform": {
|
||||
"win32": {
|
||||
"version": "v4.9.4",
|
||||
"fileName": "podman-4.9.4-setup.exe"
|
||||
},
|
||||
"darwin": {
|
||||
"version": "v4.9.4",
|
||||
"arch": {
|
||||
"x64": {
|
||||
"fileName": "podman-installer-macos-amd64-v4.9.4.pkg"
|
||||
},
|
||||
"arm64": {
|
||||
"fileName": "podman-installer-macos-aarch64-v4.9.4.pkg"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue