-
-
Notifications
You must be signed in to change notification settings - Fork 22
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
Add cloning support #40
Changes from 1 commit
3207113
79c296e
1b41394
c79545e
318e9b6
45e6642
cda6dd1
2aa81ce
5b331c1
04f3d0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,13 +8,15 @@ import test from 'ava'; | |
import {v4 as uuidv4} from 'uuid'; | ||
import sinon from 'sinon'; | ||
import assertDateEqual from './helpers/_assert'; | ||
import getFsName from './helpers/_whatfs'; | ||
import {buildEACCES, buildEIO, buildENOSPC, buildENOENT, buildEPERM, buildERRSTREAMWRITEAFTEREND} from './helpers/_fs-errors'; | ||
import cpFile from '..'; | ||
|
||
const THREE_HUNDRED_KILO = (100 * 3 * 1024) + 1; | ||
|
||
test.before(() => { | ||
process.chdir(path.dirname(__dirname)); | ||
console.log(`fs info: ${getFsName('.')}`); | ||
}); | ||
|
||
test.beforeEach(t => { | ||
|
@@ -38,20 +40,27 @@ test('reject an Error on missing `destination`', async t => { | |
}); | ||
|
||
test('copy a file', async t => { | ||
await cpFile('license', t.context.destination); | ||
await cpFile('license', t.context.destination, {clone: false}); | ||
t.is(fs.readFileSync(t.context.destination, 'utf8'), fs.readFileSync('license', 'utf8')); | ||
}); | ||
|
||
test('copy an empty file', async t => { | ||
fs.writeFileSync(t.context.source, ''); | ||
await cpFile(t.context.source, t.context.destination); | ||
await cpFile(t.context.source, t.context.destination, {clone: false}); | ||
t.is(fs.readFileSync(t.context.destination, 'utf8'), ''); | ||
}); | ||
|
||
test('copy big files', async t => { | ||
const buffer = crypto.randomBytes(THREE_HUNDRED_KILO); | ||
fs.writeFileSync(t.context.source, buffer); | ||
await cpFile(t.context.source, t.context.destination); | ||
await cpFile(t.context.source, t.context.destination, {clone: false}); | ||
t.true(buffer.equals(fs.readFileSync(t.context.destination))); | ||
}); | ||
|
||
test('clone a big file', async t => { | ||
const buffer = crypto.randomBytes(THREE_HUNDRED_KILO); | ||
fs.writeFileSync(t.context.source, buffer); | ||
await cpFile(t.context.source, t.context.destination, {clone: true}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't make this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, travis on Windows uses |
||
t.true(buffer.equals(fs.readFileSync(t.context.destination))); | ||
}); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
'use strict'; | ||
const childProcess = require('child_process'); | ||
|
||
/** | ||
* Returns a Windows drive letter. | ||
* @param {string} path | ||
* @returns {string | undefined} | ||
*/ | ||
function driveLetter(path) { | ||
return path.match(/^([A-Z]:)[\\/]/)[1]; | ||
} | ||
|
||
/** | ||
* Return something with a filesystem name for a path. | ||
* Only works on an English installation for obvious reasons. | ||
* @param {string} path | ||
* @returns {string | undefined} | ||
*/ | ||
function getFsNameWin32(path) { | ||
// Get the drive. If it has a drive letter in the front we use it, otherwise assume to be the same as cwd. | ||
const drive = driveLetter(path) || driveLetter(process.cwd); | ||
try { | ||
return childProcess.execSync(`fsutil fsinfo volumeInfo ${drive}`, {encoding: 'ascii'}) | ||
.split('\r\n') | ||
.filter(s => s.startsWith('File System Name')) | ||
.join('\r\n'); | ||
} catch (_) { | ||
return undefined; | ||
} | ||
} | ||
|
||
/** | ||
* Return something with a filesystem name for a path. | ||
* @param {string} path | ||
* @returns {string | undefined} | ||
* @see {@link https://unix.stackexchange.com/a/21807|How can I determine the fs type of my current working directory?} | ||
*/ | ||
function getFsNamePosix(path) { | ||
try { | ||
return childProcess.execSync(`mount | grep "^$(df -Pk '${path.replace(/'/g, '\'\\\'\'')}' | head -n 2 | tail -n 1 | cut -f 1 -d ' ') "`, | ||
{encoding: 'utf8'}); | ||
} catch (_) { | ||
return undefined; | ||
} | ||
} | ||
|
||
export default process.platform === 'win32' ? getFsNameWin32 : getFsNamePosix; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not clear from the docs here what
force
does.Maybe also mention some use-cases for needing to set it to
false
or'force'
as I cannot think of anything reason to not have this be justtrue
all the time.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is analogous to gnu cp's
--reflink=auto
vs--reflink
. From a usability standpoint, it is usually preferable to have a fallback (hencetrue
), but when someone comes onto a new platform it's nice to have a test for whether reflink is supported (hence"force"
).