jvcs 1.2.1 → 1.2.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/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
package/package.json
CHANGED
package/readme.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# jvcs — A Lightweight Git & GitHub Clone
|
|
2
|
+
|
|
3
|
+
> **jvcs** — a simple, beginner-friendly version control system built to make Git-like workflows easier to understand and use.
|
|
4
|
+
> Designed to simplify core version control operations like committing, reverting, pushing, and cloning — all without the complexity of branches or merges.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Motive
|
|
9
|
+
|
|
10
|
+
As a beginner, understanding Git and GitHub can be confusing — especially concepts like staging, branches, and merges.
|
|
11
|
+
So, **jvcs** was created as a **simplified alternative**, offering a lightweight CLI for personal projects or learners to understand the fundamentals of version control with minimal setup and no complexity.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## Commands Overview
|
|
15
|
+
|
|
16
|
+
| Command | Description |
|
|
17
|
+
|----------|-------------|
|
|
18
|
+
| **begin** | Initialize a new user |
|
|
19
|
+
| **init** | Initialize a new repository |
|
|
20
|
+
| **add** | Stage files for commit |
|
|
21
|
+
| **commit** | Commit staged changes |
|
|
22
|
+
| **log** | Show commit history |
|
|
23
|
+
| **unstage** | Unstage previously staged files |
|
|
24
|
+
| **revert** | Revert repository to a previous commit |
|
|
25
|
+
| **push** | Push commits to remote (Google Drive) |
|
|
26
|
+
| **clone** | Clone repository from remote |
|
|
27
|
+
| **status** | Show current repository state |
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Show help for all commands
|
|
31
|
+
```bash
|
|
32
|
+
jvcs --help
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Show help for a specific command
|
|
36
|
+
```bash
|
|
37
|
+
jvcs commandName --help
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 🧑💻 Author
|
|
41
|
+
### Jagdish Pathak
|
|
42
|
+
### GitHub: https://github.com/JagdishPathakji/
|
package/.jvcs/HEAD
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
cd2a0ec7-04b8-4ac9-b539-617bb5fea1f3
|
|
@@ -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" && target.name !== "node_modules").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,138 +0,0 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
const chalk = require("chalk");
|
|
4
|
-
const { checkGlobalConfig, getGlobalConfig } = require("./utility");
|
|
5
|
-
const { getDriveClient } = require("../config/drive-config");
|
|
6
|
-
const drive = getDriveClient()
|
|
7
|
-
|
|
8
|
-
async function findFolderIdByName(name,parentId=null) {
|
|
9
|
-
|
|
10
|
-
const safeName = name.replace(/'/g, "\\'");
|
|
11
|
-
const parts = [`name='${safeName}'`, "trashed=false"];
|
|
12
|
-
if (parentId) parts.push(`'${parentId}' in parents`);
|
|
13
|
-
|
|
14
|
-
const q = parts.join(" and ");
|
|
15
|
-
const res = await drive.files.list({
|
|
16
|
-
q,
|
|
17
|
-
fields: "files(id, name)",
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const files = (res.data && res.data.files) || [];
|
|
21
|
-
if (files.length === 0) return null;
|
|
22
|
-
return files[0].id;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function downloadFolderFromDrive(folderId, destPath) {
|
|
26
|
-
try {
|
|
27
|
-
const res = await drive.files.list({
|
|
28
|
-
q: `'${folderId}' in parents and trashed=false`,
|
|
29
|
-
fields: "files(id, name, mimeType)",
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const files = res.data.files;
|
|
33
|
-
if (!files.length) return;
|
|
34
|
-
|
|
35
|
-
for (const file of files) {
|
|
36
|
-
const filePath = path.join(destPath, file.name);
|
|
37
|
-
|
|
38
|
-
if (file.mimeType === "application/vnd.google-apps.folder") {
|
|
39
|
-
// create folder locally
|
|
40
|
-
if (!fs.existsSync(filePath)) fs.mkdirSync(filePath);
|
|
41
|
-
await downloadFolderFromDrive(file.id, filePath);
|
|
42
|
-
} else {
|
|
43
|
-
const dest = fs.createWriteStream(filePath);
|
|
44
|
-
await drive.files.get(
|
|
45
|
-
{ fileId: file.id, alt: "media" },
|
|
46
|
-
{ responseType: "stream" }
|
|
47
|
-
).then(res => {
|
|
48
|
-
return new Promise((resolve, reject) => {
|
|
49
|
-
res.data
|
|
50
|
-
.on("end", resolve)
|
|
51
|
-
.on("error", reject)
|
|
52
|
-
.pipe(dest);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
} catch (err) {
|
|
58
|
-
console.log(chalk.red("Error downloading folder: " + err.message));
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
async function getVisibilityAndLatestCommit(username,reponame,configData) {
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
|
|
67
|
-
const response = await fetch("http://localhost:3000/cloneRepo", {
|
|
68
|
-
method:"POST",
|
|
69
|
-
headers: {
|
|
70
|
-
'Content-Type':"application/json"
|
|
71
|
-
},
|
|
72
|
-
body: JSON.stringify({username,reponame,token:configData.token})
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
const data = await response.json()
|
|
76
|
-
return data
|
|
77
|
-
}
|
|
78
|
-
catch(error) {
|
|
79
|
-
console.log(chalk.red(error || error.message))
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function cloneCmd(username,reponame) {
|
|
84
|
-
|
|
85
|
-
if(!username || !reponame) {
|
|
86
|
-
console.log(chalk.red("Path is not provided properly"))
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if(!checkGlobalConfig()) {
|
|
91
|
-
console.log(chalk.red("No existing session found. Please login or signup."));
|
|
92
|
-
console.log(chalk.green("jvcs --help for help"));
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const configData = getGlobalConfig();
|
|
97
|
-
if(!configData) {
|
|
98
|
-
console.log(chalk.red("No existing session found. Please login or signup."));
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
console.log(username,reponame)
|
|
103
|
-
|
|
104
|
-
const response = await getVisibilityAndLatestCommit(username,reponame,configData)
|
|
105
|
-
if(response.status === false) {
|
|
106
|
-
console.log(chalk.red(`${response.message}`))
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const latestCommit = response.commitId
|
|
111
|
-
// find the repo from drive GithubClone/username/reponame/commit_lastestCommit
|
|
112
|
-
|
|
113
|
-
const rootFolder = await findFolderIdByName("GithubClone")
|
|
114
|
-
if(!rootFolder) throw new Error("Root folder not found on cloud.");
|
|
115
|
-
|
|
116
|
-
const userFolder = await findFolderIdByName(username, rootFolder);
|
|
117
|
-
if (!userFolder) throw new Error(`User folder '${username}' not found.`);
|
|
118
|
-
|
|
119
|
-
const repoFolder = await findFolderIdByName(reponame, userFolder);
|
|
120
|
-
if (!repoFolder) throw new Error(`Repository folder '${reponame}' not found.`);
|
|
121
|
-
|
|
122
|
-
const commitFolder = await findFolderIdByName(`commit_${latestCommit}`, repoFolder);
|
|
123
|
-
if (!commitFolder) throw new Error(`Commit folder 'commit_${latestCommit}' not found.`);
|
|
124
|
-
|
|
125
|
-
console.log(chalk.green(`Found repository, downloading...`));
|
|
126
|
-
|
|
127
|
-
const destPath = path.join(process.cwd(), reponame);
|
|
128
|
-
if(fs.existsSync(destPath)) {
|
|
129
|
-
console.log(chalk.red(`Destination '${reponame}' already exists. Remove or rename it and retry.`));
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
await downloadFolderFromDrive(commitFolder, destPath);
|
|
134
|
-
|
|
135
|
-
console.log(chalk.green(`Repository cloned successfully into ./${reponame}`));
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
module.exports = cloneCmd
|
|
@@ -1,83 +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
|
-
|
|
50
|
-
if(!fssync.existsSync(commits)) {
|
|
51
|
-
await fs.mkdir(commits)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// main commit logic
|
|
55
|
-
const commitId = uuidv4()
|
|
56
|
-
const commitFolder = path.join(commits,commitId)
|
|
57
|
-
await fs.mkdir(commitFolder, {recursive: true})
|
|
58
|
-
|
|
59
|
-
// copying the staging area content to commit folder
|
|
60
|
-
await fs.cp(staging,commitFolder, {recursive: true})
|
|
61
|
-
|
|
62
|
-
// saving metadata of commit
|
|
63
|
-
let parentId = null;
|
|
64
|
-
const headPath = path.join(repoPath, "HEAD");
|
|
65
|
-
if (fssync.existsSync(headPath)) {
|
|
66
|
-
parentId = (await fs.readFile(headPath, "utf8")).trim() || null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const meta = {
|
|
70
|
-
author: configData.username || "unknown",
|
|
71
|
-
id: commitId,
|
|
72
|
-
message,
|
|
73
|
-
timeStamp: new Date().toISOString(),
|
|
74
|
-
parentId
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
await fs.writeFile(path.join(commitFolder,"meta.json"),JSON.stringify(meta,null,2))
|
|
78
|
-
|
|
79
|
-
await fs.writeFile(path.join(repoPath, "HEAD"), commitId);
|
|
80
|
-
console.log(chalk.green(`Committed as ${commitId}: "${message}"`));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
module.exports = commitCmd
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const { getDriveClient } = require("../config/drive-config");
|
|
2
|
-
const drive = getDriveClient()
|
|
3
|
-
|
|
4
|
-
async function getDirectoryStructure(username,reponame,commitId) {
|
|
5
|
-
|
|
6
|
-
async function findOrCreateFolder(name,parentId=null) {
|
|
7
|
-
|
|
8
|
-
const query = [
|
|
9
|
-
`name='${name}'`,
|
|
10
|
-
"mimeType='application/vnd.google-apps.folder'",
|
|
11
|
-
"trashed=false"
|
|
12
|
-
]
|
|
13
|
-
|
|
14
|
-
if(parentId) {
|
|
15
|
-
query.push(`'${parentId}' in parents`)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const res = await drive.files.list({
|
|
19
|
-
q: query.join(" and "),
|
|
20
|
-
fields: "files(id,name)"
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
if (res.data.files.length > 0)
|
|
24
|
-
return { id: res.data.files[0].id, alreadyExists: true };
|
|
25
|
-
|
|
26
|
-
const folderMetaData = {
|
|
27
|
-
name,
|
|
28
|
-
mimeType: "application/vnd.google-apps.folder",
|
|
29
|
-
}
|
|
30
|
-
if(parentId) folderMetaData.parents = [parentId];
|
|
31
|
-
|
|
32
|
-
const folder = await drive.files.create({
|
|
33
|
-
resource: folderMetaData,
|
|
34
|
-
fields: "id"
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
return { id: folder.data.id, alreadyExists: false };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Build folder hierarchy in drive
|
|
41
|
-
const githubClone = await findOrCreateFolder("GithubClone");
|
|
42
|
-
const userFolder = await findOrCreateFolder(username,githubClone.id)
|
|
43
|
-
const repoFolder = await findOrCreateFolder(reponame,userFolder.id)
|
|
44
|
-
const commitFolderName = `commit_${commitId}`
|
|
45
|
-
const commitFolder = await findOrCreateFolder(commitFolderName,repoFolder.id)
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
githubCloneId: githubClone.id,
|
|
49
|
-
userFolderId: userFolder.id,
|
|
50
|
-
repoFolderId: repoFolder.id,
|
|
51
|
-
commitFolderId: commitFolder.id,
|
|
52
|
-
commitAlreadyExists: commitFolder.alreadyExists
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
module.exports = getDirectoryStructure
|