pagan-artifact 0.2.8 → 0.3.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/bin/art.js +15 -2
- package/branching/index.js +117 -46
- package/caches/index.js +112 -68
- package/changes/index.js +49 -15
- package/contributions/index.js +125 -95
- package/index.js +2 -2
- package/package.json +1 -1
- package/setup/index.js +197 -157
- package/utils/getStateByHash/index.js +61 -41
- package/workflow/index.js +199 -150
package/bin/art.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* art - Modern version control.
|
|
5
|
-
* CLI (v0.
|
|
5
|
+
* CLI (v0.3.0)
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const art = require('../index.js');
|
|
9
|
+
const path = require('path');
|
|
9
10
|
|
|
10
11
|
const [,, command, ...args] = process.argv;
|
|
11
12
|
|
|
@@ -69,7 +70,19 @@ async function run() {
|
|
|
69
70
|
|
|
70
71
|
if (ignored && ignored.length > 0) {
|
|
71
72
|
console.log('\nIgnored files:');
|
|
72
|
-
|
|
73
|
+
|
|
74
|
+
const compressedIgnored = new Set();
|
|
75
|
+
|
|
76
|
+
ignored.forEach(f => {
|
|
77
|
+
const parts = f.split(path.sep);
|
|
78
|
+
if (parts.length > 1) {
|
|
79
|
+
compressedIgnored.add(`${parts[0]}${path.sep}`);
|
|
80
|
+
} else {
|
|
81
|
+
compressedIgnored.add(f);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
compressedIgnored.forEach(f => console.log(`${GRAY}\t${f}${RESET}`));
|
|
73
86
|
}
|
|
74
87
|
|
|
75
88
|
if (untracked.length === 0 && modified.length === 0 && staged.length === 0) {
|
package/branching/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* art - Modern version control.
|
|
3
|
-
* Module: Branching (v0.
|
|
3
|
+
* Module: Branching (v0.3.0)
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
@@ -8,6 +8,8 @@ const path = require('path');
|
|
|
8
8
|
|
|
9
9
|
const getStateByHash = require('../utils/getStateByHash');
|
|
10
10
|
|
|
11
|
+
const MAX_PART_SIZE = 32000000;
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* Lists, creates, or deletes branches.
|
|
13
15
|
*/
|
|
@@ -20,10 +22,11 @@ function branch ({ name, isDelete = false } = {}) {
|
|
|
20
22
|
|
|
21
23
|
if (!name) {
|
|
22
24
|
return fs.readdirSync(localHistoryPath).filter(f => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
return f !== '.DS_Store' && f !== 'desktop.ini' && f !== 'thumbs.db';
|
|
26
|
+
});
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
const normalizedName = name.toLowerCase();
|
|
27
30
|
const illegalRegExp = /[\/\\]/g;
|
|
28
31
|
const controlRegExp = /[\x00-\x1f\x80-\x9f]/g;
|
|
29
32
|
const reservedRegExp = /^\.+$/;
|
|
@@ -60,7 +63,8 @@ function branch ({ name, isDelete = false } = {}) {
|
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
const artJson = JSON.parse(fs.readFileSync(artJsonPath, 'utf8'));
|
|
63
|
-
const
|
|
66
|
+
const sourceBranchName = artJson.active.branch;
|
|
67
|
+
const currentBranchManifest = path.join(localHistoryPath, sourceBranchName, 'manifest.json');
|
|
64
68
|
|
|
65
69
|
let initialCommits = [];
|
|
66
70
|
|
|
@@ -85,14 +89,33 @@ function branch ({ name, isDelete = false } = {}) {
|
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
if (initialCommits.length > 0) {
|
|
88
|
-
const sourceBranchPath = path.join(localHistoryPath,
|
|
92
|
+
const sourceBranchPath = path.join(localHistoryPath, sourceBranchName);
|
|
93
|
+
const sourceRemotePath = path.join(remoteHistoryPath, sourceBranchName);
|
|
89
94
|
|
|
90
95
|
for (const hash of initialCommits) {
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
let masterFile = path.join(sourceBranchPath, `${hash}.json`);
|
|
97
|
+
let currentSrcDir = sourceBranchPath;
|
|
98
|
+
|
|
99
|
+
if (!fs.existsSync(masterFile)) {
|
|
100
|
+
masterFile = path.join(sourceRemotePath, `${hash}.json`);
|
|
101
|
+
currentSrcDir = sourceRemotePath;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (fs.existsSync(masterFile)) {
|
|
105
|
+
fs.copyFileSync(masterFile, path.join(branchLocalPath, `${hash}.json`));
|
|
93
106
|
|
|
94
|
-
|
|
95
|
-
|
|
107
|
+
const commitMaster = JSON.parse(fs.readFileSync(masterFile, 'utf8'));
|
|
108
|
+
|
|
109
|
+
if (commitMaster.parts && Array.isArray(commitMaster.parts)) {
|
|
110
|
+
for (const partName of commitMaster.parts) {
|
|
111
|
+
const srcPart = path.join(currentSrcDir, partName);
|
|
112
|
+
const destPart = path.join(branchLocalPath, partName);
|
|
113
|
+
|
|
114
|
+
if (fs.existsSync(srcPart)) {
|
|
115
|
+
fs.copyFileSync(srcPart, destPart);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
96
119
|
}
|
|
97
120
|
}
|
|
98
121
|
}
|
|
@@ -122,10 +145,13 @@ function checkout (branchName, { force = false } = {}) {
|
|
|
122
145
|
.filter(f => !f.startsWith('.art') && !fs.statSync(path.join(root, f)).isDirectory());
|
|
123
146
|
|
|
124
147
|
let isDirty = false;
|
|
148
|
+
|
|
125
149
|
for (const file of allWorkDirFiles) {
|
|
126
150
|
const currentContent = fs.readFileSync(path.join(root, file), 'utf8');
|
|
151
|
+
|
|
127
152
|
if (currentContent !== currentState[file]) {
|
|
128
153
|
isDirty = true;
|
|
154
|
+
|
|
129
155
|
break;
|
|
130
156
|
}
|
|
131
157
|
}
|
|
@@ -134,6 +160,7 @@ function checkout (branchName, { force = false } = {}) {
|
|
|
134
160
|
for (const file in currentState) {
|
|
135
161
|
if (!fs.existsSync(path.join(root, file))) {
|
|
136
162
|
isDirty = true;
|
|
163
|
+
|
|
137
164
|
break;
|
|
138
165
|
}
|
|
139
166
|
}
|
|
@@ -155,12 +182,16 @@ function checkout (branchName, { force = false } = {}) {
|
|
|
155
182
|
for (const filePath of Object.keys(currentState)) {
|
|
156
183
|
if (!targetState[filePath]) {
|
|
157
184
|
const fullPath = path.join(root, filePath);
|
|
158
|
-
|
|
185
|
+
|
|
186
|
+
if (fs.existsSync(fullPath)) {
|
|
187
|
+
fs.rmSync(fullPath, { recursive: true, force: true });
|
|
188
|
+
}
|
|
159
189
|
}
|
|
160
190
|
}
|
|
161
191
|
|
|
162
192
|
for (const [filePath, content] of Object.entries(targetState)) {
|
|
163
193
|
const fullPath = path.join(root, filePath);
|
|
194
|
+
|
|
164
195
|
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
165
196
|
fs.writeFileSync(fullPath, content);
|
|
166
197
|
}
|
|
@@ -176,57 +207,97 @@ function checkout (branchName, { force = false } = {}) {
|
|
|
176
207
|
* Performs a three-way merge. Overwrites working directory with conflicts.
|
|
177
208
|
*/
|
|
178
209
|
|
|
179
|
-
function merge (targetBranch) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
210
|
+
function merge (targetBranch) {
|
|
211
|
+
const root = process.cwd();
|
|
212
|
+
const artPath = path.join(root, '.art');
|
|
213
|
+
const stageDir = path.join(artPath, 'stage');
|
|
214
|
+
const artJson = JSON.parse(fs.readFileSync(path.join(artPath, 'art.json'), 'utf8'));
|
|
215
|
+
const activeBranch = artJson.active.branch;
|
|
184
216
|
|
|
185
|
-
|
|
186
|
-
|
|
217
|
+
if (fs.existsSync(stageDir)) {
|
|
218
|
+
fs.rmSync(stageDir, { recursive: true, force: true });
|
|
219
|
+
}
|
|
187
220
|
|
|
188
|
-
|
|
221
|
+
fs.mkdirSync(stageDir, { recursive: true });
|
|
189
222
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
const lastTargetHash = targetManifest.commits[targetManifest.commits.length - 1];
|
|
193
|
-
const targetState = getStateByHash(targetBranch, lastTargetHash);
|
|
223
|
+
const activeManifest = JSON.parse(fs.readFileSync(path.join(artPath, `history/local/${activeBranch}/manifest.json`), 'utf8'));
|
|
224
|
+
const targetManifest = JSON.parse(fs.readFileSync(path.join(artPath, `history/local/${targetBranch}/manifest.json`), 'utf8'));
|
|
194
225
|
|
|
195
|
-
|
|
196
|
-
const allFiles = new Set([...Object.keys(activeState), ...Object.keys(targetState)]);
|
|
226
|
+
const commonAncestorHash = [...activeManifest.commits].reverse().find(h => targetManifest.commits.includes(h)) || null;
|
|
197
227
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const fullPath = path.join(root, filePath);
|
|
228
|
+
const baseState = commonAncestorHash ? getStateByHash(activeBranch, commonAncestorHash) : {};
|
|
229
|
+
const activeState = getStateByHash(activeBranch, artJson.active.parent);
|
|
230
|
+
const lastTargetHash = targetManifest.commits[targetManifest.commits.length - 1];
|
|
231
|
+
const targetState = getStateByHash(targetBranch, lastTargetHash);
|
|
203
232
|
|
|
204
|
-
|
|
233
|
+
const allFiles = new Set([...Object.keys(activeState), ...Object.keys(targetState)]);
|
|
205
234
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
235
|
+
let currentPartChanges = {};
|
|
236
|
+
let currentPartSize = 0;
|
|
237
|
+
let partCount = 0;
|
|
209
238
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const conflictContent = `<<<<<<< active\n${active || ''}\n=======\n${target || ''}\n>>>>>>> ${targetBranch}`;
|
|
239
|
+
const saveStagePart = () => {
|
|
240
|
+
if (Object.keys(currentPartChanges).length === 0) return;
|
|
213
241
|
|
|
214
|
-
|
|
215
|
-
fs.writeFileSync(fullPath, conflictContent);
|
|
242
|
+
const partPath = path.join(stageDir, `part.${partCount}.json`);
|
|
216
243
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
244
|
+
fs.writeFileSync(partPath, JSON.stringify({ changes: currentPartChanges }, null, 2));
|
|
245
|
+
currentPartChanges = {};
|
|
246
|
+
currentPartSize = 0;
|
|
247
|
+
partCount++;
|
|
248
|
+
};
|
|
220
249
|
|
|
221
|
-
|
|
250
|
+
for (const filePath of allFiles) {
|
|
251
|
+
const base = baseState[filePath];
|
|
252
|
+
const active = activeState[filePath];
|
|
253
|
+
const target = targetState[filePath];
|
|
254
|
+
const fullPath = path.join(root, filePath);
|
|
222
255
|
|
|
223
|
-
|
|
256
|
+
if (active === target) continue;
|
|
224
257
|
|
|
225
|
-
|
|
226
|
-
|
|
258
|
+
let change = null;
|
|
259
|
+
|
|
260
|
+
if (base === active && base !== target) {
|
|
261
|
+
if (target === undefined) {
|
|
262
|
+
if (fs.existsSync(fullPath)) fs.unlinkSync(fullPath);
|
|
263
|
+
change = { type: 'deleteFile' };
|
|
264
|
+
} else {
|
|
265
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
266
|
+
fs.writeFileSync(fullPath, target);
|
|
267
|
+
change = { type: 'createFile', content: target };
|
|
268
|
+
}
|
|
269
|
+
} else if (base !== active && base !== target && active !== target) {
|
|
270
|
+
const conflictContent = `<<<<<<< active\n${active || ''}\n=======\n${target || ''}\n>>>>>>> ${targetBranch}`;
|
|
271
|
+
|
|
272
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
273
|
+
fs.writeFileSync(fullPath, conflictContent);
|
|
274
|
+
change = { type: 'createFile', content: conflictContent };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (change) {
|
|
278
|
+
const changeSize = JSON.stringify(change).length;
|
|
279
|
+
|
|
280
|
+
if (currentPartSize + changeSize > MAX_PART_SIZE) {
|
|
281
|
+
saveStagePart();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
currentPartChanges[filePath] = change;
|
|
285
|
+
currentPartSize += changeSize;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
saveStagePart();
|
|
290
|
+
|
|
291
|
+
fs.writeFileSync(
|
|
292
|
+
path.join(stageDir, 'manifest.json'),
|
|
293
|
+
JSON.stringify({ parts: Array.from({ length: partCount }, (_, i) => `part.${i}.json`) }, null, 2)
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
return `Merged ${targetBranch}.`;
|
|
297
|
+
}
|
|
227
298
|
|
|
228
299
|
module.exports = {
|
|
229
|
-
__libraryVersion: '0.
|
|
300
|
+
__libraryVersion: '0.3.0',
|
|
230
301
|
__libraryAPIName: 'Branching',
|
|
231
302
|
branch,
|
|
232
303
|
checkout,
|
package/caches/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* art - Modern version control.
|
|
3
|
-
* Module: Caches (v0.
|
|
3
|
+
* Module: Caches (v0.3.0)
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
@@ -9,27 +9,95 @@ const path = require('path');
|
|
|
9
9
|
const { checkout } = require('../branching/index.js');
|
|
10
10
|
const getStateByHash = require('../utils/getStateByHash');
|
|
11
11
|
|
|
12
|
+
const MAX_PART_SIZE = 32000000;
|
|
13
|
+
|
|
12
14
|
/**
|
|
13
|
-
*
|
|
15
|
+
* Helper to load all changes from a paginated directory (Stage or Stash).
|
|
14
16
|
*/
|
|
15
17
|
|
|
18
|
+
function getPaginatedChanges(dirPath) {
|
|
19
|
+
const manifestPath = path.join(dirPath, 'manifest.json');
|
|
20
|
+
|
|
21
|
+
if (!fs.existsSync(dirPath) || !fs.existsSync(manifestPath)) {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
26
|
+
|
|
27
|
+
let allChanges = {};
|
|
28
|
+
|
|
29
|
+
for (const partName of manifest.parts) {
|
|
30
|
+
const partPath = path.join(dirPath, partName);
|
|
31
|
+
if (fs.existsSync(partPath)) {
|
|
32
|
+
const partData = JSON.parse(fs.readFileSync(partPath, 'utf8'));
|
|
33
|
+
|
|
34
|
+
Object.assign(allChanges, partData.changes);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return allChanges;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Helper to write changes to a paginated directory.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
function savePaginatedChanges (dirPath, changes) {
|
|
46
|
+
if (fs.existsSync(dirPath)) {
|
|
47
|
+
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
51
|
+
|
|
52
|
+
const parts = [];
|
|
53
|
+
|
|
54
|
+
let currentPartChanges = {};
|
|
55
|
+
let currentSize = 0;
|
|
56
|
+
|
|
57
|
+
const savePart = () => {
|
|
58
|
+
if (Object.keys(currentPartChanges).length === 0) return;
|
|
59
|
+
|
|
60
|
+
const partName = `part.${parts.length}.json`;
|
|
61
|
+
|
|
62
|
+
fs.writeFileSync(path.join(dirPath, partName), JSON.stringify({ changes: currentPartChanges }, null, 2));
|
|
63
|
+
parts.push(partName);
|
|
64
|
+
currentPartChanges = {};
|
|
65
|
+
currentSize = 0;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
for (const [file, changeSet] of Object.entries(changes)) {
|
|
69
|
+
const size = JSON.stringify(changeSet).length;
|
|
70
|
+
|
|
71
|
+
if (currentSize + size > MAX_PART_SIZE && Object.keys(currentPartChanges).length > 0) {
|
|
72
|
+
savePart();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
currentPartChanges[file] = changeSet;
|
|
76
|
+
currentSize += size;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
savePart();
|
|
80
|
+
fs.writeFileSync(path.join(dirPath, 'manifest.json'), JSON.stringify({ parts }, null, 2));
|
|
81
|
+
}
|
|
82
|
+
|
|
16
83
|
function stash ({ pop = false, list = false } = {}) {
|
|
17
84
|
const root = process.cwd();
|
|
18
85
|
const artPath = path.join(root, '.art');
|
|
19
|
-
const
|
|
86
|
+
const stageDir = path.join(artPath, 'stage');
|
|
20
87
|
const cachePath = path.join(artPath, 'cache');
|
|
21
88
|
const artJsonPath = path.join(artPath, 'art.json');
|
|
22
89
|
|
|
23
90
|
if (list) {
|
|
24
91
|
if (!fs.existsSync(cachePath)) return [];
|
|
25
|
-
|
|
26
|
-
|
|
92
|
+
|
|
93
|
+
const stashDirs = fs.readdirSync(cachePath)
|
|
94
|
+
.filter(d => d.startsWith('stash_') && fs.statSync(path.join(cachePath, d)).isDirectory())
|
|
27
95
|
.sort();
|
|
28
96
|
|
|
29
|
-
return
|
|
30
|
-
id: `stash@{${
|
|
31
|
-
date: new Date(parseInt(
|
|
32
|
-
|
|
97
|
+
return stashDirs.map((dirName, index) => ({
|
|
98
|
+
id: `stash@{${stashDirs.length - 1 - index}}`,
|
|
99
|
+
date: new Date(parseInt(dirName.replace('stash_', ''))).toLocaleString(),
|
|
100
|
+
dirName
|
|
33
101
|
}));
|
|
34
102
|
}
|
|
35
103
|
|
|
@@ -37,18 +105,16 @@ function stash ({ pop = false, list = false } = {}) {
|
|
|
37
105
|
if (!fs.existsSync(cachePath)) throw new Error('No stashes found.');
|
|
38
106
|
|
|
39
107
|
const stashes = fs.readdirSync(cachePath)
|
|
40
|
-
.filter(
|
|
108
|
+
.filter(d => d.startsWith('stash_') && fs.statSync(path.join(cachePath, d)).isDirectory())
|
|
41
109
|
.sort();
|
|
42
110
|
|
|
43
|
-
if (stashes.length === 0)
|
|
44
|
-
throw new Error('No stashes found.');
|
|
45
|
-
}
|
|
111
|
+
if (stashes.length === 0) throw new Error('No stashes found.');
|
|
46
112
|
|
|
47
|
-
const
|
|
48
|
-
const latestStashPath = path.join(cachePath,
|
|
49
|
-
const
|
|
113
|
+
const latestStashDirName = stashes[stashes.length - 1];
|
|
114
|
+
const latestStashPath = path.join(cachePath, latestStashDirName);
|
|
115
|
+
const stashChanges = getPaginatedChanges(latestStashPath);
|
|
50
116
|
|
|
51
|
-
for (const [filePath, changeSet] of Object.entries(
|
|
117
|
+
for (const [filePath, changeSet] of Object.entries(stashChanges)) {
|
|
52
118
|
const fullPath = path.join(root, filePath);
|
|
53
119
|
|
|
54
120
|
if (Array.isArray(changeSet)) {
|
|
@@ -71,9 +137,8 @@ function stash ({ pop = false, list = false } = {}) {
|
|
|
71
137
|
}
|
|
72
138
|
}
|
|
73
139
|
|
|
74
|
-
fs.
|
|
75
|
-
|
|
76
|
-
return `Restored changes from ${latestStashName}.`;
|
|
140
|
+
fs.rmSync(latestStashPath, { recursive: true, force: true });
|
|
141
|
+
return `Restored changes from ${latestStashDirName}.`;
|
|
77
142
|
}
|
|
78
143
|
|
|
79
144
|
const artJson = JSON.parse(fs.readFileSync(artJsonPath, 'utf8'));
|
|
@@ -85,12 +150,16 @@ function stash ({ pop = false, list = false } = {}) {
|
|
|
85
150
|
const stashChanges = {};
|
|
86
151
|
|
|
87
152
|
for (const file of allWorkDirFiles) {
|
|
88
|
-
const
|
|
153
|
+
const fullPath = path.join(root, file);
|
|
154
|
+
const currentBuffer = fs.readFileSync(fullPath);
|
|
155
|
+
const isBinary = currentBuffer.includes(0);
|
|
156
|
+
|
|
157
|
+
const currentContent = isBinary ? null : currentBuffer.toString('utf8');
|
|
89
158
|
const previousContent = activeState[file];
|
|
90
159
|
|
|
91
160
|
if (previousContent === undefined) {
|
|
92
|
-
stashChanges[file] = { type: 'createFile', content: currentContent };
|
|
93
|
-
} else if (currentContent !== previousContent) {
|
|
161
|
+
stashChanges[file] = { type: 'createFile', content: isBinary ? currentBuffer.toString('base64') : currentContent };
|
|
162
|
+
} else if (currentContent !== previousContent && !isBinary) {
|
|
94
163
|
let start = 0;
|
|
95
164
|
|
|
96
165
|
while (start < previousContent.length && start < currentContent.length && previousContent[start] === currentContent[start]) {
|
|
@@ -114,7 +183,9 @@ function stash ({ pop = false, list = false } = {}) {
|
|
|
114
183
|
|
|
115
184
|
if (insCont.length > 0) ops.push({ type: 'insert', position: start, content: insCont });
|
|
116
185
|
|
|
117
|
-
if (ops.length > 0)
|
|
186
|
+
if (ops.length > 0) {
|
|
187
|
+
stashChanges[file] = ops;
|
|
188
|
+
}
|
|
118
189
|
}
|
|
119
190
|
}
|
|
120
191
|
|
|
@@ -124,50 +195,38 @@ function stash ({ pop = false, list = false } = {}) {
|
|
|
124
195
|
}
|
|
125
196
|
}
|
|
126
197
|
|
|
127
|
-
if (Object.keys(stashChanges).length === 0)
|
|
128
|
-
return 'No local changes to stash.';
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (!fs.existsSync(cachePath)) fs.mkdirSync(cachePath, { recursive: true });
|
|
198
|
+
if (Object.keys(stashChanges).length === 0) return 'No local changes to stash.';
|
|
132
199
|
|
|
133
200
|
const timestamp = Date.now();
|
|
201
|
+
const newStashPath = path.join(cachePath, `stash_${timestamp}`);
|
|
134
202
|
|
|
135
|
-
|
|
203
|
+
savePaginatedChanges(newStashPath, stashChanges);
|
|
136
204
|
|
|
137
|
-
if (fs.existsSync(
|
|
138
|
-
fs.
|
|
205
|
+
if (fs.existsSync(stageDir)) {
|
|
206
|
+
fs.rmSync(stageDir, { recursive: true, force: true });
|
|
139
207
|
}
|
|
140
|
-
|
|
141
208
|
checkout(artJson.active.branch, { force: true });
|
|
142
209
|
|
|
143
|
-
return `Saved working directory changes to stash_${timestamp}
|
|
210
|
+
return `Saved working directory changes to paginated stash_${timestamp} and reverted to clean state.`;
|
|
144
211
|
}
|
|
145
212
|
|
|
146
|
-
/**
|
|
147
|
-
* Wipes the stage and moves the active parent pointer if a hash is provided.
|
|
148
|
-
*/
|
|
149
|
-
|
|
150
213
|
function reset (hash) {
|
|
151
214
|
const artPath = path.join(process.cwd(), '.art');
|
|
152
|
-
const
|
|
215
|
+
const stageDir = path.join(artPath, 'stage');
|
|
153
216
|
const artJsonPath = path.join(artPath, 'art.json');
|
|
154
217
|
|
|
155
|
-
if (fs.existsSync(
|
|
156
|
-
fs.
|
|
218
|
+
if (fs.existsSync(stageDir)) {
|
|
219
|
+
fs.rmSync(stageDir, { recursive: true, force: true });
|
|
157
220
|
}
|
|
158
221
|
|
|
159
|
-
if (!hash)
|
|
160
|
-
return 'Staging area cleared.';
|
|
161
|
-
}
|
|
222
|
+
if (!hash) return 'Staging area cleared.';
|
|
162
223
|
|
|
163
224
|
const artJson = JSON.parse(fs.readFileSync(artJsonPath, 'utf8'));
|
|
164
225
|
const branch = artJson.active.branch;
|
|
165
226
|
const branchPath = path.join(artPath, 'history/local', branch);
|
|
166
227
|
const commitPath = path.join(branchPath, `${hash}.json`);
|
|
167
228
|
|
|
168
|
-
if (!fs.existsSync(commitPath)) {
|
|
169
|
-
throw new Error(`Commit ${hash} not found in branch ${branch}.`);
|
|
170
|
-
}
|
|
229
|
+
if (!fs.existsSync(commitPath)) throw new Error(`Commit ${hash} not found in branch ${branch}.`);
|
|
171
230
|
|
|
172
231
|
artJson.active.parent = hash;
|
|
173
232
|
fs.writeFileSync(artJsonPath, JSON.stringify(artJson, null, 2));
|
|
@@ -183,39 +242,24 @@ function reset (hash) {
|
|
|
183
242
|
|
|
184
243
|
checkout(branch);
|
|
185
244
|
|
|
186
|
-
return `
|
|
245
|
+
return `Branch is now at ${hash.slice(0, 7)}. Working directory updated.`;
|
|
187
246
|
}
|
|
188
247
|
|
|
189
|
-
/**
|
|
190
|
-
* Marks a file for deletion by adding a "deleteFile" entry to the stage.
|
|
191
|
-
*/
|
|
192
|
-
|
|
193
248
|
function rm (filePath) {
|
|
194
249
|
const artPath = path.join(process.cwd(), '.art');
|
|
195
|
-
const stagePath = path.join(artPath, 'stage.json');
|
|
196
250
|
const fullPath = path.join(process.cwd(), filePath);
|
|
251
|
+
const stage = getPaginatedChanges(path.join(artPath, 'stage'));
|
|
197
252
|
|
|
198
|
-
|
|
253
|
+
stage[filePath] = { type: 'deleteFile' };
|
|
254
|
+
savePaginatedChanges(path.join(artPath, 'stage'), stage);
|
|
199
255
|
|
|
200
|
-
if (fs.existsSync(
|
|
201
|
-
stage = JSON.parse(fs.readFileSync(stagePath, 'utf8'));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
stage.changes[filePath] = {
|
|
205
|
-
type: 'deleteFile'
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
fs.writeFileSync(stagePath, JSON.stringify(stage, null, 2));
|
|
209
|
-
|
|
210
|
-
if (fs.existsSync(fullPath)) {
|
|
211
|
-
fs.unlinkSync(fullPath);
|
|
212
|
-
}
|
|
256
|
+
if (fs.existsSync(fullPath)) fs.unlinkSync(fullPath);
|
|
213
257
|
|
|
214
258
|
return `File ${filePath} marked for removal.`;
|
|
215
259
|
}
|
|
216
260
|
|
|
217
261
|
module.exports = {
|
|
218
|
-
__libraryVersion: '0.
|
|
262
|
+
__libraryVersion: '0.3.0',
|
|
219
263
|
__libraryAPIName: 'Caches',
|
|
220
264
|
stash,
|
|
221
265
|
reset,
|