Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy file #18

Merged
merged 11 commits into from Sep 22, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
@@ -1,6 +1,6 @@
language: node_js
node_js:
- "8"
- "8.4.0"
install: npm install
jobs:
include:
Expand Down
8 changes: 4 additions & 4 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "fs-nextra",
"version": "0.2.1",
"version": "0.3.0",
"description": "Node.js V8 native fs enhanced with util.promisify and standard extra methods.",
"main": "src/index.js",
"scripts": {
Expand Down Expand Up @@ -28,11 +28,11 @@
"author": "BDISTIN",
"license": "MIT",
"engines": {
"node": ">=8.1.0"
"node": ">=8.5.0"
},
"devDependencies": {
"ava": "^0.21.0",
"eslint": "^4.3.0",
"ava": "^0.22.0",
"eslint": "^4.6.1",
"ink-docstrap": "github:bdistin/docstrap",
"jsdoc": "github:jsdoc3/jsdoc",
"mock-fs": "^4.4.1",
Expand Down
5 changes: 5 additions & 0 deletions src/index.js
@@ -1,8 +1,11 @@
/** @namespace fsn/nextra */
const nextra = {
copy: require('./nextra/copy'),
copyFileAtomic: require('./nextra/copyFileAtomic'),
createFile: require('./nextra/createFile'),
createFileAtomic: require('./nextra/createFileAtomic'),
createFileCopy: require('./nextra/createFileCopy'),
createFileCopyAtomic: require('./nextra/createFileCopyAtomic'),
createLink: require('./nextra/createLink'),
createLinkAtomic: require('./nextra/createLinkAtomic'),
createSymlink: require('./nextra/createSymlink'),
Expand All @@ -12,6 +15,8 @@ const nextra = {
ensureDir: require('./nextra/mkdirs'),
ensureFile: require('./nextra/createFile'),
ensureFileAtomic: require('./nextra/createFileAtomic'),
ensureFileCopy: require('./nextra/createFileCopy'),
ensureFileCopyAtomic: require('./nextra/createFileCopyAtomic'),
ensureLink: require('./nextra/createLink'),
ensureLinkAtomic: require('./nextra/createLinkAtomic'),
ensureSymlink: require('./nextra/createSymlink'),
Expand Down
26 changes: 26 additions & 0 deletions src/nextra/copyFileAtomic.js
@@ -0,0 +1,26 @@
const { tempFile } = require('../util');
const { copyFile } = require('../fs');

const move = require('./move');

/**
* @typedef writeOptions
* @memberof fsn/nextra
* @property {string} [encoding = 'utf8'] The file encoding
* @property {integer} [mode = 0o666] The chmod
* @property {string} [flag = 'w'] The flag
*/

/**
* @function copyFileAtomic
* @memberof fsn/nextra
* @param {string} source The path to the file you want to copy
* @param {string} destination The path to the file destination
* @param {writeOptions|string} [options] The write options or the encoding string.
* @return {type} {description}
*/
module.exports = async function copyFileAtomic(source, destination, options) {
const tempPath = tempFile();
await copyFile(source, tempPath, options);
return move(tempPath, destination, { overwrite: true });
};
32 changes: 32 additions & 0 deletions src/nextra/createFileCopy.js
@@ -0,0 +1,32 @@
const { dirname } = require('path');

const { copyFile } = require('../fs');

const copyFileAtomic = require('./copyFileAtomic');
const mkdirs = require('./mkdirs');
const pathExists = require('./pathExists');

/**
* Creates an empty file, making all folders required to satisfy the given file path.
* @function ensureFile
* @memberof fsn/nextra
* @param {string} file Path of the file you want to create
* @param {boolean} [atomic = false] Whether the operation should run atomicly
* @return {Promise<void>}
*/

/**
* Creates an empty file, making all folders required to satisfy the given file path.
* @function createFileCopy
* @memberof fsn/nextra
* @param {string} source The path to the file you want to copy
* @param {string} destination The path to the file destination
* @param {writeOptions|string} [options] The write options or the encoding string.
* @param {boolean} [atomic = false] Whether the operation should run atomicly
* @return {Promise<void>}
*/
module.exports = async function createFileCopy(source, destination, options, atomic = false) {
const dir = dirname(destination);
if (!await pathExists(dir)) await mkdirs(dir);
return atomic ? copyFileAtomic(source, destination, options) : copyFile(source, destination, options);
};
23 changes: 23 additions & 0 deletions src/nextra/createFileCopyAtomic.js
@@ -0,0 +1,23 @@
const createFileCopy = require('./createFileCopy');

/**
* Creates an empty file, making all folders required to satisfy the given file path.
* @function ensureFile
* @memberof fsn/nextra
* @param {string} file Path of the file you want to create
* @param {boolean} [atomic = false] Whether the operation should run atomicly
* @return {Promise<void>}
*/

/**
* Creates an empty file, making all folders required to satisfy the given file path.
* @function createFileCopyAtomic
* @memberof fsn/nextra
* @param {string} source The path to the file you want to copy
* @param {string} destination The path to the file destination
* @param {writeOptions|string} [options] The write options or the encoding string.
* @return {Promise<void>}
*/
module.exports = async function createFileCopyAtomic(source, destination, options) {
return createFileCopy(source, destination, options, true);
};
31 changes: 4 additions & 27 deletions src/util.js
@@ -1,9 +1,9 @@
const { sep, resolve, dirname, join, normalize, isAbsolute, relative } = require('path');
const { sep, resolve, dirname, basename, join, normalize, isAbsolute, relative } = require('path');
const { promisify } = require('util');
const { randomBytes } = require('crypto');
const { tmpdir } = require('os');

const { rmdir, lstat, createReadStream, createWriteStream, unlink, stat, chmod, readdir, readlink, open, futimes, close, mkdir, symlink } = require('./fs');
const { rmdir, lstat, createReadStream, createWriteStream, unlink, stat, chmod, readdir, readlink, mkdir, symlink, copyFile } = require('./fs');

const remove = require('./nextra/remove');
const pathExists = require('./nextra/pathExists');
Expand Down Expand Up @@ -150,8 +150,8 @@ exports.startCopy = async (mySource, options) => {
return this.copyDir(item.name, options);
} else if (stats.isFile() || stats.isCharacterDevice() || stats.isBlockDevice()) {
const target = item.name.replace(options.currentPath, options.targetPath.replace('$', '$$$$'));
if (await this.isWritable(target)) return this.copyFile(item, target, options);
else if (options.overwrite) return unlink(target).then(() => { this.copyFile(item, target, options); });
if (await this.isWritable(target)) return copyFile(mySource, join(target, basename(mySource)), options);
else if (options.overwrite) return unlink(target).then(() => { copyFile(mySource, join(target, basename(mySource)), options); });
else if (options.errorOnExist) throw new Error(`${target} already exists`);
} else if (stats.isSymbolicLink()) {
const target = item.replace(options.currentPath, options.targetPath);
Expand All @@ -161,29 +161,6 @@ exports.startCopy = async (mySource, options) => {
throw new Error('FS-NEXTRA: An Unkown error has occured in startCopy.');
};

exports.copyFile = (file, target, options) => new Promise((res, rej) => {
const readStream = createReadStream(file.name);
const writeStream = createWriteStream(target, { mode: file.mode });

readStream.on('error', rej);
writeStream.on('error', rej);

if (options.transform) options.transform(readStream, writeStream, file);
else writeStream.on('open', () => { readStream.pipe(writeStream); });

writeStream.once('close', async () => {
const error = await chmod(target, file.mode).catch(err => err);
if (error) return rej(error);
if (!options.preserveTimestamps) return res();
const fd = await open(target, 'r+').catch(err => err);
if (fd instanceof Error) return rej(fd);
const futimesErr = futimes(fd, file.atime, file.mtime).catch(err => err);
const closeErr = close(fd).catch(err => err);
if (futimesErr || closeErr) return rej(futimesErr || closeErr);
return res();
});
});

exports.mkDir = async (dir, target, options) => {
await mkdir(target, dir.mode);
await chmod(target, dir.mode);
Expand Down