diff --git a/CommitTester.class b/CommitTester.class new file mode 100644 index 0000000..ae63880 Binary files /dev/null and b/CommitTester.class differ diff --git a/CommitTester.java b/CommitTester.java new file mode 100644 index 0000000..796f001 --- /dev/null +++ b/CommitTester.java @@ -0,0 +1,16 @@ +import java.io.IOException; + +public class CommitTester { + public static void main (String [] args) throws IOException { + Git myGit = new Git(); + myGit.initalizeGitRepo(); + myGit.stage("tester1"); + myGit.stage("tester2"); + System.out.println(myGit.commit("Aviv Pilipski", "Updated Tester1 and Tester2")); + myGit.stage("tester3"); + System.out.println(myGit.commit("Aviv Pilipski", "Added file3")); + myGit.stage("testDir"); + myGit.stage("testDirFiles"); + System.out.println(myGit.commit("Aviv Pilipski", "Empty Directory + Directory with Files")); + } +} \ No newline at end of file diff --git a/Git.class b/Git.class new file mode 100644 index 0000000..2427ce4 Binary files /dev/null and b/Git.class differ diff --git a/Git.java b/Git.java index 15856e9..451b89c 100644 --- a/Git.java +++ b/Git.java @@ -1,12 +1,46 @@ -import java.security.MessageDigest; import java.io.*; import java.math.BigInteger; -import java.nio.file.Files; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -public abstract class Git { +public class Git implements GitInterface { // initalizes a Git Repo with an "objects" folder and "index" file - public static void initalizeGitRepo() { + public void stage (String filePath) { + File fileToStage = new File (filePath); + try { + blobCreation(fileToStage); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public String commit (String author, String message) throws IOException { + return makeCommit(author, message); + } + + public void checkout (String commitHash) throws IOException { + File headFile = new File ("./git/objects"); + headFile.delete(); + headFile.createNewFile(); + BufferedWriter headBR = new BufferedWriter(new FileWriter (headFile)); + headBR.write(commitHash); + headBR.close(); + String commit = fileContent(headFile); + File commitFile = new File ("./git/objects", commit); + BufferedReader br = new BufferedReader (new FileReader (commitFile)); + String commitFileRootTree = br.readLine(); + br.close(); + commitFileRootTree = commitFileRootTree.replace("tree: ", ""); + File rootTreeFile = new File ("./git/objects", commitFileRootTree); + String rootTreeContents = fileContent(rootTreeFile); + File indexFile = new File ("./git/index"); + BufferedWriter indexWriter = new BufferedWriter(new FileWriter(indexFile)); + indexWriter.write(rootTreeContents); + indexWriter.close(); + } + + public static void initalizeGitRepo() throws IOException { File gitFolder = new File("./git"); // git folder File objectsFolder = new File("./git/objects"); // objects folder File file = new File("./git", "index"); // index file @@ -32,10 +66,27 @@ public static void initalizeGitRepo() { } catch (IOException e) { e.printStackTrace(); } - + File head = new File ("./git/HEAD"); + head.createNewFile(); } // hashes the content of a file using SHA1 + public static String SHA1Hashing(String file) throws IOException { + try { + MessageDigest crypt = MessageDigest.getInstance("SHA-1"); + crypt.update(file.getBytes("UTF-8")); + BigInteger temp = new BigInteger(1, crypt.digest()); + return temp.toString(16); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + // this is here bc otherwise there is an error message. well can anyone actually + // bypass the "try"? + return "error"; + } public static String SHA1Hashing(File file) throws IOException { String content; if(file.isDirectory()) @@ -105,6 +156,59 @@ private static String fileContent(File file) { return sb.toString(); } + public String generateRootTree() throws IOException { + File headFile = new File ("./git/HEAD"); + File indexFile = new File ("./git/index"); + String toReturn = ""; + if (headFile.length() == 0) { + toReturn = SHA1Hashing(indexFile); + blobCreation(indexFile); + } + else { + String hashOfPreviousCommit = fileContent(headFile); + File previousCommit = new File ("./git/objects", hashOfPreviousCommit); + BufferedReader br = new BufferedReader (new FileReader (previousCommit)); + String treeHash = br.readLine(); + br.close(); + treeHash = treeHash.replace("tree: ", ""); + File previousTree = new File ("./git/objects", treeHash); + String contentsOfPrevious = fileContent(previousTree); + String updatedTree = contentsOfPrevious + "\n" + fileContent(indexFile); + String hashTree = SHA1Hashing(updatedTree); + File treeFile = new File ("./git/objects", hashTree); + BufferedWriter treeWriter = new BufferedWriter(new FileWriter(treeFile)); + treeWriter.write(updatedTree); + treeWriter.close(); + toReturn = hashTree; + + } + indexFile.delete(); + indexFile.createNewFile(); + return toReturn; + } + public String makeCommit(String author, String message) throws IOException { + File headFile = new File ("./git/HEAD"); + StringBuilder sb = new StringBuilder(); +sb.append("tree: ").append(generateRootTree()).append("\n") + .append("parent: ").append(fileContent(headFile)).append("\n") + .append("author: ").append(author).append("\n") + .append("date: ").append(java.time.LocalDate.now()).append("\n") + .append("commit summary: ").append(message); + String commitHash = SHA1Hashing(sb.toString()); + File commitFile = new File ("./git/objects", commitHash); + commitFile.createNewFile(); + BufferedWriter bw = new BufferedWriter (new FileWriter (commitFile)); + bw.write(sb.toString()); + bw.close(); + headFile.delete(); + headFile.createNewFile(); + BufferedWriter bHead = new BufferedWriter(new FileWriter (headFile)); + bHead.write(commitHash); + bHead.close(); + return commitHash; + + } + public static void blobCreation(File file) throws IOException { if(!file.exists()){ throw new FileNotFoundException(); @@ -138,6 +242,7 @@ public static void blobCreation(File file) throws IOException { else{ name = SHA1Hashing(file); // getting hashed name File blobFile = new File("./git/objects/" + name); // the blob file + // creates the blob file try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(blobFile.getPath())); BufferedReader br = new BufferedReader(new FileReader (file))) { while (br.ready()) @@ -150,48 +255,29 @@ public static void blobCreation(File file) throws IOException { } } // adds a new line into the index file - try { - FileWriter fw = new FileWriter("./git/index", true); - BufferedWriter bufferedWriter = new BufferedWriter(fw); - // writes the content into index by first checking to see if the index file has been written into or not, (to determine if a /n is needed) - // and then if the file is a directory or not, (to determine if tree or blob) and then if the file is in a subdir or if it is in the home dir - // (to determine whether to write the parent dir or not) - FileReader checks = new FileReader("./git/index"); - if (!checks.ready()) { - if (file.isDirectory()){ - if(isInHomeDir(file)) - bufferedWriter.write("tree " + name + " " + file.getName()); - else - bufferedWriter.write("tree " + name + " " + file.getParentFile().getName() + "/" + file.getName()); - }else{ - if (isInHomeDir(file)) - bufferedWriter.write("blob " + name + " " + file.getName()); - else - bufferedWriter.write("blob " + name + " " + file.getParentFile().getName() + "/" + file.getName()); - } - } else { - if (file.isDirectory()){ - if (isInHomeDir(file)) - bufferedWriter.write("\ntree " + name + " " + file.getName()); - else - bufferedWriter.write("\ntree " + name + " " + file.getParentFile().getName() + "/" + file.getName()); - } else { - if(isInHomeDir(file)) - bufferedWriter.write("\nblob " + name + " " + file.getName()); - else - bufferedWriter.write("\nblob " + name + " " + file.getParentFile().getName() + "/" + file.getName()); - } + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("./git/index", true))) { + String entry = ""; + File indexFile = new File ("./git/index"); + String contents = fileContent(indexFile); + // Determine if it's a directory or a file and format the entry accordingly + if (!contents.contains(name)) { + if (file.isDirectory()) { + entry = "tree " + name + " " + file.getPath(); + } else { + entry = "blob " + name + " " + file.getPath(); + } + bufferedWriter.write(entry); + bufferedWriter.write("\n"); + bufferedWriter.close(); } - // bufferedWriter.write(name + " " + file.getName() + "\n"); - bufferedWriter.close(); - checks.close(); - } catch (IOException e) { + } catch (IOException e) { e.printStackTrace(); - } + } } + private static boolean isInHomeDir (File file){ - return file.getParentFile().getPath().equals("."); + return file.getPath().equals("."); } } diff --git a/GitInterface.class b/GitInterface.class new file mode 100644 index 0000000..cf45a79 Binary files /dev/null and b/GitInterface.class differ diff --git a/GitInterface.java b/GitInterface.java new file mode 100644 index 0000000..cf30fad --- /dev/null +++ b/GitInterface.java @@ -0,0 +1,32 @@ +import java.io.IOException; + +public interface GitInterface { + /** + * Stages a file for the next commit. + * + * @param filePath The path to the file to be staged. + */ + void stage(String filePath); + + /** + * Creates a commit with the given author and message. + * It should capture the current state of the repository, + * update the HEAD, and return the commit hash. + * + * @param author The name of the author making the commit. + * @param message The commit message describing the changes. + * @return The SHA1 hash of the new commit. + * @throws IOException + */ + String commit(String author, String message) throws IOException; + + /** + * EXTRA CREDIT: Checks out a specific commit given its hash. + * This should update the working directory to match the + * state of the repository at that commit. + * + * @param commitHash The SHA1 hash of the commit to check out. + * @throws IOException + */ + void checkout(String commitHash) throws IOException; +} \ No newline at end of file diff --git a/GitTester.class b/GitTester.class new file mode 100644 index 0000000..10b7c89 Binary files /dev/null and b/GitTester.class differ diff --git a/GitTester.java b/GitTester.java index b844472..68d5863 100644 --- a/GitTester.java +++ b/GitTester.java @@ -1,5 +1,3 @@ -import java.nio.file.*; -import java.security.MessageDigest; import java.io.*; public class GitTester { @@ -12,16 +10,22 @@ public static void main(String[] args) throws IOException { File tester2 = fileCreation("tester2", "hi\nthis is sonarii"); Git.blobCreation(tester1); Git.blobCreation(tester2); + File tester3 = fileCreation("tester3", "hmmm"); Git.blobCreation(tester3); + + // testing blob creation: empty dir File testDir = new File ("./testDir"); testDir.mkdir(); Git.blobCreation(testDir); + // testing blob creation: dir with files File testDirFiles = new File ("./testDirFiles"); testDirFiles.mkdir(); Git.blobCreation(testDirFiles); + + // testing blob creation: dir with files and subdirs File testDirDirs = new File ("./testDirDirs"); File subDirs = new File ("./testDirDirs/test/testSub"); @@ -29,8 +33,7 @@ public static void main(String[] args) throws IOException { subDirs.mkdirs(); Git.blobCreation(testDirDirs); // testing file deletion - deleteTesters(); - + //deleteTesters(); } // creates a file with given name and content diff --git a/tempCodeRunnerFile.java b/tempCodeRunnerFile.java new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tempCodeRunnerFile.java @@ -0,0 +1 @@ +