gitsheets 0.22.4 → 1.0.3
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/LICENSE +201 -0
- package/README.md +21 -0
- package/bin/gitsheets +5 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +256 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/errors.d.ts +72 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +74 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/patch.d.ts +2 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +39 -0
- package/dist/patch.js.map +1 -0
- package/dist/path-template/index.d.ts +42 -0
- package/dist/path-template/index.d.ts.map +1 -0
- package/dist/path-template/index.js +288 -0
- package/dist/path-template/index.js.map +1 -0
- package/dist/push-daemon.d.ts +53 -0
- package/dist/push-daemon.d.ts.map +1 -0
- package/dist/push-daemon.js +148 -0
- package/dist/push-daemon.js.map +1 -0
- package/dist/repository.d.ts +67 -0
- package/dist/repository.d.ts.map +1 -0
- package/dist/repository.js +322 -0
- package/dist/repository.js.map +1 -0
- package/dist/sheet.d.ts +107 -0
- package/dist/sheet.d.ts.map +1 -0
- package/dist/sheet.js +605 -0
- package/dist/sheet.js.map +1 -0
- package/dist/store.d.ts +41 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +49 -0
- package/dist/store.js.map +1 -0
- package/dist/toml.d.ts +11 -0
- package/dist/toml.d.ts.map +1 -0
- package/dist/toml.js +28 -0
- package/dist/toml.js.map +1 -0
- package/dist/transaction.d.ts +96 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +227 -0
- package/dist/transaction.js.map +1 -0
- package/dist/validation.d.ts +37 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +105 -0
- package/dist/validation.js.map +1 -0
- package/package.json +41 -35
- package/bin/cli.js +0 -61
- package/commands/edit.js +0 -90
- package/commands/normalize.js +0 -81
- package/commands/query.js +0 -206
- package/commands/read.js +0 -64
- package/commands/singer-target.js +0 -214
- package/commands/upsert.js +0 -260
- package/lib/GitSheets.js +0 -464
- package/lib/Repository.js +0 -88
- package/lib/Sheet.js +0 -625
- package/lib/errors.js +0 -21
- package/lib/hologit.js +0 -1
- package/lib/logger.js +0 -18
- package/lib/path/BaseComponent.js +0 -24
- package/lib/path/ExpressionComponent.js +0 -26
- package/lib/path/FieldComponent.js +0 -13
- package/lib/path/LiteralComponent.js +0 -12
- package/lib/path/Query.js +0 -18
- package/lib/path/Template.js +0 -214
- package/server.js +0 -120
package/lib/GitSheets.js
DELETED
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
const { Repo, BlobObject } = require('hologit/lib');
|
|
2
|
-
const { Readable } = require('stream');
|
|
3
|
-
const TOML = require('@iarna/toml');
|
|
4
|
-
const maxstache = require('maxstache');
|
|
5
|
-
const jsonpatch = require('fast-json-patch');
|
|
6
|
-
const csvParser = require('csv-parser');
|
|
7
|
-
|
|
8
|
-
const {
|
|
9
|
-
SerializationError,
|
|
10
|
-
ConfigError,
|
|
11
|
-
InvalidRefError,
|
|
12
|
-
MergeError,
|
|
13
|
-
} = require('./errors')
|
|
14
|
-
|
|
15
|
-
const DIFF_PATTERN = /([A-Z])\d*\t(\S+)\t?(\S*)/;
|
|
16
|
-
const diffStatusMap = {
|
|
17
|
-
A: 'added',
|
|
18
|
-
D: 'deleted',
|
|
19
|
-
M: 'modified',
|
|
20
|
-
R: 'renamed',
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @class
|
|
25
|
-
*/
|
|
26
|
-
module.exports = class GitSheets {
|
|
27
|
-
static async create(gitDir = null) {
|
|
28
|
-
const repo = (gitDir)
|
|
29
|
-
? new Repo({ gitDir })
|
|
30
|
-
: await Repo.getFromEnvironment();
|
|
31
|
-
const git = await repo.getGit();
|
|
32
|
-
|
|
33
|
-
return new GitSheets(repo, git);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
constructor (repo, git) {
|
|
37
|
-
this.repo = repo;
|
|
38
|
-
this.git = git;
|
|
39
|
-
this.version = 2;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Get config object from .gitsheets/config on a particular ref
|
|
44
|
-
* @public
|
|
45
|
-
* @param {string} ref - Ref of tree (e.g. master)
|
|
46
|
-
* @return {Promise<Object>}
|
|
47
|
-
* @throws {ConfigError}
|
|
48
|
-
*/
|
|
49
|
-
async getConfig (ref) {
|
|
50
|
-
const tree = await this._createTreeFromRef(ref);
|
|
51
|
-
const child = await tree.getChild('.gitsheets/config'); // TODO: Wrap errors
|
|
52
|
-
if (!child) return {};
|
|
53
|
-
|
|
54
|
-
const contents = await child.read(); // TODO: Wrap errors
|
|
55
|
-
return this._deserialize(contents);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Get a specific property from the config object
|
|
60
|
-
* @public
|
|
61
|
-
* @param {string} ref - Ref of tree (e.g. master)
|
|
62
|
-
* @param {string} key - Top-level property name (e.g. path)
|
|
63
|
-
* @return {Promise<*>}
|
|
64
|
-
* @throws {ConfigError}
|
|
65
|
-
*/
|
|
66
|
-
async getConfigItem (ref, key) {
|
|
67
|
-
const config = await this.getConfig(ref);
|
|
68
|
-
if (!config.hasOwnProperty(key)) {
|
|
69
|
-
throw new ConfigError(`config is missing property ${key}`)
|
|
70
|
-
} else {
|
|
71
|
-
return config[key];
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Save a config object to .gitsheets/config on an existing branch
|
|
77
|
-
* @public
|
|
78
|
-
* @param {string} ref - Ref of parent tree (e.g. master)
|
|
79
|
-
* @param {Object} config - Config object to save
|
|
80
|
-
* @return {Promise<void>}
|
|
81
|
-
* @throws {ConfigError}
|
|
82
|
-
*/
|
|
83
|
-
async setConfig (ref, config) {
|
|
84
|
-
const path = '.gitsheets/config';
|
|
85
|
-
const contents = this._serialize(config);
|
|
86
|
-
const tree = await this._createTreeFromRef(ref);
|
|
87
|
-
await tree.writeChild(path, contents); // TODO: Wrap errors
|
|
88
|
-
const treeHash = await tree.write();
|
|
89
|
-
await this._saveTreeToExistingBranch({
|
|
90
|
-
treeHash,
|
|
91
|
-
branch: ref,
|
|
92
|
-
msg: 'set config',
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Save a specific config property. Merges with existing config, if any.
|
|
98
|
-
* @public
|
|
99
|
-
* @param {string} ref - Ref of parent tree (e.g. master)
|
|
100
|
-
* @param {string} key - Top-level property name (e.g. path)
|
|
101
|
-
* @param {*} value - Value to set
|
|
102
|
-
* @return {Promise<void>}
|
|
103
|
-
* @throws {ConfigError}
|
|
104
|
-
*/
|
|
105
|
-
async setConfigItem (ref, key, value) {
|
|
106
|
-
const config = await this.getConfig(ref);
|
|
107
|
-
const newConfig = { ...config, [key]: value };
|
|
108
|
-
await this.setConfig(ref, newConfig);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Serialise a dataset and commit it onto current or new branch
|
|
113
|
-
* @public
|
|
114
|
-
* @param {Object} opts
|
|
115
|
-
* @param {Readable} opts.data - Stream of data to be imported
|
|
116
|
-
* @param {string} [opts.dataType] - Type of input data (valid: csv)
|
|
117
|
-
* @param {string} opts.parentRef - Ref of parent tree
|
|
118
|
-
* @param {boolean} opts.merge - Whether to merge/upsert data, as opposed to replace
|
|
119
|
-
* @param {string} [opts.saveToBranch] - Branch name to create or update. Omit to not save.
|
|
120
|
-
* @return {Promise<string>} - Tree hash
|
|
121
|
-
*/
|
|
122
|
-
async import ({
|
|
123
|
-
data,
|
|
124
|
-
dataType = null,
|
|
125
|
-
parentRef,
|
|
126
|
-
merge = false,
|
|
127
|
-
saveToBranch = null,
|
|
128
|
-
}) {
|
|
129
|
-
const pathTemplate = await this.getConfigItem(parentRef, 'path');
|
|
130
|
-
|
|
131
|
-
const treeObject = (merge)
|
|
132
|
-
? await this._createTreeFromRef(parentRef)
|
|
133
|
-
: await this._createTruncatedTree(parentRef);
|
|
134
|
-
|
|
135
|
-
const treeHash = await this._writeDataToTree({
|
|
136
|
-
data: this._attachDataParser(data, dataType),
|
|
137
|
-
treeObject,
|
|
138
|
-
pathTemplate,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
if (saveToBranch && saveToBranch === parentRef) { // TODO: check if branch exists instead
|
|
142
|
-
await this._saveTreeToExistingBranch({
|
|
143
|
-
treeHash,
|
|
144
|
-
branch: saveToBranch,
|
|
145
|
-
msg: 'import to existing branch',
|
|
146
|
-
});
|
|
147
|
-
} else if (saveToBranch) {
|
|
148
|
-
await this._saveTreeToNewBranch({
|
|
149
|
-
treeHash,
|
|
150
|
-
parentRef,
|
|
151
|
-
branch: saveToBranch,
|
|
152
|
-
msg: 'import to new branch',
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return treeHash;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Deserialize a dataset from a particular ref
|
|
161
|
-
* @public
|
|
162
|
-
* @param {string} ref - Ref of tree (e.g. master)
|
|
163
|
-
* @returns {Promise<Readable>}
|
|
164
|
-
*/
|
|
165
|
-
async export (ref) {
|
|
166
|
-
const treeObject = await this._createTreeFromRef(ref);
|
|
167
|
-
|
|
168
|
-
const blobMap = await treeObject.getBlobMap();
|
|
169
|
-
let blobsRemaining = Object.entries(blobMap)
|
|
170
|
-
.filter(this._isDataBlob)
|
|
171
|
-
|
|
172
|
-
const deserialize = this._deserialize.bind(this);
|
|
173
|
-
return new Readable({
|
|
174
|
-
objectMode: true,
|
|
175
|
-
async read () {
|
|
176
|
-
if (blobsRemaining.length > 0) {
|
|
177
|
-
const [key, blob] = blobsRemaining.shift() // mutates array
|
|
178
|
-
this.push(
|
|
179
|
-
await blob.read()
|
|
180
|
-
.then(deserialize)
|
|
181
|
-
.then((data) => ({ ...data, _path: key.substr(0, key.length-5) }))
|
|
182
|
-
);
|
|
183
|
-
} else {
|
|
184
|
-
this.push(null);
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
})
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Compare a dataset between two refs and return the diffs
|
|
192
|
-
* @public
|
|
193
|
-
* @param {string} srcRef - Ref of original state (e.g. master)
|
|
194
|
-
* @param {string} dstRef - Ref of new state (e.g. proposal)
|
|
195
|
-
* @returns {Promise<Array>}
|
|
196
|
-
*/
|
|
197
|
-
async compare (srcRef, dstRef) {
|
|
198
|
-
const [srcBlobMap, dstBlobMap] = await Promise.all([
|
|
199
|
-
this._getBlobMapFromRef(srcRef),
|
|
200
|
-
this._getBlobMapFromRef(dstRef),
|
|
201
|
-
]);
|
|
202
|
-
|
|
203
|
-
const diffs = await this._getDiffs(srcRef, dstRef);
|
|
204
|
-
|
|
205
|
-
const fullDiffs = diffs.map(({ status, path, newPath }) => ({
|
|
206
|
-
added: async () => ({
|
|
207
|
-
_path: path,
|
|
208
|
-
status,
|
|
209
|
-
value: await this._parseBlob(dstBlobMap[path]),
|
|
210
|
-
}),
|
|
211
|
-
deleted: async () => ({
|
|
212
|
-
_path: path,
|
|
213
|
-
status,
|
|
214
|
-
value: await this._parseBlob(srcBlobMap[path]),
|
|
215
|
-
}),
|
|
216
|
-
modified: async () => ({
|
|
217
|
-
_path: path,
|
|
218
|
-
status,
|
|
219
|
-
patch: await this._generatePatch(srcBlobMap[path], dstBlobMap[path]),
|
|
220
|
-
}),
|
|
221
|
-
renamed: async () => ({
|
|
222
|
-
_path: path,
|
|
223
|
-
status: 'modified',
|
|
224
|
-
patch: await this._generatePatch(srcBlobMap[path], dstBlobMap[newPath]),
|
|
225
|
-
}),
|
|
226
|
-
}[status]()));
|
|
227
|
-
|
|
228
|
-
return Promise.all(fullDiffs);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Create a merge commit between two refs and update srcRef to point to it
|
|
233
|
-
* Note: Only works if srcRef is ancestor of dstRef
|
|
234
|
-
* Note: Force deletes dstRef
|
|
235
|
-
* @public
|
|
236
|
-
* @param {string} srcRef - Ref of original state (e.g. master)
|
|
237
|
-
* @param {string} dstRef - Ref of new state (e.g. proposal)
|
|
238
|
-
* @param {string} [msg=Merge <dstRef>] - Message of merge commit
|
|
239
|
-
* @returns {Promise<void>}
|
|
240
|
-
* @throws {MergeError}
|
|
241
|
-
*/
|
|
242
|
-
async merge (srcRef, dstRef, msg = null) {
|
|
243
|
-
await this._verifyIsAncestor(srcRef, dstRef);
|
|
244
|
-
const commitMsg = msg || `Merge ${dstRef}`;
|
|
245
|
-
|
|
246
|
-
const [
|
|
247
|
-
qualifiedSrcRef,
|
|
248
|
-
srcCommitHash,
|
|
249
|
-
dstCommitHash,
|
|
250
|
-
dstTreeHash,
|
|
251
|
-
] = await Promise.all([
|
|
252
|
-
this._getQualifiedRef(srcRef),
|
|
253
|
-
this._getCommitHash(srcRef),
|
|
254
|
-
this._getCommitHash(dstRef),
|
|
255
|
-
this._getTreeHash(dstRef),
|
|
256
|
-
]);
|
|
257
|
-
|
|
258
|
-
const mergeCommitHash = await this.git.commitTree(dstTreeHash, {
|
|
259
|
-
p: [ srcCommitHash, dstCommitHash ],
|
|
260
|
-
m: commitMsg,
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
// TODO: Wrap errors
|
|
264
|
-
await this.git.updateRef(qualifiedSrcRef, mergeCommitHash, srcCommitHash);
|
|
265
|
-
await this.git.branch({D: true}, dstRef); // force delete in case srcRef is not checked out
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
_isDataBlob ([key, blob]) {
|
|
269
|
-
return !key.startsWith('.gitsheets/') && key.endsWith('.toml') && blob instanceof BlobObject;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
async _verifyIsAncestor (srcRef, dstRef) {
|
|
273
|
-
try {
|
|
274
|
-
await this.git.mergeBase({'is-ancestor': true}, srcRef, dstRef);
|
|
275
|
-
} catch (err) {
|
|
276
|
-
throw new MergeError(`${srcRef} is not an ancestor of ${dstRef}`);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
async _getBlobMapFromRef (ref) {
|
|
281
|
-
const treeObject = await this._createTreeFromRef(ref);
|
|
282
|
-
return treeObject.getBlobMap();
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
async _generatePatch (srcBlob, dstBlob) {
|
|
286
|
-
const [srcData, dstData] = await Promise.all([
|
|
287
|
-
this._parseBlob(srcBlob),
|
|
288
|
-
this._parseBlob(dstBlob),
|
|
289
|
-
]);
|
|
290
|
-
return this._compareObjects(srcData, dstData);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async _getDiffs (srcRef, dstRef) {
|
|
294
|
-
const output = await this.git.diff({'name-status': true}, srcRef, dstRef);
|
|
295
|
-
|
|
296
|
-
return output
|
|
297
|
-
.trim()
|
|
298
|
-
.split('\n')
|
|
299
|
-
.filter((line) => line.length > 0)
|
|
300
|
-
.map(this._parseDiffLine)
|
|
301
|
-
.filter((diff) => diff.status !== null)
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
_parseDiffLine (line) {
|
|
305
|
-
const [ , statusCode, path, newPath ] = line.match(DIFF_PATTERN);
|
|
306
|
-
const status = diffStatusMap[statusCode] || null;
|
|
307
|
-
return { status, path, newPath };
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
_parseBlob (blob) {
|
|
311
|
-
return blob.read()
|
|
312
|
-
.then(this._deserialize);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
_compareObjects (src, dst) {
|
|
316
|
-
const includeTestOps = true;
|
|
317
|
-
const ops = jsonpatch.compare(src, dst, includeTestOps);
|
|
318
|
-
return this._mergeTestAndReplaceOps(ops);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
_mergeTestAndReplaceOps (items) {
|
|
322
|
-
const mergeableItems = items.map((item) => {
|
|
323
|
-
if (item.op === 'test') return { path: item.path, from: item.value };
|
|
324
|
-
else return item;
|
|
325
|
-
})
|
|
326
|
-
const keyedItems = mergeableItems.reduce((accum, item) => {
|
|
327
|
-
if (accum.has(item.path)) {
|
|
328
|
-
const currentItem = accum.get(item.path);
|
|
329
|
-
accum.set(item.path, { ...currentItem, ...item });
|
|
330
|
-
} else {
|
|
331
|
-
accum.set(item.path, item);
|
|
332
|
-
}
|
|
333
|
-
return accum;
|
|
334
|
-
}, new Map());
|
|
335
|
-
|
|
336
|
-
return Array.from(keyedItems.values());
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* WARNING: mutates tree
|
|
341
|
-
*/
|
|
342
|
-
_writeDataToTree ({ data, treeObject, pathTemplate }) {
|
|
343
|
-
return new Promise((resolve, reject) => {
|
|
344
|
-
const pendingWrites = [];
|
|
345
|
-
|
|
346
|
-
data
|
|
347
|
-
.on('data', (row) => {
|
|
348
|
-
const path = this._renderTemplate(pathTemplate, row);
|
|
349
|
-
const contents = this._serialize(row);
|
|
350
|
-
|
|
351
|
-
pendingWrites.push(treeObject.writeChild(`${path}.toml`, contents));
|
|
352
|
-
})
|
|
353
|
-
.on('end', () => {
|
|
354
|
-
Promise.all(pendingWrites)
|
|
355
|
-
.then(() => treeObject.write())
|
|
356
|
-
.then(resolve)
|
|
357
|
-
.catch(reject);
|
|
358
|
-
})
|
|
359
|
-
.on('error', (err) => {
|
|
360
|
-
reject(new SerializationError(err.message))
|
|
361
|
-
})
|
|
362
|
-
})
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
_attachDataParser (data, dataType) {
|
|
366
|
-
if (dataType === 'csv') {
|
|
367
|
-
return data.pipe(csvParser({ strict: true }));
|
|
368
|
-
} else {
|
|
369
|
-
return data;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Wraps Hologit.Repo.createTreeFromRef with error matching
|
|
375
|
-
* @private
|
|
376
|
-
*/
|
|
377
|
-
async _createTreeFromRef (parent) {
|
|
378
|
-
try {
|
|
379
|
-
return await this.repo.createTreeFromRef(parent);
|
|
380
|
-
} catch (err) {
|
|
381
|
-
if (err.message.startsWith('invalid tree ref')) {
|
|
382
|
-
throw new InvalidRefError('unknown ref');
|
|
383
|
-
} else {
|
|
384
|
-
throw err;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Creates an empty tree and merges GitSheets config
|
|
391
|
-
* @private
|
|
392
|
-
*/
|
|
393
|
-
async _createTruncatedTree (parent) {
|
|
394
|
-
const parentTree = await this._createTreeFromRef(parent);
|
|
395
|
-
const tree = this.repo.createTree();
|
|
396
|
-
await tree.merge(parentTree, { files: ['.gitsheets/*'] });
|
|
397
|
-
return tree;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
_serialize (row) {
|
|
401
|
-
try {
|
|
402
|
-
return TOML.stringify(this._sortObjectKeys(row));
|
|
403
|
-
} catch (err) {
|
|
404
|
-
throw new SerializationError(err.message);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
_deserialize (contents) {
|
|
409
|
-
try {
|
|
410
|
-
return TOML.parse(contents);
|
|
411
|
-
} catch (err) {
|
|
412
|
-
throw new SerializationError(err.message);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
_renderTemplate (template, data) {
|
|
417
|
-
try {
|
|
418
|
-
return maxstache(template, data);
|
|
419
|
-
} catch (err) {
|
|
420
|
-
throw new SerializationError(err.message);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
_sortObjectKeys (unsorted) {
|
|
425
|
-
const sortedKeys = Object.keys(unsorted).sort()
|
|
426
|
-
|
|
427
|
-
return sortedKeys.reduce((accum, key) => {
|
|
428
|
-
accum[key] = unsorted[key]
|
|
429
|
-
return accum
|
|
430
|
-
}, {})
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
async _saveTreeToNewBranch({ treeHash, parentRef, branch, msg }) {
|
|
434
|
-
const commitHash = await this.git.commitTree(treeHash, { // TODO: Wrap errors
|
|
435
|
-
p: parentRef,
|
|
436
|
-
m: msg,
|
|
437
|
-
});
|
|
438
|
-
await this.git.branch(branch, commitHash); // TODO: Wrap errors
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
async _saveTreeToExistingBranch ({ treeHash, branch, msg }) {
|
|
442
|
-
const commitHash = await this.git.commitTree(treeHash, { // TODO: Wrap errors
|
|
443
|
-
p: branch,
|
|
444
|
-
m: msg,
|
|
445
|
-
});
|
|
446
|
-
const qualifiedBranch = await this._getQualifiedRef(branch);
|
|
447
|
-
await this.git.updateRef(qualifiedBranch, commitHash); // TODO: Wrap errors
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
_getQualifiedRef (ref) {
|
|
451
|
-
// TODO: Wrap errors
|
|
452
|
-
return this.git.revParse({'symbolic-full-name': true}, ref);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
_getCommitHash (ref) {
|
|
456
|
-
return this.git.revParse({verify: true}, ref);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
async _getTreeHash (ref) {
|
|
460
|
-
const tree = await this._createTreeFromRef(ref);
|
|
461
|
-
const hash = await tree.getHash();
|
|
462
|
-
return hash
|
|
463
|
-
}
|
|
464
|
-
}
|
package/lib/Repository.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const Sheet = require('./Sheet.js');
|
|
3
|
-
const { Repo: HoloRepo, BlobObject } = require('hologit/lib');
|
|
4
|
-
|
|
5
|
-
class Repository extends HoloRepo
|
|
6
|
-
{
|
|
7
|
-
constructor(options = {}) {
|
|
8
|
-
super(options);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
async resolveDataTree (root, dataTree) {
|
|
12
|
-
const workspace = await this.getWorkspace();
|
|
13
|
-
|
|
14
|
-
root = path.join('.', root);
|
|
15
|
-
|
|
16
|
-
if (typeof dataTree == 'string') {
|
|
17
|
-
dataTree = await workspace.root.getSubtree(path.join(root, dataTree), true);
|
|
18
|
-
} else if (!dataTree) {
|
|
19
|
-
dataTree = await workspace.root.getSubtree(root);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const sheetsPath = path.join(root, '.gitsheets');
|
|
23
|
-
const sheetsTree = await workspace.root.getSubtree(sheetsPath, true);
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
workspace,
|
|
27
|
-
root,
|
|
28
|
-
sheetsPath,
|
|
29
|
-
sheetsTree,
|
|
30
|
-
dataTree,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async openSheet (name, { root = '/', dataTree: dataTreeInput = null, config = null } = {}) {
|
|
35
|
-
const { workspace, sheetsPath, dataTree } = await this.resolveDataTree(root, dataTreeInput);
|
|
36
|
-
|
|
37
|
-
return new Sheet({
|
|
38
|
-
workspace,
|
|
39
|
-
dataTree,
|
|
40
|
-
name,
|
|
41
|
-
configPath: path.join(sheetsPath, `${name}.toml`),
|
|
42
|
-
phantom: config,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async openSheets ({ root = '/', dataTree: dataTreeInput = null } = {}) {
|
|
47
|
-
const { workspace, sheetsPath, sheetsTree, dataTree } = await this.resolveDataTree(root, dataTreeInput);
|
|
48
|
-
|
|
49
|
-
const children = await sheetsTree.getChildren();
|
|
50
|
-
const childNameRe = /^([^\/]+)\.toml$/;
|
|
51
|
-
|
|
52
|
-
const sheets = {};
|
|
53
|
-
|
|
54
|
-
for (const childName in children) {
|
|
55
|
-
|
|
56
|
-
// skip any child not ending in .toml
|
|
57
|
-
const filenameMatches = childName.match(childNameRe);
|
|
58
|
-
if (!filenameMatches) {
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// skip any child that is deleted or isn't a blob
|
|
63
|
-
const treeChild = children[childName];
|
|
64
|
-
if (!treeChild || !treeChild.isBlob) {
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// read sheet
|
|
69
|
-
const [, name] = filenameMatches;
|
|
70
|
-
|
|
71
|
-
sheets[name] = new Sheet({
|
|
72
|
-
workspace,
|
|
73
|
-
dataTree,
|
|
74
|
-
name,
|
|
75
|
-
configPath: path.join(sheetsPath, childName),
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return sheets;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async finishWriting () {
|
|
83
|
-
// TODO: using this instead of awaiting each upsert isn't safe currently as TreeObject.writeChild isn't safe to parallelize due to async subtree building
|
|
84
|
-
return Sheet.finishWriting(this);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
module.exports = Repository;
|