@sap/cds-dk 6.8.2 → 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 (218) hide show
  1. package/bin/activate.js +15 -7
  2. package/bin/add.js +29 -15
  3. package/bin/bind.js +49 -116
  4. package/bin/build.js +114 -0
  5. package/bin/cds.js +67 -24
  6. package/bin/compile/index.js +2 -2
  7. package/bin/deploy/index.js +46 -39
  8. package/bin/deploy/to-hana.js +11 -8
  9. package/bin/deploy/to-postgres.js +8 -2
  10. package/bin/deploy/to-sqlite.js +0 -1
  11. package/bin/env.js +75 -41
  12. package/bin/eval.js +3 -3
  13. package/bin/extend.js +17 -10
  14. package/bin/help.js +22 -21
  15. package/bin/import.js +10 -7
  16. package/bin/init.js +38 -17
  17. package/bin/login.js +69 -55
  18. package/bin/logout.js +12 -9
  19. package/bin/migrate.js +10 -4
  20. package/bin/pull.js +12 -5
  21. package/bin/push.js +24 -13
  22. package/bin/repl.js +1 -0
  23. package/bin/run.js +25 -0
  24. package/bin/subscribe.js +13 -8
  25. package/bin/unsubscribe.js +15 -8
  26. package/bin/upgrade.js +15 -9
  27. package/bin/util/log.js +24 -0
  28. package/bin/version.js +124 -0
  29. package/bin/watch.js +1 -35
  30. package/bin/watched.js +39 -0
  31. package/lib/bind/KubernetesApiAccessor.js +2 -2
  32. package/lib/bind/bindingManager.js +1 -1
  33. package/lib/bind/bindingUtil.js +0 -9
  34. package/lib/bind/cfKeyProvider.js +10 -72
  35. package/lib/bind/index.js +114 -0
  36. package/lib/bind/kubernetesCredentialsProvider.js +2 -2
  37. package/lib/bind/userCdsrcJsonStorageProvider.js +7 -44
  38. package/lib/build/buildTaskEngine.js +355 -0
  39. package/lib/build/buildTaskFactory.js +284 -0
  40. package/lib/build/buildTaskHandler.js +240 -0
  41. package/lib/build/buildTaskProvider.js +22 -0
  42. package/lib/build/buildTaskProviderFactory.js +182 -0
  43. package/lib/build/constants.js +56 -0
  44. package/lib/build/index.js +21 -0
  45. package/lib/build/provider/buildTaskHandlerEdmx.js +83 -0
  46. package/lib/build/provider/buildTaskHandlerFeatureToggles.js +132 -0
  47. package/lib/build/provider/buildTaskHandlerInternal.js +228 -0
  48. package/lib/build/provider/buildTaskProviderInternal.js +370 -0
  49. package/lib/build/provider/fiori/index.js +167 -0
  50. package/lib/build/provider/hana/2migration.js +179 -0
  51. package/lib/build/provider/hana/index.js +522 -0
  52. package/lib/build/provider/hana/migrationtable.js +472 -0
  53. package/lib/build/provider/hana/template/.hdiconfig-all +163 -0
  54. package/lib/build/provider/hana/template/.hdiconfig-cloud +137 -0
  55. package/lib/build/provider/hana/template/.hdinamespace +4 -0
  56. package/lib/build/provider/hana/template/package.json +12 -0
  57. package/lib/build/provider/hana/template/undeploy.json +5 -0
  58. package/lib/build/provider/java/index.js +93 -0
  59. package/lib/build/provider/java-cf/index.js +1 -0
  60. package/lib/build/provider/mtx/index.js +37 -0
  61. package/lib/build/provider/mtx/resourcesTarBuilder.js +94 -0
  62. package/lib/build/provider/mtx-extension/index.js +131 -0
  63. package/lib/build/provider/mtx-sidecar/index.js +138 -0
  64. package/lib/build/provider/node-cf/index.js +1 -0
  65. package/lib/build/provider/nodejs/index.js +178 -0
  66. package/lib/build/util.js +263 -0
  67. package/lib/cds.js +9 -21
  68. package/lib/client/auth_manager.js +39 -16
  69. package/lib/client/helper/dependency_helper.js +7 -6
  70. package/lib/client/push.js +2 -1
  71. package/lib/client/settings_manager.js +10 -39
  72. package/lib/deploy/to-hana/hana.js +273 -0
  73. package/lib/deploy/to-hana/hdiDeployUtil.js +68 -0
  74. package/lib/deploy/to-hana/mtaUtil.js +171 -0
  75. package/lib/import/asyncapi/importAsyncAPI.js +3 -2
  76. package/lib/import/asyncapi/index.js +5 -2
  77. package/lib/import/asyncapi/parserContext.js +67 -26
  78. package/lib/import/asyncapi/utils.js +34 -3
  79. package/lib/import/common.js +40 -30
  80. package/lib/import/importapi.js +36 -35
  81. package/lib/index.js +12 -17
  82. package/lib/init/constants.js +36 -71
  83. package/lib/init/index.js +18 -52
  84. package/lib/init/template/_merging/registry-mta.js +21 -3
  85. package/lib/init/template/approuter/files/mta.yaml.hbs +29 -29
  86. package/lib/init/template/approuter/files/values.yaml.hbs +5 -5
  87. package/lib/init/template/approuter/files/xs-app.json.hbs +8 -2
  88. package/lib/init/template/approuter/index.js +7 -8
  89. package/lib/init/template/auditlog/files/mta.yaml.hbs +5 -5
  90. package/lib/init/template/auditlog/files/package.json.hbs +13 -13
  91. package/lib/init/template/auditlog/index.js +3 -3
  92. package/lib/init/template/cf-manifest/files/manifest.yml.hbs +22 -22
  93. package/lib/init/template/cf-manifest/files/services-manifest.yml.hbs +3 -3
  94. package/lib/init/template/connectivity/files/mta.yaml.hbs +14 -0
  95. package/lib/init/template/connectivity/files/package.json.hbs +17 -0
  96. package/lib/init/template/connectivity/index.js +21 -4
  97. package/lib/init/template/data/index.js +5 -1
  98. package/lib/init/template/destination/files/mta.yaml.hbs +14 -0
  99. package/lib/init/template/destination/files/package.json.hbs +17 -0
  100. package/lib/init/template/{destinations → destination}/index.js +19 -13
  101. package/lib/init/template/enterprise-messaging/files/event-mesh.json.hbs +3 -3
  102. package/lib/init/template/enterprise-messaging/files/mta.yaml.hbs +5 -5
  103. package/lib/init/template/enterprise-messaging/files/package.json.hbs +9 -9
  104. package/lib/init/template/enterprise-messaging/files/xs-security.json.hbs +19 -0
  105. package/lib/init/template/enterprise-messaging/index.js +27 -6
  106. package/lib/init/template/enterprise-messaging-shared/files/event-mesh.json.hbs +3 -3
  107. package/lib/init/template/enterprise-messaging-shared/files/mta.yaml.hbs +5 -5
  108. package/lib/init/template/enterprise-messaging-shared/files/package.json.hbs +9 -9
  109. package/lib/init/template/enterprise-messaging-shared/index.js +4 -5
  110. package/lib/init/template/extensibility/files/package.json.hbs +10 -10
  111. package/lib/init/template/extensibility/index.js +8 -9
  112. package/lib/init/template/file-based-messaging/files/package.json.hbs +9 -9
  113. package/lib/init/template/file-based-messaging/index.js +3 -4
  114. package/lib/init/template/hana/files/db/package.json +1 -1
  115. package/lib/init/template/hana/files/mta.yaml.hbs +21 -21
  116. package/lib/init/template/hana/files/package.json.hbs +16 -22
  117. package/lib/init/template/hana/files/values.yaml.hbs +1 -1
  118. package/lib/init/template/hana/index.js +5 -15
  119. package/lib/init/template/helm/files/Chart.yaml.hbs +4 -4
  120. package/lib/init/template/helm/files/values.yaml.hbs +6 -6
  121. package/lib/init/template/helm/index.js +5 -10
  122. package/lib/init/template/helm/subcharts/content-deployment/Chart.yaml +2 -0
  123. package/lib/init/template/helm/subcharts/content-deployment/templates/_helpers.tpl +37 -31
  124. package/lib/init/template/helm/subcharts/content-deployment/templates/job.yaml +13 -14
  125. package/lib/init/template/helm/subcharts/content-deployment/templates/secret.yaml +2 -2
  126. package/lib/init/template/helm/subcharts/content-deployment/templates/service-account.yaml +1 -1
  127. package/lib/init/template/helm/subcharts/content-deployment/templates/service-binding.yaml +3 -3
  128. package/lib/init/template/helm/subcharts/content-deployment/values.md +116 -116
  129. package/lib/init/template/helm/subcharts/service-instance/Chart.yaml +2 -0
  130. package/lib/init/template/helm/subcharts/service-instance/templates/_helpers.tpl +9 -9
  131. package/lib/init/template/helm/subcharts/service-instance/templates/serviceinstance.yaml +2 -2
  132. package/lib/init/template/helm/subcharts/service-instance/values.md +15 -15
  133. package/lib/init/template/helm/subcharts/web-application/Chart.yaml +2 -0
  134. package/lib/init/template/helm/subcharts/web-application/templates/NOTES.txt +15 -0
  135. package/lib/init/template/helm/subcharts/web-application/templates/_helpers.tpl +23 -23
  136. package/lib/init/template/helm/subcharts/web-application/templates/api-rule.yaml +4 -4
  137. package/lib/init/template/helm/subcharts/web-application/templates/deployment.yaml +17 -17
  138. package/lib/init/template/helm/subcharts/web-application/templates/network-policy.yaml +24 -3
  139. package/lib/init/template/helm/subcharts/web-application/templates/pod-disruption-budget.yaml +3 -3
  140. package/lib/init/template/helm/subcharts/web-application/templates/secret.yaml +2 -2
  141. package/lib/init/template/helm/subcharts/web-application/templates/service-account.yaml +1 -1
  142. package/lib/init/template/helm/subcharts/web-application/templates/service-binding.yaml +3 -3
  143. package/lib/init/template/helm/subcharts/web-application/templates/service.yaml +3 -3
  144. package/lib/init/template/helm/subcharts/web-application/values.md +141 -123
  145. package/lib/init/template/helm/subcharts/web-application/values.schema.json +7 -0
  146. package/lib/init/template/helm/subcharts/web-application/values.yaml +1 -0
  147. package/lib/init/template/html5-repo/index.js +4 -5
  148. package/lib/init/template/java/index.js +5 -5
  149. package/lib/init/template/kibana-logging/files/mta.yaml.hbs +5 -5
  150. package/lib/init/template/kibana-logging/files/package.json.hbs +9 -9
  151. package/lib/init/template/kibana-logging/index.js +3 -4
  152. package/lib/init/template/lint/index.js +3 -3
  153. package/lib/init/template/mta/files/mta.yaml.hbs +14 -14
  154. package/lib/init/template/mta/files/package.json +5 -0
  155. package/lib/init/template/mta/index.js +12 -13
  156. package/lib/init/template/mtx/index.js +2 -2
  157. package/lib/init/template/multitenancy/files/mta.yaml.hbs +29 -27
  158. package/lib/init/template/multitenancy/files/package.json.hbs +17 -14
  159. package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +7 -7
  160. package/lib/init/template/multitenancy/files/values.yaml.hbs +19 -19
  161. package/lib/init/template/multitenancy/index.js +14 -16
  162. package/lib/init/template/nodejs/files/package.json.hbs +1 -1
  163. package/lib/init/template/nodejs/index.js +5 -8
  164. package/lib/init/template/redis-messaging/files/mta.yaml.hbs +5 -5
  165. package/lib/init/template/redis-messaging/files/package.json.hbs +9 -9
  166. package/lib/init/template/redis-messaging/index.js +4 -5
  167. package/lib/init/template/sample/files/app/_i18n/i18n.properties +43 -0
  168. package/lib/init/template/sample/files/app/_i18n/i18n_de.properties +14 -0
  169. package/lib/init/template/sample/files/app/admin-books/fiori-service.cds +114 -0
  170. package/lib/init/template/sample/files/app/admin-books/webapp/Component.js +8 -0
  171. package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n.properties +11 -0
  172. package/lib/init/template/sample/files/app/admin-books/webapp/manifest.json +129 -0
  173. package/lib/init/template/sample/files/app/appconfig/fioriSandboxConfig.json +57 -0
  174. package/lib/init/template/sample/files/app/common.cds +263 -0
  175. package/lib/init/template/sample/files/app/index.html +30 -0
  176. package/lib/init/template/sample/files/app/services.cds +5 -0
  177. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +5 -0
  178. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Books.csv +6 -0
  179. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Books_texts.csv +5 -0
  180. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Genres.csv +16 -0
  181. package/lib/init/template/sample/files/db/schema.cds +31 -0
  182. package/lib/init/template/sample/files/nodejs/admin-service.js +12 -0
  183. package/lib/init/template/sample/files/nodejs/cat-service.js +26 -0
  184. package/lib/init/template/sample/files/srv/admin-service.cds +5 -0
  185. package/lib/init/template/sample/files/srv/cat-service.cds +16 -0
  186. package/lib/init/template/sample/index.js +24 -0
  187. package/lib/init/template/sample-tiny/index.js +39 -0
  188. package/lib/init/template/samples/index.js +5 -56
  189. package/lib/init/template/sqlite/files/package.json.hbs +13 -13
  190. package/lib/init/template/sqlite/index.js +2 -2
  191. package/lib/init/template/templateBase.js +24 -1
  192. package/lib/init/template/toggles/files/package.json.hbs +10 -10
  193. package/lib/init/template/toggles/index.js +3 -3
  194. package/lib/init/template/typer/files/gitignore +1 -0
  195. package/lib/init/template/typer/files/package.json +8 -0
  196. package/lib/init/template/typer/files/xsconfig.json +9 -0
  197. package/lib/init/template/typer/index.js +36 -0
  198. package/lib/init/template/xsuaa/files/mta.yaml.hbs +12 -12
  199. package/lib/init/template/xsuaa/files/package.json.hbs +13 -13
  200. package/lib/init/template/xsuaa/files/values.yaml.hbs +8 -8
  201. package/lib/init/template/xsuaa/index.js +8 -19
  202. package/lib/init/util/merge.js +73 -59
  203. package/lib/init/util/mvn.js +21 -17
  204. package/lib/init/util/projectReader.js +49 -87
  205. package/lib/init/util/xml.js +14 -23
  206. package/lib/util/cfUtil.js +366 -0
  207. package/lib/util/command.js +3 -3
  208. package/lib/util/gitUtil.js +55 -0
  209. package/lib/util/version.js +27 -0
  210. package/npm-shrinkwrap.json +339 -277
  211. package/package.json +6 -6
  212. package/CHANGELOG.md +0 -1453
  213. package/bin/build/all.js +0 -88
  214. package/bin/build/index.js +0 -82
  215. package/lib/compile/index.js +0 -14
  216. /package/lib/init/template/{samples → sample-tiny}/files/nodejs/db/data/my.bookshop-Books.csv +0 -0
  217. /package/lib/init/template/{samples → sample-tiny}/files/nodejs/db/data-model.cds +0 -0
  218. /package/lib/init/template/{samples → sample-tiny}/files/nodejs/srv/cat-service.cds.hbs +0 -0
package/bin/version.js ADDED
@@ -0,0 +1,124 @@
1
+ /* eslint-disable no-console */
2
+ const { join, resolve } = require ('path')
3
+ const { execSync } = require('child_process')
4
+ module.exports = Object.assign(list_versions, {
5
+ flags: [ '--info', '--markdown', '--all', '--npm-list', '--npm-tree', '--no-colors'],
6
+ shortcuts: [ '-i', '-m','-a', '-ls', '-ll' ],
7
+ info,
8
+ help: `
9
+ # SYNOPSIS
10
+
11
+ *cds version* <options>
12
+ *cds -v* <option>
13
+
14
+ Prints the versions of all @sap/cds packages in your package dependencies.
15
+
16
+ # OPTIONS
17
+
18
+ *-i | --info*
19
+
20
+ Prints version information in a tabular markdown format, which you
21
+ can embed into your bug reports.
22
+
23
+ *-a | --all*
24
+
25
+ Also lists sub-packages and optional dependencies.
26
+
27
+ *-ls | --npm-list* <pattern>
28
+ *-ll | --npm-tree* <pattern>
29
+
30
+ Prints an npm ls tree filtered to the specified pattern.
31
+ (default: '@sap/cds')
32
+
33
+ `})
34
+
35
+ const MISSING = '-- missing --'
36
+
37
+ function list_versions(args, options) { //NOSONAR
38
+ if (options['npm-list'] || options['npm-tree']) {
39
+ let [pattern] = args, re = pattern ? RegExp(pattern) : /@sap\/cd[rs]|@sap\/eslint-plugin-cds/
40
+ let cmd = 'npm ls --depth ' + (options['npm-tree'] ? 11 : 0)
41
+ console.log (cmd,'| grep', pattern)
42
+ return require('child_process').exec(cmd, (e,stdout)=>{
43
+ // if (e) console.error(e)
44
+ const replacement = (options['no-colors'] ? '$1 $2$3$4' : '\x1b[91m$1 \x1b[32m$2\x1b[0m\x1b[2m$3\x1b[32m$4\x1b[0m');
45
+ for (let line of stdout.split(/\n/)) if (line.match(re)) console.log(
46
+ line.replace(/(@sap[^@]*)@([\S]+)( -> [\S]+)?(deduped)?/,replacement)
47
+ )
48
+ })
49
+ }
50
+ const versions = info ()
51
+ if (options.markdown) return _markdown (versions)
52
+ if (options.info) return _markdown (versions)
53
+ const mark = options['no-colors'] ? s => s : require('../lib/util/term').info
54
+ for (let each of Object.keys(versions).sort()) console.log(`${mark(each)}: ${versions[each]}`)
55
+ }
56
+
57
+ function info() {
58
+ const cwd = process.cwd()
59
+ const npmRoot = execSync('npm root -g').toString().trim()
60
+ return {
61
+ ..._versions_from(_pkg_path('@sap/cds-dk', __dirname), '@sap/cds-dk (global)'), // ... linked in cap/dev setup
62
+ ..._versions_from(_pkg_path('@sap/cds-dk', npmRoot), '@sap/cds-dk (global)'), // ... or installed globally
63
+ ..._versions_from(_pkg_path('@sap/cds-dk', cwd)), // local dk, important for Java projects
64
+ ..._versions_from(_pkg_path('@sap/cds', __dirname)), // @sap/cds from here
65
+ ..._versions_from(cwd), // ... or from local app dependencies
66
+ ..._versions_from(_pkg_path('@sap/cds-compiler', cwd, __dirname)), // compiler is no direct dependency, so list it explicitly
67
+ 'Node.js': process.version,
68
+ 'home': require('../lib/cds').home // effective (local) cds
69
+ }
70
+ }
71
+
72
+ function _versions_from(pkg_path, pkg_label) {
73
+ let pkg; try { pkg = require(join(pkg_path, 'package.json')) } catch { return {} }
74
+ let versions = {}
75
+ if (pkg.name) versions[pkg_label || pkg.name] = pkg.version
76
+
77
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies }
78
+ for (let dep in deps) {
79
+ if (!dep.match(/@sap\/.*cds.*/) && !dep.startsWith('@cap-js/')) continue
80
+ try {
81
+ const dep_path = require.resolve(join(dep, 'package.json'), {paths:[pkg_path]})
82
+ const dep_pkg = require(dep_path)
83
+ versions[dep_pkg.name] = dep_pkg.version
84
+ } catch (e) {
85
+ if (e.code !== 'MODULE_NOT_FOUND') console.error(e)
86
+ }
87
+ }
88
+ return versions
89
+ }
90
+
91
+ function _markdown (versions) {
92
+ console.log()
93
+ const pkg = { name:'', repository:'', version:'' }; try {
94
+ Object.assign (pkg, require (resolve('package.json')))
95
+ } catch (e) {/* ignored */}
96
+ console.log ('|', pkg.name, '|', pkg.repository.url || pkg.repository, '|')
97
+ console.log ('|:---------------------- | ----------- |')
98
+ if (require('../lib').env['project-nature'] === 'nodejs') {
99
+ console.log ('|', v('Node.js'), '|')
100
+ console.log ('|', v('@sap/cds'), '|')
101
+ } else {
102
+ console.log ('|', v('CAP Java Runtime'), '|')
103
+ }
104
+ console.log ('|', v('@sap/cds-compiler'), '|')
105
+ console.log ('|', v('@sap/cds-dk'), '|')
106
+ console.log ('|', v('@sap/cds-dk (global)'), '|')
107
+ console.log ('|', v('@sap/eslint-plugin-cds'), '|')
108
+ console.log ('|', v('@sap/cds-mtxs'), '|')
109
+ function v (component) {
110
+ const version = versions [component] || MISSING
111
+ return (component + ' ').slice(0,22)
112
+ +' | '+ (version + ' ').slice(0,11)
113
+ }
114
+ console.log()
115
+ }
116
+
117
+ function _pkg_path(id, ...paths) {
118
+ try {
119
+ const pk_path = require.resolve(join(id, 'package.json'), { paths })
120
+ return resolve(pk_path, '..')
121
+ } catch (e) {
122
+ if (e.code !== 'MODULE_NOT_FOUND') throw e
123
+ }
124
+ }
package/bin/watch.js CHANGED
@@ -125,7 +125,7 @@ async function watch ([cwd], {
125
125
 
126
126
  const nodemon = require('../lib/watch/node-watch')
127
127
  const watcher = nodemon ({
128
- script:__filename, cwd, env, ext, includes, ignore,
128
+ script: resolve(__dirname,'watched'), cwd, env, ext, includes, ignore,
129
129
  delay: parseInt(process.env.CDS_WATCH_DELAY) || 200,
130
130
  options
131
131
  }).on('restart', (files)=>{
@@ -193,37 +193,3 @@ function paths (dir) {
193
193
  const parts = resolve(dir).split(sep), n = parts.length, nm = sep+'node_modules'
194
194
  return parts.map ((_,i,a)=> a.slice(0,n-i).join(sep)+nm).filter(p => fs.existsSync(p))
195
195
  }
196
-
197
- //
198
- // Child process impl launched by watch
199
- //
200
-
201
- if (!module.parent) (async()=>{ // launched by nodemon
202
- // run through cli in order to use its error handling
203
- const bootstrap = require('./cds')(...JSON.parse(process.env._args))
204
- const {cds} = global; cds.watched = true
205
-
206
- cds.once('listening', ({server}) => {
207
- process.send ({ code:'listening', port: server.address().port })
208
- })
209
-
210
- try {
211
- await bootstrap
212
- if (!cds.service.providers.length) return _no_services_found()
213
- } catch (e) { switch (e.code) {
214
- case 'NO_SERVICES_FOUND': return _no_services_found(e)
215
- case 'MODEL_NOT_FOUND': return _no_models_found(e)
216
- case 'EADDRINUSE': return process.send(e) //> tell cds watch
217
- default: if (!e.messages) { // compiler messages have been written by cli already
218
- console.error('\n❗️ ERROR on server start: ❗️\n\n', e)
219
- }
220
- }}
221
- function _no_models_found(e) { console.log (`
222
- No models found in ${cds.resolve(e.model||'*',false)}.
223
- Waiting for some to arrive...
224
- `)}
225
- function _no_services_found() { console.log (`
226
- No service definitions found in loaded models.
227
- Waiting for some to arrive...
228
- `)}
229
- })()
package/bin/watched.js ADDED
@@ -0,0 +1,39 @@
1
+ //
2
+ // Child process impl launched by cds watch
3
+ // Extracted from watch.js to avoid cds.env loaded too eagerly
4
+ //
5
+
6
+ (async()=>{
7
+
8
+ // run through cli in order to use its error handling
9
+ const args = JSON.parse(process.env._args)
10
+ const bootstrap = require('./cds')(...args)
11
+ const {cds} = global; cds.watched = true
12
+
13
+ cds.once('listening', ({server}) => {
14
+ process.send ({ code:'listening', port: server.address().port })
15
+ })
16
+
17
+ try {
18
+ await bootstrap
19
+ if (!cds.service.providers.length) return _no_services_found()
20
+ } catch (e) { switch (e.code) {
21
+ case 'NO_SERVICES_FOUND': return _no_services_found(e)
22
+ case 'MODEL_NOT_FOUND': return _no_models_found(e)
23
+ case 'EADDRINUSE': return process.send(e) //> tell cds watch
24
+ default: if (!e.messages) { // compiler messages have been written by cli already
25
+ console.error('\n❗️ ERROR on server start: ❗️\n\n', e)
26
+ }
27
+ }}
28
+
29
+ function _no_models_found(e) { console.log (`
30
+ No models found in ${cds.resolve(e.model||'*',false)}.
31
+ Waiting for some to arrive...
32
+ `)}
33
+
34
+ function _no_services_found() { console.log (`
35
+ No service definitions found in loaded models.
36
+ Waiting for some to arrive...
37
+ `)}
38
+
39
+ })()
@@ -1,4 +1,4 @@
1
- const yaml = require("@sap/cds-foss")("yaml");
1
+ const yaml = require('@sap/cds-foss')('yaml');
2
2
  const { exec } = require('../util/exec');
3
3
 
4
4
  class KubernetesApiAccessor {
@@ -9,7 +9,7 @@ class KubernetesApiAccessor {
9
9
  const configString = await exec({result: 'stdout'}) `kubectl config view --raw`;
10
10
  const config = yaml.parse(configString);
11
11
 
12
- const currentContextName = config["current-context"];
12
+ const currentContextName = config['current-context'];
13
13
  if (!currentContextName) throw new Error(`No current context in kubectl config.`);
14
14
  const currentContextEntry = config.contexts && config.contexts.find( entry => entry.name === currentContextName && entry.context && entry.context.cluster && entry.context.user );
15
15
  if (!currentContextEntry) throw new Error(`Current context not found in kubectl config.`);
@@ -83,7 +83,7 @@ class BindingManager {
83
83
  }
84
84
 
85
85
  return services
86
- }
86
+ }
87
87
  }
88
88
 
89
89
  module.exports = BindingManager
@@ -1,5 +1,3 @@
1
- const os = require('os');
2
- const IS_WIN = os.platform() === 'win32';
3
1
 
4
2
  const KindToRequiresNameMap = {
5
3
  xsuaa: 'auth',
@@ -89,13 +87,6 @@ class BindingUtil {
89
87
  }
90
88
  }
91
89
 
92
- static execAndExit(options, command, ...args) {
93
- const { spawnSync } = require('child_process');
94
- // use shell with Windows only; without output is not visible and some commands cannot be run
95
- const result = spawnSync(command, args, { stdio: 'inherit', shell: IS_WIN, ...options });
96
- process.exit(result.status);
97
- }
98
-
99
90
  static async checkIsJavaProject(projectPath) {
100
91
  const { constants, promises: fsp } = require('fs');
101
92
  const path = require('path');
@@ -1,89 +1,32 @@
1
- const cp = require('child_process');
2
- const fsp = require('fs').promises;
3
- const os = require('os');
4
- const util = require('util');
5
-
6
1
  const cds = require('../cds');
7
2
  const DEBUG = cds.debug('cli')
8
3
 
4
+ const cfUtil = require('../util/cfUtil');
5
+
9
6
  const axios = require('axios');
10
7
  const { URL } = require('url');
11
- const path = require('path');
12
8
  const { bold, highlight } = require('../util/term');
13
9
  const { CliError } = require('../client/helper/errors');
14
10
 
15
- const execAsync = util.promisify(cp.exec);
16
- const IS_WIN = os.platform() === 'win32';
17
-
18
11
  class CFKeyProvider {
19
- async _cfRead(...args) {
20
- DEBUG?.(`_cfRead: cf ${args}`);
21
-
22
- const result = await execAsync(`cf ${args}`, {
23
- shell: IS_WIN,
24
- stdio: ['inherit', 'pipe', 'inherit'],
25
- });
26
-
27
- return result.stdout.toString().trim();
28
- }
29
-
30
- extract(string, pattern, errorMsg) {
31
- const match = string.match(pattern);
32
- if (!match || !match[1]) {
33
- throw new Error(errorMsg);
34
- }
35
- return match[1];
36
- }
37
-
38
- async getCfTargetFromConfigFile() {
39
- const cfHome = process.env.CF_HOME || process.env.cf_home || path.join(os.homedir(), '.cf');
40
- try {
41
- const fileContent = await fsp.readFile(path.join(cfHome, 'config.json'));
42
- const config = JSON.parse(fileContent);
43
- if (config) {
44
- return {
45
- apiEndpoint: this.extract(config.Target, /\s*(.+)\s*/, `CF API endpoint is missing. Use 'cf login' to login.`),
46
- org: this.extract(config.OrganizationFields.Name, /\s*(.+)\s*/, `CF org is missing. Use 'cf target -o <ORG> to specify.`),
47
- space: this.extract(config.SpaceFields.Name, /\s*(.+)\s*/, `CF space is missing. Use 'cf target -s <SPACE>' to specify.`)
48
- }
49
- }
50
- } catch (err) {
51
- DEBUG?.(`getCfTargetFromConfigFile: ${err}`);
52
- }
53
- }
54
-
55
- async getCfTargetFromCli() {
56
- const result = await this._cfRead('target');
57
- return {
58
- apiEndpoint: this.extract(result, /api endpoint\s*:\s*([^\s]+)/i, `CF API endpoint is missing. Use 'cf login' to login.`),
59
- user: this.extract(result, /user\s*:\s*(.+)/i, `CF user is missing. Use 'cf login' to login.`),
60
- org: this.extract(result, /org\s*:\s*(.+)/i, `CF org is missing. Use 'cf target -o <ORG> to specify.`),
61
- space: this.extract(result, /space\s*:\s*(.+)/i, `CF space is missing. Use 'cf target -s <SPACE>' to specify.`),
62
- };
63
- }
64
-
65
- async getCfTarget() {
66
- return await this.getCfTargetFromConfigFile() || await this.getCfTargetFromCli();
67
- }
68
-
69
12
  async getCfSpaceInfo() {
70
13
  DEBUG?.('getting space info');
71
14
 
72
- const target = await this.getCfTarget();
73
- const authorization = await this.getCfAuthorization();
15
+ const target = await cfUtil.getCfTarget();
16
+ const authorization = await cfUtil.getCfAuthorization();
74
17
  const targetWithAuth = Object.assign({}, target, { authorization });
75
18
 
76
19
 
77
20
  const { org, space } = target;
78
21
  const orgs = await BatchRequest.req(targetWithAuth, `/v3/organizations?names=${encodeURIComponent(encodeURIComponent(org))}`);
79
22
  if (!(orgs && orgs.resources.length === 1)) {
80
- throw new Error(`CF org ${org} not found!`);
23
+ throw new CliError(`CF org ${org} not found!`);
81
24
  }
82
25
 
83
26
  const orgGuid = orgs.resources[0].guid;
84
27
  const spaces = await BatchRequest.req(targetWithAuth, `/v3/spaces?names=${encodeURIComponent(encodeURIComponent(space))}&organization_guids=${encodeURIComponent(encodeURIComponent(orgGuid))}`)
85
28
  if (!(spaces && spaces.resources.length === 1)) {
86
- throw new Error(`CF space ${space} not found in org ${org}!`);
29
+ throw new CliError(`CF space ${space} not found in org ${org}!`);
87
30
  }
88
31
 
89
32
  const spaceGuid = spaces.resources[0].guid;
@@ -91,11 +34,6 @@ class CFKeyProvider {
91
34
  return Object.assign({}, target, { orgGuid, spaceGuid, authorization });
92
35
  }
93
36
 
94
- async getCfAuthorization() {
95
- DEBUG?.('getting authorization');
96
- return this._cfRead('oauth-token');
97
- }
98
-
99
37
  async init() {
100
38
  const target = this.target = await this.getCfSpaceInfo();
101
39
  this.getOrg = BatchRequest.create({ target, url: '/v3/organizations' });
@@ -142,7 +80,7 @@ class CFKeyProvider {
142
80
  try {
143
81
  instanceObj = await this.getInstance({ names: instance, space_guids: spaceGuid });
144
82
  } catch (error) {
145
- throw new Error(`Service instance "${instance}" not found.`);
83
+ throw new CliError(`Service instance "${instance}" not found.`);
146
84
  }
147
85
  switch (instanceObj.type) {
148
86
  case 'managed':
@@ -150,7 +88,7 @@ class CFKeyProvider {
150
88
  case 'user-provided':
151
89
  return this._resolveUserProvidedService(instanceObj, instance, org, space);
152
90
  default:
153
- throw new Error(`Service type ${instanceObj.type} not supported`)
91
+ throw new CliError(`Service type ${instanceObj.type} not supported`)
154
92
  }
155
93
  }
156
94
 
@@ -285,9 +223,9 @@ class BatchRequest {
285
223
  if (filteredResources.length === 1) {
286
224
  filter.resolve(filteredResources[0]);
287
225
  } else if (filteredResources.length === 0) {
288
- filter.reject(new Error(`Couldn't find resource for url "${this.url}" with filter "${fmt(filter.filter)}"`));
226
+ filter.reject(new CliError(`Couldn't find resource for url "${this.url}" with filter "${fmt(filter.filter)}"`));
289
227
  } else {
290
- filter.reject(new Error(`Found more than one resources for url "${this.url}" with filter "${fmt(filter.filter)}"`));
228
+ filter.reject(new CliError(`Found more than one resources for url "${this.url}" with filter "${fmt(filter.filter)}"`));
291
229
  }
292
230
  }
293
231
  }
@@ -0,0 +1,114 @@
1
+ const cds = require('../cds');
2
+
3
+ const { CliError } = require('../client/helper/errors');
4
+
5
+ const BindingResolver = require('./bindingResolver');
6
+ const { determineKinds, getRequiresNameFromKind, checkIsJavaProject, platformText, bindingText, logger } = require('./bindingUtil');
7
+ const { highlight, bold, info } = require('../util/term');
8
+
9
+
10
+ module.exports = { bind, parseProfile }
11
+
12
+ /**
13
+ * Executes cds build in the directory defined by cds.root.
14
+ *
15
+ * @param {object} options - command options as defined by build command.
16
+ */
17
+ async function bind(options) {
18
+ let on;
19
+ switch(options.on) {
20
+ case 'k8s':
21
+ case 'kubernetes':
22
+ on = 'k8s';
23
+ break;
24
+ case undefined:
25
+ case null:
26
+ case 'cf':
27
+ case 'cloudfoundry':
28
+ on = 'cf';
29
+ break;
30
+ default:
31
+ throw new CliError(`Invalid value '${options.on}' for option --on.`);
32
+ }
33
+
34
+ const onText = { 'cf': 'Cloud Foundry', 'k8s': 'Kubernetes' }[on];
35
+ logger.log(`Retrieving data from ${onText}...`);
36
+ let resolvedServices
37
+
38
+ const targets = options.to.split(/,/g);
39
+ try {
40
+ resolvedServices = await Promise.all(targets.map(async target => {
41
+ let binding;
42
+ if (on === 'k8s') {
43
+ binding = { type: on, name: target };
44
+ } else if (on === 'cf') {
45
+ const [instance, key] = target.split(/:/);
46
+ binding = { type: on, instance, key };
47
+ } else {
48
+ throw new Error('Internal Error');
49
+ }
50
+ const resolvedService = await BindingResolver.resolveBinding(undefined, binding);
51
+ resolvedService._target = target;
52
+ delete resolvedService.credentials;
53
+ resolvedService.binding.resolved = false;
54
+ return resolvedService;
55
+ }));
56
+ } catch (error) {
57
+ if (error.name === 'AxiosError') {
58
+ const errors = error.response?.data?.errors ?? []
59
+ const responseInfo = errors.map(e => `${e.title}: ${e.detail} (${e.code})`).join(' \n')
60
+ const requestInfo = error.request?.path
61
+ throw new Error(`${error.toString()}\nResponse: ${responseInfo}\nRequest:${requestInfo}}`)
62
+ }
63
+ throw error
64
+ }
65
+
66
+ if (options.kind) {
67
+ resolvedServices.forEach(service => service.kind = options.kind);
68
+ } else {
69
+ determineKinds(resolvedServices);
70
+ }
71
+
72
+ for (const resolvedService of resolvedServices) {
73
+ if (options.serviceArg) {
74
+ resolvedService.name = options.serviceArg;
75
+ } else if (resolvedService.kind) {
76
+ resolvedService.name = getRequiresNameFromKind(resolvedService.binding.instance, resolvedService.kind);
77
+ }
78
+
79
+ let { kind, name, binding } = resolvedService;
80
+ name = name ?? `custom-service:${binding.instance || binding.secret}`
81
+ resolvedService.name = resolvedService.name ?? name
82
+ const kindText = kind ? ` with kind ${highlight(kind)}` : ''
83
+ const nameText = highlight(name)
84
+
85
+ logger.log(`Binding ${nameText} to ${platformText(binding)} ${bindingText(binding, highlight)}${kindText}`);
86
+ }
87
+
88
+ // prepare for different providers
89
+ const userCdsrcJsonStorageProvider = require('./userCdsrcJsonStorageProvider');
90
+
91
+ await userCdsrcJsonStorageProvider.storeServices(resolvedServices, {
92
+ ...options
93
+ });
94
+
95
+ const isJavaProject = await checkIsJavaProject(cds.root);
96
+ logger.log(`${info('TIP:')} Run with cloud bindings: ${bold(runCmd(options.for, isJavaProject))}`);
97
+ }
98
+
99
+ function runCmd(profile, isJavaProject) {
100
+ profile = parseProfile(profile);
101
+ if (isJavaProject) {
102
+ const p = profile === 'hybrid' ? '' : ` --profile ${profile}`;
103
+ return `cds bind exec${p} mvn spring-boot:run`;
104
+ } else {
105
+ const p = profile === 'development' ? '' : ` --profile ${profile}`;
106
+ return `cds watch${p}`;
107
+ }
108
+ }
109
+
110
+ function parseProfile(profile) {
111
+ if (!profile) return 'hybrid';
112
+ else if (profile === '-') return 'development';
113
+ else return profile;
114
+ }
@@ -44,7 +44,7 @@ class KubernetesCredentialsProvider {
44
44
 
45
45
  const resolvedBinding = {
46
46
  binding: {
47
- type: "k8s",
47
+ type: 'k8s',
48
48
  name: bindingName,
49
49
  cluster,
50
50
  instance,
@@ -63,7 +63,7 @@ class KubernetesCredentialsProvider {
63
63
  const { data } = secret;
64
64
  const properties = {};
65
65
  for (const name in data) {
66
- const value = Buffer.from(data[name], "base64").toString()
66
+ const value = Buffer.from(data[name], 'base64').toString()
67
67
  properties[name] = value;
68
68
  }
69
69
 
@@ -2,17 +2,13 @@ const os = require('os');
2
2
  const path = require('path');
3
3
  const readline = require('readline');
4
4
 
5
- const cds = require('../cds');
6
- const DEBUG = cds.debug('cli');
7
-
8
5
  const fs = require('fs').promises;
9
6
  const { highlight } = require('../util/term');
10
7
  const { logger } = require('./bindingUtil');
11
8
 
12
- const commandUtil = require('../util/command');
9
+ const gitUtil = require('../util/gitUtil');
13
10
 
14
11
  const CDSRC_FILENAME = '.cdsrc-private.json';
15
- const GIT_IGNORE_FILE = '.gitignore';
16
12
 
17
13
  class UserCdsrcJsonStorageProvider {
18
14
  async askBooleanQuestion(question) {
@@ -34,44 +30,11 @@ class UserCdsrcJsonStorageProvider {
34
30
  });
35
31
  }
36
32
 
37
- async ensureFileIsGitignored(file) {
38
- try {
39
- await commandUtil.spawnCommand('git', ['check-ignore', '-n', '-v', file], {}, undefined, true);
40
- return; // file is git ignored
41
- } catch (err) {
42
- if (err.code === 'ENOENT') { // git command not found
43
- DEBUG?.('git command not found');
44
- return;
45
- }
46
-
47
- if (!err.stdLog.match(/::/)) { // included or not a git repo
48
- DEBUG?.(err);
49
- return;
50
- }
51
- }
52
-
53
- logger.log(`adding entry '${file}' to ${GIT_IGNORE_FILE}.`);
54
- let gitignore = await this.readFileSafely(GIT_IGNORE_FILE);
55
- gitignore = gitignore + `
56
- # added by cds bind
57
- ${file}
58
- `;
59
- await fs.writeFile(GIT_IGNORE_FILE, gitignore, 'utf8');
60
- }
61
-
62
- async readFileSafely(file) {
63
- try {
64
- return await fs.readFile(file, 'utf8');
65
- } catch (err) {
66
- return '';
67
- }
68
- }
69
-
70
33
  async storeServices(services, options = {}) {
71
- let jsonPath = options['output-file'] || CDSRC_FILENAME;
34
+ let jsonPath = options.outputFile || CDSRC_FILENAME;
72
35
 
73
36
  if (jsonPath === CDSRC_FILENAME) {
74
- await this.ensureFileIsGitignored(CDSRC_FILENAME);
37
+ await gitUtil.ensureFileIsGitignored(CDSRC_FILENAME);
75
38
  }
76
39
 
77
40
  jsonPath = jsonPath.replace(/~/g, os.homedir());
@@ -89,13 +52,13 @@ ${file}
89
52
  cdsRoot = jsonObject;
90
53
  }
91
54
 
92
- const profileKey = `[${options.profile}]`;
55
+ const profileKey = `[${options.for}]`;
93
56
  const features = cdsRoot.features && cdsRoot.features[profileKey];
94
57
  if (features) delete features.emulate_vcap_services;
95
58
 
96
59
  cdsRoot.requires = cdsRoot.requires || {};
97
60
  let section;
98
- if (options.profile) {
61
+ if (options.for) {
99
62
  section = cdsRoot.requires[profileKey] = cdsRoot.requires[profileKey] || {};
100
63
  } else {
101
64
  section = cdsRoot.requires;
@@ -109,8 +72,8 @@ ${file}
109
72
  }
110
73
 
111
74
  await this.writeJsonFile(jsonPath, jsonObject);
112
- if (options.profile) {
113
- logger.log(`Saving bindings to ${highlight(jsonPath)} in profile ${highlight(options.profile)}`);
75
+ if (options.for) {
76
+ logger.log(`Saving bindings to ${highlight(jsonPath)} in profile ${highlight(options.for)}`);
114
77
  } else {
115
78
  logger.log(`Saving bindings to ${highlight(jsonPath)}`);
116
79
  }