jvcs 1.7.3 → 1.7.4
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/controllers/status.js +82 -138
- package/package.json +1 -1
package/controllers/status.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
// Untracked files
|
|
2
|
+
// Files that exist in your working directory (project folder) but have never been added to staging or committed.
|
|
3
|
+
|
|
4
|
+
// Changes to be committed
|
|
5
|
+
// Files that are in the staging area (.jvcs/staging) — meaning, you’ve already added them using jvcs add, but haven’t committed yet.
|
|
6
|
+
|
|
7
|
+
// Changes not staged for commit
|
|
8
|
+
// Files that were already added to staging earlier, but you modified them again in your working directory after staging — i.e., the staged copy and working copy are different.
|
|
9
|
+
|
|
1
10
|
const fs = require("fs");
|
|
2
11
|
const path = require("path");
|
|
3
12
|
const crypto = require("crypto");
|
|
4
13
|
const chalk = require("chalk");
|
|
5
|
-
const { getGlobalConfig, checkforjvcs } = require("./utility");
|
|
6
|
-
const { minimatch } = require("minimatch");
|
|
14
|
+
const { checkGlobalConfig, getGlobalConfig, checkforjvcs } = require("./utility");
|
|
7
15
|
|
|
8
16
|
// normalize relative path to use forward slashes for consistent comparisons
|
|
9
17
|
function normalizeRel(p) {
|
|
@@ -15,51 +23,35 @@ function hashfile(filepath) {
|
|
|
15
23
|
const data = fs.readFileSync(filepath)
|
|
16
24
|
return crypto.createHash("sha256").update(data).digest("hex")
|
|
17
25
|
}
|
|
18
|
-
catch(error) {
|
|
19
|
-
return null
|
|
26
|
+
catch (error) {
|
|
27
|
+
// return null
|
|
20
28
|
}
|
|
21
29
|
}
|
|
22
30
|
|
|
23
|
-
function loadIgnorePatterns() {
|
|
24
|
-
const ignorePath = path.join(process.cwd(), ".jvcsignore");
|
|
25
|
-
if(!fs.existsSync(ignorePath)) return [];
|
|
26
|
-
|
|
27
|
-
const content = fs.readFileSync(ignorePath, "utf-8");
|
|
28
|
-
return content
|
|
29
|
-
.split(/[\n,]+/)
|
|
30
|
-
.map(line => line.trim())
|
|
31
|
-
.filter(line => line.length > 0 && !line.startsWith("#"));
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function isIgnored(relativePath, ignorePatterns = []) {
|
|
35
|
-
return ignorePatterns.some(pattern =>
|
|
36
|
-
minimatch(relativePath, pattern, { dot: true })
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
31
|
|
|
40
|
-
function getAllFiles(dir, rootDir=dir, collected=[]) {
|
|
32
|
+
function getAllFiles(dir, rootDir = dir, collected = []) {
|
|
41
33
|
|
|
42
34
|
if (!fs.existsSync(dir)) return collected;
|
|
43
35
|
|
|
44
|
-
const entries = fs.readdirSync(dir,{withFileTypes:true})
|
|
36
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true })
|
|
45
37
|
|
|
46
|
-
for(const entry of entries) {
|
|
47
|
-
const fullPath = path.join(dir,entry.name)
|
|
48
|
-
const rel = normalizeRel(path.relative(rootDir,fullPath))
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
const fullPath = path.join(dir, entry.name)
|
|
40
|
+
const rel = normalizeRel(path.relative(rootDir, fullPath))
|
|
49
41
|
|
|
50
|
-
if(entry.isDirectory() && (entry.name === ".jvcs" || entry.name === "
|
|
42
|
+
if (entry.isDirectory() && (entry.name === ".jvcs" || entry.name === "node_modules"))
|
|
51
43
|
continue;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if(entry.isFile() && (entry.name === "meta.json" || entry.name === "jvcs_hashcode.json" || entry.name === ".jvcsignore"))
|
|
44
|
+
|
|
45
|
+
if (entry.isFile() && (entry.name === "meta.json" || entry.name === "jvcs_hashcode.json"))
|
|
55
46
|
continue;
|
|
56
|
-
|
|
57
|
-
if(entry.isFile()) {
|
|
47
|
+
|
|
48
|
+
if (entry.isFile()) {
|
|
58
49
|
collected.push(rel);
|
|
59
50
|
}
|
|
60
|
-
else if(entry.isDirectory()) {
|
|
51
|
+
else if (entry.isDirectory()) {
|
|
61
52
|
getAllFiles(fullPath, rootDir, collected);
|
|
62
53
|
}
|
|
54
|
+
|
|
63
55
|
}
|
|
64
56
|
|
|
65
57
|
return collected
|
|
@@ -67,150 +59,102 @@ function getAllFiles(dir, rootDir=dir, collected=[]) {
|
|
|
67
59
|
|
|
68
60
|
async function statusCmd() {
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
if(!configData) {
|
|
62
|
+
if (!checkGlobalConfig()) {
|
|
72
63
|
console.log(chalk.red("No existing session found. Please login or signup."));
|
|
73
64
|
console.log(chalk.green("jvcs --help for help"));
|
|
74
|
-
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const configData = getGlobalConfig();
|
|
69
|
+
if (!configData) {
|
|
70
|
+
console.log(chalk.red("No existing session found. Please login or signup."));
|
|
71
|
+
return;
|
|
75
72
|
}
|
|
76
73
|
|
|
77
|
-
if(!checkforjvcs()) {
|
|
78
|
-
console.log(chalk.red("Repository is not initialized or is deleted.
|
|
79
|
-
|
|
74
|
+
if (!checkforjvcs()) {
|
|
75
|
+
console.log(chalk.red("Repository is not initialized or is deleted."));
|
|
76
|
+
return;
|
|
80
77
|
}
|
|
81
78
|
|
|
82
79
|
const cwd = process.cwd()
|
|
83
|
-
const jvcsDir = path.join(cwd,".jvcs")
|
|
84
|
-
const commitDir = path.join(jvcsDir,"commits")
|
|
85
|
-
const stagingDir = path.join(jvcsDir,"staging")
|
|
80
|
+
const jvcsDir = path.join(cwd, ".jvcs")
|
|
81
|
+
const commitDir = path.join(jvcsDir, "commits")
|
|
82
|
+
const stagingDir = path.join(jvcsDir, "staging")
|
|
86
83
|
const headFile = path.join(jvcsDir, "HEAD");
|
|
87
84
|
|
|
88
|
-
if(!fs.existsSync(jvcsDir)) {
|
|
85
|
+
if (!fs.existsSync(jvcsDir)) {
|
|
89
86
|
console.log(chalk.red("No repository exists. Please create one using 'jvcs init'"))
|
|
90
|
-
|
|
87
|
+
return
|
|
91
88
|
}
|
|
92
89
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// 1. Collect hashes for CWD
|
|
90
|
+
// collect files (all relative to cwd, normalized)
|
|
96
91
|
const cwdFiles = getAllFiles(cwd, cwd, []);
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
92
|
+
const stagedFiles = fs.existsSync(stagingDir) ? getAllFiles(stagingDir, stagingDir, []).map(f => normalizeRel(f)) : [];
|
|
93
|
+
let commitedFiles = []
|
|
94
|
+
if (fs.existsSync(commitDir)) {
|
|
95
|
+
const commits = fs.readdirSync(commitDir)
|
|
96
|
+
if (commits.length > 0) {
|
|
97
|
+
const lastCommit = `${fs.readFileSync(headFile, "utf-8").trim()}`;
|
|
98
|
+
const commitPath = path.join(commitDir, lastCommit);
|
|
99
|
+
commitedFiles = getAllFiles(commitPath, commitPath, []).map(f => normalizeRel(f))
|
|
102
100
|
}
|
|
103
101
|
}
|
|
104
102
|
|
|
105
|
-
//
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
const headFileContent = fs.readFileSync(headFile, "utf-8").trim();
|
|
109
|
-
if (headFileContent) {
|
|
110
|
-
const commitPath = path.join(commitDir, headFileContent);
|
|
111
|
-
if (fs.existsSync(commitPath)) {
|
|
112
|
-
const commitFiles = getAllFiles(commitPath, commitPath, []);
|
|
113
|
-
for (const f of commitFiles) {
|
|
114
|
-
const h = hashfile(path.join(commitPath, f));
|
|
115
|
-
if (h) headMap.set(f, h);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
103
|
+
// use Sets for fast looku
|
|
104
|
+
const committedSet = new Set(commitedFiles);
|
|
105
|
+
const stagedSet = new Set(stagedFiles);
|
|
120
106
|
|
|
121
|
-
//
|
|
122
|
-
const
|
|
123
|
-
const hashPath = path.join(stagingDir, "jvcs_hashcode.json");
|
|
124
|
-
if (fs.existsSync(hashPath)) {
|
|
125
|
-
try {
|
|
126
|
-
const data = JSON.parse(fs.readFileSync(hashPath, "utf-8"));
|
|
127
|
-
for (const [key, val] of Object.entries(data)) {
|
|
128
|
-
stagingMap.set(normalizeRel(key), val.hash);
|
|
129
|
-
}
|
|
130
|
-
} catch(e) {}
|
|
131
|
-
} else {
|
|
132
|
-
// Fallback
|
|
133
|
-
if (fs.existsSync(stagingDir)) {
|
|
134
|
-
const stFiles = getAllFiles(stagingDir, stagingDir, []);
|
|
135
|
-
for(const f of stFiles) {
|
|
136
|
-
const h = hashfile(path.join(stagingDir, f));
|
|
137
|
-
if (h) stagingMap.set(f, h);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
107
|
+
// Untracked: present in cwd but not in staging or commits
|
|
108
|
+
const untracked = cwdFiles.filter(f => !stagedSet.has(f) && !committedSet.has(f));
|
|
141
109
|
|
|
142
|
-
//
|
|
110
|
+
// Changes to be committed: present in staging but not in (any) commits
|
|
111
|
+
const toBeCommitted = stagedFiles.filter(f => !committedSet.has(f));
|
|
143
112
|
|
|
144
|
-
//
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
untracked.push(f);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
113
|
+
// Changes not staged for commit: present in staging and in cwd, but changed in cwd compared to staged copy
|
|
114
|
+
const modified = stagedFiles.filter((file) => {
|
|
115
|
+
const cwdFilePath = path.join(process.cwd(), file)
|
|
116
|
+
const stagedFilePath = path.join(stagingDir, file)
|
|
151
117
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const stagedModified = [];
|
|
155
|
-
const stagedDeleted = [];
|
|
118
|
+
if (!fs.existsSync(cwdFilePath) || !fs.existsSync(stagedFilePath))
|
|
119
|
+
return false
|
|
156
120
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
stagedAdded.push(f);
|
|
160
|
-
} else if (headMap.get(f) !== sHash) {
|
|
161
|
-
stagedModified.push(f);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
for (const f of headMap.keys()) {
|
|
165
|
-
if (!stagingMap.has(f)) {
|
|
166
|
-
stagedDeleted.push(f);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
121
|
+
const cwdHash = hashfile(cwdFilePath)
|
|
122
|
+
const stagingHash = hashfile(stagedFilePath)
|
|
169
123
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const unstagedDeleted = [];
|
|
124
|
+
return cwdHash !== stagingHash
|
|
125
|
+
})
|
|
173
126
|
|
|
174
|
-
for (const [f, sHash] of stagingMap.entries()) {
|
|
175
|
-
if (!cwdMap.has(f)) {
|
|
176
|
-
unstagedDeleted.push(f);
|
|
177
|
-
} else if (cwdMap.get(f) !== sHash) {
|
|
178
|
-
unstagedModified.push(f);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
127
|
|
|
182
|
-
//
|
|
128
|
+
// output
|
|
183
129
|
console.log(chalk.bold.blue(`\nOn branch: main (default)`));
|
|
184
130
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
stagedDeleted.forEach(f => console.log(chalk.green(`\tdeleted: ${f}`)));
|
|
191
|
-
} else {
|
|
131
|
+
console.log(chalk.bold.green("\nChanges to be committed (files that are staged but not commited):"));
|
|
132
|
+
if (toBeCommitted.length > 0) {
|
|
133
|
+
toBeCommitted.forEach(f => console.log(chalk.green(`\t${f}`)));
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
192
136
|
console.log(chalk.gray("\tNo changes added to commit"));
|
|
193
137
|
}
|
|
194
138
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
} else {
|
|
139
|
+
console.log(chalk.bold.yellow("\nChanges not staged for commit (files that are modified after adding to staging area):"));
|
|
140
|
+
if (modified.length > 0) {
|
|
141
|
+
modified.forEach(f => console.log(chalk.yellow(`\t${f}`)));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
201
144
|
console.log(chalk.gray("\tNo modified files detected"));
|
|
202
145
|
}
|
|
203
146
|
|
|
204
|
-
console.log(chalk.bold.red("\nUntracked files:"));
|
|
147
|
+
console.log(chalk.bold.red("\nUntracked files (files that are not staged or commited):"));
|
|
205
148
|
if (untracked.length > 0) {
|
|
206
149
|
untracked.forEach(f => console.log(chalk.red(`\t${f}`)));
|
|
207
|
-
}
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
208
152
|
console.log(chalk.gray("\tNo untracked files"));
|
|
209
153
|
}
|
|
210
154
|
|
|
211
155
|
console.log(chalk.gray("\n(use 'jvcs add <file>' to stage changes)"));
|
|
212
156
|
console.log(chalk.gray("(use 'jvcs commit -m \"message\"' to commit changes)"));
|
|
213
|
-
console.log(chalk.gray("(use 'jvcs unstage <file>/<folder>
|
|
157
|
+
console.log(chalk.gray("(use 'jvcs unstage <file>/<folder> to unstage a file/folder')"))
|
|
214
158
|
}
|
|
215
159
|
|
|
216
|
-
module.exports = statusCmd
|
|
160
|
+
module.exports = statusCmd
|