t32-stage-own-hunks.mjs 4.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. import { spawnSync } from 'node:child_process'
  2. import { readFileSync } from 'node:fs'
  3. function git(args,input) {
  4. const out=spawnSync('git',args,{input,encoding:'utf8'})
  5. if(out.status!==0) throw new Error(out.stderr)
  6. return out.stdout
  7. }
  8. function replaceOnce(text,oldValue,newValue) {
  9. if(text.split(oldValue).length!==2) throw new Error('Expected exactly one stage anchor: '+oldValue.slice(0,70))
  10. return text.replace(oldValue,newValue)
  11. }
  12. const head=git(['rev-parse','HEAD']).trim()
  13. const paths=['src/modules/cockpit/services/cesiumPipeLayer.js','src/modules/cockpit/services/mapService.js','src/modules/cockpit/components/MapInfoPanel.vue']
  14. for(const path of paths) {
  15. let staged=git(['show',`${head}:${path}`])
  16. const current=readFileSync(path,'utf8').replace(/\r\n/g,'\n')
  17. if(path.endsWith('cesiumPipeLayer.js')) {
  18. const commentStart=' * 渲染口径'
  19. const a=staged.indexOf(commentStart),b=staged.indexOf('\n */',a)
  20. const c=current.indexOf(commentStart),d=current.indexOf('\n */',c)
  21. staged=staged.slice(0,a)+current.slice(c,d)+staged.slice(b)
  22. const constants=current.slice(current.indexOf('// Viewer-scoped'),current.indexOf('/** 与 `cesiumEngine'))
  23. staged=replaceOnce(staged,'/** 与 `cesiumEngine',constants+'/** 与 `cesiumEngine')
  24. staged=replaceOnce(staged,'export async function syncPipeLayer(viewer, network) {','export async function syncPipeLayer(viewer, network, { onModelChange = () => {} } = {}) {')
  25. const versions=' const version = (layerVersions.get(viewer) || 0) + 1\n layerVersions.set(viewer, version)\n'
  26. staged=replaceOnce(staged,' clearIndex(viewer)\n',versions+' clearIndex(viewer)\n')
  27. staged=replaceOnce(staged,' const source = await ensureSource(viewer)\n',' const source = await ensureSource(viewer)\n if (layerVersions.get(viewer) !== version) return { pipes: 0, components: 0, rendered: false }\n')
  28. const models=current.slice(current.indexOf(' // Keep fallback entities'),current.indexOf(' return { pipes: pipes.length',current.indexOf(' // Keep fallback entities')))
  29. staged=replaceOnce(staged,' return { pipes: pipes.length, components: components.length, rendered: true }',models+' return { pipes: pipes.length, components: components.length, rendered: true }')
  30. const cleanup=current.slice(current.indexOf(' if (viewer) layerVersions'),current.indexOf(' const source = viewer &&'))
  31. staged=replaceOnce(staged,' const source = viewer &&',cleanup+' const source = viewer &&')
  32. } else if(path.endsWith('mapService.js')) {
  33. staged=replaceOnce(staged,' if (record.viewer) {\n record.engine.destroyViewer(record.viewer)',' if (record.viewer) {\n if (record.pipeLayer) record.pipeLayer.clearPipeLayer(record.viewer)\n record.engine.destroyViewer(record.viewer)')
  34. const old=" const engine = await import('./cesiumPipeLayer.js')\n await engine.syncPipeLayer(instance.viewer, layer)\n const host = instance.host"
  35. const start=current.indexOf(' const record = instance\n const engine = await import(\'./cesiumPipeLayer.js\')')
  36. const end=current.indexOf(' const host = record.host\n if (host',start)+' const host = record.host'.length
  37. if(start<0||end<start) throw new Error('Missing service stage block')
  38. staged=replaceOnce(staged,old,current.slice(start,end))
  39. } else {
  40. const noteStart=current.indexOf(' <p class="map-info__note" data-pipe-model-note>')
  41. const noteEnd=current.indexOf(' <!-- 坐标准入',noteStart)
  42. staged=replaceOnce(staged,' <!-- 坐标准入',current.slice(noteStart,noteEnd)+' <!-- 坐标准入')
  43. const script=current.slice(current.indexOf("import { PIPE_MODEL_NOTE }"),current.indexOf('defineProps({'))
  44. staged=replaceOnce(staged,'defineProps({',script+'defineProps({')
  45. staged=replaceOnce(staged,' if (host) {\n observer',' if (host) {\n modelHost = host\n host.addEventListener(\'cockpit-pipe-model-state\', updatePipeModelState)\n observer')
  46. staged=replaceOnce(staged,'onBeforeUnmount(() => {\n if (observer)','onBeforeUnmount(() => {\n if (modelHost) modelHost.removeEventListener(\'cockpit-pipe-model-state\', updatePipeModelState)\n modelHost = null\n if (observer)')
  47. }
  48. if(git(['rev-parse','HEAD']).trim()!==head) throw new Error('HEAD changed during staging')
  49. const hash=git(['hash-object','-w','--stdin'],staged).trim()
  50. git(['update-index','--cacheinfo',`100644,${hash},${path}`])
  51. }
  52. console.log('Staged only ticket32 text replacements against fixed HEAD; working tree preserved')