imdone-core 1.54.10 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/cli.js +114 -0
- package/lib/index.js +23 -0
- package/package.json +48 -66
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -37
- package/.github/workflows/ci.yml +0 -24
- package/.imdoneignore +0 -12
- package/.mocharc.json +0 -10
- package/.prettierrc +0 -6
- package/CHANGELOG.md +0 -160
- package/_navbar.md +0 -1
- package/cli.js +0 -74
- package/index-markdown.js +0 -55
- package/index.html +0 -184
- package/index.js +0 -1
- package/lib/ProjectContext.js +0 -42
- package/lib/adapters/date-time.js +0 -20
- package/lib/adapters/file-gateway.js +0 -127
- package/lib/adapters/git-download.js +0 -35
- package/lib/adapters/markdown.js +0 -168
- package/lib/adapters/parsers/DateLanguageParser.js +0 -10
- package/lib/adapters/parsers/content-transformer.js +0 -111
- package/lib/adapters/parsers/file/LocalFileParserFactory.js +0 -37
- package/lib/adapters/parsers/file/ReadStreamCodeParser.js +0 -126
- package/lib/adapters/parsers/file/ReadStreamMarkdownParser.js +0 -17
- package/lib/adapters/parsers/file/ReadStreamTaskParser.js +0 -104
- package/lib/adapters/parsers/function-parser.js +0 -29
- package/lib/adapters/parsers/task/CardContentParser.js +0 -376
- package/lib/adapters/parsers/task/CheckStyleTaskParser.js +0 -28
- package/lib/adapters/parsers/task/CodeStyleTaskParser.js +0 -24
- package/lib/adapters/parsers/task/HashStyleTaskParser.js +0 -27
- package/lib/adapters/parsers/task/MarkdownStyleTaskParser.js +0 -24
- package/lib/adapters/parsers/task/TaskParser.js +0 -38
- package/lib/adapters/readers/FileSystemProjectReader.js +0 -45
- package/lib/adapters/storage/config.js +0 -49
- package/lib/adapters/storage/tags.js +0 -30
- package/lib/adapters/yaml.js +0 -6
- package/lib/card.js +0 -300
- package/lib/config.js +0 -214
- package/lib/constants.js +0 -97
- package/lib/context/ApplicationContext.js +0 -32
- package/lib/context/StreamingApplicationContext.js +0 -31
- package/lib/controlers/SaveViewController.js +0 -10
- package/lib/default-settings.js +0 -37
- package/lib/domain/entities/FileProjectContext.js +0 -10
- package/lib/domain/entities/View.js +0 -30
- package/lib/domain/usecases/GetViewsUsecase.js +0 -50
- package/lib/domain/usecases/OpenProjectUsecase.js +0 -13
- package/lib/domain/usecases/SaveViewUsecase.js +0 -57
- package/lib/file.js +0 -1395
- package/lib/languages.js +0 -114
- package/lib/list.js +0 -105
- package/lib/migrate-config.js +0 -165
- package/lib/mixins/repo-fs-store.js +0 -424
- package/lib/mixins/repo-watched-fs-store.js +0 -195
- package/lib/plugins/archive-plugin.js +0 -70
- package/lib/plugins/default-board-actions-plugin.js +0 -56
- package/lib/plugins/default-board-properties-plugin.js +0 -101
- package/lib/plugins/epic-plugin.js +0 -176
- package/lib/plugins/extension-plugin.js +0 -87
- package/lib/plugins/persist-tags-plugin.js +0 -13
- package/lib/plugins/plugin-manager.js +0 -421
- package/lib/plugins/plugin-registry.js +0 -61
- package/lib/project-factory.js +0 -45
- package/lib/project.js +0 -911
- package/lib/repository.js +0 -1746
- package/lib/task.js +0 -798
- package/lib/tools.js +0 -250
- package/lib/usecases/get-imdone-url.js +0 -6
- package/lib/usecases/get-project-tags.js +0 -16
- package/lib/usecases/get-tasks-in-file.js +0 -29
|
@@ -1,424 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
var _path = require('path'),
|
|
4
|
-
_cloneDeep = require('lodash.clonedeep'),
|
|
5
|
-
_isFunction = require('lodash.isfunction'),
|
|
6
|
-
_isUndefined = require('lodash.isundefined'),
|
|
7
|
-
_assign = require('lodash.assign'),
|
|
8
|
-
_remove = require('lodash.remove'),
|
|
9
|
-
_union = require('lodash.union'),
|
|
10
|
-
async = require('async'),
|
|
11
|
-
checksum = require('checksum'),
|
|
12
|
-
tools = require('../tools'),
|
|
13
|
-
constants = require('../constants'),
|
|
14
|
-
log = require('debug')('imdone-mixins:repo-fs-store'),
|
|
15
|
-
File = require('../file'),
|
|
16
|
-
Config = require('../config'),
|
|
17
|
-
languages = require('../languages'),
|
|
18
|
-
isBinaryFile = require('isbinaryfile'),
|
|
19
|
-
eol = require('eol'),
|
|
20
|
-
_eol = String(eol.auto),
|
|
21
|
-
readdirp = require('readdirp'),
|
|
22
|
-
_ignore = require('ignore'),
|
|
23
|
-
fastSort = require('fast-sort/dist/sort.js'),
|
|
24
|
-
Repository = require('../repository'),
|
|
25
|
-
buildMigrateConfig = require('../migrate-config'),
|
|
26
|
-
{ loadYAML, dumpYAML } = require('../adapters/yaml')
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
module.exports = mixin
|
|
30
|
-
|
|
31
|
-
const {
|
|
32
|
-
CONFIG_DIR,
|
|
33
|
-
CONFIG_FILE,
|
|
34
|
-
CONFIG_FILE_YML,
|
|
35
|
-
DEFAULT_CONFIG,
|
|
36
|
-
ASYNC_LIMIT,
|
|
37
|
-
DEFAULT_IGNORE_DIRS,
|
|
38
|
-
DEFAULT_IGNORE_EXTS,
|
|
39
|
-
IGNORE_FILE,
|
|
40
|
-
SORT_FILE,
|
|
41
|
-
ERRORS,
|
|
42
|
-
} = constants
|
|
43
|
-
|
|
44
|
-
function mixin(repo, fs = require('fs')) {
|
|
45
|
-
repo.checksum = checksum
|
|
46
|
-
repo.allFiles = []
|
|
47
|
-
|
|
48
|
-
function getIgnorePatterns() {
|
|
49
|
-
var ignoreFile = _path.join(repo.path, IGNORE_FILE)
|
|
50
|
-
let patterns = DEFAULT_IGNORE_DIRS
|
|
51
|
-
if (fs.existsSync(ignoreFile))
|
|
52
|
-
patterns = patterns + _eol + fs.readFileSync(ignoreFile).toString()
|
|
53
|
-
|
|
54
|
-
return patterns
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const IG = _ignore().add(getIgnorePatterns())
|
|
58
|
-
|
|
59
|
-
function shouldIncludeFile(entry) {
|
|
60
|
-
const { path, dirent } = entry
|
|
61
|
-
return !dirent.isSymbolicLink() && !IG.ignores(path)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function getAllFilePaths(root, cb) {
|
|
65
|
-
readdirp
|
|
66
|
-
.promise(root, {
|
|
67
|
-
lstat: true,
|
|
68
|
-
fileFilter: shouldIncludeFile,
|
|
69
|
-
})
|
|
70
|
-
.then((entries) => cb(null, entries))
|
|
71
|
-
.catch((error) => cb(error, []))
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function ls(root, cb) {
|
|
75
|
-
getAllFilePaths(root, function (error, files) {
|
|
76
|
-
if (error) {
|
|
77
|
-
console.error(`Error reading dir: ${root} `, error)
|
|
78
|
-
}
|
|
79
|
-
cb(
|
|
80
|
-
null,
|
|
81
|
-
files
|
|
82
|
-
.filter((res) => repo.shouldInclude(res.path))
|
|
83
|
-
.map((res) => res.fullPath)
|
|
84
|
-
)
|
|
85
|
-
})
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
repo.addFilePath = async function (path) {
|
|
89
|
-
var relPath = repo.getRelativePath(path)
|
|
90
|
-
var fullPath = repo.getFullPath(path)
|
|
91
|
-
|
|
92
|
-
const stat = await fs.promises.lstat(fullPath)
|
|
93
|
-
if (stat.isDirectory()) relPath += _path.sep
|
|
94
|
-
if (!repo.allFiles.includes(relPath)) {
|
|
95
|
-
repo.allFiles.push(relPath)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
repo.removeFilePath = function (path) {
|
|
100
|
-
_remove(repo.allFiles, (item) => item === path)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
repo.getFilePaths = function () {
|
|
104
|
-
return repo.allFiles
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const _init = repo.init
|
|
108
|
-
repo.migrateConfig = buildMigrateConfig(repo)
|
|
109
|
-
repo.init = function (cb) {
|
|
110
|
-
_init.call(repo, (err) => {
|
|
111
|
-
if (err && repo.destroyed) return cb(err)
|
|
112
|
-
cb = tools.cb(cb)
|
|
113
|
-
fs.stat(repo.path, function (err, stat) {
|
|
114
|
-
if (err || !stat.isDirectory()) {
|
|
115
|
-
var error = new Error(
|
|
116
|
-
`Path must be an existing directory on the file system: ${repo.path}`
|
|
117
|
-
)
|
|
118
|
-
repo.emit('error', error)
|
|
119
|
-
return cb(error)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
repo.loadConfig((err) => {
|
|
123
|
-
if (err) {
|
|
124
|
-
repo.emit('error', err)
|
|
125
|
-
return cb(err)
|
|
126
|
-
}
|
|
127
|
-
repo.migrateConfig()
|
|
128
|
-
repo.saveConfig()
|
|
129
|
-
repo.emit('config.loaded')
|
|
130
|
-
repo.createListeners()
|
|
131
|
-
repo.readFiles((err, files) => {
|
|
132
|
-
if (err && repo.destroyed) return cb(err)
|
|
133
|
-
repo.emit('initialized', { ok: true, lists: repo.getTasksByList() })
|
|
134
|
-
cb(err, files)
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
})
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
repo.loadIgnore = function () {
|
|
142
|
-
const patterns = getIgnorePatterns() + _eol + DEFAULT_IGNORE_EXTS
|
|
143
|
-
repo.setIgnores(patterns)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
repo.fileOK = function (file, includeDirs, cb) {
|
|
147
|
-
if (File.isFile(file)) file = file.path
|
|
148
|
-
if (_isFunction(includeDirs)) {
|
|
149
|
-
cb = includeDirs
|
|
150
|
-
includeDirs = false
|
|
151
|
-
}
|
|
152
|
-
cb = tools.cb(cb)
|
|
153
|
-
try {
|
|
154
|
-
if (!file || !this.shouldInclude(file)) return cb(null, false)
|
|
155
|
-
} catch (e) {
|
|
156
|
-
cb(e)
|
|
157
|
-
}
|
|
158
|
-
var fullPath = repo.getFullPath(file)
|
|
159
|
-
fs.lstat(fullPath, function (err, stat) {
|
|
160
|
-
if (err) {
|
|
161
|
-
console.log(err)
|
|
162
|
-
return cb(null, false)
|
|
163
|
-
}
|
|
164
|
-
if (/\.\.(\/|\\)/.test(file) || (!includeDirs && stat.isDirectory()))
|
|
165
|
-
return cb(null, false)
|
|
166
|
-
if (stat.isFile()) {
|
|
167
|
-
isBinaryFile(fullPath, function (err, result) {
|
|
168
|
-
if (err || result) return cb(null, false)
|
|
169
|
-
cb(null, stat)
|
|
170
|
-
})
|
|
171
|
-
} else if (includeDirs && stat.isDirectory()) {
|
|
172
|
-
cb(null, stat)
|
|
173
|
-
} else cb(null, false)
|
|
174
|
-
})
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
repo.saveSort = function (sort, cb) {
|
|
178
|
-
cb = tools.cb(cb)
|
|
179
|
-
fs.writeFile(repo.getFullPath(SORT_FILE), JSON.stringify(sort), cb)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
repo.readSort = function (cb) {
|
|
183
|
-
fs.readFile(repo.getFullPath(SORT_FILE), (err, data) => {
|
|
184
|
-
if (err) return cb(err)
|
|
185
|
-
repo.sort = JSON.parse(data)
|
|
186
|
-
cb(null, repo.sort)
|
|
187
|
-
})
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
repo.saveConfig = function (cb) {
|
|
191
|
-
repo.savingConfig = true
|
|
192
|
-
cb = tools.cb(cb)
|
|
193
|
-
var _cb = function (err, resp) {
|
|
194
|
-
repo.savingConfig = false
|
|
195
|
-
cb(err, resp)
|
|
196
|
-
}
|
|
197
|
-
var dir = repo.getFullPath(CONFIG_DIR)
|
|
198
|
-
var file = repo.getFullPath(CONFIG_FILE_YML)
|
|
199
|
-
fs.exists(dir, function (exists) {
|
|
200
|
-
const data = { ...repo.getConfig() }
|
|
201
|
-
delete data.cardActionsFunction
|
|
202
|
-
delete data.boardActionsFunction
|
|
203
|
-
delete data.cardPropertiesFunction
|
|
204
|
-
delete data.path
|
|
205
|
-
if (data.lists) data.lists.forEach((list) => delete list.tasks)
|
|
206
|
-
var yaml = dumpYAML(data)
|
|
207
|
-
if (exists) {
|
|
208
|
-
fs.writeFile(file, yaml, _cb)
|
|
209
|
-
} else {
|
|
210
|
-
fs.mkdir(dir, function (err) {
|
|
211
|
-
if (err) return _cb(err)
|
|
212
|
-
fs.writeFile(file, yaml, _cb)
|
|
213
|
-
})
|
|
214
|
-
}
|
|
215
|
-
})
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
repo.updateConfig = function (loadedConfig, cb) {
|
|
219
|
-
var baseConfig = _cloneDeep(DEFAULT_CONFIG)
|
|
220
|
-
var include_lists = baseConfig.code.include_lists
|
|
221
|
-
const currentConfig = repo.config
|
|
222
|
-
if (currentConfig && currentConfig.code)
|
|
223
|
-
include_lists = _union(include_lists, currentConfig.code.include_lists)
|
|
224
|
-
|
|
225
|
-
if (currentConfig && currentConfig.settings)
|
|
226
|
-
loadedConfig.settings = {...currentConfig.settings, ...loadedConfig.settings}
|
|
227
|
-
|
|
228
|
-
if (loadedConfig && loadedConfig.code)
|
|
229
|
-
include_lists = _union(include_lists, loadedConfig.code.include_lists)
|
|
230
|
-
|
|
231
|
-
const newConfig = new Config(
|
|
232
|
-
_assign({}, baseConfig, repo.config, loadedConfig, { path: repo.path })
|
|
233
|
-
)
|
|
234
|
-
|
|
235
|
-
repo.migrateTasksByConfig(currentConfig, newConfig, (err) => {
|
|
236
|
-
if (err) return cb(err)
|
|
237
|
-
repo.config = newConfig
|
|
238
|
-
repo.config.code.include_lists = include_lists
|
|
239
|
-
var _languages = _cloneDeep(languages)
|
|
240
|
-
repo.languages = repo.config.languages
|
|
241
|
-
? _assign(_languages, repo.config.languages)
|
|
242
|
-
: _languages
|
|
243
|
-
cb(null, repo.config)
|
|
244
|
-
})
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
repo.loadConfig = function (cb) {
|
|
248
|
-
// BACKLOG If a config is bad move it to config.json.bak and save a new one with defaults gh:2 id:9 +enhancement +standup +chore
|
|
249
|
-
// <!--
|
|
250
|
-
// order:-670
|
|
251
|
-
// -->
|
|
252
|
-
cb = tools.cb(cb)
|
|
253
|
-
repo.loadIgnore()
|
|
254
|
-
// new
|
|
255
|
-
const configData = (!repo.config || repo.config.dirty) ? this.getYamlConfig() : repo.config || {}
|
|
256
|
-
repo.updateConfig(configData, cb)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
repo.getConfigFile = function () {
|
|
260
|
-
return repo.getFullPath(CONFIG_FILE)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
repo.getYamlConfig = function () {
|
|
264
|
-
const filePath = repo.getFullPath(CONFIG_FILE_YML)
|
|
265
|
-
if (!fs.existsSync(filePath)) return
|
|
266
|
-
const configData = fs.readFileSync(filePath, 'utf-8')
|
|
267
|
-
let configLike = {}
|
|
268
|
-
try {
|
|
269
|
-
configLike = loadYAML(configData.toString())
|
|
270
|
-
} catch (e) {
|
|
271
|
-
/* noop */
|
|
272
|
-
}
|
|
273
|
-
return configLike
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
var _deleteTasks = repo.deleteTasks
|
|
277
|
-
repo.deleteTasks = function (tasks, cb) {
|
|
278
|
-
_deleteTasks.call(repo, tasks, function (err) {
|
|
279
|
-
if (err) return cb(err)
|
|
280
|
-
repo.emit('tasks.updated', tasks)
|
|
281
|
-
cb()
|
|
282
|
-
})
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
repo.writeFile = function (file, emitFileUpdate, cb) {
|
|
286
|
-
if (_isFunction(emitFileUpdate)) {
|
|
287
|
-
cb = emitFileUpdate
|
|
288
|
-
emitFileUpdate = false
|
|
289
|
-
}
|
|
290
|
-
cb = tools.cb(cb)
|
|
291
|
-
|
|
292
|
-
if (!File.isFile(file)) return cb(new Error(ERRORS.NOT_A_FILE))
|
|
293
|
-
if (file.deleted) return cb(null, file)
|
|
294
|
-
|
|
295
|
-
var filePath = repo.getFullPath(file)
|
|
296
|
-
|
|
297
|
-
if (!/\.\.(\/|\\)/.test(file.path)) {
|
|
298
|
-
var write = function () {
|
|
299
|
-
var oldChecksum = file.checksum
|
|
300
|
-
file.checksum = checksum(file.getContentForFile())
|
|
301
|
-
fs.writeFile(
|
|
302
|
-
filePath,
|
|
303
|
-
file.getContentForFile(),
|
|
304
|
-
'utf8',
|
|
305
|
-
function (err) {
|
|
306
|
-
if (err) {
|
|
307
|
-
file.checksum = oldChecksum
|
|
308
|
-
return cb([new Error('Unable to write file:' + filePath), err])
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
fs.stat(filePath, function (err, stats) {
|
|
312
|
-
if (err)
|
|
313
|
-
return cb([new Error('Unable to stat file:' + filePath), err])
|
|
314
|
-
|
|
315
|
-
file.setModifiedTime(stats.mtime)
|
|
316
|
-
file.modified = false
|
|
317
|
-
repo.addFilePath(filePath)
|
|
318
|
-
if (emitFileUpdate) repo.emit('file.saved', file)
|
|
319
|
-
cb(null, file)
|
|
320
|
-
})
|
|
321
|
-
}
|
|
322
|
-
)
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
var dirName = _path.dirname(filePath)
|
|
326
|
-
if (fs.existsSync(dirName)) {
|
|
327
|
-
return write()
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
tools.mkdirp(fs, dirName, function (err) {
|
|
331
|
-
if (err) return cb(err)
|
|
332
|
-
write()
|
|
333
|
-
})
|
|
334
|
-
} else return cb(new Error('Unable to write file:' + file.path), file)
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
repo.getFilesInPath = function (includeDirs, cb) {
|
|
338
|
-
cb = tools.cb(cb)
|
|
339
|
-
ls(repo.path, function (err, allPaths) {
|
|
340
|
-
if (err) return cb(err)
|
|
341
|
-
var files = [],
|
|
342
|
-
processed = 0
|
|
343
|
-
log('allPaths=', allPaths)
|
|
344
|
-
if (allPaths.length === 0) return cb(null, [])
|
|
345
|
-
async.eachLimit(
|
|
346
|
-
allPaths,
|
|
347
|
-
ASYNC_LIMIT,
|
|
348
|
-
function (path, _cb) {
|
|
349
|
-
if (!path) return _cb()
|
|
350
|
-
path = repo.getRelativePath(path)
|
|
351
|
-
repo.fileOK(path, includeDirs, function (err, stat) {
|
|
352
|
-
// stack-3 repo-fs-store.js:250:14
|
|
353
|
-
processed++
|
|
354
|
-
if (err) return _cb(err)
|
|
355
|
-
repo.emit('file.processed', {
|
|
356
|
-
file: path,
|
|
357
|
-
ok: stat !== false,
|
|
358
|
-
total: allPaths.length,
|
|
359
|
-
processed: processed + 1,
|
|
360
|
-
repoId: repo.getId(),
|
|
361
|
-
})
|
|
362
|
-
|
|
363
|
-
if (stat) {
|
|
364
|
-
log('%s is ok %j', path, stat)
|
|
365
|
-
var file = new File({
|
|
366
|
-
repoId: repo.getId(),
|
|
367
|
-
filePath: path,
|
|
368
|
-
modifiedTime: stat.mtime,
|
|
369
|
-
createdTime: stat.birthtime,
|
|
370
|
-
languages: repo.languages,
|
|
371
|
-
project: repo.project,
|
|
372
|
-
})
|
|
373
|
-
file.isDir = stat.isDirectory()
|
|
374
|
-
files.push(file)
|
|
375
|
-
}
|
|
376
|
-
log('err=%j', err, null)
|
|
377
|
-
log('stat=%j', stat, null)
|
|
378
|
-
log('processed=%d allPaths.length=%d', processed, allPaths.length)
|
|
379
|
-
_cb() // stack-1 repo-fs-store.js:270:11
|
|
380
|
-
})
|
|
381
|
-
},
|
|
382
|
-
function (err) {
|
|
383
|
-
cb(err, fastSort(files).asc(u => u.path))
|
|
384
|
-
}
|
|
385
|
-
)
|
|
386
|
-
})
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
repo.readFileContent = function (file, cb) {
|
|
390
|
-
cb = tools.cb(cb)
|
|
391
|
-
if (!File.isFile(file)) return cb(new Error(ERRORS.NOT_A_FILE))
|
|
392
|
-
var filePath = repo.getFullPath(file)
|
|
393
|
-
|
|
394
|
-
fs.lstat(filePath, function (err, stats) {
|
|
395
|
-
if (err) return cb([new Error('Unable to stat file:' + filePath), err])
|
|
396
|
-
if (!stats.isFile()) return cb(null, file)
|
|
397
|
-
fs.readFile(filePath, 'utf8', function (err, data) {
|
|
398
|
-
if (err) return cb([new Error('Unable to read file:' + filePath), err])
|
|
399
|
-
|
|
400
|
-
file
|
|
401
|
-
.setContentFromFile(data)
|
|
402
|
-
.setModifiedTime(stats.mtime)
|
|
403
|
-
.setCreatedTime(stats.birthtime)
|
|
404
|
-
|
|
405
|
-
file.lineCount = eol.split(data).length
|
|
406
|
-
cb(null, file)
|
|
407
|
-
})
|
|
408
|
-
})
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
repo.deleteFile = function (path, cb) {
|
|
412
|
-
cb = tools.cb(cb)
|
|
413
|
-
var file = File.isFile(path) ? path : repo.getFile(path)
|
|
414
|
-
if (!_isUndefined(file)) {
|
|
415
|
-
fs.unlink(repo.getFullPath(file), function (err) {
|
|
416
|
-
if (err) return cb('Unable to delete:' + path + ' : ' + err.toString())
|
|
417
|
-
repo.removeFile(file)
|
|
418
|
-
cb(null, file)
|
|
419
|
-
})
|
|
420
|
-
} else cb('Unable to delete:' + path)
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
return repo
|
|
424
|
-
}
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
var fsStore = require('./repo-fs-store'),
|
|
4
|
-
log = require('debug')('imdone-mixins:repo-watched-fs-store'),
|
|
5
|
-
File = require('../file'),
|
|
6
|
-
constants = require('../constants'),
|
|
7
|
-
sane = require('sane')
|
|
8
|
-
|
|
9
|
-
module.exports = mixin
|
|
10
|
-
|
|
11
|
-
// BACKLOG Only emit file.update if the file checksum has changed
|
|
12
|
-
// <!--
|
|
13
|
-
// order:-650
|
|
14
|
-
// -->
|
|
15
|
-
function mixin(repo, fs = require('fs')) {
|
|
16
|
-
repo = fsStore(repo, fs)
|
|
17
|
-
var _refresh = repo.refresh
|
|
18
|
-
var _destroy = repo.destroy
|
|
19
|
-
var _init = repo.init
|
|
20
|
-
var initializing = false
|
|
21
|
-
|
|
22
|
-
repo.init = function (cb) {
|
|
23
|
-
if (initializing) {
|
|
24
|
-
const err = new Error("Can't initialize repo while it's initializing.")
|
|
25
|
-
console.error(err.message)
|
|
26
|
-
return cb ? cb(err) : null
|
|
27
|
-
}
|
|
28
|
-
log('Initializing repo:', repo.path)
|
|
29
|
-
initializing = true
|
|
30
|
-
_init.call(repo, function (err, files) {
|
|
31
|
-
if (err) {
|
|
32
|
-
console.error(`Error initializing repo: ${err.message}`)
|
|
33
|
-
initializing = false
|
|
34
|
-
return cb ? cb(err) : null
|
|
35
|
-
}
|
|
36
|
-
repo.initWatcher(() => {
|
|
37
|
-
initializing = false
|
|
38
|
-
if (cb) cb(err, files)
|
|
39
|
-
})
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
repo.destroy = function () {
|
|
44
|
-
if (repo.watcher) repo.watcher.close()
|
|
45
|
-
_destroy.apply(repo)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
repo.refresh = function (cb) {
|
|
49
|
-
if (initializing) {
|
|
50
|
-
return cb ? cb('already initializing') : null
|
|
51
|
-
}
|
|
52
|
-
console.info('Initializing repo:', repo.path)
|
|
53
|
-
initializing = true
|
|
54
|
-
if (repo.watcher) repo.watcher.close()
|
|
55
|
-
_refresh.call(repo, function (err, files) {
|
|
56
|
-
if (err) {
|
|
57
|
-
initializing = false
|
|
58
|
-
return cb ? cb(err) : null
|
|
59
|
-
}
|
|
60
|
-
repo.initWatcher(() => {
|
|
61
|
-
initializing = false
|
|
62
|
-
return cb ? cb(err, files) : null
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
var _isImdoneConfig = function (path) {
|
|
68
|
-
return path === constants.CONFIG_FILE_YML
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
var _isImdoneIgnore = function (path) {
|
|
72
|
-
return path === constants.IGNORE_FILE
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const onConfigChange = function (file) {
|
|
76
|
-
console.info('Loading config. Observed a change to:', file)
|
|
77
|
-
const label = `Refresh repo: ${repo.path}`
|
|
78
|
-
console.time(label)
|
|
79
|
-
repo.refresh((err, files) => {
|
|
80
|
-
if (err) console.error('Error refreshing repo', err)
|
|
81
|
-
console.timeEnd(label)
|
|
82
|
-
repo.emitConfigUpdate(file, repo.config)
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const onIgnoreChange = onConfigChange
|
|
87
|
-
|
|
88
|
-
repo.initWatcher = function (cb) {
|
|
89
|
-
console.log('initializing watcher for:', repo.path)
|
|
90
|
-
repo.watcher = sane(repo.path, {
|
|
91
|
-
dot: true,
|
|
92
|
-
ignored(file) {
|
|
93
|
-
if (!initializing && _isImdoneConfig(file)) {
|
|
94
|
-
onConfigChange(file)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (!initializing && _isImdoneIgnore(file)) {
|
|
98
|
-
onIgnoreChange(file)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const ignore = !repo.shouldInclude(file)
|
|
102
|
-
if (!ignore || /^.*\.(jpg|gif|pdf|png)$/i.test(file)) {
|
|
103
|
-
repo.addFilePath(file)
|
|
104
|
-
}
|
|
105
|
-
return ignore
|
|
106
|
-
},
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
repo.watcher
|
|
110
|
-
.on('error', (err) => {
|
|
111
|
-
console.error('Error in watcher')
|
|
112
|
-
console.error(err)
|
|
113
|
-
cb(err)
|
|
114
|
-
})
|
|
115
|
-
.on('ready', () => {
|
|
116
|
-
console.log('watcher ready for:', repo.path)
|
|
117
|
-
initializing = false
|
|
118
|
-
cb()
|
|
119
|
-
})
|
|
120
|
-
.on('add', function (path, root, stat) {
|
|
121
|
-
console.log('Watcher received add event for file: ' + path)
|
|
122
|
-
if (stat.isDirectory()) return
|
|
123
|
-
var file = repo.getFile(path)
|
|
124
|
-
if (file === undefined) {
|
|
125
|
-
log('Creating file: ' + path)
|
|
126
|
-
file = new File({
|
|
127
|
-
repoId: repo.getId(),
|
|
128
|
-
filePath: path,
|
|
129
|
-
languages: repo.languages,
|
|
130
|
-
project: repo.project,
|
|
131
|
-
})
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
repo.fileOK(file, function (err, stat) {
|
|
135
|
-
log('fileOK returned: ' + JSON.stringify(stat))
|
|
136
|
-
if (err || !stat) return
|
|
137
|
-
if (stat.mtime <= file.getModifiedTime()) {
|
|
138
|
-
return log('File update already applied. Change ignored for file: ' + path)
|
|
139
|
-
}
|
|
140
|
-
log('Reading file: ' + path)
|
|
141
|
-
repo.readFile(file, function (err, file) {
|
|
142
|
-
repo.emitFileUpdate(file)
|
|
143
|
-
})
|
|
144
|
-
})
|
|
145
|
-
})
|
|
146
|
-
.on('change', function (path, root, stat) {
|
|
147
|
-
console.log(
|
|
148
|
-
`Watcher received change event for file: ${path} repoPath: ${repo.path}`,
|
|
149
|
-
stat.mtime
|
|
150
|
-
)
|
|
151
|
-
if (!path || stat.isDirectory()) return
|
|
152
|
-
var file = repo.getFile(path) || path
|
|
153
|
-
const isFile = File.isFile(file)
|
|
154
|
-
// BACKLOG ## Handle the case where the file is not in the repo
|
|
155
|
-
// #urgent #1.12.0
|
|
156
|
-
// <!--
|
|
157
|
-
// order:-660
|
|
158
|
-
// -->
|
|
159
|
-
if (isFile && stat.mtime <= file.getModifiedTime()) {
|
|
160
|
-
// console.log("File update already applied. Change ignored.")
|
|
161
|
-
return
|
|
162
|
-
}
|
|
163
|
-
if (_isImdoneConfig(path)) return onConfigChange(path)
|
|
164
|
-
if (_isImdoneIgnore(path)) return onIgnoreChange(path)
|
|
165
|
-
|
|
166
|
-
repo.fileOK((file && file.path) || path, function (err, ok) {
|
|
167
|
-
if (err) {
|
|
168
|
-
console.error('Error processing ignore on path: ', path, err)
|
|
169
|
-
return
|
|
170
|
-
}
|
|
171
|
-
if (!ok) return
|
|
172
|
-
log('Reading file: ' + path)
|
|
173
|
-
if (!isFile) file = repo.getFile(path)
|
|
174
|
-
repo.readFile(file, function (err, file) {
|
|
175
|
-
repo.emitFileUpdate(file)
|
|
176
|
-
})
|
|
177
|
-
})
|
|
178
|
-
})
|
|
179
|
-
.on('delete', function (path) {
|
|
180
|
-
log('Watcher received unlink event for file: ' + path)
|
|
181
|
-
repo.removeFilePath(path)
|
|
182
|
-
var file = new File({
|
|
183
|
-
repoId: repo.getId(),
|
|
184
|
-
filePath: path,
|
|
185
|
-
languages: repo.languages,
|
|
186
|
-
project: repo.project,
|
|
187
|
-
})
|
|
188
|
-
log('Removing file: ' + path)
|
|
189
|
-
repo.removeFile(file)
|
|
190
|
-
repo.emitFileUpdate(file, true)
|
|
191
|
-
})
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return repo
|
|
195
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
const Plugin = require('imdone-api')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const { getRawTask } = require('../adapters/parsers/task/CardContentParser')
|
|
4
|
-
|
|
5
|
-
module.exports = class ArchivePlugin extends Plugin {
|
|
6
|
-
constructor(project) {
|
|
7
|
-
super(project)
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
get config() {
|
|
11
|
-
return this.project.config
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
get fileGateway() {
|
|
15
|
-
return this.project.fileGateway
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
async onBeforeBoardUpdate() {
|
|
19
|
-
const config = this.config
|
|
20
|
-
if (!config || !config.archiveCompleted || this.archivingTasks) return
|
|
21
|
-
this.archivingTasks = true
|
|
22
|
-
const cards = this.project.getAllCards(`meta.archived != "true" and list = ${config.doneList}`)
|
|
23
|
-
const messageUser = cards.length > 1
|
|
24
|
-
|
|
25
|
-
if (!cards.length) {
|
|
26
|
-
this.archivingTasks = false
|
|
27
|
-
return
|
|
28
|
-
} else {
|
|
29
|
-
if (messageUser) this.project.snackBar({message: `Archiving ${cards.length} card(s)...`})
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
cards.forEach(card => this.archiveTask(card))
|
|
33
|
-
|
|
34
|
-
if (messageUser) this.project.snackBar({message: ` Done archiving ${cards.length} card(s). Deleting original(s)...`})
|
|
35
|
-
await this.project.deleteTasks(cards)
|
|
36
|
-
|
|
37
|
-
this.archivingTasks = false
|
|
38
|
-
if (messageUser) this.project.snackBar({message: `Done deleting original card(s).`})
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
archiveTask (task, config = this.config) {
|
|
43
|
-
const archiveFolder = config.archiveFolder
|
|
44
|
-
const fileDir = path.dirname(task.relPath)
|
|
45
|
-
|
|
46
|
-
if (fileDir.startsWith(archiveFolder)) return
|
|
47
|
-
|
|
48
|
-
const fileName = this.fileGateway.sanitizeFileName(`${task.text}.md`, config.replaceSpacesWith)
|
|
49
|
-
const newPath = path.join(this.project.path, archiveFolder, fileDir, fileName)
|
|
50
|
-
|
|
51
|
-
const content = this.project.addMetaToContent(
|
|
52
|
-
[
|
|
53
|
-
{ key: 'archived', value: 'true'},
|
|
54
|
-
{ key: 'archivedAt', value: this.project.isoDateWithOffset },
|
|
55
|
-
{ key: 'originalPath', value: task.relPath },
|
|
56
|
-
{ key: 'originalLine', value: task.line }
|
|
57
|
-
],
|
|
58
|
-
task.content
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
const { tokenPrefix } = config
|
|
62
|
-
const { beforeText, list } = task
|
|
63
|
-
const taskStart = getRawTask({tokenPrefix, beforeText, list, text: ''})
|
|
64
|
-
const taskContent = `${taskStart} ${content}\n\n\n`
|
|
65
|
-
|
|
66
|
-
this.fileGateway.preparePathForWriting(newPath)
|
|
67
|
-
this.fileGateway.appendFileSync(newPath, taskContent)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
}
|