Skip to content

Commit

Permalink
refactor: de-global env (#65)
Browse files Browse the repository at this point in the history
* refactor: function signatures

Replace object parameters with separate parameters. This is mostly done for consistency, as most functions in the project use multiple parameters. Also it makes the function signature a lot shorter.

* refactor: move env usage up

Remove env usage from pkg-manifest-io

* refactor: move env usage up

Remove env usage from upm-config-io

* refactor: move up env usage

Remove env from fetchPackageInfo

* refactor: move up env usage

Remove usage from registry-client

* refactor: remove extraneous functions

Removes the _ functions that exist in some cmd files by either making them local functions inside the main cmd function or by just moving their content into the main cmd function.

The goals for this are:
- Move env usage up into just the env functions
- Avoid unnecessary parameter passing

* refactor: move up env usage

Remove env from getNpmFetchOptions function

* refactor: move up env usage

Remove env usage from manifest-assertions

* refactor: move up env usage

Remove env usage from writeUnityToken

* refactor: extract helper function

* refactor: manifest-path logic

Manifest-path is no longer stored on env, but calculated on demand from cwd. The goal here is to shrink env / deduplicate information in it.

parseEnv still checks whether manifest-path exists

* refactor: de-global env

Make env a non-global value

* refactor: registry in env

instead of storing urls for regular and upstream registry, as well as all auths, now we store only the auths for the used registries and put them together with the registry urls

* refactor: remove property from env

nmpAuth is only used inside the parse-env function and can be removed from env

* refactor: remove property from env

color is only used inside the parse-env function and can be made local

* refactor: remove property from env

region is only used inside the parse-env function and can be made local

* fix: typo in property name

This typo caused color to be used in test scenarios which would mess with the mock console

* fix: color option

If the color option is undefined it should also count as true
  • Loading branch information
ComradeVanti authored Dec 19, 2023
1 parent bb1c999 commit 2c0bdab
Show file tree
Hide file tree
Showing 18 changed files with 618 additions and 654 deletions.
358 changes: 175 additions & 183 deletions src/cmd-add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import url from "url";
import { isPackageUrl } from "./types/package-url";
import { tryGetLatestVersion } from "./types/pkg-info";
import { loadManifest, saveManifest } from "./utils/pkg-manifest-io";
import { env, parseEnv } from "./utils/env";
import { parseEnv } from "./utils/env";
import {
compareEditorVersion,
tryParseEditorVersion,
Expand Down Expand Up @@ -43,203 +43,195 @@ export const add = async function (
): Promise<ResultCode> {
if (!Array.isArray(pkgs)) pkgs = [pkgs];
// parse env
const envOk = await parseEnv(options, { checkPath: true });
if (!envOk) return 1;
// add
const results = [];
for (const pkg of pkgs)
results.push(
await _add({ pkg, testables: options.test, force: options.force })
);
const result: AddResult = {
code: results.filter((x) => x.code != 0).length > 0 ? 1 : 0,
dirty: results.filter((x) => x.dirty).length > 0,
};
// print manifest notice
if (result.dirty)
log.notice("", "please open Unity project to apply changes");
return result.code;
};
const env = await parseEnv(options, true);
if (env === null) return 1;

const _add = async function ({
pkg,
testables,
force,
}: {
pkg: PackageReference;
testables?: boolean;
force?: boolean;
}): Promise<AddResult> {
// dirty flag
let dirty = false;
// is upstream package flag
let isUpstreamPackage = false;
// parse name
const split = splitPackageReference(pkg);
const name = split[0];
let version = split[1];
const addSingle = async function (pkg: PackageReference): Promise<AddResult> {
// dirty flag
let dirty = false;
// is upstream package flag
let isUpstreamPackage = false;
// parse name
const split = splitPackageReference(pkg);
const name = split[0];
let version = split[1];

// load manifest
const manifest = loadManifest();
if (manifest === null) return { code: 1, dirty };
// packages that added to scope registry
const pkgsInScope: DomainName[] = [];
if (version === undefined || !isPackageUrl(version)) {
// verify name
let pkgInfo = await fetchPackageInfo(name);
if (!pkgInfo && env.upstream) {
pkgInfo = await fetchPackageInfo(name, env.upstreamRegistry);
if (pkgInfo) isUpstreamPackage = true;
}
if (!pkgInfo) {
log.error("404", `package not found: ${name}`);
return { code: 1, dirty };
}
// verify version
const versions = Object.keys(pkgInfo.versions) as SemanticVersion[];
// eslint-disable-next-line require-atomic-updates
if (!version || version === "latest")
version = tryGetLatestVersion(pkgInfo);
if (versions.filter((x) => x === version).length <= 0) {
log.warn(
"404",
`version ${version} is not a valid choice of: ${versions
.reverse()
.join(", ")}`
);
return { code: 1, dirty };
}

if (version === undefined)
throw new Error("Could not determine package version to add");
const versionInfo = pkgInfo.versions[version];
// verify editor version
if (versionInfo.unity) {
const requiredEditorVersion = versionInfo.unityRelease
? versionInfo.unity + "." + versionInfo.unityRelease
: versionInfo.unity;
if (env.editorVersion) {
const editorVersionResult = tryParseEditorVersion(env.editorVersion);
const requiredEditorVersionResult = tryParseEditorVersion(
requiredEditorVersion
// load manifest
const manifest = loadManifest(env.cwd);
if (manifest === null) return { code: 1, dirty };
// packages that added to scope registry
const pkgsInScope: DomainName[] = [];
if (version === undefined || !isPackageUrl(version)) {
// verify name
let pkgInfo = await fetchPackageInfo(env.registry, name);
if (!pkgInfo && env.upstream) {
pkgInfo = await fetchPackageInfo(env.upstreamRegistry, name);
if (pkgInfo) isUpstreamPackage = true;
}
if (!pkgInfo) {
log.error("404", `package not found: ${name}`);
return { code: 1, dirty };
}
// verify version
const versions = Object.keys(pkgInfo.versions) as SemanticVersion[];
// eslint-disable-next-line require-atomic-updates
if (!version || version === "latest")
version = tryGetLatestVersion(pkgInfo);
if (versions.filter((x) => x === version).length <= 0) {
log.warn(
"404",
`version ${version} is not a valid choice of: ${versions
.reverse()
.join(", ")}`
);
if (!editorVersionResult) {
log.warn(
"editor.version",
`${env.editorVersion} is unknown, the editor version check is disabled`
return { code: 1, dirty };
}

if (version === undefined)
throw new Error("Could not determine package version to add");
const versionInfo = pkgInfo.versions[version];
// verify editor version
if (versionInfo.unity) {
const requiredEditorVersion = versionInfo.unityRelease
? versionInfo.unity + "." + versionInfo.unityRelease
: versionInfo.unity;
if (env.editorVersion) {
const editorVersionResult = tryParseEditorVersion(env.editorVersion);
const requiredEditorVersionResult = tryParseEditorVersion(
requiredEditorVersion
);
}
if (!requiredEditorVersionResult) {
log.warn("package.unity", `${requiredEditorVersion} is not valid`);
if (!force) {
log.notice(
"suggest",
"contact the package author to fix the issue, or run with option -f to ignore the warning"
if (!editorVersionResult) {
log.warn(
"editor.version",
`${env.editorVersion} is unknown, the editor version check is disabled`
);
return { code: 1, dirty };
}
}
if (
editorVersionResult &&
requiredEditorVersionResult &&
compareEditorVersion(env.editorVersion, requiredEditorVersion) < 0
) {
log.warn(
"editor.version",
`requires ${requiredEditorVersion} but found ${env.editorVersion}`
);
if (!force) {
log.notice(
"suggest",
`upgrade the editor to ${requiredEditorVersion}, or run with option -f to ignore the warning`
if (!requiredEditorVersionResult) {
log.warn("package.unity", `${requiredEditorVersion} is not valid`);
if (!options.force) {
log.notice(
"suggest",
"contact the package author to fix the issue, or run with option -f to ignore the warning"
);
return { code: 1, dirty };
}
}
if (
editorVersionResult &&
requiredEditorVersionResult &&
compareEditorVersion(env.editorVersion, requiredEditorVersion) < 0
) {
log.warn(
"editor.version",
`requires ${requiredEditorVersion} but found ${env.editorVersion}`
);
return { code: 1, dirty };
if (!options.force) {
log.notice(
"suggest",
`upgrade the editor to ${requiredEditorVersion}, or run with option -f to ignore the warning`
);
return { code: 1, dirty };
}
}
}
}
}
// pkgsInScope
if (!isUpstreamPackage) {
const [depsValid, depsInvalid] = await fetchPackageDependencies({
name,
version,
deep: true,
});
// add depsValid to pkgsInScope.
depsValid
.filter((x) => !x.upstream && !x.internal)
.map((x) => x.name)
.forEach((name) => pkgsInScope.push(name));
// print suggestion for depsInvalid
depsInvalid.forEach((depObj) => {
if (depObj.reason == "package404" || depObj.reason == "version404") {
const resolvedVersion = manifest.dependencies[depObj.name];
depObj.resolved = Boolean(resolvedVersion);
if (!depObj.resolved)
log.notice(
"suggest",
`to install ${packageReference(
depObj.name,
depObj.version
)} or a replaceable version manually`
// pkgsInScope
if (!isUpstreamPackage) {
const [depsValid, depsInvalid] = await fetchPackageDependencies(
env.registry,
env.upstreamRegistry,
name,
version,
true
);
// add depsValid to pkgsInScope.
depsValid
.filter((x) => !x.upstream && !x.internal)
.map((x) => x.name)
.forEach((name) => pkgsInScope.push(name));
// print suggestion for depsInvalid
depsInvalid.forEach((depObj) => {
if (depObj.reason == "package404" || depObj.reason == "version404") {
const resolvedVersion = manifest.dependencies[depObj.name];
depObj.resolved = Boolean(resolvedVersion);
if (!depObj.resolved)
log.notice(
"suggest",
`to install ${packageReference(
depObj.name,
depObj.version
)} or a replaceable version manually`
);
}
});
if (depsInvalid.filter((x) => !x.resolved).length > 0) {
if (!options.force) {
log.error(
"missing dependencies",
"please resolve thie issue or run with option -f to ignore the warning"
);
return { code: 1, dirty };
}
}
});
if (depsInvalid.filter((x) => !x.resolved).length > 0) {
if (!force) {
log.error(
"missing dependencies",
"please resolve thie issue or run with option -f to ignore the warning"
);
return { code: 1, dirty };
}
}
} else pkgsInScope.push(name);
}
// add to dependencies
const oldVersion = manifest.dependencies[name];
addDependency(manifest, name, version);
if (!oldVersion) {
// Log the added package
log.notice("manifest", `added ${packageReference(name, version)}`);
dirty = true;
} else if (oldVersion != version) {
// Log the modified package version
log.notice("manifest", `modified ${name} ${oldVersion} => ${version}`);
dirty = true;
} else {
// Log the existed package
log.notice("manifest", `existed ${packageReference(name, version)}`);
}
if (!isUpstreamPackage) {
// add to scopedRegistries
if (!manifest.scopedRegistries) {
manifest.scopedRegistries = [];
dirty = true;
} else pkgsInScope.push(name);
}
let entry = tryGetScopedRegistryByUrl(manifest, env.registry);
if (entry === null) {
const name = url.parse(env.registry).hostname;
if (name === null) throw new Error("Could not resolve registry name");
entry = scopedRegistry(name, env.registry);
addScopedRegistry(manifest, entry);
// add to dependencies
const oldVersion = manifest.dependencies[name];
addDependency(manifest, name, version);
if (!oldVersion) {
// Log the added package
log.notice("manifest", `added ${packageReference(name, version)}`);
dirty = true;
} else if (oldVersion != version) {
// Log the modified package version
log.notice("manifest", `modified ${name} ${oldVersion} => ${version}`);
dirty = true;
} else {
// Log the existed package
log.notice("manifest", `existed ${packageReference(name, version)}`);
}
// apply pkgsInScope
const scopesSet = new Set(entry.scopes || []);
if (isDomainName(env.namespace)) pkgsInScope.push(env.namespace);
pkgsInScope.forEach((name) => {
if (!scopesSet.has(name)) {
scopesSet.add(name);
if (!isUpstreamPackage) {
// add to scopedRegistries
if (!manifest.scopedRegistries) {
manifest.scopedRegistries = [];
dirty = true;
}
});
entry.scopes = Array.from(scopesSet).sort();
}
if (testables) addTestable(manifest, name);
// save manifest
if (dirty) {
if (!saveManifest(manifest)) return { code: 1, dirty };
}
return { code: 0, dirty };
let entry = tryGetScopedRegistryByUrl(manifest, env.registry.url);
if (entry === null) {
const name = url.parse(env.registry.url).hostname;
if (name === null) throw new Error("Could not resolve registry name");
entry = scopedRegistry(name, env.registry.url);
addScopedRegistry(manifest, entry);
dirty = true;
}
// apply pkgsInScope
const scopesSet = new Set(entry.scopes || []);
if (isDomainName(env.namespace)) pkgsInScope.push(env.namespace);
pkgsInScope.forEach((name) => {
if (!scopesSet.has(name)) {
scopesSet.add(name);
dirty = true;
}
});
entry.scopes = Array.from(scopesSet).sort();
}
if (options.test) addTestable(manifest, name);
// save manifest
if (dirty) {
if (!saveManifest(env.cwd, manifest)) return { code: 1, dirty };
}
return { code: 0, dirty };
};

// add
const results = [];
for (const pkg of pkgs) results.push(await addSingle(pkg));
const result: AddResult = {
code: results.filter((x) => x.code != 0).length > 0 ? 1 : 0,
dirty: results.filter((x) => x.dirty).length > 0,
};
// print manifest notice
if (result.dirty)
log.notice("", "please open Unity project to apply changes");
return result.code;
};
Loading

0 comments on commit 2c0bdab

Please sign in to comment.