jvcs 1.0.0 → 1.0.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.
Files changed (42) hide show
  1. package/controllers/commit.js +1 -0
  2. package/controllers/unstage.js +9 -1
  3. package/package.json +1 -1
  4. package/.jvcs/HEAD +0 -1
  5. package/.jvcs/commits/292abee1-42ea-4ddf-b590-be7c98abaf45/jvcs_hashcode.json +0 -1
  6. package/.jvcs/commits/292abee1-42ea-4ddf-b590-be7c98abaf45/meta.json +0 -7
  7. package/.jvcs/commits/302af5ea-5789-4ee9-98fe-eab9308b2e27/jvcs_hashcode.json +0 -1
  8. package/.jvcs/commits/302af5ea-5789-4ee9-98fe-eab9308b2e27/meta.json +0 -7
  9. package/.jvcs/commits/376d44d4-c595-429e-b711-ae6ec7c9ef74/jvcs_hashcode.json +0 -1
  10. package/.jvcs/commits/376d44d4-c595-429e-b711-ae6ec7c9ef74/meta.json +0 -7
  11. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/add.js +0 -122
  12. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/begin.js +0 -201
  13. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/commit.js +0 -82
  14. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/init.js +0 -60
  15. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/login.js +0 -33
  16. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/pull.js +0 -98
  17. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/push.js +0 -135
  18. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/revert.js +0 -110
  19. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/signup.js +0 -28
  20. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/unstage.js +0 -96
  21. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/utility.js +0 -28
  22. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/verifyOtp.js +0 -55
  23. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/jvcs_hashcode.json +0 -50
  24. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/meta.json +0 -7
  25. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/add.js +0 -122
  26. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/begin.js +0 -201
  27. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/commit.js +0 -82
  28. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/init.js +0 -60
  29. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/login.js +0 -33
  30. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/pull.js +0 -98
  31. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/push.js +0 -135
  32. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/revert.js +0 -110
  33. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/signup.js +0 -28
  34. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/unstage.js +0 -96
  35. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/utility.js +0 -28
  36. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/verifyOtp.js +0 -55
  37. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/jvcs_hashcode.json +0 -50
  38. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/meta.json +0 -7
  39. package/.jvcs/commits/c7aa89bd-5016-4f21-8979-02e3c0a2c8ee/jvcs_hashcode.json +0 -1
  40. package/.jvcs/commits/c7aa89bd-5016-4f21-8979-02e3c0a2c8ee/meta.json +0 -7
  41. package/.jvcs/config.json +0 -9
  42. package/.jvcs/staging/jvcs_hashcode.json +0 -1
@@ -46,6 +46,7 @@ async function commitCmd(message) {
46
46
  return
47
47
  }
48
48
 
49
+
49
50
  if(!fssync.existsSync(commits)) {
50
51
  await fs.mkdir(commits)
51
52
  }
@@ -90,7 +90,15 @@ async function unstageCmd(paths) {
90
90
 
91
91
  }
92
92
 
93
- await fs.writeFile(hashPath, JSON.stringify(hashData, null, 2));
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
+
94
102
  }
95
103
 
96
104
  module.exports = unstageCmd
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jvcs",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "bin": {
5
5
  "jvcs": "./index.js"
6
6
  },
package/.jvcs/HEAD DELETED
@@ -1 +0,0 @@
1
- c7aa89bd-5016-4f21-8979-02e3c0a2c8ee
@@ -1,7 +0,0 @@
1
- {
2
- "author": "jagdish",
3
- "id": "292abee1-42ea-4ddf-b590-be7c98abaf45",
4
- "message": "commit 4",
5
- "timeStamp": "2025-10-27T15:14:00.695Z",
6
- "parentId": "302af5ea-5789-4ee9-98fe-eab9308b2e27"
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "author": "jagdish",
3
- "id": "302af5ea-5789-4ee9-98fe-eab9308b2e27",
4
- "message": "commit 3",
5
- "timeStamp": "2025-10-27T15:13:40.822Z",
6
- "parentId": "484ac37d-c1a9-4ddd-8796-6e3facda1e11"
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "author": "jagdish",
3
- "id": "376d44d4-c595-429e-b711-ae6ec7c9ef74",
4
- "message": "commit 5",
5
- "timeStamp": "2025-10-27T15:14:03.635Z",
6
- "parentId": "292abee1-42ea-4ddf-b590-be7c98abaf45"
7
- }
@@ -1,122 +0,0 @@
1
- const { checkGlobalConfig, getGlobalConfig, checkforjvcs } = require("./utility")
2
- const path = require("path")
3
- const fssync = require("fs")
4
- const chalk = require("chalk")
5
- const fs = require("fs").promises
6
- const crypto = require("crypto")
7
-
8
- async function getFileHash(filepath) {
9
- const buffer = await fs.readFile(filepath)
10
- return crypto.createHash("sha256").update(buffer).digest("hex")
11
- }
12
-
13
- async function hashDirectoryRecursive(dir,hashData) {
14
-
15
- const entries = await fs.readdir(dir, {withFileTypes: true})
16
- console.log(entries)
17
-
18
- for(const entry of entries) {
19
-
20
- const fullPath = path.join(dir,entry.name)
21
- const relativePath = path.relative(process.cwd(),fullPath)
22
-
23
- if(entry.isFile()) {
24
- const hash = await getFileHash(fullPath)
25
- hashData[relativePath] = {
26
- hash,
27
- time: new Date().toISOString(),
28
- }
29
- }
30
- else if(entry.isDirectory()) {
31
- await hashDirectoryRecursive(fullPath,hashData)
32
- }
33
- }
34
- }
35
-
36
- async function addCmd(paths) {
37
-
38
- if(!paths || paths.length === 0) {
39
- console.log(chalk.yellow("Please specify files or folders to add."));
40
- return
41
- }
42
-
43
- if(!checkGlobalConfig()) {
44
- console.log(chalk.red("No existing session found. Please login or signup."))
45
- console.log(chalk.green("jvcs --help for help"))
46
- return
47
- }
48
-
49
- let configData = getGlobalConfig()
50
-
51
- if(!configData) {
52
- console.log(chalk.red("No existing session found. Please login or signup."))
53
- console.log(chalk.green("jvcs --help for help"))
54
- return
55
- }
56
-
57
- if(!checkforjvcs()) {
58
- console.log(chalk.red("Repository is not initialized or is deleted. Please create it."))
59
- return
60
- }
61
-
62
- const repoPath = path.join(process.cwd(),".jvcs")
63
- const staging = path.join(repoPath,"staging")
64
-
65
- if(!fssync.existsSync(staging))
66
- fssync.mkdirSync(staging, {recursive: true})
67
-
68
- const hashPath = path.join(staging,"jvcs_hashcode.json")
69
- let hashData = {}
70
-
71
- if(fssync.existsSync(hashPath)) {
72
- hashData = JSON.parse(await fs.readFile(hashPath,"utf-8"))
73
- }
74
-
75
- let targets = []
76
- if(paths.length === 1 && paths[0] === ".") {
77
- targets = await fs.readdir(process.cwd(),{withFileTypes: true})
78
- targets = targets.filter((target)=> target.name !== ".jvcs").map((item)=> path.resolve(process.cwd(),item.name))
79
- }
80
- else {
81
- targets = paths.map((p)=> path.resolve(process.cwd(),p))
82
- }
83
-
84
- // copying the files and folders to staging area
85
- for(const target of targets) {
86
-
87
- try {
88
-
89
- if(!fssync.existsSync(target)) {
90
- console.log(chalk.red(`Path not found: ${target}`))
91
- continue
92
- }
93
-
94
- const destination = path.join(staging,path.relative(process.cwd(),target))
95
- await fs.mkdir(path.dirname(destination), {recursive: true})
96
-
97
- const stats = await fs.stat(target)
98
-
99
- if(stats.isFile()) {
100
- await fs.copyFile(target,destination)
101
- const hash = await getFileHash(target)
102
- hashData[path.relative(process.cwd(),target)] = {
103
- hash,
104
- time: new Date().toISOString(),
105
- }
106
- console.log(chalk.green(`Added file: ${path.relative(process.cwd(), target)}`));
107
- }
108
- else if(stats.isDirectory()) {
109
- await fs.cp(target,destination,{recursive: true})
110
- await hashDirectoryRecursive(target,hashData)
111
- console.log(chalk.cyan(`Added folder: ${path.relative(process.cwd(), target)}`));
112
- }
113
- }
114
- catch(error) {
115
- console.log(chalk.red(`Unexpected error: ${error.message}`));
116
- }
117
- }
118
-
119
- await fs.writeFile(hashPath, JSON.stringify(hashData, null, 2));
120
- }
121
-
122
- module.exports = addCmd
@@ -1,201 +0,0 @@
1
- const inquirer = require("inquirer");
2
- const chalk = require("chalk");
3
- const validator = require("validator");
4
- const signup = require("./signup")
5
- const login = require("./login")
6
- const path = require("path")
7
- const fs = require("fs")
8
-
9
-
10
-
11
- async function beginCmd() {
12
-
13
- const config = path.join(require("os").homedir(),".jvcs","config.json")
14
- let isInitialized = false
15
- let configData = null
16
- if(fs.existsSync(config)) {
17
- isInitialized = true
18
- configData = JSON.parse(fs.readFileSync(config,"utf-8"))
19
- }
20
-
21
- if (isInitialized) {
22
- console.log(chalk.green(`You are already logged in as ${configData.username} (${configData.email})`))
23
- console.log(chalk.yellow(`[1] Continue \n[2] Logout \nChoose an option (1/2) : `))
24
-
25
- const answer = await inquirer.prompt([
26
- {
27
- type: 'input',
28
- name: 'choice',
29
- validate: function (input) {
30
- if (input === "1" || input === "2")
31
- return true
32
-
33
- return "Please enter 1 or 2"
34
- },
35
- filter: function (input) {
36
- return input.trim()
37
- }
38
- }
39
- ])
40
-
41
- console.log(`Your choice was ${answer.choice}`)
42
- if (answer.choice === "1") {
43
- console.log(chalk.green("Continuing as current user..."))
44
- console.log(chalk.green("jvcs --help for help"))
45
- }
46
- else {
47
- console.log(chalk.green("logging out..."))
48
- fs.unlinkSync(config)
49
- console.log(chalk.green("Logged out Successfully"))
50
- console.log(chalk.green("Please login or signup again (jvcs begin) to use version control system"))
51
- console.log(chalk.green("jvcs --help for help"))
52
- }
53
-
54
- return
55
- }
56
-
57
- console.log(chalk.red("No existing session found. Please login or signup."))
58
- console.log(chalk.yellow(`[1] Signup \n[2] login \nChoose an option (1/2) : `))
59
-
60
- const answer = await inquirer.prompt([
61
- {
62
- type: 'input',
63
- name: 'choice',
64
- validate: function (input) {
65
-
66
- if (input === "1" || input === "2")
67
- return true
68
-
69
- return "Please enter 1 or 2"
70
- },
71
- filter: function (input) {
72
- return input.trim(); // optional: remove whitespace
73
- }
74
- }
75
- ])
76
-
77
- if (answer.choice === "1") {
78
-
79
- const signupData = await inquirer.prompt([
80
- {
81
- type: 'input',
82
- name: 'username',
83
- filter: function (input) {
84
- return input.trim()
85
- }
86
- },
87
- {
88
- type: 'input',
89
- name: 'email',
90
- validate: function (input) {
91
- // validate email
92
- if (validator.isEmail(input))
93
- return true
94
-
95
- return "Please enter an valid email"
96
- },
97
- filter: function (input) {
98
- return input.trim()
99
- }
100
- },
101
- {
102
- type: 'password',
103
- name: 'password',
104
- validate: function (input) {
105
- // validate password
106
- if (validator.isStrongPassword(input, {
107
- minLength: 8,
108
- maxLength: 20,
109
- minLowercase: 1,
110
- minUppercase: 1,
111
- minNumbers: 1,
112
- minSymbols: 1,
113
- }))
114
- return true
115
-
116
- return "Please enter a strong password"
117
- },
118
- filter: function (input) {
119
- return input.trim()
120
- }
121
- },
122
- {
123
- type: 'password',
124
- name: 'confirmPassword',
125
- validate: function (input, answers) {
126
- if (answers.password !== input)
127
- return "password must be same as above"
128
-
129
- return true
130
- },
131
- filter: function (input) {
132
- return input.trim()
133
- }
134
- }
135
- ])
136
-
137
- try {
138
- await signup(signupData)
139
- }
140
- catch (error) {
141
- console.log(chalk.red(error))
142
- }
143
- }
144
- else {
145
-
146
- const loginData = await inquirer.prompt([
147
- {
148
- type: 'input',
149
- name: 'username',
150
- filter: function (input) {
151
- return input.trim()
152
- },
153
- validate: function (input) {
154
- if (input === "")
155
- return "email cannot be empty"
156
-
157
- return true
158
- }
159
- },
160
- {
161
- type: 'input',
162
- name: 'email',
163
- filter: function (input) {
164
- return input.trim()
165
- },
166
- validate: function (input) {
167
- if (!validator.isEmail(input))
168
- return "email is not valid"
169
-
170
- if (input === "")
171
- return "email cannot be empty"
172
-
173
- return true
174
- }
175
- },
176
- {
177
- type: 'password',
178
- name: 'password',
179
- filter: function (input) {
180
- return input.trim()
181
- },
182
- validate: function (input) {
183
-
184
- if (input === "")
185
- return "password cannot be empty"
186
-
187
- return true
188
- }
189
- }
190
- ])
191
-
192
- try {
193
- await login(loginData)
194
- }
195
- catch (error) {
196
- console.log(chalk.red(error))
197
- }
198
- }
199
- }
200
-
201
- module.exports = beginCmd
@@ -1,82 +0,0 @@
1
- const path = require("path");
2
- const fs = require("fs").promises;
3
- const fssync = require("fs");
4
- const chalk = require("chalk");
5
- const { v4: uuidv4 } = require("uuid");
6
- const { checkGlobalConfig, getGlobalConfig, checkforjvcs } = require("./utility");
7
-
8
- async function commitCmd(message) {
9
-
10
- if (!message || !message.trim()) {
11
- console.log(chalk.yellow("Please provide a commit message."));
12
- return;
13
- }
14
-
15
- if(!checkGlobalConfig()) {
16
- console.log(chalk.red("No existing session found. Please login or signup."))
17
- console.log(chalk.green("jvcs --help for help"))
18
- return
19
- }
20
-
21
- let configData = getGlobalConfig()
22
-
23
- if(!configData) {
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
- if(!checkforjvcs()) {
30
- console.log(chalk.red("Repository is not initialized or is deleted. Please create it."))
31
- return
32
- }
33
-
34
- const repoPath = path.join(process.cwd(),".jvcs")
35
- const staging = path.join(repoPath,"staging")
36
- const commits = path.join(repoPath,"commits")
37
-
38
- if(!fssync.existsSync(staging)) {
39
- console.log(chalk.yellow("Nothing to commit — staging area is empty."))
40
- return
41
- }
42
-
43
- const stagedContent = await fs.readdir(staging)
44
- if(stagedContent.length === 0) {
45
- console.log(chalk.yellow("Nothing to commit — staging area is empty."))
46
- return
47
- }
48
-
49
- if(!fssync.existsSync(commits)) {
50
- await fs.mkdir(commits)
51
- }
52
-
53
- // main commit logic
54
- const commitId = uuidv4()
55
- const commitFolder = path.join(commits,commitId)
56
- await fs.mkdir(commitFolder, {recursive: true})
57
-
58
- // copying the staging area content to commit folder
59
- await fs.cp(staging,commitFolder, {recursive: true})
60
-
61
- // saving metadata of commit
62
- let parentId = null;
63
- const headPath = path.join(repoPath, "HEAD");
64
- if (fssync.existsSync(headPath)) {
65
- parentId = (await fs.readFile(headPath, "utf8")).trim() || null;
66
- }
67
-
68
- const meta = {
69
- author: configData.username || "unknown",
70
- id: commitId,
71
- message,
72
- timeStamp: new Date().toISOString(),
73
- parentId
74
- }
75
-
76
- await fs.writeFile(path.join(commitFolder,"meta.json"),JSON.stringify(meta,null,2))
77
-
78
- await fs.writeFile(path.join(repoPath, "HEAD"), commitId);
79
- console.log(chalk.green(`Committed as ${commitId}: "${message}"`));
80
- }
81
-
82
- module.exports = commitCmd
@@ -1,60 +0,0 @@
1
- const fs = require("fs").promises;
2
- const path = require("path");
3
- const chalk = require("chalk");
4
- const fssync = require("fs")
5
- const { getGlobalConfig, checkGlobalConfig } = require("./utility")
6
-
7
- async function initCmd() {
8
-
9
- if(!checkGlobalConfig()) {
10
- console.log(chalk.red("No existing session found. Please login or signup."))
11
- console.log(chalk.green("jvcs --help for help"))
12
- return
13
- }
14
-
15
- let configData = null
16
- configData = getGlobalConfig()
17
-
18
- if(!configData) {
19
- console.log(chalk.red("No existing session found. Please login or signup."))
20
- console.log(chalk.green("jvcs --help for help"))
21
- return
22
- }
23
-
24
- // initialize an empty folder with the name of current directory
25
- const cwd = process.cwd()
26
- const home = require("os").homedir()
27
-
28
- if(cwd === home) {
29
- console.log(chalk.red("Cannot initialize a repository in your home directory."));
30
- console.log(chalk.yellow("Hint: navigate to a project folder and run 'jvcs init' there."));
31
- process.exit(1);
32
- }
33
-
34
- const repoPath = path.join(cwd,".jvcs")
35
- if(fssync.existsSync(repoPath)) {
36
- console.log(chalk.yellow("Repository already is initialized."));
37
- process.exit(1);
38
- }
39
-
40
- fssync.mkdirSync(repoPath)
41
- fssync.mkdirSync(path.join(repoPath,"commits"))
42
- fssync.mkdirSync(path.join(repoPath,"staging"))
43
-
44
- const config = {
45
- repoName: path.basename(cwd),
46
- createdAt: new Date().toISOString(),
47
- remote: null,
48
- owner : {
49
- username: configData.username,
50
- email: configData.email
51
- }
52
- }
53
-
54
- fssync.writeFileSync(path.join(repoPath, "config.json"), JSON.stringify(config, null, 2))
55
- fssync.writeFileSync(path.join(repoPath, "HEAD"), "");
56
-
57
- console.log(chalk.green(`Initialized empty JVCS repository`));
58
- }
59
-
60
- module.exports = initCmd
@@ -1,33 +0,0 @@
1
- const path = require("path")
2
- const chalk = require("chalk")
3
- const fs = require("fs")
4
- async function login(loginData) {
5
-
6
- const response = await fetch("http://localhost:3000/login", {
7
- method: "POST",
8
- headers: {
9
- 'Content-Type': 'application/json'
10
- },
11
- credentials: "include",
12
- body: JSON.stringify({email:loginData.email,username:loginData.username,password:loginData.password,cli:true})
13
- })
14
-
15
- const data = await response.json()
16
-
17
- if(data.status === true) {
18
- console.log(chalk.green(data.message))
19
-
20
- const dirPath = path.join(require("os").homedir(), ".jvcs");
21
- if (!fs.existsSync(dirPath)) {
22
- fs.mkdirSync(dirPath, { recursive: true });
23
- }
24
-
25
- const configPath = path.join(dirPath, "config.json");
26
- fs.writeFileSync(configPath,JSON.stringify({email: loginData.email,username: loginData.username,token: data.token},null,2));
27
- }
28
- else {
29
- throw new Error(data.message)
30
- }
31
- }
32
-
33
- module.exports = login
@@ -1,98 +0,0 @@
1
- const fs = require("fs");
2
- const fsPromises = require("fs").promises;
3
- const path = require("path");
4
- const chalk = require("chalk");
5
- const { drive } = require("../config/drive-config");
6
- const { checkInitialization, checkRepoExists, getCLIConfig } = require("./utils");
7
-
8
- async function pullCmd(reponame) {
9
- try {
10
- if (!checkInitialization()) return;
11
- if (!checkRepoExists(reponame)) return;
12
-
13
- const repoPath = path.join(process.cwd(), `.${reponame}`);
14
- const commitFolder = path.join(repoPath, "commits");
15
- if (!fs.existsSync(commitFolder)) fs.mkdirSync(commitFolder, { recursive: true });
16
-
17
- const config = await getCLIConfig();
18
- if (!config) return console.log(chalk.red("Could not read CLI configuration."));
19
-
20
- console.log(chalk.blue("Pulling commits for user:"), chalk.green(config.username));
21
-
22
- // 1️⃣ Find user folder in Drive
23
- const userFolderRes = await drive.files.list({
24
- q: `name='${config.username}' and '1ahuoMCN_Ls5kGF2KPUGLbRZb9kGVMe0V' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false`,
25
- fields: "files(id, name)"
26
- });
27
- if (!userFolderRes.data.files.length) {
28
- console.log(chalk.yellow("⚠ No user folder found on Drive."));
29
- return;
30
- }
31
- const userFolderId = userFolderRes.data.files[0].id;
32
-
33
- // 2️⃣ Find repo folder in Drive
34
- const repoFolderRes = await drive.files.list({
35
- q: `name='${reponame}' and '${userFolderId}' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false`,
36
- fields: "files(id, name)"
37
- });
38
- if (!repoFolderRes.data.files.length) {
39
- console.log(chalk.yellow(`⚠ Repository '${reponame}' not found on Drive.`));
40
- return;
41
- }
42
- const repoFolderId = repoFolderRes.data.files[0].id;
43
-
44
- // 3️⃣ Get commit folders in Drive
45
- const driveCommitsRes = await drive.files.list({
46
- q: `'${repoFolderId}' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false`,
47
- fields: "files(name, id)"
48
- });
49
- const driveCommits = driveCommitsRes.data.files;
50
- if (!driveCommits.length) {
51
- console.log(chalk.yellow("⚠ No commits found on Drive."));
52
- return;
53
- }
54
-
55
- // 4️⃣ Get local commit folders
56
- const localCommits = await fsPromises.readdir(commitFolder);
57
-
58
- // 5️⃣ Download only missing commits
59
- for (const commit of driveCommits) {
60
- if (localCommits.includes(commit.name)) {
61
- console.log(chalk.gray(`✔ Commit '${commit.name}' already exists locally.`));
62
- continue;
63
- }
64
- const localCommitPath = path.join(commitFolder, commit.name);
65
- await fsPromises.mkdir(localCommitPath, { recursive: true });
66
- await downloadFolder(commit.id, localCommitPath);
67
- console.log(chalk.green(`⬇ Pulled new commit '${commit.name}' successfully.`));
68
- }
69
-
70
- console.log(chalk.blue("Pull complete! Local repo is now up to date."));
71
-
72
- } catch (error) {
73
- console.log(chalk.red("Error in pullCmd:"), error.message);
74
- }
75
- }
76
-
77
- // Recursive folder download helper
78
- async function downloadFolder(folderId, destPath) {
79
- const res = await drive.files.list({
80
- q: `'${folderId}' in parents and trashed=false`,
81
- fields: "files(id, name, mimeType)"
82
- });
83
- for (const file of res.data.files) {
84
- const localPath = path.join(destPath, file.name);
85
- if (file.mimeType === "application/vnd.google-apps.folder") {
86
- await fsPromises.mkdir(localPath, { recursive: true });
87
- await downloadFolder(file.id, localPath);
88
- } else {
89
- const dest = fs.createWriteStream(localPath);
90
- await drive.files.get({ fileId: file.id, alt: "media" }, { responseType: "stream" })
91
- .then(res => new Promise((resolve, reject) => {
92
- res.data.on("end", resolve).on("error", reject).pipe(dest);
93
- }));
94
- }
95
- }
96
- }
97
-
98
- module.exports = pullCmd;