thegit
Version:
Implementation of git in node.js.
152 lines (136 loc) • 3.73 kB
JavaScript
const { execSync } = require("child_process");
const globals = require("./../globals");
const {
createEmptyFile,
deleteFile,
deleteDir,
createDir,
listPathsInDir,
writeToFile,
readFile,
pathExists,
isFile,
isDir
} = require('../util/fs_util');
const {
isInit,
createObjectFromFileContent,
debug,
logMessage,
setRootDir,
hash,
compress,
decompress,
getObjectFromHash,
getLastCommit,
createCommitStr,
updateRefsWithCommit,
isDetached
} = require('../util/util.js');
function commitCaller(...args) {
if (args.length == 0) {
execSync(`code -w ${globals.rootDir + ".legit/COMMIT_EDITMSG"}`);
globals.commitMessage = readFile( ".legit/COMMIT_EDITMSG")
.split("\n")
.filter((line) => {
return line.trim()[0] != "#";
}).join("");
} else if (args.length != 0 && args[0] != "-m") {
console.log("invalid args");
return;
} else {
globals.commitMessage = args.slice(1).join(" ");
}
// console.log(globals.commitMessage,globals.username, globals.email)
if (globals.commitMessage && globals.username && globals.email) commit();
else console.log("invalid message or config info");
}
function indexToTree(paths, map, cur = "") {
let splits = paths
.map((path) => path.split("/"))
.filter((path) => path.length != 0);
let root = {};
for (let [parent, ...rest] of splits) {
if (!Object.keys(root).includes(parent)) root[parent] = [];
if (rest.length != 0) root[parent].push(rest.join("/"));
}
for (let key in root) {
if (isDir(cur + "/" + key)) {
root[key] = {
type: "tree",
name: key,
children: indexToTree(root[key], map, cur + "/" + key),
};
} else {
root[key] = {
hash: map[`${cur}/${key}`.slice(1)],
name: key,
type: "blob",
};
}
}
return root;
}
function addTreeToObjects(tree) {
let children = Object.keys(tree.children);
let treeStr = "";
for (let child of children) {
let currNode = tree.children[child];
// this generates the hash for the tree node to use next
if (currNode.type !== "blob") addTreeToObjects(currNode);
treeStr += `${currNode.type} ${currNode.hash} ${currNode.name}\n`;
}
createObjectFromFileContent(treeStr);
tree.hash = hash(treeStr);
}
function createTree() {
let fileToHash = {};
let indexFiles = readFile(globals.indexDir)
.split("\n")
.filter((line) => line.length != 0)
.map((line) => {
let [hash, path] = line.split(" ");
fileToHash[path] = hash;
return path;
})
.sort();
let tree = indexToTree(indexFiles, fileToHash);
let root = {
name: "root",
type: "tree",
children: tree,
};
addTreeToObjects(root);
return root;
}
function noChangesToCommit(treeHash) {
let lastCommit = getLastCommit();
if (lastCommit) {
let lastTree = getObjectFromHash(lastCommit);
let lastTreeHash = lastTree.split("\n")[0].split(" ")[1];
if (lastTreeHash == treeHash) {
console.log("Working directory clean, no changes made since last commit");
return true;
}
}
return false;
}
function commit() {
if(isDetached()) {
console.log("currently in detached state, not allowed to commit");
return;
}
let root = createTree();
let commitStr = createCommitStr(root.hash);
if (noChangesToCommit(root.hash)) return;
createObjectFromFileContent(commitStr);
updateRefsWithCommit(commitStr);
}
module.exports = {
commitCaller,
commit,
indexToTree,
addTreeToObjects,
createTree,
noChangesToCommit
}