cp = require("child_process") Promise = require("bluebird") os = require("os") execa = require("execa") path = require("path") la = require("lazy-ass") fs = require("fs") R = require("ramda") filesize = require("filesize") # resolves with zipped filename macZip = (src, dest) -> new Promise (resolve, reject) => if os.platform() != "darwin" throw new Error("Can only zip on Mac platform") # Ditto (Mac) options # http://www.unix.com/man-page/OSX/1/ditto/ # -c create archive # -k set archive format to PKZip # --sequesterRsrc When creating a PKZip archive, preserve resource # forks and HFS meta-data in the subdirectory __MACOSX # --keepParent when zipping folder "foo", makes the folder # the top level in the archive # foo.zip # foo/ # ... zip = "ditto -c -k --sequesterRsrc --keepParent #{src} #{dest}" console.log(zip) cp.exec zip, {}, (err, stdout, stderr) -> return reject(err) if err console.log("✅ ditto zip finished") resolve(dest) megaBytes = (bytes) -> 1024 * 1024 * bytes checkZipSize = (zipPath) -> stats = fs.statSync(zipPath) zipSize = filesize(stats.size, {round: 0}) console.log("zip file size #{zipSize}") MAX_ALLOWED_SIZE_MB = if os.platform() == "win32" then 200 else 120 MAX_ZIP_FILE_SIZE = megaBytes(MAX_ALLOWED_SIZE_MB) if stats.size > MAX_ZIP_FILE_SIZE throw new Error("Zip file is too large: #{zipSize}") # resolves with zipped filename linuxZip = (src, dest) -> # in Linux switch to the folder containing source folder la(path.isAbsolute(src), "source path should be absolute", src) la(path.isAbsolute(dest), "destination path should be absolute", dest) parentFolder = path.dirname(src) relativeSource = path.basename(src) cmd = "cd #{parentFolder} && zip -r9 #{dest} #{relativeSource}" console.log("linux zip: #{cmd}") onZipFinished = () -> console.log("✅ zip finished") onError = (err) -> console.error("⛔️ could not zip #{src} into #{dest}") console.error(err.message) throw err execa.shell(cmd) .then onZipFinished .then R.always(dest) .then R.tap(checkZipSize) .catch onError # resolves with zipped filename windowsZip = (src, dest) -> # use 7Zip to zip # http://www.7-zip.org/ # zips entire source directory including top level folder name # Cypress/ # foo.txt # creates cypress.zip for example # unzip cypress.zip to get back the folder # Cypress/ # foo.txt cmd = "7z a #{dest} #{src}" console.log("windows zip: #{cmd}") onZipFinished = () -> console.log("✅ zip finished") onError = (err) -> console.error("⛔️ could not zip #{src} into #{dest}") console.error(err.message) throw err execa.shell(cmd) .then onZipFinished .then R.always(dest) .then R.tap(checkZipSize) .catch onError zippers = { linux: linuxZip darwin: macZip win32: windowsZip } module.exports = { ditto: (src, dest) -> platform = os.platform() console.log("#zip", platform) console.log("Zipping %s into %s", src, dest) zipper = zippers[platform] if !zipper throw new Error("Missing zip function for platform #{platform}") zipper(src, dest) checkZipSize }