@sap/cds-dk 9.7.2 → 9.8.0
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 +35 -2
- package/bin/bind.js +7 -2
- package/bin/build.js +14 -4
- package/bin/cds.js +2 -2
- package/bin/completion/completionFs.js +1 -1
- package/bin/completion/index.js +2 -2
- package/bin/data-products/get-csn-via-dp-cli.js +1 -1
- package/bin/debug.js +1 -1
- package/bin/deploy/index.js +3 -2
- package/bin/gen.js +1 -1
- package/bin/help.js +1 -1
- package/bin/import.js +3 -0
- package/bin/minify.js +1 -1
- package/bin/mock.js +1 -1
- package/bin/repl.js +212 -39
- package/bin/test.js +0 -2
- package/bin/up.js +27 -3
- package/bin/util/containerize.js +1 -3
- package/bin/version.js +27 -7
- package/bin/watch.js +20 -4
- package/lib/bind/cf.js +2 -2
- package/lib/bind/k8s.js +0 -1
- package/lib/bind/plugin.js +2 -0
- package/lib/bind/shared.js +6 -1
- package/lib/build/constants.js +0 -8
- package/lib/build/index.js +569 -25
- package/lib/build/{provider/edmxBuildPlugin.js → plugins/edmx.js} +6 -15
- package/lib/build/{provider/featureToggleBuildPlugin.js → plugins/featureToggles.js} +3 -23
- package/lib/build/{provider → plugins}/fiori/index.js +27 -38
- package/lib/build/{provider → plugins}/hana/index.js +61 -83
- package/lib/build/{provider → plugins}/hana/migrationtable.js +4 -3
- package/lib/build/plugins/helm/index.js +6 -6
- package/lib/build/{provider/internalBuildPlugin.js → plugins/internal.js} +7 -31
- package/lib/build/{provider → plugins}/java/index.js +18 -26
- package/lib/build/plugins/mtx/index.js +41 -0
- package/lib/build/plugins/mtx/resourcesTarBuilder.js +41 -0
- package/lib/build/{provider → plugins}/mtx-extension/extensionCompilation.js +1 -1
- package/lib/build/{provider → plugins}/mtx-extension/index.js +35 -44
- package/lib/build/{provider → plugins}/mtx-sidecar/index.js +17 -3
- package/lib/build/{provider → plugins}/nodejs/index.js +29 -28
- package/lib/build/{plugin.js → plugins/plugin.js} +45 -59
- package/lib/build/plugins.js +11 -8
- package/lib/build/util.js +0 -8
- package/lib/compile/to-xsuaa.js +2 -2
- package/lib/deploy/to-hana/hana.js +64 -56
- package/lib/import/common.js +1 -1
- package/lib/import/odata/metadataconverter/MetadataConverter.js +4 -3
- package/lib/import/odata/v2parser.js +28 -28
- package/lib/import/odata/v4parser.js +37 -2
- package/lib/import/openapi/index.js +1 -1
- package/lib/init/constants.js +0 -1
- package/lib/init/template/app-frontend/index.js +1 -1
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/completion/completionSetup.js +1 -1
- package/lib/init/template/data/as-csv.js +1 -1
- package/lib/init/template/github-actions/index.js +1 -1
- package/lib/init/template/handler/index.js +1 -1
- package/lib/init/template/helm/index.js +3 -3
- package/lib/init/template/kyma/index.js +3 -3
- package/lib/init/template/lint/index.js +7 -21
- package/lib/init/template/multitenancy/files/package.json.hbs +0 -5
- package/lib/init/template/postgres/files/containerize.yaml.hbs +15 -0
- package/lib/init/template/postgres/files/package.json.hbs +35 -0
- package/lib/init/template/postgres/files/values.yaml.hbs +23 -0
- package/lib/init/template/postgres/index.js +34 -9
- package/lib/init/template/test/files/package.json +1 -1
- package/lib/init/template/typescript/files/package.json +1 -1
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +1 -0
- package/lib/lint/eslintHelp.json +1 -1
- package/lib/lint/io.js +9 -13
- package/lib/mtx/pull.js +1 -1
- package/lib/mtx/settings_manager.js +11 -5
- package/lib/mtx/tenant_action.js +1 -1
- package/lib/mtx/util/fs.js +2 -2
- package/lib/util/fs.js +3 -3
- package/lib/util/git.js +1 -1
- package/lib/util/glob.js +1 -1
- package/lib/watch/hot-reload.js +202 -0
- package/lib/watch/livereload-server.js +6 -4
- package/lib/watch/node-watch.js +5 -1
- package/lib/watch/watched.js +7 -3
- package/lib/watch/watcher.js +41 -3
- package/npm-shrinkwrap.json +31 -22
- package/package.json +1 -1
- package/lib/build/buildTaskEngine.js +0 -377
- package/lib/build/buildTaskFactory.js +0 -198
- package/lib/build/buildTaskProvider.js +0 -38
- package/lib/build/buildTaskProviderFactory.js +0 -233
- package/lib/build/provider/internalBuildTaskProvider.js +0 -227
- package/lib/build/provider/java-cf/index.js +0 -1
- package/lib/build/provider/mtx/index.js +0 -36
- package/lib/build/provider/mtx/resourcesTarBuilder.js +0 -102
- package/lib/build/provider/node-cf/index.js +0 -1
- package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +0 -40
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/fixed/schema.cds +0 -4
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/invalid/schema.cds +0 -4
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +0 -15
- package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/valid/schema.cds +0 -6
- package/lib/init/types.d.ts +0 -23
- /package/lib/build/{provider → plugins}/hana/2migration.js +0 -0
- /package/lib/build/{provider → plugins}/hana/template/.hdiconfig-all +0 -0
- /package/lib/build/{provider → plugins}/hana/template/.hdiconfig-cloud +0 -0
- /package/lib/build/{provider → plugins}/hana/template/.hdinamespace +0 -0
- /package/lib/build/{provider → plugins}/hana/template/package.json +0 -0
- /package/lib/build/{provider → plugins}/hana/template/undeploy.json +0 -0
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
const cds = require('../cds')
|
|
3
|
-
const BuildTaskProviderFactory = require('./buildTaskProviderFactory')
|
|
4
|
-
const { hasJavaNature, getDefaultModelPaths, hasOptionValue, BuildError } = require('./util')
|
|
5
|
-
const { OPTION_WS, IGNORE_DEFAULT_MODELS, NODEJS_MODEL_EXCLUDE_LIST, BUILD_TASK_NODEJS, BUILD_TASK_NODE_CF } = require("./constants")
|
|
6
|
-
const DEBUG = cds.debug('cli|build')
|
|
7
|
-
|
|
8
|
-
module.exports = class BuildTaskFactory {
|
|
9
|
-
constructor(options) {
|
|
10
|
-
this._providerFactory = new BuildTaskProviderFactory(options)
|
|
11
|
-
}
|
|
12
|
-
get providerFactory() {
|
|
13
|
-
return this._providerFactory
|
|
14
|
-
}
|
|
15
|
-
get options() {
|
|
16
|
-
return this.providerFactory.options
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// the following order for determining build tasks is used
|
|
20
|
-
// 1. create from command line input, e.g. cds build/all --for hana --src db --model srv --dest db
|
|
21
|
-
// 2. read using cds.env.build.tasks
|
|
22
|
-
// 3. create from cds.env.folders config data
|
|
23
|
-
async getTasks() {
|
|
24
|
-
const tasks = await this._createTasks()
|
|
25
|
-
// always resolve tasks for input validation
|
|
26
|
-
const resolvedTasks = this.providerFactory.resolveTasks(tasks)
|
|
27
|
-
if (this.options.resolve) {
|
|
28
|
-
return resolvedTasks
|
|
29
|
-
}
|
|
30
|
-
return tasks
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
createPlugin(task) {
|
|
34
|
-
return this.providerFactory.createPlugin(task)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async _createTasks() {
|
|
38
|
-
DEBUG?.(`determining build tasks for project [${cds.root}].`)
|
|
39
|
-
|
|
40
|
-
let tasks = BuildTaskFactory._getExistingTasks()
|
|
41
|
-
if (tasks.length === 0) {
|
|
42
|
-
tasks = await this.providerFactory.lookupTasks()
|
|
43
|
-
this._applyCliOptions(tasks)
|
|
44
|
-
} else {
|
|
45
|
-
this._applyCliOptions(tasks)
|
|
46
|
-
// 1. apply default values including task.for and ensure that for all tasks a provider exists - throwing error otherwise
|
|
47
|
-
await this.providerFactory.applyTaskDefaults(tasks)
|
|
48
|
-
// ensure that dependencies get wired up before filtering
|
|
49
|
-
await this.providerFactory.lookupTasks(tasks, true)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// 2. filters the list of build tasks
|
|
53
|
-
// Note: A new task might get created, e.g. 'cds build --for hana' will enforce a hana build even if sqlite has been configured
|
|
54
|
-
let existingTasks = tasks
|
|
55
|
-
tasks = await this._filterTasksForCli(tasks)
|
|
56
|
-
if (tasks.length === 0) {
|
|
57
|
-
return tasks
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// 3. add dependencies
|
|
61
|
-
existingTasks = [...tasks]
|
|
62
|
-
await this.providerFactory.lookupTasks(tasks, true)
|
|
63
|
-
if (tasks.length > existingTasks.length) {
|
|
64
|
-
const newTasks = tasks.filter(task => !existingTasks.includes(task))
|
|
65
|
-
// a dependant task was added
|
|
66
|
-
this._applyCliOptions(newTasks)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// obligatory task defaults shared by all tasks
|
|
70
|
-
await BuildTaskFactory._applyCommonTaskDefaults(tasks)
|
|
71
|
-
|
|
72
|
-
BuildTaskFactory._setDefaultBuildTargetFolder()
|
|
73
|
-
return tasks
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
static _getExistingTasks() {
|
|
77
|
-
return Array.isArray(cds.env.build?.tasks) ? structuredClone(cds.env.build.tasks) : []
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
static async _applyCommonTaskDefaults(tasks) {
|
|
81
|
-
// normalize model options
|
|
82
|
-
tasks.forEach(task => {
|
|
83
|
-
if (task.options?.model && !Array.isArray(task.options.model)) {
|
|
84
|
-
task.options.model = [task.options.model]
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
const modelPaths = await getDefaultModelPaths(false)
|
|
88
|
-
let wsModelPaths
|
|
89
|
-
// calculate only once
|
|
90
|
-
if (cds.cli.options?.[OPTION_WS] || tasks.some(task => hasOptionValue(task.options?.[OPTION_WS], true))) {
|
|
91
|
-
wsModelPaths = await getDefaultModelPaths(true)
|
|
92
|
-
}
|
|
93
|
-
// set default model options
|
|
94
|
-
tasks.forEach(task => {
|
|
95
|
-
if (!task.src) {
|
|
96
|
-
throw new BuildError(`Mandatory property 'src' not defined for build task '${task.for}'.`)
|
|
97
|
-
}
|
|
98
|
-
const optionWs = cds.cli.options?.[OPTION_WS] || hasOptionValue(task.options?.[OPTION_WS], true)
|
|
99
|
-
// shallow copy model paths
|
|
100
|
-
this._setTaskModelOptions(task, optionWs ? [...wsModelPaths] : [...modelPaths])
|
|
101
|
-
})
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
static _setDefaultBuildTargetFolder() {
|
|
105
|
-
// Java projects use "." as the default build target folder
|
|
106
|
-
if (hasJavaNature() && this._adaptBuildTargetSettingForJava()) {
|
|
107
|
-
DEBUG?.("using inplace build for java project instead of default staging build")
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Use inplace build for java projects if build.target has not been configured.
|
|
113
|
-
* @returns {boolean} true if changed, false otherwise
|
|
114
|
-
*/
|
|
115
|
-
static _adaptBuildTargetSettingForJava() {
|
|
116
|
-
if (cds.env.build.target !== ".") {
|
|
117
|
-
// filter user settings of cds.env
|
|
118
|
-
const userEnv = cds.env.for("cds", cds.root, false)
|
|
119
|
-
|
|
120
|
-
// use helper as env.build might be undefined
|
|
121
|
-
if (!userEnv.build?.target) {
|
|
122
|
-
cds.env.build.target = "."
|
|
123
|
-
return true
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return false
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
async _filterTasksForCli(tasks) {
|
|
130
|
-
const options = this.options
|
|
131
|
-
// filter tasks using either option for, use, src
|
|
132
|
-
let resultTasks = tasks.filter(task => {
|
|
133
|
-
return (!options.for || options.for === task.for)
|
|
134
|
-
&& (!options.src || options.src === task.src)
|
|
135
|
-
})
|
|
136
|
-
if (resultTasks.length === 0) {
|
|
137
|
-
if (options.for) {
|
|
138
|
-
const task = this.providerFactory.getTask({ for: options.for })
|
|
139
|
-
if (options.src) {
|
|
140
|
-
task.src = options.src
|
|
141
|
-
}
|
|
142
|
-
resultTasks.push(task)
|
|
143
|
-
this._applyCliOptions(resultTasks)
|
|
144
|
-
await this.providerFactory.applyTaskDefaults(resultTasks)
|
|
145
|
-
}
|
|
146
|
-
} else if (resultTasks.length <= tasks.length) {
|
|
147
|
-
// return the same array as long as it contains a subset of the given tasks
|
|
148
|
-
tasks.length = 0
|
|
149
|
-
resultTasks.forEach(task => tasks.push(task))
|
|
150
|
-
resultTasks = tasks
|
|
151
|
-
}
|
|
152
|
-
return resultTasks
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
_applyCliOptions(tasks) {
|
|
156
|
-
const options = this.options
|
|
157
|
-
// apply remaining cli options to filtered tasks
|
|
158
|
-
tasks.forEach(task => {
|
|
159
|
-
if (options.dest) {
|
|
160
|
-
task.dest = options.dest
|
|
161
|
-
}
|
|
162
|
-
if (options.taskOptions) {
|
|
163
|
-
const taskOptions = JSON.parse(JSON.stringify(options.taskOptions))
|
|
164
|
-
task.options = task.options ? Object.assign(task.options, taskOptions) : taskOptions
|
|
165
|
-
}
|
|
166
|
-
})
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
static _setTaskModelOptions(task, defaultModelPaths) {
|
|
170
|
-
// bootstrap service model is only required for Nodejs build task - issues/12770#issuecomment-1805719
|
|
171
|
-
if (task.for !== BUILD_TASK_NODEJS && task.for !== BUILD_TASK_NODE_CF) {
|
|
172
|
-
defaultModelPaths = defaultModelPaths.filter(p => !NODEJS_MODEL_EXCLUDE_LIST.includes(p))
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
let taskModelPaths = task.options?.model
|
|
176
|
-
if (taskModelPaths && !Array.isArray(taskModelPaths)) {
|
|
177
|
-
taskModelPaths = [taskModelPaths]
|
|
178
|
-
}
|
|
179
|
-
const allowList = new RegExp(`^@sap/cds${cds.env.requires.toggles ? '|^' + cds.env.features.folders.replace('*', '') : ''}`)
|
|
180
|
-
task.options = task.options || {}
|
|
181
|
-
let modelPaths = []
|
|
182
|
-
if (taskModelPaths?.length) {
|
|
183
|
-
if (!hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
|
|
184
|
-
modelPaths = defaultModelPaths.filter(p => p.match(allowList))
|
|
185
|
-
}
|
|
186
|
-
} else {
|
|
187
|
-
modelPaths = [...defaultModelPaths]
|
|
188
|
-
if (!modelPaths.includes(task.src)) {
|
|
189
|
-
modelPaths.push(task.src)
|
|
190
|
-
}
|
|
191
|
-
if (hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
|
|
192
|
-
// all default models except the built-in models
|
|
193
|
-
modelPaths = modelPaths.filter(p => !p.match(allowList))
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
task.options.model = [...new Set(taskModelPaths?.length ? taskModelPaths.concat(modelPaths) : modelPaths)]
|
|
197
|
-
}
|
|
198
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-unused-vars */
|
|
2
|
-
|
|
3
|
-
/** @typedef {import("./buildTaskProviderFactory").Task} Task */
|
|
4
|
-
/** @typedef {import("./plugin")} Plugin_ */
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @abstract
|
|
8
|
-
*/
|
|
9
|
-
module.exports = class BuildTaskProvider {
|
|
10
|
-
/**
|
|
11
|
-
* @abstract
|
|
12
|
-
* @param {{for: string}} key
|
|
13
|
-
* @returns {boolean | undefined}
|
|
14
|
-
*/
|
|
15
|
-
providesTask(key) { }
|
|
16
|
-
/**
|
|
17
|
-
* @param {{for: string}} key
|
|
18
|
-
* @returns {} task
|
|
19
|
-
*/
|
|
20
|
-
getTask(key) { return key }
|
|
21
|
-
/**
|
|
22
|
-
* @abstract
|
|
23
|
-
* @param {Task} task
|
|
24
|
-
* @returns {typeof Plugin_}
|
|
25
|
-
*/
|
|
26
|
-
getPlugin(task) { /** abstract */ }
|
|
27
|
-
/**
|
|
28
|
-
* @abstract
|
|
29
|
-
* @param {Array} tasks
|
|
30
|
-
* @param {boolean} dependencies
|
|
31
|
-
*/
|
|
32
|
-
async lookupTasks(tasks, dependencies) { /* abstract */ }
|
|
33
|
-
/**
|
|
34
|
-
* @abstract
|
|
35
|
-
* @param {Task} task
|
|
36
|
-
*/
|
|
37
|
-
async applyTaskDefaults(task) { /** abstract */ }
|
|
38
|
-
}
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const cds = require('../cds')
|
|
5
|
-
const { OUTPUT_MODE_FILESYSTEM, DEFAULT_SRC_FOLDER } = require('./constants')
|
|
6
|
-
const InternalBuildTaskProvider = require('./provider/internalBuildTaskProvider')
|
|
7
|
-
const BuildTaskProvider = require('./buildTaskProvider')
|
|
8
|
-
const { BuildError, normalizePath } = require('./util')
|
|
9
|
-
const DEBUG = cds.debug('cli|build')
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @typedef {import('./plugin').Task} Task
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
class BuildTaskProviderFactory {
|
|
16
|
-
/**
|
|
17
|
-
* @param {import('./index').BuildOptions} options - build options
|
|
18
|
-
*/
|
|
19
|
-
constructor(options = {}) {
|
|
20
|
-
options.outputMode = options.outputMode || OUTPUT_MODE_FILESYSTEM
|
|
21
|
-
if (options.clean === undefined) {
|
|
22
|
-
options.clean = true
|
|
23
|
-
}
|
|
24
|
-
['for', 'src', 'dest'].forEach(key => {
|
|
25
|
-
if (options[key]) {
|
|
26
|
-
if (typeof options[key] !== 'string') {
|
|
27
|
-
throw new BuildError(`Invalid build options - property '${key}' must be a string`)
|
|
28
|
-
}
|
|
29
|
-
if (key === 'src' || key === 'dest') {
|
|
30
|
-
// normalize path separator and remove trailing slash
|
|
31
|
-
options[key] = normalizePath(options[key])
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
/** @type {{ options: import('./index').BuildOptions, tasks: Task[]}} */
|
|
36
|
-
this._context = { options, tasks: [] } // resolved tasks
|
|
37
|
-
}
|
|
38
|
-
get options() {
|
|
39
|
-
return this._context.options
|
|
40
|
-
}
|
|
41
|
-
get context() {
|
|
42
|
-
return this._context
|
|
43
|
-
}
|
|
44
|
-
get providers() {
|
|
45
|
-
if (!this._providers) {
|
|
46
|
-
this._providers = this._loadProviders()
|
|
47
|
-
}
|
|
48
|
-
return this._providers
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
getTask(key) {
|
|
52
|
-
return this._getProvider(key).getTask(key)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async applyTaskDefaults(tasks) {
|
|
56
|
-
return Promise.all(tasks.map(async (task) => {
|
|
57
|
-
if (!task.for) {
|
|
58
|
-
throw new BuildError(`Mandatory property 'for' not defined for build task.`)
|
|
59
|
-
}
|
|
60
|
-
return this._applyTaskDefaults(this._getProvider(task), [task])
|
|
61
|
-
}))
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async lookupTasks(tasks = [], dependencies) {
|
|
65
|
-
for (const provider of this.providers) {
|
|
66
|
-
const existingTasks = [...tasks]
|
|
67
|
-
await this._lookupTasks(provider, tasks, dependencies)
|
|
68
|
-
if (existingTasks.length < tasks.length) {
|
|
69
|
-
// apply defaults
|
|
70
|
-
const newTasks = tasks.filter(task => !existingTasks.includes(task))
|
|
71
|
-
await this._applyTaskDefaults(provider, newTasks)
|
|
72
|
-
DEBUG?.(`Build task provider ${provider.constructor.name} returned build tasks ${JSON.stringify(newTasks)}`)
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return tasks
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Create a Plugin instance for the given build task.
|
|
80
|
-
* The implementation is loaded based on the build task's 'for' or 'use' option.
|
|
81
|
-
* @param {Task} task
|
|
82
|
-
*/
|
|
83
|
-
createPlugin(task) {
|
|
84
|
-
const Plugin = this.getPlugin(task)
|
|
85
|
-
const resolvedTask = this._resolveTask(task)
|
|
86
|
-
DEBUG?.(`loaded build plugin [${resolvedTask.for}]`)
|
|
87
|
-
|
|
88
|
-
const plugin = new Plugin()
|
|
89
|
-
if (!(plugin instanceof Plugin)) {
|
|
90
|
-
throw new Error(`Invalid Build plugin type ${task.for}`)
|
|
91
|
-
}
|
|
92
|
-
plugin._task = resolvedTask
|
|
93
|
-
plugin._context = this.context
|
|
94
|
-
this.context.tasks.push(resolvedTask)
|
|
95
|
-
DEBUG?.(`created build plugin [${resolvedTask.for}]`)
|
|
96
|
-
return plugin
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Loads the build plugin implementation for the given build task.
|
|
101
|
-
* 'for' defines an alias for built-in plugins like 'hana', 'java', 'node', 'fiori' or 'mtx'.
|
|
102
|
-
* 'use' defines the fully qualified module name of custom build plugins implementations.
|
|
103
|
-
* @param {Task} task
|
|
104
|
-
* @returns {typeof import('./plugin')}
|
|
105
|
-
*/
|
|
106
|
-
getPlugin(task) {
|
|
107
|
-
const provider = this._getProvider(task)
|
|
108
|
-
try {
|
|
109
|
-
return provider.getPlugin(task)
|
|
110
|
-
} catch (e) {
|
|
111
|
-
console.error(`Provider failed to load build plugin class ${task.for} - provider: ${provider.constructor.name}`)
|
|
112
|
-
throw e
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* @param {Task[]} tasks
|
|
118
|
-
*/
|
|
119
|
-
resolveTasks(tasks) {
|
|
120
|
-
return tasks.map(task => this._resolveTask(task))
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Resolves the given build task based on the project root folder.<br>
|
|
125
|
-
* The task is validated in order to ensure that 'src' refers to a valid folder and 'for' or 'use' reference can be required.
|
|
126
|
-
* @private
|
|
127
|
-
* @param {Task} task
|
|
128
|
-
*/
|
|
129
|
-
_resolveTask(task) {
|
|
130
|
-
// second validate src path
|
|
131
|
-
const resolvedTask = JSON.parse(JSON.stringify(task))
|
|
132
|
-
|
|
133
|
-
// Do not store resolved symlinks as this is causing issues on Windows, e.g. if git projects are
|
|
134
|
-
// located under 'C:\SAPDevelop\git\...' using a sym-link from '%USERHOME%\git' to 'C:\SAPDevelop\git'.
|
|
135
|
-
// see cap/issues/#8694
|
|
136
|
-
resolvedTask.src = path.resolve(cds.root, task.src)
|
|
137
|
-
// if --ws is passed, the db/ folder is not required, as the task will gather the model from the workspaces
|
|
138
|
-
if (!this.options.ws) {
|
|
139
|
-
try {
|
|
140
|
-
//validate source path
|
|
141
|
-
fs.realpathSync(resolvedTask.src)
|
|
142
|
-
} catch {
|
|
143
|
-
throw new BuildError(`The 'src' folder '${path.resolve(cds.root, task.src)}' for build task '${resolvedTask.for}' does not exist`)
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
resolvedTask.dest = path.resolve(cds.root, cds.env.build.target, task.dest || task.src)
|
|
147
|
-
resolvedTask.options = task.options || {}
|
|
148
|
-
return resolvedTask
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
_getProvider(key) {
|
|
152
|
-
const provider = this.providers.find(provider => {
|
|
153
|
-
try {
|
|
154
|
-
return provider.providesTask(key)
|
|
155
|
-
} catch (e) {
|
|
156
|
-
console.error(`Build task provider ${provider.constructor.name} returned an error`)
|
|
157
|
-
throw e
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
if (!provider) {
|
|
161
|
-
throw new BuildError(`No provider found for build task '${key.for}'. Ensure that all required dependencies have been added and 'npm install' has been executed.`)
|
|
162
|
-
}
|
|
163
|
-
return provider
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async _lookupTasks(provider, tasks, dependencies) {
|
|
167
|
-
return provider.lookupTasks(tasks, dependencies)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async _applyTaskDefaults(provider, tasks) {
|
|
171
|
-
return Promise.all(tasks.map(task => provider.applyTaskDefaults(task)))
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
_loadProviders() {
|
|
175
|
-
return [
|
|
176
|
-
new InternalBuildTaskProvider(),
|
|
177
|
-
new PluginBuildTaskProvider()
|
|
178
|
-
]
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Default provider implementation handling fully qualified custom build task declarations.
|
|
184
|
-
*/
|
|
185
|
-
class PluginBuildTaskProvider extends BuildTaskProvider {
|
|
186
|
-
#plugins = require('./plugins').plugins
|
|
187
|
-
get plugins() {
|
|
188
|
-
return this.#plugins
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* @param {{for: string}} key
|
|
193
|
-
*/
|
|
194
|
-
providesTask(key) {
|
|
195
|
-
return this.plugins.has(key.for)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
getPlugin(task) {
|
|
199
|
-
return this.plugins.get(task.for)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
async lookupTasks(tasks, dependencies) {
|
|
203
|
-
if (!dependencies) {
|
|
204
|
-
for (const [id, plugin] of this.plugins) {
|
|
205
|
-
if (plugin.hasTask()) {
|
|
206
|
-
tasks.push(this.getTask({ for: id }))
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
async applyTaskDefaults(task) {
|
|
213
|
-
const defaultTask = this.getTask(task)
|
|
214
|
-
const names = Object.getOwnPropertyNames(defaultTask)
|
|
215
|
-
names.forEach(name => {
|
|
216
|
-
task[name] ??= defaultTask[name]
|
|
217
|
-
})
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* @param {{for: string}} key
|
|
222
|
-
* @returns {Task}
|
|
223
|
-
*/
|
|
224
|
-
getTask(key) {
|
|
225
|
-
// plugin entry is already validated, a taskDefaults default member exists
|
|
226
|
-
const task = JSON.parse(JSON.stringify(this.plugins.get(key.for)?.taskDefaults ?? {}))
|
|
227
|
-
task.for = key.for
|
|
228
|
-
task.src ??= DEFAULT_SRC_FOLDER
|
|
229
|
-
task.src = task.src.replace(/\/$/, '')
|
|
230
|
-
return task
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
module.exports = BuildTaskProviderFactory
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
const cds = require('../../cds')
|
|
2
|
-
const { exists, isdir, path } = cds.utils
|
|
3
|
-
const { hasJavaNature, BuildError, normalizePath } = require('../util')
|
|
4
|
-
const BuildTaskProvider = require('../buildTaskProvider')
|
|
5
|
-
const { FILE_EXT_CDS, BUILD_TASK_HANA, BUILD_TASK_FIORI, BUILD_TASK_JAVA, BUILD_TASK_JAVA_CF, BUILD_TASK_NODEJS, BUILD_TASK_NODE_CF, BUILD_TASK_MTX,
|
|
6
|
-
BUILD_TASKS, BUILD_TASK_MTX_SIDECAR, MTX_SIDECAR_FOLDER, BUILD_TASK_MTX_EXTENSION } = require("../constants")
|
|
7
|
-
const ResourcesTarBuilder = require('./mtx/resourcesTarBuilder')
|
|
8
|
-
const DEBUG = cds.debug('cli|build')
|
|
9
|
-
const ModelProviderService = 'cds.xt.ModelProviderService'
|
|
10
|
-
|
|
11
|
-
module.exports = class InternalBuildTaskProvider extends BuildTaskProvider {
|
|
12
|
-
providesTask(key) {
|
|
13
|
-
return BUILD_TASKS.includes(key.for)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async lookupTasks(tasks, dependencies) {
|
|
17
|
-
return this._createTasks(tasks, dependencies)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async applyTaskDefaults(task) {
|
|
21
|
-
InternalBuildTaskProvider._setDefaultSrcFolder(task)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
getPlugin(task) {
|
|
25
|
-
return require(`./${task.for}`)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async _createTasks(tasks, dependencies) {
|
|
29
|
-
let db = typeof cds.env.folders.db === "string" ? [normalizePath(cds.env.folders.db)] : cds.env.folders.db
|
|
30
|
-
let srv = typeof cds.env.folders.srv === "string" ? [normalizePath(cds.env.folders.srv)] : cds.env.folders.srv
|
|
31
|
-
|
|
32
|
-
const folder4 = filesOrFolders => {
|
|
33
|
-
const entry = filesOrFolders
|
|
34
|
-
.flatMap(r => path.extname(r) === FILE_EXT_CDS ? [r] : [r, r + FILE_EXT_CDS])
|
|
35
|
-
.find(r => exists(r))
|
|
36
|
-
return entry && (isdir(entry) ? entry : path.dirname(entry))
|
|
37
|
-
}
|
|
38
|
-
const dbOptions = { model: [] }
|
|
39
|
-
const srvOptions = { model: [] }
|
|
40
|
-
if (Array.isArray(db) && db.length > 0) {
|
|
41
|
-
db = folder4(db)
|
|
42
|
-
if (!db && !dependencies) { // log once
|
|
43
|
-
DEBUG?.("No database module found")
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
if (Array.isArray(srv) && srv.length > 0) {
|
|
47
|
-
srv = folder4(srv)
|
|
48
|
-
if (!srv && !dependencies) { // log once
|
|
49
|
-
DEBUG?.("No service module found")
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// order of creation is relevant
|
|
54
|
-
if (dependencies) {
|
|
55
|
-
const mtxTask = tasks.find(task => task.for === BUILD_TASK_MTX || task.for === BUILD_TASK_MTX_SIDECAR)
|
|
56
|
-
if (mtxTask) {
|
|
57
|
-
//restore used tasks as they might have been filtered by 'cds build --for mtx'
|
|
58
|
-
if (mtxTask._uses) {
|
|
59
|
-
mtxTask._uses.map(use => use.task).forEach(task => {
|
|
60
|
-
if (!tasks.includes(task)) {
|
|
61
|
-
tasks.push(task)
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
}
|
|
65
|
-
let dbTask = ResourcesTarBuilder.getHanaTenantDbTask(tasks, mtxTask)
|
|
66
|
-
if (!dbTask) {
|
|
67
|
-
// db task might be missing if mtx task is enforced by 'cds build --for mtx'
|
|
68
|
-
if (cds.env.build.tasks) {
|
|
69
|
-
dbTask = ResourcesTarBuilder.getHanaTenantDbTask(cds.env.build.tasks, mtxTask)
|
|
70
|
-
}
|
|
71
|
-
if (!dbTask) {
|
|
72
|
-
dbTask = this._createDbTask(db, dbOptions)
|
|
73
|
-
}
|
|
74
|
-
if (dbTask) {
|
|
75
|
-
tasks.push(dbTask)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
if (dbTask && !mtxTask._uses?.map(use => use.task).includes(dbTask)) {
|
|
79
|
-
const use = { task: dbTask }
|
|
80
|
-
mtxTask._uses ? mtxTask._uses.push(use) : mtxTask._uses = [use]
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
} else {
|
|
84
|
-
!db && DEBUG?.(`project doesn't have a database module '${cds.env.folders.db}'`)
|
|
85
|
-
!srv && DEBUG?.(`project doesn't have a service module '${cds.env.folders.srv}'`)
|
|
86
|
-
|
|
87
|
-
// create hana build task
|
|
88
|
-
const dbTask = this._createDbTask(db, dbOptions)
|
|
89
|
-
if (dbTask) {
|
|
90
|
-
tasks.push(dbTask)
|
|
91
|
-
}
|
|
92
|
-
// create java or node build task
|
|
93
|
-
const srvTask = this._createSrvTask(srv, srvOptions)
|
|
94
|
-
if (srvTask) {
|
|
95
|
-
tasks.push(srvTask)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// create mtx build task
|
|
99
|
-
const mtxTask = this._createMtxTask(srv)
|
|
100
|
-
if (mtxTask) {
|
|
101
|
-
tasks.push(mtxTask)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
_createDbTask(src, taskOptions) {
|
|
107
|
-
if (!src || InternalBuildTaskProvider._isMtxExtension()) {
|
|
108
|
-
return null
|
|
109
|
-
}
|
|
110
|
-
let task = null
|
|
111
|
-
if (this._useHana()) {
|
|
112
|
-
DEBUG?.("found HANA database")
|
|
113
|
-
task = {
|
|
114
|
-
src: src,
|
|
115
|
-
for: BUILD_TASK_HANA,
|
|
116
|
-
options: taskOptions
|
|
117
|
-
}
|
|
118
|
-
} else {
|
|
119
|
-
DEBUG?.("found sqlite database - skipping HANA build task")
|
|
120
|
-
}
|
|
121
|
-
return task
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
_useHana() {
|
|
125
|
-
if (cds.env.requires.db?.kind === "hana" || cds.env.requires.db?.dialect === "hana") {
|
|
126
|
-
return true
|
|
127
|
-
}
|
|
128
|
-
// false if other db has been defined
|
|
129
|
-
if (cds.env.requires.db?.kind) {
|
|
130
|
-
return false
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
_createMtxTask(src) {
|
|
135
|
-
const main = cds.env
|
|
136
|
-
if (main.extends) {
|
|
137
|
-
return { for: BUILD_TASK_MTX_EXTENSION }
|
|
138
|
-
}
|
|
139
|
-
const isMtxs = main.requires.toggles || main.requires.multitenancy || main.requires[ModelProviderService]
|
|
140
|
-
if (isMtxs) {
|
|
141
|
-
if (main.requires?.[ModelProviderService]?._in_sidecar) {
|
|
142
|
-
throw new BuildError(`Seems that you are executing 'cds build' in the 'mtx/sidecar' folder. Execute 'cds build' in the project root folder instead.`)
|
|
143
|
-
}
|
|
144
|
-
const sidecarPath = path.join(cds.root, MTX_SIDECAR_FOLDER)
|
|
145
|
-
const sidecar = cds.env.for("cds", sidecarPath)
|
|
146
|
-
if (sidecar?.requires[ModelProviderService]?._in_sidecar) {
|
|
147
|
-
if (!exists(sidecarPath)) {
|
|
148
|
-
throw new BuildError(`MTX sidecar directory '${MTX_SIDECAR_FOLDER}' does not exist. Custom build task configuration required if the folder is named differently.`)
|
|
149
|
-
}
|
|
150
|
-
return { src: MTX_SIDECAR_FOLDER, for: BUILD_TASK_MTX_SIDECAR }
|
|
151
|
-
}
|
|
152
|
-
if (!hasJavaNature()) { // only Node.js: embedded multitenancy
|
|
153
|
-
return { src, for: BUILD_TASK_MTX }
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
_createSrvTask(src, taskOptions) {
|
|
159
|
-
if (!src || InternalBuildTaskProvider._isMtxExtension()) {
|
|
160
|
-
return null
|
|
161
|
-
}
|
|
162
|
-
let task = null
|
|
163
|
-
if (hasJavaNature()) {
|
|
164
|
-
task = this._createJavaTask(src, taskOptions)
|
|
165
|
-
} else {
|
|
166
|
-
task = this._createNodeTask(src, taskOptions)
|
|
167
|
-
}
|
|
168
|
-
return task
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
_createJavaTask(src, taskOptions) {
|
|
172
|
-
DEBUG?.("found Java runtime")
|
|
173
|
-
return {
|
|
174
|
-
src: src,
|
|
175
|
-
for: BUILD_TASK_JAVA,
|
|
176
|
-
options: taskOptions
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
_createNodeTask(src, taskOptions) {
|
|
181
|
-
DEBUG?.("found Nodejs runtime")
|
|
182
|
-
if (!exists('package.json')) {
|
|
183
|
-
throw new BuildError(`No 'package.json' found in project root folder '${cds.root}'`)
|
|
184
|
-
}
|
|
185
|
-
return {
|
|
186
|
-
src: src,
|
|
187
|
-
for: BUILD_TASK_NODEJS,
|
|
188
|
-
options: taskOptions
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
static _isMtxExtension() {
|
|
193
|
-
return !!cds.env.extends
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
static _setDefaultSrcFolder(task) {
|
|
197
|
-
switch (task.for) {
|
|
198
|
-
case BUILD_TASK_HANA:
|
|
199
|
-
task.src ||= normalizePath(cds.env.folders.db)
|
|
200
|
-
break
|
|
201
|
-
case BUILD_TASK_JAVA:
|
|
202
|
-
case BUILD_TASK_JAVA_CF:
|
|
203
|
-
case BUILD_TASK_NODEJS:
|
|
204
|
-
case BUILD_TASK_NODE_CF:
|
|
205
|
-
task.src ||= normalizePath(cds.env.folders.srv)
|
|
206
|
-
break
|
|
207
|
-
case BUILD_TASK_FIORI:
|
|
208
|
-
task.src ||= normalizePath(cds.env.folders.app)
|
|
209
|
-
break
|
|
210
|
-
case BUILD_TASK_MTX_SIDECAR:
|
|
211
|
-
task.src ||= MTX_SIDECAR_FOLDER
|
|
212
|
-
break
|
|
213
|
-
case BUILD_TASK_MTX_EXTENSION:
|
|
214
|
-
if (task.src && task.src !== cds.root) {
|
|
215
|
-
throw new BuildError("Invalid 'src' property value for build task 'mtx-extension', the only allowed value is '.'")
|
|
216
|
-
}
|
|
217
|
-
task.src ||= "."
|
|
218
|
-
break
|
|
219
|
-
case BUILD_TASK_MTX:
|
|
220
|
-
// mtxs with nodejs, but without sidecar
|
|
221
|
-
task.src ||= normalizePath(cds.env.folders.srv)
|
|
222
|
-
break
|
|
223
|
-
default:
|
|
224
|
-
throw new Error(`Unknown build task '${task.for}'`)
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('../java')
|