git ssb

39+

cel / git-ssb



Tree: 28bf61d928af584e5e33b424fc41deafa9dddb77

Files: 28bf61d928af584e5e33b424fc41deafa9dddb77 / lib / util.js

6998 bytesRaw
1var path = require('path')
2var ssbRef = require('ssb-ref')
3var proc = require('child_process')
4var u = exports
5
6u.help = function (cmd) {
7 require('./help').fn({_: [cmd]})
8}
9
10u.getAppName = function () {
11 return 'ssb_appname' in process.env ? process.env.ssb_appname :
12 u.gitSync('config', 'ssb.appname')
13}
14
15u.gitSync = function () {
16 var args = [].concat.apply([], arguments)
17 return proc.spawnSync('git', args, {encoding: 'utf8'}).stdout.trim()
18}
19
20u.getCurrentBranch = function () {
21 return u.gitSync('symbolic-ref', '--short', 'HEAD')
22}
23
24function getRemoteUrl(name) {
25 if (!name) return null
26 return u.gitSync('ls-remote', '--get-url', name)
27}
28
29function repoId(id) {
30 if (!id) return null
31 id = String(id).replace(/^ssb:\/*/, '')
32 return ssbRef.isMsg(id) || /^#[^\s#]{1,29}$/.test(id) ? id : null
33}
34
35u.getRemote = function (name) {
36 return name
37 ? repoId(name) || repoId(getRemoteUrl(name))
38 : repoId(getRemoteUrl('origin')) || repoId(getRemoteUrl('ssb'))
39}
40
41function fork(before, after) {
42 return function () {
43 before.apply(this, arguments)
44 after.apply(this, arguments)
45 }
46}
47
48u.getSbot = function (config, cb) {
49 var keys = require('ssb-keys')
50 .loadOrCreateSync(path.join(config.path, 'secret'))
51 require('ssb-client')(keys, config, function (err, sbot) {
52 if (err) return cb(err)
53 var keepalive = setInterval(sbot.whoami, 15e3)
54 sbot.close = fork(sbot.close, function () {
55 clearInterval(keepalive)
56 })
57 cb(null, sbot)
58 })
59}
60
61u.gitDir = function () {
62 return u.gitSync('rev-parse', '-q', '--git-dir')
63}
64
65u.gitError = function (stderr) {
66 var err = stderr.toString().trim()
67 if (!/^fatal/.test(err)) err = new Error(err)
68 return err
69}
70
71u.editor = function (name, defaultText, useText, cb) {
72 var fs = require('fs')
73 var filename = path.resolve(u.gitDir(), name + '_EDITMSG')
74
75 // prepare the file for editing
76 var separator = '=== This line and anything below will be removed ==='
77 var text = fs.existsSync(filename) ?
78 fs.readFileSync(filename, 'utf8').split(separator)[0].trim() : ''
79 text += '\n\n' + separator + '\n' + defaultText
80 fs.writeFileSync(filename, text)
81
82 // edit the file
83 var editor = u.gitSync('var', 'GIT_EDITOR')
84 var args = [filename]
85 // give vim special formats, like hub(1) does
86 if (/[ng]?vim?$/.test(editor))
87 args.unshift('-c', '"set ft=markdown tw=0 wrap lbr"')
88 var child = proc.spawn(editor, args, {shell: true, stdio: 'inherit'})
89 child.on('exit', function (code) {
90 if (code) return cb('error using text editor')
91 fs.readFile(filename, 'utf8', function (err, text) {
92 if (err) return cb(err)
93 // use the data
94 useText(text.split(separator)[0].trim(), function (err) {
95 if (err) return cb(err)
96 // delete the file after succesful read
97 fs.unlink(filename, cb)
98 })
99 })
100 })
101}
102
103// Get a name for a thing from multiple fallback sources
104u.getName = function (sbot, sources, dest, cb) {
105 var pull = require('pull-stream')
106 var cat = require('pull-cat')
107 var name
108 pull(
109 cat(sources.map(function (source) {
110 return sbot.links({
111 source: source, dest: dest, rel: 'about',
112 values: true, keys: false, meta: false,
113 reverse: true
114 })
115 })),
116 pull.drain(function (value) {
117 name = value && value.content && value.content.name
118 if (name) return false
119 }, function (err) {
120 cb(err === true ? null : err, name)
121 })
122 )
123}
124
125u.formatTitle = function (str, len) {
126 str = String(str).replace(/[\n\r\t ]+/g, ' ')
127 if (str.length > len) str = str.substr(0, len) + '…'
128 return str
129}
130
131u.issueStateBool = function (argv) {
132 return argv.all || (argv.open && argv.closed) ? null :
133 argv.open ? true :
134 argv.closed ? false :
135 true
136}
137
138u.getForks = function(sbot, baseMsg, eachFork) {
139 var cat = require('pull-cat')
140 var pull = require('pull-stream')
141 if (baseMsg.key[0] === '#') return pull.once(baseMsg)
142 return cat([
143 pull.once(baseMsg),
144 pull(
145 sbot.links({
146 dest: baseMsg.key,
147 rel: 'upstream',
148 values: true
149 }),
150 pull.map(function (msg) {
151 if (eachFork) eachFork(msg, baseMsg)
152 return u.getForks(sbot, msg, eachFork)
153 }),
154 pull.flatten()
155 )
156 ])
157}
158
159function formatRecps(r) {
160 switch (typeof r) {
161 case 'object': return r
162 case 'string': return r.split(',')
163 default: return []
164 }
165}
166
167u.getRecps = function (sbot, argv, cb) {
168 if (!argv.recps && !argv.private) return cb()
169 sbot.whoami(function (err, feed) {
170 if (err) return cb(err)
171 var recps = [feed.id]
172 var recpsArr = formatRecps(argv.recps)
173 for (var i = 0; i in recpsArr; i++) {
174 var recp = recpsArr[i]
175 if (!recp || ~recps.indexOf(recp)) continue
176 if (!ssbRef.isFeed(recp)) return cb(new Error('Invalid feed: ' + recp))
177 recps.push(recp)
178 }
179 cb(null, recps)
180 })
181}
182
183u.getMsg = function (sbot, id, cb) {
184 sbot.get(id, function (err, value) {
185 if (err) return cb(new Error(err.stack || err))
186 cb(null, {key: id, value: value})
187 })
188}
189
190u.publishToSameRecps = function (sbot, rootId, value, cb) {
191 sbot.get(rootId, function (err, rootValue) {
192 if (err) return cb(err)
193 if (typeof rootValue.content === 'string') {
194 sbot.private.unbox(rootValue.content, function (err, rootContent) {
195 if (err) return cb(err)
196 if (!rootContent) return cb(new Error('unable to decrypt'))
197 var recps = rootContent.recps || [rootValue.author]
198 value.recps = recps
199 if (process.env.DRY_RUN) throw JSON.stringify(value, 0, 2)
200 sbot.private.publish(value, recps, cb)
201 })
202 } else {
203 if (process.env.DRY_RUN) throw JSON.stringify(value, 0, 2)
204 sbot.publish(value, cb)
205 }
206 })
207}
208
209u.unbox = function (sbot, msg, cb) {
210 if (msg && msg.value && typeof msg.value.content === 'string') {
211 sbot.private.unbox(msg.value.content, function (err, content) {
212 if (content) msg.value.content = content
213 msg.value.private = true
214 cb(null, msg)
215 })
216 } else {
217 cb(null, msg)
218 }
219}
220
221u.unboxMessages = function (sbot) {
222 return u.unbox.bind(this, sbot)
223}
224
225u.gitUpdates = function (sbot, repoId) {
226 var pull = require('pull-stream')
227 var paramap = require('pull-paramap')
228
229 if (!repoId) return pull.empty()
230
231 if (sbot.backlinks) return pull(
232 sbot.backlinks.read({
233 reverse: true,
234 query: [{$filter: {
235 dest: repoId,
236 value: {
237 content: {
238 type: 'git-update',
239 repo: repoId
240 }
241 }
242 }}]
243 }),
244 paramap(u.unboxMessages(sbot), 4)
245 )
246
247 if (repoId[0] === '#') return pull.error(new Error(
248 'The ssb-backlinks plugin is required to use channel repos'))
249
250 return pull(
251 sbot.links({
252 dest: repoId,
253 rel: 'repo',
254 values: true,
255 meta: false,
256 reverse: true,
257 }),
258 paramap(u.unboxMessages(sbot), 4),
259 pull.filter(function (msg) {
260 var c = msg.value.content
261 return c.type === 'git-update'
262 })
263 )
264}
265

Built with git-ssb-web