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
4 changes: 2 additions & 2 deletions .github/workflows/caching-envs-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- uses: actions/checkout@v6.0.2

- name: Setup Miniforge
uses: conda-incubator/setup-miniconda@fc2d68f6413eb2d87b895e92f8584b5b94a10167 # v3.3.0
uses: ./
with:
miniforge-version: latest
activate-environment: anaconda-client-env
Expand All @@ -59,7 +59,7 @@ jobs:
env.CACHE_NUMBER }}
env:
# Increase this value to reset cache if etc/example-environment.yml has not changed
CACHE_NUMBER: 0
CACHE_NUMBER: 1
id: cache

- name: Update environment
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/caching-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
uses: actions/cache@v5
env:
# Increase this value to reset cache if etc/example-environment.yml has not changed
CACHE_NUMBER: 2
CACHE_NUMBER: 3
with:
# Use faster GNU tar
enableCrossOsArchive: true
Expand Down Expand Up @@ -61,7 +61,7 @@ jobs:
uses: actions/cache@v5
env:
# Increase this value to reset cache if etc/example-environment.yml has not changed
CACHE_NUMBER: 2
CACHE_NUMBER: 3
with:
# Use faster GNU tar
enableCrossOsArchive: true
Expand Down
89 changes: 59 additions & 30 deletions dist/delete/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 65 additions & 21 deletions src/delete.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as fs from "fs";
import * as os from "os";
import * as path from "path";

import * as core from "@actions/core";
Expand All @@ -8,38 +7,83 @@ import * as io from "@actions/io";
import * as input from "./input";
import * as utils from "./utils";

const STASH_SUFFIX = "_stash_";

/**
* Clean up the conda cache directory
* Clean up extracted packages from the conda packages directory, keeping only
* the compressed archive cache and loose archive files.
*
* Instead of recursively deleting each extracted folder (extremely slow on
* Windows due to filesystem overhead), we rename them to a sibling directory
* on the same filesystem. On self-hosted (persistent) runners, stash
* directories from previous runs are cleaned up before new ones are created.
*/
async function run(): Promise<void> {
try {
const inputs = await core.group("Gathering Inputs...", input.parseInputs);
let pkgsDirs = utils.parsePkgsDirs(inputs.condaConfig.pkgs_dirs);
const pkgsDirs = utils.parsePkgsDirs(inputs.condaConfig.pkgs_dirs);
if (!pkgsDirs.length) return;
core.startGroup(
"Removing uncompressed packages to trim down packages directory...",
);
for (const pkgsDir of pkgsDirs) {
if (fs.existsSync(pkgsDir) && fs.lstatSync(pkgsDir).isDirectory()) {
let fullPath: string;
for (let folder_or_file of fs.readdirSync(pkgsDir)) {
fullPath = path.join(pkgsDir, folder_or_file);
if (
fs.existsSync(fullPath) &&
fs.lstatSync(fullPath).isDirectory() &&
folder_or_file != "cache"
) {
core.info(`Removing "${fullPath}"`);
try {
await io.rmRF(fullPath);
} catch (err) {
// If file could not be deleted, move to a temp folder
core.info(`Remove failed, moving "${fullPath}" to temp folder`);
await io.mv(fullPath, path.join(os.tmpdir(), folder_or_file));
}
for (const rawPkgsDir of pkgsDirs) {
// Normalize to strip trailing separators so the sibling stash
// directory is always created next to pkgsDir, not inside it
const pkgsDir = path.resolve(rawPkgsDir);

if (!fs.existsSync(pkgsDir) || !fs.lstatSync(pkgsDir).isDirectory()) {
continue;
}

// Clean up stash directories left by previous runs (self-hosted runners)
const parentDir = path.dirname(pkgsDir);
const baseName = path.basename(pkgsDir);
for (const sibling of fs.readdirSync(parentDir)) {
if (sibling.startsWith(`${baseName}${STASH_SUFFIX}`)) {
const oldStash = path.join(parentDir, sibling);
core.info(`Cleaning up old stash directory "${oldStash}"`);
try {
await io.rmRF(oldStash);
} catch (err) {
core.warning(
`Could not remove old stash "${oldStash}": ${
(err as Error).message
}`,
);
}
}
}

// Stash directory is a sibling to pkgsDir so rename stays on the
// same filesystem and never fails with EXDEV
const stashDir = path.join(
parentDir,
`${baseName}${STASH_SUFFIX}${Date.now()}`,
);
fs.mkdirSync(stashDir, { recursive: true });

for (const entry of fs.readdirSync(pkgsDir)) {
if (entry === "cache") continue;

const fullPath = path.join(pkgsDir, entry);
if (!fs.existsSync(fullPath) || !fs.lstatSync(fullPath).isDirectory()) {
continue;
}

const dest = path.join(stashDir, entry);
core.info(`Stashing "${fullPath}"`);
try {
fs.renameSync(fullPath, dest);
} catch (err) {
core.warning(
`Could not stash "${fullPath}": ${
(err as Error).message
}. Skipping.`,
);
}
}

core.info(`Stashed extracted packages to "${stashDir}".`);
}
core.endGroup();
} catch (err) {
Expand Down
Loading