builder/lib/tasks/generateCachebusterInfo.js

  1. const crypto = require("crypto");
  2. const resourceFactory = require("@ui5/fs").resourceFactory;
  3. const log = require("@ui5/logger").getLogger("builder:tasks:generateCachebusterInfo");
  4. async function signByTime(resource) {
  5. return resource.getStatInfo().mtime.getTime();
  6. }
  7. async function signByHash(resource) {
  8. const hasher = crypto.createHash("sha1");
  9. const buffer = await resource.getBuffer();
  10. hasher.update(buffer.toString("binary"));
  11. return hasher.digest("hex");
  12. }
  13. function getSigner(type) {
  14. type = type || "time";
  15. switch (type) {
  16. case "time":
  17. return signByTime;
  18. case "hash":
  19. return signByHash;
  20. default:
  21. throw new Error(`Invalid signature type: '${type}'. Valid ones are: 'time' or 'hash'`);
  22. }
  23. }
  24. /**
  25. * Task to generate the application cachebuster info file.
  26. *
  27. * @public
  28. * @alias module:@ui5/builder.tasks.generateCachebusterInfo
  29. * @param {object} parameters Parameters
  30. * @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files
  31. * @param {module:@ui5/fs.AbstractReader} parameters.dependencies Reader or Collection to read dependency files
  32. * @param {object} parameters.options Options
  33. * @param {string} parameters.options.namespace Namespace of the application
  34. * @param {string} [parameters.options.signatureType='time'] Type of signature to be used ('time' or 'hash')
  35. * @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
  36. */
  37. module.exports = function({workspace, dependencies, options: {namespace, signatureType}}) {
  38. const basePath = `/resources/${namespace}/`;
  39. return workspace.byGlob(`/resources/${namespace}/**/*`)
  40. .then(async (resources) => {
  41. const cachebusterInfo = {};
  42. const signer = getSigner(signatureType);
  43. await Promise.all(resources.map(async (resource) => {
  44. let resourcePath = resource.getPath();
  45. if (!resourcePath.startsWith(basePath)) {
  46. log.verbose(
  47. `Ignoring resource with path ${resourcePath} since it is not based on path ${basePath}`);
  48. return;
  49. }
  50. // Remove base path. Absolute paths are not allowed in cachebuster info
  51. resourcePath = resourcePath.replace(basePath, "");
  52. cachebusterInfo[resourcePath] = await signer(resource);
  53. }));
  54. const cachebusterInfoResource = resourceFactory.createResource({
  55. path: `/resources/${namespace}/sap-ui-cachebuster-info.json`,
  56. string: JSON.stringify(cachebusterInfo, null, 2)
  57. });
  58. return workspace.write(cachebusterInfoResource);
  59. });
  60. };