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
18 changes: 3 additions & 15 deletions packages/cli/lib/framework/utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import path from "node:path";
import {graphFromStaticFile, graphFromPackageDependencies} from "@ui5/project/graph";
import Configuration from "@ui5/project/config/Configuration";
import {resolveUi5DataDir} from "@ui5/project/utils/dataDir";

export async function getRootProjectConfiguration(projectGraphOptions) {
let graph;
Expand Down Expand Up @@ -37,34 +36,23 @@ export async function createFrameworkResolverInstance({frameworkName, frameworkV
return new Resolver({
cwd,
version: frameworkVersion,
ui5DataDir: await utils.getUi5DataDir({cwd})
ui5DataDir: await resolveUi5DataDir({projectRootPath: cwd})
});
}

export async function frameworkResolverResolveVersion({frameworkName, frameworkVersion}, {cwd}) {
const Resolver = await utils.getFrameworkResolver(frameworkName, frameworkVersion);
return Resolver.resolveVersion(frameworkVersion, {
cwd,
ui5DataDir: await utils.getUi5DataDir({cwd})
ui5DataDir: await resolveUi5DataDir({projectRootPath: cwd})
});
}

async function getUi5DataDir({cwd}) {
// ENV var should take precedence over the dataDir from the configuration.
let ui5DataDir = process.env.UI5_DATA_DIR;
if (!ui5DataDir) {
const config = await Configuration.fromFile();
ui5DataDir = config.getUi5DataDir();
}
return ui5DataDir ? path.resolve(cwd, ui5DataDir) : undefined;
}

const utils = {
getRootProjectConfiguration,
getFrameworkResolver,
createFrameworkResolverInstance,
frameworkResolverResolveVersion,
getUi5DataDir
};
let _utils;
// For mocking of functions in unit tests and testing internal functions
Expand Down
89 changes: 15 additions & 74 deletions packages/cli/test/lib/framework/utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import test from "ava";
import sinonGlobal from "sinon";
import esmock from "esmock";
import path from "node:path";

test.beforeEach(async (t) => {
// Tests either rely on not having UI5_DATA_DIR defined, or explicitly define it
Expand All @@ -21,12 +20,7 @@ test.beforeEach(async (t) => {
t.context.Openui5Resolver = sinon.stub();
t.context.Sapui5MavenSnapshotResolver = sinon.stub();

t.context.ConfigurationGetUi5DataDirStub = sinon.stub().returns(undefined);
t.context.ConfigurationStub = {
fromFile: sinon.stub().resolves({
getUi5DataDir: t.context.ConfigurationGetUi5DataDirStub
})
};
t.context.resolveUi5DataDirStub = sinon.stub().resolves("my-default-ui5-data-dir");

t.context.utils = await esmock.p("../../../lib/framework/utils.js", {
"@ui5/project/graph": {
Expand All @@ -42,7 +36,9 @@ test.beforeEach(async (t) => {
"@ui5/project/ui5Framework/Sapui5MavenSnapshotResolver": {
default: t.context.Sapui5MavenSnapshotResolver
},
"@ui5/project/config/Configuration": t.context.ConfigurationStub
"@ui5/project/utils/dataDir": {
resolveUi5DataDir: t.context.resolveUi5DataDirStub
}
});
t.context._utils = t.context.utils._utils;
});
Expand Down Expand Up @@ -142,13 +138,13 @@ test.serial("getFrameworkResolver: Invalid framework.name", async (t) => {
});
});

test.serial("createFrameworkResolverInstance: Without ui5DataDir", async (t) => {
test.serial("createFrameworkResolverInstance: Without explicit ui5DataDir (uses resolved default)", async (t) => {
const {createFrameworkResolverInstance} = t.context.utils;
const {sinon} = t.context;
const {sinon, resolveUi5DataDirStub} = t.context;

const ResolverStub = sinon.stub().returns({});
sinon.stub(t.context._utils, "getFrameworkResolver").resolves(ResolverStub);
sinon.stub(t.context._utils, "getUi5DataDir").resolves(undefined);
resolveUi5DataDirStub.resolves("my-default-ui5-data-dir");

const result = await createFrameworkResolverInstance({
frameworkName: "<framework-name>",
Expand All @@ -163,12 +159,7 @@ test.serial("createFrameworkResolverInstance: Without ui5DataDir", async (t) =>
"<framework-version>"
]);

t.is(t.context._utils.getUi5DataDir.callCount, 1);
t.deepEqual(t.context._utils.getUi5DataDir.getCall(0).args, [
{
cwd: "my-project-path"
}
]);
t.is(resolveUi5DataDirStub.callCount, 1);

t.is(ResolverStub.callCount, 1);
t.is(result, ResolverStub.getCall(0).returnValue);
Expand All @@ -177,18 +168,18 @@ test.serial("createFrameworkResolverInstance: Without ui5DataDir", async (t) =>
{
cwd: "my-project-path",
version: "<framework-version>",
ui5DataDir: undefined
ui5DataDir: "my-default-ui5-data-dir"
}
]);
});

test.serial("createFrameworkResolverInstance: With ui5DataDir", async (t) => {
const {createFrameworkResolverInstance} = t.context.utils;
const {sinon} = t.context;
const {sinon, resolveUi5DataDirStub} = t.context;

const ResolverStub = sinon.stub().returns({});
sinon.stub(t.context._utils, "getFrameworkResolver").resolves(ResolverStub);
sinon.stub(t.context._utils, "getUi5DataDir").resolves("my-ui5-data-dir");
resolveUi5DataDirStub.resolves("my-ui5-data-dir");

const result = await createFrameworkResolverInstance({
frameworkName: "<framework-name>",
Expand All @@ -203,12 +194,7 @@ test.serial("createFrameworkResolverInstance: With ui5DataDir", async (t) => {
"<framework-version>"
]);

t.is(t.context._utils.getUi5DataDir.callCount, 1);
t.deepEqual(t.context._utils.getUi5DataDir.getCall(0).args, [
{
cwd: "my-project-path"
}
]);
t.is(resolveUi5DataDirStub.callCount, 1);

t.is(ResolverStub.callCount, 1);
t.is(result, ResolverStub.getCall(0).returnValue);
Expand All @@ -224,13 +210,13 @@ test.serial("createFrameworkResolverInstance: With ui5DataDir", async (t) => {

test.serial("frameworkResolverResolveVersion", async (t) => {
const {frameworkResolverResolveVersion} = t.context.utils;
const {sinon} = t.context;
const {sinon, resolveUi5DataDirStub} = t.context;

const resolveVersionStub = sinon.stub().resolves("1.111.1");
sinon.stub(t.context._utils, "getFrameworkResolver").resolves({
resolveVersion: resolveVersionStub
});
sinon.stub(t.context._utils, "getUi5DataDir").resolves(undefined);
resolveUi5DataDirStub.resolves("my-default-ui5-data-dir");

const result = await frameworkResolverResolveVersion({
frameworkName: "SAPUI5",
Expand All @@ -246,52 +232,7 @@ test.serial("frameworkResolverResolveVersion", async (t) => {
"latest",
{
cwd: "my-project-path",
ui5DataDir: undefined
ui5DataDir: "my-default-ui5-data-dir"
}
]);
});

test.serial("getUi5DataDir: no value defined", async (t) => {
const {ConfigurationGetUi5DataDirStub} = t.context;
const {getUi5DataDir} = t.context._utils;

const result = await getUi5DataDir({
cwd: path.resolve("foo")
});

t.is(result, undefined);

t.is(ConfigurationGetUi5DataDirStub.callCount, 1);
});

test.serial("getUi5DataDir: from environment variable", async (t) => {
const {ConfigurationGetUi5DataDirStub} = t.context;
const {getUi5DataDir} = t.context._utils;

// Environment variable must be preferred over configuration value
ConfigurationGetUi5DataDirStub.returns(".ui5-data-dir-from-configuration");
process.env.UI5_DATA_DIR = ".ui5-data-dir-from-env-variable";

const result = await getUi5DataDir({
cwd: path.resolve("foo")
});

t.is(result, path.join(path.resolve("foo"), ".ui5-data-dir-from-env-variable"));

t.is(ConfigurationGetUi5DataDirStub.callCount, 0);
});

test.serial("getUi5DataDir: from Configuration", async (t) => {
const {ConfigurationGetUi5DataDirStub} = t.context;
const {getUi5DataDir} = t.context._utils;

ConfigurationGetUi5DataDirStub.returns(".ui5-data-dir-from-configuration");

const result = await getUi5DataDir({
cwd: path.resolve("foo")
});

t.is(result, path.join(path.resolve("foo"), ".ui5-data-dir-from-configuration"));

t.is(ConfigurationGetUi5DataDirStub.callCount, 1);
});
21 changes: 6 additions & 15 deletions packages/project/lib/build/cache/CacheManager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import path from "node:path";
import os from "node:os";
import Configuration from "../../config/Configuration.js";
import {resolveUi5DataDir} from "../../utils/dataDir.js";
import {getLogger} from "@ui5/logger";
import BuildCacheStorage from "./BuildCacheStorage.js";

Expand Down Expand Up @@ -60,9 +59,9 @@ export default class CacheManager {
* Returns a singleton CacheManager for the determined cache directory.
* The cache directory is resolved in this order:
* 1. Explicit <code>ui5DataDir</code> option (resolved relative to cwd)
* 2. UI5_DATA_DIR environment variable (resolved relative to cwd)
* 3. ui5DataDir from UI5 configuration file
* 4. Default: ~/.ui5/
* 2. UI5_DATA_DIR environment variable or ui5DataDir from configuration file
* (resolved relative to cwd via {@link resolveUi5DataDir})
* 3. Default: ~/.ui5/
*
* @public
* @param {string} cwd Current working directory for resolving relative paths
Expand All @@ -73,17 +72,9 @@ export default class CacheManager {
*/
static async create(cwd, {ui5DataDir} = {}) {
if (!ui5DataDir) {
// ENV var should take precedence over the dataDir from the configuration.
ui5DataDir = process.env.UI5_DATA_DIR;
if (!ui5DataDir) {
const config = await Configuration.fromFile();
ui5DataDir = config.getUi5DataDir();
}
}
if (ui5DataDir) {
ui5DataDir = path.resolve(cwd, ui5DataDir);
ui5DataDir = await resolveUi5DataDir({projectRootPath: cwd});
} else {
ui5DataDir = path.join(os.homedir(), ".ui5");
ui5DataDir = path.resolve(cwd, ui5DataDir);
}
const cacheDir = path.join(ui5DataDir, "buildCache");
log.verbose(`Using build cache directory: ${cacheDir}`);
Expand Down
15 changes: 4 additions & 11 deletions packages/project/lib/graph/helpers/ui5Framework.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import Module from "../Module.js";
import ProjectGraph from "../ProjectGraph.js";
import {getLogger} from "@ui5/logger";
const log = getLogger("graph:helpers:ui5Framework");
import Configuration from "../../config/Configuration.js";
import path from "node:path";
import {resolveUi5DataDir} from "../../utils/dataDir.js";

class ProjectProcessor {
constructor({libraryMetadata, graph, workspace}) {
Expand Down Expand Up @@ -348,15 +347,9 @@ export default {
Resolver = (await import("../../ui5Framework/Sapui5Resolver.js")).default;
}

// ENV var should take precedence over the dataDir from the configuration.
let ui5DataDir = process.env.UI5_DATA_DIR;
if (!ui5DataDir) {
const config = await Configuration.fromFile();
ui5DataDir = config.getUi5DataDir();
}
if (ui5DataDir) {
ui5DataDir = path.resolve(cwd, ui5DataDir);
}
// Resolve the UI5 data directory using the shared utility.
// Returns ~/.ui5 by default when no env var or configuration is set.
const ui5DataDir = await resolveUi5DataDir({projectRootPath: cwd});

if (options.versionOverride) {
version = await Resolver.resolveVersion(options.versionOverride, {
Expand Down
34 changes: 34 additions & 0 deletions packages/project/lib/utils/dataDir.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import path from "node:path";
import os from "node:os";
import Configuration from "../config/Configuration.js";

/**
* Resolves the UI5 data directory using the standard precedence chain:
* <ol>
* <li>UI5_DATA_DIR environment variable</li>
* <li>ui5DataDir option from the configuration file (~/.ui5rc)</li>
* <li>Default: ~/.ui5</li>
* </ol>
*
* This function always returns an absolute path — never <code>undefined</code>.
*
* @param {object} [options]
* @param {string} [options.projectRootPath] The root directory of the project being processed.
* Used to resolve a relative <code>ui5DataDir</code> value from the environment variable or
* configuration file against the correct base. This is NOT necessarily the shell's current
* working directory — when processing a project in a sub-directory or a workspace member,
* this should be the root of that specific project (where its <code>package.json</code> lives).
* Defaults to <code>process.cwd()</code> when not provided.
* @returns {Promise<string>} Resolved absolute path to the UI5 data directory
*/
export async function resolveUi5DataDir({projectRootPath} = {}) {
let ui5DataDir = process.env.UI5_DATA_DIR;
if (!ui5DataDir) {
const config = await Configuration.fromFile();
ui5DataDir = config.getUi5DataDir();
}
if (ui5DataDir) {
return path.resolve(projectRootPath ?? process.cwd(), ui5DataDir);
}
return path.resolve(os.homedir(), ".ui5");
}
1 change: 1 addition & 0 deletions packages/project/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"./ui5Framework/Sapui5Resolver": "./lib/ui5Framework/Sapui5Resolver.js",
"./ui5Framework/maven/SnapshotCache": "./lib/ui5Framework/maven/SnapshotCache.js",
"./validation/validator": "./lib/validation/validator.js",
"./utils/dataDir": "./lib/utils/dataDir.js",
"./validation/ValidationError": "./lib/validation/ValidationError.js",
"./graph/ProjectGraph": "./lib/graph/ProjectGraph.js",
"./graph/projectGraphBuilder": "./lib/graph/projectGraphBuilder.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ test.beforeEach(async (t) => {
"../../../../lib/graph/Module.js": t.context.Module,
"../../../../lib/ui5Framework/Openui5Resolver.js": t.context.Openui5Resolver,
"../../../../lib/ui5Framework/Sapui5Resolver.js": t.context.Sapui5Resolver,
"../../../../lib/config/Configuration.js": t.context.Configuration
"../../../../lib/config/Configuration.js": t.context.Configuration,
"../../../../lib/utils/dataDir.js": {
resolveUi5DataDir: sinon.stub().resolves(path.join(fakeBaseDir, "homedir", ".ui5"))
}
});

t.context.projectGraphBuilder = await esmock.p("../../../../lib/graph/projectGraphBuilder.js", {
Expand Down
Loading
Loading