Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit 24ccb51

Browse files
committed
feat: implement ipfs refs
1 parent 20beea2 commit 24ccb51

File tree

14 files changed

+439
-6
lines changed

14 files changed

+439
-6
lines changed

src/cli/commands/refs.js

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
'use strict'
2+
3+
const { print } = require('../utils')
4+
5+
const Format = {
6+
default: '<dst>',
7+
edges: '<src> -> <dst>'
8+
}
9+
10+
module.exports = {
11+
command: 'refs <key>',
12+
13+
describe: 'List links (references) from an object',
14+
15+
builder: {
16+
r: {
17+
alias: 'recursive',
18+
desc: 'Recursively list links of child nodes.',
19+
type: 'boolean',
20+
default: false
21+
},
22+
format: {
23+
desc: 'Output edges with given format. Available tokens: <src> <dst> <linkname>.',
24+
type: 'string',
25+
default: Format.default
26+
},
27+
e: {
28+
alias: 'edges',
29+
desc: 'Output edge format: `<from> -> <to>`',
30+
type: 'boolean',
31+
default: false
32+
},
33+
u: {
34+
alias: 'unique',
35+
desc: 'Omit duplicate refs from output.',
36+
type: 'boolean',
37+
default: false
38+
},
39+
'max-depth': {
40+
desc: 'Only for recursive refs, limits fetch and listing to the given depth.',
41+
type: 'number'
42+
}
43+
},
44+
45+
handler ({ getIpfs, key, recursive, format, e, u, resolve, maxDepth }) {
46+
resolve((async () => {
47+
if (format !== Format.default && e) {
48+
throw new Error('Cannot set edges to true and also specify format')
49+
}
50+
51+
if (maxDepth === 0) {
52+
return
53+
}
54+
55+
const ipfs = await getIpfs()
56+
let links = await ipfs.refs(key, { recursive, maxDepth })
57+
if (!links.length) {
58+
return
59+
}
60+
61+
const linkDAG = getLinkDAG(links)
62+
format = e ? Format.edges : format || Format.default
63+
printLinks(linkDAG, links[0], format, u && new Set())
64+
})())
65+
}
66+
}
67+
68+
function getLinkDAG (links) {
69+
const linkNames = {}
70+
for (const link of links) {
71+
linkNames[link.name] = link
72+
}
73+
74+
const linkDAG = {}
75+
for (const link of links) {
76+
const parentName = link.path.substring(0, link.path.lastIndexOf('/'))
77+
linkDAG[parentName] = linkDAG[parentName] || []
78+
linkDAG[parentName].push(link)
79+
}
80+
return linkDAG
81+
}
82+
83+
function printLinks (linkDAG, link, format, uniques) {
84+
const children = linkDAG[link.path] || []
85+
for (const child of children) {
86+
if (!uniques || !uniques.has(child.hash)) {
87+
uniques && uniques.add(child.hash)
88+
printLink(link, child, format)
89+
printLinks(linkDAG, child, format, uniques)
90+
}
91+
}
92+
}
93+
94+
function printLink (src, dst, format) {
95+
let out = format.replace(/<src>/g, src.hash)
96+
out = out.replace(/<dst>/g, dst.hash)
97+
out = out.replace(/<linkname>/g, dst.name)
98+
print(out)
99+
}
100+

src/core/components/files-regular/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ module.exports = self => ({
1515
getReadableStream: require('./get-readable-stream')(self),
1616
ls: require('./ls')(self),
1717
lsPullStream: require('./ls-pull-stream')(self),
18-
lsReadableStream: require('./ls-readable-stream')(self)
18+
lsReadableStream: require('./ls-readable-stream')(self),
19+
refs: require('./refs')(self),
20+
refsPullStream: require('./refs-pull-stream')(self)
1921
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict'
2+
3+
const exporter = require('ipfs-unixfs-exporter')
4+
const pull = require('pull-stream')
5+
const { normalizePath } = require('./utils')
6+
7+
module.exports = function (self) {
8+
return function (ipfsPath, options = {}) {
9+
const path = normalizePath(ipfsPath)
10+
const pathComponents = path.split('/')
11+
const pathDepth = pathComponents.length
12+
if (options.maxDepth === undefined) {
13+
options.maxDepth = options.recursive ? global.Infinity : pathDepth
14+
} else {
15+
options.maxDepth = options.maxDepth + pathDepth - 1
16+
}
17+
18+
if (options.preload !== false) {
19+
self._preload(pathComponents[0])
20+
}
21+
22+
return pull(
23+
exporter(ipfsPath, self._ipld, options),
24+
pull.map(node => {
25+
node.hash = node.cid.toString()
26+
delete node.cid
27+
delete node.content
28+
return node
29+
})
30+
)
31+
}
32+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict'
2+
3+
const promisify = require('promisify-es6')
4+
const pull = require('pull-stream')
5+
6+
module.exports = function (self) {
7+
return promisify((ipfsPath, options, callback) => {
8+
if (typeof options === 'function') {
9+
callback = options
10+
options = {}
11+
}
12+
13+
options = options || {}
14+
15+
pull(
16+
self.refsPullStream(ipfsPath, options),
17+
pull.collect((err, values) => {
18+
if (err) {
19+
return callback(err)
20+
}
21+
callback(null, values)
22+
})
23+
)
24+
})
25+
}

0 commit comments

Comments
 (0)