Home Reference Source

cables_dev/cables_electron/src/export/export_zip_standalone.js

  1. import fs from "fs";
  2. import archiver from "archiver";
  3. import sanitizeFileName from "sanitize-filename";
  4. import { SharedExportService } from "cables-shared-api";
  5. import path from "path";
  6. import settings from "../electron/electron_settings.js";
  7. import electronApp from "../electron/main.js";
  8.  
  9. export default class StandaloneZipExport extends SharedExportService
  10. {
  11. constructor(provider)
  12. {
  13. super(provider, {});
  14. this.archive = archiver.create("zip", {});
  15.  
  16. this.options.hideMadeWithCables = true;
  17. this.options.combineJs = false;
  18. this.options.minify = false;
  19. this.options.handleAssets = "auto";
  20. this.options.rewriteAssetPorts = true;
  21. this.options.flattenAssetNames = true;
  22.  
  23. this.finalAssetPath = "/assets/";
  24. }
  25.  
  26. static getName()
  27. {
  28. return "zip";
  29. }
  30.  
  31. static getExportOptions(user, teams, project, exportQuota)
  32. {
  33. return {
  34. "type": this.getName(),
  35. "allowed": true,
  36. "possible": true,
  37. "fields": {}
  38. };
  39. }
  40.  
  41. doExport(projectId, cb)
  42. {
  43. this.collectFiles(
  44. projectId,
  45. this.createZip.bind(this),
  46. (collectErr, callbackError) =>
  47. {
  48. callbackError({ "msg": collectErr });
  49. },
  50. this.options,
  51. cb
  52. );
  53. }
  54.  
  55. /* private */
  56. createZip(project, files, callbackFinished)
  57. {
  58. const projectNameVer = sanitizeFileName(project.name).replace(/ /g, "_") + project.exports;
  59. const zipFileName = "cables_" + sanitizeFileName(projectNameVer) + ".zip";
  60. electronApp.exportProjectFileDialog(zipFileName).then((finalZipFileName) =>
  61. {
  62. if (finalZipFileName)
  63. {
  64. const output = fs.createWriteStream(finalZipFileName);
  65. this._log.info("finalZipFileName", finalZipFileName);
  66. output.on("close", () =>
  67. {
  68. this._log.info("exported file " + finalZipFileName + " / " + this.archive.pointer() / 1000000.0 + " mb");
  69.  
  70. const result = {};
  71. result.size = this.archive.pointer() / 1000000.0;
  72. result.path = finalZipFileName;
  73. result.log = this.exportLog;
  74. callbackFinished(result);
  75. });
  76.  
  77. output.on("error", (outputErr) =>
  78. {
  79. this._log.error("export error", outputErr);
  80. const result = { "error": outputErr };
  81. callbackFinished(result);
  82. });
  83.  
  84. this._log.info("finalize archive...", (Date.now() - this.startTimeExport) / 1000);
  85.  
  86. for (const [filename, content] of Object.entries(files))
  87. {
  88. const options = { "name": filename };
  89. if (filename === "/patch.app/Contents/MacOS/Electron")
  90. {
  91. options.mode = 0o777;
  92. }
  93. this.archive.append(content, options);
  94. }
  95.  
  96. this.archive.pipe(output);
  97. this.archive.finalize();
  98. }
  99. else
  100. {
  101. const outputErr = "no export directory chosen";
  102. const result = { "error": outputErr };
  103. callbackFinished(result);
  104. }
  105. });
  106. }
  107.  
  108. collectFiles(_projectId, callbackFilesCollected, callbackError, options, next)
  109. {
  110. const project = settings.getCurrentProject();
  111. this._log.info("...export");
  112. if (project)
  113. {
  114. options.handleAssets = options.handleAssets || "auto";
  115. this._exportProject(
  116. project,
  117. callbackFilesCollected,
  118. callbackError,
  119. options,
  120. next
  121. );
  122. }
  123. else
  124. {
  125. const err2 = "PROJECT_NOT_FOUND";
  126. callbackError(err2, (serviceResult) =>
  127. {
  128. next(serviceResult.msg, serviceResult);
  129. });
  130. }
  131. }
  132.  
  133. _getFilesForProjects(theProjects, options, cb)
  134. {
  135. const user = settings.getCurrentUser();
  136. if (!theProjects)
  137. {
  138. cb([]);
  139. return;
  140. }
  141. const theFiles = [];
  142. theProjects.forEach((project) =>
  143. {
  144. const assetFilenames = this._projectsUtil.getUsedAssetFilenames(project, true);
  145. assetFilenames.forEach((fileName) =>
  146. {
  147. const fileDb = this._filesUtil.getFileDb(fileName, user, project);
  148. theFiles.push(fileDb);
  149. });
  150. });
  151. cb(theFiles);
  152. }
  153.  
  154. _doAfterExport(originalProject)
  155. {
  156. return originalProject;
  157. }
  158.  
  159. _resolveFileName(filePathAndName, pathStr, project)
  160. {
  161. return this._helperUtil.fileURLToPath(filePathAndName, true);
  162. }
  163.  
  164. _getNameForZipEntry(fn, allFiles)
  165. {
  166. if (fn.substr(0, 1) === "/") fn = fn.substr(1);
  167. let fnNew = path.basename(fn);
  168. if (this.options.flattenAssetNames)
  169. {
  170. fnNew = fnNew.replaceAll("/", "_");
  171. }
  172. let assetDir = this.finalAssetPath;
  173. if (allFiles.includes(fnNew))
  174. {
  175. fnNew = path.join(this._helperUtil.generateUUID(), fnNew);
  176. }
  177. return path.join(assetDir, fnNew);
  178. }
  179.  
  180. _getPortValueReplacement(filePathAndName, fn, lzipFileName)
  181. {
  182. return lzipFileName;
  183. }
  184.  
  185. _doAfterCombine(jsCode, options)
  186. {
  187. return jsCode;
  188. }
  189. }