import { tmpdir } from 'os'; import * as path from 'path'; import * as BluebirdPromise from 'bluebird'; import { isBowerStructure, isNpmStructure, isMajorZeroStructure } from '../presentation-strategy'; import { zip } from '../archive'; import { pathExists, createReadStream, createWriteStream, readFile } from 'fs-extra'; import PresentationChecksums from '../../api/ewizard/src/PresentationChecksums'; import * as JSZip from 'jszip'; import { CoError } from '../co-error'; import PresentationFileDiff from '../../api/ewizard/src/PresentationFileDiff'; import { ignoredPatterns, ignoredFiles } from '../../api/ignored-patterns'; const ignoredFolders = [ './.git', './.sass-cache', './.vscode', './.idea', './build', './**/demo', ].concat(ignoredPatterns.map((pattern: string) => `./${pattern}`)); const ignoredMetafiles = [ '!./**/*.md', '!./node_modules/**/*.map', '!./**/*changelog*' ].concat(ignoredFiles.map((pattern: string) => `!./${pattern}`)); export function getTempPresentationPackagePath(): string { return path.join(tmpdir(), 'package' + Date.now() + '.zip'); } export function getPresentationPackagePath(id: string): string { return path.join(tmpdir(), 'package' + id + '.zip'); } export async function isPresentationPackageExist(path: string): BluebirdPromise { return pathExists(path); } export default function packPresentation(presentationPath: string, zipPath: string = getTempPresentationPackagePath()): BluebirdPromise { return pack(presentationPath, zipPath, getSrcFiles); } export async function packPresentationWithDiff(presentationChecksums: PresentationChecksums, presentationPath: string, packagePath: string) { const packageData = await readFile(packagePath); const zip = await JSZip.loadAsync(packageData); const diff = await presentationChecksums.findDiff(presentationPath); if (!hasAnyDiff(diff)) { return BluebirdPromise.reject(new CoError('ALREADY_UP_TO_DATE')); } const additionalFiles = await getAdditionalFiles(presentationPath); [...diff.updated, ...diff.added, ...additionalFiles].forEach((file: string) => zip.file(file, createReadStream(path.join(presentationPath, file)))); diff.removed.forEach((file: string) => zip.remove(file)); return new BluebirdPromise(resolve => { zip .generateNodeStream({ streamFiles: true, compression: 'DEFLATE', compressionOptions: { level: 9 } }) .pipe(createWriteStream(packagePath)) .on('finish', function () { resolve(packagePath); }); }) } async function getAdditionalFiles(presentationPath: string) { const additionalFiles: string[] = []; if(await pathExists(path.join(presentationPath, 'bower.json'))) { additionalFiles.push('bower.json'); } if(await pathExists(path.join(presentationPath, 'package.json'))) { additionalFiles.push('package.json'); } return additionalFiles; } function hasAnyDiff(diff: PresentationFileDiff) { return diff.updated.length + diff.added.length + diff.removed.length > 0; } export function packPresentationFiles(presentationPath: string, files: string[], zipPath: string = getTempPresentationPackagePath()): BluebirdPromise { return pack(presentationPath, zipPath, (isBower: boolean, isNpm: boolean, isMajorZero: boolean) => { const relativePaths = files.map(f => './' + f); return removeIgnoredFiles(relativePaths); }); } function pack(presentationPath: string, zipPath: string, getFilesFunc: (isBower: boolean, isNpm: boolean, isMajorZero: boolean) => string[]): BluebirdPromise { const isBower = isBowerStructure(presentationPath); const isNpm = isNpmStructure(presentationPath); const isMajorZero = isMajorZeroStructure(presentationPath); return BluebirdPromise.all([isBower, isNpm, isMajorZero]) .spread(getFilesFunc) .then(addIgnoredFiles) .then((files: string[]) => zip(zipPath, files, presentationPath)); } function getSrcFiles(isBower: boolean, isNpm: boolean, isMajorZero: boolean): string[] { if (isBower) { return ['./*.*', './spa/**', './app/**', './.ewizard', './.bowerrc']; } if (isNpm) { // `./**/**` - for symbosic links directory return ['./*.*', './.ewizard', './**/*', './**/**']; } if (isMajorZero) { return ['./*.*', './spa/**', './app/**', './env/spa/**']; } return ['./**']; } function addIgnoredFiles(files: string[]): string[] { return files.concat(ignoredFolders.map(path => `!${path}/**`)).concat(ignoredMetafiles); } function removeIgnoredFiles(files: string[]): string[] { return files.filter((file) => { return !ignoredFolders.some((ignored) => { return file.indexOf(ignored) === 0; }); }); }