@wwkit/shared 1.0.15 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/shell.js +47 -10
package/package.json
CHANGED
package/src/shell.js
CHANGED
|
@@ -214,6 +214,12 @@ export class Shell {
|
|
|
214
214
|
/**
|
|
215
215
|
* 向指定 profile 文件写入/更新一个环境变量标记块
|
|
216
216
|
*
|
|
217
|
+
* 写入前先清理文件中所有同名的裸 export/set 行(非标记块内的),
|
|
218
|
+
* 避免裸行与标记块并存导致残留误导。
|
|
219
|
+
* 标记块用单行注释头(无尾标记),形如:
|
|
220
|
+
* # >>> wwkit NAME >>>
|
|
221
|
+
* export NAME="value"
|
|
222
|
+
*
|
|
217
223
|
* @param {string} profilePath - profile 文件绝对路径
|
|
218
224
|
* @param {string} name - 环境变量名(用于生成标记)
|
|
219
225
|
* @param {string} line - 变量设置行(含正确语法)
|
|
@@ -225,28 +231,59 @@ export class Shell {
|
|
|
225
231
|
existing = fs.readFileSync(profilePath, 'utf8')
|
|
226
232
|
} catch {}
|
|
227
233
|
|
|
228
|
-
|
|
229
|
-
const
|
|
230
|
-
|
|
234
|
+
const marker = `# >>> wwkit ${name} >>>`
|
|
235
|
+
const oldEndMarker = `# <<< wwkit ${name} <<<`
|
|
236
|
+
|
|
237
|
+
// 清理同名裸 export/set 行(不在任何标记块内的)
|
|
238
|
+
existing = this._stripBareEnvLines(existing, name)
|
|
231
239
|
|
|
232
|
-
const beginIdx = existing.indexOf(
|
|
240
|
+
const beginIdx = existing.indexOf(marker)
|
|
233
241
|
if (beginIdx !== -1) {
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
242
|
+
const afterMarker = beginIdx + marker.length
|
|
243
|
+
// 块尾:优先找旧版 end marker,其次找下一个 wwkit marker,最后 EOF
|
|
244
|
+
const oldEndIdx = existing.indexOf(oldEndMarker, afterMarker)
|
|
245
|
+
const nextMarkerIdx = existing.indexOf('# >>> wwkit', afterMarker)
|
|
246
|
+
let blockEnd
|
|
247
|
+
if (oldEndIdx !== -1 && (nextMarkerIdx === -1 || oldEndIdx < nextMarkerIdx)) {
|
|
248
|
+
blockEnd = oldEndIdx + oldEndMarker.length
|
|
249
|
+
} else if (nextMarkerIdx !== -1) {
|
|
250
|
+
blockEnd = nextMarkerIdx
|
|
251
|
+
} else {
|
|
252
|
+
blockEnd = existing.length
|
|
237
253
|
}
|
|
238
|
-
const
|
|
239
|
-
|
|
254
|
+
const currentBlock = existing.slice(beginIdx, blockEnd)
|
|
255
|
+
const newBlock = `${marker}\n${line}`
|
|
256
|
+
if (currentBlock.trim() === newBlock.trim()) return false
|
|
257
|
+
existing = existing.slice(0, beginIdx) + newBlock + existing.slice(blockEnd)
|
|
240
258
|
fs.writeFileSync(profilePath, existing, 'utf8')
|
|
241
259
|
return true
|
|
242
260
|
}
|
|
243
261
|
|
|
244
262
|
const dir = path.dirname(profilePath)
|
|
245
263
|
fs.mkdirSync(dir, { recursive: true })
|
|
246
|
-
fs.appendFileSync(profilePath, `\n${
|
|
264
|
+
fs.appendFileSync(profilePath, `\n${marker}\n${line}\n`, 'utf8')
|
|
247
265
|
return true
|
|
248
266
|
}
|
|
249
267
|
|
|
268
|
+
/**
|
|
269
|
+
* 从 profile 内容中删除所有同名的裸 export/set 行(不在标记块内的)
|
|
270
|
+
* @param {string} content
|
|
271
|
+
* @param {string} name
|
|
272
|
+
* @returns {string}
|
|
273
|
+
* @private
|
|
274
|
+
*/
|
|
275
|
+
_stripBareEnvLines(content, name) {
|
|
276
|
+
const lines = content.split('\n')
|
|
277
|
+
const barePattern = new RegExp(`^\\s*(export|set -gx)\\s+${name}\\b`)
|
|
278
|
+
let inBlock = false
|
|
279
|
+
return lines.filter((l) => {
|
|
280
|
+
if (l.startsWith('# >>> wwkit ')) { inBlock = true; return true }
|
|
281
|
+
if (l.startsWith('# <<< wwkit ')) { inBlock = false; return true }
|
|
282
|
+
if (inBlock) return true
|
|
283
|
+
return !barePattern.test(l)
|
|
284
|
+
}).join('\n')
|
|
285
|
+
}
|
|
286
|
+
|
|
250
287
|
/**
|
|
251
288
|
* 检测系统命令是否可用
|
|
252
289
|
* Windows: where <cmd>;Unix: which <cmd>
|