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

Commit 9546629

Browse files
committed
feat: allow daemon to init and start in a single cmd
This PR aligns `ipfs init` and `ipfs daemon` with go-ipfs. ipfs/kubo#6489 `ipfs init` changed to accept a file path as an argument `ipfs daemon` changed to support `--init` and `--init-config` options. Now we can do `ipfs daemon --init --init-config /path/to/custom-config` refs: ipfs/js-ipfsd-ctl#303
1 parent 1fca5d6 commit 9546629

File tree

6 files changed

+107
-16
lines changed

6 files changed

+107
-16
lines changed

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,16 @@
194194
"execa": "^2.0.4",
195195
"form-data": "^2.5.1",
196196
"hat": "0.0.3",
197-
"ipfsd-ctl": "~0.45.0",
198197
"interface-ipfs-core": "^0.111.1",
198+
"ipfsd-ctl": "~0.45.0",
199199
"libp2p-websocket-star": "~0.10.2",
200200
"ncp": "^2.0.0",
201201
"p-event": "^4.1.0",
202202
"qs": "^6.5.2",
203203
"rimraf": "^3.0.0",
204204
"sinon": "^7.4.2",
205-
"stream-to-promise": "^2.2.0"
205+
"stream-to-promise": "^2.2.0",
206+
"temp-write": "^4.0.0"
206207
},
207208
"optionalDependencies": {
208209
"prom-client": "^11.5.3",

src/cli/commands/daemon.js

+25
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
'use strict'
22

33
const os = require('os')
4+
const fs = require('fs')
45
const toUri = require('multiaddr-to-uri')
56
const { ipfsPathHelp } = require('../utils')
7+
const debug = require('debug')('ipfs:cli:daemon')
68

79
module.exports = {
810
command: 'daemon',
@@ -12,6 +14,15 @@ module.exports = {
1214
builder (yargs) {
1315
return yargs
1416
.epilog(ipfsPathHelp)
17+
.option('init', {
18+
type: 'boolean',
19+
default: false,
20+
desc: 'Initialize ipfs with default settings if not already initialized.'
21+
})
22+
.option('init-config', {
23+
type: 'string',
24+
desc: 'Path to existing configuration file to be loaded during --init.'
25+
})
1526
.option('enable-sharding-experiment', {
1627
type: 'boolean',
1728
default: false
@@ -46,9 +57,23 @@ module.exports = {
4657

4758
const repoPath = argv.getRepoPath()
4859

60+
let config = {}
61+
// read and parse config file
62+
if (argv.initConfig) {
63+
try {
64+
const raw = fs.readFileSync(argv.initConfig)
65+
config = JSON.parse(raw)
66+
} catch (error) {
67+
debug(error)
68+
throw new Error('Default config couldn\'t be found or content isn\'t valid JSON.')
69+
}
70+
}
71+
4972
// Required inline to reduce startup time
5073
const Daemon = require('../../cli/daemon')
5174
const daemon = new Daemon({
75+
init: argv.init,
76+
config,
5277
silent: argv.silent,
5378
repo: process.env.IPFS_PATH,
5479
offline: argv.offline,

src/cli/commands/init.js

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
'use strict'
22

3+
const fs = require('fs')
4+
const debug = require('debug')('ipfs:cli:init')
35
const { ipfsPathHelp } = require('../utils')
46

57
module.exports = {
6-
command: 'init [config] [options]',
8+
command: 'init [default-config] [options]',
79
describe: 'Initialize a local IPFS node',
810
builder (yargs) {
911
return yargs
1012
.epilog(ipfsPathHelp)
11-
.positional('config', {
12-
describe: 'Node config, this should JSON and will be merged with the default config. Check https://github.com/ipfs/js-ipfs#optionsconfig',
13+
.positional('default-config', {
14+
describe: 'Initialize with the given configuration. Path to the config file. Check https://github.com/ipfs/js-ipfs#optionsconfig',
1315
type: 'string'
1416
})
1517
.option('bits', {
@@ -34,6 +36,18 @@ module.exports = {
3436
argv.resolve((async () => {
3537
const path = argv.getRepoPath()
3638

39+
let config = {}
40+
// read and parse config file
41+
if (argv.defaultConfig) {
42+
try {
43+
const raw = fs.readFileSync(argv.defaultConfig)
44+
config = JSON.parse(raw)
45+
} catch (error) {
46+
debug(error)
47+
throw new Error('Default config couldn\'t be found or content isn\'t valid JSON.')
48+
}
49+
}
50+
3751
argv.print(`initializing ipfs node at ${path}`)
3852

3953
// Required inline to reduce startup time
@@ -44,7 +58,7 @@ module.exports = {
4458
repo: new Repo(path),
4559
init: false,
4660
start: false,
47-
config: argv.config || {}
61+
config
4862
})
4963

5064
try {

src/cli/daemon.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class Daemon {
5555
}
5656

5757
// start the daemon
58-
const ipfsOpts = Object.assign({ init: false }, this._options, { start: true, libp2p })
58+
const ipfsOpts = Object.assign({ }, this._options, { start: true, libp2p })
5959
const ipfs = new IPFS(ipfsOpts)
6060

6161
await new Promise((resolve, reject) => {

test/cli/daemon.js

+49
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,29 @@ const os = require('os')
99
const path = require('path')
1010
const hat = require('hat')
1111
const fs = require('fs')
12+
const tempWrite = require('temp-write')
1213
const pkg = require('../../package.json')
1314

1415
const skipOnWindows = isWindows() ? it.skip : it
16+
const daemonReady = (daemon, fn) => {
17+
let r = null
18+
const p = new Promise((resolve, reject) => {
19+
daemon.stdout.on('data', async (data) => {
20+
if (data.toString().includes('Daemon is ready')) {
21+
try {
22+
r = await fn()
23+
} catch (err) {
24+
reject(err)
25+
}
26+
daemon.kill()
27+
}
28+
})
29+
daemon.stderr.on('data', () => reject(new Error('Daemon didnt start')))
30+
daemon.then(() => resolve(r)).catch(reject)
31+
})
1532

33+
return p
34+
}
1635
const checkLock = (repo) => {
1736
// skip on windows
1837
// https://github.com/ipfs/js-ipfsd-ctl/pull/155#issuecomment-326983530
@@ -265,4 +284,34 @@ describe('daemon', () => {
265284
expect(err.stdout).to.include(`Node.js version: ${process.versions.node}`)
266285
}
267286
})
287+
288+
it('should init', async function () {
289+
this.timeout(100 * 1000)
290+
const daemon = ipfs('daemon --init')
291+
let stdout = ''
292+
293+
daemon.stdout.on('data', (data) => {
294+
stdout += data.toString('utf8')
295+
296+
if (stdout.includes('Daemon is ready')) {
297+
daemon.kill()
298+
}
299+
})
300+
301+
try {
302+
await daemon
303+
throw new Error('Did not kill process')
304+
} catch (err) {
305+
expect(err.killed).to.be.true()
306+
}
307+
})
308+
309+
it('should init with custom config', async function () {
310+
this.timeout(100 * 1000)
311+
const configPath = tempWrite.sync('{"Addresses": {"API": "/ip4/127.0.0.1/tcp/9999"}}', 'config.json')
312+
const daemon = ipfs(`daemon --init --init-config ${configPath}`)
313+
314+
const r = await daemonReady(daemon, () => ipfs('config \'Addresses.API\''))
315+
expect(r).to.be.eq('/ip4/127.0.0.1/tcp/9999')
316+
})
268317
})

test/cli/init.js

+11-9
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ const clean = require('../utils/clean')
88
const hat = require('hat')
99
const ipfsExec = require('../utils/ipfs-exec')
1010
const os = require('os')
11+
const tempWrite = require('temp-write')
1112

1213
describe('init', function () {
13-
this.timeout(40 * 1000)
14+
this.timeout(100 * 1000)
1415

1516
let repoPath
1617
let ipfs
@@ -33,8 +34,6 @@ describe('init', function () {
3334
afterEach(() => clean(repoPath))
3435

3536
it('basic', function () {
36-
this.timeout(40 * 1000)
37-
3837
return ipfs('init').then((out) => {
3938
expect(repoDirSync('blocks')).to.have.length.above(2)
4039
expect(repoExistsSync('config')).to.equal(true)
@@ -48,8 +47,6 @@ describe('init', function () {
4847
})
4948

5049
it('bits', function () {
51-
this.timeout(40 * 1000)
52-
5350
return ipfs('init --bits 1024').then(() => {
5451
expect(repoDirSync('blocks')).to.have.length.above(2)
5552
expect(repoExistsSync('config')).to.equal(true)
@@ -58,8 +55,6 @@ describe('init', function () {
5855
})
5956

6057
it('empty', function () {
61-
this.timeout(40 * 1000)
62-
6358
return ipfs('init --bits 1024 --empty-repo true').then(() => {
6459
expect(repoDirSync('blocks')).to.have.length(2)
6560
expect(repoExistsSync('config')).to.equal(true)
@@ -68,11 +63,18 @@ describe('init', function () {
6863
})
6964

7065
it('should present ipfs path help when option help is received', function (done) {
71-
this.timeout(100 * 1000)
72-
7366
ipfs('init --help').then((res) => {
7467
expect(res).to.have.string('export IPFS_PATH=/path/to/ipfsrepo')
7568
done()
7669
})
7770
})
71+
72+
it('default config argument', () => {
73+
const configPath = tempWrite.sync('{"Addresses": {"API": "/ip4/127.0.0.1/tcp/9999"}}', 'config.json')
74+
return ipfs(`init ${configPath}`).then((res) => {
75+
const configRaw = fs.readFileSync(path.join(repoPath, 'config')).toString()
76+
const config = JSON.parse(configRaw)
77+
expect(config.Addresses.API).to.be.eq('/ip4/127.0.0.1/tcp/99999')
78+
})
79+
})
7880
})

0 commit comments

Comments
 (0)