This repository has been archived by the owner on Feb 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Stat command working on directories
- Loading branch information
1 parent
bad24b3
commit 4671b2e
Showing
4 changed files
with
195 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
'use strict' | ||
|
||
const exporter = require('ipfs-unixfs-engine').exporter | ||
const unmarshal = require('ipfs-unixfs').unmarshal | ||
const promisify = require('promisify-es6') | ||
const pull = require('pull-stream') | ||
const bs58 = require('bs58') | ||
const CID = require('cids') | ||
const { | ||
collect | ||
} = pull | ||
const { | ||
withMfsRoot, | ||
validatePath | ||
} = require('./utils') | ||
const { | ||
waterfall | ||
} = require('async') | ||
|
||
const defaultOptions = { | ||
hash: false, | ||
size: false, | ||
withLocal: false | ||
} | ||
|
||
module.exports = function mfsStat (ipfs) { | ||
return promisify((path, options, callback) => { | ||
withMfsRoot(ipfs, (error, root) => { | ||
if (error) { | ||
return callback(error) | ||
} | ||
|
||
if (typeof options === 'function') { | ||
callback = options | ||
options = {} | ||
} | ||
|
||
options = Object.assign({}, defaultOptions, options) | ||
|
||
try { | ||
path = validatePath(path) | ||
root = root.toBaseEncodedString() | ||
} catch (error) { | ||
return callback(error) | ||
} | ||
|
||
waterfall([ | ||
(done) => pull( | ||
exporter(`/ipfs/${root}${path}`, ipfs._ipld), | ||
collect(done) | ||
), | ||
(results, done) => { | ||
if (!results.length) { | ||
return done(new Error('file does not exist')) | ||
} | ||
|
||
done(null, results[0]) | ||
}, | ||
(result, done) => { | ||
if (options.hash) { | ||
return done(null, { | ||
hash: bs58.encode(result.hash) | ||
}) | ||
} else if (options.size) { | ||
return done(null, { | ||
size: result.size | ||
}) | ||
} | ||
|
||
waterfall([ | ||
(next) => ipfs.dag.get(new CID(result.hash), next), | ||
(result, next) => next(null, result.value), | ||
(node, next) => { | ||
const data = unmarshal(node.data) | ||
|
||
next(null, { | ||
hash: node.multihash, | ||
size: data.blockSizes.reduce((acc, curr) => acc + curr, 0), | ||
cumulativeSize: node.size, | ||
childBlocks: node.links.length, | ||
type: data.type | ||
}) | ||
} | ||
], done) | ||
} | ||
], callback) | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* eslint-env mocha */ | ||
'use strict' | ||
|
||
const chai = require('chai') | ||
chai.use(require('dirty-chai')) | ||
const expect = chai.expect | ||
|
||
const { | ||
createMfs, | ||
EMPTY_DIRECTORY_HASH | ||
} = require('./fixtures') | ||
|
||
describe('stat', function () { | ||
this.timeout(30000) | ||
|
||
let mfs | ||
|
||
before(() => { | ||
return createMfs() | ||
.then(instance => { | ||
mfs = instance | ||
}) | ||
}) | ||
|
||
after((done) => { | ||
mfs.node.stop(done) | ||
}) | ||
|
||
it('refuses to stat files with an empty path', () => { | ||
return mfs.stat('') | ||
.then(() => expect.fail('No error was thrown for an empty path')) | ||
.catch(error => { | ||
expect(error.message).to.contain('paths must not be empty') | ||
}) | ||
}) | ||
|
||
it('refuses to lists files with an invalid path', () => { | ||
return mfs.stat('not-valid') | ||
.then(() => expect.fail('No error was thrown for an empty path')) | ||
.catch(error => { | ||
expect(error.message).to.contain('paths must start with a leading /') | ||
}) | ||
}) | ||
|
||
it('fails to stat non-existent file', () => { | ||
return mfs.stat('/i-do-not-exist') | ||
.then(() => expect.fail('No error was thrown for a non-existent file')) | ||
.catch(error => { | ||
expect(error.message).to.contain('file does not exist') | ||
}) | ||
}) | ||
|
||
it('stats an empty directory', () => { | ||
const path = '/empty-directory' | ||
|
||
return mfs.mkdir('/empty-directory') | ||
.then(() => mfs.stat(path)) | ||
.then(stats => { | ||
expect(stats.size).to.equal(0) | ||
expect(stats.cumulativeSize).to.equal(4) | ||
expect(stats.childBlocks).to.equal(0) | ||
expect(stats.type).to.equal('directory') | ||
}) | ||
}) | ||
|
||
it('returns only a hash', () => { | ||
const path = '/empty-directory' | ||
|
||
return mfs.mkdir('/empty-directory') | ||
.then(() => mfs.stat(path, { | ||
hash: true | ||
})) | ||
.then(stats => { | ||
expect(Object.keys(stats).length).to.equal(1) | ||
expect(stats.hash).to.equal(EMPTY_DIRECTORY_HASH) | ||
}) | ||
}) | ||
|
||
it('returns only the size', () => { | ||
const path = '/empty-directory' | ||
|
||
return mfs.mkdir('/empty-directory') | ||
.then(() => mfs.stat(path, { | ||
size: true | ||
})) | ||
.then(stats => { | ||
expect(Object.keys(stats).length).to.equal(1) | ||
expect(stats.size).to.equal(4) // protobuf size?! | ||
}) | ||
}) | ||
|
||
it.skip('computes how much of the DAG is local', () => { | ||
|
||
}) | ||
|
||
it.skip('stats a file', () => { | ||
|
||
}) | ||
}) |