@expo/build-tools 1.0.243 → 1.0.244
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builders/android.js +28 -152
- package/dist/builders/android.js.map +1 -1
- package/dist/builders/ios.js +28 -152
- package/dist/builders/ios.js.map +1 -1
- package/dist/context.d.ts +0 -4
- package/dist/context.js +0 -14
- package/dist/context.js.map +1 -1
- package/dist/steps/functionGroups/build.js +41 -0
- package/dist/steps/functionGroups/build.js.map +1 -1
- package/dist/steps/functions/restoreBuildCache.d.ts +13 -0
- package/dist/steps/functions/restoreBuildCache.js +91 -0
- package/dist/steps/functions/restoreBuildCache.js.map +1 -0
- package/dist/steps/functions/saveBuildCache.d.ts +14 -0
- package/dist/steps/functions/saveBuildCache.js +97 -0
- package/dist/steps/functions/saveBuildCache.js.map +1 -0
- package/dist/utils/cacheKey.d.ts +8 -0
- package/dist/utils/cacheKey.js +68 -0
- package/dist/utils/cacheKey.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createRestoreBuildCacheFunction = createRestoreBuildCacheFunction;
|
|
7
|
+
exports.restoreCcacheAsync = restoreCcacheAsync;
|
|
8
|
+
const steps_1 = require("@expo/steps");
|
|
9
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
10
|
+
const results_1 = require("@expo/results");
|
|
11
|
+
const nullthrows_1 = __importDefault(require("nullthrows"));
|
|
12
|
+
const cacheKey_1 = require("../../utils/cacheKey");
|
|
13
|
+
const turtleFetch_1 = require("../../utils/turtleFetch");
|
|
14
|
+
const restoreCache_1 = require("./restoreCache");
|
|
15
|
+
function createRestoreBuildCacheFunction() {
|
|
16
|
+
return new steps_1.BuildFunction({
|
|
17
|
+
namespace: 'eas',
|
|
18
|
+
id: 'restore_build_cache',
|
|
19
|
+
name: 'Restore Cache',
|
|
20
|
+
inputProviders: [
|
|
21
|
+
steps_1.BuildStepInput.createProvider({
|
|
22
|
+
id: 'platform',
|
|
23
|
+
required: false,
|
|
24
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
fn: async (stepCtx, { env, inputs }) => {
|
|
28
|
+
var _a;
|
|
29
|
+
const { logger } = stepCtx;
|
|
30
|
+
const workingDirectory = stepCtx.workingDirectory;
|
|
31
|
+
const platform = (_a = inputs.platform.value) !== null && _a !== void 0 ? _a : stepCtx.global.staticContext.job.platform;
|
|
32
|
+
if (!platform || ![eas_build_job_1.Platform.ANDROID, eas_build_job_1.Platform.IOS].includes(platform)) {
|
|
33
|
+
throw new Error(`Unsupported platform: ${platform}. Platform must be "${eas_build_job_1.Platform.ANDROID}" or "${eas_build_job_1.Platform.IOS}"`);
|
|
34
|
+
}
|
|
35
|
+
await restoreCcacheAsync({
|
|
36
|
+
logger,
|
|
37
|
+
workingDirectory,
|
|
38
|
+
platform,
|
|
39
|
+
env,
|
|
40
|
+
secrets: stepCtx.global.staticContext.job.secrets,
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async function restoreCcacheAsync({ logger, workingDirectory, platform, env, secrets, }) {
|
|
46
|
+
var _a;
|
|
47
|
+
const enabled = env.EAS_RESTORE_CACHE === '1' || (env.EAS_USE_CACHE === '1' && env.EAS_RESTORE_CACHE !== '0');
|
|
48
|
+
if (!enabled) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const cacheKey = await (0, cacheKey_1.generateDefaultBuildCacheKeyAsync)(workingDirectory, platform);
|
|
53
|
+
logger.info(`Restoring cache key: ${cacheKey}`);
|
|
54
|
+
const jobId = (0, nullthrows_1.default)(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');
|
|
55
|
+
const robotAccessToken = (0, nullthrows_1.default)(secrets === null || secrets === void 0 ? void 0 : secrets.robotAccessToken, 'Robot access token is required for cache operations');
|
|
56
|
+
const expoApiServerURL = (0, nullthrows_1.default)(env.__API_SERVER_URL, '__API_SERVER_URL is not set');
|
|
57
|
+
const cachePath = (0, cacheKey_1.getCcachePath)(env);
|
|
58
|
+
const { archivePath, matchedKey } = await (0, restoreCache_1.downloadCacheAsync)({
|
|
59
|
+
logger,
|
|
60
|
+
jobId,
|
|
61
|
+
expoApiServerURL,
|
|
62
|
+
robotAccessToken,
|
|
63
|
+
paths: [cachePath],
|
|
64
|
+
key: cacheKey,
|
|
65
|
+
keyPrefixes: [cacheKey_1.CACHE_KEY_PREFIX_BY_PLATFORM[platform]],
|
|
66
|
+
platform,
|
|
67
|
+
});
|
|
68
|
+
await (0, restoreCache_1.decompressCacheAsync)({
|
|
69
|
+
archivePath,
|
|
70
|
+
workingDirectory,
|
|
71
|
+
verbose: env.EXPO_DEBUG === '1',
|
|
72
|
+
logger,
|
|
73
|
+
});
|
|
74
|
+
logger.info(`Cache restored successfully ${matchedKey === cacheKey ? '(direct hit)' : '(prefix match)'}`);
|
|
75
|
+
// Zero ccache stats for accurate tracking
|
|
76
|
+
await (0, results_1.asyncResult)((0, steps_1.spawnAsync)('ccache', ['--zero-stats'], {
|
|
77
|
+
env,
|
|
78
|
+
logger,
|
|
79
|
+
stdio: 'pipe',
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
if (err instanceof turtleFetch_1.TurtleFetchError && ((_a = err.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
|
|
84
|
+
logger.info('No cache found for this key.');
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
logger.warn({ err }, 'Failed to restore cache');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=restoreBuildCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restoreBuildCache.js","sourceRoot":"","sources":["../../../src/steps/functions/restoreBuildCache.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BuildFunction,\n BuildStepInput,\n BuildStepInputValueTypeName,\n spawnAsync,\n} from '@expo/steps';\nimport { Platform } from '@expo/eas-build-job';\nimport { bunyan } from '@expo/logger';\nimport { asyncResult } from '@expo/results';\nimport nullthrows from 'nullthrows';\n\nimport {\n CACHE_KEY_PREFIX_BY_PLATFORM,\n generateDefaultBuildCacheKeyAsync,\n getCcachePath,\n} from '../../utils/cacheKey';\nimport { TurtleFetchError } from '../../utils/turtleFetch';\n\nimport { downloadCacheAsync, decompressCacheAsync } from './restoreCache';\n\nexport function createRestoreBuildCacheFunction(): BuildFunction {\n return new BuildFunction({\n namespace: 'eas',\n id: 'restore_build_cache',\n name: 'Restore Cache',\n inputProviders: [\n BuildStepInput.createProvider({\n id: 'platform',\n required: false,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n ],\n fn: async (stepCtx, { env, inputs }) => {\n const { logger } = stepCtx;\n const workingDirectory = stepCtx.workingDirectory;\n const platform =\n (inputs.platform.value as Platform | undefined) ??\n stepCtx.global.staticContext.job.platform;\n if (!platform || ![Platform.ANDROID, Platform.IOS].includes(platform)) {\n throw new Error(\n `Unsupported platform: ${platform}. Platform must be \"${Platform.ANDROID}\" or \"${Platform.IOS}\"`\n );\n }\n\n await restoreCcacheAsync({\n logger,\n workingDirectory,\n platform,\n env,\n secrets: stepCtx.global.staticContext.job.secrets,\n });\n },\n });\n}\n\nexport async function restoreCcacheAsync({\n logger,\n workingDirectory,\n platform,\n env,\n secrets,\n}: {\n logger: bunyan;\n workingDirectory: string;\n platform: Platform;\n env: Record<string, string | undefined>;\n secrets?: { robotAccessToken?: string };\n}): Promise<void> {\n const enabled =\n env.EAS_RESTORE_CACHE === '1' || (env.EAS_USE_CACHE === '1' && env.EAS_RESTORE_CACHE !== '0');\n\n if (!enabled) {\n return;\n }\n try {\n const cacheKey = await generateDefaultBuildCacheKeyAsync(workingDirectory, platform);\n logger.info(`Restoring cache key: ${cacheKey}`);\n\n const jobId = nullthrows(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');\n const robotAccessToken = nullthrows(\n secrets?.robotAccessToken,\n 'Robot access token is required for cache operations'\n );\n const expoApiServerURL = nullthrows(env.__API_SERVER_URL, '__API_SERVER_URL is not set');\n const cachePath = getCcachePath(env);\n const { archivePath, matchedKey } = await downloadCacheAsync({\n logger,\n jobId,\n expoApiServerURL,\n robotAccessToken,\n paths: [cachePath],\n key: cacheKey,\n keyPrefixes: [CACHE_KEY_PREFIX_BY_PLATFORM[platform]],\n platform,\n });\n\n await decompressCacheAsync({\n archivePath,\n workingDirectory,\n verbose: env.EXPO_DEBUG === '1',\n logger,\n });\n\n logger.info(\n `Cache restored successfully ${matchedKey === cacheKey ? '(direct hit)' : '(prefix match)'}`\n );\n\n // Zero ccache stats for accurate tracking\n await asyncResult(\n spawnAsync('ccache', ['--zero-stats'], {\n env,\n logger,\n stdio: 'pipe',\n })\n );\n } catch (err: unknown) {\n if (err instanceof TurtleFetchError && err.response?.status === 404) {\n logger.info('No cache found for this key.');\n } else {\n logger.warn({ err }, 'Failed to restore cache');\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BuildFunction } from '@expo/steps';
|
|
2
|
+
import { Platform } from '@expo/eas-build-job';
|
|
3
|
+
import { bunyan } from '@expo/logger';
|
|
4
|
+
export declare function createSaveBuildCacheFunction(evictUsedBefore: Date): BuildFunction;
|
|
5
|
+
export declare function saveCcacheAsync({ logger, workingDirectory, platform, evictUsedBefore, env, secrets, }: {
|
|
6
|
+
logger: bunyan;
|
|
7
|
+
workingDirectory: string;
|
|
8
|
+
platform: Platform;
|
|
9
|
+
evictUsedBefore: Date;
|
|
10
|
+
env: Record<string, string | undefined>;
|
|
11
|
+
secrets?: {
|
|
12
|
+
robotAccessToken?: string;
|
|
13
|
+
};
|
|
14
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createSaveBuildCacheFunction = createSaveBuildCacheFunction;
|
|
7
|
+
exports.saveCcacheAsync = saveCcacheAsync;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const steps_1 = require("@expo/steps");
|
|
10
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
11
|
+
const results_1 = require("@expo/results");
|
|
12
|
+
const nullthrows_1 = __importDefault(require("nullthrows"));
|
|
13
|
+
const cacheKey_1 = require("../../utils/cacheKey");
|
|
14
|
+
const saveCache_1 = require("./saveCache");
|
|
15
|
+
function createSaveBuildCacheFunction(evictUsedBefore) {
|
|
16
|
+
return new steps_1.BuildFunction({
|
|
17
|
+
namespace: 'eas',
|
|
18
|
+
id: 'save_build_cache',
|
|
19
|
+
name: 'Save Cache',
|
|
20
|
+
inputProviders: [
|
|
21
|
+
steps_1.BuildStepInput.createProvider({
|
|
22
|
+
id: 'platform',
|
|
23
|
+
required: false,
|
|
24
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
fn: async (stepCtx, { env, inputs }) => {
|
|
28
|
+
var _a;
|
|
29
|
+
const { logger } = stepCtx;
|
|
30
|
+
const workingDirectory = stepCtx.workingDirectory;
|
|
31
|
+
const platform = (_a = inputs.platform.value) !== null && _a !== void 0 ? _a : stepCtx.global.staticContext.job.platform;
|
|
32
|
+
if (!platform || ![eas_build_job_1.Platform.ANDROID, eas_build_job_1.Platform.IOS].includes(platform)) {
|
|
33
|
+
throw new Error(`Unsupported platform: ${platform}. Platform must be "${eas_build_job_1.Platform.ANDROID}" or "${eas_build_job_1.Platform.IOS}"`);
|
|
34
|
+
}
|
|
35
|
+
await saveCcacheAsync({
|
|
36
|
+
logger,
|
|
37
|
+
workingDirectory,
|
|
38
|
+
platform,
|
|
39
|
+
evictUsedBefore,
|
|
40
|
+
env,
|
|
41
|
+
secrets: stepCtx.global.staticContext.job.secrets,
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function saveCcacheAsync({ logger, workingDirectory, platform, evictUsedBefore, env, secrets, }) {
|
|
47
|
+
const enabled = env.EAS_SAVE_CACHE === '1' || (env.EAS_USE_CACHE === '1' && env.EAS_SAVE_CACHE !== '0');
|
|
48
|
+
if (!enabled) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const cacheKey = await (0, cacheKey_1.generateDefaultBuildCacheKeyAsync)(workingDirectory, platform);
|
|
53
|
+
logger.info(`Saving cache key: ${cacheKey}`);
|
|
54
|
+
const jobId = (0, nullthrows_1.default)(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');
|
|
55
|
+
const robotAccessToken = (0, nullthrows_1.default)(secrets === null || secrets === void 0 ? void 0 : secrets.robotAccessToken, 'Robot access token is required for cache operations');
|
|
56
|
+
const expoApiServerURL = (0, nullthrows_1.default)(env.__API_SERVER_URL, '__API_SERVER_URL is not set');
|
|
57
|
+
const cachePath = (0, cacheKey_1.getCcachePath)(env);
|
|
58
|
+
// Cache size can blow up over time over many builds, so evict stale files
|
|
59
|
+
// and only upload what was used within this build's time window
|
|
60
|
+
const evictWindow = Math.floor((Date.now() - evictUsedBefore.getTime()) / 1000);
|
|
61
|
+
logger.info('Pruning cache...');
|
|
62
|
+
await (0, results_1.asyncResult)((0, steps_1.spawnAsync)('ccache', ['--evict-older-than', evictWindow + 's'], {
|
|
63
|
+
env,
|
|
64
|
+
logger,
|
|
65
|
+
stdio: 'pipe',
|
|
66
|
+
}));
|
|
67
|
+
logger.info('Cache stats:');
|
|
68
|
+
await (0, results_1.asyncResult)((0, steps_1.spawnAsync)('ccache', ['--show-stats', '-v'], {
|
|
69
|
+
env,
|
|
70
|
+
logger,
|
|
71
|
+
stdio: 'pipe',
|
|
72
|
+
}));
|
|
73
|
+
logger.info('Preparing cache archive...');
|
|
74
|
+
const { archivePath } = await (0, saveCache_1.compressCacheAsync)({
|
|
75
|
+
paths: [cachePath],
|
|
76
|
+
workingDirectory,
|
|
77
|
+
verbose: env.EXPO_DEBUG === '1',
|
|
78
|
+
logger,
|
|
79
|
+
});
|
|
80
|
+
const { size } = await fs_1.default.promises.stat(archivePath);
|
|
81
|
+
await (0, saveCache_1.uploadCacheAsync)({
|
|
82
|
+
logger,
|
|
83
|
+
jobId,
|
|
84
|
+
expoApiServerURL,
|
|
85
|
+
robotAccessToken,
|
|
86
|
+
archivePath,
|
|
87
|
+
key: cacheKey,
|
|
88
|
+
paths: [cachePath],
|
|
89
|
+
size,
|
|
90
|
+
platform,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
logger.error({ err }, 'Failed to save cache');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=saveBuildCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"saveBuildCache.js","sourceRoot":"","sources":["../../../src/steps/functions/saveBuildCache.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\n\nimport {\n BuildFunction,\n BuildStepInput,\n BuildStepInputValueTypeName,\n spawnAsync,\n} from '@expo/steps';\nimport { Platform } from '@expo/eas-build-job';\nimport { bunyan } from '@expo/logger';\nimport { asyncResult } from '@expo/results';\nimport nullthrows from 'nullthrows';\n\nimport { generateDefaultBuildCacheKeyAsync, getCcachePath } from '../../utils/cacheKey';\n\nimport { compressCacheAsync, uploadCacheAsync } from './saveCache';\n\nexport function createSaveBuildCacheFunction(evictUsedBefore: Date): BuildFunction {\n return new BuildFunction({\n namespace: 'eas',\n id: 'save_build_cache',\n name: 'Save Cache',\n inputProviders: [\n BuildStepInput.createProvider({\n id: 'platform',\n required: false,\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n }),\n ],\n fn: async (stepCtx, { env, inputs }) => {\n const { logger } = stepCtx;\n const workingDirectory = stepCtx.workingDirectory;\n const platform =\n (inputs.platform.value as Platform | undefined) ??\n stepCtx.global.staticContext.job.platform;\n if (!platform || ![Platform.ANDROID, Platform.IOS].includes(platform)) {\n throw new Error(\n `Unsupported platform: ${platform}. Platform must be \"${Platform.ANDROID}\" or \"${Platform.IOS}\"`\n );\n }\n\n await saveCcacheAsync({\n logger,\n workingDirectory,\n platform,\n evictUsedBefore,\n env,\n secrets: stepCtx.global.staticContext.job.secrets,\n });\n },\n });\n}\n\nexport async function saveCcacheAsync({\n logger,\n workingDirectory,\n platform,\n evictUsedBefore,\n env,\n secrets,\n}: {\n logger: bunyan;\n workingDirectory: string;\n platform: Platform;\n evictUsedBefore: Date;\n env: Record<string, string | undefined>;\n secrets?: { robotAccessToken?: string };\n}): Promise<void> {\n const enabled =\n env.EAS_SAVE_CACHE === '1' || (env.EAS_USE_CACHE === '1' && env.EAS_SAVE_CACHE !== '0');\n\n if (!enabled) {\n return;\n }\n\n try {\n const cacheKey = await generateDefaultBuildCacheKeyAsync(workingDirectory, platform);\n logger.info(`Saving cache key: ${cacheKey}`);\n\n const jobId = nullthrows(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');\n const robotAccessToken = nullthrows(\n secrets?.robotAccessToken,\n 'Robot access token is required for cache operations'\n );\n const expoApiServerURL = nullthrows(env.__API_SERVER_URL, '__API_SERVER_URL is not set');\n const cachePath = getCcachePath(env);\n\n // Cache size can blow up over time over many builds, so evict stale files\n // and only upload what was used within this build's time window\n const evictWindow = Math.floor((Date.now() - evictUsedBefore.getTime()) / 1000);\n logger.info('Pruning cache...');\n await asyncResult(\n spawnAsync('ccache', ['--evict-older-than', evictWindow + 's'], {\n env,\n logger,\n stdio: 'pipe',\n })\n );\n\n logger.info('Cache stats:');\n await asyncResult(\n spawnAsync('ccache', ['--show-stats', '-v'], {\n env,\n logger,\n stdio: 'pipe',\n })\n );\n\n logger.info('Preparing cache archive...');\n\n const { archivePath } = await compressCacheAsync({\n paths: [cachePath],\n workingDirectory,\n verbose: env.EXPO_DEBUG === '1',\n logger,\n });\n\n const { size } = await fs.promises.stat(archivePath);\n\n await uploadCacheAsync({\n logger,\n jobId,\n expoApiServerURL,\n robotAccessToken,\n archivePath,\n key: cacheKey,\n paths: [cachePath],\n size,\n platform,\n });\n } catch (err) {\n logger.error({ err }, 'Failed to save cache');\n }\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Platform } from '@expo/eas-build-job';
|
|
2
|
+
export declare const IOS_CACHE_KEY_PREFIX = "ios-ccache-";
|
|
3
|
+
export declare const ANDROID_CACHE_KEY_PREFIX = "android-ccache-";
|
|
4
|
+
export declare const DARWIN_CACHE_PATH = "Library/Caches/ccache";
|
|
5
|
+
export declare const LINUX_CACHE_PATH = ".cache/ccache";
|
|
6
|
+
export declare const CACHE_KEY_PREFIX_BY_PLATFORM: Record<Platform, string>;
|
|
7
|
+
export declare function getCcachePath(env: Record<string, string | undefined>): string;
|
|
8
|
+
export declare function generateDefaultBuildCacheKeyAsync(workingDirectory: string, platform: Platform): Promise<string>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.CACHE_KEY_PREFIX_BY_PLATFORM = exports.LINUX_CACHE_PATH = exports.DARWIN_CACHE_PATH = exports.ANDROID_CACHE_KEY_PREFIX = exports.IOS_CACHE_KEY_PREFIX = void 0;
|
|
30
|
+
exports.getCcachePath = getCcachePath;
|
|
31
|
+
exports.generateDefaultBuildCacheKeyAsync = generateDefaultBuildCacheKeyAsync;
|
|
32
|
+
const path_1 = __importDefault(require("path"));
|
|
33
|
+
const os_1 = __importDefault(require("os"));
|
|
34
|
+
const assert_1 = __importDefault(require("assert"));
|
|
35
|
+
const PackageManagerUtils = __importStar(require("@expo/package-manager"));
|
|
36
|
+
const steps_1 = require("@expo/steps");
|
|
37
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
38
|
+
const packageManager_1 = require("./packageManager");
|
|
39
|
+
exports.IOS_CACHE_KEY_PREFIX = 'ios-ccache-';
|
|
40
|
+
exports.ANDROID_CACHE_KEY_PREFIX = 'android-ccache-';
|
|
41
|
+
exports.DARWIN_CACHE_PATH = 'Library/Caches/ccache';
|
|
42
|
+
exports.LINUX_CACHE_PATH = '.cache/ccache';
|
|
43
|
+
exports.CACHE_KEY_PREFIX_BY_PLATFORM = {
|
|
44
|
+
[eas_build_job_1.Platform.ANDROID]: exports.ANDROID_CACHE_KEY_PREFIX,
|
|
45
|
+
[eas_build_job_1.Platform.IOS]: exports.IOS_CACHE_KEY_PREFIX,
|
|
46
|
+
};
|
|
47
|
+
const PATH_BY_PLATFORM = {
|
|
48
|
+
darwin: exports.DARWIN_CACHE_PATH,
|
|
49
|
+
linux: exports.LINUX_CACHE_PATH,
|
|
50
|
+
};
|
|
51
|
+
function getCcachePath(env) {
|
|
52
|
+
(0, assert_1.default)(env.HOME, 'Failed to infer directory: $HOME environment variable is empty.');
|
|
53
|
+
return path_1.default.join(env.HOME, PATH_BY_PLATFORM[os_1.default.platform()]);
|
|
54
|
+
}
|
|
55
|
+
async function generateDefaultBuildCacheKeyAsync(workingDirectory, platform) {
|
|
56
|
+
// This will resolve which package manager and use the relevant lock file
|
|
57
|
+
// The lock file hash is the key and ensures cache is fresh
|
|
58
|
+
const packagerRunDir = (0, packageManager_1.findPackagerRootDir)(workingDirectory);
|
|
59
|
+
const manager = PackageManagerUtils.createForProject(packagerRunDir);
|
|
60
|
+
const lockPath = path_1.default.join(packagerRunDir, manager.lockFile);
|
|
61
|
+
try {
|
|
62
|
+
return `${exports.CACHE_KEY_PREFIX_BY_PLATFORM[platform]}${(0, steps_1.hashFiles)([lockPath])}`;
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
throw new Error(`Failed to read lockfile for cache key generation: ${err.message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=cacheKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cacheKey.js","sourceRoot":"","sources":["../../src/utils/cacheKey.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,sCAGC;AAED,8EAeC;AA7CD,gDAAwB;AACxB,4CAAoB;AACpB,oDAA4B;AAE5B,2EAA6D;AAC7D,uCAAwC;AACxC,uDAA+C;AAE/C,qDAAuD;AAE1C,QAAA,oBAAoB,GAAG,aAAa,CAAC;AACrC,QAAA,wBAAwB,GAAG,iBAAiB,CAAC;AAC7C,QAAA,iBAAiB,GAAG,uBAAuB,CAAC;AAC5C,QAAA,gBAAgB,GAAG,eAAe,CAAC;AAEnC,QAAA,4BAA4B,GAA6B;IACpE,CAAC,wBAAQ,CAAC,OAAO,CAAC,EAAE,gCAAwB;IAC5C,CAAC,wBAAQ,CAAC,GAAG,CAAC,EAAE,4BAAoB;CACrC,CAAC;AAEF,MAAM,gBAAgB,GAA2B;IAC/C,MAAM,EAAE,yBAAiB;IACzB,KAAK,EAAE,wBAAgB;CACxB,CAAC;AAEF,SAAgB,aAAa,CAAC,GAAuC;IACnE,IAAA,gBAAM,EAAC,GAAG,CAAC,IAAI,EAAE,iEAAiE,CAAC,CAAC;IACpF,OAAO,cAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,gBAAgB,CAAC,YAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;AAC9D,CAAC;AAEM,KAAK,UAAU,iCAAiC,CACrD,gBAAwB,EACxB,QAAkB;IAElB,yEAAyE;IACzE,2DAA2D;IAC3D,MAAM,cAAc,GAAG,IAAA,oCAAmB,EAAC,gBAAgB,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,mBAAmB,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,OAAO,GAAG,oCAA4B,CAAC,QAAQ,CAAC,GAAG,IAAA,iBAAS,EAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;IAC7E,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,qDAAqD,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACtF,CAAC;AACH,CAAC","sourcesContent":["import path from 'path';\nimport os from 'os';\nimport assert from 'assert';\n\nimport * as PackageManagerUtils from '@expo/package-manager';\nimport { hashFiles } from '@expo/steps';\nimport { Platform } from '@expo/eas-build-job';\n\nimport { findPackagerRootDir } from './packageManager';\n\nexport const IOS_CACHE_KEY_PREFIX = 'ios-ccache-';\nexport const ANDROID_CACHE_KEY_PREFIX = 'android-ccache-';\nexport const DARWIN_CACHE_PATH = 'Library/Caches/ccache';\nexport const LINUX_CACHE_PATH = '.cache/ccache';\n\nexport const CACHE_KEY_PREFIX_BY_PLATFORM: Record<Platform, string> = {\n [Platform.ANDROID]: ANDROID_CACHE_KEY_PREFIX,\n [Platform.IOS]: IOS_CACHE_KEY_PREFIX,\n};\n\nconst PATH_BY_PLATFORM: Record<string, string> = {\n darwin: DARWIN_CACHE_PATH,\n linux: LINUX_CACHE_PATH,\n};\n\nexport function getCcachePath(env: Record<string, string | undefined>): string {\n assert(env.HOME, 'Failed to infer directory: $HOME environment variable is empty.');\n return path.join(env.HOME, PATH_BY_PLATFORM[os.platform()]);\n}\n\nexport async function generateDefaultBuildCacheKeyAsync(\n workingDirectory: string,\n platform: Platform\n): Promise<string> {\n // This will resolve which package manager and use the relevant lock file\n // The lock file hash is the key and ensures cache is fresh\n const packagerRunDir = findPackagerRootDir(workingDirectory);\n const manager = PackageManagerUtils.createForProject(packagerRunDir);\n const lockPath = path.join(packagerRunDir, manager.lockFile);\n\n try {\n return `${CACHE_KEY_PREFIX_BY_PLATFORM[platform]}${hashFiles([lockPath])}`;\n } catch (err: any) {\n throw new Error(`Failed to read lockfile for cache key generation: ${err.message}`);\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/build-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.244",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@expo/package-manager": "1.7.0",
|
|
38
38
|
"@expo/plist": "^0.2.0",
|
|
39
39
|
"@expo/results": "^1.0.0",
|
|
40
|
-
"@expo/steps": "1.0.
|
|
40
|
+
"@expo/steps": "1.0.244",
|
|
41
41
|
"@expo/template-file": "1.0.221",
|
|
42
42
|
"@expo/turtle-spawn": "1.0.221",
|
|
43
43
|
"@expo/xcpretty": "^4.3.1",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"node": "20.14.0",
|
|
86
86
|
"yarn": "1.22.21"
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "3b2beb943feeb88779e363d3c5ebc21f4f80e4b1"
|
|
89
89
|
}
|