pax_global_header00006660000000000000000000000064130000023120014467gustar00rootroot0000000000000052 comment=8779a407d76ded1880a9fa6300dc007afd9a94f6 vinyl-fs-2.4.4/000077500000000000000000000000001300000231200132455ustar00rootroot00000000000000vinyl-fs-2.4.4/.editorconfig000066400000000000000000000002451300000231200157230ustar00rootroot00000000000000# editorconfig.org root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = truevinyl-fs-2.4.4/.eslintrc000066400000000000000000000000301300000231200150620ustar00rootroot00000000000000{ "extends": "gulp" } vinyl-fs-2.4.4/.gitignore000066400000000000000000000001101300000231200152250ustar00rootroot00000000000000.DS_Store *.log node_modules build *.node *.orig .idea sandbox coverage vinyl-fs-2.4.4/.jscsrc000066400000000000000000000000271300000231200145340ustar00rootroot00000000000000{ "preset": "gulp" } vinyl-fs-2.4.4/.travis.yml000066400000000000000000000004111300000231200153520ustar00rootroot00000000000000sudo: required language: node_js node_js: - 'stable' - '4' - '0.12' - '0.10' before_script: - find test -type d -exec chmod g+s {} \; - sudo chown root test/not-owned/ - sudo chown root test/not-owned/not-owned.txt after_script: - npm run coveralls vinyl-fs-2.4.4/CHANGELOG.md000066400000000000000000001221141300000231200150570ustar00rootroot00000000000000## Change Log ### v2.4.2 (2016/03/03 19:59 +00:00) - [5edb75a](https://github.com/gulpjs/vinyl-fs/commit/5edb75a10935fdc89e29d5e2413694aca77a3e85) 2.4.2 (@phated) - [f445987](https://github.com/gulpjs/vinyl-fs/commit/f445987ce905659e62dcb27a8ad69f4ed2fb8198) upgrade glob-stream and remove path.normalize workaround (@phated) ### v2.4.1 (2016/03/02 20:53 +00:00) - [caac041](https://github.com/gulpjs/vinyl-fs/commit/caac041836436577d52468d32b9844c00d666265) 2.4.1 (@phated) - [#154](https://github.com/gulpjs/vinyl-fs/pull/154) Don't pass `read` option from `src` to `through2` (@erikkemperman) ### v2.4.0 (2016/03/01 22:40 +00:00) - [926a9ad](https://github.com/gulpjs/vinyl-fs/commit/926a9ad3cf40d133120eb6f90d26234dc9f00138) 2.4.0 (@phated) - [#160](https://github.com/gulpjs/vinyl-fs/pull/160) Allow specify dest sourcemaps option as string (@TrySound) - [ebaffbe](https://github.com/gulpjs/vinyl-fs/commit/ebaffbecd642d3f8dd7d6edd6a19a1e768e7d2d1) Upgrade documentation (@TrySound) - [7a0c94a](https://github.com/gulpjs/vinyl-fs/commit/7a0c94ae97de5e46392efe9a08ee3c68885dd7ba) Allow specify dest sourcemaps option as string (@TrySound) ### v2.3.4 (2016/02/26 21:48 +00:00) - [cd8a992](https://github.com/gulpjs/vinyl-fs/commit/cd8a992294228eea1d08957efc823794baa48fba) 2.3.4 (@phated) - [8b50f49](https://github.com/gulpjs/vinyl-fs/commit/8b50f495c9b782d2afc64b38c0b7181a21c20b62) revert string handling from previous release, add support for SlowBuffer support (@phated) ### v2.3.3 (2016/02/26 20:08 +00:00) - [a75feda](https://github.com/gulpjs/vinyl-fs/commit/a75feda20131177a8f5a5008483f24169d0b3df3) 2.3.3 (@phated) - [165149c](https://github.com/gulpjs/vinyl-fs/commit/165149c6a676ac867933173db28300cf3bab2a5f) support strings in writeFile (@phated) - [3b67921](https://github.com/gulpjs/vinyl-fs/commit/3b67921fe5ddd925fc12acef2bd03777b0081dc3) Don't pass `read` option from `src` to `through2` (@erikkemperman) - [5918841](https://github.com/gulpjs/vinyl-fs/commit/5918841bbd2c5256413b86c000e28ac3fff516e7) update changelog (@phated) ### v2.3.2 (2016/02/26 01:17 +00:00) - [6ed1793](https://github.com/gulpjs/vinyl-fs/commit/6ed179380da7caa4e3506f78b8864ea59164992e) 2.3.2 (@phated) - [#151](https://github.com/gulpjs/vinyl-fs/pull/151) Feature metadata refactor (@gulpjs) - [0cd8f22](https://github.com/gulpjs/vinyl-fs/commit/0cd8f2229d7788477a3fa2613dbf93e019503198) add docs for changes (@phated) - [8d55978](https://github.com/gulpjs/vinyl-fs/commit/8d55978c3640ac25db8331ac4d7314579eb04da9) skip broken tests that were not testing the right thing (@phated) - [550edd5](https://github.com/gulpjs/vinyl-fs/commit/550edd56f555240c36068ad060b2136213b135f6) test on latest node 4 instead of old ones (@phated) - [6f4c2eb](https://github.com/gulpjs/vinyl-fs/commit/6f4c2eb396b78a91dcf41f5063eee27b66b35fe0) `sourcemaps` is not a valid option to gulp-sourcemaps (@phated) - [011320b](https://github.com/gulpjs/vinyl-fs/commit/011320b1f988ecd7846ef04f7a597ee4b25d7285) add appveyor to test on windows & get tests to actually pass (@phated) - [84cf3c2](https://github.com/gulpjs/vinyl-fs/commit/84cf3c2e1901bd700c089edac06ce0c75f8e701d) refactor and lots of tests for updating of metadata (@phated) - [90a1189](https://github.com/gulpjs/vinyl-fs/commit/90a11894472d29abe9e34b80df0dfab9907f11e7) Make the tests pass again, some more refactoring of metadata handling (@erikkemperman) - [35e9b3a](https://github.com/gulpjs/vinyl-fs/commit/35e9b3a68907167b51fa31edd0701ae24915fd84) Use filedescriptors where possible, refactor handling of stats metadata in dest (@piranna) - [#150](https://github.com/gulpjs/vinyl-fs/pull/150) Update license year from initial date of release to current (@pra85) - [ec48559](https://github.com/gulpjs/vinyl-fs/commit/ec485592d7a96562acc97ccd8b39a12cf17ed319) Update license year from initial date of release to current (@pra85) - [#149](https://github.com/gulpjs/vinyl-fs/pull/149) chore: add NPM script for changelog (@T1st3) - [0010bd3](https://github.com/gulpjs/vinyl-fs/commit/0010bd3b3c49e7b60e0d69dacdd8fd1b87a6c3dd) chore: add NPM script for changelog (@t1st3) - [#148](https://github.com/gulpjs/vinyl-fs/pull/148) docs: add CHANGELOG.md (@T1st3) - [da4cd0b](https://github.com/gulpjs/vinyl-fs/commit/da4cd0b449f8e9bd4bd0842fe2eb2b4eceea6c0b) docs: add changelog (@t1st3) ### v2.3.1 (2016/01/14 09:13 +00:00) - [7d2fcba](https://github.com/gulpjs/vinyl-fs/commit/7d2fcbaa49c78087fa975a4183fee38d422b9d4a) 2.3.1 - [#145](https://github.com/gulpjs/vinyl-fs/pull/145) Allow things to listen for data or readable events and avoid sinking in those cases (@gulpjs) - [a7fae5a](https://github.com/gulpjs/vinyl-fs/commit/a7fae5a2e2f349237614fc3cb3f371b6f10f5df3) keep style consistent - [1b02a46](https://github.com/gulpjs/vinyl-fs/commit/1b02a46aff9650afbfdf36aea386d177508d45fa) more updates, nextTick the removable of listeners in tests - [3a0cf5b](https://github.com/gulpjs/vinyl-fs/commit/3a0cf5b098d4a4f2f407f7622cbccc4b29ddbf0e) DRY up listenerCount check - [dcfc8b8](https://github.com/gulpjs/vinyl-fs/commit/dcfc8b8b2e93486703449960a69fef87b495a7e9) new sink removal impl - [8cec809](https://github.com/gulpjs/vinyl-fs/commit/8cec80998516b20a6fc43c3e865b588a34236899) more tests, better tests - [5167080](https://github.com/gulpjs/vinyl-fs/commit/5167080b13bfecd307da3b04be3b1892a9e8996c) harden event handling - [ef0b8e0](https://github.com/gulpjs/vinyl-fs/commit/ef0b8e043eb3c3ff72f09d7597b4ae9ed105ba6d) Fix sink from preventing the readable event to fire on the underlying stream (@benurb) ### v2.3.0 (2016/01/12 01:46 +00:00) - [941b040](https://github.com/gulpjs/vinyl-fs/commit/941b040905616eb0408a44213d5efe010388cb9d) 2.3.0 - [#121](https://github.com/gulpjs/vinyl-fs/pull/121) Fix file descriptor exhaustion when streaming many files (@Klowner) - [1f3af33](https://github.com/gulpjs/vinyl-fs/commit/1f3af33b1693b07fa2af5ed325ba8f0c0380b5f0) Add test for unbuffered file descriptor exhaustion issue (@Klowner) - [38b032c](https://github.com/gulpjs/vinyl-fs/commit/38b032cd9b481a1c16d88f1b7968dd51c6a5ed15) Add 20 second timeout to dest's afterEach wipeOut task (@Klowner) - [c63a797](https://github.com/gulpjs/vinyl-fs/commit/c63a79749a4b2ea500c519e1be5e073a87e4b940) Use lazystream for streamFile to avoid fd exhaustion (@Klowner) - [00ece7e](https://github.com/gulpjs/vinyl-fs/commit/00ece7ef6b794fd1999695fde2d88bba8d69f5d0) avoid else-if and isFatal variable - [6b9912e](https://github.com/gulpjs/vinyl-fs/commit/6b9912e14a3a7504bbba9d176c04b35e69208b64) get max statements warning for future cleanup - [a2be0d6](https://github.com/gulpjs/vinyl-fs/commit/a2be0d69de86af9e09ab1193b740d1a0736009fc) ESLint and JSCS plus fixup (@pdehaan) - [24119a8](https://github.com/gulpjs/vinyl-fs/commit/24119a862ad062f39ed15db767feff459843c2d8) Rework writeStream to prevent issue with futimes (@Klowner) - [17ef52e](https://github.com/gulpjs/vinyl-fs/commit/17ef52ec014ea6a72abda35d104e92786904f92b) Add test for streaming with buffering disabled (@Klowner) - [6934485](https://github.com/gulpjs/vinyl-fs/commit/69344858edb85e7c904621fa5d45782aa9825878) drastically improve docs - [80add99](https://github.com/gulpjs/vinyl-fs/commit/80add99101bd41f5161ff90c8b4a9b3ba496c73d) big timeout for slow node - [d553e74](https://github.com/gulpjs/vinyl-fs/commit/d553e7474ebb65b89e496dfc3916292b59eec4c2) Send options to through2 (@vineethawal) - [#134](https://github.com/gulpjs/vinyl-fs/pull/134) Make tests ignore gid (@gulpjs) - [e33b632](https://github.com/gulpjs/vinyl-fs/commit/e33b632ffb139599922bc414f76e4c5b81c82f70) adjust realMode method to avoid gid in the parse - fixes #103 - [4adb4d9](https://github.com/gulpjs/vinyl-fs/commit/4adb4d9d35a148d0c2507a5f06946951b54d443e) setgid on test directory - make travis fail as per #103 - [#130](https://github.com/gulpjs/vinyl-fs/pull/130) #129 - Update documentation to more clearly explain what happens for default base option values. (@treshugart) - [#126](https://github.com/gulpjs/vinyl-fs/pull/126) read from the stream once we finish processing a file, this avoids highWaterMark being hit - add test (@gulpjs) - [df97b14](https://github.com/gulpjs/vinyl-fs/commit/df97b1482200e7bc5dd01a49f0bdedeed2b6bd08) sink the saveStream on nextTick to start flowing and avoid highWaterMark - add tests - [#133](https://github.com/gulpjs/vinyl-fs/pull/133) fix TypeError when the dest sourcemaps option is a boolean (@chocolateboy) - [df874af](https://github.com/gulpjs/vinyl-fs/commit/df874af6c3dce1b8f008230b06f3ef9ef0e30d1a) add test for the boolean (true) source-map option (@chocolateboy) - [6ab48dd](https://github.com/gulpjs/vinyl-fs/commit/6ab48dd66899141d1c8e7f14e1ccb1ccc62c261e) fix TypeError when the dest sourcemaps option is a boolean (@chocolateboy) - [edb9caa](https://github.com/gulpjs/vinyl-fs/commit/edb9caa91e57690ddaace09aafb863f5bbac3ed8) #129 - Update documentation to more clearly explain what happens for default base option values. (@treshugart) - [#125](https://github.com/gulpjs/vinyl-fs/pull/125) Use `fs.futimes` to retain sub-second precision in `atime` and `mtime` (@erikkemperman) - [e3849f2](https://github.com/gulpjs/vinyl-fs/commit/e3849f2a19fa967842506fe4d34eeb8f6565464b) Use `fs.futimes` to retain sub-second precision in `atime` and `mtime` (@erikkemperman) - [be8d1fd](https://github.com/gulpjs/vinyl-fs/commit/be8d1fd878ae2c6332851aa15a669a1cd128c6cb) guarantee 5.2.0 glob-stream and update test - [#119](https://github.com/gulpjs/vinyl-fs/pull/119) Check if `atime` Date object is invalid and set a new one explicitly (@NodeOS) - [#122](https://github.com/gulpjs/vinyl-fs/pull/122) Change writeStream callbacks from cb to complete (@Klowner) - [8f93a48](https://github.com/gulpjs/vinyl-fs/commit/8f93a48c98ff75bab09bed47b989c9c1dbb5aaa0) Change writeStream callbacks from cb to complete (@Klowner) - [f575377](https://github.com/gulpjs/vinyl-fs/commit/f5753770962df157023e37dfadca2dcce6aa18b5) Check if `atime` Date object is invalid and set a new one explicitly (@piranna) ### v2.2.1 (2015/10/20 01:06 +00:00) - [a28ba42](https://github.com/gulpjs/vinyl-fs/commit/a28ba42d87eeaecc2ae3de9174270019fab76fe3) 2.2.1 - [7f539dd](https://github.com/gulpjs/vinyl-fs/commit/7f539dd562e501e904ab6401892f6f4c68a4da25) simplify utimes helper - [c2beec8](https://github.com/gulpjs/vinyl-fs/commit/c2beec86ddab2ef51a3a6fa7077907c74d1eadd7) fix tests for invalid dates - [97ff9ce](https://github.com/gulpjs/vinyl-fs/commit/97ff9ce60efba49a3d6cafcece3c9dce95aa670a) Test for invalid atime and mtime (@piranna) - [624d7f5](https://github.com/gulpjs/vinyl-fs/commit/624d7f59090a4ae8e7e5c83178b199e13973c635) [Fix] Ignore atime and mtime if they are invalid (@piranna) ### v2.2.0 (2015/10/16 02:02 +00:00) - [bf7edd3](https://github.com/gulpjs/vinyl-fs/commit/bf7edd37cb0207951b75879d4e07402c51ac8770) 2.2.0 - [039d689](https://github.com/gulpjs/vinyl-fs/commit/039d68920cc5bde6f0f12375daee2713260a1ecf) make tests pass - [6f36372](https://github.com/gulpjs/vinyl-fs/commit/6f36372b9d0b0bf10087b3ac863f858b15e54bb9) Test for vynil stat not modified (FAIL) (@piranna) - [dbc606b](https://github.com/gulpjs/vinyl-fs/commit/dbc606bb091008215fd586e4a1eee6ec8bdb22d3) Don't modify vynil stat when atime is not defined (@piranna) - [573b8b6](https://github.com/gulpjs/vinyl-fs/commit/573b8b656032e1b486f7e4bca9f5916ceb6def54) Tests for atime and mtime (@piranna) - [d7a53d5](https://github.com/gulpjs/vinyl-fs/commit/d7a53d5f557c23aa26d9d5d179645288204a6faa) Style improvements (@piranna) - [9237100](https://github.com/gulpjs/vinyl-fs/commit/92371008a2bafa74ba87450b57578d0ace17b194) Fix mtime test to 1 second resolution as Node.js does (@piranna) - [801da1c](https://github.com/gulpjs/vinyl-fs/commit/801da1c04696736df9c9c2ad47645faadab970d2) Test for mtime (fail on second decimals) (@piranna) - [def6815](https://github.com/gulpjs/vinyl-fs/commit/def68150d0e42ad870afe314cd3b7cea760e9c48) Updated style & made utility function (@piranna) - [d55fd11](https://github.com/gulpjs/vinyl-fs/commit/d55fd119718a3166cf3f76362a896bfa8e91427d) Made atime optional ("cpio" don't have it, and sometimes "tar" too) (@piranna) - [9a10c15](https://github.com/gulpjs/vinyl-fs/commit/9a10c15aeb1ef3f0b3c1e39c7c7c94f5295449d2) Set utimes of files if they are provided (@piranna) - [#108](https://github.com/gulpjs/vinyl-fs/pull/108) Fix links, spacing in README (@moshen) - [c603138](https://github.com/gulpjs/vinyl-fs/commit/c603138077df416cf7892f82a2e3a91daa3456fd) Fix links, spacing in README (@moshen) - [#105](https://github.com/gulpjs/vinyl-fs/pull/105) updated to test on nodejs 4 (@ckross01) - [3148943](https://github.com/gulpjs/vinyl-fs/commit/3148943032a834ad1c82c951576e735d4824d6f0) updated to test on nodejs 4 (@ckross01) - [#102](https://github.com/gulpjs/vinyl-fs/pull/102) Update tests to 'strict mode' (@OnkelTem) - [85c1286](https://github.com/gulpjs/vinyl-fs/commit/85c128604b521d2e465f1e78548d128c95f4719c) Update tests to 'strict mode' (@OnkelTem) ### v2.1.1 (2015/09/28 09:55 +00:00) - [812c696](https://github.com/gulpjs/vinyl-fs/commit/812c696709a16f0de2e06e03b5fe41a45fbfe4f2) 2.1.1 (@contra) - [0a4caf6](https://github.com/gulpjs/vinyl-fs/commit/0a4caf61f5745e3a0f368be9d285d006fd7cbf4c) more elegant sourcemap handling, more docs (@contra) - [0ac5a2c](https://github.com/gulpjs/vinyl-fs/commit/0ac5a2cb072111917e561c655441aa10a8ee1718) only pass buffer files to sourcemaps (@contra) ### v2.1.0 (2015/09/27 22:01 +00:00) - [dbf2a25](https://github.com/gulpjs/vinyl-fs/commit/dbf2a25dc9273e1d5bfa592e6b8564d245294e55) 2.1.0 (@contra) - [#100](https://github.com/gulpjs/vinyl-fs/pull/100) allow a function to be used as value for the overwrite option - closes #68 (@gulpjs) - [#99](https://github.com/gulpjs/vinyl-fs/pull/99) add option to strip BOM, default to true - closes #83 (@gulpjs) - [b966d51](https://github.com/gulpjs/vinyl-fs/commit/b966d517906116021b5cec4ab7d41bbe8dd23168) update docs - [13c853a](https://github.com/gulpjs/vinyl-fs/commit/13c853a1ae0a829f0fd33347ed791f9b92593d18) allow a function to be used as value for the overwrite option - closes #68 - [870551c](https://github.com/gulpjs/vinyl-fs/commit/870551c43d69547accd4b4918142b06926f20e99) add option to strip BOM, default to true - closes #83 - [50c9e33](https://github.com/gulpjs/vinyl-fs/commit/50c9e33149a7f365d039cd0115526c79145a5534) more sourcemaps docs (@contra) ### v2.0.0 (2015/09/25 22:43 +00:00) - [de7bf7b](https://github.com/gulpjs/vinyl-fs/commit/de7bf7ba79acf33610d8d8e58626dc39d8ed2611) 2.0.0 (@contra) - [59620dc](https://github.com/gulpjs/vinyl-fs/commit/59620dce078d0a458d96ba0c82416f24b82cb95f) update vinyl (@contra) ### v1.0.0 (2015/03/01 23:10 +00:00) - [db025fe](https://github.com/gulpjs/vinyl-fs/commit/db025fe85b190414b28512c1f5ef08662564d4eb) 1.0.0 (@contra) - [c7195ed](https://github.com/gulpjs/vinyl-fs/commit/c7195ed3a7c93b5206ba9a1035e84da479888f4e) 1.0.0 (@contra) - [4a70dd6](https://github.com/gulpjs/vinyl-fs/commit/4a70dd63386db8abfeeb985630406e1a39f776a5) update dep, remove engineStrict (@contra) - [#59](https://github.com/gulpjs/vinyl-fs/pull/59) Implemented `overwrite` option in `dest()` (@derekslife) - [c4750b2](https://github.com/gulpjs/vinyl-fs/commit/c4750b2efccd840e4ae840dc55b01cb7051f2f48) Encapsulated error filtering logic into `isErrorFatal` func (@derekslife) - [32fc5c8](https://github.com/gulpjs/vinyl-fs/commit/32fc5c805ec6209c3d2145036ff2eabff79845be) Updated docs for `overwrite` option (@derekslife) - [5572793](https://github.com/gulpjs/vinyl-fs/commit/5572793954b63e1ec00983bad716af01e02476ef) Implemented `overwrite` option in `dest()` (@derekslife) - [2dfe290](https://github.com/gulpjs/vinyl-fs/commit/2dfe2901cc329f5db86d0f2272d4292a2078d5a3) update watch to fix a bug with .remove (@contra) - [#57](https://github.com/gulpjs/vinyl-fs/pull/57) Follow symlinks (@valeriangalliat) - [a4ea945](https://github.com/gulpjs/vinyl-fs/commit/a4ea945cf04660fc007266c87caa43d345a5b1bc) Follow symlinks (@valeriangalliat) - [041de1b](https://github.com/gulpjs/vinyl-fs/commit/041de1b6f20434a7bd6146fdf0a3425dfe301f96) update should (@contra) - [#55](https://github.com/gulpjs/vinyl-fs/pull/55) Add `passthrough` option, fixes #25, fixes gulpjs/gulp#840 (@UltCombo) - [972c8ad](https://github.com/gulpjs/vinyl-fs/commit/972c8ad3ac377ff7b4a03edeb04f52409d383dd4) Code style (@UltCombo) - [b9629ea](https://github.com/gulpjs/vinyl-fs/commit/b9629ea6e9b9b797b518ab8192f4a2ec446ea325) Add `passthrough` option, fixes #25, fixes gulpjs/gulp#840 (@UltCombo) - [318a983](https://github.com/gulpjs/vinyl-fs/commit/318a983832408ddc5500b27cfcb8c5cb07c8af11) new glob-watcher (@contra) - [#53](https://github.com/gulpjs/vinyl-fs/pull/53) Remove unnecessary `coveralls` from devDependencies (@shinnn) - [1ccdc53](https://github.com/gulpjs/vinyl-fs/commit/1ccdc53e22e2449a8b1f9fdc9dfbe7cd526f1dec) remove unnecessary `coveralls` from devDeps (@shinnn) - [#52](https://github.com/gulpjs/vinyl-fs/pull/52) Update dotfiles and readme (@shinnn) - [87c36ed](https://github.com/gulpjs/vinyl-fs/commit/87c36ede9da5e1508e62a984da4ebc9c8412f6d2) introduce istanbul-coveralls (@shinnn) - [fb1a0fa](https://github.com/gulpjs/vinyl-fs/commit/fb1a0fa6bf4028f54629014f89fee0dd148945b6) use sag badges instead of png badges (@shinnn) - [5e1b24b](https://github.com/gulpjs/vinyl-fs/commit/5e1b24b4d2a811a02ae7b6449d4f0de778bbe4ef) update dotfiles (@shinnn) - [96c721f](https://github.com/gulpjs/vinyl-fs/commit/96c721f07b59964849b15d737ab8abaf52377312) clean up empty object allocation (@contra) - [6e97447](https://github.com/gulpjs/vinyl-fs/commit/6e97447dab806b1da7df52d9d4da337d49fe71cb) logic consolidation (@contra) - [6f8f045](https://github.com/gulpjs/vinyl-fs/commit/6f8f0459e51fe4c1065a0e693fbcdc26776b6e78) more style normalization (@contra) - [141ff43](https://github.com/gulpjs/vinyl-fs/commit/141ff43302dec6535d086cf27d538530161952c5) style normalization (@contra) - [500f5cf](https://github.com/gulpjs/vinyl-fs/commit/500f5cf9100256db5ea2d180773385bacaca251e) logic cleanups (@contra) - [f081c21](https://github.com/gulpjs/vinyl-fs/commit/f081c21cb264164fee8896056bd0337f734c1904) code cleanups in dest logic (@contra) - [2692230](https://github.com/gulpjs/vinyl-fs/commit/269223036d24fe700dba8b5b9f04ad4023eadb2a) fix dest memory leak when writing streams (@contra) - [3d2c6c0](https://github.com/gulpjs/vinyl-fs/commit/3d2c6c0350407b3b98c7d2e7950f999f3832b2de) report errors preparing write on symlinks (@contra) - [4481668](https://github.com/gulpjs/vinyl-fs/commit/448166864ba6c973055eb205575c3e392cf0f39a) add dirMode param to dest and symlink, closes #36 (@contra) - [#49](https://github.com/gulpjs/vinyl-fs/pull/49) Add symlink support (Fixes #42) (@JonAbrams) - [558f374](https://github.com/gulpjs/vinyl-fs/commit/558f3744489d5e671f4172453b24ba62bfd9b102) new glob ordering (@contra) - [5876564](https://github.com/gulpjs/vinyl-fs/commit/587656487d7cd8a56cadd57d311d28af820377a0) Match function to prepareWrite.js filename (@JonAbrams) - [21d7528](https://github.com/gulpjs/vinyl-fs/commit/21d7528f04afbc88529a69e81e4c64823edbbfe9) Move and rename to prepareWrite.js (@JonAbrams) - [b447d5e](https://github.com/gulpjs/vinyl-fs/commit/b447d5ea22bbd9a54bcdceccac8e94c0bd0e18e7) Fix jshint warnings (@JonAbrams) - [15af3e5](https://github.com/gulpjs/vinyl-fs/commit/15af3e58512c2cdfb00fcc6f8850cfffa69ef431) De-dup common code between dest + symlink (#42) (@JonAbrams) - [4392605](https://github.com/gulpjs/vinyl-fs/commit/439260503481296ac8f3482ee901434fd7e3969e) Add symlink support (Fixes #42) (@JonAbrams) - [#47](https://github.com/gulpjs/vinyl-fs/pull/47) option.since implementation (@doowb) - [8cca620](https://github.com/gulpjs/vinyl-fs/commit/8cca62066c07ce4cc75f390aeb523c228cd887c3) updates per @contra (@doowb) - [cec31c6](https://github.com/gulpjs/vinyl-fs/commit/cec31c66d03c0e9c57b6e7223ea2e1029b0b5110) docs (@doowb) - [3d440b3](https://github.com/gulpjs/vinyl-fs/commit/3d440b3dfe745261239071335b3839a8a12460b7) check for instance of Date (@doowb) - [44cc193](https://github.com/gulpjs/vinyl-fs/commit/44cc193a9984a012f93082fa940516ad6249023f) since implementation (@doowb) - [#44](https://github.com/gulpjs/vinyl-fs/pull/44) Swap defaults dependency with object-assign. (@ben-eb) - [c07074c](https://github.com/gulpjs/vinyl-fs/commit/c07074c835cae9361973c1046a3f0522565a919d) Swap defaults dep with object-assign. (@ben-eb) ### v0.3.14 (2015/09/21 23:57 +00:00) - [5b056f6](https://github.com/gulpjs/vinyl-fs/commit/5b056f66c476ff32687c172d5fe79eaf47b2e80e) update object-assign dep (@contra) - [27983ef](https://github.com/gulpjs/vinyl-fs/commit/27983ef0114ceb16abd82a5c47557cb0be95ae62) merge (@contra) - [7ca959e](https://github.com/gulpjs/vinyl-fs/commit/7ca959e8ac89034e0e09714da76eb06b7b55d61c) remove watch #92 (@contra) - [#90](https://github.com/gulpjs/vinyl-fs/pull/90) Updated merge-stream version to 1.0.0 (@davidbarrows) - [22e5e13](https://github.com/gulpjs/vinyl-fs/commit/22e5e13f8edf399cf286f5d908a1bd6766308408) Updated merge-stream version to 1.0.0 (@davidbarrows) - [#88](https://github.com/gulpjs/vinyl-fs/pull/88) fix wrong event name in README.md (@kketch) - [65445ec](https://github.com/gulpjs/vinyl-fs/commit/65445ec16f1546b268c6a66c2ee798baa94883c8) fix wrong event name in README.md (@kketch) - [#85](https://github.com/gulpjs/vinyl-fs/pull/85) Add symlink passthrough with `followSymlinks` (@Klowner) - [9f5f6e8](https://github.com/gulpjs/vinyl-fs/commit/9f5f6e8770b4e1364381bfdc832a1c4aacd68274) Add symlink copy with `followSymlinks` option (@Klowner) - [#82](https://github.com/gulpjs/vinyl-fs/pull/82) symlink opt.base should be the same as dest (@stevemao) - [0b3eed2](https://github.com/gulpjs/vinyl-fs/commit/0b3eed2d84a7b8c134b990a2234916b24e54906b) symlink opt.base should be the same as dest (@stevemao) - [3e2a5ef](https://github.com/gulpjs/vinyl-fs/commit/3e2a5ef63c98b9ef44b3d05cdc6c03bdb9c2392b) base can be a function now, also add better error messaging. closes #78 (@contra) - [#81](https://github.com/gulpjs/vinyl-fs/pull/81) use valid semver range for `engine` (@silverwind) - [69090c4](https://github.com/gulpjs/vinyl-fs/commit/69090c41d79bcb7c492fab6c4ac1a7788a0e8dc7) use valid semver range for `engine` (@silverwind) - [65090b8](https://github.com/gulpjs/vinyl-fs/commit/65090b81b98c8ed80fda247495d8015701d62813) Merge branch 'master' of https://github.com/wearefractal/vinyl-fs (@contra) - [b481130](https://github.com/gulpjs/vinyl-fs/commit/b48113066f04fa5a240770132fbf1e57af12687c) fix filter-since (@contra) - [#79](https://github.com/gulpjs/vinyl-fs/pull/79) add missing test for f7516ebac102104ad0f39437f7739bf5aedec165 (@stevemao) - [8e8135c](https://github.com/gulpjs/vinyl-fs/commit/8e8135c3f99c4669129295e65b54581c45535191) update vinyl-filter-since (@contra) - [cb86d86](https://github.com/gulpjs/vinyl-fs/commit/cb86d86deefa593f3099d2494e06cbc59b69e9bc) add missing test for f7516ebac102104ad0f39437f7739bf5aedec165 (@stevemao) - [a8161c8](https://github.com/gulpjs/vinyl-fs/commit/a8161c87f38d465497c63ec3158f0f033868b60b) update vinyl filter since (@contra) - [99db7de](https://github.com/gulpjs/vinyl-fs/commit/99db7de8f0485c5ca158c79126b53b8fdab9d821) add sourcemaps to dest, clear up some dead src code now that empty arrays arent valid globs, dep updates (@contra) - [d32876f](https://github.com/gulpjs/vinyl-fs/commit/d32876f8df5a8a28f71b476ae907644ab5d35c07) update deps (@contra) - [#77](https://github.com/gulpjs/vinyl-fs/pull/77) Improvements (@stevemao) - [f7516eb](https://github.com/gulpjs/vinyl-fs/commit/f7516ebac102104ad0f39437f7739bf5aedec165) Expose `options.base` for `dest` (@stevemao) - [435c401](https://github.com/gulpjs/vinyl-fs/commit/435c40193acebdaca62a9d688ceec5875b1ece15) test on iojs and 0.12 (@stevemao) - [a3b1aa6](https://github.com/gulpjs/vinyl-fs/commit/a3b1aa6d5446760bf18de77ebf2aa199bef9f9b0) Make readme more consistent (@stevemao) - [#75](https://github.com/gulpjs/vinyl-fs/pull/75) Fix default option in README (@stevemao) - [a0820f4](https://github.com/gulpjs/vinyl-fs/commit/a0820f4ec4737ab826999cde2dda6ee0dae2db03) Fix default option in README (@stevemao) - [812d0e6](https://github.com/gulpjs/vinyl-fs/commit/812d0e6ef55ac7ecd6e7dc83ef6f58e324837354) add new glob tests, empty string is a failing glob now. https://github.com/google/material-design-lite/issues/790 (@contra) - [1b7322d](https://github.com/gulpjs/vinyl-fs/commit/1b7322d800008095596da9472801a2ddabcdf938) Merge branch 'master' of https://github.com/wearefractal/vinyl-fs (@contra) - [5af3ed8](https://github.com/gulpjs/vinyl-fs/commit/5af3ed844d4dac6a84cf836aa09373ad2d3193dd) fix dir symlinks on windows, closes #74 (@contra) - [#73](https://github.com/gulpjs/vinyl-fs/pull/73) using is-valid-glob module to handle nested arrays properly (@doowb) - [0a6bcb1](https://github.com/gulpjs/vinyl-fs/commit/0a6bcb15067f2ac0b534d17c0f66aa9616c2bd54) using is-valid-glob module to handle nested arrays properly (@doowb) - [baf97e1](https://github.com/gulpjs/vinyl-fs/commit/baf97e1f66caa4f1a9f9630620233c8c927f7509) passing options through to readers is still a good idea, so not a full revert. #72 (@contra) - [f6ead3c](https://github.com/gulpjs/vinyl-fs/commit/f6ead3cec64c27a86f2a2e497d75e8a4f235339c) remove stripBOM flag, document BOM stripping. #72 (@contra) - [#71](https://github.com/gulpjs/vinyl-fs/pull/71) Update vinyl to 0.5.x (@lijunle) - [3a44b5d](https://github.com/gulpjs/vinyl-fs/commit/3a44b5da290c1d0279381a4d13f8816bc2ebb014) Update vinyl to 0.5.x (@lijunle) - [#69](https://github.com/gulpjs/vinyl-fs/pull/69) update license attribute (@pgilad) - [23640fd](https://github.com/gulpjs/vinyl-fs/commit/23640fde7378465625b2e0579bb661c7501b0e04) update license attribute (@pgilad) - [60685eb](https://github.com/gulpjs/vinyl-fs/commit/60685eb89e57f61c4462855532f43d75f0a616db) fix problem where you couldnt catch singular glob errors. add sourcemaps into src (@contra) - [12dec99](https://github.com/gulpjs/vinyl-fs/commit/12dec99a99af362ddfa2a0f7af7a39063803f182) dep updates (@contra) - [#63](https://github.com/gulpjs/vinyl-fs/pull/63) export `filterSince` to `vinyl-filter-since` (@tunnckoCore) - [9bbf989](https://github.com/gulpjs/vinyl-fs/commit/9bbf989151a912307686d36dc6ee4ef01cdbd38f) bump to `vinyl-filter-since@v2` (@tunnckoCore) - [1a788e8](https://github.com/gulpjs/vinyl-fs/commit/1a788e826951939e81ab1a2505f2aaf2a9cde264) Merge github.com:wearefractal/vinyl-fs (@tunnckoCore) - [#65](https://github.com/gulpjs/vinyl-fs/pull/65) Remove realMode equality test on special bit test (@Meroje) - [627ace7](https://github.com/gulpjs/vinyl-fs/commit/627ace7702895c35f313d439c357e6387961d05a) Remove realMode equality test on special bit test (@Meroje) - [fd9388d](https://github.com/gulpjs/vinyl-fs/commit/fd9388db1a15afe1e3c748d3859ab969c34ba1db) merge in blaines changes (@contra) - [fda2a71](https://github.com/gulpjs/vinyl-fs/commit/fda2a71b8d26580f8dc564636005f78514e2b791) fix some tests, update deps (@contra) - [#64](https://github.com/gulpjs/vinyl-fs/pull/64) switch to glob-watcher 2.0 (@phated) - [6524088](https://github.com/gulpjs/vinyl-fs/commit/65240883f15b9f0aa792735a2f358c3ee5761c51) switch to glob-watcher 2.0 - [5d9f058](https://github.com/gulpjs/vinyl-fs/commit/5d9f0581b0d3985d135b507086dbd464e4aaafb9) export `filterSince` to `vinyl-filter-since` (@tunnckoCore) - [#62](https://github.com/gulpjs/vinyl-fs/pull/62) Fix mode comparison (@Meroje) - [ba57ce7](https://github.com/gulpjs/vinyl-fs/commit/ba57ce76e978850f79f78bba9b8aa1a73ac5fb2f) Test for chmod with additional bits (@Meroje) - [0c3516b](https://github.com/gulpjs/vinyl-fs/commit/0c3516bd67ca56810f3e587cda12584caced223e) Fix mode comparison (@Meroje) ### v0.3.13 (2014/11/13 23:18 +00:00) - [315e76a](https://github.com/gulpjs/vinyl-fs/commit/315e76a248e9d150f228e4ef50b61de15dc55123) 0.3.13 (@contra) - [ac5b449](https://github.com/gulpjs/vinyl-fs/commit/ac5b449ec49b4de5f10313d31fd8e8effed0421b) switch off lodash to reduce size (@contra) ### v0.3.12 (2014/11/13 23:01 +00:00) - [84a3fe9](https://github.com/gulpjs/vinyl-fs/commit/84a3fe96dd162041eac9c9d4465cc1369659027a) 0.3.12 (@contra) - [b963614](https://github.com/gulpjs/vinyl-fs/commit/b963614bf206862f9bed60bab16ed7038f554c42) exclude files to save space (@contra) ### v0.3.11 (2014/11/04 18:56 +00:00) - [5ee1404](https://github.com/gulpjs/vinyl-fs/commit/5ee1404cc25b54fc338e6f84909e87be2eb09e84) 0.3.11 (@contra) - [#41](https://github.com/gulpjs/vinyl-fs/pull/41) use default mode for new files and directories (@joachimgit) - [99661c5](https://github.com/gulpjs/vinyl-fs/commit/99661c5881cf2b22545be688c68318c6b7541df1) use default mode for new files and directories (@joachimgit) - [c0cf9d0](https://github.com/gulpjs/vinyl-fs/commit/c0cf9d0663460881f9ee97310f44e382d9a09fbe) small style fix (@contra) ### v0.3.10 (2014/10/22 06:48 +00:00) - [c6e7433](https://github.com/gulpjs/vinyl-fs/commit/c6e7433a93d052905611680dc3f6f87c8e629376) 0.3.10 (@contra) - [793f538](https://github.com/gulpjs/vinyl-fs/commit/793f538beaa275a6d31f67e5499cb96949654699) remove duplexer2 which was broken (@contra) - [1e3b338](https://github.com/gulpjs/vinyl-fs/commit/1e3b33883c5a9efbb28ec9141564bdfe6292c716) end false (@contra) ### v0.3.9 (2014/10/09 18:34 +00:00) - [37c648d](https://github.com/gulpjs/vinyl-fs/commit/37c648da6826b36600f48c3002a03b1248d4f58e) 0.3.9 (@contra) - [6bba193](https://github.com/gulpjs/vinyl-fs/commit/6bba193c8395d2e32ccfa332684bec1bdd52d4ad) empty arrays = dead stream, closes #40 (@contra) - [3e3d371](https://github.com/gulpjs/vinyl-fs/commit/3e3d371c41a9e3e50a9af9ad5f5c8634744dcd6d) fix that potentially closes #25 (@contra) ### v0.3.8 (2014/09/29 22:16 +00:00) - [0507aed](https://github.com/gulpjs/vinyl-fs/commit/0507aed94a1902ee61a45f77caf059669fb7ea76) 0.3.8 (@contra) - [4d95e2e](https://github.com/gulpjs/vinyl-fs/commit/4d95e2e19f35045ca5ec66d697167078696bfc86) lstat (@contra) - [#37](https://github.com/gulpjs/vinyl-fs/pull/37) Docs link fix (@yuvilio) - [b9f3053](https://github.com/gulpjs/vinyl-fs/commit/b9f3053a8640839c2098f43066d06cc11d2e6196) Docs link fix (@yuvilio) ### v0.3.7 (2014/08/29 07:10 +00:00) - [1a5efe8](https://github.com/gulpjs/vinyl-fs/commit/1a5efe8d1f7d698691103f2fdc21e07dc1bd5634) 0.3.7 (@contra) - [97d3195](https://github.com/gulpjs/vinyl-fs/commit/97d3195464893ad526f40a6355c792d35ab562e6) update deps (@contra) - [#34](https://github.com/gulpjs/vinyl-fs/pull/34) Chmod mode to match the vinyl object (@oconnore) - [a73458e](https://github.com/gulpjs/vinyl-fs/commit/a73458e33aba6de1ee2852a1374da7e8c8225e22) reduce nesting per review - [cf8e5fd](https://github.com/gulpjs/vinyl-fs/commit/cf8e5fd59070beedf88936527935168d18afbbfc) Code review changes - [e5684ac](https://github.com/gulpjs/vinyl-fs/commit/e5684ace84d0d226c382a77d505e1517c6f4c7a3) Check final mode in no-chmod test - [dc8e769](https://github.com/gulpjs/vinyl-fs/commit/dc8e7691430555c4fe419825306426062c3e03e8) Fix a fall through error - [b20d11b](https://github.com/gulpjs/vinyl-fs/commit/b20d11bbbaf9e244e16af7eabb7c98af213e7a89) Test stat/chmod approach with sinon stubs - [126164a](https://github.com/gulpjs/vinyl-fs/commit/126164a4f2056d3cb1996c39562a2a008153975d) Test if the file should be chmod'ed ### v0.3.6 (2014/08/02 04:56 +00:00) - [7256498](https://github.com/gulpjs/vinyl-fs/commit/72564989a5dc17468e645f00ae811f8614dec17b) 0.3.6 (@contra) - [dc9d723](https://github.com/gulpjs/vinyl-fs/commit/dc9d7230a4173792b0296e54a9560b44103d50c2) update vinyl dep (@contra) - [387c47b](https://github.com/gulpjs/vinyl-fs/commit/387c47b6fda5f0af8f95b93e513bc130bee3cdd3) Satisfy the bot. - [5887067](https://github.com/gulpjs/vinyl-fs/commit/58870677ff458a3e855ac87f2d165f43c4aafd2e) Chmod mode to match the vinyl object ### v0.3.5 (2014/07/30 23:04 +00:00) - [22edfd2](https://github.com/gulpjs/vinyl-fs/commit/22edfd20dc2fbad888fedd022d02fdf933bf30b6) 0.3.5 (@contra) - [20a7a05](https://github.com/gulpjs/vinyl-fs/commit/20a7a0525b80cf0884cf73bee9690e1dab17a2bb) fix dep tree (@contra) - [#33](https://github.com/gulpjs/vinyl-fs/pull/33) Display the invalid glob in error message (@kevinwestern) - [726b3a1](https://github.com/gulpjs/vinyl-fs/commit/726b3a1ac771c90a8186828e3eb37ad9f4832df8) Display the invalid glob in error message (@kevinwestern) ### v0.3.4 (2014/06/27 06:07 +00:00) - [a83eb9a](https://github.com/gulpjs/vinyl-fs/commit/a83eb9a53aa0c4e50306a20845111ccda276146d) 0.3.4 (@contra) - [4f4a3f3](https://github.com/gulpjs/vinyl-fs/commit/4f4a3f363cf491de80afdcf58f9926d2bfeb408e) resume stream (@contra) ### v0.3.3 (2014/06/26 16:35 +00:00) - [52ce21b](https://github.com/gulpjs/vinyl-fs/commit/52ce21ba241f73f0348d7683306c1175ce6c88b3) 0.3.3 (@contra) - [#29](https://github.com/gulpjs/vinyl-fs/pull/29) Quick fix for using through2 to create dest stream (@tomchentw) - [c678bd4](https://github.com/gulpjs/vinyl-fs/commit/c678bd469e11e768713219b774fa82aa781e4fef) test(dest): also added finish event check for #26 (@tomchentw) - [595e96e](https://github.com/gulpjs/vinyl-fs/commit/595e96e45f12fc868f9ce256d0421da7f4932843) test(dest): added test case for #26 (@tomchentw) - [8bf8612](https://github.com/gulpjs/vinyl-fs/commit/8bf8612702e228fcc0c678acafe7634f2c6b269b) fix(vfs.dest): attatched an noop data listener (@tomchentw) ### v0.3.2 (2014/06/25 18:34 +00:00) - [8fef1ed](https://github.com/gulpjs/vinyl-fs/commit/8fef1ed6d65a2532271983360d8700ec8dd03023) 0.3.2 (@contra) - [#27](https://github.com/gulpjs/vinyl-fs/pull/27) Removed through2-map dependency (@tomchentw) - [ede010b](https://github.com/gulpjs/vinyl-fs/commit/ede010be5aa110f55f2fc9daa34c1643e377e11c) feat(index.js): removed through2-map dependency (@tomchentw) - [d1433cb](https://github.com/gulpjs/vinyl-fs/commit/d1433cb41ed3e0bf78bc2ea3a52e0599cccc45c2) .npmignore (@contra) - [74347cc](https://github.com/gulpjs/vinyl-fs/commit/74347ccc71e5189e5d8809919fb145cfa9657481) .npmignore (@contra) - [7c66ea2](https://github.com/gulpjs/vinyl-fs/commit/7c66ea2f09acb2dba51b192ccc8a8f09ef01489f) .npmignore (@contra) - [cece0dc](https://github.com/gulpjs/vinyl-fs/commit/cece0dc68dfc1ebd3b344e367a4a269c43f15a0e) .npmignore (@contra) - [33ac098](https://github.com/gulpjs/vinyl-fs/commit/33ac098ca8ff2e3216399784cd58b775d764ccab) .npmignore (@contra) - [831044b](https://github.com/gulpjs/vinyl-fs/commit/831044b683c65eb9858323dc2744fd3ec33d82e1) .npmignore (@contra) - [ff582cc](https://github.com/gulpjs/vinyl-fs/commit/ff582ccd55e6481134f6c44d1d2cb1dfc338818c) .npmignore (@contra) - [fe75d6a](https://github.com/gulpjs/vinyl-fs/commit/fe75d6af6703bf2b6711ca1abfe9832d1d836375) .npmignore (@contra) - [0c1da37](https://github.com/gulpjs/vinyl-fs/commit/0c1da37d252d16a171f30dfea42714bb208d1b3d) .npmignore (@contra) - [10e6b53](https://github.com/gulpjs/vinyl-fs/commit/10e6b53bd9f8683408f6394c04142ac55ab9f493) .gitignore (@contra) - [97296ef](https://github.com/gulpjs/vinyl-fs/commit/97296ef8e724953570ab989b043692cea5ba9062) .npmignore (@contra) - [a12356c](https://github.com/gulpjs/vinyl-fs/commit/a12356c36cfd24e19d0c88225d364368ae7dac36) .gitignore (@contra) - [7a7f2e5](https://github.com/gulpjs/vinyl-fs/commit/7a7f2e544b5eacf595bcc1fd9cac34de880ec071) .jshintrc (@contra) ### v0.3.1 (2014/06/25 14:28 +00:00) - [6004e32](https://github.com/gulpjs/vinyl-fs/commit/6004e32a6c5dca3f9361695d1b9797bbc4529337) 0.3.1 (@contra) - [#26](https://github.com/gulpjs/vinyl-fs/pull/26) feat(lib/*.js): change map-stream to through2 (@tomchentw) - [b181693](https://github.com/gulpjs/vinyl-fs/commit/b181693e7c2dd1b3992be02af899b8024669771c) styles(lib): changed done back to cb (@tomchentw) - [c5d76e5](https://github.com/gulpjs/vinyl-fs/commit/c5d76e51157a7ae7788d7dd762145ca48a701dfb) feat(lib/*.js): change map-stream to through2@0.5.1 (@tomchentw) - [583d30e](https://github.com/gulpjs/vinyl-fs/commit/583d30efd72267b59752f98a920541b1cfadb31c) function for dest, closes #15 (@contra) - [d0ba8bb](https://github.com/gulpjs/vinyl-fs/commit/d0ba8bba4519df2b6bb41f0f07cfaf1d7a5fbf7d) make src a passthrough, clean up mode logic in dest, jshint, stylize (@contra) - [c9b2c07](https://github.com/gulpjs/vinyl-fs/commit/c9b2c075dbb55ee97cd6ab9909bd1e1f87bf77e0) update graceful-fs dep (@contra) - [7af93d0](https://github.com/gulpjs/vinyl-fs/commit/7af93d0c63822f17183b89ec591622d14f9f17ca) update travis yml (@contra) - [49fb44d](https://github.com/gulpjs/vinyl-fs/commit/49fb44d44d6891f450c4c7cef9bda3caa4035107) 0.2.0 - BOM stripping and dep updates (@contra) - [#21](https://github.com/gulpjs/vinyl-fs/pull/21) Strip BOM when reading UTF-8 files (@mathiasbynens) - [4c1fc02](https://github.com/gulpjs/vinyl-fs/commit/4c1fc02bab8c2ca8fcefe0bff80347cc0b17712b) Strip BOM when reading UTF-8-encoded files (@mathiasbynens) - [abd2fe4](https://github.com/gulpjs/vinyl-fs/commit/abd2fe4e1e32ef46d7544ce90fe941ece3a49a55) rollback gaze update (@contra) - [103bb8c](https://github.com/gulpjs/vinyl-fs/commit/103bb8ca0b16e888ee44146603d5591220e228f4) update glob-watcher (@contra) - [a319889](https://github.com/gulpjs/vinyl-fs/commit/a319889b9cbad1db0097d041ad02e0e2f76640bf) check src and dest args, closes #8 (@contra) - [671197a](https://github.com/gulpjs/vinyl-fs/commit/671197a54ddda0277abdc0c1c9fce27cc8ab9b86) drop support for 0.9 (@contra) - [f89e03e](https://github.com/gulpjs/vinyl-fs/commit/f89e03e62cb62dc6c28d0ebe6f146123be2232a7) 0.1.0 (@contra) - [bb34369](https://github.com/gulpjs/vinyl-fs/commit/bb343692f3bbeab08b40b4bb1ee20af7205f2837) comment (@contra) - [c1c866a](https://github.com/gulpjs/vinyl-fs/commit/c1c866a5277038056d52fb106b2bca8cea430e59) mergit (@contra) - [cc81580](https://github.com/gulpjs/vinyl-fs/commit/cc81580a4818e2260a367c54bdcc42b0b4d0a5cc) respect file modes in dest, add mode option to dest (@contra) - [#10](https://github.com/gulpjs/vinyl-fs/pull/10) Allow piping streaming vinyls through multiple .dest()'s (@hughsk) - [d5566b2](https://github.com/gulpjs/vinyl-fs/commit/d5566b213b7e90a94b20aad35d4c08b2861c8247) Use ./src/streamFile for re-streaming .dest() streams (@hughsk) - [868a3ec](https://github.com/gulpjs/vinyl-fs/commit/868a3ecc7945e798ee702cc30c5bcfff2af3ecd5) Allow piping streaming vinyls through multiple .dest()'s (@hughsk) - [191d4ae](https://github.com/gulpjs/vinyl-fs/commit/191d4ae3672c76eb0cf0d46a2404c8e60e587d85) update file paths as they cruise through .dest (@contra) - [cb69aa6](https://github.com/gulpjs/vinyl-fs/commit/cb69aa6c7ead7a435067fdfc89f89cd8af1215d4) cleanup (@contra) - [f50d669](https://github.com/gulpjs/vinyl-fs/commit/f50d669a968f6f69ef07a0cc34b11704829c9c9f) add tests for relative cwd (@contra) - [39dfc18](https://github.com/gulpjs/vinyl-fs/commit/39dfc189367154136718fa0958712b1b14ea5e5a) fix tests (@contra) - [60dac5f](https://github.com/gulpjs/vinyl-fs/commit/60dac5fa38c3470556d987b01405d3ccca6af9ec) remove async dep (@contra) - [1178422](https://github.com/gulpjs/vinyl-fs/commit/11784223e5a38795715c759333b352d40e83c76a) more tests (@contra) - [ed50c02](https://github.com/gulpjs/vinyl-fs/commit/ed50c02ba3487e8f4212792a0db2aa39dbc060a6) directory test (@contra) - [ee32c0a](https://github.com/gulpjs/vinyl-fs/commit/ee32c0a3a5f7aa30fc62a8481dd2f38aa410fa1a) more simplifying (@contra) - [fb481f0](https://github.com/gulpjs/vinyl-fs/commit/fb481f0c6baedf89635faa1eb278cafb4b72c5bb) more simplifying (@contra) - [a415173](https://github.com/gulpjs/vinyl-fs/commit/a4151738c740a760fa8b577a4f633ea6aad4055c) yep (@contra) - [753add9](https://github.com/gulpjs/vinyl-fs/commit/753add9acc8cc0b3ff883f5228c972731a5fde74) simplify dest (@contra) - [5325dcf](https://github.com/gulpjs/vinyl-fs/commit/5325dcf796e1e6db86a3c9abd58484f552c299f8) cwd in dest (@contra) - [1b975fd](https://github.com/gulpjs/vinyl-fs/commit/1b975fdbf6c005674e86454b1a780b1fbf72f605) test cleaning (@contra) - [abdcbb7](https://github.com/gulpjs/vinyl-fs/commit/abdcbb7fcd8b78469eaf784675df2d7c7a15c766) coveralls (@contra) - [b7a8ebc](https://github.com/gulpjs/vinyl-fs/commit/b7a8ebcfa07865a283b5efe69303b795a2dcdd83) license update (@contra) - [bac7381](https://github.com/gulpjs/vinyl-fs/commit/bac7381e31b7c30aed8ae925d12821cf65f9337e) more dep updates (@contra) - [14f0a1e](https://github.com/gulpjs/vinyl-fs/commit/14f0a1eeaab5ca6a52042aae489a2da5ef78c318) badges and refactor (@contra) - [8ac77fc](https://github.com/gulpjs/vinyl-fs/commit/8ac77fc245b8b3938c74748900358e9ad540e4bd) wait for file close in writeStream (@contra) - [002273c](https://github.com/gulpjs/vinyl-fs/commit/002273cfae226d562a8b22173c3a718614444c7a) writeStream fix (@contra) - [af64059](https://github.com/gulpjs/vinyl-fs/commit/af640595b1325385ce650b410f9091531447b35a) Merge branch 'master' of https://github.com/wearefractal/vinyl-fs (@contra) - [5c36fbc](https://github.com/gulpjs/vinyl-fs/commit/5c36fbcaa7d7eca58fb5f035bf15492f4a3b737a) trim fat - graceful-fs, map-stream, etc. (@contra) - [#3](https://github.com/gulpjs/vinyl-fs/pull/3) Fix broken refactor changes (@yyx990803) - [c610342](https://github.com/gulpjs/vinyl-fs/commit/c610342755156dc9c059f21ac31a679623cef227) fix writePath - [b09678b](https://github.com/gulpjs/vinyl-fs/commit/b09678b05069852d713a263e8526f30f83ecae23) require deps in writecontent.js - [a30a0ea](https://github.com/gulpjs/vinyl-fs/commit/a30a0ea5ba65aa32b8a3a7a72fe6ddcbb20fe3fa) watch added (@contra) - [209d4f2](https://github.com/gulpjs/vinyl-fs/commit/209d4f235fcd4419318527a96f6bc8757a4b87a7) flesh out more (@contra) - [5958e7e](https://github.com/gulpjs/vinyl-fs/commit/5958e7e7b55bed41ae0972d721eae91ea9d21cbf) new vinyl file isDirectory changes (@contra) - [7f8684b](https://github.com/gulpjs/vinyl-fs/commit/7f8684b87d93ee66fdbefe5397c8b7e365727d3d) more tests (@contra) - [bf1f18c](https://github.com/gulpjs/vinyl-fs/commit/bf1f18cef59dff9ad01658b5e11968f2a3b11ff5) start tests (@contra) - [23a1cff](https://github.com/gulpjs/vinyl-fs/commit/23a1cff61b8fcc07d543c1757a415591277a5425) fix deps (@contra) - [35f230b](https://github.com/gulpjs/vinyl-fs/commit/35f230b2abe22e5fa0cc710a9bbbfb8dd3cfe3fa) start impl (@contra)vinyl-fs-2.4.4/LICENSE000077500000000000000000000020731300000231200142570ustar00rootroot00000000000000Copyright (c) 2013-2016 Fractal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. vinyl-fs-2.4.4/README.md000066400000000000000000000225201300000231200145250ustar00rootroot00000000000000

# vinyl-fs [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url] [Vinyl][vinyl] adapter for the file system. ## What is Vinyl? [Vinyl][vinyl] is a very simple metadata object that describes a file. When you think of a file, two attributes come to mind: `path` and `contents`. These are the main attributes on a [Vinyl][vinyl] object. A file does not necessarily represent something on your computer’s file system. You have files on S3, FTP, Dropbox, Box, CloudThingly.io and other services. [Vinyl][vinyl] can be used to describe files from all of these sources. ## What is a Vinyl Adapter? While Vinyl provides a clean way to describe a file, we now need a way to access these files. Each file source needs what I call a "Vinyl adapter". A Vinyl adapter simply exposes a `src(globs)` and a `dest(folder)` method. Each return a stream. The `src` stream produces Vinyl objects, and the `dest` stream consumes Vinyl objects. Vinyl adapters can expose extra methods that might be specific to their input/output medium, such as the `symlink` method `vinyl-fs` provides. ## Usage ```javascript var map = require('map-stream'); var vfs = require('vinyl-fs'); var log = function(file, cb) { console.log(file.path); cb(null, file); }; vfs.src(['./js/**/*.js', '!./js/vendor/*.js']) .pipe(map(log)) .pipe(vfs.dest('./output')); ``` ## API ### `src(globs[, options])` Takes a glob string or an array of glob strings as the first argument and an options object as the second. Returns a stream of [vinyl] `File` objects. __Note: UTF-8 BOM will be stripped from all UTF-8 files read with `.src` unless disabled in the options.__ #### Globs Globs are executed in order, so negations should follow positive globs. For example: ```js fs.src(['!b*.js', '*.js']) ``` would not exclude any files, but the following would: ```js fs.src(['*.js', '!b*.js']) ``` #### Options ##### `options.cwd` The working directory the folder is relative to. Type: `String` Default: `process.cwd()` ##### `options.base` The folder relative to the cwd. This is used to determine the file names when saving in `.dest()`. Type: `String` Default: The part of the path before the glob (if any) begins. For example, `path/to/**/*.js` would resolve to `path/to`. If there is no glob (i.e. a file path with no pattern), then the dirname of the path is used. For example, `path/to/some/file.js` would resolve to `path/to/some`. ##### `options.buffer` Whether or not you want to buffer the file contents into memory. Setting to `false` will make `file.contents` a paused Stream. Type: `Boolean` Default: `true` ##### `options.read` Whether or not you want the file to be read at all. Useful for stuff like removing files. Setting to `false` will make `file.contents` `null` and will disable writing the file to disk via `.dest()`. Type: `Boolean` Default: `true` ##### `options.since` Only streams files that have been modified since the time specified. Type: `Date` or `Number` Default: `undefined` ##### `options.stripBOM` Causes the BOM to be stripped on UTF-8 encoded files. Set to `false` if you need the BOM for some reason. Type: `Boolean` Default: `true` ##### `options.passthrough` Allows `.src` to be used in the middle of a pipeline (using a duplex stream) which passes through all objects received and adds all files globbed to the stream. Type: `Boolean` Default: `false` ##### `options.sourcemaps` Enables sourcemap support on files passed through the stream. Will load inline sourcemaps and resolve sourcemap links from files. Uses [gulp-sourcemaps] under the hood. Type: `Boolean` Default: `false` ##### `options.followSymlinks` - `true` if you want Whether or not to recursively resolve symlinks to their targets. Setting to `false` to preserve them as symlinks and make `file.symlink` equal the original symlink's target path. Type: `Boolean` Default: `true` ##### other Any glob-related options are documented in [glob-stream] and [node-glob]. Any through2-related options are documented in [through2]. ### `dest(folder[, options])` Takes a folder path string or a function as the first argument and an options object as the second. If given a function, it will be called with each [vinyl] `File` object and must return a folder path. Returns a stream that accepts [vinyl] `File` objects, writes them to disk at the folder/cwd specified, and passes them downstream so you can keep piping these around. Once the file is written to disk, an attempt is made to determine if the `stat.mode`, `stat.mtime` and `stat.atime` of the [vinyl] `File` object differ from the file on the filesystem. If they differ and the running process owns the file, the corresponding filesystem metadata is updated. If they don't differ or the process doesn't own the file, the attempt is skipped silently. __This functionality is disabled on Windows operating systems or any other OS that doesn't support `process.getuid` or `process.geteuid` in node. This is due to Windows having very unexpected results through usage of `fs.fchmod` and `fs.futimes`.__ If the file has a `symlink` attribute specifying a target path, then a symlink will be created. __Note: The file will be modified after being written to this stream.__ - `cwd`, `base`, and `path` will be overwritten to match the folder. - `stat` will be updated to match the file on the filesystem. - `contents` will have it's position reset to the beginning if it is a stream. #### Options ##### `options.cwd` The working directory the folder is relative to. Type: `String` Default: `process.cwd()` ##### `options.base` The folder relative to the cwd. This is used to determine the file names when saving in `.dest()`. Can also be a function that takes in a file and returns a folder path. Type: `String` or `Function` Default: The `cwd` resolved to the folder path. ##### `options.mode` The mode the files should be created with. Type: `Number` Default: The `mode` of the input file (`file.stat.mode`) if any, or the process mode if the input file has no `mode` property. ##### `options.dirMode` The mode the directory should be created with. Type: `Number` Default: The process `mode`. ##### `options.overwrite` Whether or not existing files with the same path should be overwritten. Can also be a function that takes in a file and returns `true` or `false`. Type: `Boolean` or `Function` Default: `true` (always overwrite existing files) ##### `options.sourcemaps` Enables sourcemap support on files passed through the stream. Will write inline soucemaps if specified as `true`. Specifying a `string` is shorthand for the path option. Uses [gulp-sourcemaps] under the hood. Examples: ```js // Write as inline comments vfs.dest('./', { sourcemaps: true }); // Write as files in the same folder vfs.dest('./', { sourcemaps: '.' }); // Any other options are passed through to [gulp-sourcemaps] vfs.dest('./', { sourcemaps: { path: '.', addComment: false, includeContent: false } }); ``` Type: `Boolean`, `String` or `Object` Default: `undefined` (do not write sourcemaps) ##### other Any through2-related options are documented in [through2]. ### `symlink(folder[, options])` Takes a folder path string or a function as the first argument and an options object as the second. If given a function, it will be called with each [vinyl] `File` object and must return a folder path. Returns a stream that accepts [vinyl] `File` objects, create a symbolic link (i.e. symlink) at the folder/cwd specified, and passes them downstream so you can keep piping these around. __Note: The file will be modified after being written to this stream.__ - `cwd`, `base`, and `path` will be overwritten to match the folder. #### Options ##### `options.cwd` The working directory the folder is relative to. Type: `String` Default: `process.cwd()` ##### `options.base` The folder relative to the cwd. This is used to determine the file names when saving in `.symlink()`. Can also be a function that takes in a file and returns a folder path. Type: `String` or `Function` Default: The `cwd` resolved to the folder path. ##### `options.dirMode` The mode the directory should be created with. Type: `Number` Default: The process mode. ##### other Any through2-related options are documented in [through2]. [glob-stream]: https://github.com/gulpjs/glob-stream [gulp-sourcemaps]: https://github.com/floridoo/gulp-sourcemaps [node-glob]: https://github.com/isaacs/node-glob [gaze]: https://github.com/shama/gaze [glob-watcher]: https://github.com/wearefractal/glob-watcher [vinyl]: https://github.com/wearefractal/vinyl [through2]: https://github.com/rvagg/through2 [downloads-image]: http://img.shields.io/npm/dm/vinyl-fs.svg [npm-url]: https://www.npmjs.com/package/vinyl-fs [npm-image]: https://badge.fury.io/js/vinyl-fs.svg [travis-url]: https://travis-ci.org/gulpjs/vinyl-fs [travis-image]: https://travis-ci.org/gulpjs/vinyl-fs.svg?branch=master [coveralls-url]: https://coveralls.io/r/gulpjs/vinyl-fs [coveralls-image]: https://coveralls.io/repos/gulpjs/vinyl-fs/badge.svg [gitter-url]: https://gitter.im/gulpjs/gulp [gitter-image]: https://badges.gitter.im/gulpjs/gulp.png vinyl-fs-2.4.4/appveyor.yml000066400000000000000000000006671300000231200156460ustar00rootroot00000000000000# http://www.appveyor.com/docs/appveyor-yml # http://www.appveyor.com/docs/lang/nodejs-iojs environment: matrix: # node.js - nodejs_version: "0.10" - nodejs_version: "0.12" - nodejs_version: "4" - nodejs_version: "5" install: - ps: Install-Product node $env:nodejs_version - npm install test_script: - node --version - npm --version - cmd: npm test build: off # build version format version: "{build}" vinyl-fs-2.4.4/index.js000066400000000000000000000002061300000231200147100ustar00rootroot00000000000000'use strict'; module.exports = { src: require('./lib/src'), dest: require('./lib/dest'), symlink: require('./lib/symlink'), }; vinyl-fs-2.4.4/lib/000077500000000000000000000000001300000231200140135ustar00rootroot00000000000000vinyl-fs-2.4.4/lib/dest/000077500000000000000000000000001300000231200147525ustar00rootroot00000000000000vinyl-fs-2.4.4/lib/dest/index.js000066400000000000000000000025321300000231200164210ustar00rootroot00000000000000'use strict'; var through2 = require('through2'); var sourcemaps = require('gulp-sourcemaps'); var duplexify = require('duplexify'); var sink = require('../sink'); var prepareWrite = require('../prepareWrite'); var writeContents = require('./writeContents'); function dest(outFolder, opt) { if (!opt) { opt = {}; } function saveFile(file, enc, cb) { prepareWrite(outFolder, file, opt, function(err, writePath) { if (err) { return cb(err); } writeContents(writePath, file, cb); }); } var saveStream = through2.obj(opt, saveFile); if (!opt.sourcemaps) { // Sink the save stream to start flowing // Do this on nextTick, it will flow at slowest speed of piped streams process.nextTick(sink(saveStream)); return saveStream; } var sourcemapOpt = opt.sourcemaps; if (typeof sourcemapOpt === 'boolean') { sourcemapOpt = {}; } if (typeof sourcemapOpt === 'string') { sourcemapOpt = { path: sourcemapOpt, }; } var mapStream = sourcemaps.write(sourcemapOpt.path, sourcemapOpt); var outputStream = duplexify.obj(mapStream, saveStream); mapStream.pipe(saveStream); // Sink the output stream to start flowing // Do this on nextTick, it will flow at slowest speed of piped streams process.nextTick(sink(outputStream)); return outputStream; } module.exports = dest; vinyl-fs-2.4.4/lib/dest/writeContents/000077500000000000000000000000001300000231200176225ustar00rootroot00000000000000vinyl-fs-2.4.4/lib/dest/writeContents/index.js000066400000000000000000000025061300000231200212720ustar00rootroot00000000000000'use strict'; var writeDir = require('./writeDir'); var writeStream = require('./writeStream'); var writeBuffer = require('./writeBuffer'); var writeSymbolicLink = require('./writeSymbolicLink'); function writeContents(writePath, file, callback) { // If directory then mkdirp it if (file.isDirectory()) { return writeDir(writePath, file, written); } // Stream it to disk yo if (file.isStream()) { return writeStream(writePath, file, written); } // Write it as a symlink if (file.symlink) { return writeSymbolicLink(writePath, file, written); } // Write it like normal if (file.isBuffer()) { return writeBuffer(writePath, file, written); } // If no contents then do nothing if (file.isNull()) { return written(); } // This is invoked by the various writeXxx modules when they've finished // writing the contents. function written(err) { if (isErrorFatal(err)) { return callback(err); } callback(null, file); } function isErrorFatal(err) { if (!err) { return false; } if (err.code === 'EEXIST' && file.flag === 'wx') { // Handle scenario for file overwrite failures. return false; // "These aren't the droids you're looking for" } // Otherwise, this is a fatal error return true; } } module.exports = writeContents; vinyl-fs-2.4.4/lib/dest/writeContents/writeBuffer.js000066400000000000000000000007731300000231200224530ustar00rootroot00000000000000'use strict'; var fo = require('../../fileOperations'); function writeBuffer(writePath, file, written) { var opt = { mode: file.stat.mode, flag: file.flag, }; fo.writeFile(writePath, file.contents, opt, onWriteFile); function onWriteFile(writeErr, fd) { if (writeErr) { return fo.closeFd(writeErr, fd, written); } fo.updateMetadata(fd, file, onUpdate); } function onUpdate(statErr, fd) { fo.closeFd(statErr, fd, written); } } module.exports = writeBuffer; vinyl-fs-2.4.4/lib/dest/writeContents/writeDir.js000066400000000000000000000017051300000231200217540ustar00rootroot00000000000000'use strict'; var fs = require('graceful-fs'); var mkdirp = require('mkdirp'); var fo = require('../../fileOperations'); function writeDir(writePath, file, written) { var mkdirpOpts = { mode: file.stat.mode, fs: fs, }; mkdirp(writePath, mkdirpOpts, onMkdirp); function onMkdirp(mkdirpErr) { if (mkdirpErr) { return written(mkdirpErr); } fs.open(writePath, 'r', onOpen); } function onOpen(openErr, fd) { // If we don't have access, just move along if (isInaccessible(openErr)) { return fo.closeFd(null, fd, written); } if (openErr) { return fo.closeFd(openErr, fd, written); } fo.updateMetadata(fd, file, onUpdate); } function onUpdate(statErr, fd) { fo.closeFd(statErr, fd, written); } } function isInaccessible(err) { if (!err) { return false; } if (err.code === 'EACCES') { return true; } return false; } module.exports = writeDir; vinyl-fs-2.4.4/lib/dest/writeContents/writeStream.js000066400000000000000000000025111300000231200224650ustar00rootroot00000000000000'use strict'; var fs = require('graceful-fs'); var fo = require('../../fileOperations'); var streamFile = require('../../src/getContents/streamFile'); function writeStream(writePath, file, written) { var opt = { mode: file.stat.mode, flag: file.flag, }; var outStream = fs.createWriteStream(writePath, opt); file.contents.once('error', complete); file.contents.once('end', readStreamEnd); outStream.once('error', complete); outStream.once('finish', complete); // Streams are piped with end disabled, this prevents the // WriteStream from closing the file descriptor after all // data is written. file.contents.pipe(outStream, { end: false }); function readStreamEnd() { streamFile(file, complete); } function end(propagatedErr) { outStream.end(onEnd); function onEnd(endErr) { written(propagatedErr || endErr); } } // Cleanup function complete(streamErr) { file.contents.removeListener('error', complete); file.contents.removeListener('end', readStreamEnd); outStream.removeListener('error', complete); outStream.removeListener('finish', complete); if (streamErr) { return end(streamErr); } if (typeof outStream.fd !== 'number') { return end(); } fo.updateMetadata(outStream.fd, file, end); } } module.exports = writeStream; vinyl-fs-2.4.4/lib/dest/writeContents/writeSymbolicLink.js000066400000000000000000000006051300000231200236330ustar00rootroot00000000000000'use strict'; var fs = require('graceful-fs'); function writeSymbolicLink(writePath, file, written) { // TODO handle symlinks properly fs.symlink(file.symlink, writePath, function(err) { if (isFatalError(err)) { return written(err); } written(); }); } function isFatalError(err) { return (err && err.code !== 'EEXIST'); } module.exports = writeSymbolicLink; vinyl-fs-2.4.4/lib/fileOperations.js000066400000000000000000000104351300000231200173370ustar00rootroot00000000000000'use strict'; var fs = require('graceful-fs'); var assign = require('object-assign'); var isEqual = require('lodash.isequal'); var isValidDate = require('vali-date'); // TODO shared module // TODO include sticky/setuid/setgid, i.e. 7777? var MASK_MODE = parseInt('0777', 8); var DEFAULT_FILE_MODE = parseInt('0666', 8); var APPEND_MODE_REGEXP = /a/; function closeFd(propagatedErr, fd, callback) { if (typeof fd !== 'number') { return callback(propagatedErr); } fs.close(fd, onClosed); function onClosed(closeErr) { if (propagatedErr || closeErr) { return callback(propagatedErr || closeErr); } callback(); } } function getModeDiff(fsMode, vinylMode) { var modeDiff = 0; if (typeof vinylMode === 'number') { modeDiff = (vinylMode ^ fsMode) & MASK_MODE; } return modeDiff; } function getTimesDiff(fsStat, vinylStat) { if (!isValidDate(vinylStat.mtime)) { return; } if (isEqual(vinylStat.mtime, fsStat.mtime) && isEqual(vinylStat.atime, fsStat.atime)) { return; } var atime; if (isValidDate(vinylStat.atime)) { atime = vinylStat.atime; } else { atime = fsStat.atime; } if (!isValidDate(atime)) { atime = undefined; } var timesDiff = { mtime: vinylStat.mtime, atime: atime, }; return timesDiff; } function isOwner(fsStat) { var hasGetuid = (typeof process.getuid === 'function'); var hasGeteuid = (typeof process.geteuid === 'function'); // If we don't have either, assume we don't have permissions. // This should only happen on Windows. // Windows basically noops fchmod and errors on futimes called on directories. if (!hasGeteuid && !hasGetuid) { return false; } var uid; if (hasGeteuid) { uid = process.geteuid(); } else { uid = process.getuid(); } if (fsStat.uid !== uid && uid !== 0) { return false; } return true; } function updateMetadata(fd, file, callback) { fs.fstat(fd, onStat); function onStat(err, stat) { if (err) { return callback(err, fd); } // Check if mode needs to be updated var modeDiff = getModeDiff(stat.mode, file.stat.mode); // Check if atime/mtime need to be updated var timesDiff = getTimesDiff(stat, file.stat); // Set file.stat to the reflect current state on disk assign(file.stat, stat); // Nothing to do if (!modeDiff && !timesDiff) { return callback(null, fd); } // Check access, `futimes` and `fchmod` only work if we own the file, // or if we are effectively root. if (!isOwner(stat)) { return callback(null, fd); } if (modeDiff) { return mode(); } times(); function mode() { var mode = stat.mode ^ modeDiff; fs.fchmod(fd, mode, onFchmod); function onFchmod(fchmodErr) { if (!fchmodErr) { file.stat.mode = mode; } if (timesDiff) { return times(fchmodErr); } callback(fchmodErr, fd); } } function times(fchmodErr) { fs.futimes(fd, timesDiff.atime, timesDiff.mtime, onFutimes); function onFutimes(futimesErr) { if (!futimesErr) { file.stat.atime = timesDiff.atime; file.stat.mtime = timesDiff.mtime; } callback(fchmodErr || futimesErr, fd); } } } } /* Custom writeFile implementation because we need access to the file descriptor after the write is complete. Most of the implementation taken from node core. */ function writeFile(path, data, options, callback) { if (typeof options === 'function') { callback = options; options = {}; } if (!Buffer.isBuffer(data)) { callback(new TypeError('Data must be a Buffer')); return; } if (!options) { options = {}; } // Default the same as node var mode = options.mode || DEFAULT_FILE_MODE; var flag = options.flag || 'w'; var position = APPEND_MODE_REGEXP.test(flag) ? null : 0; fs.open(path, flag, mode, onOpen); function onOpen(err, fd) { if (err) { return onComplete(err); } fs.write(fd, data, 0, data.length, position, onComplete); function onComplete(err) { callback(err, fd); } } } module.exports = { closeFd: closeFd, getModeDiff: getModeDiff, getTimesDiff: getTimesDiff, isOwner: isOwner, updateMetadata: updateMetadata, writeFile: writeFile, }; vinyl-fs-2.4.4/lib/filterSince.js000066400000000000000000000005541300000231200166240ustar00rootroot00000000000000'use strict'; var filter = require('through2-filter'); module.exports = function(d) { var isValid = typeof d === 'number' || d instanceof Number || d instanceof Date; if (!isValid) { throw new Error('expected since option to be a date or a number'); } return filter.obj(function(file) { return file.stat && file.stat.mtime > d; }); }; vinyl-fs-2.4.4/lib/prepareWrite.js000066400000000000000000000032251300000231200170240ustar00rootroot00000000000000'use strict'; var assign = require('object-assign'); var path = require('path'); var mkdirp = require('mkdirp'); var fs = require('graceful-fs'); function booleanOrFunc(v, file) { if (typeof v !== 'boolean' && typeof v !== 'function') { return null; } return typeof v === 'boolean' ? v : v(file); } function stringOrFunc(v, file) { if (typeof v !== 'string' && typeof v !== 'function') { return null; } return typeof v === 'string' ? v : v(file); } function prepareWrite(outFolder, file, opt, cb) { var options = assign({ cwd: process.cwd(), mode: (file.stat ? file.stat.mode : null), dirMode: null, overwrite: true, }, opt); var overwrite = booleanOrFunc(options.overwrite, file); options.flag = (overwrite ? 'w' : 'wx'); var cwd = path.resolve(options.cwd); var outFolderPath = stringOrFunc(outFolder, file); if (!outFolderPath) { throw new Error('Invalid output folder'); } var basePath = options.base ? stringOrFunc(options.base, file) : path.resolve(cwd, outFolderPath); if (!basePath) { throw new Error('Invalid base option'); } var writePath = path.resolve(basePath, file.relative); var writeFolder = path.dirname(writePath); // Wire up new properties file.stat = (file.stat || new fs.Stats()); file.stat.mode = options.mode; file.flag = options.flag; file.cwd = cwd; file.base = basePath; file.path = writePath; // Mkdirp the folder the file is going in var mkdirpOpts = { mode: options.dirMode, fs: fs, }; mkdirp(writeFolder, mkdirpOpts, function(err) { if (err) { return cb(err); } cb(null, writePath); }); } module.exports = prepareWrite; vinyl-fs-2.4.4/lib/sink.js000066400000000000000000000017151300000231200153210ustar00rootroot00000000000000'use strict'; var Writable = require('readable-stream/writable'); function listenerCount(stream, evt) { return stream.listeners(evt).length; } function hasListeners(stream) { return !!(listenerCount(stream, 'readable') || listenerCount(stream, 'data')); } function sink(stream) { var sinkAdded = false; var sinkStream = new Writable({ objectMode: true, write: function(file, enc, cb) { cb(); }, }); function addSink() { if (sinkAdded) { return; } if (hasListeners(stream)) { return; } sinkAdded = true; stream.pipe(sinkStream); } function removeSink(evt) { if (evt !== 'readable' && evt !== 'data') { return; } if (hasListeners(stream)) { sinkAdded = false; stream.unpipe(sinkStream); } } stream.on('newListener', removeSink); stream.on('removeListener', removeSink); stream.on('removeListener', addSink); return addSink; } module.exports = sink; vinyl-fs-2.4.4/lib/src/000077500000000000000000000000001300000231200146025ustar00rootroot00000000000000vinyl-fs-2.4.4/lib/src/getContents/000077500000000000000000000000001300000231200170775ustar00rootroot00000000000000vinyl-fs-2.4.4/lib/src/getContents/bufferFile.js000066400000000000000000000005761300000231200215160ustar00rootroot00000000000000'use strict'; var fs = require('graceful-fs'); var stripBom = require('strip-bom'); function bufferFile(file, opt, cb) { fs.readFile(file.path, function(err, data) { if (err) { return cb(err); } if (opt.stripBOM) { file.contents = stripBom(data); } else { file.contents = data; } cb(null, file); }); } module.exports = bufferFile; vinyl-fs-2.4.4/lib/src/getContents/index.js000066400000000000000000000014771300000231200205550ustar00rootroot00000000000000'use strict'; var through2 = require('through2'); var readDir = require('./readDir'); var readSymbolicLink = require('./readSymbolicLink'); var bufferFile = require('./bufferFile'); var streamFile = require('./streamFile'); function getContents(opt) { return through2.obj(opt, function(file, enc, cb) { // Don't fail to read a directory if (file.isDirectory()) { return readDir(file, opt, cb); } // Process symbolic links included with `followSymlinks` option if (file.stat && file.stat.isSymbolicLink()) { return readSymbolicLink(file, opt, cb); } // Read and pass full contents if (opt.buffer !== false) { return bufferFile(file, opt, cb); } // Don't buffer anything - just pass streams return streamFile(file, opt, cb); }); } module.exports = getContents; vinyl-fs-2.4.4/lib/src/getContents/readDir.js000066400000000000000000000001701300000231200210050ustar00rootroot00000000000000'use strict'; function readDir(file, opt, cb) { // Do nothing for now cb(null, file); } module.exports = readDir; vinyl-fs-2.4.4/lib/src/getContents/readSymbolicLink.js000066400000000000000000000004561300000231200226750ustar00rootroot00000000000000'use strict'; var fs = require('graceful-fs'); function readLink(file, opt, cb) { fs.readlink(file.path, function(err, target) { if (err) { return cb(err); } // Store the link target path file.symlink = target; return cb(null, file); }); } module.exports = readLink; vinyl-fs-2.4.4/lib/src/getContents/streamFile.js000066400000000000000000000007641300000231200215370ustar00rootroot00000000000000'use strict'; var fs = require('graceful-fs'); var stripBom = require('strip-bom-stream'); var lazystream = require('lazystream'); function streamFile(file, opt, cb) { if (typeof opt === 'function') { cb = opt; opt = {}; } var filePath = file.path; file.contents = new lazystream.Readable(function() { return fs.createReadStream(filePath); }); if (opt.stripBOM) { file.contents = file.contents.pipe(stripBom()); } cb(null, file); } module.exports = streamFile; vinyl-fs-2.4.4/lib/src/index.js000066400000000000000000000030241300000231200162460ustar00rootroot00000000000000'use strict'; var assign = require('object-assign'); var through2 = require('through2'); var gs = require('glob-stream'); var duplexify = require('duplexify'); var merge = require('merge-stream'); var sourcemaps = require('gulp-sourcemaps'); var filterSince = require('../filterSince'); var isValidGlob = require('is-valid-glob'); var getContents = require('./getContents'); var wrapWithVinylFile = require('./wrapWithVinylFile'); function src(glob, opt) { var options = assign({ read: true, buffer: true, stripBOM: true, sourcemaps: false, passthrough: false, followSymlinks: true, }, opt); // Don't pass `read` option on to through2 var read = options.read !== false; options.read = undefined; var inputPass; if (!isValidGlob(glob)) { throw new Error('Invalid glob argument: ' + glob); } var globStream = gs.create(glob, options); var outputStream = globStream .pipe(wrapWithVinylFile(options)); if (options.since != null) { outputStream = outputStream .pipe(filterSince(options.since)); } if (read) { outputStream = outputStream .pipe(getContents(options)); } if (options.passthrough === true) { inputPass = through2.obj(options); outputStream = duplexify.obj(inputPass, merge(outputStream, inputPass)); } if (options.sourcemaps === true) { outputStream = outputStream .pipe(sourcemaps.init({ loadMaps: true })); } globStream.on('error', outputStream.emit.bind(outputStream, 'error')); return outputStream; } module.exports = src; vinyl-fs-2.4.4/lib/src/wrapWithVinylFile.js000066400000000000000000000026661300000231200206010ustar00rootroot00000000000000'use strict'; var through2 = require('through2'); var fs = require('graceful-fs'); var File = require('vinyl'); function wrapWithVinylFile(options) { // A stat property is exposed on file objects as a (wanted) side effect function resolveFile(globFile, enc, cb) { fs.lstat(globFile.path, function(err, stat) { if (err) { return cb(err); } globFile.stat = stat; if (!stat.isSymbolicLink() || !options.followSymlinks) { var vinylFile = new File(globFile); if (globFile.originalSymlinkPath) { // If we reach here, it means there is at least one // symlink on the path and we need to rewrite the path // to its original value. // Updated file stats will tell getContents() to actually read it. vinylFile.path = globFile.originalSymlinkPath; } return cb(null, vinylFile); } fs.realpath(globFile.path, function(err, filePath) { if (err) { return cb(err); } if (!globFile.originalSymlinkPath) { // Store the original symlink path before the recursive call // to later rewrite it back. globFile.originalSymlinkPath = globFile.path; } globFile.path = filePath; // Recurse to get real file stat resolveFile(globFile, enc, cb); }); }); } return through2.obj(options, resolveFile); } module.exports = wrapWithVinylFile; vinyl-fs-2.4.4/lib/symlink/000077500000000000000000000000001300000231200155015ustar00rootroot00000000000000vinyl-fs-2.4.4/lib/symlink/index.js000066400000000000000000000013621300000231200171500ustar00rootroot00000000000000'use strict'; var through2 = require('through2'); var fs = require('graceful-fs'); var prepareWrite = require('../prepareWrite'); function symlink(outFolder, opt) { function linkFile(file, enc, cb) { var srcPath = file.path; var symType = (file.isDirectory() ? 'dir' : 'file'); prepareWrite(outFolder, file, opt, function(err, writePath) { if (err) { return cb(err); } fs.symlink(srcPath, writePath, symType, function(err) { if (err && err.code !== 'EEXIST') { return cb(err); } cb(null, file); }); }); } var stream = through2.obj(opt, linkFile); // TODO: option for either backpressure or lossy stream.resume(); return stream; } module.exports = symlink; vinyl-fs-2.4.4/package.json000066400000000000000000000033241300000231200155350ustar00rootroot00000000000000{ "name": "vinyl-fs", "description": "Vinyl adapter for the file system", "version": "2.4.4", "homepage": "http://github.com/wearefractal/vinyl-fs", "repository": "git://github.com/wearefractal/vinyl-fs.git", "author": "Fractal (http://wearefractal.com/)", "main": "./index.js", "files": [ "index.js", "lib" ], "dependencies": { "duplexify": "^3.2.0", "glob-stream": "^5.3.2", "graceful-fs": "^4.0.0", "gulp-sourcemaps": "1.6.0", "is-valid-glob": "^0.3.0", "lazystream": "^1.0.0", "lodash.isequal": "^4.0.0", "merge-stream": "^1.0.0", "mkdirp": "^0.5.0", "object-assign": "^4.0.0", "readable-stream": "^2.0.4", "strip-bom": "^2.0.0", "strip-bom-stream": "^1.0.0", "through2": "^2.0.0", "through2-filter": "^2.0.0", "vali-date": "^1.0.0", "vinyl": "^1.0.0" }, "devDependencies": { "buffer-equal": "^0.0.1", "default-resolution": "^1.0.1", "del": "^2.2.0", "eslint": "^1.10.3", "eslint-config-gulp": "^2.0.0", "expect": "^1.14.0", "github-changes": "^1.0.1", "istanbul": "^0.3.0", "istanbul-coveralls": "^1.0.1", "jscs": "^2.4.0", "jscs-preset-gulp": "^1.0.0", "mocha": "^2.0.0", "mocha-lcov-reporter": "^1.0.0", "rimraf": "^2.2.5", "should": "^7.0.0", "sinon": "^1.10.3" }, "scripts": { "lint": "eslint . && jscs index.js lib/ test/", "test": "npm run lint && mocha", "cover": "istanbul cover _mocha", "coveralls": "npm run cover && istanbul-coveralls", "changelog": "github-changes -o gulpjs -r vinyl-fs -b master -f ./CHANGELOG.md --order-semver --use-commit-body" }, "engines": { "node": ">=0.10" }, "license": "MIT" } vinyl-fs-2.4.4/test/000077500000000000000000000000001300000231200142245ustar00rootroot00000000000000vinyl-fs-2.4.4/test/.eslintrc000066400000000000000000000000351300000231200160460ustar00rootroot00000000000000{ "extends": "gulp/test" } vinyl-fs-2.4.4/test/dest.js000066400000000000000000001067161300000231200155340ustar00rootroot00000000000000'use strict'; var spies = require('./spy'); var chmodSpy = spies.chmodSpy; var fchmodSpy = spies.fchmodSpy; var futimesSpy = spies.futimesSpy; var fstatSpy = spies.fstatSpy; var vfs = require('../'); var os = require('os'); var path = require('path'); var fs = require('graceful-fs'); var del = require('del'); var Writeable = require('readable-stream/writable'); var expect = require('expect'); var bufEqual = require('buffer-equal'); var through = require('through2'); var File = require('vinyl'); var should = require('should'); require('mocha'); var wipeOut = function() { this.timeout(20000); spies.setError('false'); fstatSpy.reset(); chmodSpy.reset(); fchmodSpy.reset(); futimesSpy.reset(); expect.restoreSpies(); // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 return del(path.join(__dirname, './fixtures/highwatermark')) .then(function() { return del(path.join(__dirname, './out-fixtures/')); }); }; var dataWrap = function(fn) { return function(data, enc, cb) { fn(data); cb(); }; }; var realMode = function(n) { return n & parseInt('777', 8); }; function noop() {} describe('dest stream', function() { beforeEach(wipeOut); afterEach(wipeOut); it.skip('should explode on invalid folder (empty)', function(done) { var stream; try { stream = vfs.dest(); } catch (err) { should.exist(err); should.not.exist(stream); done(); } }); it.skip('should explode on invalid folder (empty string)', function(done) { var stream; try { stream = vfs.dest(''); } catch (err) { should.exist(err); should.not.exist(stream); done(); } }); it('should not explode if the sourcemap option is true', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); done(); }; var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); var stream = vfs.dest(path.join(__dirname, './out-fixtures/'), { sourcemaps: true }); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should not explode if the sourcemap option is string', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); done(); }; var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); var stream = vfs.dest(path.join(__dirname, './out-fixtures/'), { sourcemaps: '.' }); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should not explode if sourcemap option is an object', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var options = { sourcemaps: { addComment: false, }, }; var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); done(); }; var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); var stream = vfs.dest(path.join(__dirname, './out-fixtures/'), options); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should pass through writes with cwd', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should pass through writes with default cwd', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); done(); }; var stream = vfs.dest(path.join(__dirname, './out-fixtures/')); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should not write null files', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedCwd = __dirname; var expectedBase = path.join(__dirname, './out-fixtures'); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: null, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(false); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should write buffer files to the right folder with relative cwd', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedCwd = __dirname; var expectedBase = path.join(__dirname, './out-fixtures'); var expectedContents = fs.readFileSync(inputPath); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(true); bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: path.relative(process.cwd(), __dirname) }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should write buffer files to the right folder with function and relative cwd', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedCwd = __dirname; var expectedBase = path.join(__dirname, './out-fixtures'); var expectedContents = fs.readFileSync(inputPath); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(true); bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); done(); }; var stream = vfs.dest(function(file) { should.exist(file); file.should.equal(expectedFile); return './out-fixtures'; }, { cwd: path.relative(process.cwd(), __dirname) }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should write buffer files to the right folder', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedCwd = __dirname; var expectedBase = path.join(__dirname, './out-fixtures'); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(true); bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should write streaming files to the right folder', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedCwd = __dirname; var expectedBase = path.join(__dirname, './out-fixtures'); var contentStream = through.obj(); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: contentStream, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(true); bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered))); bufferStream.on('finish', onEnd); stream.pipe(bufferStream); stream.write(expectedFile); setTimeout(function() { contentStream.write(expectedContents); contentStream.end(); }, 100); stream.end(); }); it('should write directories to the right folder', function(done) { var inputPath = path.join(__dirname, './fixtures/test'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test'); var expectedCwd = __dirname; var expectedBase = path.join(__dirname, './out-fixtures'); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: null, stat: { isDirectory: function() { return true; }, }, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(true); fs.lstatSync(expectedPath).isDirectory().should.equal(true); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should allow piping multiple dests in streaming mode', function(done) { var inputPath1 = path.join(__dirname, './out-fixtures/multiple-first'); var inputPath2 = path.join(__dirname, './out-fixtures/multiple-second'); var inputBase = path.join(__dirname, './out-fixtures/'); var srcPath = path.join(__dirname, './fixtures/test.coffee'); var stream1 = vfs.dest('./out-fixtures/', { cwd: __dirname }); var stream2 = vfs.dest('./out-fixtures/', { cwd: __dirname }); var content = fs.readFileSync(srcPath); var rename = through.obj(function(file, _, next) { file.path = inputPath2; this.push(file); next(); }); stream1.on('data', function(file) { file.path.should.equal(inputPath1); }); stream1.pipe(rename).pipe(stream2); stream2.on('data', function(file) { file.path.should.equal(inputPath2); }).once('end', function() { fs.readFileSync(inputPath1, 'utf8').should.equal(content.toString()); fs.readFileSync(inputPath2, 'utf8').should.equal(content.toString()); done(); }); var file = new File({ base: inputBase, path: inputPath1, cwd: __dirname, contents: content, }); stream1.write(file); stream1.end(); }); it('should write new files with the default user mode', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedMode = parseInt('666', 8) & (~process.umask()); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); fs.existsSync(expectedPath).should.equal(true); realMode(fs.lstatSync(expectedPath).mode).should.equal(expectedMode); done(); }; chmodSpy.reset(); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should change to the specified base as string', function(done) { var inputBase = path.join(__dirname, './fixtures'); var inputPath = path.join(__dirname, './fixtures/wow/suchempty'); var firstFile = new File({ cwd: __dirname, path: inputPath, stat: fs.statSync(inputPath), }); var buffered = []; var onEnd = function() { buffered[0].base.should.equal(inputBase); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, base: inputBase, }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(firstFile); stream.end(); }); it('should change to the specified base as function', function(done) { var inputBase = path.join(__dirname, './fixtures'); var inputPath = path.join(__dirname, './fixtures/wow/suchempty'); var firstFile = new File({ cwd: __dirname, path: inputPath, stat: fs.statSync(inputPath), }); var buffered = []; var onEnd = function() { buffered[0].base.should.equal(inputBase); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, base: function(file) { should.exist(file); file.path.should.equal(inputPath); return inputBase; }, }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(firstFile); stream.end(); }); it('should report IO errors', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, }); fs.mkdirSync(expectedBase); fs.closeSync(fs.openSync(expectedPath, 'w')); fs.chmodSync(expectedPath, 0); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('error', function(err) { expect(err).toExist(); done(); }); stream.write(expectedFile); }); it('should report stat errors', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedMode = parseInt('722', 8); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { mode: expectedMode, }, }); fs.mkdirSync(expectedBase); fs.closeSync(fs.openSync(expectedPath, 'w')); spies.setError(function(mod, fn) { if (fn === 'fstat' && typeof arguments[2] === 'number') { return new Error('stat error'); } }); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('error', function(err) { err.message.should.equal('stat error'); done(); }); stream.write(expectedFile); }); it('should not overwrite files with overwrite option set to false', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var inputContents = fs.readFileSync(inputPath); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedBase = path.join(__dirname, './out-fixtures'); var existingContents = 'Lorem Ipsum'; var inputFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: inputContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); bufEqual(fs.readFileSync(expectedPath), new Buffer(existingContents)).should.equal(true); done(); }; // Write expected file which should not be overwritten fs.mkdirSync(expectedBase); fs.writeFileSync(expectedPath, existingContents); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, overwrite: false }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(inputFile); stream.end(); }); it('should overwrite files with overwrite option set to true', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var inputContents = fs.readFileSync(inputPath); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedBase = path.join(__dirname, './out-fixtures'); var existingContents = 'Lorem Ipsum'; var inputFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: inputContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); bufEqual(fs.readFileSync(expectedPath), new Buffer(inputContents)).should.equal(true); done(); }; // This should be overwritten fs.mkdirSync(expectedBase); fs.writeFileSync(expectedPath, existingContents); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, overwrite: true }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(inputFile); stream.end(); }); it('should not overwrite files with overwrite option set to a function that returns false', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var inputContents = fs.readFileSync(inputPath); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedBase = path.join(__dirname, './out-fixtures'); var existingContents = 'Lorem Ipsum'; var inputFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: inputContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); bufEqual(fs.readFileSync(expectedPath), new Buffer(existingContents)).should.equal(true); done(); }; // Write expected file which should not be overwritten fs.mkdirSync(expectedBase); fs.writeFileSync(expectedPath, existingContents); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, overwrite: function() { return false; }, }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(inputFile); stream.end(); }); it('should overwrite files with overwrite option set to a function that returns true', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var inputContents = fs.readFileSync(inputPath); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedBase = path.join(__dirname, './out-fixtures'); var existingContents = 'Lorem Ipsum'; var inputFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: inputContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); bufEqual(fs.readFileSync(expectedPath), new Buffer(inputContents)).should.equal(true); done(); }; // This should be overwritten fs.mkdirSync(expectedBase); fs.writeFileSync(expectedPath, existingContents); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, overwrite: function() { return true; }, }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(inputFile); stream.end(); }); it('should create symlinks when the `symlink` attribute is set on the file', function(done) { var inputPath = path.join(__dirname, './fixtures/test-create-dir-symlink'); var inputBase = path.join(__dirname, './fixtures/'); var inputRelativeSymlinkPath = 'wow'; var expectedPath = path.join(__dirname, './out-fixtures/test-create-dir-symlink'); var inputFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: null, // '' }); // `src()` adds this side-effect with `keepSymlinks` option set to false inputFile.symlink = inputRelativeSymlinkPath; var buffered = []; var onEnd = function() { fs.readlink(buffered[0].path, function() { buffered[0].symlink.should.equal(inputFile.symlink); buffered[0].path.should.equal(expectedPath); done(); }); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.on('error', done); stream.pipe(bufferStream); stream.write(inputFile); stream.end(); }); it('should emit finish event', function(done) { var srcPath = path.join(__dirname, './fixtures/test.coffee'); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.once('finish', function() { done(); }); var file = new File({ path: srcPath, cwd: __dirname, contents: new Buffer('1234567890'), }); stream.write(file); stream.end(); }); it('does not get clogged by highWaterMark', function(done) { fs.mkdirSync(path.join(__dirname, './fixtures/highwatermark')); for (var idx = 0; idx < 17; idx++) { fs.writeFileSync(path.join(__dirname, './fixtures/highwatermark/', 'file' + idx + '.txt')); } var srcPath = path.join(__dirname, './fixtures/highwatermark/*.txt'); var srcStream = vfs.src(srcPath); var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var fileCount = 0; var countFiles = through.obj(function(file, enc, cb) { fileCount++; cb(null, file); }); destStream.once('finish', function() { fileCount.should.equal(17); done(); }); srcStream.pipe(countFiles).pipe(destStream); }); it('allows backpressure when piped to another, slower stream', function(done) { this.timeout(20000); fs.mkdirSync(path.join(__dirname, './fixtures/highwatermark')); for (var idx = 0; idx < 24; idx++) { fs.writeFileSync(path.join(__dirname, './fixtures/highwatermark/', 'file' + idx + '.txt')); } var srcPath = path.join(__dirname, './fixtures/highwatermark/*.txt'); var srcStream = vfs.src(srcPath); var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var fileCount = 0; var countFiles = through.obj(function(file, enc, cb) { fileCount++; cb(null, file); }); var slowFileCount = 0; var slowCountFiles = new Writeable({ objectMode: true, write: function(file, enc, cb) { slowFileCount++; setTimeout(function() { cb(null, file); }, 250); }, }); slowCountFiles.once('finish', function() { fileCount.should.equal(24); slowFileCount.should.equal(24); done(); }); srcStream .pipe(countFiles) .pipe(destStream) .pipe(slowCountFiles); }); it('should respect readable listeners on destination stream', function(done) { var srcPath = path.join(__dirname, './fixtures/test.coffee'); var srcStream = vfs.src(srcPath); var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); srcStream .pipe(destStream); var readables = 0; destStream.on('readable', function() { var data = destStream.read(); if (data != null) { readables++; } }); destStream.on('error', done); destStream.on('finish', function() { readables.should.equal(1); done(); }); }); it('should respect data listeners on destination stream', function(done) { var srcPath = path.join(__dirname, './fixtures/test.coffee'); var srcStream = vfs.src(srcPath); var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); srcStream .pipe(destStream); var datas = 0; destStream.on('data', function() { datas++; }); destStream.on('error', done); destStream.on('finish', function() { datas.should.equal(1); done(); }); }); it('sinks the stream if all the readable event handlers are removed', function(done) { fs.mkdirSync(path.join(__dirname, './fixtures/highwatermark')); for (var idx = 0; idx < 17; idx++) { fs.writeFileSync(path.join(__dirname, './fixtures/highwatermark/', 'file' + idx + '.txt')); } var srcPath = path.join(__dirname, './fixtures/highwatermark/*.txt'); var srcStream = vfs.src(srcPath); var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var fileCount = 0; var countFiles = through.obj(function(file, enc, cb) { fileCount++; cb(null, file); }); destStream.on('readable', noop); destStream.once('finish', function() { fileCount.should.equal(17); done(); }); srcStream.pipe(countFiles).pipe(destStream); process.nextTick(function() { destStream.removeListener('readable', noop); }); }); it('sinks the stream if all the data event handlers are removed', function(done) { this.timeout(10000); fs.mkdirSync(path.join(__dirname, './fixtures/highwatermark')); for (var idx = 0; idx < 17; idx++) { fs.writeFileSync(path.join(__dirname, './fixtures/highwatermark/', 'file' + idx + '.txt')); } var srcPath = path.join(__dirname, './fixtures/highwatermark/*.txt'); var srcStream = vfs.src(srcPath); var destStream = vfs.dest('./out-fixtures/', { cwd: __dirname }); var fileCount = 0; function onData() { fileCount++; } var countFiles = through.obj(function(file, enc, cb) { onData(); cb(null, file); }); destStream.on('data', onData); destStream.once('finish', function() { fileCount.should.equal(17); done(); }); srcStream.pipe(countFiles).pipe(destStream); process.nextTick(function() { destStream.removeListener('data', onData); }); }); it('should pass options to through2', function(done) { var srcPath = path.join(__dirname, './fixtures/test.coffee'); var content = fs.readFileSync(srcPath); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, objectMode: false }); stream.on('error', function(err) { err.should.match(/Invalid non-string\/buffer chunk/); done(); }); var file = new File({ path: srcPath, cwd: __dirname, contents: content, }); stream.write(file); stream.end(); }); it('should successfully process unbuffered items', function(done) { var srcPath = path.join(__dirname, './fixtures/*'); var srcStream = vfs.src(srcPath, { buffer: false }); var destStream = vfs.dest('./out-fixtures', { cwd: __dirname }); srcStream .pipe(destStream) .once('finish', done); }); it('should not exhaust available file descriptors when streaming thousands of files', function(done) { // This can be a very slow test on boxes with slow disk i/o this.timeout(0); // Make a ton of files. Changed from hard links due to Windows failures var numFiles = 6000; fs.mkdirSync(path.join(__dirname, './out-fixtures')); fs.mkdirSync(path.join(__dirname, './out-fixtures/in/')); for (var idx = 0; idx < numFiles; idx++) { fs.writeFileSync(path.join(__dirname, './out-fixtures/in/test' + idx + '.coffee'), ''); } var srcStream = vfs.src(path.join(__dirname, './out-fixtures/in/*.coffee'), { buffer: false }); var destStream = vfs.dest('./out-fixtures/out/', { cwd: __dirname }); var fileCount = 0; srcStream .pipe(through.obj(function(file, enc, cb) { fileCount++; cb(null, file); })) .pipe(destStream) .once('finish', function() { fileCount.should.equal(numFiles); done(); }); }); it('errors if we cannot mkdirp', function(done) { var mkdirSpy = expect.spyOn(fs, 'mkdir').andCall(function() { var callback = arguments[arguments.length - 1]; callback(new Error('mocked error')); }); var outputDir = path.join(__dirname, './out-fixtures/'); var inputPath = path.join(__dirname, './fixtures/test.coffee'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, }); var stream = vfs.dest(outputDir); stream.write(expectedFile); stream.on('error', function(err) { expect(err).toExist(); expect(mkdirSpy.calls.length).toEqual(1); done(); }); }); it('errors if vinyl object is a directory and we cannot mkdirp', function(done) { var ogMkdir = fs.mkdir; var mkdirSpy = expect.spyOn(fs, 'mkdir').andCall(function() { if (mkdirSpy.calls.length > 1) { var callback = arguments[arguments.length - 1]; callback(new Error('mocked error')); } else { ogMkdir.apply(null, arguments); } }); var outputDir = path.join(__dirname, './out-fixtures/'); var inputPath = path.join(__dirname, './other-dir/'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, stat: { isDirectory: function() { return true; }, }, }); var stream = vfs.dest(outputDir); stream.write(expectedFile); stream.on('error', function(err) { expect(err).toExist(); expect(mkdirSpy.calls.length).toEqual(2); done(); }); }); // TODO: is this correct behavior? had to adjust it it('does not error if vinyl object is a directory and we cannot open it', function(done) { var outputDir = path.join(__dirname, './out-fixtures/'); var inputPath = path.join(__dirname, './other-dir/'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, stat: { isDirectory: function() { return true; }, mode: parseInt('000', 8), }, }); var stream = vfs.dest(outputDir); stream.write(expectedFile); stream.on('error', function(err) { expect(err).toNotExist(); done(err); }); stream.end(function() { var exists = fs.existsSync(path.join(outputDir, './other-dir/')); expect(exists).toEqual(true); done(); }); }); it('errors if vinyl object is a directory and open errors', function(done) { var openSpy = expect.spyOn(fs, 'open').andCall(function(writePath, flag, cb) { cb(new Error('mocked error')); }); var outputDir = path.join(__dirname, './out-fixtures/'); var inputPath = path.join(__dirname, './other-dir/'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, stat: { isDirectory: function() { return true; }, }, }); var stream = vfs.dest(outputDir); stream.write(expectedFile); stream.on('error', function(err) { expect(err).toExist(); expect(openSpy.calls.length).toEqual(1); done(); }); }); it('error if content stream errors', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var contentStream = through.obj(); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: contentStream, }); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.write(expectedFile); setTimeout(function() { contentStream.emit('error', new Error('mocked error')); }, 100); stream.on('error', function(err) { expect(err).toExist(); done(); }); }); }); vinyl-fs-2.4.4/test/destModes.js000066400000000000000000000264321300000231200165200ustar00rootroot00000000000000'use strict'; var os = require('os'); var path = require('path'); var fs = require('graceful-fs'); var del = require('del'); var File = require('vinyl'); var expect = require('expect'); var through = require('through2'); var vfs = require('../'); function wipeOut() { this.timeout(20000); expect.restoreSpies(); // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 return del(path.join(__dirname, './fixtures/highwatermark')) .then(function() { return del(path.join(__dirname, './out-fixtures/')); }); } var MASK_MODE = parseInt('777', 8); function masked(mode) { return mode & MASK_MODE; } var isWindows = (os.platform() === 'win32'); describe('.dest() with custom modes', function() { beforeEach(wipeOut); afterEach(wipeOut); it('should set the mode of a written buffer file if set on the vinyl object', function(done) { if (isWindows) { console.log('Changing the mode of a file is not supported by node.js in Windows.'); console.log('Windows is treated as though it does not have permission to make this operation.'); this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedMode = parseInt('655', 8); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { mode: expectedMode, }, }); var onEnd = function() { expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedMode); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should set the mode of a written stream file if set on the vinyl object', function(done) { if (isWindows) { this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedMode = parseInt('655', 8); var contentStream = through.obj(); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: contentStream, stat: { mode: expectedMode, }, }); var onEnd = function() { expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedMode); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); setTimeout(function() { contentStream.write(expectedContents); contentStream.end(); }, 100); stream.end(); }); it('should set the mode of a written directory if set on the vinyl object', function(done) { if (isWindows) { this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test'); var expectedMode = parseInt('655', 8); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: null, stat: { isDirectory: function() { return true; }, mode: expectedMode, }, }); var onEnd = function() { expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedMode); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should write new files with the mode specified in options', function(done) { if (isWindows) { this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedMode = parseInt('744', 8); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, }); var onEnd = function() { expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedMode); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, mode: expectedMode }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should update file mode to match the vinyl mode', function(done) { if (isWindows) { this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedBase = path.join(__dirname, './out-fixtures'); var startMode = parseInt('0655', 8); var expectedMode = parseInt('0722', 8); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { mode: expectedMode, }, }); var onEnd = function() { expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedMode); done(); }; fs.mkdirSync(expectedBase); fs.closeSync(fs.openSync(expectedPath, 'w')); fs.chmodSync(expectedPath, startMode); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should update directory mode to match the vinyl mode', function(done) { if (isWindows) { this.skip(); return; } var inputBase = path.join(__dirname, './fixtures/'); var inputPath = path.join(__dirname, './fixtures/wow'); var expectedPath = path.join(__dirname, './out-fixtures/wow'); var expectedBase = path.join(__dirname, './out-fixtures'); var firstFile = new File({ base: inputBase, cwd: __dirname, path: expectedPath, stat: fs.statSync(inputPath), }); var startMode = firstFile.stat.mode; var expectedMode = parseInt('727', 8); var expectedFile = new File(firstFile); expectedFile.stat.mode = (startMode & ~parseInt('7777', 8)) | expectedMode; var onEnd = function() { expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedMode); done(); }; fs.mkdirSync(expectedBase); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(firstFile); stream.write(expectedFile); stream.end(); }); it('should use different modes for files and directories', function(done) { if (isWindows) { this.skip(); return; } var inputBase = path.join(__dirname, './fixtures'); var inputPath = path.join(__dirname, './fixtures/wow/suchempty'); var expectedBase = path.join(__dirname, './out-fixtures/wow'); var expectedPath = path.join(__dirname, './out-fixtures/wow/suchempty'); var expectedDirMode = parseInt('755', 8); var expectedFileMode = parseInt('655', 8); var firstFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: fs.readFileSync(inputPath), stat: fs.statSync(inputPath), }); var onEnd = function() { expect(masked(fs.lstatSync(expectedBase).mode)).toEqual(expectedDirMode); expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedFileMode); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname, mode: expectedFileMode, dirMode: expectedDirMode, }); stream.on('end', onEnd); stream.write(firstFile); stream.end(); }); it('should not fchmod a matching file', function(done) { if (isWindows) { this.skip(); return; } var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedMode = parseInt('711', 8); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { mode: expectedMode, }, }); var onEnd = function() { expect(fchmodSpy.calls.length).toEqual(0); expect(masked(fs.lstatSync(expectedPath).mode)).toEqual(expectedMode); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should see a file with special chmod (setuid/setgid/sticky) as matching', function(done) { if (isWindows) { this.skip(); return; } var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedMode = parseInt('3722', 8); var normalMode = parseInt('722', 8); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { mode: normalMode, }, }); var onEnd = function() { expect(fchmodSpy.calls.length).toEqual(0); done(); }; fs.mkdirSync(expectedBase); fs.closeSync(fs.openSync(expectedPath, 'w')); fs.chmodSync(expectedPath, expectedMode); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should report fchmod errors', function(done) { if (isWindows) { this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedMode = parseInt('722', 8); var fchmodSpy = expect.spyOn(fs, 'fchmod').andCall(function() { var callback = arguments[arguments.length - 1]; callback(new Error('mocked error')); }); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { mode: expectedMode, }, }); fs.mkdirSync(expectedBase); fs.closeSync(fs.openSync(expectedPath, 'w')); var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('error', function(err) { expect(err).toExist(); expect(fchmodSpy.calls.length).toEqual(1); done(); }); stream.write(expectedFile); }); }); vinyl-fs-2.4.4/test/destTimes.js000066400000000000000000000146221300000231200165300ustar00rootroot00000000000000'use strict'; var os = require('os'); var path = require('path'); var fs = require('graceful-fs'); var del = require('del'); var File = require('vinyl'); var expect = require('expect'); var vfs = require('../'); function wipeOut() { this.timeout(20000); expect.restoreSpies(); // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 return del(path.join(__dirname, './out-fixtures/')); } var isWindows = (os.platform() === 'win32'); describe('.dest() with custom times', function() { beforeEach(wipeOut); afterEach(wipeOut); it('should not call futimes when no mtime is provided on the vinyl stat', function(done) { if (isWindows) { console.log('Changing the time of a directory errors in Windows.'); console.log('Windows is treated as though it does not have permission to make this operation.'); this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var earlier = Date.now() - 1000; var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: {}, }); var onEnd = function() { var stats = fs.lstatSync(expectedPath); expect(futimesSpy.calls.length).toEqual(0); expect(stats.atime.getTime()).toBeGreaterThan(earlier); expect(stats.mtime.getTime()).toBeGreaterThan(earlier); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should call futimes when an mtime is provided on the vinyl stat', function(done) { if (isWindows) { this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedMtime = fs.lstatSync(inputPath).mtime; var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { mtime: expectedMtime, }, }); var onEnd = function() { var stats = fs.lstatSync(expectedPath); expect(futimesSpy.calls.length).toEqual(1); expect(stats.mtime.getTime()).toEqual(expectedMtime.getTime()); expect(expectedFile.stat.mtime).toEqual(expectedMtime); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should not call futimes when provided mtime on the vinyl stat is invalid', function(done) { if (isWindows) { this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var earlier = Date.now() - 1000; var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { mtime: new Date(undefined), }, }); var onEnd = function() { var stats = fs.lstatSync(expectedPath); expect(futimesSpy.calls.length).toEqual(0); expect(stats.mtime.getTime()).toBeGreaterThan(earlier); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should call futimes when provided mtime on the vinyl stat is valid but provided atime is invalid', function(done) { if (isWindows) { this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedMtime = fs.lstatSync(inputPath).mtime; var invalidAtime = new Date(undefined); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { atime: invalidAtime, mtime: expectedMtime, }, }); var onEnd = function() { var stats = fs.lstatSync(expectedPath); expect(futimesSpy.calls.length).toEqual(1); expect(stats.mtime.getTime()).toEqual(expectedMtime.getTime()); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); it('should write file atime and mtime using the vinyl stat', function(done) { if (isWindows) { this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedAtime = fs.lstatSync(inputPath).atime; var expectedMtime = fs.lstatSync(inputPath).mtime; var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { atime: expectedAtime, mtime: expectedMtime, }, }); var onEnd = function() { var stats = fs.lstatSync(expectedPath); expect(stats.atime.getTime()).toEqual(expectedAtime.getTime()); expect(stats.mtime.getTime()).toEqual(expectedMtime.getTime()); expect(expectedFile.stat.mtime).toEqual(expectedMtime); expect(expectedFile.stat.atime).toEqual(expectedAtime); done(); }; var stream = vfs.dest('./out-fixtures/', { cwd: __dirname }); stream.on('end', onEnd); stream.write(expectedFile); stream.end(); }); }); vinyl-fs-2.4.4/test/fileOperations.js000066400000000000000000000517761300000231200175650ustar00rootroot00000000000000'use strict'; var expect = require('expect'); var os = require('os'); var fs = require('graceful-fs'); var del = require('del'); var path = require('path'); var File = require('vinyl'); var buffer = require('buffer'); var defaultResolution = require('default-resolution'); var fo = require('../lib/fileOperations'); var closeFd = fo.closeFd; var isOwner = fo.isOwner; var writeFile = fo.writeFile; var getModeDiff = fo.getModeDiff; var getTimesDiff = fo.getTimesDiff; var updateMetadata = fo.updateMetadata; var resolution = defaultResolution(); var MASK_MODE = parseInt('777', 8); function masked(mode) { return mode & MASK_MODE; } function noop() {} var isWindows = (os.platform() === 'win32'); describe('isOwner', function() { var ownerStat = { uid: 9001, }; var nonOwnerStat = { uid: 9002, }; var getuidSpy; var geteuidSpy; beforeEach(function(done) { if (typeof process.geteuid !== 'function') { process.geteuid = noop; } // Windows :( if (typeof process.getuid !== 'function') { process.getuid = noop; } getuidSpy = expect.spyOn(process, 'getuid').andReturn(ownerStat.uid); geteuidSpy = expect.spyOn(process, 'geteuid').andReturn(ownerStat.uid); done(); }); afterEach(function(done) { expect.restoreSpies(); if (process.geteuid === noop) { delete process.geteuid; } // Windows :( if (process.getuid === noop) { delete process.getuid; } done(); }); // TODO: test for having neither it('uses process.geteuid() when available', function(done) { isOwner(ownerStat); expect(getuidSpy.calls.length).toEqual(0); expect(geteuidSpy.calls.length).toEqual(1); done(); }); it('uses process.getuid() when geteuid() is not available', function(done) { delete process.geteuid; isOwner(ownerStat); expect(getuidSpy.calls.length).toEqual(1); done(); }); it('returns false when non-root and non-owner', function(done) { var result = isOwner(nonOwnerStat); expect(result).toEqual(false); done(); }); it('returns true when owner and non-root', function(done) { var result = isOwner(ownerStat); expect(result).toEqual(true); done(); }); it('returns true when non-owner but root', function(done) { expect.spyOn(process, 'geteuid').andReturn(0); // 0 is root uid var result = isOwner(nonOwnerStat); expect(result).toEqual(true); done(); }); }); describe('getModeDiff', function() { it('returns 0 if both modes are the same', function(done) { var fsMode = parseInt('777', 8); var vfsMode = parseInt('777', 8); var result = getModeDiff(fsMode, vfsMode); expect(result).toEqual(0); done(); }); it('returns 0 if vinyl mode is not a number', function(done) { var fsMode = parseInt('777', 8); var vfsMode = undefined; var result = getModeDiff(fsMode, vfsMode); expect(result).toEqual(0); done(); }); it('returns a value greater than 0 if modes are different', function(done) { var fsMode = parseInt('777', 8); var vfsMode = parseInt('744', 8); var result = getModeDiff(fsMode, vfsMode); expect(result).toEqual(27); done(); }); it('does not matter the order of diffing', function(done) { var fsMode = parseInt('655', 8); var vfsMode = parseInt('777', 8); var result = getModeDiff(fsMode, vfsMode); expect(result).toEqual(82); done(); }); it('ignores the sticky/setuid/setgid bits', function(done) { var fsMode = parseInt('1777', 8); var vfsMode = parseInt('4777', 8); var result = getModeDiff(fsMode, vfsMode); expect(result).toEqual(0); done(); }); }); describe('getTimesDiff', function() { it('returns undefined if vinyl mtime is not a valid date', function(done) { var fsStat = { mtime: new Date(), }; var vfsStat = { mtime: new Date(undefined), }; var result = getTimesDiff(fsStat, vfsStat); expect(result).toEqual(undefined); done(); }); it('returns undefined if vinyl mtime & atime are both equal to counterparts', function(done) { var now = Date.now(); var fsStat = { mtime: new Date(now), atime: new Date(now), }; var vfsStat = { mtime: new Date(now), atime: new Date(now), }; var result = getTimesDiff(fsStat, vfsStat); expect(result).toEqual(undefined); done(); }); // TODO: is this proper/expected? it('returns undefined if vinyl mtimes equals the counterpart and atimes are null', function(done) { var now = Date.now(); var fsStat = { mtime: new Date(now), atime: null, }; var vfsStat = { mtime: new Date(now), atime: null, }; var result = getTimesDiff(fsStat, vfsStat); expect(result).toEqual(undefined); done(); }); it('returns a diff object if mtimes do not match', function(done) { var now = Date.now(); var then = now - 1000; var fsStat = { mtime: new Date(now), }; var vfsStat = { mtime: new Date(then), }; var expected = { mtime: new Date(then), atime: undefined, }; var result = getTimesDiff(fsStat, vfsStat); expect(result).toEqual(expected); done(); }); it('returns a diff object if atimes do not match', function(done) { var now = Date.now(); var then = now - 1000; var fsStat = { mtime: new Date(now), atime: new Date(now), }; var vfsStat = { mtime: new Date(now), atime: new Date(then), }; var expected = { mtime: new Date(now), atime: new Date(then), }; var result = getTimesDiff(fsStat, vfsStat); expect(result).toEqual(expected); done(); }); it('returns the fs atime if the vinyl atime is invalid', function(done) { var now = Date.now(); var fsStat = { mtime: new Date(now), atime: new Date(now), }; var vfsStat = { mtime: new Date(now), atime: new Date(undefined), }; var expected = { mtime: new Date(now), atime: new Date(now), }; var result = getTimesDiff(fsStat, vfsStat); expect(result).toEqual(expected); done(); }); // TODO: is this proper/expected? it('makes atime diff undefined if fs and vinyl atime are invalid', function(done) { var now = Date.now(); var fsStat = { mtime: new Date(now), atime: new Date(undefined), }; var vfsStat = { mtime: new Date(now), atime: new Date(undefined), }; var expected = { mtime: new Date(now), atime: undefined, }; var result = getTimesDiff(fsStat, vfsStat); expect(result).toEqual(expected); done(); }); }); describe('closeFd', function() { it('calls the callback with propagated error if fd is not a number', function(done) { var propagatedError = new Error(); closeFd(propagatedError, null, function(err) { expect(err).toEqual(propagatedError); done(); }); }); it('calls the callback with close error if no error to propagate', function(done) { closeFd(null, -1, function(err) { expect(err).toExist(); done(); }); }); it('calls the callback with propagated error if close errors', function(done) { var propagatedError = new Error(); closeFd(propagatedError, -1, function(err) { expect(err).toEqual(propagatedError); done(); }); }); it('calls the callback with propagated error if close succeeds', function(done) { var propagatedError = new Error(); var fd = fs.openSync(path.join(__dirname, './fixtures/test.coffee'), 'r'); var spy = expect.spyOn(fs, 'close').andCallThrough(); closeFd(propagatedError, fd, function(err) { spy.restore(); expect(spy.calls.length).toEqual(1); expect(err).toEqual(propagatedError); done(); }); }); it('calls the callback with no error if close succeeds & no propagated error', function(done) { var fd = fs.openSync(path.join(__dirname, './fixtures/test.coffee'), 'r'); var spy = expect.spyOn(fs, 'close').andCallThrough(); closeFd(null, fd, function(err) { spy.restore(); expect(spy.calls.length).toEqual(1); expect(err).toEqual(undefined); done(); }); }); }); describe('writeFile', function() { var filepath; beforeEach(function(done) { filepath = path.join(__dirname, './fixtures/writeFile.txt'); done(); }); afterEach(function() { // Async del to get sort-of-fix for https://github.com/isaacs/rimraf/issues/72 return del(filepath); }); it('writes a file to the filesystem, does not close and returns the fd', function(done) { var expected = 'test'; var content = new Buffer(expected); writeFile(filepath, content, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { var written = fs.readFileSync(filepath, 'utf-8'); expect(written).toEqual(expected); done(); }); }); }); it('defaults to writing files with 0666 mode', function(done) { var expected = parseInt('0666', 8) & (~process.umask()); var content = new Buffer('test'); writeFile(filepath, content, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { var stats = fs.lstatSync(filepath); expect(masked(stats.mode)).toEqual(expected); done(); }); }); }); it('accepts a different mode in options', function(done) { if (isWindows) { console.log('Changing the mode of a file is not supported by node.js in Windows.'); this.skip(); return; } var expected = parseInt('0777', 8) & (~process.umask()); var content = new Buffer('test'); var options = { mode: parseInt('0777', 8), }; writeFile(filepath, content, options, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { var stats = fs.lstatSync(filepath); expect(masked(stats.mode)).toEqual(expected); done(); }); }); }); it('defaults to opening files with write flag', function(done) { var content = new Buffer('test'); writeFile(filepath, content, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.read(fd, new Buffer(4), 0, 4, 0, function(readErr) { expect(readErr).toExist(); fs.close(fd, done); }); }); }); it('accepts a different flag in options', function(done) { var expected = 'test'; var content = new Buffer(expected); var options = { flag: 'w+', }; writeFile(filepath, content, options, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.read(fd, new Buffer(4), 0, 4, 0, function(readErr, _, written) { expect(readErr).toNotExist(); expect(written.toString()).toEqual(expected); fs.close(fd, done); }); }); }); it('appends to a file if append flag is given', function(done) { var initial = 'test'; var toWrite = '-a-thing'; fs.writeFileSync(filepath, initial, 'utf-8'); var expected = initial + toWrite; var content = new Buffer(toWrite); var options = { flag: 'a', }; writeFile(filepath, content, options, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { var written = fs.readFileSync(filepath, 'utf-8'); expect(written).toEqual(expected); done(); }); }); }); it('does not pass a file descriptor if open call errors', function(done) { filepath = path.join(__dirname, './not-exist-dir/writeFile.txt'); var content = new Buffer('test'); writeFile(filepath, content, function(err, fd) { expect(err).toExist(); expect(typeof fd === 'number').toEqual(false); done(); }); }); it('passes a file descriptor if write call errors', function(done) { var existsFilepath = path.join(__dirname, './fixtures/test.coffee'); // File must exist var content = new Buffer('test'); var options = { flag: 'r', }; writeFile(existsFilepath, content, options, function(err, fd) { expect(err).toExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, done); }); }); it('passes an error if called with string as data', function(done) { writeFile(filepath, 'test', function(err) { expect(err).toExist(); done(); }); }); it('does not error on SlowBuffer', function(done) { if (!buffer.SlowBuffer) { this.skip(); return; } var expected = 'test'; var buf = new Buffer(expected); var content = new buffer.SlowBuffer(4); buf.copy(content, 0, 0, 4); writeFile(filepath, content, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, function() { var written = fs.readFileSync(filepath, 'utf-8'); expect(written).toEqual(expected); done(); }); }); }); it('does not error if options is falsey', function(done) { var content = new Buffer('test'); writeFile(filepath, content, null, function(err, fd) { expect(err).toNotExist(); expect(typeof fd === 'number').toEqual(true); fs.close(fd, done); }); }); }); describe('updateMetadata', function() { var inputPath = path.join(__dirname, './fixtures/stats.txt'); var file; beforeEach(function(done) { file = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, stat: { }, }); done(); }); afterEach(function(done) { expect.restoreSpies(); del.sync(inputPath); if (process.geteuid === noop) { delete process.geteuid; } done(); }); it('passes the error and file descriptor if fstat fails', function(done) { if (isWindows) { console.log('Changing the time of a directory errors in Windows.'); console.log('Changing the mode of a file is not supported by node.js in Windows.'); console.log('Windows is treated as though it does not have permission to make these operations.'); this.skip(); return; } var fd = 9001; updateMetadata(fd, file, function(err, fd2) { expect(err).toExist(); expect(typeof fd === 'number').toEqual(true); expect(fd2).toEqual(fd); done(); }); }); it('updates the vinyl object with fs stats', function(done) { if (isWindows) { this.skip(); return; } var fd = fs.openSync(inputPath, 'w+'); var stats = fs.fstatSync(fd); updateMetadata(fd, file, function(err, fd2) { // Not sure why .toEqual doesn't match these Object.keys(file.stat).forEach(function(key) { expect(file.stat[key]).toEqual(stats[key]); }); fs.close(fd2, done); }); }); it('does not touch the fs if nothing to update', function(done) { if (isWindows) { this.skip(); return; } var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); var fd = fs.openSync(inputPath, 'w+'); updateMetadata(fd, file, function(err, fd2) { expect(fchmodSpy.calls.length).toEqual(0); expect(futimesSpy.calls.length).toEqual(0); fs.close(fd2, done); }); }); it('does not touch the fs if process is not owner of the file', function(done) { if (isWindows) { this.skip(); return; } if (typeof process.geteuid !== 'function') { process.geteuid = noop; } expect.spyOn(process, 'geteuid').andReturn(9002); var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); file.stat.mtime = new Date(Date.now() - 1000); var fd = fs.openSync(inputPath, 'w+'); updateMetadata(fd, file, function(err, fd2) { expect(fchmodSpy.calls.length).toEqual(0); expect(futimesSpy.calls.length).toEqual(0); fs.close(fd2, done); }); }); it('updates times on fs and vinyl object if there is a diff', function(done) { if (isWindows) { this.skip(); return; } var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); var now = Date.now(); var then = now - 1000; file.stat.mtime = new Date(then); file.stat.atime = new Date(then); var fd = fs.openSync(inputPath, 'w+'); updateMetadata(fd, file, function(err, fd2) { expect(futimesSpy.calls.length).toEqual(1); var stats = fs.fstatSync(fd); var mtimeMs = Date.parse(file.stat.mtime); var mtime = resolution ? mtimeMs - (mtimeMs % resolution) : mtimeMs; var atimeMs = Date.parse(file.stat.atime); var atime = resolution ? atimeMs - (atimeMs % resolution) : atimeMs; expect(file.stat.mtime).toEqual(new Date(then)); expect(mtime).toEqual(Date.parse(stats.mtime)); expect(file.stat.atime).toEqual(new Date(then)); expect(atime).toEqual(Date.parse(stats.atime)); fs.close(fd2, done); }); }); it('forwards futimes error and descriptor upon error', function(done) { if (isWindows) { this.skip(); return; } var futimesSpy = expect.spyOn(fs, 'futimes').andCall(function(fd, atime, mtime, cb) { cb(new Error('mocked error')); }); var now = Date.now(); var then = now - 1000; file.stat.mtime = new Date(then); file.stat.atime = new Date(then); var fd = fs.openSync(inputPath, 'w+'); updateMetadata(fd, file, function(err, fd2) { expect(err).toExist(); expect(futimesSpy.calls.length).toEqual(1); expect(typeof fd2 === 'number').toEqual(true); fs.close(fd2, done); }); }); it('updates the mode on fs and vinyl object if there is a diff', function(done) { if (isWindows) { this.skip(); return; } var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); var mode = parseInt('777', 8); file.stat.mode = mode; var fd = fs.openSync(inputPath, 'w+'); updateMetadata(fd, file, function(err, fd2) { expect(fchmodSpy.calls.length).toEqual(1); var stats = fs.fstatSync(fd); expect(file.stat.mode).toEqual(stats.mode); fs.close(fd2, done); }); }); it('forwards fchmod error and descriptor upon error', function(done) { if (isWindows) { this.skip(); return; } var mode = parseInt('777', 8); file.stat.mode = mode; var fd = fs.openSync(inputPath, 'w+'); var fchmodSpy = expect.spyOn(fs, 'fchmod').andCall(function(fd, mode, cb) { cb(new Error('mocked error')); }); updateMetadata(fd, file, function(err, fd2) { expect(err).toExist(); expect(fchmodSpy.calls.length).toEqual(1); expect(typeof fd2 === 'number').toEqual(true); fs.close(fd2, done); }); }); it('updates the mode & times on fs and vinyl object if there is a diff', function(done) { if (isWindows) { this.skip(); return; } var fchmodSpy = expect.spyOn(fs, 'fchmod').andCallThrough(); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); var mode = parseInt('777', 8); file.stat.mode = mode; var now = Date.now(); var then = now - 1000; file.stat.mtime = new Date(then); file.stat.atime = new Date(then); var fd = fs.openSync(inputPath, 'w+'); updateMetadata(fd, file, function(err, fd2) { expect(fchmodSpy.calls.length).toEqual(1); expect(futimesSpy.calls.length).toEqual(1); var stats = fs.fstatSync(fd); var mtimeMs = Date.parse(file.stat.mtime); var mtime = resolution ? mtimeMs - (mtimeMs % resolution) : mtimeMs; var atimeMs = Date.parse(file.stat.atime); var atime = resolution ? atimeMs - (atimeMs % resolution) : atimeMs; expect(file.stat.mtime).toEqual(new Date(then)); expect(mtime).toEqual(Date.parse(stats.mtime)); expect(file.stat.atime).toEqual(new Date(then)); expect(atime).toEqual(Date.parse(stats.atime)); expect(file.stat.mode).toEqual(stats.mode); fs.close(fd2, done); }); }); it('forwards fchmod error and descriptor through futimes if there is a time diff', function(done) { if (isWindows) { this.skip(); return; } var expectedErr = new Error('mocked error'); var fchmodSpy = expect.spyOn(fs, 'fchmod').andCall(function(fd, mode, cb) { cb(expectedErr); }); var futimesSpy = expect.spyOn(fs, 'futimes').andCallThrough(); var mode = parseInt('777', 8); file.stat.mode = mode; var now = Date.now(); var then = now - 1000; file.stat.mtime = new Date(then); file.stat.atime = new Date(then); var fd = fs.openSync(inputPath, 'w'); updateMetadata(fd, file, function(err, fd2) { expect(err).toExist(); expect(err).toEqual(expectedErr); expect(fchmodSpy.calls.length).toEqual(1); expect(futimesSpy.calls.length).toEqual(1); expect(typeof fd2 === 'number').toEqual(true); fs.close(fd2, done); }); }); }); vinyl-fs-2.4.4/test/fixtures/000077500000000000000000000000001300000231200160755ustar00rootroot00000000000000vinyl-fs-2.4.4/test/fixtures/bom-utf16be.txt000066400000000000000000000003641300000231200206700ustar00rootroot00000000000000This file is saved as UTF-16-BE. It contains some garbage at the start that looks like a UTF-8-encoded BOM (but isn t). vinyl-fs-2.4.4/test/fixtures/bom-utf16le.txt000066400000000000000000000003641300000231200207020ustar00rootroot00000000000000This file is saved as UTF-16-LE. It contains some garbage at the start that looks like a UTF-8-encoded BOM (but isn t). vinyl-fs-2.4.4/test/fixtures/bom-utf8.txt000066400000000000000000000000561300000231200203000ustar00rootroot00000000000000This file is saved as UTF-8 with BOM. 𝌆 vinyl-fs-2.4.4/test/fixtures/foo/000077500000000000000000000000001300000231200166605ustar00rootroot00000000000000vinyl-fs-2.4.4/test/fixtures/foo/bar/000077500000000000000000000000001300000231200174245ustar00rootroot00000000000000vinyl-fs-2.4.4/test/fixtures/foo/bar/baz.txt000066400000000000000000000000161300000231200207360ustar00rootroot00000000000000symlink works vinyl-fs-2.4.4/test/fixtures/test.coffee000066400000000000000000000000141300000231200202200ustar00rootroot00000000000000Hello world!vinyl-fs-2.4.4/test/fixtures/wow/000077500000000000000000000000001300000231200167115ustar00rootroot00000000000000vinyl-fs-2.4.4/test/fixtures/wow/suchempty000066400000000000000000000000111300000231200206450ustar00rootroot00000000000000suchemptyvinyl-fs-2.4.4/test/not-owned/000077500000000000000000000000001300000231200161365ustar00rootroot00000000000000vinyl-fs-2.4.4/test/not-owned/not-owned.txt000066400000000000000000000000151300000231200206050ustar00rootroot00000000000000Something newvinyl-fs-2.4.4/test/notOwned.js000066400000000000000000000035171300000231200163650ustar00rootroot00000000000000'use strict'; var path = require('path'); var expect = require('expect'); var fs = require('graceful-fs'); var File = require('vinyl'); var vfs = require('../'); describe('.dest() on not owned files', function() { var outDir = path.join(__dirname, './not-owned/'); var outPath = path.join(outDir, 'not-owned.txt'); var dirStats = fs.statSync(outDir); var fileStats = fs.statSync(outPath); it('does not error if mtime is different', function(done) { if (dirStats.uid !== 0 || fileStats.uid !== 0) { console.log('Test files not owned by root. ' + 'Please chown ' + outDir + ' and' + outPath + ' and try again.'); this.skip(); return; } var expectedFile = new File({ base: __dirname, cwd: __dirname, path: 'not-owned/not-owned.txt', contents: new Buffer('Something new'), stat: { mtime: new Date(Date.now() - 1000), }, }); var stream = vfs.dest(outDir); stream.write(expectedFile); stream.on('error', function(err) { expect(err).toNotExist(); done(err); }); stream.on('end', done); stream.end(); }); it('does not error if mode is different', function(done) { if (dirStats.uid !== 0 || fileStats.uid !== 0) { console.log('Test files not owned by root. ' + 'Please chown ' + outDir + ' and' + outPath + ' and try again.'); this.skip(); return; } var expectedFile = new File({ base: __dirname, cwd: __dirname, path: 'not-owned/not-owned.txt', contents: new Buffer('Something new'), stat: { mode: parseInt('777', 8), }, }); var stream = vfs.dest(outDir); stream.write(expectedFile); stream.on('error', function(err) { expect(err).toNotExist(); done(err); }); stream.on('end', done); stream.end(); }); }); vinyl-fs-2.4.4/test/spy.js000066400000000000000000000014411300000231200153750ustar00rootroot00000000000000'use strict'; var fs = require('graceful-fs'); var sinon = require('sinon'); var errorfn = false; function maybeCallAsync(module, func) { var original = module[func]; return sinon.stub(module, func, function() { var args = Array.prototype.slice.call(arguments); args.unshift(module, func); var err = typeof errorfn === 'function' && errorfn.apply(this, args); if (!err) { original.apply(this, arguments); } else { arguments[arguments.length - 1](err); } }); } module.exports = { setError: function(fn) { errorfn = fn; }, chmodSpy: maybeCallAsync(fs, 'chmod'), fchmodSpy: maybeCallAsync(fs, 'fchmod'), futimesSpy: maybeCallAsync(fs, 'futimes'), statSpy: maybeCallAsync(fs, 'stat'), fstatSpy: maybeCallAsync(fs, 'fstat'), }; vinyl-fs-2.4.4/test/src.js000066400000000000000000000402541300000231200153560ustar00rootroot00000000000000'use strict'; var vfs = require('../'); var path = require('path'); var fs = require('graceful-fs'); var bufEqual = require('buffer-equal'); var through = require('through2'); var File = require('vinyl'); var should = require('should'); require('mocha'); var dataWrap = function(fn) { return function(data, enc, cb) { fn(data); cb(); }; }; describe('source stream', function() { it('should explode on invalid glob (empty)', function(done) { var stream; try { stream = vfs.src(); } catch (err) { should.exist(err); should.not.exist(stream); done(); } }); it('should explode on invalid glob (empty string)', function(done) { var stream; try { stream = vfs.src(''); } catch (err) { should.exist(err); should.not.exist(stream); done(); } }); it('should explode on invalid glob (number)', function(done) { var stream; try { stream = vfs.src(123); } catch (err) { should.exist(err); should.not.exist(stream); done(); } }); it('should explode on invalid glob (nested array)', function(done) { var stream; try { stream = vfs.src([['./fixtures/*.coffee']]); } catch (err) { should.exist(err); should.not.exist(stream); err.message.should.containEql('Invalid glob argument'); done(); } }); it('should explode on invalid glob (empty string in array)', function(done) { var stream; try { stream = vfs.src(['']); } catch (err) { should.exist(err); should.not.exist(stream); done(); } }); it('should explode on invalid glob (empty array)', function(done) { var stream; try { stream = vfs.src([]); } catch (err) { should.exist(err); should.not.exist(stream); done(); } }); it('should error on file not existing', function(done) { var stream = vfs.src('./fixtures/noexist.coffee'); stream.on('error', function(err) { should.exist(err); done(); }); }); it('should pass through writes', function(done) { var expectedPath = path.join(__dirname, './fixtures/test.coffee'); var expectedContent = fs.readFileSync(expectedPath); var files = []; var expectedFile = new File({ base: __dirname, cwd: __dirname, path: expectedPath, contents: expectedContent, stat: fs.lstatSync(expectedPath), }); var stream = vfs.src(expectedPath, { cwd: __dirname, base: __dirname }); stream.on('data', function(file) { files.push(file); }); stream.once('end', function() { files.length.should.equal(2); files[0].should.eql(expectedFile); bufEqual(files[0].contents, expectedContent).should.equal(true); files[1].should.eql(expectedFile); bufEqual(files[1].contents, expectedContent).should.equal(true); done(); }); stream.write(expectedFile); }); it('should strip BOM from UTF-8-encoded files by default', function(done) { var expectedPath = path.join(__dirname, './fixtures/bom-utf8.txt'); var expectedContent = fs.readFileSync(expectedPath) // U+FEFF takes up 3 bytes in UTF-8: http://mothereff.in/utf-8#%EF%BB%BF .slice(3); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); should.exist(buffered[0].stat); buffered[0].path.should.equal(expectedPath); buffered[0].isBuffer().should.equal(true); bufEqual(buffered[0].contents, expectedContent).should.equal(true); done(); }; var stream = vfs.src('./fixtures/bom-utf8.txt', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should not strip BOM from UTF-8-encoded files if option is false', function(done) { var expectedPath = path.join(__dirname, './fixtures/bom-utf8.txt'); var expectedContent = fs.readFileSync(expectedPath); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); should.exist(buffered[0].stat); buffered[0].path.should.equal(expectedPath); buffered[0].isBuffer().should.equal(true); bufEqual(buffered[0].contents, expectedContent).should.equal(true); done(); }; var stream = vfs.src('./fixtures/bom-utf8.txt', { cwd: __dirname, stripBOM: false }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should not strip anything that looks like a UTF-8-encoded BOM from UTF-16-BE-encoded files', function(done) { // Note: this goes for any non-UTF-8 encoding, but testing for UTF-16-BE // and UTF-16-LE is enough to demonstrate this is done properly. var expectedPath = path.join(__dirname, './fixtures/bom-utf16be.txt'); var expectedContent = fs.readFileSync(expectedPath); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); should.exist(buffered[0].stat); buffered[0].path.should.equal(expectedPath); buffered[0].isBuffer().should.equal(true); bufEqual(buffered[0].contents, expectedContent).should.equal(true); done(); }; var stream = vfs.src('./fixtures/bom-utf16be.txt', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should not strip anything that looks like a UTF-8-encoded BOM from UTF-16-LE-encoded files', function(done) { // Note: this goes for any non-UTF-8 encoding, but testing for UTF-16-BE // and UTF-16-LE is enough to demonstrate this is done properly. var expectedPath = path.join(__dirname, './fixtures/bom-utf16le.txt'); var expectedContent = fs.readFileSync(expectedPath); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); should.exist(buffered[0].stat); buffered[0].path.should.equal(expectedPath); buffered[0].isBuffer().should.equal(true); bufEqual(buffered[0].contents, expectedContent).should.equal(true); done(); }; var stream = vfs.src('./fixtures/bom-utf16le.txt', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should glob a file with default settings', function(done) { var expectedPath = path.join(__dirname, './fixtures/test.coffee'); var expectedContent = fs.readFileSync(expectedPath); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); should.exist(buffered[0].stat); buffered[0].path.should.equal(expectedPath); buffered[0].isBuffer().should.equal(true); bufEqual(buffered[0].contents, expectedContent).should.equal(true); done(); }; var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should glob a file with default settings and relative cwd', function(done) { var expectedPath = path.join(__dirname, './fixtures/test.coffee'); var expectedContent = fs.readFileSync(expectedPath); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); should.exist(buffered[0].stat); buffered[0].path.should.equal(expectedPath); buffered[0].isBuffer().should.equal(true); bufEqual(buffered[0].contents, expectedContent).should.equal(true); done(); }; var stream = vfs.src('./fixtures/*.coffee', { cwd: path.relative(process.cwd(), __dirname) }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should glob a directory with default settings', function(done) { var expectedPath = path.join(__dirname, './fixtures/wow/'); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].path.should.equal(expectedPath); buffered[0].isNull().should.equal(true); buffered[0].isDirectory().should.equal(true); done(); }; var stream = vfs.src('./fixtures/wow/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should glob a file with with no contents', function(done) { var expectedPath = path.join(__dirname, './fixtures/test.coffee'); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].path.should.equal(expectedPath); buffered[0].isNull().should.equal(true); should.not.exist(buffered[0].contents); done(); }; var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname, read: false }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should glob a file changed after since', function(done) { var expectedPath = path.join(__dirname, './fixtures/test.coffee'); var expectedContent = fs.readFileSync(expectedPath); var lastUpdateDate = new Date(+fs.statSync(expectedPath).mtime - 1000); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); should.exist(buffered[0].stat); buffered[0].path.should.equal(expectedPath); buffered[0].isBuffer().should.equal(true); bufEqual(buffered[0].contents, expectedContent).should.equal(true); done(); }; var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname, since: lastUpdateDate }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should not glob a file changed before since', function(done) { var expectedPath = path.join(__dirname, './fixtures/test.coffee'); var lastUpdateDate = new Date(+fs.statSync(expectedPath).mtime + 1000); var buffered = []; var onEnd = function() { buffered.length.should.equal(0); done(); }; var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname, since: lastUpdateDate }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should glob a file with streaming contents', function(done) { var expectedPath = path.join(__dirname, './fixtures/test.coffee'); var expectedContent = fs.readFileSync(expectedPath); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); should.exist(buffered[0].stat); buffered[0].path.should.equal(expectedPath); buffered[0].isStream().should.equal(true); var contentBuffer = new Buffer([]); var contentBufferStream = through(dataWrap(function(data) { contentBuffer = Buffer.concat([contentBuffer, data]); })); buffered[0].contents.pipe(contentBufferStream); buffered[0].contents.once('end', function() { bufEqual(contentBuffer, expectedContent); done(); }); }; var stream = vfs.src('./fixtures/*.coffee', { cwd: __dirname, buffer: false }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); it('should pass files through', function(done) { var expectedPaths = [ path.join(__dirname, './fixtures/test.coffee'), path.join(__dirname, './fixtures/wow/suchempty'), ]; var expectedContents = expectedPaths.map(function(path/* More args here so can't pass function directly */) { return fs.readFileSync(path); }); var buffered = []; var onEnd = function() { buffered.length.should.equal(2); buffered.forEach(function(file) { should.exist(file.stat); file.isBuffer().should.equal(true); expectedPaths.some(function(expectedPath) { return file.path === expectedPath; }).should.equal(true); expectedContents.some(function(expectedContent) { return bufEqual(file.contents, expectedContent); }).should.equal(true); }); done(); }; var stream1 = vfs.src('./fixtures/*.coffee', { cwd: __dirname }); var stream2 = vfs.src('./fixtures/wow/*', { cwd: __dirname, passthrough: true }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream1.pipe(stream2).pipe(bufferStream); }); it('should not pass options.read on to through2', function(done) { // Note: https://github.com/gulpjs/vinyl-fs/issues/153 // In future, if/when function values are supported for options like // `read` and `buffered`, the expected value here will be 1. var canary = 0; var expected = 0; var read = function() { canary++; return 0; }; var onEnd = function() { canary.should.equal(expected); done(); }; var buffered = []; var stream = vfs.src('./fixtures/test.coffee', { cwd: __dirname, read: read }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); }); }); describe('.src() symlinks', function() { var dirPath = path.join(__dirname, './fixtures/wow'); var dirSymlinkPath = path.join(__dirname, './fixtures/test-symlink-dir'); var filePath = path.join(__dirname, './fixtures/test.coffee'); var fileSymlinkPath = path.join(__dirname, './fixtures/test-symlink'); var symlinkFirstLayer = path.join(__dirname, './fixtures/test-multi-layer-symlink'); var symlinkSecondLayer = path.join(__dirname, './fixtures/foo/baz-link.txt'); var symlinkSecondLayerTarget = path.join(__dirname, './fixtures/foo/bar/baz.txt'); beforeEach(function(done) { fs.symlinkSync(dirPath, dirSymlinkPath); fs.symlinkSync(filePath, fileSymlinkPath); fs.symlinkSync(symlinkSecondLayerTarget, symlinkSecondLayer); fs.symlinkSync(symlinkSecondLayer, symlinkFirstLayer); done(); }); afterEach(function(done) { fs.unlinkSync(dirSymlinkPath); fs.unlinkSync(fileSymlinkPath); fs.unlinkSync(symlinkSecondLayer); fs.unlinkSync(symlinkFirstLayer); done(); }); it('should follow symlinks correctly', function(done) { var linkTarget = './fixtures/test-multi-layer-symlink'; var expectedPath = path.join(__dirname, linkTarget); var stream = vfs.src(linkTarget, { cwd: __dirname, base: __dirname }); stream.on('data', function(file) { file.base.should.equal(__dirname); // The path should be the symlink itself file.path.should.equal(expectedPath); // But the content should be what's in the actual file file.contents.toString().should.equal('symlink works\n'); file.stat.isSymbolicLink().should.equal(false); file.stat.isFile().should.equal(true); done(); }); }); it('should follow dir symlinks correctly', function(done) { var linkTarget = './fixtures/test-symlink-dir'; var expectedPath = path.join(__dirname, linkTarget); var stream = vfs.src(linkTarget, { cwd: __dirname, base: __dirname }); stream.on('data', function(file) { file.base.should.equal(__dirname); // The path should be the symlink itself file.path.should.equal(expectedPath); // But the stats should have been updated file.stat.isSymbolicLink().should.equal(false); file.stat.isDirectory().should.equal(true); done(); }); }); it('should preserve file symlinks with followSymlinks option set to false', function(done) { fs.readlink(fileSymlinkPath, function(err, expectedRelativeSymlinkPath) { if (err) { throw err; } var stream = vfs.src(fileSymlinkPath, { cwd: __dirname, followSymlinks: false }); stream.on('data', function(file) { file.path.should.equal(fileSymlinkPath); file.symlink.should.equal(expectedRelativeSymlinkPath); done(); }); }); }); it('should preserve dir symlinks with followSymlinks option set to false', function(done) { fs.readlink(dirSymlinkPath, function(err, expectedRelativeSymlinkPath) { if (err) { throw err; } var stream = vfs.src(dirSymlinkPath, { cwd: __dirname, followSymlinks: false }); stream.on('data', function(file) { file.path.should.equal(dirSymlinkPath); file.symlink.should.equal(expectedRelativeSymlinkPath); done(); }); }); }); }); vinyl-fs-2.4.4/test/symlink.js000066400000000000000000000327271300000231200162630ustar00rootroot00000000000000'use strict'; var spies = require('./spy'); var chmodSpy = spies.chmodSpy; var statSpy = spies.statSpy; var vfs = require('../'); var os = require('os'); var path = require('path'); var fs = require('graceful-fs'); var del = require('del'); var bufEqual = require('buffer-equal'); var through = require('through2'); var File = require('vinyl'); var should = require('should'); require('mocha'); function wipeOut() { spies.setError('false'); statSpy.reset(); chmodSpy.reset(); return del(path.join(__dirname, './out-fixtures/')); } var dataWrap = function(fn) { return function(data, enc, cb) { fn(data); cb(); }; }; var realMode = function(n) { return n & parseInt('777', 8); }; var isWindows = (os.platform() === 'win32'); describe('symlink stream', function() { beforeEach(wipeOut); afterEach(wipeOut); it.skip('should explode on invalid folder', function(done) { var stream; try { stream = vfs.symlink(); } catch (err) { should.exist(err); should.not.exist(stream); done(); } }); it('should pass through writes with cwd', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); done(); }; var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should pass through writes with default cwd', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var expectedFile = new File({ base: __dirname, cwd: __dirname, path: inputPath, contents: null, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); done(); }; var stream = vfs.symlink(path.join(__dirname, './out-fixtures/')); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should make link to the right folder with relative cwd', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedContents = fs.readFileSync(inputPath); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(true); bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); fs.readlinkSync(expectedPath).should.equal(inputPath); done(); }; var stream = vfs.symlink('./out-fixtures/', { cwd: path.relative(process.cwd(), __dirname) }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should write buffer files to the right folder with function and relative cwd', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedContents = fs.readFileSync(inputPath); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(true); bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); fs.readlinkSync(expectedPath).should.equal(inputPath); done(); }; var stream = vfs.symlink(function(file) { should.exist(file); file.should.equal(expectedFile); return './out-fixtures'; }, { cwd: path.relative(process.cwd(), __dirname) }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should write buffer files to the right folder', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedMode = parseInt('655', 8); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, stat: { mode: expectedMode, }, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(true); bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); fs.readlinkSync(expectedPath).should.equal(inputPath); done(); }; var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should write streaming files to the right folder', function(done) { var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); var expectedContents = fs.readFileSync(inputPath); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedMode = parseInt('655', 8); var contentStream = through.obj(); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: contentStream, stat: { mode: expectedMode, }, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.existsSync(expectedPath).should.equal(true); bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); fs.readlinkSync(expectedPath).should.equal(inputPath); done(); }; var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); setTimeout(function() { contentStream.write(expectedContents); contentStream.end(); }, 100); stream.end(); }); it('should write directories to the right folder', function(done) { var inputPath = path.join(__dirname, './fixtures/wow'); var inputBase = path.join(__dirname, './fixtures/'); var expectedPath = path.join(__dirname, './out-fixtures/wow'); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedMode = parseInt('655', 8); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: null, stat: { isDirectory: function() { return true; }, mode: expectedMode, }, }); var buffered = []; var onEnd = function() { buffered.length.should.equal(1); buffered[0].should.equal(expectedFile); buffered[0].cwd.should.equal(__dirname, 'cwd should have changed'); buffered[0].base.should.equal(expectedBase, 'base should have changed'); buffered[0].path.should.equal(expectedPath, 'path should have changed'); fs.readlinkSync(expectedPath).should.equal(inputPath); fs.lstatSync(expectedPath).isDirectory().should.equal(false); fs.statSync(expectedPath).isDirectory().should.equal(true); done(); }; var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(expectedFile); stream.end(); }); it('should use different modes for files and directories', function(done) { if (isWindows) { console.log('Changing the mode of a file is not supported by node.js in Windows.'); this.skip(); return; } var inputBase = path.join(__dirname, './fixtures'); var inputPath = path.join(__dirname, './fixtures/wow/suchempty'); var expectedBase = path.join(__dirname, './out-fixtures/wow'); var expectedDirMode = parseInt('755', 8); var expectedFileMode = parseInt('655', 8); var firstFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, stat: fs.statSync(inputPath), }); var buffered = []; var onEnd = function() { realMode(fs.lstatSync(expectedBase).mode).should.equal(expectedDirMode); realMode(buffered[0].stat.mode).should.equal(expectedFileMode); done(); }; var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname, mode: expectedFileMode, dirMode: expectedDirMode, }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(firstFile); stream.end(); }); it('should change to the specified base', function(done) { var inputBase = path.join(__dirname, './fixtures'); var inputPath = path.join(__dirname, './fixtures/wow/suchempty'); var firstFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, stat: fs.statSync(inputPath), }); var buffered = []; var onEnd = function() { buffered[0].base.should.equal(inputBase); done(); }; var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname, base: inputBase, }); var bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); stream.pipe(bufferStream); stream.write(firstFile); stream.end(); }); it('should report IO errors', function(done) { if (isWindows) { console.log('Changing the mode of a file is not supported by node.js in Windows.'); console.log('This test is skipped on Windows because we have to chmod the file to 0.'); this.skip(); return; } var inputPath = path.join(__dirname, './fixtures/test.coffee'); var inputBase = path.join(__dirname, './fixtures/'); var expectedContents = fs.readFileSync(inputPath); var expectedBase = path.join(__dirname, './out-fixtures'); var expectedFile = new File({ base: inputBase, cwd: __dirname, path: inputPath, contents: expectedContents, }); fs.mkdirSync(expectedBase); fs.chmodSync(expectedBase, 0); var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); stream.on('error', function(err) { err.code.should.equal('EACCES'); done(); }); stream.write(expectedFile); }); ['end', 'finish'].forEach(function(eventName) { it('should emit ' + eventName + ' event', function(done) { var srcPath = path.join(__dirname, './fixtures/test.coffee'); var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname }); stream.on(eventName, function() { done(); }); var file = new File({ path: srcPath, cwd: __dirname, contents: new Buffer('1234567890'), }); stream.write(file); stream.end(); }); }); it('should pass options to through2', function(done) { var srcPath = path.join(__dirname, './fixtures/test.coffee'); var content = fs.readFileSync(srcPath); var stream = vfs.symlink('./out-fixtures/', { cwd: __dirname, objectMode: false }); stream.on('error', function(err) { err.should.match(/Invalid non-string\/buffer chunk/); done(); }); var file = new File({ path: srcPath, cwd: __dirname, contents: content, }); stream.write(file); stream.end(); }); });