diff --git a/.gitignore b/.gitignore index 5419ebf..5b3151c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /git *.DS_Store -.txt \ No newline at end of file +*.class \ No newline at end of file diff --git a/Blob.class b/Blob.class deleted file mode 100644 index e7af97b..0000000 Binary files a/Blob.class and /dev/null differ diff --git a/Blob.java b/Blob.java index 0212c33..8e1a283 100644 --- a/Blob.java +++ b/Blob.java @@ -13,6 +13,7 @@ import java.security.NoSuchAlgorithmException; import java.util.zip.GZIPOutputStream; +import mickeybutil.Terminate; public class Blob { private String blobName; @@ -21,20 +22,23 @@ public class Blob { private static boolean compressionAuthorization = false; public Blob(String fileName, boolean compressionAuthorization) throws IOException { + if (fileName.substring(0, 2).equals("./")) + throw new Error("./ is not allowed"); + Blob.compressionAuthorization = compressionAuthorization; - + // Check if the git/objects directory exists if (!Files.exists(Paths.get("git/objects"))) { throw new FileNotFoundException("No git or objects directories"); } - + File ogFile = new File(fileName); - + // Check if the file exists if (!ogFile.exists()) { throw new FileNotFoundException("File does not exist: " + fileName); } - + // Determine if the input is a file or a directory if (ogFile.isFile()) { isBlob = true; @@ -48,80 +52,90 @@ public Blob(String fileName, boolean compressionAuthorization) throws IOExceptio System.err.println("Compression failed, proceeding with uncompressed data."); } } - + // Create a SHA1 hash and save the file in the objects directory String blobSHA1 = newFileName(fileContents); // Get SHA1 based on file content File backupFile = new File("git/objects", blobSHA1); try (BufferedWriter bw = new BufferedWriter(new FileWriter(backupFile))) { bw.write(fileContents); } - + // Store original fileName and SHA1 in the index file String str = "blob " + backupFile.getName() + " " + ogFile.getName() + "\n"; try (BufferedWriter bw2 = new BufferedWriter(new FileWriter("git/index", true))) { bw2.append(str); } - + blobName = backupFile.getName(); // Set the blobName to the SHA1 of the blob - - } - + + } + else if (ogFile.isDirectory()) { isTree = true; StringBuilder treeContent = new StringBuilder(); - + StringBuilder indexContent = new StringBuilder(); + // Iterate over the contents of the directory for (File file : ogFile.listFiles()) { if (file.isFile()) { String fileContents = readFileAsString(file); String createdHash = encryptThisString(fileContents); - File objectFile = new File ("git/objects", createdHash); + File objectFile = new File("git/objects", createdHash); BufferedWriter bw = new BufferedWriter(new FileWriter(objectFile)); bw.write(fileContents); bw.close(); - treeContent.append("blob ").append(createdHash).append(" ").append(file.getPath().replace("/Users/avivpilipski/Desktop/12/HTCS_Projects/git-project-AVIV", "")).append("\n"); + treeContent.append("blob ").append(createdHash).append(" ") + .append(file.getName()) + .append("\n"); + indexContent.append("blob ").append(createdHash).append(" ") + .append(file.getPath()) + .append("\n"); } else if (file.isDirectory()) { // Recursively create a tree for each subdirectory - String [] dirContents = file.list(); + String[] dirContents = file.list(); String toHash = ""; for (String c : dirContents) { toHash += c; } String newObjectSHA1 = encryptThisString(toHash); - File objectFile = new File ("git/objects", newObjectSHA1); + File objectFile = new File("git/objects", newObjectSHA1); try (BufferedWriter tempBR = new BufferedWriter(new FileWriter(objectFile))) { tempBR.write(toHash); } - Blob subTree = new Blob(file.getAbsolutePath(), compressionAuthorization); + Blob subTree = new Blob(file.getPath(), compressionAuthorization); String treeSHA1 = subTree.getBlobName(); // Get the tree's SHA1 - treeContent.append("tree ").append(treeSHA1).append(" ").append(file.getPath().replace("/Users/avivpilipski/Desktop/12/HTCS_Projects/git-project-AVIV", "")).append("\n"); + treeContent.append("tree ").append(treeSHA1).append(" ") + .append(file.getName()) + .append("\n"); } } - + // Save the tree content to a file String treeSHA1 = encryptThisString(treeContent.toString()); File treeFile = new File("git/objects", treeSHA1); try (BufferedWriter treeWriter = new BufferedWriter(new FileWriter(treeFile))) { treeWriter.write(treeContent.toString()); } - + // Add the tree to the index try (BufferedWriter indexWriter = new BufferedWriter(new FileWriter("git/index", true))) { - indexWriter.append(treeContent); + // writes all the blobs in the tree to index + indexWriter.append(indexContent); + // adds the current tree to index + indexWriter.append("tree " + treeSHA1 + " " + fileName + "\n"); + // all the other trees are written to index when `new Blob`ed } - + blobName = treeSHA1; // Set the blobName to the SHA1 of the tree - - } - + + } + else { throw new IOException("The specified path is neither a file nor a directory: " + fileName); } } - - - public String getBlobName(){ + public String getBlobName() { return blobName; } @@ -135,12 +149,12 @@ public static byte[] compress(String data) throws IOException { return compressed; } - public boolean isCompressed(){ + public boolean isCompressed() { return compressionAuthorization; } - - public String newFileName (String str) throws IOException{ - //encrypts a String using the SHA1 function + + public String newFileName(String str) throws IOException { + // encrypts a String using the SHA1 function String SHA1 = encryptThisString(str); return SHA1; } @@ -176,7 +190,7 @@ public static String encryptThisString(String input) { } } - public String readFileAsString(File file) throws IOException { + public static String readFileAsString(File file) throws IOException { try { Path path = file.toPath(); return new String(Files.readAllBytes(path)); @@ -185,4 +199,20 @@ public String readFileAsString(File file) throws IOException { throw e; } } + + public static void writeFileAsString(File file, String data) { + try { + Path path = file.toPath(); + var parent = file.getParentFile(); + if (parent != null && !parent.exists()) + parent.mkdirs(); + if (!Files.exists(path)) + Files.createFile(path); + + Files.write(path, data.getBytes()); + } catch (IOException e) { + System.err.println("Failed to write to file: " + file.getPath()); + Terminate.exception(e); + } + } } \ No newline at end of file diff --git a/CommitFile.java b/CommitFile.java new file mode 100644 index 0000000..5682cce --- /dev/null +++ b/CommitFile.java @@ -0,0 +1,70 @@ +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; + +import mickeybutil.Terminate; + +public class CommitFile { + public String tree; + public String parent; + public String author; + public String date; + public String message; + + public CommitFile(String tree, String parent, String author, String message, String date) { + this.tree = tree; + this.parent = parent; + this.author = author; + this.date = date; + this.message = message; + } + + static CommitFile read(File file) { + try { + BufferedReader reader = new BufferedReader(new FileReader(file)); + var treeLine = reader.readLine(); + var parentLine = reader.readLine(); + var authorLine = reader.readLine(); + var dateLine = reader.readLine(); + var messageLine = reader.readLine(); + + Terminate.assertEq(treeLine.substring(0, 5), "tree "); + var tree = treeLine.substring(5); + Terminate.assertEq(parentLine.substring(0, 7), "parent "); + var parent = parentLine.substring(7); + Terminate.assertEq(authorLine.substring(0, 7), "author "); + var author = authorLine.substring(7); + Terminate.assertEq(dateLine.substring(0, 5), "date "); + var date = dateLine.substring(9); + Terminate.assertEq(messageLine.substring(0, 8), "message "); + var message = messageLine.substring(8); + reader.close(); + return new CommitFile(tree, parent, author, message, date); + } catch (Exception e) { + Terminate.exception(e); + } + return null; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("tree " + tree + "\n"); + sb.append("parent " + parent + "\n"); + sb.append("author " + author + "\n"); + sb.append("date " + date + "\n"); + sb.append("message " + message + "\n"); + return sb.toString(); + } + + static void write(File file, CommitFile commit) { + try { + BufferedWriter writer = new BufferedWriter(new FileWriter(file)); + writer.write(commit.toString()); + writer.close(); + } catch (Exception e) { + Terminate.exception(e); + } + } +} diff --git a/DirectoryTester.java b/DirectoryTester.java new file mode 100644 index 0000000..0d0ba23 --- /dev/null +++ b/DirectoryTester.java @@ -0,0 +1,24 @@ +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public class DirectoryTester { + public static void main(String[] args) throws IOException { + Git.deleteDirectory(new File("./git")); + Git.initGit(); + Git.stageEverything(); + var git = new Git(); + var commit = git.commit("me", "test commit"); + git.checkout(commit); + } + + // Helper method to create a file with specified content + private static void createFile(File file, String content) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { + writer.write(content); + } catch (IOException e) { + System.err.println("Failed to create file: " + file.getAbsolutePath()); + } + } +} diff --git a/Git.class b/Git.class deleted file mode 100644 index 2cc1c1d..0000000 Binary files a/Git.class and /dev/null differ diff --git a/Git.java b/Git.java index 1c01d6a..11cf7d6 100644 --- a/Git.java +++ b/Git.java @@ -1,116 +1,283 @@ +import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Date; -public class Git { - public static void main (String [] args) throws IOException { - //test initialization of git repo and deletes it (then recreates it for further testing) - initGit(); - checkInitGit(); - initGit(); - - //creates two blobs with unique file names and data - File newFile = new File ("newFile.txt"); - newFile.createNewFile(); - BufferedWriter bw = new BufferedWriter(new FileWriter(newFile)); - bw.write ("sfodvunaoernoienv"); - bw.close(); - Blob blob = new Blob ("newFile.txt", false); - File newFile2 = new File ("newFile2.txt"); - newFile.createNewFile(); - BufferedWriter bw2 = new BufferedWriter(new FileWriter(newFile2)); - bw2.write ("sodvunaoernoien"); - bw2.close(); - Blob blob2 = new Blob ("newFile2.txt", false); - - //verifies that the location of a blob is correct (git/objects) - String blobName = blob.getBlobName(); - String desiredPath = "git/objects/"+blobName; - File b = new File (desiredPath); - if (b.exists()&&b.isFile()) - System.out.println ("Blob exists in the correct path."); - - //tests that the blob has correct hash and file contents- for compressed and non-compressed files - String correctHash = ""; - if (blob.isCompressed()){ - correctHash = "ddd8ff69c3b86f4f8a3efcb1387a5787f464a26f"; - if (blob.getBlobName().equals(correctHash)){ - System.out.println ("blob has correct hash/name."); +import mickeybutil.Terminate; +import mickeybutil.PathUtil; + +public class Git implements GitInterface { + // Dear Aviv, + // ! once a directory is staged, anything within it should not be staged + // ! this is a limitation of how blob is currently implemented + public void stage(String filePath) { + try { + new Blob(filePath, false); + } catch (IOException e) { + throw new Error("Error"); + } + } + + /** + * Generates a tree file with all the root files in it + */ + static String generateMegaTree() { + try { + File git = new File("git"); + File objects = new File(git, "objects"); + File index = new File(git, "index"); + + // so basically we go through index and look for stuff without a slash + BufferedReader reader = new BufferedReader(new FileReader(index)); + StringBuffer megaTree = new StringBuffer(); + while (true) { + var line = reader.readLine(); + if (line == null) + break; + var slashesNum = line.split("/").length - 1; + if (slashesNum == 0) + megaTree.append(line + "\n"); } + final var sha = Blob.encryptThisString(megaTree.toString()); + + File outFile = new File(objects, sha); + BufferedWriter writer = new BufferedWriter(new FileWriter(outFile)); + + // reads in the tree from the last commit + var commitHash = Head.getHeadCommit(); + String commitTreeData = ""; + if (!commitHash.equals("")) { + var commitFile = new File(objects, commitHash); + var commitData = CommitFile.read(commitFile); + var commitTree = new File(objects, commitData.tree); + commitTreeData = Blob.readFileAsString(commitTree); + } + + writer.write(megaTree.toString() + commitTreeData); + + reader.close(); + writer.close(); + + return sha; + } catch (IOException e) { + Terminate.exception(e); + return null; } - else{ - correctHash = "aaa8b870cdae19a38f9ad6f328dbaaf31ad38965"; - if (blob.getBlobName().equals(correctHash)){ - System.out.println ("blob has correct hash/name."); - String BlobContents = blob.readFileAsString(b); - String FileContents = blob.readFileAsString(newFile); - if (BlobContents.equals(FileContents)){ - System.out.println ("blob has correct contents."); - } + } + + // Generate a root `tree` file and its inner `blob` files: + + // 1. Identify the **root tree** in the Working Directory—the topmost directory + // that encompasses all other folders and files. The SHA1 hash of this `tree` + // file will be referenced by the `commit` file created in step 2. + + // Recall that `tree` files contain references to their immediate child blobs + // and subtrees. Thus, its corresponding SHA1 hash will be the hash of its + // contents and be created only when all `files` within the directory have been + // hashed. + + // 2. Save each `blob` file (including `trees`) in the `objects` directory with + // its corresponding SHA1 hash as the filename. The last `blob` created should + // be the **root** **`tree`**. + public static void stageEverything() { + File thisDir = new File("./"); + for (var file : thisDir.listFiles()) { + try { + System.out.println(file.getPath()); + if (!file.getPath().equals("./git") && !file.getPath().equals("./.git")) + new Blob(file.getPath().substring(2), false); + } catch (Exception e) { + Terminate.exception(e); + } + } + generateMegaTree(); + } + + public String commit(String author, String message) { + var tree = generateMegaTree(); + CommitFile commit = new CommitFile(tree, Head.getHeadCommit(), author, message, new Date().toString()); + var commitHash = Blob.encryptThisString(commit.toString()); + File git = new File("git"); + File objects = new File(git, "objects"); + File outFile = new File(objects, commitHash); + Blob.writeFileAsString(outFile, commit.toString()); + Head.setHeadCommit(commitHash); + var index = new File(git, "index"); + index.delete(); + try { + index.createNewFile(); + } catch (IOException e) { + Terminate.exception(e); + } + return commitHash; + } + + private static void handleLine(String line, String path) throws IOException { + String[] parts = line.split(" "); + String type = parts[0]; + String hash = parts[1]; + String name = parts[2]; + if (type.equals("tree")) { + File treeFile = new File("git/objects/" + hash); + String treeData = Blob.readFileAsString(treeFile); + String[] lines = treeData.split("\n"); + for (var l : lines) { + handleLine(l, path + "/" + name); } + } else if (type.equals("blob")) { + File blobFile = new File("git/objects/" + hash); + String blobData = Blob.readFileAsString(blobFile); + File outFile = new File(PathUtil.removeLeadingSlash(path + "/" + name)); + Blob.writeFileAsString(outFile, blobData); + } + } + + public void checkout(String hash) { + for (var file : new File("./").listFiles()) { + if (!file.getPath().equals("./git") && !file.getPath().equals("./.git")) + if (file.isDirectory()) + deleteDirectory(file); + else + file.delete(); } - //verifies that the index was updated correctly - String indexContents = blob.readFileAsString(new File ("git/index")); - if (indexContents.equals(blobName+" newFile.txt" + "\n" + blob2.getBlobName()+" newFile2.txt" + "\n")){ - System.out.println ("index was updated correctly"); + try { + File git = new File("git"); + File objects = new File(git, "objects"); + File commitFile = new File(objects, hash); + CommitFile commit = CommitFile.read(commitFile); + File treeFile = new File(objects, commit.tree); + String treeData = Blob.readFileAsString(treeFile); + String[] lines = treeData.split("\n"); + for (var line : lines) { + handleLine(line, ""); + } + } catch (Exception e) { + Terminate.exception(e); } } + // Lovingly, + // Michael Barr + + // public static void main(String[] args) throws IOException { + // // test initialization of git repo and deletes it (then recreates it for + // further + // // testing) + // initGit(); + // checkInitGit(); + // initGit(); + + // // creates two blobs with unique file names and data + // File newFile = new File("newFile.txt"); + // newFile.createNewFile(); + // BufferedWriter bw = new BufferedWriter(new FileWriter(newFile)); + // bw.write("sfodvunaoernoienv"); + // bw.close(); + // Blob blob = new Blob("newFile.txt", false); + // File newFile2 = new File("newFile2.txt"); + // newFile.createNewFile(); + // BufferedWriter bw2 = new BufferedWriter(new FileWriter(newFile2)); + // bw2.write("sodvunaoernoien"); + // bw2.close(); + // Blob blob2 = new Blob("newFile2.txt", false); + + // // verifies that the location of a blob is correct (git/objects) + // String blobName = blob.getBlobName(); + // String desiredPath = "git/objects/" + blobName; + // File b = new File(desiredPath); + // if (b.exists() && b.isFile()) + // System.out.println("Blob exists in the correct path."); - public static void initGit() throws IOException{ - File git = new File ("git"); - File objects = new File (git, "objects"); - File index = new File (git, "index"); + // // tests that the blob has correct hash and file contents- for compressed and + // // non-compressed files + // String correctHash = ""; + // if (blob.isCompressed()) { + // correctHash = "ddd8ff69c3b86f4f8a3efcb1387a5787f464a26f"; + // if (blob.getBlobName().equals(correctHash)) { + // System.out.println("blob has correct hash/name."); + // } + // } else { + // correctHash = "aaa8b870cdae19a38f9ad6f328dbaaf31ad38965"; + // if (blob.getBlobName().equals(correctHash)) { + // System.out.println("blob has correct hash/name."); + // String BlobContents = blob.readFileAsString(b); + // String FileContents = blob.readFileAsString(newFile); + // if (BlobContents.equals(FileContents)) { + // System.out.println("blob has correct contents."); + // } + // } + // } + // // verifies that the index was updated correctly + // String indexContents = blob.readFileAsString(new File("git/index")); + // if (indexContents.equals(blobName + " newFile.txt" + "\n" + + // blob2.getBlobName() + " newFile2.txt" + "\n")) { + // System.out.println("index was updated correctly"); + // } - if (git.exists()&&objects.exists()&&index.exists()){ - System.out.println ("Git Repository already exists"); + // new Blob("dr", false); + // } + + public static void initGit() throws IOException { + File git = new File("git"); + File objects = new File(git, "objects"); + File index = new File(git, "index"); + + if (git.exists() && objects.exists() && index.exists()) { + System.out.println("Git Repository already exists"); } - if (!git.exists()){ + if (!git.exists()) { git.mkdir(); } - - if (!objects.exists()){ + if (!objects.exists()) { objects.mkdirs(); } - - if (!index.exists()){ + if (!index.exists()) { index.createNewFile(); } + + // Dear Aviv, + File head = new File(git, "HEAD"); + if (!head.exists()) + head.createNewFile(); + // Squigglingly, + // Michael Barr } - public static void checkInitGit(){ + public static void checkInitGit() { Path indexPath = Paths.get("git/index"); - if (Files.exists(indexPath)){ - System.out.println ("index file exists."); + if (Files.exists(indexPath)) { + System.out.println("index file exists."); } - + Path objectsPath = Paths.get("git/objects"); - if (Files.exists(objectsPath)){ - System.out.println ("objects directory exists."); + if (Files.exists(objectsPath)) { + System.out.println("objects directory exists."); } Path gitPath = Paths.get("git"); - if (Files.exists(gitPath)){ - System.out.println ("git directory exists."); - File gitFile = new File ("git"); - if (deleteDirectory(gitFile)){ - System.out.println ("git directory removed."); + if (Files.exists(gitPath)) { + System.out.println("git directory exists."); + File gitFile = new File("git"); + if (deleteDirectory(gitFile)) { + System.out.println("git directory removed."); } } } - //recursively deletes a directory - public static boolean deleteDirectory(File directory){ - if (directory.isDirectory()){ - File [] files = directory.listFiles(); - if (files.length>0){ - for (int i=0;i 0) { + for (int i = 0; i < files.length; i++) { deleteDirectory(files[i]); } } diff --git a/GitInterface.java b/GitInterface.java new file mode 100644 index 0000000..c0b71b7 --- /dev/null +++ b/GitInterface.java @@ -0,0 +1,24 @@ +public interface GitInterface { + /** + * Adds a file to the next commit + * + * @param path The path to the file or directory to be staged. + */ + void stage(String path); + + /** + * Creates a file defining the changes made to the repository + * + * @param author The author's username + * @param message Text field for the commit + * @return The commit's hash + */ + String commit(String author, String message); + + /** + * Restores the repository to it's state at a given commit + * + * @param hash The hash of the commit to check out + */ + void checkout(String hash); +} diff --git a/Head.java b/Head.java new file mode 100644 index 0000000..33dbdb5 --- /dev/null +++ b/Head.java @@ -0,0 +1,28 @@ +import java.io.IOException; +import java.io.File; + +public class Head { + static String getHeadCommit() { + try { + File head = new File("git/HEAD"); + if (!head.exists()) { + return null; + } + return Blob.readFileAsString(head); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + static void setHeadCommit(String commit) { + try { + File head = new File("git/HEAD"); + if (!head.exists()) { + head.createNewFile(); + } + Blob.writeFileAsString(head, commit); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/README.md b/README.md index 277bd6e..532e10c 100644 --- a/README.md +++ b/README.md @@ -1 +1,12 @@ -# git-project-NAME +1. Did you code stage() / how well does it work? +> I did! All it does is call Aviv's existing code, and I think my implementation is good. +2. Did you code commit() / how well does it work? +> I did! A commit generates a good looking commit and tree file. +3. Did you do checkout / how well does it work? +> I did! when you stage everything and make a commit and check it out it recreates the working directory. +4. What bugs did find / which of em did you fix? +> The paths in trees and index were incorrect: +> Trees from new Blob were not added to index due to a recursion bug (although subtrees were) +> The absolute path of the current directory was hardcoded and relied on +> An absolute path was used in tree files in some scenarious +I think there were a couple others, and some I haven't seen, but overall I think this was super readable mega-awesome code. \ No newline at end of file diff --git a/directoryTester.class b/directoryTester.class deleted file mode 100644 index a8031c2..0000000 Binary files a/directoryTester.class and /dev/null differ diff --git a/directoryTester.java b/directoryTester.java deleted file mode 100644 index 6e0843b..0000000 --- a/directoryTester.java +++ /dev/null @@ -1,35 +0,0 @@ -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -public class directoryTester { - public static void main(String[] args) { - // Create a new directory - File exampleDirectory = new File("exampleDirectory"); - if (!exampleDirectory.exists()) { - exampleDirectory.mkdir(); - } - - // Create two files in the directory with different data - createFile(new File(exampleDirectory, "file1.txt"), "This is the content of file 1."); - createFile(new File(exampleDirectory, "file2.txt"), "This is the content of file 2."); - - // Create a new Blob using the example directory - try { - Blob blob = new Blob(exampleDirectory.getAbsolutePath(), false); // Adjust compression as needed - System.out.println("Blob created with name: " + blob.getBlobName()); - } catch (IOException e) { - System.err.println("Error creating Blob: " + e.getMessage()); - } - } - - // Helper method to create a file with specified content - private static void createFile(File file, String content) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { - writer.write(content); - } catch (IOException e) { - System.err.println("Failed to create file: " + file.getAbsolutePath()); - } - } -} diff --git a/dr/dr2/wee.java b/dr/dr2/wee.java new file mode 100644 index 0000000..4697152 --- /dev/null +++ b/dr/dr2/wee.java @@ -0,0 +1,5 @@ +package dr.dr2; + +public class wee { + +} diff --git a/dr/shibidi.java b/dr/shibidi.java new file mode 100644 index 0000000..e69de29 diff --git a/mickeybutil/PathUtil.java b/mickeybutil/PathUtil.java new file mode 100644 index 0000000..e108166 --- /dev/null +++ b/mickeybutil/PathUtil.java @@ -0,0 +1,10 @@ +package mickeybutil; + +public class PathUtil { + public static String removeLeadingSlash(String path) { + if (path.startsWith("/")) { + return path.substring(1); + } + return path; + } +} diff --git a/mickeybutil/Terminate.java b/mickeybutil/Terminate.java new file mode 100644 index 0000000..aff01c5 --- /dev/null +++ b/mickeybutil/Terminate.java @@ -0,0 +1,14 @@ +package mickeybutil; + +public class Terminate { + public static void exception(Exception e) { + System.err.println(e); + e.printStackTrace(); + System.exit(0); + } + + public static void assertEq(Object a, Object b) { + if (!a.equals(b)) + throw new Error(a + " != " + b); + } +} diff --git a/newFile.txt b/newFile.txt index beda079..426ded2 100644 --- a/newFile.txt +++ b/newFile.txt @@ -1 +1 @@ -sodvunaoernoienv \ No newline at end of file +sfodvunaoernoienv \ No newline at end of file