Skip to content
This repository was archived by the owner on Apr 29, 2020. It is now read-only.

Commit a47c9ed

Browse files
authored
feat: support storing metadata in unixfs nodes (#39)
* feat: support storing metadata in unixfs nodes Adds `mtime` and `mode` properties to `{path, content}` import entries * chore: remove gh url * chore: upgrade node * chore: update deps * fix: add metadata to directories too * fix: add metadata to imported directories
1 parent 25c7295 commit a47c9ed

11 files changed

+331
-48
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ stages:
66
- cov
77

88
node_js:
9-
- '10'
9+
- '12'
1010

1111
os:
1212
- linux

README.md

+13-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# ipfs-unixfs-importer
1+
# ipfs-unixfs-importer <!-- omit in toc -->
22

33
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
44
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/)
@@ -13,22 +13,19 @@
1313

1414
> JavaScript implementation of the layout and chunking mechanisms used by IPFS to handle Files
1515
16-
## Lead Maintainer
16+
## Lead Maintainer <!-- omit in toc -->
1717

1818
[Alex Potsides](https://github.com/achingbrain)
1919

20-
## Table of Contents
20+
## Table of Contents <!-- omit in toc -->
2121

22-
- [ipfs-unixfs-importer](#ipfs-unixfs-importer)
23-
- [Lead Maintainer](#lead-maintainer)
24-
- [Table of Contents](#table-of-contents)
25-
- [Install](#install)
26-
- [Usage](#usage)
27-
- [Example](#example)
28-
- [API](#api)
29-
- [const import = importer(source, ipld [, options])](#const-import--importersource-ipld--options)
30-
- [Contribute](#contribute)
31-
- [License](#license)
22+
- [Install](#install)
23+
- [Usage](#usage)
24+
- [Example](#example)
25+
- [API](#api)
26+
- [const import = importer(source, ipld [, options])](#const-import--importersource-ipld--options)
27+
- [Contribute](#contribute)
28+
- [License](#license)
3229

3330
## Install
3431

@@ -108,7 +105,9 @@ The `import` function returns an async iterator takes a source async iterator th
108105
```js
109106
{
110107
path: 'a name',
111-
content: (Buffer or iterator emitting Buffers)
108+
content: (Buffer or iterator emitting Buffers),
109+
mtime: (Number representing seconds since (positive) or before (negative) the Unix Epoch),
110+
mode: (Number representing ugo-rwx, setuid, setguid and sticky bit)
112111
}
113112
```
114113

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"cids": "~0.7.1",
4545
"detect-node": "^2.0.4",
4646
"dirty-chai": "^2.0.1",
47-
"ipfs-unixfs-exporter": "~0.37.0",
47+
"ipfs-unixfs-exporter": "^0.39.0",
4848
"ipld": "^0.25.0",
4949
"ipld-in-memory": "^3.0.0",
5050
"multihashes": "~0.4.14",
@@ -55,16 +55,16 @@
5555
"async-iterator-all": "^1.0.0",
5656
"async-iterator-batch": "~0.0.1",
5757
"async-iterator-first": "^1.0.0",
58-
"bl": "^3.0.0",
58+
"bl": "^4.0.0",
5959
"deep-extend": "~0.6.0",
6060
"err-code": "^2.0.0",
6161
"hamt-sharding": "~0.0.2",
62-
"ipfs-unixfs": "~0.1.16",
62+
"ipfs-unixfs": "^0.2.0",
6363
"ipld-dag-pb": "^0.18.0",
6464
"multicodec": "~0.5.1",
65-
"multihashing-async": "~0.7.0",
65+
"multihashing-async": "^0.8.0",
6666
"rabin-wasm": "~0.0.8",
67-
"superstruct": "~0.6.1"
67+
"superstruct": "^0.8.2"
6868
},
6969
"contributors": [
7070
"Alan Shaw <[email protected]>",

src/dag-builder/dir.js

+9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ const {
88

99
const dirBuilder = async (item, ipld, options) => {
1010
const unixfs = new UnixFS('directory')
11+
12+
if (item.mtime) {
13+
unixfs.mtime = item.mtime
14+
}
15+
16+
if (item.mode) {
17+
unixfs.mode = item.mode
18+
}
19+
1120
const node = new DAGNode(unixfs.marshal(), [])
1221
const cid = await persist(node, ipld, options)
1322
const path = item.path

src/dag-builder/file/index.js

+19-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const dagBuilders = {
1515
trickle: require('./trickle')
1616
}
1717

18-
async function * buildFile (source, ipld, options) {
18+
async function * buildFile (file, source, ipld, options) {
1919
let count = -1
2020
let previous
2121

@@ -36,6 +36,15 @@ async function * buildFile (source, ipld, options) {
3636
opts.cidVersion = 1
3737
} else {
3838
unixfs = new UnixFS(options.leafType, buffer)
39+
40+
if (file.mtime) {
41+
unixfs.mtime = file.mtime
42+
}
43+
44+
if (file.mode) {
45+
unixfs.mode = file.mode
46+
}
47+
3948
node = new DAGNode(unixfs.marshal())
4049
}
4150

@@ -81,6 +90,14 @@ const reduce = (file, ipld, options) => {
8190
// create a parent node and add all the leaves
8291
const f = new UnixFS('file')
8392

93+
if (file.mtime) {
94+
f.mtime = file.mtime
95+
}
96+
97+
if (file.mode) {
98+
f.mode = file.mode
99+
}
100+
84101
const links = leaves
85102
.filter(leaf => {
86103
if (leaf.cid.codec === 'raw' && leaf.node.length) {
@@ -132,7 +149,7 @@ const fileBuilder = async (file, source, ipld, options) => {
132149
throw errCode(new Error(`Unknown importer build strategy name: ${options.strategy}`), 'ERR_BAD_STRATEGY')
133150
}
134151

135-
const roots = await all(dagBuilder(buildFile(source, ipld, options), reduce(file, ipld, options), options.builderOptions))
152+
const roots = await all(dagBuilder(buildFile(file, source, ipld, options), reduce(file, ipld, options), options.builderOptions))
136153

137154
if (roots.length > 1) {
138155
throw errCode(new Error('expected a maximum of 1 roots and got ' + roots.length), 'ETOOMANYROOTS')

src/dir-flat.js

+10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class DirFlat extends Dir {
1717
put (name, value) {
1818
this.cid = undefined
1919
this.size = undefined
20+
2021
this._children[name] = value
2122
}
2223

@@ -68,6 +69,15 @@ class DirFlat extends Dir {
6869
}
6970

7071
const unixfs = new UnixFS('directory')
72+
73+
if (this.mtime) {
74+
unixfs.mtime = this.mtime
75+
}
76+
77+
if (this.mode) {
78+
unixfs.mode = this.mode
79+
}
80+
7181
const node = new DAGNode(unixfs.marshal(), links)
7282
const cid = await persist(node, ipld, this.options)
7383

src/dir-sharded.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class DirSharded extends Dir {
7373
}
7474

7575
async * flush (path, ipld) {
76-
for await (const entry of flush(path, this._bucket, ipld, this.options)) {
76+
for await (const entry of flush(path, this._bucket, ipld, this, this.options)) {
7777
yield entry
7878
}
7979
}
@@ -83,7 +83,7 @@ module.exports = DirSharded
8383

8484
module.exports.hashFn = hashFn
8585

86-
async function * flush (path, bucket, ipld, options) {
86+
async function * flush (path, bucket, ipld, shardRoot, options) {
8787
const children = bucket._children
8888
const links = []
8989

@@ -99,7 +99,7 @@ async function * flush (path, bucket, ipld, options) {
9999
if (Bucket.isBucket(child)) {
100100
let shard
101101

102-
for await (const subShard of await flush('', child, ipld, options)) {
102+
for await (const subShard of await flush('', child, ipld, null, options)) {
103103
shard = subShard
104104
}
105105

@@ -141,6 +141,14 @@ async function * flush (path, bucket, ipld, options) {
141141
dir.fanout = bucket.tableSize()
142142
dir.hashType = options.hashFn.code
143143

144+
if (shardRoot && shardRoot.mtime) {
145+
dir.mtime = shardRoot.mtime
146+
}
147+
148+
if (shardRoot && shardRoot.mode) {
149+
dir.mode = shardRoot.mode
150+
}
151+
144152
const node = new DAGNode(dir.marshal(), links)
145153
const cid = await persist(node, ipld, options)
146154

src/flat-to-shard.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ module.exports = async function flatToShard (child, dir, threshold, options) {
2020
await parent.put(newDir.parentKey, newDir)
2121
}
2222

23-
if (parent) {
24-
return flatToShard(newDir, parent, threshold, options)
25-
}
23+
return flatToShard(newDir, parent, threshold, options)
2624
}
2725

2826
return newDir
@@ -36,7 +34,9 @@ async function convertToShard (oldDir, options) {
3634
parentKey: oldDir.parentKey,
3735
path: oldDir.path,
3836
dirty: oldDir.dirty,
39-
flat: false
37+
flat: false,
38+
mtime: oldDir.mtime,
39+
mode: oldDir.mode
4040
}, options)
4141

4242
for await (const { key, child } of oldDir.eachChildSeries()) {

src/tree-builder.js

+18-18
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ async function addToTree (elem, tree, options) {
3636
parentKey: pathElem,
3737
path: currentPath,
3838
dirty: true,
39-
flat: true
39+
flat: true,
40+
mtime: dir && dir.unixfs && dir.unixfs.mtime,
41+
mode: dir && dir.unixfs && dir.unixfs.mode
4042
}, options)
4143
}
4244

@@ -64,28 +66,26 @@ async function * treeBuilder (source, ipld, options) {
6466
yield entry
6567
}
6668

67-
if (tree) {
68-
if (!options.wrapWithDirectory) {
69-
if (tree.childCount() > 1) {
70-
throw errCode(new Error('detected more than one root'), 'ERR_MORE_THAN_ONE_ROOT')
71-
}
72-
73-
const unwrapped = await first(tree.eachChildSeries())
74-
75-
if (!unwrapped) {
76-
return
77-
}
78-
79-
tree = unwrapped.child
69+
if (!options.wrapWithDirectory) {
70+
if (tree.childCount() > 1) {
71+
throw errCode(new Error('detected more than one root'), 'ERR_MORE_THAN_ONE_ROOT')
8072
}
8173

82-
if (!tree.dir) {
74+
const unwrapped = await first(tree.eachChildSeries())
75+
76+
if (!unwrapped) {
8377
return
8478
}
8579

86-
for await (const entry of tree.flush(tree.path, ipld)) {
87-
yield entry
88-
}
80+
tree = unwrapped.child
81+
}
82+
83+
if (!tree.dir) {
84+
return
85+
}
86+
87+
for await (const entry of tree.flush(tree.path, ipld)) {
88+
yield entry
8989
}
9090
}
9191

test/benchmark.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe.skip('benchmark', function () {
2424
const times = []
2525

2626
after(() => {
27-
console.info(`Percent\tms`) // eslint-disable-line no-console
27+
console.info('Percent\tms') // eslint-disable-line no-console
2828
times.forEach((time, index) => {
2929
console.info(`${index}\t${parseInt(time / REPEATS)}`) // eslint-disable-line no-console
3030
})

0 commit comments

Comments
 (0)