@multiplatform.one/cli 7.10.0 → 7.15.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 (163) hide show
  1. package/README.md +121 -111
  2. package/bin/createMultiplatformApp.mjs +39 -37
  3. package/lib/bin/multiplatformOne.mjs +65 -75
  4. package/lib/commands/addApp.mjs +78 -0
  5. package/lib/commands/adoptApp.mjs +11 -7
  6. package/lib/commands/doctypeTypes.mjs +148 -0
  7. package/lib/commands/e2e.mjs +2 -2
  8. package/lib/commands/init.mjs +142 -459
  9. package/lib/commands/merge.mjs +359 -0
  10. package/lib/commands/pieces.mjs +236 -0
  11. package/lib/commands/provenance.mjs +108 -0
  12. package/lib/commands/scaffold.mjs +105 -0
  13. package/lib/commands/updateApp.mjs +211 -528
  14. package/lib/source.json +5 -0
  15. package/lib/source.mjs +63 -0
  16. package/package.json +7 -7
  17. package/scripts/frappe-bootstrap.sh +29 -3
  18. package/scripts/frappe-dev.sh +1 -2
  19. package/scripts/frappe-helpers.sh +50 -2
  20. package/scripts/frappe.sh +5 -0
  21. package/scripts/scaffold.sh +937 -0
  22. package/scripts/stamp-source.mjs +51 -0
  23. package/scripts/stamp-source.spec.ts +86 -0
  24. package/src/bin/multiplatformOne.ts +116 -226
  25. package/src/commands/addApp.ts +102 -0
  26. package/src/commands/adoptApp.spec.ts +5 -1
  27. package/src/commands/adoptApp.ts +15 -10
  28. package/src/commands/doctypeTypes.spec.ts +155 -0
  29. package/src/commands/doctypeTypes.ts +214 -0
  30. package/src/commands/init.spec.ts +66 -0
  31. package/src/commands/init.ts +201 -643
  32. package/src/commands/merge.spec.ts +81 -0
  33. package/src/commands/merge.ts +411 -0
  34. package/src/commands/pieces.spec.ts +62 -0
  35. package/src/commands/pieces.ts +340 -0
  36. package/src/commands/provenance.spec.ts +92 -0
  37. package/src/commands/provenance.ts +169 -0
  38. package/src/commands/scaffold.ts +131 -0
  39. package/src/commands/updateApp.spec.ts +540 -331
  40. package/src/commands/updateApp.ts +255 -668
  41. package/src/source.spec.ts +45 -0
  42. package/src/source.ts +88 -0
  43. package/templates/AGENTS.md +161 -0
  44. package/templates/README.md +62 -0
  45. package/templates/pieces/frappe/universal/README.md.partial +7 -32
  46. package/templates/pieces/frappe/universal/env.example.partial +3 -3
  47. package/templates/pieces/frappe-bench/universal/README.md.partial +28 -0
  48. package/templates/pieces/{frappe → frappe-bench}/universal/docker/compose.frappe.yaml +2 -2
  49. package/templates/pieces/tauri/universal/README.md.partial +7 -5
  50. package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/dev.rs +463 -0
  51. package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/src/lib.rs +6 -0
  52. package/templates/pieces/tauri/universal/apps/__NAME__/src-tauri/tauri.conf.json +2 -1
  53. package/templates/pieces/webext/universal/apps/__NAME__/package.json.partial +1 -0
  54. package/templates/pieces/webext/universal/apps/__NAME__/vite.config.webext.ts +6 -2
  55. package/types/bin/multiplatformOne.d.ts.map +1 -1
  56. package/types/commands/addApp.d.ts +20 -0
  57. package/types/commands/addApp.d.ts.map +1 -0
  58. package/types/commands/adoptApp.d.ts +4 -3
  59. package/types/commands/adoptApp.d.ts.map +1 -1
  60. package/types/commands/doctypeTypes.d.ts +40 -0
  61. package/types/commands/doctypeTypes.d.ts.map +1 -0
  62. package/types/commands/init.d.ts +30 -13
  63. package/types/commands/init.d.ts.map +1 -1
  64. package/types/commands/merge.d.ts +54 -0
  65. package/types/commands/merge.d.ts.map +1 -0
  66. package/types/commands/pieces.d.ts +54 -0
  67. package/types/commands/pieces.d.ts.map +1 -0
  68. package/types/commands/provenance.d.ts +52 -0
  69. package/types/commands/provenance.d.ts.map +1 -0
  70. package/types/commands/scaffold.d.ts +43 -0
  71. package/types/commands/scaffold.d.ts.map +1 -0
  72. package/types/commands/updateApp.d.ts +19 -27
  73. package/types/commands/updateApp.d.ts.map +1 -1
  74. package/types/source.d.ts +35 -0
  75. package/types/source.d.ts.map +1 -0
  76. package/lib/commands/initApp.mjs +0 -431
  77. package/lib/generateVscode.mjs +0 -184
  78. package/scripts/clone.sh +0 -17
  79. package/scripts/update.sh +0 -46
  80. package/src/commands/initApp.spec.ts +0 -720
  81. package/src/commands/initApp.ts +0 -706
  82. package/src/generateVscode.ts +0 -238
  83. package/templates/app/AGENTS.md +0 -142
  84. package/templates/app/README.md +0 -62
  85. package/templates/app/apps/__NAME__/index.html +0 -36
  86. package/templates/app/apps/__NAME__/package.json +0 -31
  87. package/templates/app/apps/__NAME__/public/fonts/inter-400.woff2 +0 -0
  88. package/templates/app/apps/__NAME__/public/fonts/inter-700.woff2 +0 -0
  89. package/templates/app/apps/__NAME__/src/App.tsx +0 -9
  90. package/templates/app/apps/__NAME__/src/main.tsx +0 -14
  91. package/templates/app/apps/__NAME__/tsconfig.json +0 -8
  92. package/templates/app/apps/__NAME__/vite.config.ts +0 -17
  93. package/templates/app/features/__NAME__/package.json +0 -34
  94. package/templates/app/features/__NAME__/src/HomeScreen.tsx +0 -70
  95. package/templates/app/features/__NAME__/src/index.ts +0 -1
  96. package/templates/app/features/__NAME__/tsconfig.json +0 -5
  97. package/templates/app/gitignore +0 -9
  98. package/templates/app/npmrc +0 -2
  99. package/templates/app/oxlintrc.json +0 -39
  100. package/templates/app/package.json +0 -38
  101. package/templates/app/packages/config/config.json +0 -4
  102. package/templates/app/packages/config/index.ts +0 -5
  103. package/templates/app/packages/config/package.json +0 -17
  104. package/templates/app/packages/config/tsconfig.json +0 -5
  105. package/templates/app/pnpm-workspace.yaml +0 -4
  106. package/templates/app/tsconfig.base.json +0 -16
  107. package/templates/universal/AGENTS.md +0 -142
  108. package/templates/universal/README.md +0 -97
  109. package/templates/universal/apps/__NAME__/app.config.js +0 -31
  110. package/templates/universal/apps/__NAME__/config/tamagui.config.ts +0 -4
  111. package/templates/universal/apps/__NAME__/package.json +0 -62
  112. package/templates/universal/apps/__NAME__/polyfills.native.ts +0 -23
  113. package/templates/universal/apps/__NAME__/polyfills.ts +0 -3
  114. package/templates/universal/apps/__NAME__/public/fonts/inter-400.woff2 +0 -0
  115. package/templates/universal/apps/__NAME__/public/fonts/inter-700.woff2 +0 -0
  116. package/templates/universal/apps/__NAME__/routes/_layout.tsx +0 -22
  117. package/templates/universal/apps/__NAME__/routes/_layout.web.tsx +0 -21
  118. package/templates/universal/apps/__NAME__/routes/about.tsx +0 -3
  119. package/templates/universal/apps/__NAME__/routes/index.tsx +0 -3
  120. package/templates/universal/apps/__NAME__/src/app.ts +0 -10
  121. package/templates/universal/apps/__NAME__/tamagui.css +0 -3
  122. package/templates/universal/apps/__NAME__/tsconfig.json +0 -8
  123. package/templates/universal/apps/__NAME__/types.d.ts +0 -9
  124. package/templates/universal/apps/__NAME__/vite.config.ts +0 -20
  125. package/templates/universal/features/__NAME__/package.json +0 -35
  126. package/templates/universal/features/__NAME__/src/AboutScreen.tsx +0 -27
  127. package/templates/universal/features/__NAME__/src/AppLayout.tsx +0 -50
  128. package/templates/universal/features/__NAME__/src/ContactForm.spec.tsx +0 -22
  129. package/templates/universal/features/__NAME__/src/ContactForm.tsx +0 -55
  130. package/templates/universal/features/__NAME__/src/HomeScreen.tsx +0 -40
  131. package/templates/universal/features/__NAME__/src/index.ts +0 -4
  132. package/templates/universal/features/__NAME__/src/screens.spec.ts +0 -12
  133. package/templates/universal/features/__NAME__/tsconfig.json +0 -5
  134. package/templates/universal/features/__NAME__/vitest.config.mjs +0 -7
  135. package/templates/universal/gitignore +0 -14
  136. package/templates/universal/npmrc +0 -3
  137. package/templates/universal/oxlintrc.json +0 -39
  138. package/templates/universal/package.json +0 -51
  139. package/templates/universal/packages/config/config.json +0 -4
  140. package/templates/universal/packages/config/index.ts +0 -5
  141. package/templates/universal/packages/config/package.json +0 -17
  142. package/templates/universal/packages/config/tsconfig.json +0 -5
  143. package/templates/universal/packages/i18n/en/common.json +0 -30
  144. package/templates/universal/packages/i18n/es/common.json +0 -30
  145. package/templates/universal/packages/i18n/i18n.d.ts +0 -16
  146. package/templates/universal/packages/i18n/index.ts +0 -26
  147. package/templates/universal/packages/i18n/package.json +0 -20
  148. package/templates/universal/packages/i18n/resources.ts +0 -13
  149. package/templates/universal/packages/i18n/tsconfig.json +0 -5
  150. package/templates/universal/packages/themes/accent.ts +0 -32
  151. package/templates/universal/packages/themes/base.ts +0 -50
  152. package/templates/universal/packages/themes/fonts.ts +0 -8
  153. package/templates/universal/packages/themes/index.ts +0 -33
  154. package/templates/universal/packages/themes/package.json +0 -23
  155. package/templates/universal/packages/themes/tamagui.config.ts +0 -14
  156. package/templates/universal/packages/themes/tsconfig.json +0 -5
  157. package/templates/universal/pnpm-workspace.yaml +0 -4
  158. package/templates/universal/tsconfig.base.json +0 -21
  159. package/templates/universal/types/env.d.ts +0 -9
  160. package/types/commands/initApp.d.ts +0 -114
  161. package/types/commands/initApp.d.ts.map +0 -1
  162. package/types/generateVscode.d.ts +0 -7
  163. package/types/generateVscode.d.ts.map +0 -1
@@ -0,0 +1,5 @@
1
+ {
2
+ "cliVersion": "7.15.0",
3
+ "url": "https://git.corp.bitspur.com/multiplatform.one/mpo.git",
4
+ "sha": "ea0fe3578a58e4c3d40cc1feb878f8cecce9cb3a"
5
+ }
package/lib/source.mjs ADDED
@@ -0,0 +1,63 @@
1
+ import { cliRoot, cliVersion } from "./commands/provenance.mjs";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { join, resolve } from "node:path";
4
+
5
+ //#region src/source.ts
6
+ const monorepoUrl = "https://git.corp.bitspur.com/multiplatform.one/mpo.git";
7
+ function isGitUrl(source) {
8
+ return /^(https?|ssh|git|file):\/\//.test(source) || /^[\w.-]+@[\w.-]+:/.test(source);
9
+ }
10
+ /** The monorepo checkout this CLI runs from, if any (src via tsx, or the workspace link). */
11
+ function monorepoCheckout() {
12
+ const root = resolve(cliRoot(), "../..");
13
+ if (existsSync(join(root, "apps/one/package.json")) && existsSync(join(root, "public/cli/package.json"))) return root;
14
+ }
15
+ function readSourceStamp() {
16
+ try {
17
+ return JSON.parse(readFileSync(join(cliRoot(), "lib/source.json"), "utf-8"));
18
+ } catch {
19
+ return;
20
+ }
21
+ }
22
+ /**
23
+ * Where `mpo init` clones from. Flags win; a CLI running inside the monorepo
24
+ * uses that checkout's HEAD; a published CLI uses the commit stamped at build
25
+ * time; a build without a stamp falls back to the release tag of its own
26
+ * version, and `init` retries `main` when that tag is missing.
27
+ */
28
+ function resolveSource(flags = {}) {
29
+ if (flags.source) return {
30
+ source: flags.source,
31
+ ref: flags.checkout ?? (isGitUrl(flags.source) ? "main" : "HEAD"),
32
+ origin: "flag"
33
+ };
34
+ const checkout = monorepoCheckout();
35
+ if (checkout) return {
36
+ source: checkout,
37
+ ref: flags.checkout ?? "HEAD",
38
+ origin: "monorepo"
39
+ };
40
+ const stamp = readSourceStamp();
41
+ const url = stamp?.url ?? "https://git.corp.bitspur.com/multiplatform.one/mpo.git";
42
+ if (flags.checkout) return {
43
+ source: url,
44
+ ref: flags.checkout,
45
+ origin: "flag"
46
+ };
47
+ if (stamp?.sha) return {
48
+ source: url,
49
+ ref: stamp.sha,
50
+ origin: "stamp"
51
+ };
52
+ const version = cliVersion();
53
+ const ref = version ? `v${version}` : "main";
54
+ return {
55
+ source: url,
56
+ ref,
57
+ origin: "tag",
58
+ warning: `this build of @multiplatform.one/cli carries no source commit (lib/source.json); scaffolding from ${ref} instead`
59
+ };
60
+ }
61
+
62
+ //#endregion
63
+ export { isGitUrl, monorepoCheckout, monorepoUrl, readSourceStamp, resolveSource };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@multiplatform.one/cli",
3
- "version": "7.10.0",
4
- "description": "multiplatform.one cli — mpo init / create-multiplatform-app",
3
+ "version": "7.15.0",
4
+ "description": "multiplatform.one cli — mpo init clones and prunes the monorepo, mpo update merges it back",
5
5
  "keywords": [
6
6
  "create-multiplatform-app",
7
7
  "mpo",
@@ -9,7 +9,7 @@
9
9
  "scaffold"
10
10
  ],
11
11
  "bugs": {
12
- "url": "https://gitlab.com/bitspur/multiplatform.one/multiplatform.one/issues"
12
+ "url": "https://projects.corp.bitspur.com/tracker/MPO"
13
13
  },
14
14
  "license": "Apache-2.0",
15
15
  "author": "BitSpur <support@bitspur.com> (https://bitspur.com)",
@@ -21,7 +21,7 @@
21
21
  ],
22
22
  "repository": {
23
23
  "type": "git",
24
- "url": "git+https://gitlab.com/bitspur/frappe/multiplatform.one.git",
24
+ "url": "git+https://git.corp.bitspur.com/multiplatform.one/mpo.git",
25
25
  "directory": "public/cli"
26
26
  },
27
27
  "bin": {
@@ -56,12 +56,12 @@
56
56
  "access": "public"
57
57
  },
58
58
  "dependencies": {
59
+ "@multiplatform.one/utils": "7.15.0",
59
60
  "commander": "^14.0.3",
60
61
  "inquirer": "^13.4.2",
61
62
  "nano-spawn": "^2.1.0",
62
63
  "yaml": "^2.8.3",
63
- "yocto-spinner": "^1.1.0",
64
- "@multiplatform.one/utils": "7.10.0"
64
+ "yocto-spinner": "^1.1.0"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@types/inquirer": "^9.0.9",
@@ -73,7 +73,7 @@
73
73
  "node": ">= 16.0"
74
74
  },
75
75
  "scripts": {
76
- "build": "rm -rf lib types 2>/dev/null && tsc -p tsconfig.build.json && tsdown",
76
+ "build": "rm -rf lib types 2>/dev/null && tsc -p tsconfig.build.json && tsdown && node scripts/stamp-source.mjs",
77
77
  "test": "vitest run",
78
78
  "typecheck": "tsgo --noEmit"
79
79
  }
@@ -1,6 +1,28 @@
1
1
  #!/bin/sh
2
+ # Every checkout of this repo shares one dev mariadb/postgres, so each checkout
3
+ # gets its own database. FRAPPE_DB_NAME wins when set; otherwise the db_name the
4
+ # site's site_config.json already holds (the main checkout keeps its frappe);
5
+ # otherwise frappe_<dir>_<hash of the checkout path>. Bootstrap drops only a
6
+ # database its own site_config.json names, or one with no tables, and refuses
7
+ # otherwise.
2
8
  set -e
3
9
 
10
+ _db_table_count() {
11
+ if [ "$FRAPPE_DB_TYPE" = "postgres" ]; then
12
+ _exists="$(PGPASSWORD="$FRAPPE_DB_PASSWORD" psql -h "$FRAPPE_DB_HOST" -p "$FRAPPE_DB_PORT" -U "$FRAPPE_DB_USER" -d postgres -tAc \
13
+ "SELECT 1 FROM pg_database WHERE datname = '$1'")" || return 1
14
+ if [ -z "$_exists" ]; then
15
+ echo 0
16
+ return 0
17
+ fi
18
+ PGPASSWORD="$FRAPPE_DB_PASSWORD" psql -h "$FRAPPE_DB_HOST" -p "$FRAPPE_DB_PORT" -U "$FRAPPE_DB_USER" -d "$1" -tAc \
19
+ "SELECT count(*) FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog', 'information_schema')"
20
+ else
21
+ _mysql -h "$FRAPPE_DB_HOST" -P "$FRAPPE_DB_PORT" -u "$FRAPPE_DB_USER" -p"$FRAPPE_DB_PASSWORD" -N -B -e \
22
+ "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = '$1'"
23
+ fi
24
+ }
25
+
4
26
  _mysql() {
5
27
  if command -v mysql >/dev/null 2>&1; then
6
28
  mysql "$@"
@@ -271,7 +293,6 @@ FRAPPE_DB_HOST="${FRAPPE_DB_HOST:-$([ "$FRAPPE_DB_TYPE" = "postgres" ] && echo "
271
293
  if [ "$FRAPPE_DB_HOST" = "localhost" ]; then
272
294
  FRAPPE_DB_HOST="127.0.0.1"
273
295
  fi
274
- FRAPPE_DB_NAME="${FRAPPE_DB_NAME:-frappe}"
275
296
  FRAPPE_DB_PASSWORD="${FRAPPE_DB_PASSWORD:-$([ "$FRAPPE_DB_TYPE" = "postgres" ] && echo "$POSTGRES_PASSWORD" || echo "${MARIADB_PASSWORD:-${MYSQL_PASSWORD:-root}}")}"
276
297
  FRAPPE_DB_PORT="${FRAPPE_DB_PORT:-$([ "$FRAPPE_DB_TYPE" = "postgres" ] && echo "$POSTGRES_PORT" || echo "${MARIADB_PORT:-${MYSQL_PORT:-3306}}")}"
277
298
  FRAPPE_DB_TYPE="${FRAPPE_DB_TYPE:-mariadb}"
@@ -281,6 +302,8 @@ FRAPPE_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/frappe"
281
302
  REDIS_CACHE_URI="${REDIS_CACHE_URI:-redis://localhost:6379}"
282
303
  REDIS_QUEUE_URI="${REDIS_QUEUE_URI:-redis://localhost:6380}"
283
304
  SITE_NAME="${SITE_NAME:-$(echo "$FRAPPE_BASE_URL" | sed 's|^https*://||' | sed 's|:[0-9]*.*||' | sed 's|/.*||')}"
305
+ FRAPPE_DB_NAME="$(frappe_resolve_db_name "${FRAPPE_DB_NAME:-}" "$BENCH_DIR/sites/$SITE_NAME/site_config.json" "$ROOTDIR")"
306
+ echo "dev database $FRAPPE_DB_NAME"
284
307
  bench() {
285
308
  uv tool run --from frappe-bench bench "$@"
286
309
  }
@@ -361,6 +384,8 @@ if [ -f "$BENCH_DIR/sites/$SITE_NAME/site_config.json" ]; then
361
384
  fi
362
385
  fi
363
386
  if [ ! -f "$BENCH_DIR/sites/$SITE_NAME/site_config.json" ] || [ "$_DB_INITIALIZED" = "0" ]; then
387
+ _TABLES="$(_db_table_count "$FRAPPE_DB_NAME")" || _TABLES=""
388
+ frappe_db_may_drop "$FRAPPE_DB_NAME" "$BENCH_DIR/sites/$SITE_NAME/site_config.json" "$_TABLES" || exit 1
364
389
  if [ "$FRAPPE_DB_TYPE" = "postgres" ]; then
365
390
  PGPASSWORD="$FRAPPE_DB_PASSWORD" psql -h "$FRAPPE_DB_HOST" -p "$FRAPPE_DB_PORT" -U "$FRAPPE_DB_USER" -c \
366
391
  "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$FRAPPE_DB_NAME';"
@@ -452,8 +477,9 @@ fi
452
477
  if [ -n "${ONE_PORT:-}" ] && [ "$(echo "$SITE_CONFIG" | jq -r '.one_dev_proxy_target // ""')" != "http://localhost:${ONE_PORT}" ]; then
453
478
  bench --site "$SITE_NAME" set-config one_dev_proxy_target "http://localhost:${ONE_PORT}"
454
479
  fi
455
- if [ -n "${KEYCLOAK_PORT:-}" ] && [ "$(echo "$SITE_CONFIG" | jq -r '.keycloak_dev_proxy_target // ""')" != "http://localhost:${KEYCLOAK_PORT}" ]; then
456
- bench --site "$SITE_NAME" set-config keycloak_dev_proxy_target "http://localhost:${KEYCLOAK_PORT}"
480
+ frappe_site_config_drop "$BENCH_DIR/sites/$SITE_NAME/site_config.json" keycloak_dev_proxy_target
481
+ if [ -n "${KEYCLOAK_PORT:-}" ] && [ "$(echo "$SITE_CONFIG" | jq -r '.one_dev_proxy_keycloak_target // ""')" != "http://localhost:${KEYCLOAK_PORT}/auth" ]; then
482
+ bench --site "$SITE_NAME" set-config one_dev_proxy_keycloak_target "http://localhost:${KEYCLOAK_PORT}/auth"
457
483
  fi
458
484
  bench migrate
459
485
  # Mark the Frappe setup wizard complete so freshly bootstrapped sites skip it.
@@ -37,5 +37,4 @@ _sed "s|[^ ]*/node |$(command -v node) |g" "$BENCH_DIR/Procfile"
37
37
  _sed "s| bench | uv tool run --from frappe-bench bench |g" "$BENCH_DIR/Procfile"
38
38
  _sed "s|: *bench |: uv tool run --from frappe-bench bench |g" "$BENCH_DIR/Procfile"
39
39
  _sed "s|uv tool run --from frappe-bench bench serve.*--port [0-9][0-9]*|uv tool run --from frappe-bench bench serve --port ${FRAPPE_PORT:-8000}|g" "$BENCH_DIR/Procfile"
40
- command -v honcho >/dev/null 2>&1 || uv pip install honcho
41
- exec honcho start "$@"
40
+ exec uv tool run honcho start "$@"
@@ -87,8 +87,56 @@ frappe_remove_non_keep_apps() {
87
87
  [ -d "$_d" ] || continue
88
88
  _name="$(basename "$_d")"
89
89
  case "$FRAPPE_KEEP_APPS" in
90
- *" $_name "*) ;;
91
- *) rm -rf "$_d" ;;
90
+ *" $_name "*) continue ;;
92
91
  esac
92
+ # An app the repo tracks is source, not a derived copy, whether or not
93
+ # frappe.yaml lists it yet.
94
+ if [ -n "$(git -C "$BENCH_DIR" ls-files -- "apps/$_name" 2>/dev/null | head -n 1)" ]; then
95
+ continue
96
+ fi
97
+ rm -rf "$_d"
93
98
  done
94
99
  }
100
+
101
+ frappe_site_config_drop() {
102
+ _file="$1"
103
+ _key="$2"
104
+ [ -f "$_file" ] || return 0
105
+ _has="$(jq --arg k "$_key" 'has($k)' "$_file")" || return 1
106
+ [ "$_has" = "true" ] || return 0
107
+ jq --arg k "$_key" 'del(.[$k])' "$_file" > "$_file.tmp" && mv "$_file.tmp" "$_file"
108
+ }
109
+
110
+ frappe_checkout_db_name() {
111
+ _root="$(cd "$1" && pwd -P)" || return 1
112
+ _slug="$(printf '%s' "${_root##*/}" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9' '_' | cut -c1-16)"
113
+ _sum="$(printf '%s' "$_root" | sha256sum | cut -c1-8)"
114
+ printf 'frappe_%s_%s\n' "$_slug" "$_sum"
115
+ }
116
+
117
+ frappe_resolve_db_name() {
118
+ if [ -n "$1" ]; then
119
+ printf '%s\n' "$1"
120
+ return 0
121
+ fi
122
+ if [ -f "$2" ]; then
123
+ _name="$(jq -r '.db_name // ""' "$2")" || return 1
124
+ if [ -n "$_name" ]; then
125
+ printf '%s\n' "$_name"
126
+ return 0
127
+ fi
128
+ fi
129
+ frappe_checkout_db_name "$3"
130
+ }
131
+
132
+ frappe_db_may_drop() {
133
+ _db="$1"
134
+ _cfg="$2"
135
+ _tables="$3"
136
+ if [ -f "$_cfg" ] && [ "$(jq -r '.db_name // ""' "$_cfg")" = "$_db" ]; then
137
+ return 0
138
+ fi
139
+ [ "$_tables" = "0" ] && return 0
140
+ echo "refusing to drop database $_db: $_cfg does not name it and it is not empty (tables: ${_tables:-unknown}), so another checkout may own it. Set FRAPPE_DB_NAME in .env to a new name, or drop $_db yourself if it is yours." >&2
141
+ return 1
142
+ }
package/scripts/frappe.sh CHANGED
@@ -3,6 +3,11 @@ set -e
3
3
 
4
4
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
5
 
6
+ # bench build runs yarn 1 inside the bench, and yarn 1 reads this repo's .npmrc
7
+ # and aborts on an unset ${NPM_AUTH_TOKEN} (pnpm only warns). The bench never
8
+ # fetches from the private registry, so an empty value is enough.
9
+ export NPM_AUTH_TOKEN="${NPM_AUTH_TOKEN-}"
10
+
6
11
  usage() {
7
12
  cat <<'EOF'
8
13
  Usage: frappe.sh <command> [options]