@sap/cds 6.8.3 → 7.0.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.
Files changed (214) hide show
  1. package/CHANGELOG.md +61 -2
  2. package/README.md +0 -1
  3. package/bin/cds-serve.js +50 -3
  4. package/bin/deploy/to-hana.js +1 -0
  5. package/bin/serve.js +16 -20
  6. package/lib/auth/basic-auth.js +6 -4
  7. package/lib/auth/index.js +4 -3
  8. package/lib/auth/jwt-auth.js +2 -5
  9. package/lib/compile/cds-compile.js +34 -89
  10. package/lib/compile/cdsc.js +11 -0
  11. package/lib/compile/etc/properties.js +2 -2
  12. package/lib/compile/for/lean_drafts.js +36 -69
  13. package/lib/compile/for/nodejs.js +2 -1
  14. package/lib/compile/load.js +1 -1
  15. package/lib/compile/minify.js +2 -0
  16. package/lib/compile/to/csn.js +74 -0
  17. package/{bin/build/provider/hana/2tabledata.js → lib/compile/to/hdbtabledata.js} +4 -6
  18. package/lib/compile/to/json.js +1 -1
  19. package/lib/compile/to/sql.js +8 -6
  20. package/lib/dbs/cds-deploy.js +174 -114
  21. package/lib/env/cds-env.js +64 -79
  22. package/lib/env/cds-requires.js +11 -28
  23. package/lib/env/defaults.js +13 -3
  24. package/lib/env/plugins.js +1 -12
  25. package/lib/env/presets.js +25 -21
  26. package/lib/index.js +121 -147
  27. package/lib/{core/reflect.js → linked/models.js} +2 -2
  28. package/lib/{core/infer.js → linked/queries.js} +2 -0
  29. package/lib/{core/index.js → linked/types.js} +2 -1
  30. package/lib/log/cds-error.js +13 -7
  31. package/lib/log/format/cf.js +1 -1
  32. package/lib/plugins.js +49 -0
  33. package/lib/ql/Query.js +0 -9
  34. package/lib/ql/STREAM.js +0 -1
  35. package/lib/req/context.js +2 -7
  36. package/lib/req/request.js +6 -2
  37. package/lib/req/response.js +23 -10
  38. package/lib/srv/middlewares/ctx-model.js +1 -1
  39. package/lib/srv/middlewares/errors.js +1 -1
  40. package/lib/srv/protocols/_legacy.js +1 -0
  41. package/lib/srv/protocols/graphql.js +7 -16
  42. package/lib/srv/protocols/index.js +59 -45
  43. package/lib/srv/protocols/odata-v2-proxy.js +2 -70
  44. package/lib/srv/srv-api.js +9 -3
  45. package/lib/srv/srv-dispatch.js +12 -9
  46. package/lib/srv/srv-models.js +4 -21
  47. package/lib/srv/srv-tx.js +15 -12
  48. package/lib/utils/cds-test.js +14 -9
  49. package/lib/utils/cds-utils.js +2 -12
  50. package/lib/utils/check-version.js +17 -0
  51. package/{bin/build → lib/utils}/csv-reader.js +23 -24
  52. package/libx/_runtime/auth/index.js +27 -23
  53. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
  54. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  55. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
  56. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
  57. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
  58. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
  59. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
  60. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
  61. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
  62. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
  63. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
  64. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
  65. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
  66. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  67. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
  68. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
  69. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
  70. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
  71. package/libx/_runtime/cds-services/services/Service.js +79 -107
  72. package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
  73. package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
  74. package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
  75. package/libx/_runtime/cds-services/util/assert.js +65 -2
  76. package/libx/_runtime/common/composition/data.js +1 -0
  77. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  78. package/libx/_runtime/common/generic/auth/restrict.js +5 -10
  79. package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
  80. package/libx/_runtime/common/generic/auth/utils.js +1 -2
  81. package/libx/_runtime/common/generic/crud.js +32 -16
  82. package/libx/_runtime/common/generic/etag.js +133 -104
  83. package/libx/_runtime/common/generic/input.js +6 -21
  84. package/libx/_runtime/common/generic/put.js +1 -1
  85. package/libx/_runtime/common/generic/stream.js +52 -0
  86. package/libx/_runtime/common/generic/temporal.js +25 -8
  87. package/libx/_runtime/common/i18n/messages.properties +0 -2
  88. package/libx/_runtime/common/utils/cqn.js +1 -1
  89. package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
  90. package/libx/_runtime/common/utils/csn.js +0 -51
  91. package/libx/_runtime/common/utils/etag.js +30 -0
  92. package/libx/_runtime/common/utils/keys.js +1 -1
  93. package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
  94. package/libx/_runtime/common/utils/path.js +1 -1
  95. package/libx/_runtime/common/utils/resolveView.js +2 -1
  96. package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
  97. package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
  98. package/libx/_runtime/common/utils/stream.js +140 -0
  99. package/libx/_runtime/common/utils/streamProp.js +29 -12
  100. package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
  101. package/libx/_runtime/db/generic/index.js +0 -2
  102. package/libx/_runtime/db/query/delete.js +2 -2
  103. package/libx/_runtime/db/query/insert.js +2 -2
  104. package/libx/_runtime/db/query/read.js +2 -2
  105. package/libx/_runtime/db/query/run.js +2 -2
  106. package/libx/_runtime/db/query/update.js +2 -2
  107. package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
  108. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
  109. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
  110. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
  111. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
  112. package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
  113. package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
  114. package/libx/_runtime/fiori/draft.js +2 -0
  115. package/libx/_runtime/fiori/generic/activate.js +8 -9
  116. package/libx/_runtime/fiori/generic/before.js +30 -20
  117. package/libx/_runtime/fiori/generic/cancel.js +5 -3
  118. package/libx/_runtime/fiori/generic/delete.js +5 -3
  119. package/libx/_runtime/fiori/generic/edit.js +7 -7
  120. package/libx/_runtime/fiori/generic/index.js +10 -16
  121. package/libx/_runtime/fiori/generic/new.js +5 -3
  122. package/libx/_runtime/fiori/generic/patch.js +11 -8
  123. package/libx/_runtime/fiori/generic/prepare.js +13 -6
  124. package/libx/_runtime/fiori/generic/read.js +12 -6
  125. package/libx/_runtime/fiori/lean-draft.js +207 -152
  126. package/libx/_runtime/fiori/utils/delete.js +10 -5
  127. package/libx/_runtime/fiori/utils/req.js +17 -5
  128. package/libx/_runtime/fiori/utils/stream.js +36 -0
  129. package/libx/_runtime/hana/Service.js +12 -9
  130. package/libx/_runtime/hana/conversion.js +10 -15
  131. package/libx/_runtime/hana/driver.js +2 -0
  132. package/libx/_runtime/hana/execute.js +28 -6
  133. package/libx/_runtime/hana/pool.js +36 -122
  134. package/libx/_runtime/hana/search2cqn4sql.js +34 -36
  135. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
  136. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
  137. package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
  138. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  139. package/libx/_runtime/remote/Service.js +20 -1
  140. package/libx/_runtime/remote/utils/client.js +3 -5
  141. package/libx/_runtime/sqlite/Service.js +4 -6
  142. package/libx/_runtime/sqlite/conversion.js +3 -13
  143. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
  144. package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
  145. package/libx/_runtime/sqlite/execute.js +5 -16
  146. package/libx/odata/afterburner.js +22 -6
  147. package/libx/odata/grammar.pegjs +6 -1
  148. package/libx/odata/parser.js +1 -1
  149. package/libx/rest/RestAdapter.js +16 -9
  150. package/libx/rest/RestRequest.js +1 -1
  151. package/libx/rest/middleware/input.js +2 -1
  152. package/libx/rest/middleware/operation.js +1 -0
  153. package/libx/rest/middleware/parse.js +3 -2
  154. package/libx/rest/middleware/payload.js +9 -8
  155. package/libx/rest/middleware/read.js +1 -0
  156. package/package.json +9 -16
  157. package/app/fiori/preview.js +0 -270
  158. package/app/fiori/routes.js +0 -59
  159. package/bin/build/buildTaskEngine.js +0 -360
  160. package/bin/build/buildTaskFactory.js +0 -283
  161. package/bin/build/buildTaskHandler.js +0 -241
  162. package/bin/build/buildTaskProvider.js +0 -22
  163. package/bin/build/buildTaskProviderFactory.js +0 -175
  164. package/bin/build/cds.js +0 -5
  165. package/bin/build/constants.js +0 -66
  166. package/bin/build/index.js +0 -58
  167. package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
  168. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
  169. package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
  170. package/bin/build/provider/buildTaskProviderInternal.js +0 -383
  171. package/bin/build/provider/fiori/index.js +0 -171
  172. package/bin/build/provider/hana/2migration.js +0 -179
  173. package/bin/build/provider/hana/index.js +0 -505
  174. package/bin/build/provider/hana/migrationtable.js +0 -472
  175. package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
  176. package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
  177. package/bin/build/provider/hana/template/.hdinamespace +0 -4
  178. package/bin/build/provider/hana/template/package.json +0 -12
  179. package/bin/build/provider/hana/template/undeploy.json +0 -5
  180. package/bin/build/provider/java/index.js +0 -111
  181. package/bin/build/provider/java-cf/index.js +0 -1
  182. package/bin/build/provider/mtx/index.js +0 -268
  183. package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
  184. package/bin/build/provider/mtx-extension/index.js +0 -131
  185. package/bin/build/provider/mtx-sidecar/index.js +0 -137
  186. package/bin/build/provider/node-cf/index.js +0 -1
  187. package/bin/build/provider/nodejs/index.js +0 -192
  188. package/bin/build/util.js +0 -299
  189. package/bin/cds.js +0 -125
  190. package/bin/deploy/to-hana/cfUtil.js +0 -355
  191. package/bin/deploy/to-hana/gitUtil.js +0 -57
  192. package/bin/deploy/to-hana/hana.js +0 -306
  193. package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
  194. package/bin/deploy/to-hana/index.js +0 -16
  195. package/bin/deploy/to-hana/mtaUtil.js +0 -170
  196. package/bin/mtx/in-cds.js +0 -17
  197. package/bin/plugins.js +0 -32
  198. package/bin/run.js +0 -24
  199. package/bin/utils/log.js +0 -24
  200. package/bin/version.js +0 -178
  201. package/libx/_runtime/audit/Service.js +0 -222
  202. package/libx/_runtime/audit/generic/personal/access.js +0 -61
  203. package/libx/_runtime/audit/generic/personal/index.js +0 -56
  204. package/libx/_runtime/audit/generic/personal/modification.js +0 -132
  205. package/libx/_runtime/audit/generic/personal/utils.js +0 -186
  206. package/libx/_runtime/audit/utils/log.js +0 -23
  207. package/libx/_runtime/audit/utils/v2.js +0 -176
  208. package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
  209. package/libx/_runtime/db/generic/integrity.js +0 -455
  210. package/srv/audit-log.cds +0 -87
  211. package/srv/mtx.cds +0 -2
  212. package/srv/mtx.js +0 -8
  213. /package/lib/{core → linked}/classes.js +0 -0
  214. /package/lib/{core → linked}/entities.js +0 -0
@@ -1,306 +0,0 @@
1
- const cp = require('child_process');
2
- const os = require('os');
3
- const path = require('path');
4
- const util = require('util');
5
-
6
- const fs = require('fs').promises;
7
-
8
- const { BuildTaskEngine, BuildTaskFactory } = require('../../build');
9
- const buildConstants = require('../../build/constants');
10
-
11
- const cfUtil = require('./cfUtil');
12
- const hdiDeployUtil = require('./hdiDeployUtil');
13
- const gitUtil = require('./gitUtil');
14
- const mtaUtil = require('./mtaUtil');
15
-
16
- const { bold, info } = require('../../utils/term');
17
-
18
- const IS_WIN = (os.platform() === 'win32');
19
- const UTF_8 = 'utf-8';
20
-
21
-
22
- class HanaDeployer {
23
-
24
- constructor() {
25
- this.execAsync = util.promisify(cp.exec);
26
- this.spawnSync = cp.spawnSync;
27
- }
28
-
29
- getFromEnv(...varNames) {
30
- const result = {}
31
- for (const varName of varNames) {
32
- if (process.env[varName]) {
33
- try {
34
- result[varName] = JSON.parse(process.env[varName]);
35
- } catch (err) {
36
- throw new Error(`Error parsing environment variable ${varName}`);
37
- }
38
- }
39
- }
40
- return result;
41
- }
42
-
43
- async deploy(model, serviceName, noSave, tunnelAddress, buildTaskOptions, vcapFile, undeployWhitelist, hdiOptions, bindCallback) { // NOSONAR
44
- hdiOptions = hdiOptions || {}
45
-
46
- console.log(`${bold('Starting deploy to SAP HANA ...')}`);
47
- if (vcapFile) {
48
- console.log(`Using VCAP_SERVICES from file ${vcapFile} (beta feature).`);
49
- bindCallback = null // credentials are given - no cds bind then
50
- } else if (bindCallback) {
51
- console.log('Using cds bind');
52
- }
53
-
54
- const projectPath = path.resolve(process.env._TEST_CWD || process.cwd());
55
-
56
- const { buildResults } = await this._build(model, buildTaskOptions);
57
-
58
- let globalVcapEnv = vcapFile ? await this._loadEnvFile(vcapFile) : {};
59
- globalVcapEnv = { ...globalVcapEnv, ...this.getFromEnv('VCAP_SERVICES', 'SERVICE_REPLACEMENTS') };
60
- if (process.env.TARGET_CONTAINER) {
61
- globalVcapEnv.TARGET_CONTAINER = process.env.TARGET_CONTAINER;
62
- }
63
-
64
- for (const buildResult of buildResults) {
65
- let vcapEnv = globalVcapEnv;
66
- let serviceKeyName;
67
- const currentModelFolder = buildResult.result.dest;
68
-
69
- if (undeployWhitelist) {
70
- console.log('Writing undeploy.json');
71
- await fs.write(path.join(currentModelFolder, 'undeploy.json'), JSON.stringify(undeployWhitelist, null, 2));
72
- }
73
-
74
- const hasVCAPEnv = Object.keys(vcapEnv).length > 0;
75
- if (!serviceName && hasVCAPEnv) {
76
- await fs.mkdir(currentModelFolder, { recursive: true });
77
- } else {
78
- const { cfServiceInstanceName, cfServiceInstanceKeyName, serviceKey } =
79
- await this._getOrCreateCFService(projectPath, currentModelFolder, serviceName, tunnelAddress);
80
- serviceKeyName = cfServiceInstanceKeyName;
81
- serviceName = serviceName || cfServiceInstanceName;
82
-
83
- vcapEnv = this._getVCAPServicesEntry(cfServiceInstanceName, serviceKey);
84
-
85
- if (!noSave && !bindCallback) {
86
- await this._addInstanceToDefaultEnvJson([currentModelFolder, projectPath], cfServiceInstanceName, serviceKey);
87
- }
88
- }
89
-
90
- // Check if deployer is already installed, otherwise only install this one, not the rest of dependencies.
91
- if (!await hdiDeployUtil.findHdiDeployLib(currentModelFolder)) {
92
- const { deployerName, deployerVersionSpec } = hdiDeployUtil;
93
- console.log(`Installing ${deployerName}`);
94
-
95
- // spawn has not callback and cannot be promisified, using sync instead
96
- this.spawnSync(`npm`, [`install`, `${deployerName}@${deployerVersionSpec}`, (noSave ? '--no-save' : '--save-dev')], {
97
- cwd: currentModelFolder,
98
- shell: IS_WIN,
99
- stdio: 'inherit',
100
- env: {
101
- ...process.env,
102
- NODE_ENV: 'development' // for 'install --save-dev' to work, there must be no 'production' set
103
- }
104
- });
105
- }
106
-
107
- await hdiDeployUtil.deploy(currentModelFolder, vcapEnv, hdiOptions);
108
-
109
- // let isLoggedInToCF;
110
- // try {
111
- // isLoggedInToCF = !!(await cfUtil.getCfTarget());
112
- // } catch (err) {
113
- // // valid state: not logged in
114
- // }
115
- // if (bindCallback && isLoggedInToCF) {
116
- if (!hasVCAPEnv && bindCallback) {
117
- const args = [path.relative(projectPath, buildResult.task.src)];
118
- const options = { to: `${serviceName}:${serviceKeyName}`, kind: buildResult.task.for }
119
- await bindCallback(args, options);
120
- }
121
- }
122
-
123
- if (!bindCallback) {
124
- await gitUtil.ensureFileIsGitignored('default-env.json', projectPath);
125
- }
126
-
127
- console.log(`If not already done, use ${info('cds add hana')} to configure the project for SAP HANA.\n`);
128
- console.log(`Done.`);
129
-
130
- return { buildResults };
131
- }
132
-
133
-
134
- async _getOrCreateCFService(projectPath, currentModelFolder, serviceName, tunnelAddress) {
135
- const modelName = path.basename(currentModelFolder);
136
-
137
- // get from param
138
- let cfServiceInstanceMta;
139
- let cfServiceInstanceName;
140
- if (serviceName) {
141
- cfServiceInstanceName = serviceName;
142
- } else {
143
- const cfServiceDescriptor = await mtaUtil.getHanaDbModuleDescriptor(projectPath, modelName);
144
- cfServiceInstanceName = cfServiceDescriptor.hdiServiceName;
145
- cfServiceInstanceMta = cfServiceDescriptor.hdiService
146
- }
147
-
148
- console.log();
149
- this._validateServiceInstanceName(cfServiceInstanceName);
150
- console.log(`Using container ${bold(cfServiceInstanceName)}`);
151
-
152
- let cfConfig = cfServiceInstanceMta && cfServiceInstanceMta.parameters && cfServiceInstanceMta.parameters.config;
153
- const serviceInstance = await this.createHanaService(cfServiceInstanceName, cfConfig);
154
-
155
- const cfServiceInstanceKeyName = `${cfServiceInstanceName}-key`;
156
- let serviceKey = await cfUtil.getOrCreateServiceKey(serviceInstance, cfServiceInstanceKeyName);
157
- this._validateServiceKey(serviceKey, cfServiceInstanceKeyName);
158
-
159
- if (tunnelAddress) {
160
- console.log(`Using tunnel address ${bold(tunnelAddress)} (beta feature)`);
161
- serviceKey = this._injectTunnelAddress(serviceKey, tunnelAddress)
162
- }
163
-
164
- return { cfServiceInstanceName, cfServiceInstanceKeyName, serviceKey, serviceInstance }
165
- }
166
-
167
-
168
- async createHanaService(instanceName, cfConfig) {
169
- // hana or hanatrial, error if neither found
170
- try {
171
- return await cfUtil.getOrCreateService('hana', 'hdi-shared', instanceName, cfConfig);
172
- } catch (error) {
173
- if (error.command && /offering .* not found/i.test(error.command.stderr)) {
174
- console.log(`Falling back to 'hanatrial'`);
175
- return await cfUtil.getOrCreateService('hanatrial', 'hdi-shared', instanceName, cfConfig);
176
- }
177
- else if (error.command && /no database/i.test(error.command.stderr)) {
178
- console.log(`No database connected to 'hana' service. Falling back to 'hanatrial'`);
179
- return await cfUtil.getOrCreateService('hanatrial', 'hdi-shared', instanceName, cfConfig);
180
- }
181
- throw error;
182
- }
183
- }
184
-
185
-
186
- _validateServiceKey(serviceKey, cfServiceInstanceKey) {
187
- if (!serviceKey) {
188
- throw new Error(`Could not create service key ${bold(cfServiceInstanceKey)}.`);
189
- }
190
-
191
- const fields = ['schema', 'user', 'password', 'url'];
192
- for (const field of fields) {
193
- if (!serviceKey[field]) {
194
- throw new Error(`Service key is missing mandatory field '${field}'. Make sure you are ${bold('not')} using a managed service.`);
195
- }
196
- }
197
- }
198
-
199
-
200
- async _build(model, buildTaskOptions) {
201
- buildTaskOptions = buildTaskOptions || {
202
- root: process.env._TEST_CWD || process.cwd(),
203
- cli: true,
204
- cmdOptions: {
205
- for: buildConstants.BUILD_TASK_HANA
206
- }
207
- };
208
-
209
- if (typeof model === 'string') {
210
- model = [model];
211
- }
212
- console.log(`Creating build tasks`);
213
- const buildTaskFactory = new BuildTaskFactory();
214
- const hanaTasks = await buildTaskFactory.getTasks(buildTaskOptions);
215
- console.log(`Running build`);
216
-
217
- const buildResults = await new BuildTaskEngine().processTasks(hanaTasks, buildTaskOptions);
218
- return { buildResults, hanaTasks }
219
- }
220
-
221
- async _loadEnvFile(defaultEnvFile) {
222
- try {
223
- const content = await fs.readFile(defaultEnvFile);
224
- return JSON.parse(content);
225
- } catch (err) {
226
- throw new Error(`Error reading default env file: ${err.message}`);
227
- }
228
- }
229
-
230
-
231
- async _addInstanceToDefaultEnvJson(currentFolders, serviceInstanceName, serviceKey) {
232
- for (const currentFolder of currentFolders) {
233
- let defaultEnvJson = {};
234
- const defaultEnvJsonPath = path.join(currentFolder, 'default-env.json');
235
-
236
- try {
237
- defaultEnvJson = JSON.parse(await fs.readFile(defaultEnvJsonPath, UTF_8));
238
- } catch (err) {
239
- // ignore any errors
240
- }
241
-
242
- defaultEnvJson.VCAP_SERVICES = defaultEnvJson.VCAP_SERVICES || {};
243
- for (const serviceKey of Object.keys(defaultEnvJson.VCAP_SERVICES)) {
244
- defaultEnvJson.VCAP_SERVICES[serviceKey] = defaultEnvJson.VCAP_SERVICES[serviceKey].filter((service) => {
245
- return (service.name !== serviceInstanceName);
246
- });
247
- }
248
-
249
- const hanaEntry = this._getVCAPServicesEntry(serviceInstanceName, serviceKey)
250
- Object.assign(defaultEnvJson, hanaEntry);
251
-
252
- console.log(`Writing ${defaultEnvJsonPath}`);
253
- await fs.mkdir(path.dirname(defaultEnvJsonPath), { recursive: true })
254
- await fs.writeFile(defaultEnvJsonPath, JSON.stringify(defaultEnvJson, null, 2));
255
- }
256
- }
257
-
258
-
259
- _getVCAPServicesEntry(serviceInstanceName, serviceKey) {
260
- return {
261
- VCAP_SERVICES: {
262
- hana: [
263
- {
264
- name: serviceInstanceName,
265
- tags: ['hana'],
266
- credentials: serviceKey
267
- }
268
- ]
269
- }
270
- };
271
- }
272
-
273
-
274
- _validateServiceInstanceName(serviceInstanceName) {
275
- // valid service name chars: alpha-numeric, hyphens, and underscores
276
- if (/[^\w-_]+/g.exec(serviceInstanceName)) {
277
- throw new Error(`Service name ${serviceInstanceName} must only contain alpha-numeric, hyphens, and underscores.`);
278
- }
279
- }
280
-
281
-
282
- _injectTunnelAddress(serviceKey, tunnelAddress) {
283
- if (!/\w+:\d+/.test(tunnelAddress)) {
284
- throw new Error(`Invalid tunnel address '${tunnelAddress}' - must be in form 'host:port'`)
285
- }
286
- const [tunnelHost, tunnelPort] = tunnelAddress.split(':')
287
- const { host, port } = serviceKey
288
- serviceKey.host = tunnelHost
289
- serviceKey.port = tunnelPort
290
- serviceKey.url = serviceKey.url.replace(`${host}:${port}`, tunnelAddress)
291
- serviceKey.hostname_in_certificate = host // make cert. verification happy, see xs2/hdideploy.js#527
292
- serviceKey.url = serviceKey.url + (serviceKey.url.includes('?') ? '&' : '?') + 'hostNameInCertificate=' + host
293
- return serviceKey
294
- }
295
-
296
-
297
- async readFileSafely(file) {
298
- try {
299
- return await fs.readFile(file, 'utf8');
300
- } catch (err) {
301
- return '';
302
- }
303
- }
304
- }
305
-
306
- module.exports = new HanaDeployer();
@@ -1,153 +0,0 @@
1
- const cp = require('child_process');
2
- const path = require('path');
3
- const util = require('util');
4
-
5
- const execAsync = util.promisify(cp.exec);
6
-
7
- const cds = require('../../../lib');
8
- const LOG = cds.log ? cds.log('deploy') : console;
9
- const DEBUG = cds.debug('deploy');
10
- const { SILENT } = cds.log.levels;
11
-
12
- class HdiDeployUtil {
13
-
14
- constructor() {
15
- this.hdiDeployLibs = new Map();
16
- this.deployerName = '@sap/hdi-deploy'
17
- this.deployerVersionSpec = '^4'
18
- }
19
-
20
- async deployTenant(dbDir, env) {
21
- await this._executeDeploy(dbDir, env, true);
22
- }
23
-
24
- async deploy(dbDir, vcapEnv, options) {
25
- vcapEnv = vcapEnv || {}; // handles null and undefined
26
- options = options || {};
27
-
28
- console.log(`Deploying to HANA from ${dbDir}`);
29
-
30
- const hdiDeployLib = await this._getHdiDeployLib(dbDir);
31
-
32
- let deployerEnv = JSON.parse(JSON.stringify(process.env));
33
- const hdiDeployOptions = deployerEnv.HDI_DEPLOY_OPTIONS ? JSON.parse(deployerEnv.HDI_DEPLOY_OPTIONS) : {};
34
- delete hdiDeployOptions.root;
35
-
36
- if (typeof hdiDeployLib.clean_env === 'function') {
37
- deployerEnv = hdiDeployLib.clean_env(deployerEnv);
38
- }
39
-
40
- if (vcapEnv.VCAP_SERVICES) {
41
- deployerEnv.VCAP_SERVICES = JSON.stringify(vcapEnv.VCAP_SERVICES);
42
- }
43
- if (vcapEnv.SERVICE_REPLACEMENTS) {
44
- deployerEnv.SERVICE_REPLACEMENTS = JSON.stringify(vcapEnv.SERVICE_REPLACEMENTS);
45
- }
46
- if (vcapEnv.TARGET_CONTAINER) {
47
- deployerEnv.TARGET_CONTAINER = vcapEnv.TARGET_CONTAINER;
48
- }
49
-
50
- if (options.autoUndeploy) {
51
- console.log(`Hdi deployer automatically undeploys deleted resources using --auto-undeploy.`);
52
- hdiDeployOptions.auto_undeploy = true;
53
- }
54
-
55
- if (Object.entries(hdiDeployOptions).length > 0) {
56
- deployerEnv.HDI_DEPLOY_OPTIONS = JSON.stringify(hdiDeployOptions);
57
- }
58
-
59
- await this._executeDeploy(dbDir, deployerEnv);
60
- }
61
-
62
-
63
- async findHdiDeployLib(cwd) {
64
- const searchPaths = await this._npmSearchPaths(cwd)
65
- try {
66
- return require.resolve(path.join(this.deployerName, 'library'), { paths: searchPaths });
67
- } catch (err) {
68
- // no luck
69
- }
70
- }
71
-
72
-
73
- async _getHdiDeployLib(dbDir) {
74
- let hdiDeployLib = this.hdiDeployLibs.get(dbDir)
75
- if (!hdiDeployLib) {
76
- hdiDeployLib = await this._loadHdiDeployLib(dbDir);
77
- this.hdiDeployLibs.set(dbDir, hdiDeployLib);
78
- }
79
-
80
- return hdiDeployLib;
81
- }
82
-
83
-
84
- async _loadHdiDeployLib(cwd) {
85
- const libPath = await this.findHdiDeployLib(cwd)
86
- if (!libPath) {
87
- const searchPaths = await this._npmSearchPaths(cwd)
88
- throw new Error(`Required library '${this.deployerName}' not found in
89
- ${searchPaths.join('\n ')}
90
- Add it either as a devDependency using 'npm install -D ${this.deployerName}' or install it globally using 'npm install -g ${this.deployerName}'.`);
91
- }
92
-
93
- LOG.info(`Using HDI deployer from ${libPath}`)
94
-
95
- // let any error go through and abort deploy
96
- return require(libPath);
97
- }
98
-
99
-
100
- async _npmSearchPaths(cwd) {
101
- // REVISIT: we shouldn't have to rely on `npm` on the server
102
- try {
103
- const npmRootCall = await execAsync('npm root -g');
104
- const globalNodeModules = npmRootCall.stdout.toString().trim();
105
- return [cwd, globalNodeModules, '@sap/hdi-deploy']
106
- } catch (error) {
107
- if (/Command failed: npm.*not found/s.test(error.message)) return [cwd, '@sap/hdi-deploy']
108
- else throw error
109
- }
110
- }
111
-
112
-
113
- async _executeDeploy(dbDir, env, fromMtx) {
114
- const hdiDeployLib = await this._getHdiDeployLib(dbDir);
115
- let writeStream
116
- if (fromMtx) {
117
- await cds.utils.mkdirp('logs')
118
- writeStream = require('fs').createWriteStream(path.join(cds.root, 'logs', `${cds.context.tenant}.log`))
119
- }
120
- return new Promise((resolve, reject) => {
121
- const callbacks = {
122
- stderrCB: buffer => {
123
- LOG.error(buffer.toString())
124
- writeStream?.write(buffer)
125
- },
126
- }
127
- if (fromMtx) {
128
- callbacks.stdoutCB = buffer => {
129
- DEBUG?.(buffer.toString())
130
- writeStream.write(buffer)
131
- }
132
- } else if (LOG.level !== SILENT) {
133
- callbacks.stdoutCB = buffer => LOG.info(buffer.toString())
134
- }
135
- hdiDeployLib.deploy(dbDir, env, (error, response) => {
136
- if (error) {
137
- return reject(error);
138
- }
139
- if (response?.exitCode) {
140
- let message = `HDI deployment failed with exit code ${response.exitCode}`
141
- if (response.signal) message += `. ${response.signal}`
142
- return reject(new Error(message));
143
- }
144
- return resolve();
145
- }, callbacks);
146
- }).finally(() => writeStream?.end());
147
- }
148
- }
149
-
150
-
151
- module.exports = new HdiDeployUtil();
152
-
153
- /* eslint no-console: off */
@@ -1,16 +0,0 @@
1
- exports.deploy = (_model, _dbSpecificParameter, {
2
- 'no-save': no_save,
3
- 'auto-undeploy': autoUndeploy = false,
4
- 'tunnel-address': tunnelAddress,
5
- 'vcap-file': vcapFile,
6
- }, bindCallback) => {
7
- const hanaDeployer = require('./hana');
8
-
9
- return hanaDeployer.deploy(
10
- _model, _dbSpecificParameter,
11
- no_save, tunnelAddress,
12
- null, vcapFile, null,
13
- { autoUndeploy },
14
- bindCallback
15
- )
16
- }
@@ -1,170 +0,0 @@
1
- const cds = require('../../../lib')
2
- const fs = require('fs').promises
3
- const {existsSync} = require('fs')
4
- const path = require('path')
5
-
6
- const HDI_CONTAINER_TYPES = ['com.sap.xs.hdi-container']
7
- const UTF_8 = 'utf-8'
8
- const MTA_YAML = 'mta.yaml'
9
- const LOG = cds.log ? cds.log('deploy') : console;
10
-
11
- async function getHanaDbModuleDescriptor(projectPath, moduleName) {
12
- // mta might be null if mta.yaml does not exist
13
- const mta = await _getMta(projectPath)
14
- const projectInfo = await _getProjectInfo(projectPath, mta)
15
- const hdiService = _findHdiResource(mta, moduleName)
16
- const appName = _getApplicationName(mta, moduleName, 'hdb')
17
-
18
- return {
19
- project: projectInfo,
20
- appName: appName ? appName : `${projectInfo.name}-${moduleName}-deployer`,
21
- hdiServiceName: hdiService ? hdiService.name : `${projectInfo.name}-${moduleName}`,
22
- hdiService: hdiService
23
- }
24
- }
25
-
26
- async function getServiceModuleDescriptor(projectPath, moduleName, moduleType) {
27
- // mta might be null if mta.yaml does not exist
28
- const mta = await _getMta(projectPath)
29
- const projectInfo = await _getProjectInfo(projectPath, mta)
30
- const appName = _getApplicationName(mta, moduleName, moduleType)
31
-
32
- return {
33
- project: projectInfo,
34
- appName: appName ? appName : `${projectInfo.name}-${moduleName}`
35
- }
36
- }
37
-
38
- async function _getProjectInfo(projectPath, mta) {
39
- const details = {
40
- }
41
- // 1. use mta data
42
- if (mta) {
43
- details.id = mta.ID
44
- details.description = mta.description
45
- details.version = mta.version
46
- if (mta.ID) {
47
- details.name = mta.ID.replace(/\./g, '-')
48
- }
49
- }
50
- // 2. use package.json data
51
- const packageJsonPath = path.join(projectPath, 'package.json')
52
- if (existsSync(packageJsonPath)) {
53
- try {
54
- const packageJson = JSON.parse((await fs.readFile(packageJsonPath, 'utf-8')).toString())
55
- if (!details.description && packageJson.description) {
56
- details.description = packageJson.description
57
- }
58
- if (!details.version && packageJson.version) {
59
- details.version = packageJson.version
60
- }
61
- if (packageJson.name) {
62
- let segments = packageJson.name.trim().split('/')
63
- // scope as namespace
64
- if (segments[0].startsWith('@')) {
65
- segments[0] = segments[0].replace('@', '')
66
- }
67
- segments = segments.map(segment => segment.startsWith('@') ? encodeURIComponent(segment.replace('@', '')) : encodeURIComponent(segment))
68
- if (!details.name) {
69
- details.name = segments[segments.length - 1]
70
- }
71
- if (!details.id) {
72
- details.id = segments.join('.')
73
- }
74
- if (!details.description) {
75
- details.description = segments[segments.length - 1]
76
- }
77
- }
78
- } catch (e) {
79
- console.error(`Failed to load ${packageJsonPath} - skip application data`, e)
80
- }
81
- }
82
- // 3. use project name and static default values
83
- const projectName = path.basename(projectPath)
84
- if (!details.name) {
85
- details.name = projectName
86
- }
87
- if (!details.description) {
88
- details.description = projectName
89
- }
90
- if (!details.id) {
91
- details.id = projectName
92
- }
93
- if (!details.version) {
94
- details.version = '1.0.0'
95
- }
96
- return details
97
- }
98
-
99
- async function _getMta(projectPath) {
100
- // yaml.parse oesn't like null
101
- const mtaFilePath = path.join(projectPath, MTA_YAML)
102
-
103
- const existsMtaYaml = existsSync(mtaFilePath)
104
- if (!existsMtaYaml) {
105
- LOG.debug('mta.yaml not existing')
106
- return null
107
- }
108
-
109
- const yamlStr = await fs.readFile(mtaFilePath, UTF_8)
110
-
111
- // yaml returns null if string couldn't be parsed, e.g. empty string
112
- return cds.parse.yaml(yamlStr)
113
- }
114
-
115
- function _getApplicationName(mta, moduleName, moduleType) {
116
- const module = _findModule(mta, moduleName, moduleType)
117
- if (module) {
118
- const appName = module.parameters && module.parameters['app-name']
119
- return appName ? appName : module.name
120
- }
121
- return null
122
- }
123
-
124
- function _findModules(mta, moduleType) {
125
- let modules = []
126
- if (mta && Array.isArray(mta.modules)) {
127
- modules = mta.modules.filter(module => module.type === moduleType)
128
- }
129
- return modules
130
- }
131
-
132
- function _findModule(mta, moduleName, moduleType) {
133
- const modules = _findModules(mta, moduleType)
134
- if (modules.length === 1) {
135
- return modules[0]
136
- } else if (modules.length > 1) {
137
- return modules.find(module => typeof module.path === 'string' && module.path.includes(moduleName))
138
- }
139
- return null
140
- }
141
-
142
- function _findHdiResource(mta, moduleName) {
143
- if (mta && Array.isArray(mta.resources)) {
144
- const hdiResources = mta.resources.filter(resource => HDI_CONTAINER_TYPES.includes(resource.type))
145
-
146
- if (hdiResources.length > 0) {
147
- if (Array.isArray(mta.modules)) {
148
- const module = _findModule(mta, moduleName, 'hdb')
149
- if (module && Array.isArray(module.requires)) {
150
- return hdiResources.find(hdiResource =>
151
- module.requires.find(req =>
152
- hdiResource.name === req.name
153
- )
154
- )
155
- }
156
- }
157
-
158
- console.warn(`No matching hdi resource found for ${moduleName}. Using ${hdiResources[0].name}.`)
159
- return hdiResources[0]
160
- }
161
- }
162
-
163
- return null
164
- }
165
-
166
- module.exports = {
167
- getHanaDbModuleDescriptor,
168
- getServiceModuleDescriptor,
169
- MTA_YAML
170
- }
package/bin/mtx/in-cds.js DELETED
@@ -1,17 +0,0 @@
1
- const cds = require('../build/cds')
2
-
3
- if (cds.requires.multitenancy && cds.utils._oldMtx()) try {
4
- // eslint-disable-next-line cds/no-missing-dependencies
5
- const mtx = module.exports = require ('@sap/cds-mtx')()
6
- mtx.inject (cds)
7
- cds.on('served', () => cds.emit('mtx'))
8
- } catch(e) {
9
- if (e.code === 'MODULE_NOT_FOUND') throw new Error('Error serving MTX APIs: @sap/cds-mtx is not installed')
10
- else throw e
11
- }
12
- else module.exports = undefined
13
-
14
- /*
15
- cds.requires.multitenancy -- use this to check whether mt is enabled (old or new)
16
- cds.mtx -- use this to check whether old(!) mtx is enabled
17
- */
package/bin/plugins.js DELETED
@@ -1,32 +0,0 @@
1
- const cds = require('../lib')
2
- const DEBUG = cds.debug('plugins')
3
-
4
- module.exports = async function load_plugins (log = console.log) {
5
-
6
- if (DEBUG) console.time('[cds] - loaded plugins in')
7
- const plugins = []
8
- if (cds.env.plugins) {
9
- for (let each of cds.env.plugins) {
10
- let impl = typeof each === 'string' ? each : each.impl
11
- if (impl.startsWith('.'))
12
- impl = require.resolve(cds.root + '/' + impl)
13
- plugins.push(_load_plugin(impl, each))
14
- }
15
- } else
16
- try {
17
- const pkg = require(cds.root + '/package.json')
18
- const dependencies = { ...pkg.dependencies, ...(process.env.NODE_ENV !== 'production' && pkg.devDependencies) }
19
- for (let each in dependencies) {
20
- plugins.push(_load_plugin(each + '/cds-plugin'))
21
- }
22
- } catch { /* ignored */ }
23
- try { await Promise.all(plugins); } catch { /* ignored */ }
24
- if (DEBUG) console.timeEnd('[cds] - loaded plugins in')
25
-
26
- async function _load_plugin (impl, conf) {
27
- // TODO support ESM plugins. But see cap/cds/pull/1838#issuecomment-1177200 !
28
- const plugin = require(impl)
29
- log('loaded plugin:', { impl })
30
- if (plugin.activate) await plugin.activate(conf)
31
- }
32
- }