jvcs 1.2.0 → 1.2.2
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/clone.js +2 -2
- package/package.json +1 -1
- package/readme.md +42 -0
- package/.jvcs/HEAD +0 -1
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/add.js +0 -122
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/begin.js +0 -201
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/clone.js +0 -138
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/commit.js +0 -83
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/driveUtility.js +0 -56
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/init.js +0 -60
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/log.js +0 -99
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/login.js +0 -33
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/push.js +0 -165
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/revert.js +0 -208
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/signup.js +0 -28
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/status.js +0 -160
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/unstage.js +0 -104
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/utility.js +0 -29
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/controllers/verifyOtp.js +0 -55
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/jvcs_hashcode.json +0 -62
- package/.jvcs/commits/cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3/meta.json +0 -7
- package/.jvcs/config.json +0 -9
- package/.jvcs/staging/controllers/add.js +0 -122
- package/.jvcs/staging/controllers/begin.js +0 -201
- package/.jvcs/staging/controllers/clone.js +0 -138
- package/.jvcs/staging/controllers/commit.js +0 -83
- package/.jvcs/staging/controllers/driveUtility.js +0 -56
- package/.jvcs/staging/controllers/init.js +0 -60
- package/.jvcs/staging/controllers/log.js +0 -99
- package/.jvcs/staging/controllers/login.js +0 -33
- package/.jvcs/staging/controllers/push.js +0 -165
- package/.jvcs/staging/controllers/revert.js +0 -208
- package/.jvcs/staging/controllers/signup.js +0 -28
- package/.jvcs/staging/controllers/status.js +0 -160
- package/.jvcs/staging/controllers/unstage.js +0 -104
- package/.jvcs/staging/controllers/utility.js +0 -29
- package/.jvcs/staging/controllers/verifyOtp.js +0 -55
- package/.jvcs/staging/jvcs_hashcode.json +0 -62
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
const fs = require("fs")
|
|
2
|
-
const path = require("path")
|
|
3
|
-
const chalk = require("chalk")
|
|
4
|
-
const { getDriveClient } = require("../config/drive-config")
|
|
5
|
-
const drive = getDriveClient()
|
|
6
|
-
const { getGlobalConfig, checkGlobalConfig, checkforjvcs } = require("./utility")
|
|
7
|
-
const getDirectoryStructure = require("./driveUtility")
|
|
8
|
-
const handleDbForRepo = require("../apicall/handleDbForRepo")
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
async function uploadFile(localFile, parentId,data) {
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
|
|
17
|
-
const fileName = path.basename(localFile)
|
|
18
|
-
const fileMetaData = {
|
|
19
|
-
name: fileName,
|
|
20
|
-
parents: [parentId]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const media = {
|
|
24
|
-
mimeType: "application/octet-stream",
|
|
25
|
-
body: fs.createReadStream(localFile),
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const res = await drive.files.create({
|
|
29
|
-
resource: fileMetaData,
|
|
30
|
-
media,
|
|
31
|
-
fields: "id"
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
console.log(chalk.gray(` ↳ Uploaded: ${fileName}`));
|
|
35
|
-
data.files.push({name:fileName,driveId:res.data.id,parentId:parentId,type:"file"})
|
|
36
|
-
return res.data.id;
|
|
37
|
-
}
|
|
38
|
-
catch(error) {
|
|
39
|
-
console.log(chalk.red(`Failed to upload ${filePath}: ${err.message}`));
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function uploadDirectory(localDir, parentId,data) {
|
|
44
|
-
|
|
45
|
-
const entries = fs.readdirSync(localDir, {withFileTypes: true})
|
|
46
|
-
|
|
47
|
-
for(const entry of entries) {
|
|
48
|
-
|
|
49
|
-
const entryPath = path.join(localDir,entry.name)
|
|
50
|
-
|
|
51
|
-
if(entry.isDirectory()) {
|
|
52
|
-
const folderMeta = {
|
|
53
|
-
name: entry.name,
|
|
54
|
-
mimeType: "application/vnd.google-apps.folder",
|
|
55
|
-
parents: [parentId],
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const folder = await drive.files.create({
|
|
59
|
-
resource: folderMeta,
|
|
60
|
-
fields: "id"
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
data.files.push({name:entry.name,driveId:folder.data.id,parentId:parentId,type:"folder"})
|
|
64
|
-
await uploadDirectory(entryPath,folder.data.id,data)
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
await uploadFile(entryPath,parentId,data)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async function pushCmd() {
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
|
|
76
|
-
let userFolderId,repoFolderId
|
|
77
|
-
|
|
78
|
-
if(!checkGlobalConfig()) {
|
|
79
|
-
console.log(chalk.red("No existing session found. Please login or signup."))
|
|
80
|
-
console.log(chalk.green("jvcs --help for help"))
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
let configData = getGlobalConfig()
|
|
85
|
-
|
|
86
|
-
if(!configData) {
|
|
87
|
-
console.log(chalk.red("No existing session found. Please login or signup."))
|
|
88
|
-
console.log(chalk.green("jvcs --help for help"))
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if(!checkforjvcs()) {
|
|
93
|
-
console.log(chalk.red("Repository is not initialized or is deleted. Please create it."))
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const cwd = process.cwd()
|
|
98
|
-
const jvcsDir = path.join(cwd,".jvcs")
|
|
99
|
-
const commitDir = path.join(jvcsDir,"commits")
|
|
100
|
-
const reponame = path.basename(process.cwd())
|
|
101
|
-
|
|
102
|
-
if(!fs.existsSync(commitDir)) {
|
|
103
|
-
console.log(chalk.yellow("No commits to push"))
|
|
104
|
-
return
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// storing the name of commit folders
|
|
108
|
-
const commitFolders = fs.readdirSync(commitDir, {withFileTypes: true}).filter((e)=> e.isDirectory()).map((e)=> e.name)
|
|
109
|
-
if(commitFolders.length === 0) {
|
|
110
|
-
console.log(chalk.yellow('No commits to push'))
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
console.log(chalk.blue("Pushing commits of ",reponame," to cloud storage..."))
|
|
115
|
-
|
|
116
|
-
const Content = []
|
|
117
|
-
for(const commitId of commitFolders) {
|
|
118
|
-
let data = {}
|
|
119
|
-
data.files = []
|
|
120
|
-
data.uuid = commitId
|
|
121
|
-
const commitFolder = path.join(commitDir,commitId)
|
|
122
|
-
const metaPath = path.join(commitFolder,"meta.json")
|
|
123
|
-
|
|
124
|
-
if(!fs.existsSync(metaPath)) {
|
|
125
|
-
console.log(chalk.yellow(`Skipping ${commitId} (no meta.json found)`));
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const metaData = JSON.parse(fs.readFileSync(metaPath,"utf-8"))
|
|
130
|
-
const { author, message, timeStamp } = metaData;
|
|
131
|
-
|
|
132
|
-
console.log(chalk.green(`\n Uploading commit:`));
|
|
133
|
-
console.log(chalk.gray(` id: ${commitId}`));
|
|
134
|
-
console.log(chalk.gray(` message: ${message}`));
|
|
135
|
-
console.log(chalk.gray(` author: ${author}`));
|
|
136
|
-
console.log(chalk.gray(` time: ${timeStamp}`));
|
|
137
|
-
|
|
138
|
-
const folderStructure = await getDirectoryStructure(configData.username,reponame,commitId)
|
|
139
|
-
const driveCommitId = folderStructure.commitFolderId;
|
|
140
|
-
repoFolderId = folderStructure.repoFolderId;
|
|
141
|
-
userFolderId = folderStructure.userFolderId;
|
|
142
|
-
const commitAlreadyExists = folderStructure.commitAlreadyExists;
|
|
143
|
-
|
|
144
|
-
if (commitAlreadyExists) {
|
|
145
|
-
console.log(chalk.yellow(`Skipping ${commitId} (already uploaded)`));
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
await uploadDirectory(commitFolder,driveCommitId,data)
|
|
150
|
-
console.log(chalk.green(`Commit ${commitId} uploaded successfully!`));
|
|
151
|
-
Content.push(data)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
console.log(chalk.bold.green("\nAll commits pushed successfully!"));
|
|
155
|
-
|
|
156
|
-
// database call for creating/updating an repository
|
|
157
|
-
await handleDbForRepo(reponame,repoFolderId,userFolderId,Content,configData.token)
|
|
158
|
-
}
|
|
159
|
-
catch(error) {
|
|
160
|
-
console.log(chalk.red.bold("\nPush Failed"));
|
|
161
|
-
console.error(chalk.red(error.stack || error.message || error));
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
module.exports = pushCmd
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const chalk = require("chalk");
|
|
4
|
-
const { checkGlobalConfig, getGlobalConfig, checkforjvcs } = require("./utility");
|
|
5
|
-
const { getDriveClient } = require("../config/drive-config");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function copyDir(targetCommitFolder, destDir=process.cwd()) {
|
|
9
|
-
|
|
10
|
-
const entries = fs.readdirSync(targetCommitFolder, {withFileTypes: true})
|
|
11
|
-
|
|
12
|
-
for(const entry of entries) {
|
|
13
|
-
|
|
14
|
-
if (entry.name === ".jvcs") continue;
|
|
15
|
-
|
|
16
|
-
const srcpath = path.join(targetCommitFolder,entry.name)
|
|
17
|
-
const destpath = path.join(destDir,entry.name)
|
|
18
|
-
|
|
19
|
-
if(entry.isDirectory()) {
|
|
20
|
-
fs.mkdirSync(destpath, { recursive: true });
|
|
21
|
-
copyDir(srcpath, destpath);
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
if(entry.name !== "meta.json" && entry.name !== "jvcs_hashcode.json")
|
|
25
|
-
fs.copyFileSync(srcpath, destpath);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function cleanCWD() {
|
|
31
|
-
|
|
32
|
-
const cwd = process.cwd()
|
|
33
|
-
const entries = fs.readdirSync(cwd, {withFileTypes: true})
|
|
34
|
-
|
|
35
|
-
for(const entry of entries) {
|
|
36
|
-
if(entry.name === ".jvcs") continue
|
|
37
|
-
const deleteEntry = path.join(cwd,entry.name)
|
|
38
|
-
fs.rmSync(deleteEntry, {recursive: true, force: true})
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function buildCommitMap(commitFolder) {
|
|
43
|
-
|
|
44
|
-
const map = {}
|
|
45
|
-
const dirs = fs.readdirSync(commitFolder)
|
|
46
|
-
for(const dir of dirs) {
|
|
47
|
-
const metaPath = path.join(commitFolder,dir,"meta.json")
|
|
48
|
-
if(fs.existsSync(metaPath)) {
|
|
49
|
-
const data = JSON.parse(fs.readFileSync(metaPath,"utf-8"))
|
|
50
|
-
map[dir] = data.parentId
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return map
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function getCommitsToDelete(commitFolder,currentCommit,targetCommit) {
|
|
58
|
-
|
|
59
|
-
const commitMap = buildCommitMap(commitFolder)
|
|
60
|
-
console.log("Commit Map:", commitMap); // 👈 debug log
|
|
61
|
-
const toDelete = []
|
|
62
|
-
|
|
63
|
-
while(currentCommit && currentCommit !== targetCommit) {
|
|
64
|
-
toDelete.push(currentCommit)
|
|
65
|
-
currentCommit = commitMap[currentCommit] || null
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return toDelete
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function deleteLocalCommits(commitDir,Ids) {
|
|
72
|
-
|
|
73
|
-
for(const id of Ids) {
|
|
74
|
-
const p = path.join(commitDir,id)
|
|
75
|
-
fs.rmSync(p, {recursive: true, force: true})
|
|
76
|
-
console.log(chalk.red(`Deleted local commit ${id}`))
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async function deleteCommitsFromDrive(ids) {
|
|
81
|
-
|
|
82
|
-
const drive = getDriveClient();
|
|
83
|
-
|
|
84
|
-
if (!drive) {
|
|
85
|
-
console.log(chalk.red("Drive client not initialized. Please re-authenticate."));
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
let folderName = null
|
|
90
|
-
try {
|
|
91
|
-
for(const id of ids) {
|
|
92
|
-
folderName = `commit_${id}`
|
|
93
|
-
|
|
94
|
-
const res = await drive.files.list({
|
|
95
|
-
q: `name='${folderName}' and trashed=false`,
|
|
96
|
-
fields: "files(id,name)"
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
if(res.data.files.length > 0) {
|
|
100
|
-
const fileId = res.data.files[0].id;
|
|
101
|
-
await drive.files.delete({fileId})
|
|
102
|
-
console.log(chalk.red(`Deleted folder ${folderName} from remote`));
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
console.log(chalk.gray(`Drive folder ${folderName} not found.`));
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
catch(error) {
|
|
110
|
-
console.log(chalk.red(`Failed to delete ${folderName} from remote: ${error.message}`));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async function deleteCommitsFromDatabase(configData,toDelete,reponame) {
|
|
115
|
-
|
|
116
|
-
try {
|
|
117
|
-
|
|
118
|
-
const response = await fetch("http://localhost:3000/deleteCommit", {
|
|
119
|
-
method: "POST",
|
|
120
|
-
headers: {
|
|
121
|
-
'Content-Type': 'application/json'
|
|
122
|
-
},
|
|
123
|
-
body: JSON.stringify({token:configData.token,email:configData.email,username:configData.username,toDelete,reponame})
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
const data = await response.json()
|
|
127
|
-
|
|
128
|
-
if(data.status === true) {
|
|
129
|
-
console.log(chalk.green("Removed previous commits from DB"))
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
console.log(chalk.red(data.message))
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
catch(error) {
|
|
136
|
-
console.log(chalk.red(error || error.message))
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
async function revertCmd(commitId) {
|
|
141
|
-
|
|
142
|
-
if(!checkGlobalConfig()) {
|
|
143
|
-
console.log(chalk.red("No existing session found. Please login or signup."));
|
|
144
|
-
console.log(chalk.green("jvcs --help for help"));
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const configData = getGlobalConfig();
|
|
149
|
-
if(!configData) {
|
|
150
|
-
console.log(chalk.red("No existing session found. Please login or signup."));
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if(!checkforjvcs()) {
|
|
155
|
-
console.log(chalk.red("Repository is not initialized or is deleted."));
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// actual implementation
|
|
160
|
-
const cwd = process.cwd()
|
|
161
|
-
const jvcsDir = path.join(cwd,".jvcs")
|
|
162
|
-
const commitFolder = path.join(jvcsDir,"commits")
|
|
163
|
-
const targetCommitFolder = path.join(commitFolder,commitId)
|
|
164
|
-
const headFile = path.join(jvcsDir,"HEAD")
|
|
165
|
-
|
|
166
|
-
if(!fs.existsSync(jvcsDir)) {
|
|
167
|
-
console.log(chalk.red("Repository is not initialized or is deleted."));
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if(!fs.existsSync(commitFolder)) {
|
|
172
|
-
console.log(chalk.red("You have made no commits yet. Revert not possible"))
|
|
173
|
-
return
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if(!fs.existsSync(targetCommitFolder)) {
|
|
177
|
-
console.log(chalk.red("No commit exists with commit Id : ",commitId))
|
|
178
|
-
return
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const currentHead = fs.readFileSync(headFile,"utf-8").trim()
|
|
183
|
-
|
|
184
|
-
if(currentHead === commitId) {
|
|
185
|
-
console.log(chalk.green("HEAD is already at the given commit"))
|
|
186
|
-
return
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// get commits to delete
|
|
190
|
-
const toDelete = getCommitsToDelete(commitFolder,currentHead,commitId)
|
|
191
|
-
|
|
192
|
-
// clear the current working directory except .jvcs
|
|
193
|
-
cleanCWD()
|
|
194
|
-
|
|
195
|
-
// copy the content of commit to cwd
|
|
196
|
-
copyDir(targetCommitFolder)
|
|
197
|
-
|
|
198
|
-
fs.writeFileSync(headFile,commitId,"utf-8")
|
|
199
|
-
console.log(chalk.green(`HEAD moved to ${commitId}`));
|
|
200
|
-
|
|
201
|
-
deleteLocalCommits(commitFolder,toDelete)
|
|
202
|
-
await deleteCommitsFromDrive(toDelete)
|
|
203
|
-
await deleteCommitsFromDatabase(configData,toDelete,path.basename(process.cwd()))
|
|
204
|
-
|
|
205
|
-
console.log(chalk.green(`Successfully reverted to commit ${commitId}`));
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
module.exports = revertCmd
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
const chalk = require("chalk")
|
|
2
|
-
const verifyOtp = require("./verifyOtp")
|
|
3
|
-
async function signup(signupData) {
|
|
4
|
-
|
|
5
|
-
const response = await fetch("http://localhost:3000/signup", {
|
|
6
|
-
method: "POST",
|
|
7
|
-
headers: {
|
|
8
|
-
'Content-Type': 'application/json'
|
|
9
|
-
},
|
|
10
|
-
credentials: "include",
|
|
11
|
-
body: JSON.stringify(signupData)
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
const data = await response.json()
|
|
15
|
-
|
|
16
|
-
if(data.status === true) {
|
|
17
|
-
console.log(chalk.green(data.message))
|
|
18
|
-
await verifyOtp(signupData)
|
|
19
|
-
}
|
|
20
|
-
else if(data.status == "user") {
|
|
21
|
-
console.log(chalk.yellow(data.message))
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
throw new Error(data.message)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
module.exports = signup
|
|
@@ -1,160 +0,0 @@
|
|
|
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
|
-
|
|
10
|
-
const fs = require("fs");
|
|
11
|
-
const path = require("path");
|
|
12
|
-
const crypto = require("crypto");
|
|
13
|
-
const chalk = require("chalk");
|
|
14
|
-
const { checkGlobalConfig, getGlobalConfig, checkforjvcs } = require("./utility");
|
|
15
|
-
|
|
16
|
-
// normalize relative path to use forward slashes for consistent comparisons
|
|
17
|
-
function normalizeRel(p) {
|
|
18
|
-
return p.split(path.sep).join("/")
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function hashfile(filepath) {
|
|
22
|
-
try {
|
|
23
|
-
const data = fs.readFileSync(filepath)
|
|
24
|
-
return crypto.createHash("sha256").update(data).digest("hex")
|
|
25
|
-
}
|
|
26
|
-
catch(error) {
|
|
27
|
-
// return null
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
function getAllFiles(dir, rootDir=dir, collected=[]) {
|
|
33
|
-
|
|
34
|
-
if (!fs.existsSync(dir)) return collected;
|
|
35
|
-
|
|
36
|
-
const entries = fs.readdirSync(dir,{withFileTypes:true})
|
|
37
|
-
|
|
38
|
-
for(const entry of entries) {
|
|
39
|
-
const fullPath = path.join(dir,entry.name)
|
|
40
|
-
const rel = normalizeRel(path.relative(rootDir,fullPath))
|
|
41
|
-
|
|
42
|
-
if(entry.isDirectory() && (entry.name === ".jvcs" || entry.name === "node_modules"))
|
|
43
|
-
continue;
|
|
44
|
-
|
|
45
|
-
if(entry.isFile() && (entry.name === "meta.json" || entry.name === "jvcs_hashcode.json"))
|
|
46
|
-
continue;
|
|
47
|
-
|
|
48
|
-
if(entry.isFile()) {
|
|
49
|
-
collected.push(rel);
|
|
50
|
-
}
|
|
51
|
-
else if(entry.isDirectory()) {
|
|
52
|
-
getAllFiles(fullPath, rootDir, collected);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return collected
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async function statusCmd() {
|
|
61
|
-
|
|
62
|
-
if(!checkGlobalConfig()) {
|
|
63
|
-
console.log(chalk.red("No existing session found. Please login or signup."));
|
|
64
|
-
console.log(chalk.green("jvcs --help for help"));
|
|
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;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if(!checkforjvcs()) {
|
|
75
|
-
console.log(chalk.red("Repository is not initialized or is deleted."));
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const cwd = process.cwd()
|
|
80
|
-
const jvcsDir = path.join(cwd,".jvcs")
|
|
81
|
-
const commitDir = path.join(jvcsDir,"commits")
|
|
82
|
-
const stagingDir = path.join(jvcsDir,"staging")
|
|
83
|
-
const headFile = path.join(jvcsDir, "HEAD");
|
|
84
|
-
|
|
85
|
-
if(!fs.existsSync(jvcsDir)) {
|
|
86
|
-
console.log(chalk.red("No repository exists. Please create one using 'jvcs init'"))
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// collect files (all relative to cwd, normalized)
|
|
91
|
-
const cwdFiles = getAllFiles(cwd, cwd, []);
|
|
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))
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// use Sets for fast looku
|
|
104
|
-
const committedSet = new Set(commitedFiles);
|
|
105
|
-
const stagedSet = new Set(stagedFiles);
|
|
106
|
-
|
|
107
|
-
// Untracked: present in cwd but not in staging or commits
|
|
108
|
-
const untracked = cwdFiles.filter(f => !stagedSet.has(f) && !committedSet.has(f));
|
|
109
|
-
|
|
110
|
-
// Changes to be committed: present in staging but not in (any) commits
|
|
111
|
-
const toBeCommitted = stagedFiles.filter(f => !committedSet.has(f));
|
|
112
|
-
|
|
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)
|
|
117
|
-
|
|
118
|
-
if(!fs.existsSync(cwdFilePath) || !fs.existsSync(stagedFilePath))
|
|
119
|
-
return false
|
|
120
|
-
|
|
121
|
-
const cwdHash = hashfile(cwdFilePath)
|
|
122
|
-
const stagingHash = hashfile(stagedFilePath)
|
|
123
|
-
|
|
124
|
-
return cwdHash !== stagingHash
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
// output
|
|
129
|
-
console.log(chalk.bold.blue(`\nOn branch: main (default)`));
|
|
130
|
-
|
|
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 {
|
|
136
|
-
console.log(chalk.gray("\tNo changes added to commit"));
|
|
137
|
-
}
|
|
138
|
-
|
|
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 {
|
|
144
|
-
console.log(chalk.gray("\tNo modified files detected"));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
console.log(chalk.bold.red("\nUntracked files (files that are not staged or commited):"));
|
|
148
|
-
if(untracked.length > 0) {
|
|
149
|
-
untracked.forEach(f => console.log(chalk.red(`\t${f}`)));
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
console.log(chalk.gray("\tNo untracked files"));
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
console.log(chalk.gray("\n(use 'jvcs add <file>' to stage changes)"));
|
|
156
|
-
console.log(chalk.gray("(use 'jvcs commit -m \"message\"' to commit changes)"));
|
|
157
|
-
console.log(chalk.gray("(use 'jvcs unstage <file>/<folder> to unstage a file/folder')"))
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
module.exports = statusCmd
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
const fs = require("fs").promises;
|
|
2
|
-
const fssync = require("fs");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
const chalk = require("chalk");
|
|
5
|
-
const { checkGlobalConfig, getGlobalConfig, checkforjvcs } = require("./utility");
|
|
6
|
-
|
|
7
|
-
function removeHashesForFolder(hashData,folderPath) {
|
|
8
|
-
|
|
9
|
-
for(const key of Object.keys(hashData)) {
|
|
10
|
-
if(key.startsWith(folderPath+path.sep)) {
|
|
11
|
-
delete hashData[key]
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async function unstageCmd(paths) {
|
|
17
|
-
|
|
18
|
-
if(!paths || paths.length === 0) {
|
|
19
|
-
console.log(chalk.yellow("Please specify files or folders to unstage."));
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if(!checkGlobalConfig()) {
|
|
24
|
-
console.log(chalk.red("No existing session found. Please login or signup."));
|
|
25
|
-
console.log(chalk.green("jvcs --help for help"));
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const configData = getGlobalConfig();
|
|
30
|
-
if(!configData) {
|
|
31
|
-
console.log(chalk.red("No existing session found. Please login or signup."));
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if(!checkforjvcs()) {
|
|
36
|
-
console.log(chalk.red("Repository is not initialized or is deleted."));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const repoPath = path.join(process.cwd(), ".jvcs");
|
|
41
|
-
const stagingPath = path.join(repoPath, "staging");
|
|
42
|
-
const hashPath = path.join(stagingPath, "jvcs_hashcode.json");
|
|
43
|
-
|
|
44
|
-
if(!fssync.existsSync(stagingPath)) {
|
|
45
|
-
console.log(chalk.yellow("Nothing is staged yet."));
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const stagedItems = fssync.readdirSync(stagingPath).filter((item)=> item !== "jvcs_hashcode.json")
|
|
50
|
-
if(stagedItems.length === 0) {
|
|
51
|
-
console.log(chalk.yellow("Staging area is empty. Nothing to unstage."));
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let hashData = {};
|
|
56
|
-
if(fssync.existsSync(hashPath)) {
|
|
57
|
-
hashData = JSON.parse(await fs.readFile(hashPath, "utf-8"));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if(paths.length === 1 && paths[0] === ".") {
|
|
61
|
-
await fs.rm(stagingPath, {recursive: true, force: true})
|
|
62
|
-
await fs.mkdir(stagingPath, {recursive: true})
|
|
63
|
-
console.log(chalk.cyan("Unstaged all files and folders."));
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const targets = paths.map((p) => path.resolve(process.cwd(), p));
|
|
68
|
-
|
|
69
|
-
for(const target of targets) {
|
|
70
|
-
|
|
71
|
-
const stagedTarget = path.join(stagingPath, path.relative(process.cwd(),target))
|
|
72
|
-
|
|
73
|
-
if(!fssync.existsSync(stagedTarget)) {
|
|
74
|
-
console.log(chalk.yellow(`Not found in staging: ${path.relative(process.cwd(), target)}`));
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const stats = await fs.stat(stagedTarget);
|
|
79
|
-
|
|
80
|
-
if(stats.isDirectory()) {
|
|
81
|
-
await fs.rm(stagedTarget, {recursive: true, force: true})
|
|
82
|
-
removeHashesForFolder(hashData,path.relative(process.cwd(),target))
|
|
83
|
-
console.log(chalk.cyan(`Unstaged folder: ${path.relative(process.cwd(), target)}`));
|
|
84
|
-
}
|
|
85
|
-
else if(stats.isFile()) {
|
|
86
|
-
await fs.rm(stagedTarget)
|
|
87
|
-
delete hashData[path.relative(process.cwd(),target)]
|
|
88
|
-
console.log(chalk.green(`Unstaged file: ${path.relative(process.cwd(), target)}`));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if(Object.keys(hashData).length === 0) {
|
|
94
|
-
if(fssync.existsSync(hashPath)) {
|
|
95
|
-
await fs.rm(hashPath)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
await fs.writeFile(hashPath,JSON.stringify(hashData,null,2))
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
module.exports = unstageCmd
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
const fs = require("fs")
|
|
2
|
-
const path = require("path")
|
|
3
|
-
|
|
4
|
-
const config = path.join(require("os").homedir(),".jvcs","config.json")
|
|
5
|
-
|
|
6
|
-
function checkGlobalConfig() {
|
|
7
|
-
return fs.existsSync(config)
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function getGlobalConfig() {
|
|
11
|
-
if(checkGlobalConfig()) {
|
|
12
|
-
const configData = JSON.parse(fs.readFileSync(config,"utf-8"))
|
|
13
|
-
if(configData.username && configData.email && configData.token)
|
|
14
|
-
return configData
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return null
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function checkforjvcs() {
|
|
21
|
-
const jvcsPath = path.join(process.cwd(),".jvcs")
|
|
22
|
-
return fs.existsSync(jvcsPath)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
module.exports = {
|
|
26
|
-
checkGlobalConfig,
|
|
27
|
-
getGlobalConfig,
|
|
28
|
-
checkforjvcs
|
|
29
|
-
}
|