@platforma-sdk/package-builder-lib 1.1.0 → 1.2.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 (99) hide show
  1. package/dist/core/archive.cjs +3 -3
  2. package/dist/core/archive.cjs.map +1 -1
  3. package/dist/core/archive.js.map +1 -1
  4. package/dist/core/conda/builder.cjs +9 -4
  5. package/dist/core/conda/builder.cjs.map +1 -1
  6. package/dist/core/conda/builder.js +5 -1
  7. package/dist/core/conda/builder.js.map +1 -1
  8. package/dist/core/conda/validate-spec.cjs +2 -2
  9. package/dist/core/conda/validate-spec.cjs.map +1 -1
  10. package/dist/core/conda/validate-spec.js.map +1 -1
  11. package/dist/core/core.cjs +29 -8
  12. package/dist/core/core.cjs.map +1 -1
  13. package/dist/core/core.d.ts +6 -1
  14. package/dist/core/core.d.ts.map +1 -1
  15. package/dist/core/core.js +27 -6
  16. package/dist/core/core.js.map +1 -1
  17. package/dist/core/docker-conda.cjs +2 -2
  18. package/dist/core/docker-conda.cjs.map +1 -1
  19. package/dist/core/docker-conda.js.map +1 -1
  20. package/dist/core/docker-python.cjs +3 -2
  21. package/dist/core/docker-python.cjs.map +1 -1
  22. package/dist/core/docker-python.js +1 -1
  23. package/dist/core/docker-python.js.map +1 -1
  24. package/dist/core/docker.cjs +3 -3
  25. package/dist/core/docker.cjs.map +1 -1
  26. package/dist/core/docker.js.map +1 -1
  27. package/dist/core/envs.cjs +34 -0
  28. package/dist/core/envs.cjs.map +1 -1
  29. package/dist/core/envs.d.ts +8 -2
  30. package/dist/core/envs.d.ts.map +1 -1
  31. package/dist/core/envs.js +13 -1
  32. package/dist/core/envs.js.map +1 -1
  33. package/dist/core/package-info.cjs +59 -5
  34. package/dist/core/package-info.cjs.map +1 -1
  35. package/dist/core/package-info.d.ts +11 -2
  36. package/dist/core/package-info.d.ts.map +1 -1
  37. package/dist/core/package-info.js +60 -6
  38. package/dist/core/package-info.js.map +1 -1
  39. package/dist/core/paths.cjs +1 -1
  40. package/dist/core/paths.cjs.map +1 -1
  41. package/dist/core/paths.js +1 -1
  42. package/dist/core/paths.js.map +1 -1
  43. package/dist/core/resolver.cjs +7 -2
  44. package/dist/core/resolver.cjs.map +1 -1
  45. package/dist/core/resolver.js +1 -1
  46. package/dist/core/resolver.js.map +1 -1
  47. package/dist/core/schemas/artifacts.cjs +7 -1
  48. package/dist/core/schemas/artifacts.cjs.map +1 -1
  49. package/dist/core/schemas/artifacts.d.ts +1 -1
  50. package/dist/core/schemas/artifacts.d.ts.map +1 -1
  51. package/dist/core/schemas/artifacts.js +1 -1
  52. package/dist/core/schemas/artifacts.js.map +1 -1
  53. package/dist/core/schemas/entrypoints.cjs +4 -1
  54. package/dist/core/schemas/entrypoints.cjs.map +1 -1
  55. package/dist/core/schemas/entrypoints.d.ts +1 -1
  56. package/dist/core/schemas/entrypoints.d.ts.map +1 -1
  57. package/dist/core/schemas/entrypoints.js +1 -1
  58. package/dist/core/schemas/entrypoints.js.map +1 -1
  59. package/dist/core/schemas/sw-json.cjs +16 -1
  60. package/dist/core/schemas/sw-json.cjs.map +1 -1
  61. package/dist/core/schemas/sw-json.js +1 -1
  62. package/dist/core/schemas/sw-json.js.map +1 -1
  63. package/dist/core/storage.cjs +6 -2
  64. package/dist/core/storage.cjs.map +1 -1
  65. package/dist/core/storage.js +4 -1
  66. package/dist/core/storage.js.map +1 -1
  67. package/dist/core/sw-json-render.cjs +38 -7
  68. package/dist/core/sw-json-render.cjs.map +1 -1
  69. package/dist/core/sw-json-render.js +37 -8
  70. package/dist/core/sw-json-render.js.map +1 -1
  71. package/dist/core/util.cjs +33 -12
  72. package/dist/core/util.cjs.map +1 -1
  73. package/dist/core/util.d.ts +12 -7
  74. package/dist/core/util.d.ts.map +1 -1
  75. package/dist/core/util.js +17 -8
  76. package/dist/core/util.js.map +1 -1
  77. package/dist/defaults.cjs +18 -1
  78. package/dist/defaults.cjs.map +1 -1
  79. package/dist/defaults.d.ts +9 -3
  80. package/dist/defaults.d.ts.map +1 -1
  81. package/dist/defaults.js +13 -2
  82. package/dist/defaults.js.map +1 -1
  83. package/dist/index.cjs.map +1 -1
  84. package/dist/index.d.ts +4 -2
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js.map +1 -1
  87. package/package.json +3 -3
  88. package/src/core/core.test.ts +17 -0
  89. package/src/core/core.ts +48 -8
  90. package/src/core/envs.ts +8 -0
  91. package/src/core/package-info.test.ts +162 -3
  92. package/src/core/package-info.ts +88 -3
  93. package/src/core/schemas/test-artifacts.ts +1 -1
  94. package/src/core/sw-json-render.test.ts +23 -0
  95. package/src/core/sw-json-render.ts +30 -2
  96. package/src/core/util.test.ts +52 -0
  97. package/src/core/util.ts +27 -7
  98. package/src/defaults.ts +19 -1
  99. package/src/index.ts +4 -0
@@ -1,12 +1,12 @@
1
1
  const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
2
  const require_util = require("./util.cjs");
3
3
  let node_fs = require("node:fs");
4
- node_fs = require_runtime.__toESM(node_fs);
4
+ node_fs = require_runtime.__toESM(node_fs, 1);
5
5
  let node_path = require("node:path");
6
- node_path = require_runtime.__toESM(node_path);
6
+ node_path = require_runtime.__toESM(node_path, 1);
7
7
  let node_crypto = require("node:crypto");
8
8
  let archiver = require("archiver");
9
- archiver = require_runtime.__toESM(archiver);
9
+ archiver = require_runtime.__toESM(archiver, 1);
10
10
  //#region src/core/archive.ts
11
11
  function getPath(options) {
12
12
  const packageName = options.packageName.replaceAll("/", "-").replaceAll("\\", "-");
@@ -1 +1 @@
1
- {"version":3,"file":"archive.cjs","names":["path","fs"],"sources":["../../src/core/archive.ts"],"sourcesContent":["import archiver from \"archiver\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type * as winston from \"winston\";\nimport * as util from \"./util\";\nimport type { Hash } from \"node:crypto\";\nimport { createHash } from \"node:crypto\";\n\nconst tarArchiveType = \"tgz\";\nconst zipArchiveType = \"zip\";\nexport const allArchiveTypes = [tarArchiveType, zipArchiveType];\nexport type archiveType = (typeof allArchiveTypes)[number];\n\nexport type archiveOptions = {\n packageRoot: string;\n packageName: string;\n packageVersion: string;\n\n crossplatform: boolean;\n os: util.OSType;\n arch: util.ArchType;\n ext: archiveType;\n};\n\nexport function getPath(options: archiveOptions): string {\n const packageName = options.packageName.replaceAll(\"/\", \"-\").replaceAll(\"\\\\\", \"-\");\n\n if (options && !options.crossplatform) {\n return path.resolve(\n options.packageRoot,\n `pkg-${packageName}-${options.packageVersion}-${options.os}-${options.arch}.${options.ext}`,\n );\n }\n\n return path.resolve(\n options.packageRoot,\n `pkg-${packageName}-${options.packageVersion}.${options.ext}`,\n );\n}\n\nexport async function create(\n logger: winston.Logger,\n contentRoot: string,\n dstArchivePath: string,\n hasher?: Hash,\n): Promise<Hash> {\n const compressionLevel = 9;\n\n let format = \"\";\n if (dstArchivePath.endsWith(\".tgz\") || dstArchivePath.endsWith(\".tar.gz\")) {\n format = \"tar\";\n }\n if (dstArchivePath.endsWith(\".zip\")) {\n format = \"zip\";\n }\n\n if (format == \"\") {\n throw util.CLIError(\n `Archive ${dstArchivePath} has unsupported extension. Cannot create archive of unknown format`,\n );\n }\n\n const output = fs.createWriteStream(dstArchivePath);\n const hash = hasher ? hasher : createHash(\"sha256\");\n\n const a = archiver.create(format, {\n gzip: true,\n gzipOptions: { level: compressionLevel },\n zlib: { level: compressionLevel },\n });\n\n return new Promise((resolve, reject) => {\n // Waits for the output stream to be closed.\n output.on(\"close\", function () {\n logger.debug(`archive created. Total data processed: ${a.pointer()} bytes`);\n resolve(hash);\n });\n\n output.on(\"error\", function (err) {\n reject(err);\n });\n\n // Catch errors\n a.on(\"error\", function (err) {\n reject(err);\n });\n\n // Update hash with every chunk of data written to the archive\n a.on(\"data\", function (chunk) {\n hash.update(chunk);\n });\n\n // Pipe archive data to the file\n a.pipe(output);\n\n // Append files from sourceDir without prefix\n a.directory(contentRoot, false);\n\n // Finalize the archive (i.e. we are done appending files but streams have to finish yet)\n a.finalize().catch(reject);\n });\n}\n"],"mappings":";;;;;;;;;;AAwBA,SAAgB,QAAQ,SAAiC;CACvD,MAAM,cAAc,QAAQ,YAAY,WAAW,KAAK,IAAI,CAAC,WAAW,MAAM,IAAI;AAElF,KAAI,WAAW,CAAC,QAAQ,cACtB,QAAOA,UAAAA,QAAK,QACV,QAAQ,aACR,OAAO,YAAY,GAAG,QAAQ,eAAe,GAAG,QAAQ,GAAG,GAAG,QAAQ,KAAK,GAAG,QAAQ,MACvF;AAGH,QAAOA,UAAAA,QAAK,QACV,QAAQ,aACR,OAAO,YAAY,GAAG,QAAQ,eAAe,GAAG,QAAQ,MACzD;;AAGH,eAAsB,OACpB,QACA,aACA,gBACA,QACe;CACf,MAAM,mBAAmB;CAEzB,IAAI,SAAS;AACb,KAAI,eAAe,SAAS,OAAO,IAAI,eAAe,SAAS,UAAU,CACvE,UAAS;AAEX,KAAI,eAAe,SAAS,OAAO,CACjC,UAAS;AAGX,KAAI,UAAU,GACZ,OAAA,aAAA,SACE,WAAW,eAAe,qEAC3B;CAGH,MAAM,SAASC,QAAAA,QAAG,kBAAkB,eAAe;CACnD,MAAM,OAAO,SAAS,UAAA,GAAA,YAAA,YAAoB,SAAS;CAEnD,MAAM,IAAI,SAAA,QAAS,OAAO,QAAQ;EAChC,MAAM;EACN,aAAa,EAAE,OAAO,kBAAkB;EACxC,MAAM,EAAE,OAAO,kBAAkB;EAClC,CAAC;AAEF,QAAO,IAAI,SAAS,SAAS,WAAW;AAEtC,SAAO,GAAG,SAAS,WAAY;AAC7B,UAAO,MAAM,0CAA0C,EAAE,SAAS,CAAC,QAAQ;AAC3E,WAAQ,KAAK;IACb;AAEF,SAAO,GAAG,SAAS,SAAU,KAAK;AAChC,UAAO,IAAI;IACX;AAGF,IAAE,GAAG,SAAS,SAAU,KAAK;AAC3B,UAAO,IAAI;IACX;AAGF,IAAE,GAAG,QAAQ,SAAU,OAAO;AAC5B,QAAK,OAAO,MAAM;IAClB;AAGF,IAAE,KAAK,OAAO;AAGd,IAAE,UAAU,aAAa,MAAM;AAG/B,IAAE,UAAU,CAAC,MAAM,OAAO;GAC1B"}
1
+ {"version":3,"file":"archive.cjs","names":["path","fs"],"sources":["../../src/core/archive.ts"],"sourcesContent":["import archiver from \"archiver\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type * as winston from \"winston\";\nimport * as util from \"./util\";\nimport type { Hash } from \"node:crypto\";\nimport { createHash } from \"node:crypto\";\n\nconst tarArchiveType = \"tgz\";\nconst zipArchiveType = \"zip\";\nexport const allArchiveTypes = [tarArchiveType, zipArchiveType];\nexport type archiveType = (typeof allArchiveTypes)[number];\n\nexport type archiveOptions = {\n packageRoot: string;\n packageName: string;\n packageVersion: string;\n\n crossplatform: boolean;\n os: util.OSType;\n arch: util.ArchType;\n ext: archiveType;\n};\n\nexport function getPath(options: archiveOptions): string {\n const packageName = options.packageName.replaceAll(\"/\", \"-\").replaceAll(\"\\\\\", \"-\");\n\n if (options && !options.crossplatform) {\n return path.resolve(\n options.packageRoot,\n `pkg-${packageName}-${options.packageVersion}-${options.os}-${options.arch}.${options.ext}`,\n );\n }\n\n return path.resolve(\n options.packageRoot,\n `pkg-${packageName}-${options.packageVersion}.${options.ext}`,\n );\n}\n\nexport async function create(\n logger: winston.Logger,\n contentRoot: string,\n dstArchivePath: string,\n hasher?: Hash,\n): Promise<Hash> {\n const compressionLevel = 9;\n\n let format = \"\";\n if (dstArchivePath.endsWith(\".tgz\") || dstArchivePath.endsWith(\".tar.gz\")) {\n format = \"tar\";\n }\n if (dstArchivePath.endsWith(\".zip\")) {\n format = \"zip\";\n }\n\n if (format == \"\") {\n throw util.CLIError(\n `Archive ${dstArchivePath} has unsupported extension. Cannot create archive of unknown format`,\n );\n }\n\n const output = fs.createWriteStream(dstArchivePath);\n const hash = hasher ? hasher : createHash(\"sha256\");\n\n const a = archiver.create(format, {\n gzip: true,\n gzipOptions: { level: compressionLevel },\n zlib: { level: compressionLevel },\n });\n\n return new Promise((resolve, reject) => {\n // Waits for the output stream to be closed.\n output.on(\"close\", function () {\n logger.debug(`archive created. Total data processed: ${a.pointer()} bytes`);\n resolve(hash);\n });\n\n output.on(\"error\", function (err) {\n reject(err);\n });\n\n // Catch errors\n a.on(\"error\", function (err) {\n reject(err);\n });\n\n // Update hash with every chunk of data written to the archive\n a.on(\"data\", function (chunk) {\n hash.update(chunk);\n });\n\n // Pipe archive data to the file\n a.pipe(output);\n\n // Append files from sourceDir without prefix\n a.directory(contentRoot, false);\n\n // Finalize the archive (i.e. we are done appending files but streams have to finish yet)\n a.finalize().catch(reject);\n });\n}\n"],"mappings":";;;;;;;;;;AAwBA,SAAgB,QAAQ,SAAiC;CACvD,MAAM,cAAc,QAAQ,YAAY,WAAW,KAAK,GAAG,CAAC,CAAC,WAAW,MAAM,GAAG;CAEjF,IAAI,WAAW,CAAC,QAAQ,eACtB,OAAOA,UAAAA,QAAK,QACV,QAAQ,aACR,OAAO,YAAY,GAAG,QAAQ,eAAe,GAAG,QAAQ,GAAG,GAAG,QAAQ,KAAK,GAAG,QAAQ,KACxF;CAGF,OAAOA,UAAAA,QAAK,QACV,QAAQ,aACR,OAAO,YAAY,GAAG,QAAQ,eAAe,GAAG,QAAQ,KAC1D;AACF;AAEA,eAAsB,OACpB,QACA,aACA,gBACA,QACe;CACf,MAAM,mBAAmB;CAEzB,IAAI,SAAS;CACb,IAAI,eAAe,SAAS,MAAM,KAAK,eAAe,SAAS,SAAS,GACtE,SAAS;CAEX,IAAI,eAAe,SAAS,MAAM,GAChC,SAAS;CAGX,IAAI,UAAU,IACZ,MAAA,aAAA,SACE,WAAW,eAAe,oEAC5B;CAGF,MAAM,SAASC,QAAAA,QAAG,kBAAkB,cAAc;CAClD,MAAM,OAAO,SAAS,UAAA,GAAA,YAAA,WAAA,CAAoB,QAAQ;CAElD,MAAM,IAAI,SAAA,QAAS,OAAO,QAAQ;EAChC,MAAM;EACN,aAAa,EAAE,OAAO,iBAAiB;EACvC,MAAM,EAAE,OAAO,iBAAiB;CAClC,CAAC;CAED,OAAO,IAAI,SAAS,SAAS,WAAW;EAEtC,OAAO,GAAG,SAAS,WAAY;GAC7B,OAAO,MAAM,0CAA0C,EAAE,QAAQ,EAAE,OAAO;GAC1E,QAAQ,IAAI;EACd,CAAC;EAED,OAAO,GAAG,SAAS,SAAU,KAAK;GAChC,OAAO,GAAG;EACZ,CAAC;EAGD,EAAE,GAAG,SAAS,SAAU,KAAK;GAC3B,OAAO,GAAG;EACZ,CAAC;EAGD,EAAE,GAAG,QAAQ,SAAU,OAAO;GAC5B,KAAK,OAAO,KAAK;EACnB,CAAC;EAGD,EAAE,KAAK,MAAM;EAGb,EAAE,UAAU,aAAa,KAAK;EAG9B,EAAE,SAAS,CAAC,CAAC,MAAM,MAAM;CAC3B,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"archive.js","names":["util.CLIError"],"sources":["../../src/core/archive.ts"],"sourcesContent":["import archiver from \"archiver\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type * as winston from \"winston\";\nimport * as util from \"./util\";\nimport type { Hash } from \"node:crypto\";\nimport { createHash } from \"node:crypto\";\n\nconst tarArchiveType = \"tgz\";\nconst zipArchiveType = \"zip\";\nexport const allArchiveTypes = [tarArchiveType, zipArchiveType];\nexport type archiveType = (typeof allArchiveTypes)[number];\n\nexport type archiveOptions = {\n packageRoot: string;\n packageName: string;\n packageVersion: string;\n\n crossplatform: boolean;\n os: util.OSType;\n arch: util.ArchType;\n ext: archiveType;\n};\n\nexport function getPath(options: archiveOptions): string {\n const packageName = options.packageName.replaceAll(\"/\", \"-\").replaceAll(\"\\\\\", \"-\");\n\n if (options && !options.crossplatform) {\n return path.resolve(\n options.packageRoot,\n `pkg-${packageName}-${options.packageVersion}-${options.os}-${options.arch}.${options.ext}`,\n );\n }\n\n return path.resolve(\n options.packageRoot,\n `pkg-${packageName}-${options.packageVersion}.${options.ext}`,\n );\n}\n\nexport async function create(\n logger: winston.Logger,\n contentRoot: string,\n dstArchivePath: string,\n hasher?: Hash,\n): Promise<Hash> {\n const compressionLevel = 9;\n\n let format = \"\";\n if (dstArchivePath.endsWith(\".tgz\") || dstArchivePath.endsWith(\".tar.gz\")) {\n format = \"tar\";\n }\n if (dstArchivePath.endsWith(\".zip\")) {\n format = \"zip\";\n }\n\n if (format == \"\") {\n throw util.CLIError(\n `Archive ${dstArchivePath} has unsupported extension. Cannot create archive of unknown format`,\n );\n }\n\n const output = fs.createWriteStream(dstArchivePath);\n const hash = hasher ? hasher : createHash(\"sha256\");\n\n const a = archiver.create(format, {\n gzip: true,\n gzipOptions: { level: compressionLevel },\n zlib: { level: compressionLevel },\n });\n\n return new Promise((resolve, reject) => {\n // Waits for the output stream to be closed.\n output.on(\"close\", function () {\n logger.debug(`archive created. Total data processed: ${a.pointer()} bytes`);\n resolve(hash);\n });\n\n output.on(\"error\", function (err) {\n reject(err);\n });\n\n // Catch errors\n a.on(\"error\", function (err) {\n reject(err);\n });\n\n // Update hash with every chunk of data written to the archive\n a.on(\"data\", function (chunk) {\n hash.update(chunk);\n });\n\n // Pipe archive data to the file\n a.pipe(output);\n\n // Append files from sourceDir without prefix\n a.directory(contentRoot, false);\n\n // Finalize the archive (i.e. we are done appending files but streams have to finish yet)\n a.finalize().catch(reject);\n });\n}\n"],"mappings":";;;;;;AAwBA,SAAgB,QAAQ,SAAiC;CACvD,MAAM,cAAc,QAAQ,YAAY,WAAW,KAAK,IAAI,CAAC,WAAW,MAAM,IAAI;AAElF,KAAI,WAAW,CAAC,QAAQ,cACtB,QAAO,KAAK,QACV,QAAQ,aACR,OAAO,YAAY,GAAG,QAAQ,eAAe,GAAG,QAAQ,GAAG,GAAG,QAAQ,KAAK,GAAG,QAAQ,MACvF;AAGH,QAAO,KAAK,QACV,QAAQ,aACR,OAAO,YAAY,GAAG,QAAQ,eAAe,GAAG,QAAQ,MACzD;;AAGH,eAAsB,OACpB,QACA,aACA,gBACA,QACe;CACf,MAAM,mBAAmB;CAEzB,IAAI,SAAS;AACb,KAAI,eAAe,SAAS,OAAO,IAAI,eAAe,SAAS,UAAU,CACvE,UAAS;AAEX,KAAI,eAAe,SAAS,OAAO,CACjC,UAAS;AAGX,KAAI,UAAU,GACZ,OAAMA,SACJ,WAAW,eAAe,qEAC3B;CAGH,MAAM,SAAS,GAAG,kBAAkB,eAAe;CACnD,MAAM,OAAO,SAAS,SAAS,WAAW,SAAS;CAEnD,MAAM,IAAI,SAAS,OAAO,QAAQ;EAChC,MAAM;EACN,aAAa,EAAE,OAAO,kBAAkB;EACxC,MAAM,EAAE,OAAO,kBAAkB;EAClC,CAAC;AAEF,QAAO,IAAI,SAAS,SAAS,WAAW;AAEtC,SAAO,GAAG,SAAS,WAAY;AAC7B,UAAO,MAAM,0CAA0C,EAAE,SAAS,CAAC,QAAQ;AAC3E,WAAQ,KAAK;IACb;AAEF,SAAO,GAAG,SAAS,SAAU,KAAK;AAChC,UAAO,IAAI;IACX;AAGF,IAAE,GAAG,SAAS,SAAU,KAAK;AAC3B,UAAO,IAAI;IACX;AAGF,IAAE,GAAG,QAAQ,SAAU,OAAO;AAC5B,QAAK,OAAO,MAAM;IAClB;AAGF,IAAE,KAAK,OAAO;AAGd,IAAE,UAAU,aAAa,MAAM;AAG/B,IAAE,UAAU,CAAC,MAAM,OAAO;GAC1B"}
1
+ {"version":3,"file":"archive.js","names":["util.CLIError"],"sources":["../../src/core/archive.ts"],"sourcesContent":["import archiver from \"archiver\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type * as winston from \"winston\";\nimport * as util from \"./util\";\nimport type { Hash } from \"node:crypto\";\nimport { createHash } from \"node:crypto\";\n\nconst tarArchiveType = \"tgz\";\nconst zipArchiveType = \"zip\";\nexport const allArchiveTypes = [tarArchiveType, zipArchiveType];\nexport type archiveType = (typeof allArchiveTypes)[number];\n\nexport type archiveOptions = {\n packageRoot: string;\n packageName: string;\n packageVersion: string;\n\n crossplatform: boolean;\n os: util.OSType;\n arch: util.ArchType;\n ext: archiveType;\n};\n\nexport function getPath(options: archiveOptions): string {\n const packageName = options.packageName.replaceAll(\"/\", \"-\").replaceAll(\"\\\\\", \"-\");\n\n if (options && !options.crossplatform) {\n return path.resolve(\n options.packageRoot,\n `pkg-${packageName}-${options.packageVersion}-${options.os}-${options.arch}.${options.ext}`,\n );\n }\n\n return path.resolve(\n options.packageRoot,\n `pkg-${packageName}-${options.packageVersion}.${options.ext}`,\n );\n}\n\nexport async function create(\n logger: winston.Logger,\n contentRoot: string,\n dstArchivePath: string,\n hasher?: Hash,\n): Promise<Hash> {\n const compressionLevel = 9;\n\n let format = \"\";\n if (dstArchivePath.endsWith(\".tgz\") || dstArchivePath.endsWith(\".tar.gz\")) {\n format = \"tar\";\n }\n if (dstArchivePath.endsWith(\".zip\")) {\n format = \"zip\";\n }\n\n if (format == \"\") {\n throw util.CLIError(\n `Archive ${dstArchivePath} has unsupported extension. Cannot create archive of unknown format`,\n );\n }\n\n const output = fs.createWriteStream(dstArchivePath);\n const hash = hasher ? hasher : createHash(\"sha256\");\n\n const a = archiver.create(format, {\n gzip: true,\n gzipOptions: { level: compressionLevel },\n zlib: { level: compressionLevel },\n });\n\n return new Promise((resolve, reject) => {\n // Waits for the output stream to be closed.\n output.on(\"close\", function () {\n logger.debug(`archive created. Total data processed: ${a.pointer()} bytes`);\n resolve(hash);\n });\n\n output.on(\"error\", function (err) {\n reject(err);\n });\n\n // Catch errors\n a.on(\"error\", function (err) {\n reject(err);\n });\n\n // Update hash with every chunk of data written to the archive\n a.on(\"data\", function (chunk) {\n hash.update(chunk);\n });\n\n // Pipe archive data to the file\n a.pipe(output);\n\n // Append files from sourceDir without prefix\n a.directory(contentRoot, false);\n\n // Finalize the archive (i.e. we are done appending files but streams have to finish yet)\n a.finalize().catch(reject);\n });\n}\n"],"mappings":";;;;;;AAwBA,SAAgB,QAAQ,SAAiC;CACvD,MAAM,cAAc,QAAQ,YAAY,WAAW,KAAK,GAAG,CAAC,CAAC,WAAW,MAAM,GAAG;CAEjF,IAAI,WAAW,CAAC,QAAQ,eACtB,OAAO,KAAK,QACV,QAAQ,aACR,OAAO,YAAY,GAAG,QAAQ,eAAe,GAAG,QAAQ,GAAG,GAAG,QAAQ,KAAK,GAAG,QAAQ,KACxF;CAGF,OAAO,KAAK,QACV,QAAQ,aACR,OAAO,YAAY,GAAG,QAAQ,eAAe,GAAG,QAAQ,KAC1D;AACF;AAEA,eAAsB,OACpB,QACA,aACA,gBACA,QACe;CACf,MAAM,mBAAmB;CAEzB,IAAI,SAAS;CACb,IAAI,eAAe,SAAS,MAAM,KAAK,eAAe,SAAS,SAAS,GACtE,SAAS;CAEX,IAAI,eAAe,SAAS,MAAM,GAChC,SAAS;CAGX,IAAI,UAAU,IACZ,MAAMA,SACJ,WAAW,eAAe,oEAC5B;CAGF,MAAM,SAAS,GAAG,kBAAkB,cAAc;CAClD,MAAM,OAAO,SAAS,SAAS,WAAW,QAAQ;CAElD,MAAM,IAAI,SAAS,OAAO,QAAQ;EAChC,MAAM;EACN,aAAa,EAAE,OAAO,iBAAiB;EACvC,MAAM,EAAE,OAAO,iBAAiB;CAClC,CAAC;CAED,OAAO,IAAI,SAAS,SAAS,WAAW;EAEtC,OAAO,GAAG,SAAS,WAAY;GAC7B,OAAO,MAAM,0CAA0C,EAAE,QAAQ,EAAE,OAAO;GAC1E,QAAQ,IAAI;EACd,CAAC;EAED,OAAO,GAAG,SAAS,SAAU,KAAK;GAChC,OAAO,GAAG;EACZ,CAAC;EAGD,EAAE,GAAG,SAAS,SAAU,KAAK;GAC3B,OAAO,GAAG;EACZ,CAAC;EAGD,EAAE,GAAG,QAAQ,SAAU,OAAO;GAC5B,KAAK,OAAO,KAAK;EACnB,CAAC;EAGD,EAAE,KAAK,MAAM;EAGb,EAAE,UAAU,aAAa,KAAK;EAG9B,EAAE,SAAS,CAAC,CAAC,MAAM,MAAM;CAC3B,CAAC;AACH"}
@@ -1,17 +1,21 @@
1
1
  const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
2
2
  const require_util = require("../util.cjs");
3
3
  let node_fs = require("node:fs");
4
- node_fs = require_runtime.__toESM(node_fs);
4
+ node_fs = require_runtime.__toESM(node_fs, 1);
5
5
  let node_fs_promises = require("node:fs/promises");
6
- node_fs_promises = require_runtime.__toESM(node_fs_promises);
6
+ node_fs_promises = require_runtime.__toESM(node_fs_promises, 1);
7
7
  let node_path = require("node:path");
8
- node_path = require_runtime.__toESM(node_path);
8
+ node_path = require_runtime.__toESM(node_path, 1);
9
9
  let node_child_process = require("node:child_process");
10
10
  let undici = require("undici");
11
- undici = require_runtime.__toESM(undici);
11
+ undici = require_runtime.__toESM(undici, 1);
12
12
  //#region src/core/conda/builder.ts
13
13
  const defaultEnvironmentName = "default";
14
14
  var micromamba = class {
15
+ logger;
16
+ rootPrefix;
17
+ binaryVersion;
18
+ binaryPath;
15
19
  constructor(logger, rootPrefix, binaryVersion = "latest", binaryPath = "") {
16
20
  this.logger = logger;
17
21
  this.rootPrefix = rootPrefix;
@@ -220,6 +224,7 @@ async function downloadFile(logger, url, outputPath) {
220
224
  });
221
225
  }
222
226
  //#endregion
227
+ exports.downloadMicromamba = downloadMicromamba;
223
228
  exports.micromamba = micromamba;
224
229
  exports.micromambaDownloadUrl = micromambaDownloadUrl;
225
230
 
@@ -1 +1 @@
1
- {"version":3,"file":"builder.cjs","names":["path","fs","fsp"],"sources":["../../../src/core/conda/builder.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { spawnSync, type SpawnSyncOptions } from \"node:child_process\";\nimport * as undici from \"undici\";\nimport type winston from \"winston\";\n\nimport * as util from \"../util\";\n\nconst defaultEnvironmentName = \"default\";\n\nexport interface BuilderOptions {\n mambaRootPrefix: string; // root directory for all conda data\n logger: winston.Logger;\n micromambaVersion?: string; // use specific version of micromamba\n}\n\nexport interface MicromambaDownloadOptions {\n platform: util.PlatformType;\n outputPath: string; // output path for the binary\n\n version?: string; // defalut: latest\n}\n\nexport interface EnvCreateOptions {\n /** Environment name */\n environmentName?: string;\n /** Prefix where to create the environment */\n environmentPrefix?: string;\n /** Path to the environment specification file */\n specFile: string;\n}\n\nexport interface EnvExportOptions {\n /** Name of the environment to export */\n environmentName?: string;\n /** Prefix of the environment to export */\n environmentPrefix?: string;\n /** Export in JSON format */\n json?: boolean;\n /** Output file path for the exported specification */\n outputFile?: string;\n}\n\nexport interface EnvDeleteOptions {\n /** Environment name */\n environmentName?: string;\n /** Prefix where to create the environment */\n environmentPrefix?: string;\n}\n\nexport class micromamba {\n constructor(\n private readonly logger: winston.Logger,\n private readonly rootPrefix: string,\n private readonly binaryVersion: string = \"latest\",\n private readonly binaryPath: string = \"\",\n ) {\n if (!binaryPath) {\n this.binaryPath = path.join(rootPrefix, \"micromamba\");\n }\n\n if (util.currentOS() === \"windows\" && !this.binaryPath.endsWith(\".exe\")) {\n this.binaryPath += \".exe\";\n }\n }\n\n public async downloadBinary(): Promise<void> {\n if (fs.existsSync(this.binaryPath)) {\n try {\n await fsp.access(this.binaryPath, fs.constants.X_OK);\n this.logger.debug(\n `micromamba binary '${this.binaryPath}' exists and executable. Download was skipped`,\n );\n return;\n } catch {\n this.logger.debug(\n `file exists but is not executable: ${this.binaryPath}. Fixing permissions`,\n );\n await fsp.chmod(this.binaryPath, 0o755);\n }\n }\n\n await downloadMicromamba(this.logger, {\n platform: util.currentPlatform(),\n outputPath: this.binaryPath,\n version: this.binaryVersion,\n });\n }\n\n public getVersion(): string {\n return this.execSync([\"--version\"])!;\n }\n\n public createEnvironment(opts: EnvCreateOptions): void {\n const { environmentName, environmentPrefix, specFile } = opts;\n this.logger.debug(\n `Creating conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n\n const args = [\"env\", \"create\", \"--file\", specFile, \"--yes\"];\n if (environmentPrefix) {\n args.push(\"--prefix\", environmentPrefix);\n } else if (environmentName) {\n args.push(\"--name\", environmentName);\n } else {\n args.push(\"--name\", defaultEnvironmentName);\n }\n\n this.execSync(args, {\n stdio: \"inherit\",\n });\n }\n\n public exportEnvironment(opts: {\n environmentName?: string;\n environmentPrefix?: string;\n json?: boolean;\n }): string;\n public exportEnvironment(opts: {\n environmentName?: string;\n environmentPrefix?: string;\n json?: boolean;\n outputFile: string;\n }): void;\n public exportEnvironment(opts: EnvExportOptions): void | string {\n const { environmentName, environmentPrefix, json, outputFile } = opts;\n this.logger.debug(\n `Exporting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n\n const file = outputFile ? fs.openSync(outputFile, \"w\") : \"pipe\";\n\n const args = [\"env\", \"export\"];\n if (environmentPrefix) {\n args.push(\"--prefix\", environmentPrefix);\n } else if (environmentName) {\n args.push(\"--name\", environmentName);\n } else {\n args.push(\"--name\", defaultEnvironmentName);\n }\n if (json) {\n args.push(\"--json\");\n }\n\n try {\n const envInfo = this.execSync(args, {\n stdio: [\"inherit\", file, \"inherit\"],\n });\n\n if (!outputFile) {\n return envInfo;\n }\n } catch (error) {\n if (file !== \"pipe\") {\n fs.closeSync(file);\n }\n if (outputFile) {\n fs.rmSync(outputFile, { force: true });\n }\n throw error;\n }\n\n if (file !== \"pipe\") {\n fs.closeSync(file);\n }\n }\n\n public deleteEnvironment(opts: EnvDeleteOptions): void {\n const { environmentName, environmentPrefix } = opts;\n\n if (environmentPrefix) {\n this.logger.debug(\n `Deleting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n fs.rmSync(environmentPrefix, { recursive: true });\n return;\n }\n\n const result = this.exportEnvironment({ environmentName, environmentPrefix, json: true });\n const envInfo = JSON.parse(result ?? \"{}\") as Record<string, unknown>;\n\n if (envInfo.prefix) {\n this.logger.debug(\n `Deleting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n fs.rmSync(envInfo.prefix as string, { recursive: true });\n } else {\n const errMsg =\n \"Failed to delete environment: cannot get environment location from micromamba tool\";\n this.logger.error(errMsg);\n throw new Error(errMsg);\n }\n }\n\n // FIXME: IMHO better to have async exec with promises. I just am not skilled enough to implement it fast. :(\n private execSync(args: string[], opts?: SpawnSyncOptions): string | void {\n this.logger.debug(`Executing micromamba: ${this.binaryPath} ${args.join(\" \")}`);\n\n const result = spawnSync(this.binaryPath, args, {\n encoding: \"utf8\",\n stdio: \"pipe\",\n ...opts,\n env: {\n ...process.env,\n MAMBA_ROOT_PREFIX: this.rootPrefix,\n CONDA_PKGS_DIRS: path.join(this.rootPrefix, \"pkgs\"),\n ...opts?.env,\n },\n });\n\n if (result.error) {\n throw new Error(`Failed to get micromamba version: ${result.error.message}`);\n }\n\n if (result.status !== 0) {\n const errMsg = `micromamba command failed with status ${result.status}: ${result.stderr?.toString().trim() ?? \"no piped stderr\"}`;\n this.logger.error(errMsg);\n throw new Error(errMsg);\n }\n\n if (!result.stdout) {\n return;\n }\n\n return result.stdout.toString().trim();\n }\n}\n\nexport function micromambaDownloadUrl(version: string, platform: util.PlatformType): string {\n return version === \"latest\"\n ? `https://github.com/mamba-org/micromamba-releases/releases/latest/download/${micromambaAssetName(platform)}`\n : `https://github.com/mamba-org/micromamba-releases/releases/download/${version}/${micromambaAssetName(platform)}`;\n}\n\n/**\n * Downloads micromamba binary for the specified platform and version\n */\nexport async function downloadMicromamba(\n logger: winston.Logger,\n options: MicromambaDownloadOptions,\n): Promise<string> {\n const { version = \"latest\", platform, outputPath } = options;\n\n const targetPlatform = platform ?? util.currentPlatform();\n const binaryPath = outputPath;\n\n logger.debug(`Downloading micromamba version ${version} for platform ${targetPlatform}`);\n\n const downloadUrl = micromambaDownloadUrl(version, targetPlatform);\n\n logger.debug(`Download URL: ${downloadUrl}`);\n\n await downloadFile(logger, downloadUrl, binaryPath);\n\n logger.debug(`making binary executable: ${binaryPath}`);\n await fsp.chmod(binaryPath, 0o755);\n\n logger.info(`Micromamba downloaded to: ${binaryPath}`);\n return binaryPath;\n}\n\n/**\n * Get correct asset name with micromamba binary for particular platform,\n * as they are available in micromamba-releases repo.\n */\nfunction micromambaAssetName(platform: util.PlatformType): string {\n const { os, arch } = util.splitPlatform(platform);\n switch (os) {\n case \"linux\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-linux-64\";\n case \"aarch64\":\n return \"micromamba-linux-aarch64\";\n default:\n util.assertNever(arch);\n }\n break;\n }\n case \"macosx\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-osx-64\";\n case \"aarch64\":\n return \"micromamba-osx-arm64\";\n default:\n util.assertNever(arch);\n }\n break;\n }\n case \"windows\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-win-64\";\n case \"aarch64\":\n throw new Error(\"Micromamba does not support ARM64 on Windows\");\n default:\n util.assertNever(arch);\n }\n break;\n }\n default:\n util.assertNever(os);\n }\n throw new Error(\"calm down linter, this code is unreachable\");\n}\n\n/**\n * Downloads a file from URL to local path\n */\nasync function downloadFile(\n logger: winston.Logger,\n url: string,\n outputPath: string,\n): Promise<void> {\n type responseInfo = {\n statusCode: number;\n body: NodeJS.ReadableStream;\n location: string;\n };\n\n let response: responseInfo;\n const maxRedirects = 5;\n const maxAttempts = 3;\n\n let redirCount = 0;\n let attempt = 0;\n for (; attempt <= maxAttempts; ) {\n attempt++;\n\n logger.debug(`Trying to download: ${url}`);\n try {\n const requestResult = await undici.request(url, {\n method: \"GET\",\n });\n response = {\n statusCode: requestResult.statusCode,\n location: requestResult.headers[\"location\"]?.toString() ?? \"\",\n body: requestResult.body,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to make request: ${errorMessage}`);\n }\n\n if (response.statusCode === 301 || response.statusCode === 302) {\n if (redirCount >= maxRedirects) {\n throw new Error(`Too many redirects: ${redirCount}, last location: ${response.location}`);\n }\n\n logger.debug(`Processing redirect. New location: ${response.location}`);\n redirCount++;\n url = response.location;\n continue;\n }\n\n if (response.statusCode === 200) {\n break;\n }\n\n logger.error(`Failed to download: ${response.statusCode}, attempt ${attempt}`);\n }\n\n if (response!.statusCode !== 200) {\n throw new Error(`Failed to download: last attempt status code: ${response!.statusCode}`);\n }\n\n const fileStream = fs.createWriteStream(outputPath);\n\n response!.body.pipe(fileStream);\n\n return new Promise((resolve, reject) => {\n fileStream.on(\"finish\", () => {\n fileStream.close();\n resolve();\n });\n\n fileStream.on(\"error\", (err) => {\n fs.unlink(outputPath, () => {}); // Delete the file on error\n reject(err);\n });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"builder.cjs","names":["path","fs","fsp"],"sources":["../../../src/core/conda/builder.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { spawnSync, type SpawnSyncOptions } from \"node:child_process\";\nimport * as undici from \"undici\";\nimport type winston from \"winston\";\n\nimport * as util from \"../util\";\n\nconst defaultEnvironmentName = \"default\";\n\nexport interface BuilderOptions {\n mambaRootPrefix: string; // root directory for all conda data\n logger: winston.Logger;\n micromambaVersion?: string; // use specific version of micromamba\n}\n\nexport interface MicromambaDownloadOptions {\n platform: util.PlatformType;\n outputPath: string; // output path for the binary\n\n version?: string; // defalut: latest\n}\n\nexport interface EnvCreateOptions {\n /** Environment name */\n environmentName?: string;\n /** Prefix where to create the environment */\n environmentPrefix?: string;\n /** Path to the environment specification file */\n specFile: string;\n}\n\nexport interface EnvExportOptions {\n /** Name of the environment to export */\n environmentName?: string;\n /** Prefix of the environment to export */\n environmentPrefix?: string;\n /** Export in JSON format */\n json?: boolean;\n /** Output file path for the exported specification */\n outputFile?: string;\n}\n\nexport interface EnvDeleteOptions {\n /** Environment name */\n environmentName?: string;\n /** Prefix where to create the environment */\n environmentPrefix?: string;\n}\n\nexport class micromamba {\n constructor(\n private readonly logger: winston.Logger,\n private readonly rootPrefix: string,\n private readonly binaryVersion: string = \"latest\",\n private readonly binaryPath: string = \"\",\n ) {\n if (!binaryPath) {\n this.binaryPath = path.join(rootPrefix, \"micromamba\");\n }\n\n if (util.currentOS() === \"windows\" && !this.binaryPath.endsWith(\".exe\")) {\n this.binaryPath += \".exe\";\n }\n }\n\n public async downloadBinary(): Promise<void> {\n if (fs.existsSync(this.binaryPath)) {\n try {\n await fsp.access(this.binaryPath, fs.constants.X_OK);\n this.logger.debug(\n `micromamba binary '${this.binaryPath}' exists and executable. Download was skipped`,\n );\n return;\n } catch {\n this.logger.debug(\n `file exists but is not executable: ${this.binaryPath}. Fixing permissions`,\n );\n await fsp.chmod(this.binaryPath, 0o755);\n }\n }\n\n await downloadMicromamba(this.logger, {\n platform: util.currentPlatform(),\n outputPath: this.binaryPath,\n version: this.binaryVersion,\n });\n }\n\n public getVersion(): string {\n return this.execSync([\"--version\"])!;\n }\n\n public createEnvironment(opts: EnvCreateOptions): void {\n const { environmentName, environmentPrefix, specFile } = opts;\n this.logger.debug(\n `Creating conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n\n const args = [\"env\", \"create\", \"--file\", specFile, \"--yes\"];\n if (environmentPrefix) {\n args.push(\"--prefix\", environmentPrefix);\n } else if (environmentName) {\n args.push(\"--name\", environmentName);\n } else {\n args.push(\"--name\", defaultEnvironmentName);\n }\n\n this.execSync(args, {\n stdio: \"inherit\",\n });\n }\n\n public exportEnvironment(opts: {\n environmentName?: string;\n environmentPrefix?: string;\n json?: boolean;\n }): string;\n public exportEnvironment(opts: {\n environmentName?: string;\n environmentPrefix?: string;\n json?: boolean;\n outputFile: string;\n }): void;\n public exportEnvironment(opts: EnvExportOptions): void | string {\n const { environmentName, environmentPrefix, json, outputFile } = opts;\n this.logger.debug(\n `Exporting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n\n const file = outputFile ? fs.openSync(outputFile, \"w\") : \"pipe\";\n\n const args = [\"env\", \"export\"];\n if (environmentPrefix) {\n args.push(\"--prefix\", environmentPrefix);\n } else if (environmentName) {\n args.push(\"--name\", environmentName);\n } else {\n args.push(\"--name\", defaultEnvironmentName);\n }\n if (json) {\n args.push(\"--json\");\n }\n\n try {\n const envInfo = this.execSync(args, {\n stdio: [\"inherit\", file, \"inherit\"],\n });\n\n if (!outputFile) {\n return envInfo;\n }\n } catch (error) {\n if (file !== \"pipe\") {\n fs.closeSync(file);\n }\n if (outputFile) {\n fs.rmSync(outputFile, { force: true });\n }\n throw error;\n }\n\n if (file !== \"pipe\") {\n fs.closeSync(file);\n }\n }\n\n public deleteEnvironment(opts: EnvDeleteOptions): void {\n const { environmentName, environmentPrefix } = opts;\n\n if (environmentPrefix) {\n this.logger.debug(\n `Deleting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n fs.rmSync(environmentPrefix, { recursive: true });\n return;\n }\n\n const result = this.exportEnvironment({ environmentName, environmentPrefix, json: true });\n const envInfo = JSON.parse(result ?? \"{}\") as Record<string, unknown>;\n\n if (envInfo.prefix) {\n this.logger.debug(\n `Deleting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n fs.rmSync(envInfo.prefix as string, { recursive: true });\n } else {\n const errMsg =\n \"Failed to delete environment: cannot get environment location from micromamba tool\";\n this.logger.error(errMsg);\n throw new Error(errMsg);\n }\n }\n\n // FIXME: IMHO better to have async exec with promises. I just am not skilled enough to implement it fast. :(\n private execSync(args: string[], opts?: SpawnSyncOptions): string | void {\n this.logger.debug(`Executing micromamba: ${this.binaryPath} ${args.join(\" \")}`);\n\n const result = spawnSync(this.binaryPath, args, {\n encoding: \"utf8\",\n stdio: \"pipe\",\n ...opts,\n env: {\n ...process.env,\n MAMBA_ROOT_PREFIX: this.rootPrefix,\n CONDA_PKGS_DIRS: path.join(this.rootPrefix, \"pkgs\"),\n ...opts?.env,\n },\n });\n\n if (result.error) {\n throw new Error(`Failed to get micromamba version: ${result.error.message}`);\n }\n\n if (result.status !== 0) {\n const errMsg = `micromamba command failed with status ${result.status}: ${result.stderr?.toString().trim() ?? \"no piped stderr\"}`;\n this.logger.error(errMsg);\n throw new Error(errMsg);\n }\n\n if (!result.stdout) {\n return;\n }\n\n return result.stdout.toString().trim();\n }\n}\n\nexport function micromambaDownloadUrl(version: string, platform: util.PlatformType): string {\n return version === \"latest\"\n ? `https://github.com/mamba-org/micromamba-releases/releases/latest/download/${micromambaAssetName(platform)}`\n : `https://github.com/mamba-org/micromamba-releases/releases/download/${version}/${micromambaAssetName(platform)}`;\n}\n\n/**\n * Downloads micromamba binary for the specified platform and version\n */\nexport async function downloadMicromamba(\n logger: winston.Logger,\n options: MicromambaDownloadOptions,\n): Promise<string> {\n const { version = \"latest\", platform, outputPath } = options;\n\n const targetPlatform = platform ?? util.currentPlatform();\n const binaryPath = outputPath;\n\n logger.debug(`Downloading micromamba version ${version} for platform ${targetPlatform}`);\n\n const downloadUrl = micromambaDownloadUrl(version, targetPlatform);\n\n logger.debug(`Download URL: ${downloadUrl}`);\n\n await downloadFile(logger, downloadUrl, binaryPath);\n\n logger.debug(`making binary executable: ${binaryPath}`);\n await fsp.chmod(binaryPath, 0o755);\n\n logger.info(`Micromamba downloaded to: ${binaryPath}`);\n return binaryPath;\n}\n\n/**\n * Get correct asset name with micromamba binary for particular platform,\n * as they are available in micromamba-releases repo.\n */\nfunction micromambaAssetName(platform: util.PlatformType): string {\n const { os, arch } = util.splitPlatform(platform);\n switch (os) {\n case \"linux\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-linux-64\";\n case \"aarch64\":\n return \"micromamba-linux-aarch64\";\n default:\n util.assertNever(arch);\n }\n break;\n }\n case \"macosx\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-osx-64\";\n case \"aarch64\":\n return \"micromamba-osx-arm64\";\n default:\n util.assertNever(arch);\n }\n break;\n }\n case \"windows\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-win-64\";\n case \"aarch64\":\n throw new Error(\"Micromamba does not support ARM64 on Windows\");\n default:\n util.assertNever(arch);\n }\n break;\n }\n default:\n util.assertNever(os);\n }\n throw new Error(\"calm down linter, this code is unreachable\");\n}\n\n/**\n * Downloads a file from URL to local path\n */\nasync function downloadFile(\n logger: winston.Logger,\n url: string,\n outputPath: string,\n): Promise<void> {\n type responseInfo = {\n statusCode: number;\n body: NodeJS.ReadableStream;\n location: string;\n };\n\n let response: responseInfo;\n const maxRedirects = 5;\n const maxAttempts = 3;\n\n let redirCount = 0;\n let attempt = 0;\n for (; attempt <= maxAttempts; ) {\n attempt++;\n\n logger.debug(`Trying to download: ${url}`);\n try {\n const requestResult = await undici.request(url, {\n method: \"GET\",\n });\n response = {\n statusCode: requestResult.statusCode,\n location: requestResult.headers[\"location\"]?.toString() ?? \"\",\n body: requestResult.body,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to make request: ${errorMessage}`);\n }\n\n if (response.statusCode === 301 || response.statusCode === 302) {\n if (redirCount >= maxRedirects) {\n throw new Error(`Too many redirects: ${redirCount}, last location: ${response.location}`);\n }\n\n logger.debug(`Processing redirect. New location: ${response.location}`);\n redirCount++;\n url = response.location;\n continue;\n }\n\n if (response.statusCode === 200) {\n break;\n }\n\n logger.error(`Failed to download: ${response.statusCode}, attempt ${attempt}`);\n }\n\n if (response!.statusCode !== 200) {\n throw new Error(`Failed to download: last attempt status code: ${response!.statusCode}`);\n }\n\n const fileStream = fs.createWriteStream(outputPath);\n\n response!.body.pipe(fileStream);\n\n return new Promise((resolve, reject) => {\n fileStream.on(\"finish\", () => {\n fileStream.close();\n resolve();\n });\n\n fileStream.on(\"error\", (err) => {\n fs.unlink(outputPath, () => {}); // Delete the file on error\n reject(err);\n });\n });\n}\n"],"mappings":"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"}
@@ -7,6 +7,10 @@ import * as undici from "undici";
7
7
  //#region src/core/conda/builder.ts
8
8
  const defaultEnvironmentName = "default";
9
9
  var micromamba = class {
10
+ logger;
11
+ rootPrefix;
12
+ binaryVersion;
13
+ binaryPath;
10
14
  constructor(logger, rootPrefix, binaryVersion = "latest", binaryPath = "") {
11
15
  this.logger = logger;
12
16
  this.rootPrefix = rootPrefix;
@@ -215,6 +219,6 @@ async function downloadFile(logger, url, outputPath) {
215
219
  });
216
220
  }
217
221
  //#endregion
218
- export { micromamba, micromambaDownloadUrl };
222
+ export { downloadMicromamba, micromamba, micromambaDownloadUrl };
219
223
 
220
224
  //# sourceMappingURL=builder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"builder.js","names":["util.currentOS","util.currentPlatform","util.splitPlatform"],"sources":["../../../src/core/conda/builder.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { spawnSync, type SpawnSyncOptions } from \"node:child_process\";\nimport * as undici from \"undici\";\nimport type winston from \"winston\";\n\nimport * as util from \"../util\";\n\nconst defaultEnvironmentName = \"default\";\n\nexport interface BuilderOptions {\n mambaRootPrefix: string; // root directory for all conda data\n logger: winston.Logger;\n micromambaVersion?: string; // use specific version of micromamba\n}\n\nexport interface MicromambaDownloadOptions {\n platform: util.PlatformType;\n outputPath: string; // output path for the binary\n\n version?: string; // defalut: latest\n}\n\nexport interface EnvCreateOptions {\n /** Environment name */\n environmentName?: string;\n /** Prefix where to create the environment */\n environmentPrefix?: string;\n /** Path to the environment specification file */\n specFile: string;\n}\n\nexport interface EnvExportOptions {\n /** Name of the environment to export */\n environmentName?: string;\n /** Prefix of the environment to export */\n environmentPrefix?: string;\n /** Export in JSON format */\n json?: boolean;\n /** Output file path for the exported specification */\n outputFile?: string;\n}\n\nexport interface EnvDeleteOptions {\n /** Environment name */\n environmentName?: string;\n /** Prefix where to create the environment */\n environmentPrefix?: string;\n}\n\nexport class micromamba {\n constructor(\n private readonly logger: winston.Logger,\n private readonly rootPrefix: string,\n private readonly binaryVersion: string = \"latest\",\n private readonly binaryPath: string = \"\",\n ) {\n if (!binaryPath) {\n this.binaryPath = path.join(rootPrefix, \"micromamba\");\n }\n\n if (util.currentOS() === \"windows\" && !this.binaryPath.endsWith(\".exe\")) {\n this.binaryPath += \".exe\";\n }\n }\n\n public async downloadBinary(): Promise<void> {\n if (fs.existsSync(this.binaryPath)) {\n try {\n await fsp.access(this.binaryPath, fs.constants.X_OK);\n this.logger.debug(\n `micromamba binary '${this.binaryPath}' exists and executable. Download was skipped`,\n );\n return;\n } catch {\n this.logger.debug(\n `file exists but is not executable: ${this.binaryPath}. Fixing permissions`,\n );\n await fsp.chmod(this.binaryPath, 0o755);\n }\n }\n\n await downloadMicromamba(this.logger, {\n platform: util.currentPlatform(),\n outputPath: this.binaryPath,\n version: this.binaryVersion,\n });\n }\n\n public getVersion(): string {\n return this.execSync([\"--version\"])!;\n }\n\n public createEnvironment(opts: EnvCreateOptions): void {\n const { environmentName, environmentPrefix, specFile } = opts;\n this.logger.debug(\n `Creating conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n\n const args = [\"env\", \"create\", \"--file\", specFile, \"--yes\"];\n if (environmentPrefix) {\n args.push(\"--prefix\", environmentPrefix);\n } else if (environmentName) {\n args.push(\"--name\", environmentName);\n } else {\n args.push(\"--name\", defaultEnvironmentName);\n }\n\n this.execSync(args, {\n stdio: \"inherit\",\n });\n }\n\n public exportEnvironment(opts: {\n environmentName?: string;\n environmentPrefix?: string;\n json?: boolean;\n }): string;\n public exportEnvironment(opts: {\n environmentName?: string;\n environmentPrefix?: string;\n json?: boolean;\n outputFile: string;\n }): void;\n public exportEnvironment(opts: EnvExportOptions): void | string {\n const { environmentName, environmentPrefix, json, outputFile } = opts;\n this.logger.debug(\n `Exporting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n\n const file = outputFile ? fs.openSync(outputFile, \"w\") : \"pipe\";\n\n const args = [\"env\", \"export\"];\n if (environmentPrefix) {\n args.push(\"--prefix\", environmentPrefix);\n } else if (environmentName) {\n args.push(\"--name\", environmentName);\n } else {\n args.push(\"--name\", defaultEnvironmentName);\n }\n if (json) {\n args.push(\"--json\");\n }\n\n try {\n const envInfo = this.execSync(args, {\n stdio: [\"inherit\", file, \"inherit\"],\n });\n\n if (!outputFile) {\n return envInfo;\n }\n } catch (error) {\n if (file !== \"pipe\") {\n fs.closeSync(file);\n }\n if (outputFile) {\n fs.rmSync(outputFile, { force: true });\n }\n throw error;\n }\n\n if (file !== \"pipe\") {\n fs.closeSync(file);\n }\n }\n\n public deleteEnvironment(opts: EnvDeleteOptions): void {\n const { environmentName, environmentPrefix } = opts;\n\n if (environmentPrefix) {\n this.logger.debug(\n `Deleting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n fs.rmSync(environmentPrefix, { recursive: true });\n return;\n }\n\n const result = this.exportEnvironment({ environmentName, environmentPrefix, json: true });\n const envInfo = JSON.parse(result ?? \"{}\") as Record<string, unknown>;\n\n if (envInfo.prefix) {\n this.logger.debug(\n `Deleting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n fs.rmSync(envInfo.prefix as string, { recursive: true });\n } else {\n const errMsg =\n \"Failed to delete environment: cannot get environment location from micromamba tool\";\n this.logger.error(errMsg);\n throw new Error(errMsg);\n }\n }\n\n // FIXME: IMHO better to have async exec with promises. I just am not skilled enough to implement it fast. :(\n private execSync(args: string[], opts?: SpawnSyncOptions): string | void {\n this.logger.debug(`Executing micromamba: ${this.binaryPath} ${args.join(\" \")}`);\n\n const result = spawnSync(this.binaryPath, args, {\n encoding: \"utf8\",\n stdio: \"pipe\",\n ...opts,\n env: {\n ...process.env,\n MAMBA_ROOT_PREFIX: this.rootPrefix,\n CONDA_PKGS_DIRS: path.join(this.rootPrefix, \"pkgs\"),\n ...opts?.env,\n },\n });\n\n if (result.error) {\n throw new Error(`Failed to get micromamba version: ${result.error.message}`);\n }\n\n if (result.status !== 0) {\n const errMsg = `micromamba command failed with status ${result.status}: ${result.stderr?.toString().trim() ?? \"no piped stderr\"}`;\n this.logger.error(errMsg);\n throw new Error(errMsg);\n }\n\n if (!result.stdout) {\n return;\n }\n\n return result.stdout.toString().trim();\n }\n}\n\nexport function micromambaDownloadUrl(version: string, platform: util.PlatformType): string {\n return version === \"latest\"\n ? `https://github.com/mamba-org/micromamba-releases/releases/latest/download/${micromambaAssetName(platform)}`\n : `https://github.com/mamba-org/micromamba-releases/releases/download/${version}/${micromambaAssetName(platform)}`;\n}\n\n/**\n * Downloads micromamba binary for the specified platform and version\n */\nexport async function downloadMicromamba(\n logger: winston.Logger,\n options: MicromambaDownloadOptions,\n): Promise<string> {\n const { version = \"latest\", platform, outputPath } = options;\n\n const targetPlatform = platform ?? util.currentPlatform();\n const binaryPath = outputPath;\n\n logger.debug(`Downloading micromamba version ${version} for platform ${targetPlatform}`);\n\n const downloadUrl = micromambaDownloadUrl(version, targetPlatform);\n\n logger.debug(`Download URL: ${downloadUrl}`);\n\n await downloadFile(logger, downloadUrl, binaryPath);\n\n logger.debug(`making binary executable: ${binaryPath}`);\n await fsp.chmod(binaryPath, 0o755);\n\n logger.info(`Micromamba downloaded to: ${binaryPath}`);\n return binaryPath;\n}\n\n/**\n * Get correct asset name with micromamba binary for particular platform,\n * as they are available in micromamba-releases repo.\n */\nfunction micromambaAssetName(platform: util.PlatformType): string {\n const { os, arch } = util.splitPlatform(platform);\n switch (os) {\n case \"linux\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-linux-64\";\n case \"aarch64\":\n return \"micromamba-linux-aarch64\";\n default:\n util.assertNever(arch);\n }\n break;\n }\n case \"macosx\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-osx-64\";\n case \"aarch64\":\n return \"micromamba-osx-arm64\";\n default:\n util.assertNever(arch);\n }\n break;\n }\n case \"windows\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-win-64\";\n case \"aarch64\":\n throw new Error(\"Micromamba does not support ARM64 on Windows\");\n default:\n util.assertNever(arch);\n }\n break;\n }\n default:\n util.assertNever(os);\n }\n throw new Error(\"calm down linter, this code is unreachable\");\n}\n\n/**\n * Downloads a file from URL to local path\n */\nasync function downloadFile(\n logger: winston.Logger,\n url: string,\n outputPath: string,\n): Promise<void> {\n type responseInfo = {\n statusCode: number;\n body: NodeJS.ReadableStream;\n location: string;\n };\n\n let response: responseInfo;\n const maxRedirects = 5;\n const maxAttempts = 3;\n\n let redirCount = 0;\n let attempt = 0;\n for (; attempt <= maxAttempts; ) {\n attempt++;\n\n logger.debug(`Trying to download: ${url}`);\n try {\n const requestResult = await undici.request(url, {\n method: \"GET\",\n });\n response = {\n statusCode: requestResult.statusCode,\n location: requestResult.headers[\"location\"]?.toString() ?? \"\",\n body: requestResult.body,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to make request: ${errorMessage}`);\n }\n\n if (response.statusCode === 301 || response.statusCode === 302) {\n if (redirCount >= maxRedirects) {\n throw new Error(`Too many redirects: ${redirCount}, last location: ${response.location}`);\n }\n\n logger.debug(`Processing redirect. New location: ${response.location}`);\n redirCount++;\n url = response.location;\n continue;\n }\n\n if (response.statusCode === 200) {\n break;\n }\n\n logger.error(`Failed to download: ${response.statusCode}, attempt ${attempt}`);\n }\n\n if (response!.statusCode !== 200) {\n throw new Error(`Failed to download: last attempt status code: ${response!.statusCode}`);\n }\n\n const fileStream = fs.createWriteStream(outputPath);\n\n response!.body.pipe(fileStream);\n\n return new Promise((resolve, reject) => {\n fileStream.on(\"finish\", () => {\n fileStream.close();\n resolve();\n });\n\n fileStream.on(\"error\", (err) => {\n fs.unlink(outputPath, () => {}); // Delete the file on error\n reject(err);\n });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"builder.js","names":["util.currentOS","util.currentPlatform","util.splitPlatform"],"sources":["../../../src/core/conda/builder.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { spawnSync, type SpawnSyncOptions } from \"node:child_process\";\nimport * as undici from \"undici\";\nimport type winston from \"winston\";\n\nimport * as util from \"../util\";\n\nconst defaultEnvironmentName = \"default\";\n\nexport interface BuilderOptions {\n mambaRootPrefix: string; // root directory for all conda data\n logger: winston.Logger;\n micromambaVersion?: string; // use specific version of micromamba\n}\n\nexport interface MicromambaDownloadOptions {\n platform: util.PlatformType;\n outputPath: string; // output path for the binary\n\n version?: string; // defalut: latest\n}\n\nexport interface EnvCreateOptions {\n /** Environment name */\n environmentName?: string;\n /** Prefix where to create the environment */\n environmentPrefix?: string;\n /** Path to the environment specification file */\n specFile: string;\n}\n\nexport interface EnvExportOptions {\n /** Name of the environment to export */\n environmentName?: string;\n /** Prefix of the environment to export */\n environmentPrefix?: string;\n /** Export in JSON format */\n json?: boolean;\n /** Output file path for the exported specification */\n outputFile?: string;\n}\n\nexport interface EnvDeleteOptions {\n /** Environment name */\n environmentName?: string;\n /** Prefix where to create the environment */\n environmentPrefix?: string;\n}\n\nexport class micromamba {\n constructor(\n private readonly logger: winston.Logger,\n private readonly rootPrefix: string,\n private readonly binaryVersion: string = \"latest\",\n private readonly binaryPath: string = \"\",\n ) {\n if (!binaryPath) {\n this.binaryPath = path.join(rootPrefix, \"micromamba\");\n }\n\n if (util.currentOS() === \"windows\" && !this.binaryPath.endsWith(\".exe\")) {\n this.binaryPath += \".exe\";\n }\n }\n\n public async downloadBinary(): Promise<void> {\n if (fs.existsSync(this.binaryPath)) {\n try {\n await fsp.access(this.binaryPath, fs.constants.X_OK);\n this.logger.debug(\n `micromamba binary '${this.binaryPath}' exists and executable. Download was skipped`,\n );\n return;\n } catch {\n this.logger.debug(\n `file exists but is not executable: ${this.binaryPath}. Fixing permissions`,\n );\n await fsp.chmod(this.binaryPath, 0o755);\n }\n }\n\n await downloadMicromamba(this.logger, {\n platform: util.currentPlatform(),\n outputPath: this.binaryPath,\n version: this.binaryVersion,\n });\n }\n\n public getVersion(): string {\n return this.execSync([\"--version\"])!;\n }\n\n public createEnvironment(opts: EnvCreateOptions): void {\n const { environmentName, environmentPrefix, specFile } = opts;\n this.logger.debug(\n `Creating conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n\n const args = [\"env\", \"create\", \"--file\", specFile, \"--yes\"];\n if (environmentPrefix) {\n args.push(\"--prefix\", environmentPrefix);\n } else if (environmentName) {\n args.push(\"--name\", environmentName);\n } else {\n args.push(\"--name\", defaultEnvironmentName);\n }\n\n this.execSync(args, {\n stdio: \"inherit\",\n });\n }\n\n public exportEnvironment(opts: {\n environmentName?: string;\n environmentPrefix?: string;\n json?: boolean;\n }): string;\n public exportEnvironment(opts: {\n environmentName?: string;\n environmentPrefix?: string;\n json?: boolean;\n outputFile: string;\n }): void;\n public exportEnvironment(opts: EnvExportOptions): void | string {\n const { environmentName, environmentPrefix, json, outputFile } = opts;\n this.logger.debug(\n `Exporting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n\n const file = outputFile ? fs.openSync(outputFile, \"w\") : \"pipe\";\n\n const args = [\"env\", \"export\"];\n if (environmentPrefix) {\n args.push(\"--prefix\", environmentPrefix);\n } else if (environmentName) {\n args.push(\"--name\", environmentName);\n } else {\n args.push(\"--name\", defaultEnvironmentName);\n }\n if (json) {\n args.push(\"--json\");\n }\n\n try {\n const envInfo = this.execSync(args, {\n stdio: [\"inherit\", file, \"inherit\"],\n });\n\n if (!outputFile) {\n return envInfo;\n }\n } catch (error) {\n if (file !== \"pipe\") {\n fs.closeSync(file);\n }\n if (outputFile) {\n fs.rmSync(outputFile, { force: true });\n }\n throw error;\n }\n\n if (file !== \"pipe\") {\n fs.closeSync(file);\n }\n }\n\n public deleteEnvironment(opts: EnvDeleteOptions): void {\n const { environmentName, environmentPrefix } = opts;\n\n if (environmentPrefix) {\n this.logger.debug(\n `Deleting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n fs.rmSync(environmentPrefix, { recursive: true });\n return;\n }\n\n const result = this.exportEnvironment({ environmentName, environmentPrefix, json: true });\n const envInfo = JSON.parse(result ?? \"{}\") as Record<string, unknown>;\n\n if (envInfo.prefix) {\n this.logger.debug(\n `Deleting conda environment '${environmentName ?? environmentPrefix ?? defaultEnvironmentName}'...`,\n );\n fs.rmSync(envInfo.prefix as string, { recursive: true });\n } else {\n const errMsg =\n \"Failed to delete environment: cannot get environment location from micromamba tool\";\n this.logger.error(errMsg);\n throw new Error(errMsg);\n }\n }\n\n // FIXME: IMHO better to have async exec with promises. I just am not skilled enough to implement it fast. :(\n private execSync(args: string[], opts?: SpawnSyncOptions): string | void {\n this.logger.debug(`Executing micromamba: ${this.binaryPath} ${args.join(\" \")}`);\n\n const result = spawnSync(this.binaryPath, args, {\n encoding: \"utf8\",\n stdio: \"pipe\",\n ...opts,\n env: {\n ...process.env,\n MAMBA_ROOT_PREFIX: this.rootPrefix,\n CONDA_PKGS_DIRS: path.join(this.rootPrefix, \"pkgs\"),\n ...opts?.env,\n },\n });\n\n if (result.error) {\n throw new Error(`Failed to get micromamba version: ${result.error.message}`);\n }\n\n if (result.status !== 0) {\n const errMsg = `micromamba command failed with status ${result.status}: ${result.stderr?.toString().trim() ?? \"no piped stderr\"}`;\n this.logger.error(errMsg);\n throw new Error(errMsg);\n }\n\n if (!result.stdout) {\n return;\n }\n\n return result.stdout.toString().trim();\n }\n}\n\nexport function micromambaDownloadUrl(version: string, platform: util.PlatformType): string {\n return version === \"latest\"\n ? `https://github.com/mamba-org/micromamba-releases/releases/latest/download/${micromambaAssetName(platform)}`\n : `https://github.com/mamba-org/micromamba-releases/releases/download/${version}/${micromambaAssetName(platform)}`;\n}\n\n/**\n * Downloads micromamba binary for the specified platform and version\n */\nexport async function downloadMicromamba(\n logger: winston.Logger,\n options: MicromambaDownloadOptions,\n): Promise<string> {\n const { version = \"latest\", platform, outputPath } = options;\n\n const targetPlatform = platform ?? util.currentPlatform();\n const binaryPath = outputPath;\n\n logger.debug(`Downloading micromamba version ${version} for platform ${targetPlatform}`);\n\n const downloadUrl = micromambaDownloadUrl(version, targetPlatform);\n\n logger.debug(`Download URL: ${downloadUrl}`);\n\n await downloadFile(logger, downloadUrl, binaryPath);\n\n logger.debug(`making binary executable: ${binaryPath}`);\n await fsp.chmod(binaryPath, 0o755);\n\n logger.info(`Micromamba downloaded to: ${binaryPath}`);\n return binaryPath;\n}\n\n/**\n * Get correct asset name with micromamba binary for particular platform,\n * as they are available in micromamba-releases repo.\n */\nfunction micromambaAssetName(platform: util.PlatformType): string {\n const { os, arch } = util.splitPlatform(platform);\n switch (os) {\n case \"linux\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-linux-64\";\n case \"aarch64\":\n return \"micromamba-linux-aarch64\";\n default:\n util.assertNever(arch);\n }\n break;\n }\n case \"macosx\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-osx-64\";\n case \"aarch64\":\n return \"micromamba-osx-arm64\";\n default:\n util.assertNever(arch);\n }\n break;\n }\n case \"windows\": {\n switch (arch) {\n case \"x64\":\n return \"micromamba-win-64\";\n case \"aarch64\":\n throw new Error(\"Micromamba does not support ARM64 on Windows\");\n default:\n util.assertNever(arch);\n }\n break;\n }\n default:\n util.assertNever(os);\n }\n throw new Error(\"calm down linter, this code is unreachable\");\n}\n\n/**\n * Downloads a file from URL to local path\n */\nasync function downloadFile(\n logger: winston.Logger,\n url: string,\n outputPath: string,\n): Promise<void> {\n type responseInfo = {\n statusCode: number;\n body: NodeJS.ReadableStream;\n location: string;\n };\n\n let response: responseInfo;\n const maxRedirects = 5;\n const maxAttempts = 3;\n\n let redirCount = 0;\n let attempt = 0;\n for (; attempt <= maxAttempts; ) {\n attempt++;\n\n logger.debug(`Trying to download: ${url}`);\n try {\n const requestResult = await undici.request(url, {\n method: \"GET\",\n });\n response = {\n statusCode: requestResult.statusCode,\n location: requestResult.headers[\"location\"]?.toString() ?? \"\",\n body: requestResult.body,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to make request: ${errorMessage}`);\n }\n\n if (response.statusCode === 301 || response.statusCode === 302) {\n if (redirCount >= maxRedirects) {\n throw new Error(`Too many redirects: ${redirCount}, last location: ${response.location}`);\n }\n\n logger.debug(`Processing redirect. New location: ${response.location}`);\n redirCount++;\n url = response.location;\n continue;\n }\n\n if (response.statusCode === 200) {\n break;\n }\n\n logger.error(`Failed to download: ${response.statusCode}, attempt ${attempt}`);\n }\n\n if (response!.statusCode !== 200) {\n throw new Error(`Failed to download: last attempt status code: ${response!.statusCode}`);\n }\n\n const fileStream = fs.createWriteStream(outputPath);\n\n response!.body.pipe(fileStream);\n\n return new Promise((resolve, reject) => {\n fileStream.on(\"finish\", () => {\n fileStream.close();\n resolve();\n });\n\n fileStream.on(\"error\", (err) => {\n fs.unlink(outputPath, () => {}); // Delete the file on error\n reject(err);\n });\n });\n}\n"],"mappings":";;;;;;;AASA,MAAM,yBAAyB;AA0C/B,IAAa,aAAb,MAAwB;CAEH;CACA;CACA;CACA;CAJnB,YACE,QACA,YACA,gBAAyC,UACzC,aAAsC,IACtC;EAJiB,KAAA,SAAA;EACA,KAAA,aAAA;EACA,KAAA,gBAAA;EACA,KAAA,aAAA;EAEjB,IAAI,CAAC,YACH,KAAK,aAAa,KAAK,KAAK,YAAY,YAAY;EAGtD,IAAIA,UAAe,MAAM,aAAa,CAAC,KAAK,WAAW,SAAS,MAAM,GACpE,KAAK,cAAc;CAEvB;CAEA,MAAa,iBAAgC;EAC3C,IAAI,GAAG,WAAW,KAAK,UAAU,GAC/B,IAAI;GACF,MAAM,IAAI,OAAO,KAAK,YAAY,GAAG,UAAU,IAAI;GACnD,KAAK,OAAO,MACV,sBAAsB,KAAK,WAAW,8CACxC;GACA;EACF,QAAQ;GACN,KAAK,OAAO,MACV,sCAAsC,KAAK,WAAW,qBACxD;GACA,MAAM,IAAI,MAAM,KAAK,YAAY,GAAK;EACxC;EAGF,MAAM,mBAAmB,KAAK,QAAQ;GACpC,UAAUC,gBAAqB;GAC/B,YAAY,KAAK;GACjB,SAAS,KAAK;EAChB,CAAC;CACH;CAEA,aAA4B;EAC1B,OAAO,KAAK,SAAS,CAAC,WAAW,CAAC;CACpC;CAEA,kBAAyB,MAA8B;EACrD,MAAM,EAAE,iBAAiB,mBAAmB,aAAa;EACzD,KAAK,OAAO,MACV,+BAA+B,mBAAmB,qBAAqB,uBAAuB,KAChG;EAEA,MAAM,OAAO;GAAC;GAAO;GAAU;GAAU;GAAU;EAAO;EAC1D,IAAI,mBACF,KAAK,KAAK,YAAY,iBAAiB;OAClC,IAAI,iBACT,KAAK,KAAK,UAAU,eAAe;OAEnC,KAAK,KAAK,UAAU,sBAAsB;EAG5C,KAAK,SAAS,MAAM,EAClB,OAAO,UACT,CAAC;CACH;CAaA,kBAAyB,MAAuC;EAC9D,MAAM,EAAE,iBAAiB,mBAAmB,MAAM,eAAe;EACjE,KAAK,OAAO,MACV,gCAAgC,mBAAmB,qBAAqB,uBAAuB,KACjG;EAEA,MAAM,OAAO,aAAa,GAAG,SAAS,YAAY,GAAG,IAAI;EAEzD,MAAM,OAAO,CAAC,OAAO,QAAQ;EAC7B,IAAI,mBACF,KAAK,KAAK,YAAY,iBAAiB;OAClC,IAAI,iBACT,KAAK,KAAK,UAAU,eAAe;OAEnC,KAAK,KAAK,UAAU,sBAAsB;EAE5C,IAAI,MACF,KAAK,KAAK,QAAQ;EAGpB,IAAI;GACF,MAAM,UAAU,KAAK,SAAS,MAAM,EAClC,OAAO;IAAC;IAAW;IAAM;GAAS,EACpC,CAAC;GAED,IAAI,CAAC,YACH,OAAO;EAEX,SAAS,OAAO;GACd,IAAI,SAAS,QACX,GAAG,UAAU,IAAI;GAEnB,IAAI,YACF,GAAG,OAAO,YAAY,EAAE,OAAO,KAAK,CAAC;GAEvC,MAAM;EACR;EAEA,IAAI,SAAS,QACX,GAAG,UAAU,IAAI;CAErB;CAEA,kBAAyB,MAA8B;EACrD,MAAM,EAAE,iBAAiB,sBAAsB;EAE/C,IAAI,mBAAmB;GACrB,KAAK,OAAO,MACV,+BAA+B,mBAAmB,qBAAqB,uBAAuB,KAChG;GACA,GAAG,OAAO,mBAAmB,EAAE,WAAW,KAAK,CAAC;GAChD;EACF;EAEA,MAAM,SAAS,KAAK,kBAAkB;GAAE;GAAiB;GAAmB,MAAM;EAAK,CAAC;EACxF,MAAM,UAAU,KAAK,MAAM,UAAU,IAAI;EAEzC,IAAI,QAAQ,QAAQ;GAClB,KAAK,OAAO,MACV,+BAA+B,mBAAmB,qBAAqB,uBAAuB,KAChG;GACA,GAAG,OAAO,QAAQ,QAAkB,EAAE,WAAW,KAAK,CAAC;EACzD,OAAO;GACL,MAAM,SACJ;GACF,KAAK,OAAO,MAAM,MAAM;GACxB,MAAM,IAAI,MAAM,MAAM;EACxB;CACF;CAGA,SAAiB,MAAgB,MAAwC;EACvE,KAAK,OAAO,MAAM,yBAAyB,KAAK,WAAW,GAAG,KAAK,KAAK,GAAG,GAAG;EAE9E,MAAM,SAAS,UAAU,KAAK,YAAY,MAAM;GAC9C,UAAU;GACV,OAAO;GACP,GAAG;GACH,KAAK;IACH,GAAG,QAAQ;IACX,mBAAmB,KAAK;IACxB,iBAAiB,KAAK,KAAK,KAAK,YAAY,MAAM;IAClD,GAAG,MAAM;GACX;EACF,CAAC;EAED,IAAI,OAAO,OACT,MAAM,IAAI,MAAM,qCAAqC,OAAO,MAAM,SAAS;EAG7E,IAAI,OAAO,WAAW,GAAG;GACvB,MAAM,SAAS,yCAAyC,OAAO,OAAO,IAAI,OAAO,QAAQ,SAAS,CAAC,CAAC,KAAK,KAAK;GAC9G,KAAK,OAAO,MAAM,MAAM;GACxB,MAAM,IAAI,MAAM,MAAM;EACxB;EAEA,IAAI,CAAC,OAAO,QACV;EAGF,OAAO,OAAO,OAAO,SAAS,CAAC,CAAC,KAAK;CACvC;AACF;AAEA,SAAgB,sBAAsB,SAAiB,UAAqC;CAC1F,OAAO,YAAY,WACf,6EAA6E,oBAAoB,QAAQ,MACzG,sEAAsE,QAAQ,GAAG,oBAAoB,QAAQ;AACnH;;;;AAKA,eAAsB,mBACpB,QACA,SACiB;CACjB,MAAM,EAAE,UAAU,UAAU,UAAU,eAAe;CAErD,MAAM,iBAAiB,YAAYA,gBAAqB;CACxD,MAAM,aAAa;CAEnB,OAAO,MAAM,kCAAkC,QAAQ,gBAAgB,gBAAgB;CAEvF,MAAM,cAAc,sBAAsB,SAAS,cAAc;CAEjE,OAAO,MAAM,iBAAiB,aAAa;CAE3C,MAAM,aAAa,QAAQ,aAAa,UAAU;CAElD,OAAO,MAAM,6BAA6B,YAAY;CACtD,MAAM,IAAI,MAAM,YAAY,GAAK;CAEjC,OAAO,KAAK,6BAA6B,YAAY;CACrD,OAAO;AACT;;;;;AAMA,SAAS,oBAAoB,UAAqC;CAChE,MAAM,EAAE,IAAI,SAASC,cAAmB,QAAQ;CAChD,QAAQ,IAAR;EACE,KAAK;GACH,QAAQ,MAAR;IACE,KAAK,OACH,OAAO;IACT,KAAK,WACH,OAAO;IACT,SACE,YAAiB,IAAI;GACzB;GACA;EAEF,KAAK;GACH,QAAQ,MAAR;IACE,KAAK,OACH,OAAO;IACT,KAAK,WACH,OAAO;IACT,SACE,YAAiB,IAAI;GACzB;GACA;EAEF,KAAK;GACH,QAAQ,MAAR;IACE,KAAK,OACH,OAAO;IACT,KAAK,WACH,MAAM,IAAI,MAAM,8CAA8C;IAChE,SACE,YAAiB,IAAI;GACzB;GACA;EAEF,SACE,YAAiB,EAAE;CACvB;CACA,MAAM,IAAI,MAAM,4CAA4C;AAC9D;;;;AAKA,eAAe,aACb,QACA,KACA,YACe;CAOf,IAAI;CACJ,MAAM,eAAe;CACrB,MAAM,cAAc;CAEpB,IAAI,aAAa;CACjB,IAAI,UAAU;CACd,OAAO,WAAW,cAAe;EAC/B;EAEA,OAAO,MAAM,uBAAuB,KAAK;EACzC,IAAI;GACF,MAAM,gBAAgB,MAAM,OAAO,QAAQ,KAAK,EAC9C,QAAQ,MACV,CAAC;GACD,WAAW;IACT,YAAY,cAAc;IAC1B,UAAU,cAAc,QAAQ,WAAW,EAAE,SAAS,KAAK;IAC3D,MAAM,cAAc;GACtB;EACF,SAAS,OAAO;GACd,MAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAC1E,MAAM,IAAI,MAAM,2BAA2B,cAAc;EAC3D;EAEA,IAAI,SAAS,eAAe,OAAO,SAAS,eAAe,KAAK;GAC9D,IAAI,cAAc,cAChB,MAAM,IAAI,MAAM,uBAAuB,WAAW,mBAAmB,SAAS,UAAU;GAG1F,OAAO,MAAM,sCAAsC,SAAS,UAAU;GACtE;GACA,MAAM,SAAS;GACf;EACF;EAEA,IAAI,SAAS,eAAe,KAC1B;EAGF,OAAO,MAAM,uBAAuB,SAAS,WAAW,YAAY,SAAS;CAC/E;CAEA,IAAI,SAAU,eAAe,KAC3B,MAAM,IAAI,MAAM,iDAAiD,SAAU,YAAY;CAGzF,MAAM,aAAa,GAAG,kBAAkB,UAAU;CAElD,SAAU,KAAK,KAAK,UAAU;CAE9B,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,WAAW,GAAG,gBAAgB;GAC5B,WAAW,MAAM;GACjB,QAAQ;EACV,CAAC;EAED,WAAW,GAAG,UAAU,QAAQ;GAC9B,GAAG,OAAO,kBAAkB,CAAC,CAAC;GAC9B,OAAO,GAAG;EACZ,CAAC;CACH,CAAC;AACH"}
@@ -1,8 +1,8 @@
1
1
  const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
2
2
  let node_fs = require("node:fs");
3
- node_fs = require_runtime.__toESM(node_fs);
3
+ node_fs = require_runtime.__toESM(node_fs, 1);
4
4
  let yaml = require("yaml");
5
- yaml = require_runtime.__toESM(yaml);
5
+ yaml = require_runtime.__toESM(yaml, 1);
6
6
  //#region src/core/conda/validate-spec.ts
7
7
  /**
8
8
  * Channels that are forbidden because they reference the official Anaconda channel.
@@ -1 +1 @@
1
- {"version":3,"file":"validate-spec.cjs","names":["fs"],"sources":["../../../src/core/conda/validate-spec.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport yaml from \"yaml\";\nimport type winston from \"winston\";\n\nexport interface CondaSpec {\n channels?: string[];\n dependencies?: (string | Record<string, unknown>)[];\n name?: string;\n prefix?: string;\n [key: string]: unknown;\n}\n\n/**\n * Channels that are forbidden because they reference the official Anaconda channel.\n * These channels (main, r, msys2, defaults, anaconda) should be avoided in favor of\n * community-maintained channels like conda-forge to avoid licensing restrictions\n */\nconst FORBIDDEN_CHANNELS = [\"main\", \"r\", \"msys2\", \"defaults\", \"anaconda\"];\n\n/**\n * Validates a conda spec file to ensure it doesn't use forbidden channels\n * @param logger Winston logger instance\n * @param specPath Path to the conda spec file\n * @throws Error if forbidden channels are found\n */\nexport function validateCondaSpec(logger: winston.Logger, specPath: string): void {\n logger.debug(`Validating conda spec file: ${specPath}`);\n\n if (!fs.existsSync(specPath)) {\n throw new Error(`Conda spec file not found: ${specPath}`);\n }\n\n const specContent = fs.readFileSync(specPath, \"utf-8\");\n const spec = yaml.parse(specContent) as CondaSpec;\n\n if (!spec || typeof spec !== \"object\") {\n throw new Error(`Invalid conda spec file format: ${specPath}`);\n }\n\n const errors: string[] = [];\n\n if (spec.channels) {\n const channelErrors = validateChannels(spec.channels);\n if (channelErrors.length > 0) {\n errors.push(...channelErrors);\n }\n }\n\n if (spec.dependencies) {\n const depErrors = validateDependencies(spec.dependencies);\n if (depErrors.length > 0) {\n errors.push(...depErrors);\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Conda spec file contains forbidden Anaconda channels:\\n${errors.join(\"\\n\")}`);\n }\n\n logger.debug(`Conda spec file validation passed: ${specPath}`);\n}\n\n/**\n * Validates that no forbidden channels are in the channels list\n * @param channels Array of channel names\n * @returns Array of error messages for forbidden channels\n */\nfunction validateChannels(channels: string[]): string[] {\n const errors: string[] = [];\n\n for (const channel of channels) {\n const channelLower = channel.toLowerCase().trim();\n if (FORBIDDEN_CHANNELS.includes(channelLower)) {\n errors.push(` - Forbidden channel '${channel}' in channels list`);\n }\n }\n\n return errors;\n}\n\n/**\n * Validates that no dependencies use forbidden channel prefixes\n * @param dependencies Array of dependencies (can be strings or objects)\n * @returns Array of error messages for forbidden dependencies\n */\nfunction validateDependencies(dependencies: (string | Record<string, unknown>)[]): string[] {\n const errors: string[] = [];\n\n for (const dep of dependencies) {\n // Skip non-string dependencies (they might be pip dependencies, etc.)\n if (typeof dep !== \"string\") {\n continue;\n }\n\n // Check if dependency uses channel prefix (format: channel::package)\n if (dep.includes(\"::\")) {\n const [channel, ..._packageParts] = dep.split(\"::\");\n const channelLower = channel.toLowerCase().trim();\n\n if (FORBIDDEN_CHANNELS.includes(channelLower)) {\n errors.push(` - Forbidden channel prefix '${channel}::' in dependency '${dep}'`);\n }\n }\n }\n\n return errors;\n}\n"],"mappings":";;;;;;;;;;;AAiBA,MAAM,qBAAqB;CAAC;CAAQ;CAAK;CAAS;CAAY;CAAW;;;;;;;AAQzE,SAAgB,kBAAkB,QAAwB,UAAwB;AAChF,QAAO,MAAM,+BAA+B,WAAW;AAEvD,KAAI,CAACA,QAAAA,QAAG,WAAW,SAAS,CAC1B,OAAM,IAAI,MAAM,8BAA8B,WAAW;CAG3D,MAAM,cAAcA,QAAAA,QAAG,aAAa,UAAU,QAAQ;CACtD,MAAM,OAAO,KAAA,QAAK,MAAM,YAAY;AAEpC,KAAI,CAAC,QAAQ,OAAO,SAAS,SAC3B,OAAM,IAAI,MAAM,mCAAmC,WAAW;CAGhE,MAAM,SAAmB,EAAE;AAE3B,KAAI,KAAK,UAAU;EACjB,MAAM,gBAAgB,iBAAiB,KAAK,SAAS;AACrD,MAAI,cAAc,SAAS,EACzB,QAAO,KAAK,GAAG,cAAc;;AAIjC,KAAI,KAAK,cAAc;EACrB,MAAM,YAAY,qBAAqB,KAAK,aAAa;AACzD,MAAI,UAAU,SAAS,EACrB,QAAO,KAAK,GAAG,UAAU;;AAI7B,KAAI,OAAO,SAAS,EAClB,OAAM,IAAI,MAAM,0DAA0D,OAAO,KAAK,KAAK,GAAG;AAGhG,QAAO,MAAM,sCAAsC,WAAW;;;;;;;AAQhE,SAAS,iBAAiB,UAA8B;CACtD,MAAM,SAAmB,EAAE;AAE3B,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,eAAe,QAAQ,aAAa,CAAC,MAAM;AACjD,MAAI,mBAAmB,SAAS,aAAa,CAC3C,QAAO,KAAK,0BAA0B,QAAQ,oBAAoB;;AAItE,QAAO;;;;;;;AAQT,SAAS,qBAAqB,cAA8D;CAC1F,MAAM,SAAmB,EAAE;AAE3B,MAAK,MAAM,OAAO,cAAc;AAE9B,MAAI,OAAO,QAAQ,SACjB;AAIF,MAAI,IAAI,SAAS,KAAK,EAAE;GACtB,MAAM,CAAC,SAAS,GAAG,iBAAiB,IAAI,MAAM,KAAK;GACnD,MAAM,eAAe,QAAQ,aAAa,CAAC,MAAM;AAEjD,OAAI,mBAAmB,SAAS,aAAa,CAC3C,QAAO,KAAK,iCAAiC,QAAQ,qBAAqB,IAAI,GAAG;;;AAKvF,QAAO"}
1
+ {"version":3,"file":"validate-spec.cjs","names":["fs"],"sources":["../../../src/core/conda/validate-spec.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport yaml from \"yaml\";\nimport type winston from \"winston\";\n\nexport interface CondaSpec {\n channels?: string[];\n dependencies?: (string | Record<string, unknown>)[];\n name?: string;\n prefix?: string;\n [key: string]: unknown;\n}\n\n/**\n * Channels that are forbidden because they reference the official Anaconda channel.\n * These channels (main, r, msys2, defaults, anaconda) should be avoided in favor of\n * community-maintained channels like conda-forge to avoid licensing restrictions\n */\nconst FORBIDDEN_CHANNELS = [\"main\", \"r\", \"msys2\", \"defaults\", \"anaconda\"];\n\n/**\n * Validates a conda spec file to ensure it doesn't use forbidden channels\n * @param logger Winston logger instance\n * @param specPath Path to the conda spec file\n * @throws Error if forbidden channels are found\n */\nexport function validateCondaSpec(logger: winston.Logger, specPath: string): void {\n logger.debug(`Validating conda spec file: ${specPath}`);\n\n if (!fs.existsSync(specPath)) {\n throw new Error(`Conda spec file not found: ${specPath}`);\n }\n\n const specContent = fs.readFileSync(specPath, \"utf-8\");\n const spec = yaml.parse(specContent) as CondaSpec;\n\n if (!spec || typeof spec !== \"object\") {\n throw new Error(`Invalid conda spec file format: ${specPath}`);\n }\n\n const errors: string[] = [];\n\n if (spec.channels) {\n const channelErrors = validateChannels(spec.channels);\n if (channelErrors.length > 0) {\n errors.push(...channelErrors);\n }\n }\n\n if (spec.dependencies) {\n const depErrors = validateDependencies(spec.dependencies);\n if (depErrors.length > 0) {\n errors.push(...depErrors);\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Conda spec file contains forbidden Anaconda channels:\\n${errors.join(\"\\n\")}`);\n }\n\n logger.debug(`Conda spec file validation passed: ${specPath}`);\n}\n\n/**\n * Validates that no forbidden channels are in the channels list\n * @param channels Array of channel names\n * @returns Array of error messages for forbidden channels\n */\nfunction validateChannels(channels: string[]): string[] {\n const errors: string[] = [];\n\n for (const channel of channels) {\n const channelLower = channel.toLowerCase().trim();\n if (FORBIDDEN_CHANNELS.includes(channelLower)) {\n errors.push(` - Forbidden channel '${channel}' in channels list`);\n }\n }\n\n return errors;\n}\n\n/**\n * Validates that no dependencies use forbidden channel prefixes\n * @param dependencies Array of dependencies (can be strings or objects)\n * @returns Array of error messages for forbidden dependencies\n */\nfunction validateDependencies(dependencies: (string | Record<string, unknown>)[]): string[] {\n const errors: string[] = [];\n\n for (const dep of dependencies) {\n // Skip non-string dependencies (they might be pip dependencies, etc.)\n if (typeof dep !== \"string\") {\n continue;\n }\n\n // Check if dependency uses channel prefix (format: channel::package)\n if (dep.includes(\"::\")) {\n const [channel, ..._packageParts] = dep.split(\"::\");\n const channelLower = channel.toLowerCase().trim();\n\n if (FORBIDDEN_CHANNELS.includes(channelLower)) {\n errors.push(` - Forbidden channel prefix '${channel}::' in dependency '${dep}'`);\n }\n }\n }\n\n return errors;\n}\n"],"mappings":";;;;;;;;;;;AAiBA,MAAM,qBAAqB;CAAC;CAAQ;CAAK;CAAS;CAAY;AAAU;;;;;;;AAQxE,SAAgB,kBAAkB,QAAwB,UAAwB;CAChF,OAAO,MAAM,+BAA+B,UAAU;CAEtD,IAAI,CAACA,QAAAA,QAAG,WAAW,QAAQ,GACzB,MAAM,IAAI,MAAM,8BAA8B,UAAU;CAG1D,MAAM,cAAcA,QAAAA,QAAG,aAAa,UAAU,OAAO;CACrD,MAAM,OAAO,KAAA,QAAK,MAAM,WAAW;CAEnC,IAAI,CAAC,QAAQ,OAAO,SAAS,UAC3B,MAAM,IAAI,MAAM,mCAAmC,UAAU;CAG/D,MAAM,SAAmB,CAAC;CAE1B,IAAI,KAAK,UAAU;EACjB,MAAM,gBAAgB,iBAAiB,KAAK,QAAQ;EACpD,IAAI,cAAc,SAAS,GACzB,OAAO,KAAK,GAAG,aAAa;CAEhC;CAEA,IAAI,KAAK,cAAc;EACrB,MAAM,YAAY,qBAAqB,KAAK,YAAY;EACxD,IAAI,UAAU,SAAS,GACrB,OAAO,KAAK,GAAG,SAAS;CAE5B;CAEA,IAAI,OAAO,SAAS,GAClB,MAAM,IAAI,MAAM,0DAA0D,OAAO,KAAK,IAAI,GAAG;CAG/F,OAAO,MAAM,sCAAsC,UAAU;AAC/D;;;;;;AAOA,SAAS,iBAAiB,UAA8B;CACtD,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,eAAe,QAAQ,YAAY,CAAC,CAAC,KAAK;EAChD,IAAI,mBAAmB,SAAS,YAAY,GAC1C,OAAO,KAAK,0BAA0B,QAAQ,mBAAmB;CAErE;CAEA,OAAO;AACT;;;;;;AAOA,SAAS,qBAAqB,cAA8D;CAC1F,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,OAAO,cAAc;EAE9B,IAAI,OAAO,QAAQ,UACjB;EAIF,IAAI,IAAI,SAAS,IAAI,GAAG;GACtB,MAAM,CAAC,SAAS,GAAG,iBAAiB,IAAI,MAAM,IAAI;GAClD,MAAM,eAAe,QAAQ,YAAY,CAAC,CAAC,KAAK;GAEhD,IAAI,mBAAmB,SAAS,YAAY,GAC1C,OAAO,KAAK,iCAAiC,QAAQ,qBAAqB,IAAI,EAAE;EAEpF;CACF;CAEA,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate-spec.js","names":[],"sources":["../../../src/core/conda/validate-spec.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport yaml from \"yaml\";\nimport type winston from \"winston\";\n\nexport interface CondaSpec {\n channels?: string[];\n dependencies?: (string | Record<string, unknown>)[];\n name?: string;\n prefix?: string;\n [key: string]: unknown;\n}\n\n/**\n * Channels that are forbidden because they reference the official Anaconda channel.\n * These channels (main, r, msys2, defaults, anaconda) should be avoided in favor of\n * community-maintained channels like conda-forge to avoid licensing restrictions\n */\nconst FORBIDDEN_CHANNELS = [\"main\", \"r\", \"msys2\", \"defaults\", \"anaconda\"];\n\n/**\n * Validates a conda spec file to ensure it doesn't use forbidden channels\n * @param logger Winston logger instance\n * @param specPath Path to the conda spec file\n * @throws Error if forbidden channels are found\n */\nexport function validateCondaSpec(logger: winston.Logger, specPath: string): void {\n logger.debug(`Validating conda spec file: ${specPath}`);\n\n if (!fs.existsSync(specPath)) {\n throw new Error(`Conda spec file not found: ${specPath}`);\n }\n\n const specContent = fs.readFileSync(specPath, \"utf-8\");\n const spec = yaml.parse(specContent) as CondaSpec;\n\n if (!spec || typeof spec !== \"object\") {\n throw new Error(`Invalid conda spec file format: ${specPath}`);\n }\n\n const errors: string[] = [];\n\n if (spec.channels) {\n const channelErrors = validateChannels(spec.channels);\n if (channelErrors.length > 0) {\n errors.push(...channelErrors);\n }\n }\n\n if (spec.dependencies) {\n const depErrors = validateDependencies(spec.dependencies);\n if (depErrors.length > 0) {\n errors.push(...depErrors);\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Conda spec file contains forbidden Anaconda channels:\\n${errors.join(\"\\n\")}`);\n }\n\n logger.debug(`Conda spec file validation passed: ${specPath}`);\n}\n\n/**\n * Validates that no forbidden channels are in the channels list\n * @param channels Array of channel names\n * @returns Array of error messages for forbidden channels\n */\nfunction validateChannels(channels: string[]): string[] {\n const errors: string[] = [];\n\n for (const channel of channels) {\n const channelLower = channel.toLowerCase().trim();\n if (FORBIDDEN_CHANNELS.includes(channelLower)) {\n errors.push(` - Forbidden channel '${channel}' in channels list`);\n }\n }\n\n return errors;\n}\n\n/**\n * Validates that no dependencies use forbidden channel prefixes\n * @param dependencies Array of dependencies (can be strings or objects)\n * @returns Array of error messages for forbidden dependencies\n */\nfunction validateDependencies(dependencies: (string | Record<string, unknown>)[]): string[] {\n const errors: string[] = [];\n\n for (const dep of dependencies) {\n // Skip non-string dependencies (they might be pip dependencies, etc.)\n if (typeof dep !== \"string\") {\n continue;\n }\n\n // Check if dependency uses channel prefix (format: channel::package)\n if (dep.includes(\"::\")) {\n const [channel, ..._packageParts] = dep.split(\"::\");\n const channelLower = channel.toLowerCase().trim();\n\n if (FORBIDDEN_CHANNELS.includes(channelLower)) {\n errors.push(` - Forbidden channel prefix '${channel}::' in dependency '${dep}'`);\n }\n }\n }\n\n return errors;\n}\n"],"mappings":";;;;;;;;AAiBA,MAAM,qBAAqB;CAAC;CAAQ;CAAK;CAAS;CAAY;CAAW;;;;;;;AAQzE,SAAgB,kBAAkB,QAAwB,UAAwB;AAChF,QAAO,MAAM,+BAA+B,WAAW;AAEvD,KAAI,CAAC,GAAG,WAAW,SAAS,CAC1B,OAAM,IAAI,MAAM,8BAA8B,WAAW;CAG3D,MAAM,cAAc,GAAG,aAAa,UAAU,QAAQ;CACtD,MAAM,OAAO,KAAK,MAAM,YAAY;AAEpC,KAAI,CAAC,QAAQ,OAAO,SAAS,SAC3B,OAAM,IAAI,MAAM,mCAAmC,WAAW;CAGhE,MAAM,SAAmB,EAAE;AAE3B,KAAI,KAAK,UAAU;EACjB,MAAM,gBAAgB,iBAAiB,KAAK,SAAS;AACrD,MAAI,cAAc,SAAS,EACzB,QAAO,KAAK,GAAG,cAAc;;AAIjC,KAAI,KAAK,cAAc;EACrB,MAAM,YAAY,qBAAqB,KAAK,aAAa;AACzD,MAAI,UAAU,SAAS,EACrB,QAAO,KAAK,GAAG,UAAU;;AAI7B,KAAI,OAAO,SAAS,EAClB,OAAM,IAAI,MAAM,0DAA0D,OAAO,KAAK,KAAK,GAAG;AAGhG,QAAO,MAAM,sCAAsC,WAAW;;;;;;;AAQhE,SAAS,iBAAiB,UAA8B;CACtD,MAAM,SAAmB,EAAE;AAE3B,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,eAAe,QAAQ,aAAa,CAAC,MAAM;AACjD,MAAI,mBAAmB,SAAS,aAAa,CAC3C,QAAO,KAAK,0BAA0B,QAAQ,oBAAoB;;AAItE,QAAO;;;;;;;AAQT,SAAS,qBAAqB,cAA8D;CAC1F,MAAM,SAAmB,EAAE;AAE3B,MAAK,MAAM,OAAO,cAAc;AAE9B,MAAI,OAAO,QAAQ,SACjB;AAIF,MAAI,IAAI,SAAS,KAAK,EAAE;GACtB,MAAM,CAAC,SAAS,GAAG,iBAAiB,IAAI,MAAM,KAAK;GACnD,MAAM,eAAe,QAAQ,aAAa,CAAC,MAAM;AAEjD,OAAI,mBAAmB,SAAS,aAAa,CAC3C,QAAO,KAAK,iCAAiC,QAAQ,qBAAqB,IAAI,GAAG;;;AAKvF,QAAO"}
1
+ {"version":3,"file":"validate-spec.js","names":[],"sources":["../../../src/core/conda/validate-spec.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport yaml from \"yaml\";\nimport type winston from \"winston\";\n\nexport interface CondaSpec {\n channels?: string[];\n dependencies?: (string | Record<string, unknown>)[];\n name?: string;\n prefix?: string;\n [key: string]: unknown;\n}\n\n/**\n * Channels that are forbidden because they reference the official Anaconda channel.\n * These channels (main, r, msys2, defaults, anaconda) should be avoided in favor of\n * community-maintained channels like conda-forge to avoid licensing restrictions\n */\nconst FORBIDDEN_CHANNELS = [\"main\", \"r\", \"msys2\", \"defaults\", \"anaconda\"];\n\n/**\n * Validates a conda spec file to ensure it doesn't use forbidden channels\n * @param logger Winston logger instance\n * @param specPath Path to the conda spec file\n * @throws Error if forbidden channels are found\n */\nexport function validateCondaSpec(logger: winston.Logger, specPath: string): void {\n logger.debug(`Validating conda spec file: ${specPath}`);\n\n if (!fs.existsSync(specPath)) {\n throw new Error(`Conda spec file not found: ${specPath}`);\n }\n\n const specContent = fs.readFileSync(specPath, \"utf-8\");\n const spec = yaml.parse(specContent) as CondaSpec;\n\n if (!spec || typeof spec !== \"object\") {\n throw new Error(`Invalid conda spec file format: ${specPath}`);\n }\n\n const errors: string[] = [];\n\n if (spec.channels) {\n const channelErrors = validateChannels(spec.channels);\n if (channelErrors.length > 0) {\n errors.push(...channelErrors);\n }\n }\n\n if (spec.dependencies) {\n const depErrors = validateDependencies(spec.dependencies);\n if (depErrors.length > 0) {\n errors.push(...depErrors);\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Conda spec file contains forbidden Anaconda channels:\\n${errors.join(\"\\n\")}`);\n }\n\n logger.debug(`Conda spec file validation passed: ${specPath}`);\n}\n\n/**\n * Validates that no forbidden channels are in the channels list\n * @param channels Array of channel names\n * @returns Array of error messages for forbidden channels\n */\nfunction validateChannels(channels: string[]): string[] {\n const errors: string[] = [];\n\n for (const channel of channels) {\n const channelLower = channel.toLowerCase().trim();\n if (FORBIDDEN_CHANNELS.includes(channelLower)) {\n errors.push(` - Forbidden channel '${channel}' in channels list`);\n }\n }\n\n return errors;\n}\n\n/**\n * Validates that no dependencies use forbidden channel prefixes\n * @param dependencies Array of dependencies (can be strings or objects)\n * @returns Array of error messages for forbidden dependencies\n */\nfunction validateDependencies(dependencies: (string | Record<string, unknown>)[]): string[] {\n const errors: string[] = [];\n\n for (const dep of dependencies) {\n // Skip non-string dependencies (they might be pip dependencies, etc.)\n if (typeof dep !== \"string\") {\n continue;\n }\n\n // Check if dependency uses channel prefix (format: channel::package)\n if (dep.includes(\"::\")) {\n const [channel, ..._packageParts] = dep.split(\"::\");\n const channelLower = channel.toLowerCase().trim();\n\n if (FORBIDDEN_CHANNELS.includes(channelLower)) {\n errors.push(` - Forbidden channel prefix '${channel}::' in dependency '${dep}'`);\n }\n }\n }\n\n return errors;\n}\n"],"mappings":";;;;;;;;AAiBA,MAAM,qBAAqB;CAAC;CAAQ;CAAK;CAAS;CAAY;AAAU;;;;;;;AAQxE,SAAgB,kBAAkB,QAAwB,UAAwB;CAChF,OAAO,MAAM,+BAA+B,UAAU;CAEtD,IAAI,CAAC,GAAG,WAAW,QAAQ,GACzB,MAAM,IAAI,MAAM,8BAA8B,UAAU;CAG1D,MAAM,cAAc,GAAG,aAAa,UAAU,OAAO;CACrD,MAAM,OAAO,KAAK,MAAM,WAAW;CAEnC,IAAI,CAAC,QAAQ,OAAO,SAAS,UAC3B,MAAM,IAAI,MAAM,mCAAmC,UAAU;CAG/D,MAAM,SAAmB,CAAC;CAE1B,IAAI,KAAK,UAAU;EACjB,MAAM,gBAAgB,iBAAiB,KAAK,QAAQ;EACpD,IAAI,cAAc,SAAS,GACzB,OAAO,KAAK,GAAG,aAAa;CAEhC;CAEA,IAAI,KAAK,cAAc;EACrB,MAAM,YAAY,qBAAqB,KAAK,YAAY;EACxD,IAAI,UAAU,SAAS,GACrB,OAAO,KAAK,GAAG,SAAS;CAE5B;CAEA,IAAI,OAAO,SAAS,GAClB,MAAM,IAAI,MAAM,0DAA0D,OAAO,KAAK,IAAI,GAAG;CAG/F,OAAO,MAAM,sCAAsC,UAAU;AAC/D;;;;;;AAOA,SAAS,iBAAiB,UAA8B;CACtD,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,eAAe,QAAQ,YAAY,CAAC,CAAC,KAAK;EAChD,IAAI,mBAAmB,SAAS,YAAY,GAC1C,OAAO,KAAK,0BAA0B,QAAQ,mBAAmB;CAErE;CAEA,OAAO;AACT;;;;;;AAOA,SAAS,qBAAqB,cAA8D;CAC1F,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,OAAO,cAAc;EAE9B,IAAI,OAAO,QAAQ,UACjB;EAIF,IAAI,IAAI,SAAS,IAAI,GAAG;GACtB,MAAM,CAAC,SAAS,GAAG,iBAAiB,IAAI,MAAM,IAAI;GAClD,MAAM,eAAe,QAAQ,YAAY,CAAC,CAAC,KAAK;GAEhD,IAAI,mBAAmB,SAAS,YAAY,GAC1C,OAAO,KAAK,iCAAiC,QAAQ,qBAAqB,IAAI,EAAE;EAEpF;CACF;CAEA,OAAO;AACT"}
@@ -11,29 +11,33 @@ const require_sw_json_render = require("./sw-json-render.cjs");
11
11
  const require_archive = require("./archive.cjs");
12
12
  const require_storage = require("./storage.cjs");
13
13
  let node_fs = require("node:fs");
14
- node_fs = require_runtime.__toESM(node_fs);
14
+ node_fs = require_runtime.__toESM(node_fs, 1);
15
15
  let node_fs_promises = require("node:fs/promises");
16
- node_fs_promises = require_runtime.__toESM(node_fs_promises);
16
+ node_fs_promises = require_runtime.__toESM(node_fs_promises, 1);
17
17
  let node_path = require("node:path");
18
- node_path = require_runtime.__toESM(node_path);
18
+ node_path = require_runtime.__toESM(node_path, 1);
19
19
  let yaml = require("yaml");
20
- yaml = require_runtime.__toESM(yaml);
20
+ yaml = require_runtime.__toESM(yaml, 1);
21
21
  //#region src/core/core.ts
22
22
  var Core = class {
23
23
  logger;
24
24
  _entrypoints;
25
25
  _renderer;
26
26
  pkgInfo;
27
- buildMode;
28
27
  targetPlatform;
29
28
  allPlatforms = false;
30
29
  fullDirHash;
31
30
  constructor(logger, opts) {
32
31
  this.logger = logger;
33
32
  this.pkgInfo = opts?.pkgInfo ?? new require_package_info.PackageInfo(logger, { packageRoot: opts?.packageRoot });
34
- this.buildMode = "release";
35
33
  this.fullDirHash = false;
36
34
  }
35
+ get buildMode() {
36
+ return this.pkgInfo.buildMode;
37
+ }
38
+ set buildMode(mode) {
39
+ this.pkgInfo.buildMode = mode;
40
+ }
37
41
  set version(v) {
38
42
  this.pkgInfo.version = v;
39
43
  }
@@ -112,7 +116,7 @@ var Core = class {
112
116
  }
113
117
  let entrypoints = Array.from(this.entrypoints.entries());
114
118
  if (entrypointNames.length > 0) entrypoints = entrypoints.filter(([epName, _]) => entrypointNames.includes(epName));
115
- const infos = this.renderer.renderSoftwareEntrypoints(this.buildMode, new Map(entrypoints), {
119
+ const infos = options?.noSoftware ? this.renderer.renderPlaceholderEntrypoints(new Map(entrypoints)) : this.renderer.renderSoftwareEntrypoints(this.buildMode, new Map(entrypoints), {
116
120
  requireAllArtifacts: options?.requireAllArtifacts,
117
121
  fullDirHash: this.fullDirHash
118
122
  });
@@ -122,6 +126,22 @@ var Core = class {
122
126
  this.renderer.copySwJson(epName, srcPath);
123
127
  }
124
128
  }
129
+ writePublishedArtifactInfo(options) {
130
+ const platform = require_util.currentPlatform();
131
+ for (const [id, artifact] of this.buildablePackages) {
132
+ if (options?.ids && !options.ids.includes(id)) continue;
133
+ const locationKey = require_artifacts.isCrossPlatform(artifact.type) ? void 0 : platform;
134
+ const registry = this.pkgInfo.artifactRegistrySettings(artifact);
135
+ require_sw_json_render.writeBuiltArtifactInfo(this.pkgInfo.artifactInfoLocation(id, "archive", locationKey), {
136
+ type: artifact.type,
137
+ platform,
138
+ registryURL: registry.downloadURL,
139
+ registryName: registry.name,
140
+ remoteArtifactLocation: this.pkgInfo.artifactArchiveAddressPattern(artifact),
141
+ uploadPath: this.pkgInfo.artifactArchiveFullName(artifact, platform)
142
+ });
143
+ }
144
+ }
125
145
  async buildSoftwareArchives(options) {
126
146
  this.logger.info(`Building package archives...`);
127
147
  const packagesToBuild = options?.ids ?? Array.from(this.buildablePackages.keys());
@@ -167,7 +187,7 @@ var Core = class {
167
187
  else this.logger.debug(`Conda environment build was skipped.`);
168
188
  break;
169
189
  }
170
- if (require_util.isDevLocalMode(this.buildMode)) {
190
+ if (!require_util.producesRegistryDescriptor(this.buildMode)) {
171
191
  this.logger.info(` no need to build software archive in '${this.buildMode}' mode: archive build was skipped`);
172
192
  return;
173
193
  }
@@ -191,6 +211,7 @@ var Core = class {
191
211
  continue;
192
212
  }
193
213
  }
214
+ if (this.targetPlatform && require_util.splitPlatform(this.targetPlatform).arch !== "x64") throw require_util.CLIError(`cannot build docker image '${artifact.id}' for target '${this.targetPlatform}': docker software is built as ${require_defaults.DOCKER_BUILD_PLATFORM} only`);
194
215
  this.buildDockerImage(artifact.id, artifact, options?.registry);
195
216
  }
196
217
  }