Skip to content

Commit 149afb4

Browse files
committed
refactor(cli): organize code that should only be used by the CLI into a folder
1 parent 5377586 commit 149afb4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+994
-2815
lines changed

packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES

Lines changed: 72 additions & 1923 deletions
Large diffs are not rendered by default.
Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,36 @@
1-
export { DEFAULT_TOOLKIT_STACK_NAME, SdkProvider } from '../../../../aws-cdk/lib/api';
2-
export type { SuccessfulDeployStackResult } from '../../../../aws-cdk/lib/api';
3-
export { formatSdkLoggerContent } from '../../../../aws-cdk/lib/api/aws-auth/sdk-logger';
4-
export { CloudAssembly, sanitizePatterns, StackCollection, ExtendedStackSelection } from '../../../../aws-cdk/lib/api/cxapp/cloud-assembly';
5-
export { prepareDefaultEnvironment, prepareContext, spaceAvailableForContext } from '../../../../aws-cdk/lib/api/cxapp/exec';
6-
export { Deployments } from '../../../../aws-cdk/lib/api/deployments';
1+
// APIs
2+
export { formatSdkLoggerContent, SdkProvider } from '../../../../aws-cdk/lib/api/aws-auth';
3+
export { Context, PROJECT_CONTEXT } from '../../../../aws-cdk/lib/api/context';
4+
export { Deployments, type SuccessfulDeployStackResult } from '../../../../aws-cdk/lib/api/deployments';
5+
export { Settings } from '../../../../aws-cdk/lib/api/settings';
6+
export { tagsForStack } from '../../../../aws-cdk/lib/api/tags';
7+
export { DEFAULT_TOOLKIT_STACK_NAME } from '../../../../aws-cdk/lib/api/toolkit-info';
8+
9+
// Context Providers
10+
export * as contextproviders from '../../../../aws-cdk/lib/context-providers';
11+
12+
// @todo APIs not clean import
713
export { HotswapMode } from '../../../../aws-cdk/lib/api/hotswap/common';
814
export { StackActivityProgress } from '../../../../aws-cdk/lib/api/util/cloudformation/stack-activity-monitor';
9-
export { RWLock } from '../../../../aws-cdk/lib/api/util/rwlock';
10-
export type { ILock } from '../../../../aws-cdk/lib/api/util/rwlock';
15+
export { RWLock, type ILock } from '../../../../aws-cdk/lib/api/util/rwlock';
1116
export { formatTime } from '../../../../aws-cdk/lib/api/util/string-manipulation';
12-
export * as contextproviders from '../../../../aws-cdk/lib/context-providers';
17+
18+
// @todo Not yet API probably should be
1319
export { ResourceMigrator } from '../../../../aws-cdk/lib/migrator';
1420
export { obscureTemplate, serializeStructure } from '../../../../aws-cdk/lib/serialize';
15-
export { Context, Settings, PROJECT_CONTEXT } from '../../../../aws-cdk/lib/settings';
16-
export { tagsForStack } from '../../../../aws-cdk/lib/tags';
17-
export { CliIoHost } from '../../../../aws-cdk/lib/toolkit/cli-io-host';
1821
export { loadTree, some } from '../../../../aws-cdk/lib/tree';
1922
export { splitBySize } from '../../../../aws-cdk/lib/util';
2023
export { validateSnsTopicArn } from '../../../../aws-cdk/lib/util/validate-notification-arn';
2124
export { WorkGraph } from '../../../../aws-cdk/lib/util/work-graph';
2225
export type { Concurrency } from '../../../../aws-cdk/lib/util/work-graph';
2326
export { WorkGraphBuilder } from '../../../../aws-cdk/lib/util/work-graph-builder';
2427
export type { AssetBuildNode, AssetPublishNode, StackNode } from '../../../../aws-cdk/lib/util/work-graph-types';
25-
export { versionNumber } from '../../../../aws-cdk/lib/version';
28+
29+
// @todo Cloud Assembly and Executable - this is a messy API right now
30+
export { CloudAssembly, sanitizePatterns, StackCollection, ExtendedStackSelection } from '../../../../aws-cdk/lib/api/cxapp/cloud-assembly';
31+
export { prepareDefaultEnvironment, prepareContext, spaceAvailableForContext } from '../../../../aws-cdk/lib/api/cxapp/exec';
2632
export { guessExecutable } from '../../../../aws-cdk/lib/api/cxapp/exec';
33+
34+
// @todo Should not use! investigate how to replace
35+
export { versionNumber } from '../../../../aws-cdk/lib/cli/version';
36+
export { CliIoHost } from '../../../../aws-cdk/lib/toolkit/cli-io-host';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './sdk';
22
export * from './sdk-provider';
3+
export * from './sdk-logger';

packages/aws-cdk/lib/api/bootstrap/bootstrap-props.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { BootstrapSource } from './bootstrap-environment';
2-
import { Tag } from '../../tags';
2+
import { Tag } from '../tags';
33
import { StringWithoutPlaceholders } from '../util/placeholders';
44

55
export const BUCKET_NAME_OUTPUT = 'BucketName';
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { Settings } from './settings';
2+
import { ToolkitError } from '../toolkit/error';
3+
4+
export { TRANSIENT_CONTEXT_KEY } from './settings';
5+
export const PROJECT_CONTEXT = 'cdk.context.json';
6+
7+
interface ContextBag {
8+
/**
9+
* The file name of the context. Will be used to potentially
10+
* save new context back to the original file.
11+
*/
12+
fileName?: string;
13+
14+
/**
15+
* The context values.
16+
*/
17+
bag: Settings;
18+
}
19+
20+
/**
21+
* Class that supports overlaying property bags
22+
*
23+
* Reads come from the first property bag that can has the given key,
24+
* writes go to the first property bag that is not readonly. A write
25+
* will remove the value from all property bags after the first
26+
* writable one.
27+
*/
28+
export class Context {
29+
private readonly bags: Settings[];
30+
private readonly fileNames: (string|undefined)[];
31+
32+
constructor(...bags: ContextBag[]) {
33+
this.bags = bags.length > 0 ? bags.map(b => b.bag) : [new Settings()];
34+
this.fileNames = bags.length > 0 ? bags.map(b => b.fileName) : ['default'];
35+
}
36+
37+
public get keys(): string[] {
38+
return Object.keys(this.all);
39+
}
40+
41+
public has(key: string) {
42+
return this.keys.indexOf(key) > -1;
43+
}
44+
45+
public get all(): {[key: string]: any} {
46+
let ret = new Settings();
47+
48+
// In reverse order so keys to the left overwrite keys to the right of them
49+
for (const bag of [...this.bags].reverse()) {
50+
ret = ret.merge(bag);
51+
}
52+
53+
return ret.all;
54+
}
55+
56+
public get(key: string): any {
57+
for (const bag of this.bags) {
58+
const v = bag.get([key]);
59+
if (v !== undefined) { return v; }
60+
}
61+
return undefined;
62+
}
63+
64+
public set(key: string, value: any) {
65+
for (const bag of this.bags) {
66+
if (bag.readOnly) { continue; }
67+
68+
// All bags past the first one have the value erased
69+
bag.set([key], value);
70+
value = undefined;
71+
}
72+
}
73+
74+
public unset(key: string) {
75+
this.set(key, undefined);
76+
}
77+
78+
public clear() {
79+
for (const key of this.keys) {
80+
this.unset(key);
81+
}
82+
}
83+
84+
/**
85+
* Save a specific context file
86+
*/
87+
public async save(fileName: string): Promise<this> {
88+
const index = this.fileNames.indexOf(fileName);
89+
90+
// File not found, don't do anything in this scenario
91+
if (index === -1) {
92+
return this;
93+
}
94+
95+
const bag = this.bags[index];
96+
if (bag.readOnly) {
97+
throw new ToolkitError(`Context file ${fileName} is read only!`);
98+
}
99+
100+
await bag.save(fileName);
101+
return this;
102+
}
103+
}

packages/aws-cdk/lib/api/cxapp/cloud-executable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as cxapi from '@aws-cdk/cx-api';
22
import { CloudAssembly } from './cloud-assembly';
3+
import { Configuration } from '../../cli/user-configuration';
34
import * as contextproviders from '../../context-providers';
45
import { debug } from '../../logging';
5-
import { Configuration } from '../../settings';
66
import { ToolkitError } from '../../toolkit/error';
77
import { SdkProvider } from '../aws-auth';
88

packages/aws-cdk/lib/api/cxapp/exec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema';
55
import * as cxapi from '@aws-cdk/cx-api';
66
import * as fs from 'fs-extra';
77
import * as semver from 'semver';
8+
import { Configuration, PROJECT_CONFIG, USER_DEFAULTS } from '../../cli/user-configuration';
9+
import { versionNumber } from '../../cli/version';
810
import { debug, warning } from '../../logging';
9-
import { Configuration, PROJECT_CONFIG, Settings, USER_DEFAULTS } from '../../settings';
1011
import { ToolkitError } from '../../toolkit/error';
1112
import { loadTree, some } from '../../tree';
1213
import { splitBySize } from '../../util/objects';
13-
import { versionNumber } from '../../version';
1414
import { SdkProvider } from '../aws-auth';
15+
import { Settings } from '../settings';
1516
import { RWLock, ILock } from '../util/rwlock';
1617

1718
export interface ExecProgramResult {

packages/aws-cdk/lib/api/deployments/deployments.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ import {
2929
type RootTemplateWithNestedStacks,
3030
} from './nested-stack-helpers';
3131
import { debug, warning } from '../../logging';
32-
import type { Tag } from '../../tags';
3332
import { ToolkitError } from '../../toolkit/error';
3433
import { formatErrorMessage } from '../../util/error';
3534
import type { SdkProvider } from '../aws-auth/sdk-provider';
3635
import { EnvironmentAccess } from '../environment-access';
3736
import { type EnvironmentResources } from '../environment-resources';
3837
import { HotswapMode, HotswapPropertyOverrides } from '../hotswap/common';
38+
import type { Tag } from '../tags';
3939
import { DEFAULT_TOOLKIT_STACK_NAME } from '../toolkit-info';
4040
import { StackActivityMonitor, StackActivityProgress } from '../util/cloudformation/stack-activity-monitor';
4141
import { StackEventPoller } from '../util/cloudformation/stack-event-poller';
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import * as os from 'os';
2+
import * as fs_path from 'path';
3+
import * as fs from 'fs-extra';
4+
import { warning } from '../logging';
5+
import { ToolkitError } from '../toolkit/error';
6+
import * as util from '../util/objects';
7+
8+
export type SettingsMap = {[key: string]: any};
9+
10+
/**
11+
* If a context value is an object with this key set to a truthy value, it won't be saved to cdk.context.json
12+
*/
13+
export const TRANSIENT_CONTEXT_KEY = '$dontSaveContext';
14+
15+
/**
16+
* A single bag of settings
17+
*/
18+
export class Settings {
19+
public static mergeAll(...settings: Settings[]): Settings {
20+
let ret = new Settings();
21+
for (const setting of settings) {
22+
ret = ret.merge(setting);
23+
}
24+
return ret;
25+
}
26+
27+
constructor(private settings: SettingsMap = {}, public readonly readOnly = false) {}
28+
29+
public async load(fileName: string): Promise<this> {
30+
if (this.readOnly) {
31+
throw new ToolkitError(`Can't load ${fileName}: settings object is readonly`);
32+
}
33+
this.settings = {};
34+
35+
const expanded = expandHomeDir(fileName);
36+
if (await fs.pathExists(expanded)) {
37+
this.settings = await fs.readJson(expanded);
38+
}
39+
40+
// See https://github.com/aws/aws-cdk/issues/59
41+
this.prohibitContextKey('default-account', fileName);
42+
this.prohibitContextKey('default-region', fileName);
43+
this.warnAboutContextKey('aws:', fileName);
44+
45+
return this;
46+
}
47+
48+
public async save(fileName: string): Promise<this> {
49+
const expanded = expandHomeDir(fileName);
50+
await fs.writeJson(expanded, stripTransientValues(this.settings), { spaces: 2 });
51+
return this;
52+
}
53+
54+
public get all(): any {
55+
return this.get([]);
56+
}
57+
58+
public merge(other: Settings): Settings {
59+
return new Settings(util.deepMerge(this.settings, other.settings));
60+
}
61+
62+
public subSettings(keyPrefix: string[]) {
63+
return new Settings(this.get(keyPrefix) || {}, false);
64+
}
65+
66+
public makeReadOnly(): Settings {
67+
return new Settings(this.settings, true);
68+
}
69+
70+
public clear() {
71+
if (this.readOnly) {
72+
throw new ToolkitError('Cannot clear(): settings are readonly');
73+
}
74+
this.settings = {};
75+
}
76+
77+
public get empty(): boolean {
78+
return Object.keys(this.settings).length === 0;
79+
}
80+
81+
public get(path: string[]): any {
82+
return util.deepClone(util.deepGet(this.settings, path));
83+
}
84+
85+
public set(path: string[], value: any): Settings {
86+
if (this.readOnly) {
87+
throw new ToolkitError(`Can't set ${path}: settings object is readonly`);
88+
}
89+
if (path.length === 0) {
90+
// deepSet can't handle this case
91+
this.settings = value;
92+
} else {
93+
util.deepSet(this.settings, path, value);
94+
}
95+
return this;
96+
}
97+
98+
public unset(path: string[]) {
99+
this.set(path, undefined);
100+
}
101+
102+
private prohibitContextKey(key: string, fileName: string) {
103+
if (!this.settings.context) { return; }
104+
if (key in this.settings.context) {
105+
// eslint-disable-next-line max-len
106+
throw new ToolkitError(`The 'context.${key}' key was found in ${fs_path.resolve(fileName)}, but it is no longer supported. Please remove it.`);
107+
}
108+
}
109+
110+
private warnAboutContextKey(prefix: string, fileName: string) {
111+
if (!this.settings.context) { return; }
112+
for (const contextKey of Object.keys(this.settings.context)) {
113+
if (contextKey.startsWith(prefix)) {
114+
// eslint-disable-next-line max-len
115+
warning(`A reserved context key ('context.${prefix}') key was found in ${fs_path.resolve(fileName)}, it might cause surprising behavior and should be removed.`);
116+
}
117+
}
118+
}
119+
}
120+
121+
function expandHomeDir(x: string) {
122+
if (x.startsWith('~')) {
123+
return fs_path.join(os.homedir(), x.slice(1));
124+
}
125+
return x;
126+
}
127+
128+
/**
129+
* Return all context value that are not transient context values
130+
*/
131+
function stripTransientValues(obj: {[key: string]: any}) {
132+
const ret: any = {};
133+
for (const [key, value] of Object.entries(obj)) {
134+
if (!isTransientValue(value)) {
135+
ret[key] = value;
136+
}
137+
}
138+
return ret;
139+
}
140+
141+
/**
142+
* Return whether the given value is a transient context value
143+
*
144+
* Values that are objects with a magic key set to a truthy value are considered transient.
145+
*/
146+
function isTransientValue(value: any) {
147+
return typeof value === 'object' && value !== null && (value as any)[TRANSIENT_CONTEXT_KEY];
148+
}
149+
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import * as cxapi from '@aws-cdk/cx-api';
1+
import type * as cxapi from '@aws-cdk/cx-api';
2+
3+
export interface Tag {
4+
readonly Key: string;
5+
readonly Value: string;
6+
}
27

38
/**
49
* @returns an array with the tags available in the stack metadata.
510
*/
611
export function tagsForStack(stack: cxapi.CloudFormationStackArtifact): Tag[] {
712
return Object.entries(stack.tags).map(([Key, Value]) => ({ Key, Value }));
813
}
9-
10-
export interface Tag {
11-
readonly Key: string;
12-
readonly Value: string;
13-
}

0 commit comments

Comments
 (0)