All files / src/lib/project saveProjectData.ts

100% Statements 39/39
75% Branches 6/8
100% Functions 9/9
100% Lines 39/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 842x 2x 2x 2x 2x   2x 2x 2x 2x   2x   2x           2x         7x 7x   7x   7x   7x 13x     7x         10x   7x   7x 10x     7x   10x 10x       6x   6x   8x 8x 7x 7x       5x         5x 10x       5x 2x 2x       2x  
import { ensureDir, remove } from "fs-extra";
import glob from "glob";
import { promisify } from "util";
import { writeFileWithBackupAsync } from "lib/helpers/fs/writeFileWithBackup";
import Path from "path";
import { WriteResourcesPatch } from "shared/lib/resources/types";
import promiseLimit from "lib/helpers/promiseLimit";
import { uniq } from "lodash";
import { pathToPosix } from "shared/lib/helpers/path";
import { encodeResource } from "shared/lib/resources/save";
 
const CONCURRENT_RESOURCE_SAVE_COUNT = 8;
 
const globAsync = promisify(glob);
 
interface SaveProjectDataOptions {
  progress?: (completed: number, total: number) => void;
}
 
const saveProjectData = async (
  projectPath: string,
  patch: WriteResourcesPatch,
  options?: SaveProjectDataOptions
) => {
  const writeBuffer = patch.data;
  const metadata = patch.metadata;
 
  const projectFolder = Path.dirname(projectPath);
 
  let completedCount = 0;
 
  const notifyProgress = () => {
    options?.progress?.(completedCount, writeBuffer.length);
  };
 
  const existingResourcePaths = new Set(
    (
      await globAsync(
        Path.join(projectFolder, "{project,assets,plugins}", "**/*.gbsres")
      )
    ).map((path) => pathToPosix(Path.relative(projectFolder, path)))
  );
  const expectedResourcePaths: Set<string> = new Set(patch.paths);
 
  const resourceDirPaths = uniq(
    writeBuffer.map(({ path }) => Path.dirname(path))
  );
 
  await promiseLimit(
    CONCURRENT_RESOURCE_SAVE_COUNT,
    resourceDirPaths.map((path) => async () => {
      await ensureDir(Path.join(projectFolder, path));
    })
  );
 
  notifyProgress();
 
  await promiseLimit(
    CONCURRENT_RESOURCE_SAVE_COUNT,
    writeBuffer.map(({ path, data }) => async () => {
      await writeFileWithBackupAsync(Path.join(projectFolder, path), data);
      completedCount++;
      notifyProgress();
    })
  );
 
  await writeFileWithBackupAsync(
    projectPath,
    encodeResource("project", metadata)
  );
 
  const resourceDiff = Array.from(existingResourcePaths).filter(
    (path) => !expectedResourcePaths.has(path)
  );
 
  // Remove previous project files that are no longer needed
  for (const path of resourceDiff) {
    const removePath = Path.join(projectFolder, path);
    await remove(removePath);
  }
};
 
export default saveProjectData;