Skip to content

Commit

Permalink
[wip] [5 of #107] add dynamic options (#125)
Browse files Browse the repository at this point in the history
* adopt dynamic options pattern, with temporary condaConfig

* collapse additional type imports
  • Loading branch information
bollwyvl authored Dec 20, 2020
1 parent 21dbde1 commit 9ed7b04
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 231 deletions.
185 changes: 100 additions & 85 deletions dist/setup/index.js

Large diffs are not rendered by default.

91 changes: 46 additions & 45 deletions src/conda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import * as core from "@actions/core";
import * as io from "@actions/io";

import { IS_LINUX, IS_MAC, IS_WINDOWS, MINICONDA_DIR_PATH } from "./constants";
import { IShells, TCondaConfig } from "./types";
import { execute } from "./utils";
import * as types from "./types";

/**
* Provide current location of miniconda or location where it will be installed
*/
export function minicondaPath(useBundled: boolean = true): string {
export function minicondaPath(options: types.IDynamicOptions): string {
let condaPath: string = MINICONDA_DIR_PATH;
if (!useBundled) {
if (!options.useBundled) {
if (IS_MAC) {
condaPath = "/Users/runner/miniconda3";
} else {
Expand All @@ -31,14 +31,11 @@ export function minicondaPath(useBundled: boolean = true): string {
/**
* Provide cross platform location of conda/mamba executable
*/
export function condaExecutable(
useBundled: boolean,
useMamba: boolean = false
): string {
const dir: string = minicondaPath(useBundled);
export function condaExecutable(options: types.IDynamicOptions): string {
const dir: string = minicondaPath(options);
let condaExe: string;
let commandName: string;
commandName = useMamba ? "mamba" : "conda";
commandName = options.useMamba ? "mamba" : "conda";
commandName = IS_WINDOWS ? commandName + ".bat" : commandName;
condaExe = path.join(dir, "condabin", commandName);
return condaExe;
Expand All @@ -49,41 +46,42 @@ export function condaExecutable(
*/
export async function condaCommand(
cmd: string[],
useBundled: boolean,
useMamba: boolean = false
options: types.IDynamicOptions
): Promise<void> {
const command = [condaExecutable(useBundled, useMamba), ...cmd];
const command = [condaExecutable(options), ...cmd];
return await execute(command);
}

/**
* Setup Conda configuration
*/
export async function applyCondaConfiguration(
condaConfig: TCondaConfig,
useBundled: boolean
options: types.IDynamicOptions
): Promise<void> {
for (const key of Object.keys(condaConfig)) {
core.info(`"${key}": "${condaConfig[key]}"`);
if (condaConfig[key].length !== 0) {
// TODO: figure out a way to know a-priori if we have mamba for initial commands
const notMambaOptions = { ...options, useMamba: false };

for (const key of Object.keys(options.condaConfig)) {
core.info(`"${key}": "${options.condaConfig[key]}"`);
if (options.condaConfig[key].length !== 0) {
if (key === "channels") {
// Split by comma and reverse order to preserve higher priority
// as listed in the option
let channels: Array<string> = condaConfig[key].split(",").reverse();
let channels: Array<string> = options.condaConfig[key]
.split(",")
.reverse();
let channel: string;
for (channel of channels) {
await condaCommand(
["config", "--add", key, channel],
useBundled,
false
notMambaOptions
);
}
} else {
try {
await condaCommand(
["config", "--set", key, condaConfig[key]],
useBundled,
false
["config", "--set", key, options.condaConfig[key]],
options
);
} catch (err) {
core.warning(`Couldn't set conda configuration '${key}'`);
Expand All @@ -92,30 +90,28 @@ export async function applyCondaConfiguration(
}
}

await condaCommand(["config", "--show-sources"], useBundled, false);
await condaCommand(["config", "--show-sources"], notMambaOptions);

await condaCommand(["config", "--show"], useBundled, false);
await condaCommand(["config", "--show"], notMambaOptions);
}

/**
* Initialize Conda
*/
export async function condaInit(
activateEnvironment: string,
useBundled: boolean,
condaConfig: TCondaConfig,
removeProfiles: string
inputs: types.IActionInputs,
options: types.IDynamicOptions
): Promise<void> {
let ownPath: string;
const isValidActivate: boolean =
activateEnvironment !== "base" &&
activateEnvironment !== "root" &&
activateEnvironment !== "";
inputs.activateEnvironment !== "base" &&
inputs.activateEnvironment !== "root" &&
inputs.activateEnvironment !== "";
const autoActivateBase: boolean =
condaConfig["auto_activate_base"] === "true";
options.condaConfig["auto_activate_base"] === "true";

// Fix ownership of folders
if (useBundled) {
if (options.useBundled) {
if (IS_MAC) {
core.startGroup("Fixing conda folders ownership");
const userName: string = process.env.USER as string;
Expand All @@ -124,7 +120,7 @@ export async function condaInit(
"chown",
"-R",
`${userName}:staff`,
minicondaPath(useBundled),
minicondaPath(options),
]);
core.endGroup();
} else if (IS_WINDOWS) {
Expand All @@ -135,7 +131,7 @@ export async function condaInit(
"etc/profile.d/",
"/Lib/site-packages/xonsh/",
]) {
ownPath = path.join(minicondaPath(useBundled), folder);
ownPath = path.join(minicondaPath(options), folder);
if (fs.existsSync(ownPath)) {
core.startGroup(`Fixing ${folder} ownership`);
await execute(["takeown", "/f", ownPath, "/r", "/d", "y"]);
Expand All @@ -146,7 +142,7 @@ export async function condaInit(
}

// Remove profile files
if (removeProfiles == "true") {
if (inputs.removeProfiles == "true") {
for (let rc of [
".bashrc",
".bash_profile",
Expand All @@ -173,7 +169,12 @@ export async function condaInit(

// Run conda init
for (let cmd of ["--all"]) {
await execute([condaExecutable(useBundled, false), "init", cmd]);
// TODO: determine when it's safe to use mamba
await execute([
condaExecutable({ ...options, useMamba: false }),
"init",
cmd,
]);
}

// Rename files
Expand All @@ -195,7 +196,7 @@ export async function condaInit(
if (isValidActivate) {
powerExtraText += `
# Conda Setup Action: Custom activation
conda activate ${activateEnvironment}`;
conda activate ${inputs.activateEnvironment}`;
}
powerExtraText += `
# ----------------------------------------------------------------------------`;
Expand All @@ -208,7 +209,7 @@ export async function condaInit(
if (isValidActivate) {
bashExtraText += `
# Conda Setup Action: Custom activation
conda activate ${activateEnvironment}`;
conda activate ${inputs.activateEnvironment}`;
bashExtraText += `
# ----------------------------------------------------------------------------`;
}
Expand All @@ -224,16 +225,16 @@ export async function condaInit(
if (isValidActivate) {
batchExtraText += `
:: Conda Setup Action: Custom activation
@CALL "%CONDA_BAT%" activate ${activateEnvironment}`;
@CALL "%CONDA_BAT%" activate ${inputs.activateEnvironment}`;
}
batchExtraText += `
:: Conda Setup Action: Basic configuration
@SETLOCAL EnableExtensions
@SETLOCAL DisableDelayedExpansion
:: ---------------------------------------------------------------------------`;

let extraShells: IShells;
const shells: IShells = {
let extraShells: types.IShells;
const shells: types.IShells = {
"~/.bash_profile": bashExtraText,
"~/.profile": bashExtraText,
"~/.zshrc": bashExtraText,
Expand All @@ -244,7 +245,7 @@ export async function condaInit(
"~/Documents/PowerShell/profile.ps1": powerExtraText,
"~/Documents/WindowsPowerShell/profile.ps1": powerExtraText,
};
if (useBundled) {
if (options.useBundled) {
extraShells = {
"C:/Miniconda/etc/profile.d/conda.sh": bashExtraText,
"C:/Miniconda/etc/fish/conf.d/conda.fish": bashExtraText,
Expand All @@ -257,7 +258,7 @@ export async function condaInit(
"C:/Miniconda3/condabin/conda_hook.bat": batchExtraText,
};
}
const allShells: IShells = { ...shells, ...extraShells };
const allShells: types.IShells = { ...shells, ...extraShells };
Object.keys(allShells).forEach((key) => {
let filePath: string = key.replace("~", os.homedir());
const text = allShells[key];
Expand Down
6 changes: 3 additions & 3 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as os from "os";
import * as path from "path";

import { IArchitectures, IOperatingSystems } from "./types";
import * as types from "./types";

//-----------------------------------------------------------------------
// Constants
Expand All @@ -14,14 +14,14 @@ export const IS_UNIX: boolean = IS_MAC || IS_LINUX;
export const MINICONDA_BASE_URL: string =
"https://repo.anaconda.com/miniconda/";

export const ARCHITECTURES: IArchitectures = {
export const ARCHITECTURES: types.IArchitectures = {
x64: "x86_64",
x86: "x86",
ARM64: "aarch64", // To be supported by github runners
ARM32: "armv7l", // To be supported by github runners
};

export const OS_NAMES: IOperatingSystems = {
export const OS_NAMES: types.IOperatingSystems = {
win32: "Windows",
darwin: "MacOSX",
linux: "Linux",
Expand Down
28 changes: 15 additions & 13 deletions src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@ import * as path from "path";
import * as core from "@actions/core";

import { minicondaPath, condaCommand } from "./conda";
import * as types from "./types";

/**
* Check if a given conda environment exists
*/
export function environmentExists(name: string, useBundled: boolean): boolean {
export function environmentExists(
inputs: types.IActionInputs,
options: types.IDynamicOptions
): boolean {
const condaMetaPath: string = path.join(
minicondaPath(useBundled),
minicondaPath(options),
"envs",
name,
inputs.activateEnvironment,
"conda-meta"
);
return fs.existsSync(condaMetaPath);
Expand All @@ -22,21 +26,19 @@ export function environmentExists(name: string, useBundled: boolean): boolean {
* Create test environment
*/
export async function createTestEnvironment(
activateEnvironment: string,
useBundled: boolean,
useMamba: boolean
inputs: types.IActionInputs,
options: types.IDynamicOptions
): Promise<void> {
if (
activateEnvironment !== "root" &&
activateEnvironment !== "base" &&
activateEnvironment !== ""
inputs.activateEnvironment !== "root" &&
inputs.activateEnvironment !== "base" &&
inputs.activateEnvironment !== ""
) {
if (!environmentExists(activateEnvironment, useBundled)) {
if (!environmentExists(inputs, options)) {
core.startGroup("Create test environment...");
await condaCommand(
["create", "--name", activateEnvironment],
useBundled,
useMamba
["create", "--name", inputs.activateEnvironment],
options
);
core.endGroup();
}
Expand Down
8 changes: 4 additions & 4 deletions src/installer/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import * as core from "@actions/core";
import * as io from "@actions/io";
import * as tc from "@actions/tool-cache";

import { ILocalInstallerOpts } from "../types";
import { minicondaPath } from "../conda";
import { execute } from "../utils";
import * as types from "../types";

/** Get the path for a locally-executable installer from cache, or as downloaded
*
Expand All @@ -22,7 +22,7 @@ import { execute } from "../utils";
* - or has been renamed during a build process
*/
export async function ensureLocalInstaller(
options: ILocalInstallerOpts
options: types.ILocalInstallerOpts
): Promise<string> {
core.startGroup("Ensuring Installer...");

Expand Down Expand Up @@ -88,9 +88,9 @@ export async function ensureLocalInstaller(
*/
export async function runInstaller(
installerPath: string,
useBundled: boolean
options: types.IDynamicOptions
): Promise<void> {
const outputPath: string = minicondaPath(useBundled);
const outputPath: string = minicondaPath(options);
const installerExtension = path.extname(installerPath);
let command: string[];

Expand Down
13 changes: 7 additions & 6 deletions src/installer/download-miniconda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
OS_NAMES,
} from "../constants";

import * as types from "../types";

/**
* List available Miniconda versions
*
Expand Down Expand Up @@ -45,18 +47,17 @@ async function minicondaVersions(arch: string): Promise<string[]> {
*/
export async function downloadMiniconda(
pythonMajorVersion: number,
minicondaVersion: string,
architecture: string
inputs: types.IActionInputs
): Promise<string> {
// Check valid arch
const arch: string = ARCHITECTURES[architecture];
const arch: string = ARCHITECTURES[inputs.architecture];
if (!arch) {
throw new Error(`Invalid arch "${architecture}"!`);
throw new Error(`Invalid arch "${inputs.architecture}"!`);
}

let extension: string = IS_UNIX ? "sh" : "exe";
let osName: string = OS_NAMES[process.platform];
const minicondaInstallerName: string = `Miniconda${pythonMajorVersion}-${minicondaVersion}-${osName}-${arch}.${extension}`;
const minicondaInstallerName: string = `Miniconda${pythonMajorVersion}-${inputs.minicondaVersion}-${osName}-${arch}.${extension}`;
core.info(minicondaInstallerName);

// Check version name
Expand All @@ -72,7 +73,7 @@ export async function downloadMiniconda(
return await ensureLocalInstaller({
url: MINICONDA_BASE_URL + minicondaInstallerName,
tool: `Miniconda${pythonMajorVersion}`,
version: minicondaVersion,
version: inputs.minicondaVersion,
arch: arch,
});
}
7 changes: 5 additions & 2 deletions src/installer/download-url.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { ensureLocalInstaller } from "./base";
import * as types from "../types";

/**
* @param url A URL for a file with the CLI of a `constructor`-built artifact
*/
export async function downloadCustomInstaller(url: string): Promise<string> {
return await ensureLocalInstaller({ url });
export async function downloadCustomInstaller(
inputs: types.IActionInputs
): Promise<string> {
return await ensureLocalInstaller({ url: inputs.installerUrl });
}
Loading

0 comments on commit 9ed7b04

Please sign in to comment.