Skip to content
This repository has been archived by the owner on Mar 10, 2020. It is now read-only.

Add symlink support to feat/files-api #224

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions dist/ipfsapi.js

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions dist/ipfsapi.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ipfs-api",
"version": "2.13.1",
"version": "2.13.2",
"description": "A client library for the IPFS API",
"main": "src/index.js",
"dependencies": {
Expand Down Expand Up @@ -37,7 +37,7 @@
"gulp": "^3.9.0",
"gulp-bump": "^1.0.0",
"gulp-eslint": "^2.0.0-rc-3",
"gulp-filter": "^3.0.1",
"gulp-filter": "^4.0.0",
"gulp-git": "^1.6.0",
"gulp-load-plugins": "^1.0.0",
"gulp-mocha": "^2.1.3",
Expand Down
48 changes: 36 additions & 12 deletions src/get-files-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ function headers (file) {

if (file.dir) {
header['Content-Type'] = 'application/x-directory'
} else if (file.symlink) {
header['Content-Type'] = 'application/symlink'
} else {
header['Content-Type'] = 'application/octet-stream'
}
Expand Down Expand Up @@ -46,20 +48,41 @@ function loadPaths (opts, file) {
follow: followSymlinks
})

return mg.found.map((name) => {
if (mg.cache[name] === 'FILE') {
return {
path: strip(name, file),
dir: false,
content: fs.createReadStream(name)
return mg.found
.map((name) => {
// symlinks
if (mg.symlinks[name] === true) {
return {
path: strip(name, file),
symlink: true,
dir: false,
content: fs.readlinkSync(name)
}
}
} else {
return {
path: strip(name, file),
dir: true

// files
if (mg.cache[name] === 'FILE') {
return {
path: strip(name, file),
symlink: false,
dir: false,
content: fs.createReadStream(name)
}
}
}
})

// directories
if (mg.cache[name] === 'DIR' || mg.cache[name] instanceof Array) {
return {
path: strip(name, file),
symlink: false,
dir: true
}
}

// files inside symlinks and others
return
})
.filter((file) => !!file) // filter out null files
}

return {
Expand Down Expand Up @@ -88,6 +111,7 @@ function getFilesStream (files, opts) {

return {
path: '',
symlink: false,
dir: false,
content: file
}
Expand Down
2 changes: 1 addition & 1 deletion src/request-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function onRes (buffer, cb) {

const stream = !!res.headers['x-stream-output']
const chunkedObjects = !!res.headers['x-chunked-output']
const isJson = res.headers['content-type'].indexOf('application/json') === 0
const isJson = res.headers['content-type'] && res.headers['content-type'].indexOf('application/json') === 0

if (res.statusCode >= 400 || !res.statusCode) {
const error = new Error(`Server responded with ${res.statusCode}`)
Expand Down
28 changes: 26 additions & 2 deletions test/api/add.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,37 @@ describe('.add', () => {
})
})

it('add a nested dir', (done) => {
it('add a nested dir following symlinks', (done) => {
apiClients['a'].add(path.join(__dirname, '/../test-folder'), { recursive: true }, (err, res) => {
if (isNode) {
expect(err).to.not.exist

const added = res[res.length - 1]
expect(added).to.have.property('Hash', 'QmTDH2RXGn8XyDAo9YyfbZAUXwL1FCr44YJCN9HBZmL9Gj')
expect(added).to.have.property('Hash', 'QmRNjDeKStKGTQXnJ2NFqeQ9oW23WcpbmvCVrpDHgDg3T6')

// check that the symlink was replaced by the target file
const linkPath = 'test-folder/hello-link'
const filePath = 'test-folder/files/hello.txt'
const linkHash = res.filter((e) => e.Name === linkPath)[0].Hash
const fileHash = res.filter((e) => e.Name === filePath)[0].Hash
expect(linkHash).to.equal(fileHash)

done()
} else {
expect(err.message).to.be.equal('Recursive uploads are not supported in the browser')
done()
}
})
})

it('add a nested dir without following symlinks', (done) => {
apiClients['a'].add(path.join(__dirname, '/../test-folder'), { recursive: true, followSymlinks: false }, (err, res) => {
if (isNode) {
expect(err).to.not.exist

const added = res[res.length - 1]
// same hash as the result from the cli (ipfs add test/test-folder -r)
expect(added).to.have.property('Hash', 'QmRArDYd8Rk7Zb7K2699KqmQM1uUoejn1chtEAcqkvjzGg')
done()
} else {
expect(err.message).to.be.equal('Recursive uploads are not supported in the browser')
Expand Down
4 changes: 2 additions & 2 deletions test/api/ls.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('ls', function () {
it('should correctly handle a nonexisting path', function (done) {
if (!isNode) return done()

apiClients['a'].ls('QmTDH2RXGn8XyDAo9YyfbZAUXwL1FCr44YJCN9HBZmL9Gj/folder_that_isnt_there', (err, res) => {
apiClients['a'].ls('QmRNjDeKStKGTQXnJ2NFqeQ9oW23WcpbmvCVrpDHgDg3T6/folder_that_isnt_there', (err, res) => {
expect(err).to.exist
expect(res).to.not.exist
done()
Expand Down Expand Up @@ -56,7 +56,7 @@ describe('ls', function () {
it('should correctly handle a nonexisting path', () => {
if (!isNode) return

return apiClients['a'].ls('QmTDH2RXGn8XyDAo9YyfbZAUXwL1FCr44YJCN9HBZmL9Gj/folder_that_isnt_there')
return apiClients['a'].ls('QmRNjDeKStKGTQXnJ2NFqeQ9oW23WcpbmvCVrpDHgDg3T6/folder_that_isnt_there')
.catch((err) => {
expect(err).to.exist
})
Expand Down
19 changes: 19 additions & 0 deletions test/request-api.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,24 @@ describe('ipfsAPI request tests', () => {
protocol: 'http'
}).id(noop)
})

it('does not crash if no content-type header is provided', (done) => {
if (!isNode) {
return done()
}

// go-ipfs always (currently) adds a content-type header, even if no content is present,
// the standard behaviour for an http-api is to omit this header if no content is present
const server = require('http').createServer((req, res) => {
res.writeHead(200)
res.end()
}).listen(6001, () => {
ipfsAPI('/ip4/127.0.0.1/tcp/6001')
.config.replace('test/r-config.json', (err) => {
expect(err).to.not.exist
server.close(done)
})
})
})
})
})
1 change: 1 addition & 0 deletions test/test-folder/hello-link