@sap/cds-dk 6.2.3 → 6.3.1
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/CHANGELOG.md +39 -0
- package/bin/bind.js +4 -4
- package/bin/deploy/to-h2.js +4 -0
- package/bin/deploy/to-sqlite.js +6 -4
- package/bin/help.js +1 -1
- package/bin/login.js +1 -0
- package/bin/push.js +29 -7
- package/lib/bind/userCdsrcJsonStorageProvider.js +4 -4
- package/lib/client/activate.js +1 -1
- package/lib/client/base_command.js +10 -10
- package/lib/client/helper/dependency_helper.js +10 -1
- package/lib/client/helper/logging.js +6 -2
- package/lib/client/pull.js +6 -6
- package/lib/client/push.js +33 -14
- package/lib/client/settings_manager.js +53 -22
- package/lib/compile/openapi/csdl2openapi.js +1 -1
- package/lib/compile/to-xsuaa.js +1 -1
- package/lib/import/odata/v2parser.js +37 -1
- package/lib/import/odata/v4parser.js +101 -23
- package/lib/init/constants.js +1 -1
- package/lib/init/index.js +23 -45
- package/lib/init/template/approuter/index.js +44 -48
- package/lib/init/template/auditlog/index.js +14 -10
- package/lib/init/template/cf-manifest/index.js +9 -11
- package/lib/init/template/connectivity/index.js +10 -10
- package/lib/init/template/data/index.js +20 -19
- package/lib/init/template/destinations/index.js +14 -9
- package/lib/init/template/enterprise-messaging/index.js +14 -9
- package/lib/init/template/extensibility/index.js +14 -9
- package/lib/init/template/hana/index.js +51 -57
- package/lib/init/template/helm/index.js +27 -59
- package/lib/init/template/helm/subchart/templates/_helpers.tpl +38 -0
- package/lib/init/template/helm/subchart/templates/deployment.yaml +12 -12
- package/lib/init/template/helm/subchart/values.md +565 -194
- package/lib/init/template/helm/subchart/values.schema.json +163 -8
- package/lib/init/template/helm/subchart/values.yaml +17 -1
- package/lib/init/template/html5-repo/index.js +15 -11
- package/lib/init/template/java/index.js +15 -11
- package/lib/init/template/kibana-logging/index.js +30 -31
- package/lib/init/template/lint/index.js +17 -18
- package/lib/init/template/mta/index.js +18 -40
- package/lib/init/template/mtx/index.js +2 -3
- package/lib/init/template/multitenancy/index.js +27 -20
- package/lib/init/template/nodejs/index.js +18 -20
- package/lib/init/template/notebook/index.js +5 -434
- package/lib/init/template/pipeline/index.js +10 -10
- package/lib/init/template/samples/index.js +7 -16
- package/lib/init/template/templateBase.js +17 -18
- package/lib/init/template/toggles/files/cdsrc.json +5 -0
- package/lib/init/template/toggles/files/cdsrc.json.hbs +7 -0
- package/lib/init/template/toggles/index.js +12 -6
- package/lib/init/template/xsuaa/index.js +44 -41
- package/lib/init/types.d.ts +0 -59
- package/lib/init/util/commandUtil.js +6 -7
- package/lib/init/util/fsUtil.js +23 -109
- package/lib/init/util/merge.js +319 -0
- package/lib/init/util/mvnArchetypeUtil.js +6 -5
- package/lib/init/util/projectReader.js +125 -300
- package/lib/init/util/spinner.js +10 -8
- package/lib/init/util/templateUtil.js +25 -368
- package/lib/lint/Linter.js +2 -3
- package/lib/lint/checks.js +0 -1
- package/lib/lint/io.js +18 -34
- package/npm-shrinkwrap.json +1132 -1190
- package/package.json +3 -3
- package/lib/init/template/notebook/cap_magic.py +0 -118
- package/lib/init/template/notebook/files/{{{name}}}.ipynb.hbs +0 -90
- package/lib/init/template/notebook/files/{{{name}}}.json +0 -102
- package/lib/init/template/notebook/notebook.js +0 -394
- package/lib/init/util/logger.js +0 -42
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
|
-
const { nullLogger } = require('../util/logger')
|
|
3
2
|
const cds = require('../../cds')
|
|
4
3
|
const { BuildTaskFactory } = cds.build
|
|
5
|
-
const {
|
|
4
|
+
const { read, exists } = cds.utils
|
|
6
5
|
const P_LANGUAGE_JAVA = 'java'
|
|
7
6
|
const P_LANGUAGE_NODEJS = 'nodejs'
|
|
8
7
|
const DEFAULT_P_LANGUAGE = P_LANGUAGE_NODEJS
|
|
@@ -14,11 +13,13 @@ const BUILD_TASK_HANA = "hana"
|
|
|
14
13
|
const BUILD_TASK_FIORI = "fiori"
|
|
15
14
|
const BUILD_TASK_MTX = "mtx"
|
|
16
15
|
const BUILD_TASK_MTX_SIDECAR = "mtx-sidecar"
|
|
16
|
+
const DEBUG = /\b(cli)\b/.test(process.env.DEBUG) && console.debug
|
|
17
|
+
const LOG = console
|
|
17
18
|
|
|
18
19
|
module.exports = class ProjectReader {
|
|
19
20
|
|
|
20
|
-
constructor(
|
|
21
|
-
this.
|
|
21
|
+
constructor(projectPath) {
|
|
22
|
+
this.projectPath = projectPath
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -28,104 +29,59 @@ module.exports = class ProjectReader {
|
|
|
28
29
|
const cdsEnvVar = process.env.CDS_ENV
|
|
29
30
|
process.env.CDS_ENV = profile
|
|
30
31
|
try {
|
|
31
|
-
return
|
|
32
|
+
return cds.env.for('cds', exists(this.projectPath) ? this.projectPath : this.cwd);
|
|
32
33
|
} finally {
|
|
33
34
|
cdsEnvVar ? process.env.CDS_ENV = cdsEnvVar : delete process.env.CDS_ENV
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
get fsUtil() {
|
|
38
|
-
return this.template.fsUtil
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
get logger() {
|
|
42
|
-
return this.template.logger
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
get projectPath() {
|
|
46
|
-
return this.template.projectPath
|
|
47
|
-
}
|
|
48
|
-
|
|
49
38
|
async read(options) {
|
|
50
39
|
const env = await this.getEnv();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const capDescriptor = await this._getCapDescriptor(env, options)
|
|
54
|
-
const uiDescriptor = await this._getUiDescriptor(env)
|
|
55
|
-
const projectDescriptor = {
|
|
56
|
-
cap: capDescriptor,
|
|
57
|
-
ui: uiDescriptor
|
|
58
|
-
}
|
|
40
|
+
DEBUG && DEBUG({ env })
|
|
59
41
|
|
|
60
|
-
await this.
|
|
42
|
+
const cap = await this._getCapDescriptor(env, options)
|
|
43
|
+
const ui = await this._getUiDescriptor(env)
|
|
44
|
+
const projectDescriptor = { cap, ui }
|
|
45
|
+
this._validateDbFolders(cap)
|
|
61
46
|
|
|
62
|
-
|
|
47
|
+
DEBUG && DEBUG({ projectDescriptor })
|
|
63
48
|
return projectDescriptor
|
|
64
49
|
}
|
|
65
50
|
|
|
51
|
+
_validateDbFolders(cap) {
|
|
52
|
+
const { root, db: dbs, isJava } = cap
|
|
53
|
+
if (isJava) {
|
|
54
|
+
for (const db of dbs) if (!exists(path.join(root, db.path, 'package.json'))) {
|
|
55
|
+
LOG.error(`Missing 'package.json' in folder ${db.path} - 'cds add hana' adds configuration for SAP HANA`)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
66
60
|
async _getCapDescriptor(env, options) {
|
|
67
61
|
const projectPath = this.projectPath
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
const _hasFacet = template => require(`../template/${template}`).hasFacet(env, projectPath, options)
|
|
63
|
+
const cap = {
|
|
64
|
+
for: options?.for,
|
|
70
65
|
pLanguage: DEFAULT_P_LANGUAGE,
|
|
71
66
|
srv: {},
|
|
72
67
|
db: [],
|
|
73
68
|
requires: [],
|
|
74
|
-
get
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
},
|
|
80
|
-
get isExtensible()
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
},
|
|
84
|
-
get
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
get
|
|
88
|
-
|
|
89
|
-
},
|
|
90
|
-
get hasRequires() {
|
|
91
|
-
return this.requires.length > 0
|
|
92
|
-
},
|
|
93
|
-
get hasRequiresDb() {
|
|
94
|
-
return this.db.length > 0
|
|
95
|
-
},
|
|
96
|
-
get hasHana() {
|
|
97
|
-
return this.requires.some(({ resource }) => resource.isHana)
|
|
98
|
-
},
|
|
99
|
-
get hasXsuaa() {
|
|
100
|
-
return this.requires.some(({ resource }) => resource.isXsuaa)
|
|
101
|
-
},
|
|
102
|
-
get hasAuditlog() {
|
|
103
|
-
return false // TODO: Need a `cds.requires.auditlog` or some other way to detect if enabled.
|
|
104
|
-
},
|
|
105
|
-
get needsSidecar() {
|
|
106
|
-
return (options?.add.has('hana') || this.db.length > 0) && (this.isJava || !this.isMultitenant)
|
|
107
|
-
},
|
|
108
|
-
get hasApprouter() {
|
|
109
|
-
return !!env.requires.approuter
|
|
110
|
-
},
|
|
111
|
-
get hasMessaging() {
|
|
112
|
-
return !!env.requires.messaging
|
|
113
|
-
},
|
|
114
|
-
get hasDestination() {
|
|
115
|
-
const kinds = { odata: 1, 'odata-v2': 1, 'odata-v4': 1, rest: 1 }
|
|
116
|
-
return Object.entries(env.requires).some(([service, require]) => !kinds[service] && kinds[require.kind])
|
|
117
|
-
},
|
|
118
|
-
get hasHtml5Repo() {
|
|
119
|
-
return fs.existsSync(path.join(projectPath, 'chart', 'templates', 'html5-apps-repo-host.yaml'))
|
|
120
|
-
},
|
|
121
|
-
get hasMtaDeployment() {
|
|
122
|
-
if (!options?.add.has('mta') && options?.add.has('helm')) return false
|
|
123
|
-
return fs.existsSync(path.join(projectPath, 'mta.yaml'))
|
|
124
|
-
},
|
|
125
|
-
get hasHelmDeployment() {
|
|
126
|
-
if (options?.add.has('mta') && !options?.add.has('helm')) return false
|
|
127
|
-
return fs.existsSync(path.join(projectPath, 'chart', 'values.yaml'))
|
|
128
|
-
}
|
|
69
|
+
get root() { return projectPath },
|
|
70
|
+
get hasRequires() { return this.requires.length > 0 },
|
|
71
|
+
get needsSidecar() { return (options?.add.has('hana') || this.db.length > 0) && (this.isJava || !this.isMultitenant) },
|
|
72
|
+
get isNodejs() { return this.pLanguage === P_LANGUAGE_NODEJS },
|
|
73
|
+
get isJava() { return this.pLanguage === P_LANGUAGE_JAVA },
|
|
74
|
+
get isMultitenant() { return _hasFacet('multitenancy') },
|
|
75
|
+
get isExtensible() { return _hasFacet('extensibility') },
|
|
76
|
+
get hasHana() { return _hasFacet('hana') },
|
|
77
|
+
get hasXsuaa() { return _hasFacet('xsuaa') },
|
|
78
|
+
get hasAuditlog() { return _hasFacet('auditlog') },
|
|
79
|
+
get hasApprouter() { return _hasFacet('approuter') },
|
|
80
|
+
get hasMessaging() { return _hasFacet('enterprise-messaging') },
|
|
81
|
+
get hasDestination() { return _hasFacet('destinations') },
|
|
82
|
+
get hasHtml5Repo() { return _hasFacet('html5-repo') },
|
|
83
|
+
get hasMta() { return _hasFacet('mta') },
|
|
84
|
+
get hasHelm() { return _hasFacet('helm') },
|
|
129
85
|
}
|
|
130
86
|
|
|
131
87
|
// setting the effective env as it might have changed by already executed 'add' commands, e.g. cds init foo --add hana,mta
|
|
@@ -133,23 +89,25 @@ module.exports = class ProjectReader {
|
|
|
133
89
|
cds.env // make sure env is initialized, otherwise we cannot set it (exotic case)
|
|
134
90
|
cds.env = env
|
|
135
91
|
|
|
136
|
-
const
|
|
92
|
+
const root = this.projectPath
|
|
93
|
+
const nullLogger = { debug: () => {}, log: () => {}, warn: () => {}, error: () => {}, write: () => {}}
|
|
94
|
+
const buildTasks = await new BuildTaskFactory(nullLogger, cds).getTasks({ root, resolve: true, mta: false })
|
|
137
95
|
|
|
138
96
|
await Promise.all(buildTasks.map(async (task) => {
|
|
139
|
-
const relDestPath =
|
|
97
|
+
const relDestPath = path.relative(root, task.dest)?.replace(/\\/g, '/')
|
|
140
98
|
|
|
141
99
|
switch (task.for) {
|
|
142
100
|
case BUILD_TASK_HANA:
|
|
143
101
|
// check whether we have a hana service binding defined as a hana build task is returned by default for compatibility reasons if neither hana, nor sqlite has been defined
|
|
144
102
|
if (this._hasHanaServiceBinding(env)) {
|
|
145
|
-
|
|
103
|
+
cap.db.push({ path: relDestPath, name: path.basename(task.src) })
|
|
146
104
|
}
|
|
147
105
|
break
|
|
148
106
|
|
|
149
107
|
case BUILD_TASK_JAVA:
|
|
150
108
|
case BUILD_TASK_JAVA_CF:
|
|
151
|
-
|
|
152
|
-
|
|
109
|
+
cap.pLanguage = P_LANGUAGE_JAVA
|
|
110
|
+
cap.srv = {
|
|
153
111
|
path: relDestPath,
|
|
154
112
|
name: path.basename(task.src),
|
|
155
113
|
ext: await this._getJavaExtDescriptor(task)
|
|
@@ -158,7 +116,7 @@ module.exports = class ProjectReader {
|
|
|
158
116
|
|
|
159
117
|
case BUILD_TASK_NODEJS:
|
|
160
118
|
case BUILD_TASK_NODE_CF:
|
|
161
|
-
|
|
119
|
+
cap.srv = {
|
|
162
120
|
path: relDestPath,
|
|
163
121
|
name: path.basename(task.src)
|
|
164
122
|
}
|
|
@@ -170,17 +128,17 @@ module.exports = class ProjectReader {
|
|
|
170
128
|
break
|
|
171
129
|
|
|
172
130
|
default:
|
|
173
|
-
|
|
131
|
+
LOG.warn(`Unknown build task type ${task.for}`)
|
|
174
132
|
}
|
|
175
133
|
}))
|
|
176
134
|
|
|
177
135
|
// setting app name, app description...
|
|
178
|
-
await this._setAppDetails(
|
|
136
|
+
await this._setAppDetails(cap)
|
|
179
137
|
|
|
180
138
|
// setting required resource information
|
|
181
|
-
this._setResourceDependencies(env,
|
|
139
|
+
this._setResourceDependencies(env, cap)
|
|
182
140
|
|
|
183
|
-
return
|
|
141
|
+
return cap
|
|
184
142
|
}
|
|
185
143
|
|
|
186
144
|
/**
|
|
@@ -188,206 +146,127 @@ module.exports = class ProjectReader {
|
|
|
188
146
|
* @param {object} task
|
|
189
147
|
*/
|
|
190
148
|
async _getJavaExtDescriptor(task) {
|
|
191
|
-
let descriptor = null
|
|
192
149
|
// by default spring-boot:repackage is used creating an executable jar archive
|
|
193
150
|
const pomJson = await this._parseXml(path.join(task.src, 'pom.xml'))
|
|
194
151
|
if (pomJson) {
|
|
195
|
-
|
|
196
|
-
|
|
152
|
+
const dependencies = pomJson?.project?.dependencies?.[0]?.dependency
|
|
153
|
+
const isOldJavaRuntime = [...dependencies].some(d => /com\.sap\.cloud\.servicesdk/.test(d?.groupId?.[0]))
|
|
154
|
+
if (isOldJavaRuntime) {
|
|
197
155
|
throw new Error("Projects using the classic CAP Java SDK are not supported")
|
|
198
156
|
}
|
|
199
157
|
|
|
200
|
-
descriptor = {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (ProjectReader._getProperty(pomJson, 'project.packaging.0') === 'war') {
|
|
206
|
-
descriptor.archiveName = archiveName + '-exec.war'
|
|
207
|
-
} else {
|
|
208
|
-
descriptor.archiveName = archiveName + '-exec.jar'
|
|
209
|
-
}
|
|
210
|
-
}
|
|
158
|
+
const descriptor = { archiveName: path.basename(this.projectPath) + "-exec.jar" }
|
|
159
|
+
const archiveName = pomJson?.project?.artifactId?.[0]
|
|
160
|
+
const suffix = pomJson?.project?.packaging?.[0]
|
|
161
|
+
if (archiveName) descriptor.archiveName = archiveName + '-exec.' + suffix
|
|
162
|
+
return descriptor
|
|
211
163
|
}
|
|
212
|
-
return descriptor
|
|
213
164
|
}
|
|
214
165
|
|
|
215
166
|
async _getUiDescriptor(env) {
|
|
216
|
-
const uiDescriptor = {
|
|
217
|
-
appPath: null
|
|
218
|
-
}
|
|
219
|
-
|
|
220
167
|
const absoluteAppPath = path.join(this.projectPath, env.folders.app)
|
|
221
|
-
|
|
222
|
-
|
|
168
|
+
return {
|
|
169
|
+
appPath: exists(absoluteAppPath) ? env.folders.app : null
|
|
223
170
|
}
|
|
224
|
-
|
|
225
|
-
return uiDescriptor
|
|
226
171
|
}
|
|
227
172
|
|
|
228
|
-
async _setAppDetails(
|
|
229
|
-
if (
|
|
230
|
-
throw Error(`${
|
|
173
|
+
async _setAppDetails(cap) {
|
|
174
|
+
if (cap.pLanguage !== P_LANGUAGE_JAVA && cap.pLanguage !== P_LANGUAGE_NODEJS) {
|
|
175
|
+
throw Error(`${cap.pLanguage} not supported`)
|
|
231
176
|
}
|
|
232
177
|
|
|
233
178
|
// 1.1. java - use parent pom.xml
|
|
234
|
-
if (
|
|
179
|
+
if (cap.pLanguage === P_LANGUAGE_JAVA) {
|
|
235
180
|
const pomXmlPath = path.join(this.projectPath, 'pom.xml')
|
|
236
181
|
try {
|
|
237
|
-
if (
|
|
182
|
+
if (exists(pomXmlPath)) {
|
|
238
183
|
const pomJson = await this._parseXml(pomXmlPath)
|
|
239
|
-
const artifactId =
|
|
240
|
-
const description =
|
|
241
|
-
let version =
|
|
184
|
+
const [artifactId] = pomJson?.project?.artifactId ?? []
|
|
185
|
+
const [description] = pomJson?.project?.description ?? []
|
|
186
|
+
let [version] = pomJson?.project?.version ?? []
|
|
242
187
|
// might need to resolve <version>${revision}</version> property
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
const resolved = ProjectReader._getProperty(pomJson, 'project.properties.0.' + versionMatch[1] + '.0')
|
|
246
|
-
if (resolved) {
|
|
247
|
-
version = resolved
|
|
248
|
-
}
|
|
188
|
+
if (version.match(/\${1}\{{1}([\w-\\.]+)\}{1}/)?.length === 2) {
|
|
189
|
+
version = pomJson?.project?.properties?.[0].revision[0]
|
|
249
190
|
}
|
|
250
191
|
if (version) {
|
|
251
192
|
// check compliance with mta version format - copied from mbt build error message
|
|
252
193
|
// if not compliant we use a static default value, see below...
|
|
253
194
|
if (/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/.test(version)) {
|
|
254
|
-
|
|
195
|
+
cap.appVersion = version
|
|
255
196
|
}
|
|
256
197
|
}
|
|
257
198
|
if (artifactId) {
|
|
258
|
-
|
|
259
|
-
if (Array.isArray(nameMatch)) {
|
|
260
|
-
capDescriptor.appName = nameMatch.length === 3 ? nameMatch[1] : artifactId
|
|
261
|
-
}
|
|
199
|
+
cap.appName = artifactId.split(/-parent/)[0]
|
|
262
200
|
}
|
|
263
201
|
if (description) {
|
|
264
|
-
|
|
202
|
+
cap.appDescription = description
|
|
265
203
|
}
|
|
266
204
|
}
|
|
267
205
|
} catch (e) {
|
|
268
|
-
|
|
269
|
-
|
|
206
|
+
LOG.error(`Failed to read file ${pomXmlPath} - skip pom.xml data`)
|
|
207
|
+
LOG.error(e)
|
|
270
208
|
}
|
|
271
209
|
}
|
|
272
210
|
|
|
273
211
|
// 1.2. use package.json
|
|
274
|
-
if (!
|
|
212
|
+
if (!cap.appName) {
|
|
275
213
|
const packageJsonPath = path.join(this.projectPath, 'package.json')
|
|
276
|
-
if (
|
|
214
|
+
if (exists(packageJsonPath)) {
|
|
277
215
|
try {
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
let segments = packageJson.name.trim().split('/')
|
|
287
|
-
// scope as namespace
|
|
288
|
-
if (segments[0].startsWith('@')) {
|
|
289
|
-
segments[0] = segments[0].replace('@', '')
|
|
290
|
-
}
|
|
291
|
-
segments = segments.map(segment => segment.startsWith('@') ? encodeURIComponent(segment.replace('@', '')) : encodeURIComponent(segment))
|
|
292
|
-
if (!capDescriptor.appName) {
|
|
293
|
-
capDescriptor.appName = segments[segments.length - 1]
|
|
294
|
-
}
|
|
295
|
-
if (!capDescriptor.appId) {
|
|
296
|
-
capDescriptor.appId = segments.join('.')
|
|
297
|
-
}
|
|
298
|
-
if (!capDescriptor.appDescription) {
|
|
299
|
-
capDescriptor.appDescription = segments[segments.length - 1]
|
|
300
|
-
}
|
|
216
|
+
const { name, version, description } = await read(packageJsonPath)
|
|
217
|
+
cap.appDescription = cap.appDescription ?? description
|
|
218
|
+
cap.appVersion = cap.appVersion ?? version
|
|
219
|
+
if (name) {
|
|
220
|
+
const segments = name.trim().replace(/@/g, '').split('/').map(encodeURIComponent)
|
|
221
|
+
cap.appName = cap.appName ?? segments[segments.length - 1]
|
|
222
|
+
cap.appId = cap.appId ?? segments.join('.')
|
|
223
|
+
cap.appDescription = cap.appDescription ?? cap.appName
|
|
301
224
|
}
|
|
302
225
|
} catch (e) {
|
|
303
|
-
|
|
304
|
-
|
|
226
|
+
LOG.error(`Failed to read file ${packageJsonPath} - skip application data`)
|
|
227
|
+
LOG.error(e)
|
|
305
228
|
}
|
|
306
229
|
}
|
|
307
230
|
}
|
|
308
231
|
|
|
309
232
|
// 2. use project name and static default values
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (!capDescriptor.appDescription) {
|
|
315
|
-
capDescriptor.appDescription = capDescriptor.appName + " application"
|
|
316
|
-
}
|
|
317
|
-
if (!capDescriptor.appId) {
|
|
318
|
-
capDescriptor.appId = capDescriptor.appName
|
|
319
|
-
}
|
|
320
|
-
if (!capDescriptor.appVersion) {
|
|
321
|
-
capDescriptor.appVersion = '1.0.0'
|
|
322
|
-
}
|
|
233
|
+
cap.appName = cap.appName ?? path.basename(this.projectPath)
|
|
234
|
+
cap.appDescription = cap.appDescription ?? cap.appName + " application"
|
|
235
|
+
cap.appId = cap.appId ?? cap.appName
|
|
236
|
+
cap.appVersion = cap.appVersion ?? '1.0.0'
|
|
323
237
|
}
|
|
324
238
|
|
|
325
|
-
_setResourceDependencies(env,
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
// ignore abstract helper definitions like sql
|
|
331
|
-
if (key === 'sql' || key === 'sqlite' || key === 'hana') continue
|
|
332
|
-
const { kind } = env.requires[key]
|
|
333
|
-
if (kind === 'hana' || kind === 'hana-mt' || kind === 'hana-cloud') {
|
|
334
|
-
hanaResources.set(key, env.requires[key])
|
|
335
|
-
} else {
|
|
336
|
-
otherResources.set(key, env.requires[key])
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
for (const [key, value] of hanaResources) {
|
|
341
|
-
const resource = this._getReqResource(key, value, capDescriptor)
|
|
342
|
-
if (resource) {
|
|
343
|
-
// using production profile
|
|
344
|
-
capDescriptor.requires.push({ resource })
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
// add after hana resource dependencies have been handled as multitenant information is required
|
|
348
|
-
for (const [key, value] of otherResources) {
|
|
349
|
-
const resource = this._getReqResource(key, value, capDescriptor)
|
|
350
|
-
if (resource) {
|
|
351
|
-
// using production profile
|
|
352
|
-
capDescriptor.requires.push({ resource })
|
|
353
|
-
}
|
|
239
|
+
_setResourceDependencies(env, cap) {
|
|
240
|
+
for (const [key, require] of Object.entries(env.requires)) {
|
|
241
|
+
if (key === 'sql' || key === 'sqlite' || key === 'hana') continue // ignore abstract helper definitions like sql
|
|
242
|
+
const resource = this._getReqResource(key, require, cap)
|
|
243
|
+
if (resource) cap.requires.push({ resource }) // using production profile
|
|
354
244
|
}
|
|
355
245
|
}
|
|
356
246
|
|
|
357
247
|
_hasHanaServiceBinding(env) {
|
|
358
|
-
const
|
|
359
|
-
return kind === 'hana' || kind === 'sql' && (
|
|
360
|
-
ProjectReader._getProperty(env, 'requires.db.dialect') === 'hana' ||
|
|
361
|
-
ProjectReader._getProperty(env, 'requires.db.use') === 'hana'
|
|
362
|
-
)
|
|
248
|
+
const db = env?.requires?.db
|
|
249
|
+
return db?.kind === 'hana' || db?.kind === 'sql' && (db?.dialect === 'hana' || db?.use === 'hana')
|
|
363
250
|
}
|
|
364
251
|
|
|
365
|
-
_getReqResource(key, reqEntry,
|
|
252
|
+
_getReqResource(key, reqEntry, cap) {
|
|
253
|
+
const { kind, dialect, use, vcap = {}, multiTenant } = reqEntry
|
|
254
|
+
const { appName, isMultitenant } = cap
|
|
366
255
|
const resource = {
|
|
367
|
-
name:
|
|
256
|
+
name: !key.includes(appName) ? `${appName}-${key}` : key,
|
|
368
257
|
service: '',
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
},
|
|
372
|
-
|
|
373
|
-
get
|
|
374
|
-
|
|
375
|
-
},
|
|
376
|
-
get isPlainHana() {
|
|
377
|
-
return this.service === 'hana' && !this.isManagedHana
|
|
378
|
-
},
|
|
379
|
-
get isHana() {
|
|
380
|
-
return this.isPlainHana || this.isManagedHana
|
|
381
|
-
},
|
|
382
|
-
get isXsuaa() {
|
|
383
|
-
return this.service === 'xsuaa'
|
|
384
|
-
},
|
|
258
|
+
vcap,
|
|
259
|
+
get isMultitenant() { return isMultitenant || multiTenant || false },
|
|
260
|
+
get isManagedHana() { return this.vcap.label === 'service-manager' || this.service === 'service-manager' },
|
|
261
|
+
get isPlainHana() { return this.service === 'hana' && !this.isManagedHana },
|
|
262
|
+
get isHana() { return this.isPlainHana || this.isManagedHana },
|
|
263
|
+
get isXsuaa() { return this.service === 'xsuaa' },
|
|
385
264
|
}
|
|
386
265
|
|
|
387
|
-
switch (
|
|
266
|
+
switch (kind) {
|
|
388
267
|
case 'sql':
|
|
389
268
|
case 'hana':
|
|
390
|
-
if (
|
|
269
|
+
if (kind === 'sql' && dialect !== 'hana' && use !== 'hana') {
|
|
391
270
|
break
|
|
392
271
|
}
|
|
393
272
|
// use different service name to avoid conflicts when switching from single tenant to multitenant
|
|
@@ -402,16 +281,11 @@ module.exports = class ProjectReader {
|
|
|
402
281
|
break
|
|
403
282
|
|
|
404
283
|
case 'xsuaa':
|
|
405
|
-
resource.service =
|
|
284
|
+
resource.service = kind
|
|
406
285
|
resource.vcap.plan = 'application'
|
|
407
286
|
break
|
|
408
|
-
|
|
409
287
|
default: {
|
|
410
|
-
|
|
411
|
-
resource.service = reqEntry.kind
|
|
412
|
-
} else {
|
|
413
|
-
this.logger.debug(`Skip resource ${key}`)
|
|
414
|
-
}
|
|
288
|
+
vcap.plan ? resource.service = kind : DEBUG && DEBUG(`Skip resource ${key}`)
|
|
415
289
|
}
|
|
416
290
|
}
|
|
417
291
|
return resource.service ? resource : null
|
|
@@ -429,7 +303,7 @@ module.exports = class ProjectReader {
|
|
|
429
303
|
const xmljs = require('xml-js');
|
|
430
304
|
let xmljsParse = {};
|
|
431
305
|
try {
|
|
432
|
-
const xml = await
|
|
306
|
+
const xml = await read(pomXmlPath, 'utf-8')
|
|
433
307
|
xmljsParse.project = JSON.parse(await xmljs.xml2json(xml, {
|
|
434
308
|
ignoreComment: true,
|
|
435
309
|
compact: true,
|
|
@@ -441,12 +315,12 @@ module.exports = class ProjectReader {
|
|
|
441
315
|
ignoreInstruction: true,
|
|
442
316
|
ignoreCdata: true,
|
|
443
317
|
ignoreDoctype: true,
|
|
444
|
-
textFn: this.
|
|
318
|
+
textFn: this._removeTextAttributes
|
|
445
319
|
})).project[0];
|
|
446
320
|
return xmljsParse;
|
|
447
321
|
} catch (e) {
|
|
448
|
-
|
|
449
|
-
|
|
322
|
+
LOG.error(`Failed to read file ${pomXmlPath} - skip pom.xml data`)
|
|
323
|
+
LOG.error(e)
|
|
450
324
|
}
|
|
451
325
|
}
|
|
452
326
|
|
|
@@ -455,63 +329,14 @@ module.exports = class ProjectReader {
|
|
|
455
329
|
input : "groupId":[{"_text":["customer"]}]
|
|
456
330
|
output: "groupId":["customer"]
|
|
457
331
|
*/
|
|
458
|
-
|
|
459
|
-
const
|
|
460
|
-
const key =
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
if (arrKeyLen > 0) {
|
|
465
|
-
const arr = arrKey;
|
|
466
|
-
const arrIndex = arrKey.length - 1;
|
|
467
|
-
arr[arrIndex] = value;
|
|
468
|
-
} else {
|
|
469
|
-
parentElement._parent[keyName] = value;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
async _validate(projectDescriptor) {
|
|
473
|
-
const capDescriptor = projectDescriptor.cap
|
|
474
|
-
if (capDescriptor.db.length > 0) {
|
|
475
|
-
if (capDescriptor.isJava) {
|
|
476
|
-
//ensure package.json exists in db module
|
|
477
|
-
await Promise.all(capDescriptor.db.map(async db => {
|
|
478
|
-
const dbPath = path.join(this.projectPath, db.path, "package.json")
|
|
479
|
-
if (!await this.fsUtil.pathExists(dbPath)) {
|
|
480
|
-
this.logger.error(`Missing package.json file in folder ${db.path} - 'cds add hana' will add the configuration for SAP HANA deployment`) //NOSONAR
|
|
481
|
-
}
|
|
482
|
-
}))
|
|
483
|
-
}
|
|
332
|
+
_removeTextAttributes(value, parentElement) {
|
|
333
|
+
const parentKeys = Object.keys(parentElement._parent);
|
|
334
|
+
const key = parentKeys[parentKeys.length - 1];
|
|
335
|
+
const _text = parentElement._parent[key];
|
|
336
|
+
if (_text.length > 0) {
|
|
337
|
+
_text[_text.length - 1] = value;
|
|
484
338
|
} else {
|
|
485
|
-
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
_isOldJavaRuntime(pomJson) {
|
|
490
|
-
const dependencies = ProjectReader._getProperty(pomJson, "project.dependencies.0.dependency")
|
|
491
|
-
if (Array.isArray(dependencies)) {
|
|
492
|
-
return dependencies.some((dependency) => {
|
|
493
|
-
const groupId = ProjectReader._getProperty(dependency, 'groupId.0')
|
|
494
|
-
return /com\.sap\.cloud\.servicesdk/.test(groupId)
|
|
495
|
-
})
|
|
339
|
+
parentElement._parent[key] = value;
|
|
496
340
|
}
|
|
497
|
-
return false
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
static _slash(filename) {
|
|
501
|
-
return filename ? filename.replace(/\\/g, '/') : filename
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
static _getResourceName(key, capDescriptor) {
|
|
505
|
-
let name = key
|
|
506
|
-
// only if not already present
|
|
507
|
-
if (!name.includes(capDescriptor.appName)) {
|
|
508
|
-
name = capDescriptor.appName + '-' + name
|
|
509
|
-
}
|
|
510
|
-
return name
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
static _getProperty(src, segments) {
|
|
514
|
-
segments = Array.isArray(segments) ? segments : segments.split('.')
|
|
515
|
-
return segments.reduce((p, n) => p && p[n], src)
|
|
516
341
|
}
|
|
517
342
|
}
|
package/lib/init/util/spinner.js
CHANGED
|
@@ -16,9 +16,11 @@ const ERASE_LINE = ESC_SEQ + 'K';
|
|
|
16
16
|
// const SAVE_CURSOR = ESC_SEQ + 's';
|
|
17
17
|
// const RESTORE_CURSOR = ESC_SEQ + 'u';
|
|
18
18
|
|
|
19
|
+
const LOG = console
|
|
20
|
+
const DEBUG = /\bcli\b/.test(process.env.DEBUG) && LOG.debug
|
|
21
|
+
|
|
19
22
|
class Spinner {
|
|
20
|
-
constructor(
|
|
21
|
-
this.logger = logger;
|
|
23
|
+
constructor(theme = Spinner.THEME_SPIN, initialDelay = 1000) {
|
|
22
24
|
this.theme = theme;
|
|
23
25
|
this.initialDelay = initialDelay;
|
|
24
26
|
}
|
|
@@ -40,22 +42,22 @@ class Spinner {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
_start(msg) {
|
|
43
|
-
if (!
|
|
44
|
-
|
|
45
|
+
if (!DEBUG && process.stdout.isTTY) {
|
|
46
|
+
LOG.info(msg + HIDE_CURSOR + ERASE_LINE + MOVE_CURSOR_UP);
|
|
45
47
|
this.timeoutId = setTimeout(() => {
|
|
46
48
|
let idx = 0;
|
|
47
49
|
this.intervalId = setInterval(() => {
|
|
48
|
-
|
|
50
|
+
LOG.info(msg + ' ' + SPINNER_THEMES[this.theme][idx] + ERASE_LINE + MOVE_CURSOR_UP);
|
|
49
51
|
idx = (idx + 1) % SPINNER_THEMES[this.theme].length;
|
|
50
52
|
}, RENDER_DELAY);
|
|
51
53
|
}, this.initialDelay);
|
|
52
54
|
} else {
|
|
53
|
-
|
|
55
|
+
LOG.info(msg);
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
_stop(msg, postfix) {
|
|
58
|
-
if (!
|
|
60
|
+
if (!DEBUG && process.stdout.isTTY) {
|
|
59
61
|
if (this.timeoutId) {
|
|
60
62
|
clearTimeout(this.timeoutId);
|
|
61
63
|
this.timeoutId = null;
|
|
@@ -66,7 +68,7 @@ class Spinner {
|
|
|
66
68
|
this.intervalId = null;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
LOG.info(SHOW_CURSOR + msg + ' ' + postfix + ERASE_LINE);
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
}
|