Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions change/change-0dd2175c-32cf-405a-9191-dc49f581835e.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"type": "minor",
"comment": "Add Linux x64 and arm64 support with .deb binary installation",
"packageName": "azureauth",
"email": "sverre.johansen@microsoft.com",
"dependentChangeType": "patch"
}
]
}
11 changes: 11 additions & 0 deletions change/change-0f97b1a9-426e-4722-82e8-54b54ec2b0a2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"type": "patch",
"comment": "Add Linux x64 and arm64 platform support",
"packageName": "ado-npm-auth",
"email": "sverre.johansen@microsoft.com",
"dependentChangeType": "patch"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { arch, platform } from "os";
import { isWsl } from "../utils/is-wsl.js";

/**
* Determines if the currently running platform is supported by azureauth. Currently, supported platforms are Windows, Mac & WSL
* Determines if the currently running platform is supported by azureauth. Currently, supported platforms are Windows, Mac, Linux & WSL
* @returns { boolean } if the current platform is supported by azureauth
*/
export const isSupportedPlatformAndArchitecture = (): boolean => {
const supportedPlatformsAndArchitectures: Record<string, string[]> = {
win32: ["x64"],
darwin: ["x64", "arm64"],
linux: ["x64", "arm64"],
};

return (
Expand Down
88 changes: 80 additions & 8 deletions packages/node-azureauth/src/install.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from "node:path";
import fs from "node:fs";
import { execSync } from "node:child_process";

import { DownloaderHelper } from "node-downloader-helper";
import decompress from "decompress";
Expand All @@ -22,6 +23,73 @@ async function download(url: string, saveDirectory: string): Promise<void> {
});
}

async function extractDeb(debPath: string, outputDir: string): Promise<void> {
const tempDir = path.join(outputDir, "temp_deb_extract");
fs.mkdirSync(tempDir, { recursive: true });

try {
// Copy .deb to temp directory
const debInTemp = path.join(tempDir, path.basename(debPath));
fs.copyFileSync(debPath, debInTemp);

// Extract the .deb file (which is an ar archive) in temp directory
execSync(`ar x ${path.basename(debPath)}`, {
cwd: tempDir,
stdio: "inherit",
});

// Find and extract the data.tar.* file
const files = fs.readdirSync(tempDir);
const dataTar = files.find((f) => f.startsWith("data.tar"));

if (!dataTar) {
throw new Error("data.tar.* not found in .deb archive");
}

// Extract data.tar.* to a temp extract directory
const extractDir = path.join(tempDir, "extract");
fs.mkdirSync(extractDir, { recursive: true });

execSync(`tar -xf ${dataTar} -C ${extractDir}`, {
cwd: tempDir,
stdio: "inherit",
});

// Move all files from usr/lib/azureauth to the root of outputDir
const sourceDir = path.join(extractDir, "usr", "lib", "azureauth");

if (fs.existsSync(sourceDir)) {
// Recursively copy all files and directories
const copyRecursive = (src: string, dest: string) => {
const stats = fs.statSync(src);
if (stats.isDirectory()) {
if (!fs.existsSync(dest)) {
fs.mkdirSync(dest, { recursive: true });
}
const entries = fs.readdirSync(src);
for (const entry of entries) {
copyRecursive(path.join(src, entry), path.join(dest, entry));
}
} else {
fs.copyFileSync(src, dest);
// Make executable files executable
if (path.basename(src) === "azureauth" || stats.mode & fs.constants.S_IXUSR) {
fs.chmodSync(dest, 0o755);
}
}
};

const entries = fs.readdirSync(sourceDir);
for (const entry of entries) {
copyRecursive(path.join(sourceDir, entry), path.join(outputDir, entry));
}
}
} finally {
// Clean up temp directory
fs.rmSync(tempDir, { recursive: true, force: true });
}
}

const platform = process.platform;
const arch = process.arch;

Expand All @@ -37,7 +105,7 @@ const AZUREAUTH_INFO = {
const AZUREAUTH_NAME_MAP: any = {
def: "azureauth",
win32: "azureauth.exe",
linux: "azureauth.exe",
linux: "azureauth",
};

export const AZUREAUTH_NAME =
Expand Down Expand Up @@ -73,11 +141,10 @@ export const install = async () => {
x64: `azureauth-${AZUREAUTH_INFO.version}-osx-x64.tar.gz`,
arm64: `azureauth-${AZUREAUTH_INFO.version}-osx-arm64.tar.gz`,
},
// TODO: support linux when the binaries are available
// linux: {
// def: "azureauth.exe",
// x64: "azureauth-${AZUREAUTH_INFO.version}-win10-x64.zip",
// },
linux: {
x64: `azureauth-${AZUREAUTH_INFO.version}-linux-x64.deb`,
arm64: `azureauth-${AZUREAUTH_INFO.version}-linux-arm64.deb`,
},
};
if (platform in DOWNLOAD_MAP) {
// download the executable
Expand Down Expand Up @@ -106,7 +173,12 @@ export const install = async () => {

const binaryPath = path.join(distPath, AZUREAUTH_NAME);

await decompress(archivePath, distPath);
// Handle .deb files differently from .zip and .tar.gz
if (filename.endsWith(".deb")) {
await extractDeb(archivePath, distPath);
} else {
await decompress(archivePath, distPath);
}

if (fileExist(binaryPath)) {
fs.chmodSync(binaryPath, fs.constants.S_IXUSR || 0o100);
Expand All @@ -115,7 +187,7 @@ export const install = async () => {
fs.chmodSync(binaryPath, 0o755);
}

console.log(`Unzipped in ${archivePath}`);
console.log(`Extracted in ${archivePath}`);
fs.unlinkSync(archivePath);
}
};
Expand Down
Loading