diff --git a/README.md b/README.md
index 4314260..5eeb441 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,8 @@
-# java_homeworks
\ No newline at end of file
+## Мой GIT.
+Пример использования:
+
+```
+
+./mygit commit "добавлен первый файл в репозиторий"
+
+```
diff --git a/hw_git/mygit b/hw_git/mygit
new file mode 100755
index 0000000..d59a813
--- /dev/null
+++ b/hw_git/mygit
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+java -jar target/hw_git-0.0.1-SNAPSHOT.jar "$@"
diff --git a/hw_git/pom.xml b/hw_git/pom.xml
new file mode 100644
index 0000000..2402663
--- /dev/null
+++ b/hw_git/pom.xml
@@ -0,0 +1,103 @@
+
+ 4.0.0
+
+ 1
+ hw_git
+ 0.0.1-SNAPSHOT
+ jar
+
+ hw_git
+ http://maven.apache.org
+
+
+ UTF-8
+
+
+
+
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M1
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.1.0
+
+
+
+ true
+ hw_git.GitCli
+ hw_git
+ true
+ lib/
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.1.0
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+ compile
+ ${project.build.directory}/lib
+
+
+
+
+
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.9.6
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.9.6
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.9.6
+
+
+
+
+ org.apache.commons
+ commons-io
+ 1.3.2
+
+
+
diff --git a/hw_git/src/main/java/hw_git/BranchProblemException.java b/hw_git/src/main/java/hw_git/BranchProblemException.java
new file mode 100644
index 0000000..29024a1
--- /dev/null
+++ b/hw_git/src/main/java/hw_git/BranchProblemException.java
@@ -0,0 +1,8 @@
+package hw_git;
+
+public class BranchProblemException extends Exception {
+ String message;
+ public BranchProblemException(String s) {
+ message = s;
+ }
+}
diff --git a/hw_git/src/main/java/hw_git/GitCli.java b/hw_git/src/main/java/hw_git/GitCli.java
new file mode 100644
index 0000000..82c3528
--- /dev/null
+++ b/hw_git/src/main/java/hw_git/GitCli.java
@@ -0,0 +1,125 @@
+package hw_git;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Scanner;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+public class GitCli {
+ public static void printFile(Path p) {
+ try (Scanner in = new Scanner(new File(p.toString()))) {
+ System.out.println(p.toString());
+ System.out.println("--------------------------------");
+ while (in.hasNextLine()) {
+ System.out.println(in.nextLine());
+ }
+ System.out.println("--------------------------------");
+ } catch (FileNotFoundException e) {
+ System.out.println("File " + p.toString() + " not found");
+ }
+ }
+
+ public static void main(String[] args) throws JsonGenerationException, JsonMappingException {
+ System.out.println(
+ processArgs(args)
+ .stream()
+ .collect(
+ Collectors.joining("\n")
+ )
+ );
+ }
+
+ public static ArrayList processArgs(String[] args) throws JsonGenerationException, JsonMappingException{
+
+ ArrayList res = new ArrayList<>();
+
+ GitCore core = new GitCore();
+ int revision;
+
+ try {
+ switch (args[0]) {
+ case "init":
+ core.makeInit();
+ res.add("Repository initiated.");
+ break;
+ case "add":
+ res.add("Addition...");
+ core.makeAdd(Arrays.copyOfRange(args, 1, args.length));
+ break;
+ case "commit":
+ res.add("Commiting...");
+ core.makeCommit(args[1]);
+ res.add("Commit made at revision " + (core.getCurrentRevision() + 1));
+ break;
+ case "checkout":
+ if (args[1].equals("--")) {
+ res.add("Checking out files...");
+ core.makeCheckout(Arrays.copyOfRange(args, 2, args.length));
+ } else {
+ try {
+ revision = Integer.parseInt(args[1]);
+ res.add("Checkout to revision " + revision);
+ core.makeCheckout(revision - 1);
+ res.add("HEAD detached on revison " + revision);
+ } catch (NumberFormatException e) {
+ res.add("Checking out branch...");
+ core.makeCheckout(args[1]);
+ }
+ }
+ break;
+ case "reset":
+ revision = Integer.parseInt(args[1]);
+ res.add("Performing reset to revision " + revision);
+ core.makeReset(revision - 1);
+ break;
+ case "log":
+ revision = args.length == 2 ? Integer.parseInt(args[1]) : 0;
+ res.add("Log:");
+ res.addAll(core.getLog(revision - 1));
+ break;
+ case "rm":
+ res.add("Removing...");
+ core.makeRM(Arrays.copyOfRange(args, 1, args.length));
+ break;
+ case "status":
+ res.addAll(core.getStatus());
+ break;
+ case "branch":
+ if (args[1].equals("-d")) {
+ res.add("Deleting branch " + args[2]);
+ core.makeDeleteBranch(args[2]);
+ } else {
+ res.add("Making branch " + args[1]);
+ core.makeBranch(args[1]);
+ }
+ break;
+ case "merge":
+ res.add("Merging branch " + args[1] + " to current state."
+ + "\nYou should make commit then.");
+ res.addAll(core.makeMerge(args[1]));
+ break;
+ default:
+ res.add("Unknown argument: " + args[0]);
+ }
+ } catch (UnversionedException e) {
+ res.add("This directory is not versioned");
+ } catch (BranchProblemException e) {
+ res.add(e.message);
+ } catch (FileNotFoundException e) {
+ res.add(e.getMessage());
+ } catch (IOException e) {
+ res.add("IOException: " + e.getMessage());
+ } catch (ArrayIndexOutOfBoundsException e) {
+ res.add("Lack of arguments");
+ }
+
+ return res;
+ }
+}
diff --git a/hw_git/src/main/java/hw_git/GitCore.java b/hw_git/src/main/java/hw_git/GitCore.java
new file mode 100644
index 0000000..f07862f
--- /dev/null
+++ b/hw_git/src/main/java/hw_git/GitCore.java
@@ -0,0 +1,600 @@
+package hw_git;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import org.apache.commons.io.FileUtils;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class GitCore {
+ private RepInformation inform = null;
+ private Path informPath = null;
+ private final String infoFileName = ".myGitDataFile";
+ private final String storageFolder = ".myGitDataStorage";
+ private final String stageFolder = ".stageData";
+
+ void findRepInformation() throws JsonParseException, JsonMappingException, IOException, UnversionedException {
+ RepInformation result = null;
+ Path p = Paths.get("");
+
+ while (p != null && !Files.exists(p.resolve(infoFileName))) {
+ p = p.getParent();
+ }
+
+ if (p != null) {
+ ObjectMapper omapper = new ObjectMapper();
+ result = omapper.readValue(p.resolve(infoFileName).toFile(), RepInformation.class);
+ }
+
+ if (result == null) {
+ throw new UnversionedException();
+ }
+ inform = result;
+ informPath = p;
+ }
+
+ private void updateRepInformation() throws JsonGenerationException, JsonMappingException, IOException {
+ ObjectMapper omapper = new ObjectMapper();
+ omapper.writeValue(informPath.resolve(infoFileName).toFile(), inform);
+ }
+
+ void makeInit() throws JsonGenerationException, JsonMappingException, IOException, UnversionedException {
+ try {
+ findRepInformation();
+ } catch (UnversionedException e) {
+ informPath = Paths.get("");
+ inform = new RepInformation();
+ updateRepInformation();
+ }
+ }
+
+ void addAtIdx(ArrayList list, int idx, int inc) {
+ list.set(idx, list.get(idx) + inc);
+ }
+
+ private Path getKeyPath(String filename) {
+ return informPath.relativize(Paths.get(filename));
+ }
+
+ private Path getStoragePath(Path keyPath, int revision) {
+ return informPath.resolve(storageFolder)
+ .resolve(keyPath.toString() + "r" + revision);
+ }
+
+ private Path cutRoot(Path p) {
+ return p.subpath(1, p.getNameCount());
+ }
+
+ private void addFileDuringCommit(Path filepath) throws IOException {
+ int revision = inform.revision;
+ Path keyPath = cutRoot(filepath);
+ Path storage = getStoragePath(keyPath, revision);
+ storage.getParent().toFile().mkdirs();
+ Files.copy(filepath, storage);
+ String keyName = keyPath.toString();
+ if (!inform.fileNumber.containsKey(keyName)) {
+ System.out.println(keyName);
+ inform.fileNumber.put(keyName, inform.nFiles++);
+ }
+
+ Set currentRevisionFiles = inform.commitedFiles.get(revision);
+ assert inform.fileNumber.get(keyName) != null;
+ currentRevisionFiles.add(inform.fileNumber.get(keyName));
+
+ }
+
+ void makeAdd(String[] filenames) throws IOException, UnversionedException {
+ findRepInformation();
+ for (String fname : filenames) {
+ Path orig = getKeyPath(fname);
+ Path dest = informPath.resolve(stageFolder).resolve(orig);
+ FileUtils.copyFile(orig.toFile(), dest.toFile());
+ }
+ }
+
+ void makeCommit(String message) throws IOException, UnversionedException, BranchProblemException {
+ findRepInformation();
+
+ inform.revision = inform.nCommits;
+ inform.commitMessages.add(message);
+ inform.timestamps.add(new Timestamp(System.currentTimeMillis()));
+
+ {
+ inform.nCommits++;
+ inform.commitedFiles.add(new TreeSet<>());
+ inform.removedFiles.add(new TreeSet<>());
+ inform.prevCommit.add(inform.branchEnds.get(inform.currentBranchNumber));
+ inform.branchEnds.put(inform.currentBranchNumber, inform.revision);
+ inform.numberOfStartedBranchesAtRevision.add(0);
+ }
+
+ inform.removedFiles.get(inform.revision).addAll(inform.stageRemovedFiles);
+ inform.stageRemovedFiles.clear();
+
+ Files.walkFileTree(
+ informPath.resolve(stageFolder),
+ new FileVisitor() {
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ addFileDuringCommit(file);
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ updateRepInformation();
+
+
+ if (inform.currentBranchNumber == -1) {
+ throw new BranchProblemException("Staying not at end of some branch.");
+ }
+
+ }
+
+ private void deleteVersionedFiles(File root) {
+ if (root.isFile()) {
+ String key = informPath.toAbsolutePath()
+ .relativize(Paths.get(root.getAbsolutePath()))
+ .toString();
+
+ if (inform.fileNumber.containsKey(key)) {
+ root.delete();
+ }
+ return;
+ }
+ if (root.isDirectory()) {
+ for (File f : root.listFiles()) {
+ if (f.getName().equals(infoFileName) || f.getName().equals(storageFolder)) {
+ continue;
+ }
+ deleteVersionedFiles(f);
+ }
+ }
+ }
+
+ private void collectVersionedFiles(int revision, Map filesToRestore) throws IOException {
+ if (revision < 0) {
+ return;
+ }
+
+ collectVersionedFiles(inform.prevCommit.get(revision), filesToRestore);
+
+ for (Integer fileNumber : inform.commitedFiles.get(revision)) {
+ filesToRestore.put(fileNumber, revision);
+ }
+
+ for (Integer fileNumber : inform.removedFiles.get(revision)) {
+ filesToRestore.remove(fileNumber);
+ }
+
+ }
+
+ private void restoreFile(Integer fileNumber, Integer revision) throws IOException {
+ String keyName = RepInformation.getKeyByValue(fileNumber, inform.fileNumber);
+ FileUtils.copyFile(
+ informPath.resolve(getStoragePath(Paths.get(keyName), revision)).toFile(),
+ informPath.resolve(keyName).toFile()
+ );
+ }
+
+ void makeCheckout(int revision) throws IOException, UnversionedException, BranchProblemException {
+ findRepInformation();
+ if (revision >= inform.nCommits || revision < 0) {
+ throw new BranchProblemException("revision number" + (revision + 1) + " is incorrect");
+ }
+
+ deleteVersionedFiles(informPath.toAbsolutePath().toFile());
+
+ Map filesToRestore = new TreeMap<>();
+ collectVersionedFiles(revision, filesToRestore);
+
+ for (Entry fileEntry : filesToRestore.entrySet()) {
+ restoreFile(fileEntry.getKey(), fileEntry.getValue());
+ }
+
+ inform.revision = revision;
+ inform.detachedHeadRevision = revision;
+ inform.currentBranchNumber = -1;
+
+ updateRepInformation();
+ }
+
+ void makeCheckout(String branchName) throws JsonParseException, JsonMappingException, IOException, UnversionedException, BranchProblemException {
+ findRepInformation();
+ Integer branchNumber = inform.branchNumbers.get(branchName);
+ if (branchNumber == null) {
+ throw new BranchProblemException("Branch not exists: " + branchName);
+ }
+
+ int branchRevision = inform.branchEnds.get(branchNumber);
+
+ try {
+ makeCheckout(branchRevision);
+ } catch (BranchProblemException e) {}
+
+ inform.currentBranchNumber = branchNumber;
+ updateRepInformation();
+ }
+
+ private int getLastRevisionOfFile(String keyName) {
+ int revision = inform.revision;
+ while (revision >= 0 && !inform.commitedFiles.get(revision)
+ .contains(inform.fileNumber.get(keyName))) {
+ revision = inform.prevCommit.get(revision);
+ }
+ return revision;
+ }
+
+ private void checkoutFile(Path keyPath) throws IOException {
+ int revision = getLastRevisionOfFile(keyPath.toString());
+ if (revision == -1) {
+ throw new FileNotFoundException("No file " + keyPath.toString() + " found");
+ }
+ FileUtils.copyFile(getStoragePath(keyPath, revision).toFile(),
+ informPath.resolve(keyPath).toFile());
+ }
+
+ void makeCheckout(String[] files) throws JsonParseException, JsonMappingException, IOException, UnversionedException {
+ findRepInformation();
+ for (String fname : files) {
+ System.out.println("checkout key: " + fname);
+ checkoutFile(getKeyPath(fname));
+ }
+ }
+
+ void makeReset(int revision) throws JsonParseException, JsonMappingException, IOException, UnversionedException, BranchProblemException {
+ findRepInformation();
+
+ int currBranchT = inform.currentBranchNumber;
+ int currDetachedPosT = inform.detachedHeadRevision;
+ makeCheckout(revision);
+
+ FileUtils.cleanDirectory(Paths.get(stageFolder).toFile());
+ inform.stageRemovedFiles.clear();
+
+ if (currBranchT != -1) {
+ inform.currentBranchNumber = currBranchT;
+ inform.branchEnds.put(currBranchT, revision);
+ }
+ inform.detachedHeadRevision = currDetachedPosT;
+
+ updateRepInformation();
+ }
+
+ ArrayList getLog(int revision) throws JsonParseException, JsonMappingException, IOException, UnversionedException, BranchProblemException {
+ findRepInformation();
+
+ ArrayList result = new ArrayList<>();
+
+ if (revision < -1 || revision >= inform.nCommits) {
+ throw new BranchProblemException("revision number " + (revision + 1) + " is incorrect");
+ }
+
+ if (revision == -1) {
+ revision = inform.revision;
+ }
+
+ if(revision == -1) {
+ result.add("Empty log");
+ return result;
+ }
+
+ while (revision >= 0) {
+ result.add(
+ "\nrevision: " + (revision + 1) + "\n"
+ + inform.commitMessages.get(revision)
+ );
+ result.add(inform.timestamps.get(revision) + "\n");
+
+ revision = inform.prevCommit.get(revision);
+ }
+
+ return result;
+ }
+
+ List getDeletedFiles() throws JsonParseException, JsonMappingException, IOException, UnversionedException {
+ findRepInformation();
+
+ return inform.stageRemovedFiles.stream()
+ .map(i -> RepInformation.getKeyByValue(i, inform.fileNumber))
+ .collect(Collectors.toList());
+ }
+
+
+ List getChangedFiles() throws JsonParseException, JsonMappingException, IOException, UnversionedException {
+ ArrayList result = new ArrayList<>();
+ findRepInformation();
+
+ int revision = inform.revision;
+ TreeMap filesToRestore = new TreeMap<>();
+ collectVersionedFiles(revision, filesToRestore);
+ for (Entry fileEnt : filesToRestore.entrySet()) {
+ String keyName = RepInformation.getKeyByValue(
+ fileEnt.getKey(), inform.fileNumber);
+ if (!FileUtils.contentEquals(
+ informPath.resolve(keyName).toFile(),
+ getStoragePath(Paths.get(keyName), fileEnt.getValue()).toFile()))
+ {
+ result.add(keyName);
+ }
+ }
+ return result;
+ }
+
+ List getStagedFiles() throws JsonParseException, JsonMappingException, IOException, UnversionedException {
+ ArrayList result = new ArrayList<>();
+ Files.walkFileTree(informPath.resolve(stageFolder), new FileVisitor() {
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ result.add(cutRoot(file).toString());
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ return result;
+ }
+
+ List getUntrackedFiles() throws IOException {
+ ArrayList result = new ArrayList<>();
+ Files.walkFileTree(Paths.get(""), new FileVisitor() {
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ return dir.equals(Paths.get(stageFolder)) || dir.equals(Paths.get(storageFolder))
+ ? FileVisitResult.SKIP_SUBTREE : FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ if (!inform.fileNumber.containsKey(informPath.relativize(file).toString())) {
+ result.add(file.toString());
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ return result;
+ }
+
+ int getCurrentRevision() {
+ return inform.revision;
+ }
+
+
+ private void removeFromRep(String filename) throws IOException {
+ Path keypath = getKeyPath(filename);
+
+ Integer fileNumber = inform.fileNumber.get(keypath.toString());
+
+ if (fileNumber == null) {
+ throw new FileNotFoundException("File not versioned: " + filename);
+ }
+
+ inform.stageRemovedFiles.add(fileNumber);
+
+ Files.deleteIfExists(informPath.resolve(stageFolder).resolve(keypath));
+ }
+
+ void makeRM(String[] files) throws IOException, UnversionedException {
+ findRepInformation();
+ for (String filename : files) {
+ removeFromRep(filename);
+ }
+ updateRepInformation();
+ }
+
+ void makeBranch(String branchName) throws JsonParseException, JsonMappingException, IOException, UnversionedException, BranchProblemException {
+ findRepInformation();
+ if (inform.branchNumbers.containsKey(branchName)) {
+ throw new BranchProblemException("Branch already exists: " + branchName);
+ }
+
+ Integer newBranchNumber = inform.nBranches++;
+ inform.branchNumbers.put(branchName, newBranchNumber);
+ inform.branchEnds.put(newBranchNumber, inform.revision);
+ addAtIdx(inform.numberOfStartedBranchesAtRevision, inform.revision, 1);
+ updateRepInformation();
+ }
+
+ void makeDeleteBranch(String branchName) throws JsonParseException, JsonMappingException, IOException, UnversionedException, BranchProblemException {
+
+ findRepInformation();
+ Integer branchNumber = inform.branchNumbers.get(branchName);
+
+ if (branchNumber == null) {
+ throw new BranchProblemException("No such branch: " + branchName);
+ }
+
+ if (branchNumber.equals(inform.currentBranchNumber)) {
+ throw new BranchProblemException("You can't delete this branch while staying on it.");
+ }
+
+ inform.branchEnds.remove(branchNumber);
+
+ inform.branchNumbers.remove(branchName);
+
+ updateRepInformation();
+ }
+
+ private int findLCA(int u, int v) {
+ int ulen = 0, vlen = 0;
+ for (int u1 = u; u1 >= 0; u1 = inform.prevCommit.get(u1), ulen++);
+ for (int v1 = v; v1 >= 0; v1 = inform.prevCommit.get(v1), vlen++);
+
+ for (;ulen > vlen; ulen--, u = inform.prevCommit.get(u));
+ for (;vlen > ulen; vlen--, v = inform.prevCommit.get(v));
+
+ for(; u != v;
+ u = inform.prevCommit.get(u),
+ v = inform.prevCommit.get(v));
+ return u;
+ }
+
+ ArrayList makeMerge(String otherBranchName) throws JsonParseException, JsonMappingException, IOException, UnversionedException, BranchProblemException {
+ findRepInformation();
+
+ Integer otherBranchNumber = inform.branchNumbers.get(otherBranchName);
+ if (otherBranchNumber == null) {
+ throw new BranchProblemException("No branch with name " + otherBranchName + " found.");
+ }
+
+ ArrayList res = new ArrayList<>();
+ res.add("Please, resolve conflicts in these files, and \"add\" them to commit:");
+
+ int currRev = inform.revision;
+ int otherRev = inform.branchEnds.get(otherBranchNumber);
+
+ //fileNumber, revision
+ Map
+ filesToRestoreCurrent = new TreeMap<>(),
+ filesToRestoreOther = new TreeMap<>();
+
+ collectVersionedFiles(currRev, filesToRestoreCurrent);
+ collectVersionedFiles(otherRev, filesToRestoreOther);
+
+ Integer lca = findLCA(currRev, otherRev);
+
+ for (Entry fileEntry : filesToRestoreCurrent.entrySet()) {
+ Integer thisEntRevision = fileEntry.getValue();
+ Integer otherEntRevision = filesToRestoreOther.get(fileEntry.getKey());
+ Integer entFileNum = fileEntry.getKey();
+ String keyName = RepInformation.getKeyByValue(entFileNum, inform.fileNumber);
+
+ if (otherEntRevision == null
+ || otherEntRevision <= lca) {
+ } else if (thisEntRevision <= lca && otherEntRevision > lca) {
+ restoreFile(entFileNum, otherEntRevision);
+ makeAdd(new String[] {keyName});
+ } else {
+
+ File fCurr = getStoragePath(Paths.get(keyName), thisEntRevision).toFile();
+ File fOth = getStoragePath(Paths.get(keyName), otherEntRevision).toFile();
+
+ try (PrintWriter out = new PrintWriter(new File(keyName))) {
+ out.println("===============Content from revision " + (thisEntRevision + 1) + " ========");
+ try (BufferedReader in = new BufferedReader(new FileReader(fCurr))) {
+ in.lines().forEach(l -> out.println(l));
+ }
+ out.println("===============Content from revision " + (otherEntRevision + 1) + " ========");
+ try (BufferedReader in = new BufferedReader(new FileReader(fOth))) {
+ in.lines().forEach(l -> out.println(l));
+ }
+ }
+
+ res.add(keyName);
+
+ }
+ }
+
+ for (Entry fileEntry : filesToRestoreOther.entrySet()) {
+ if (!filesToRestoreCurrent.containsKey(fileEntry.getKey())) {
+ restoreFile(fileEntry.getKey(), fileEntry.getValue());
+ String keyName = RepInformation.getKeyByValue(
+ fileEntry.getKey(), inform.fileNumber);
+ makeAdd(new String[] {keyName});
+ }
+ }
+
+ updateRepInformation();
+
+ if (res.size() == 1)
+ res.clear();
+ return res;
+ }
+
+ String getCurrentBranchName() throws JsonParseException, JsonMappingException, IOException, UnversionedException {
+ findRepInformation();
+ return inform.getCurrentBranchName();
+ }
+
+ public ArrayList getStatus() throws JsonParseException, JsonMappingException, IOException, UnversionedException {
+ ArrayList result = new ArrayList<>();
+
+ findRepInformation();
+ result.add("Status:");
+ if (inform.currentBranchNumber != -1) {
+ result.add("branch " + inform.getCurrentBranchName());
+ } else {
+ result.add("detached head at revision " + (inform.detachedHeadRevision + 1));
+ }
+
+ result.add("Staged files:\n________________");
+ result.addAll(getStagedFiles());
+
+ result.add("Deleted files:\n________________");
+ result.addAll(getDeletedFiles());
+
+ result.add("Changed files:\n________________");
+ result.addAll(getChangedFiles());
+
+ result.add("Untracked files:\n________________");
+ result.addAll(getUntrackedFiles());
+
+ return result;
+ }
+}
diff --git a/hw_git/src/main/java/hw_git/RepInformation.java b/hw_git/src/main/java/hw_git/RepInformation.java
new file mode 100644
index 0000000..9e7d942
--- /dev/null
+++ b/hw_git/src/main/java/hw_git/RepInformation.java
@@ -0,0 +1,193 @@
+package hw_git;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
+public class RepInformation {
+
+ int revision = -1;
+ int currentBranchNumber = 0;
+ int detachedHeadRevision;
+
+ int nCommits = 0;
+ int nFiles = 0;
+ int nBranches = 1;
+
+ ArrayList commitMessages = new ArrayList<>();
+
+ ArrayList timestamps = new ArrayList<>();
+
+ ArrayList prevCommit = new ArrayList<>();
+
+ ArrayList> commitedFiles = new ArrayList<>();
+
+ ArrayList> removedFiles = new ArrayList<>();
+
+ TreeMap fileNumber = new TreeMap<>();
+
+ TreeMap branchNumbers = new TreeMap<>();
+
+ TreeMap branchEnds = new TreeMap<>();
+
+ ArrayList numberOfStartedBranchesAtRevision = new ArrayList<>();
+
+ ArrayList stageRemovedFiles = new ArrayList<>();
+
+ public RepInformation() {
+ branchNumbers.put("master", 0);
+ branchEnds.put(0, -1);
+ }
+
+ static K getKeyByValue(V i, Map map) {
+ for (Entry ent : map.entrySet()) {
+ if (ent.getValue().equals(i)) {
+ return ent.getKey();
+ }
+ }
+
+ return null;
+ }
+
+ String getCurrentBranchName() {
+ return getKeyByValue(currentBranchNumber, branchNumbers);
+ }
+
+ int currentBranchLastRevision() {
+ return branchEnds.get(currentBranchNumber);
+ }
+
+// Automatic getters and setters
+
+ public int getRevision() {
+ return revision;
+ }
+
+ public void setRevision(int revision) {
+ this.revision = revision;
+ }
+
+ public int getCurrentBranchNumber() {
+ return currentBranchNumber;
+ }
+
+ public void setCurrentBranchNumber(int currentBranchNumber) {
+ this.currentBranchNumber = currentBranchNumber;
+ }
+
+ public int getnCommits() {
+ return nCommits;
+ }
+
+ public void setnCommits(int nCommits) {
+ this.nCommits = nCommits;
+ }
+
+ public ArrayList getCommitMessages() {
+ return commitMessages;
+ }
+
+ public void setCommitMessages(ArrayList commitMessages) {
+ this.commitMessages = commitMessages;
+ }
+
+ public ArrayList getTimestamps() {
+ return timestamps;
+ }
+
+ public void setTimestamps(ArrayList timestamps) {
+ this.timestamps = timestamps;
+ }
+
+ public ArrayList getPrevCommit() {
+ return prevCommit;
+ }
+
+ public void setPrevCommit(ArrayList prevCommit) {
+ this.prevCommit = prevCommit;
+ }
+
+ public ArrayList> getCommitedFiles() {
+ return commitedFiles;
+ }
+
+ public void setCommitedFiles(ArrayList> commitedFiles) {
+ this.commitedFiles = commitedFiles;
+ }
+
+ public ArrayList> getRemovedFiles() {
+ return removedFiles;
+ }
+
+ public void setRemovedFiles(ArrayList> removedFiles) {
+ this.removedFiles = removedFiles;
+ }
+
+ public TreeMap getFileNumber() {
+ return fileNumber;
+ }
+
+ public void setFileNumber(TreeMap fileNumber) {
+ this.fileNumber = fileNumber;
+ }
+
+ public TreeMap getBranchNumbers() {
+ return branchNumbers;
+ }
+
+ public void setBranchNumbers(TreeMap branchNumbers) {
+ this.branchNumbers = branchNumbers;
+ }
+
+ public TreeMap getBranchEnds() {
+ return branchEnds;
+ }
+
+ public void setBranchEnds(TreeMap branchEnds) {
+ this.branchEnds = branchEnds;
+ }
+
+ public int getnFiles() {
+ return nFiles;
+ }
+
+ public void setnFiles(int nFiles) {
+ this.nFiles = nFiles;
+ }
+
+ public int getnBranches() {
+ return nBranches;
+ }
+
+ public void setnBranches(int lastBranchNumber) {
+ this.nBranches = lastBranchNumber;
+ }
+
+ public ArrayList getNumberOfStartedBranchesAtRevision() {
+ return numberOfStartedBranchesAtRevision;
+ }
+
+ public void setNumberOfStartedBranchesAtRevision(ArrayList numberOfStartedBrancesAtRevision) {
+ this.numberOfStartedBranchesAtRevision = numberOfStartedBrancesAtRevision;
+ }
+
+ public int getDetachedHeadRevision() {
+ return detachedHeadRevision;
+ }
+
+ public void setDetachedHeadRevision(int detachedHeadRevision) {
+ this.detachedHeadRevision = detachedHeadRevision;
+ }
+
+ public ArrayList getStageRemovedFiles() {
+ return stageRemovedFiles;
+ }
+
+ public void setStageRemovedFiles(ArrayList stageRemovedFiles) {
+ this.stageRemovedFiles = stageRemovedFiles;
+ }
+
+}
diff --git a/hw_git/src/main/java/hw_git/UnversionedException.java b/hw_git/src/main/java/hw_git/UnversionedException.java
new file mode 100644
index 0000000..33f9cf9
--- /dev/null
+++ b/hw_git/src/main/java/hw_git/UnversionedException.java
@@ -0,0 +1,5 @@
+package hw_git;
+
+public class UnversionedException extends Exception {
+
+}
diff --git a/hw_git/src/test/java/hw_git/AppTest.java b/hw_git/src/test/java/hw_git/AppTest.java
new file mode 100644
index 0000000..3069599
--- /dev/null
+++ b/hw_git/src/test/java/hw_git/AppTest.java
@@ -0,0 +1,379 @@
+package hw_git;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Scanner;
+import org.apache.commons.io.FileUtils;
+
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AppTest extends Assert {
+
+ public static final String storageFilename = ".myGitDataFile";
+ public static final String storageFolder = ".myGitDataStorage";
+ public static final String stageFolder = ".stageData";
+
+ //files
+ final String file1 = "testdir/file.txt";
+ final String file2 = "testdir/dir1/file_d1.txt";
+
+ @Before
+ public void setUp() throws IOException {
+ //System.out.println("setUp");
+ Files.createDirectories(Paths.get("testdir/dir1"));
+ Files.createFile(Paths.get(file2));
+ Files.createFile(Paths.get(file1));
+ Files.createFile(Paths.get("one.txt"));
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ //System.out.println("tearDown");
+ FileUtils.deleteDirectory(Paths.get("testdir").toFile());
+ FileUtils.deleteDirectory(Paths.get(storageFolder).toFile());
+ FileUtils.deleteDirectory(Paths.get(stageFolder).toFile());
+ if (Files.exists(Paths.get(storageFilename))) {
+ Files.delete(Paths.get(storageFilename));
+ }
+ if (Files.exists(Paths.get("one.txt"))) {
+ Files.delete(Paths.get("one.txt"));
+ }
+ }
+
+ @Test
+ public void testInformationLoad() throws JsonGenerationException, JsonMappingException, IOException, UnversionedException {
+ GitCli.main(new String[] {"init"});
+ GitCore core = new GitCore();
+ core.findRepInformation();
+ assertEquals(core.getCurrentRevision(), -1);
+ }
+
+ @Test(expected = UnversionedException.class)
+ public void testUnversioned() throws IOException, UnversionedException {
+ GitCore core = new GitCore();
+ core.findRepInformation();
+ }
+
+ @Test
+ public void testCheckout() throws JsonGenerationException, JsonMappingException, IOException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+ GitCli.main(new String[] {"add", file2});
+ GitCli.main(new String[] {"commit", "message 2"});
+
+ GitCli.main(new String[] {"checkout", "1"});
+ assertTrue(Files.exists(Paths.get(file1)));
+ assertFalse(Files.exists(Paths.get(file2)));
+
+ GitCli.main(new String[] {"checkout", "2"});
+ assertTrue(Files.exists(Paths.get(file1)));
+ assertTrue(Files.exists(Paths.get(file2)));
+ }
+
+ @Test
+ public void testCheckoutFiles() throws JsonGenerationException, JsonMappingException, IOException {
+ GitCli.main(new String[] {"init"});
+ try (PrintWriter out = new PrintWriter(new File(file1))) {
+ out.println("text 1");
+ }
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+ try (PrintWriter out = new PrintWriter(new File(file1))) {
+ out.println("text 2");
+ }
+
+ GitCli.main(new String[] {"checkout", "--", file1});
+ try (Scanner in = new Scanner(new File(file1))) {
+ assertTrue(in.nextLine().equals("text 1"));
+ }
+ }
+
+ @Test
+ public void testFileChangeBetweenCommits() throws JsonGenerationException, JsonMappingException, IOException {
+ GitCli.main(new String[] {"init"});
+ try (PrintWriter out = new PrintWriter(new File(file1))) {
+ out.print("commit 1 content");
+ }
+ GitCli.main(new String[] {"add", file1, file2});
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ try (PrintWriter out = new PrintWriter(new File(file1))) {
+ out.print("commit 2 content");
+ }
+
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 2"});
+
+ GitCli.main(new String[] {"checkout", "1"});
+ try (Scanner in = new Scanner(new File(file1))) {
+ assertEquals(in.nextLine(), "commit 1 content");
+ }
+
+ GitCli.main(new String[] {"checkout", "2"});
+ try (Scanner in = new Scanner(new File(file1))) {
+ assertEquals(in.nextLine(), "commit 2 content");
+ }
+ }
+
+ @Test
+ public void testRM() throws JsonGenerationException, JsonMappingException, IOException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 2"});
+ Files.delete(Paths.get(file1));
+ GitCli.main(new String[] {"rm", file1});
+ GitCli.main(new String[] {"commit", "remove file1"});
+ GitCli.main(new String[] {"checkout", "2"});
+ assertTrue(Files.exists(Paths.get(file1)));
+
+ GitCli.main(new String[] {"checkout", "1"});
+ assertTrue(Files.exists(Paths.get(file1)));
+ GitCli.main(new String[] {"checkout", "master"});
+ assertFalse(Files.exists(Paths.get(file1)));
+ }
+
+ @Test
+ public void testStatus() throws JsonGenerationException, JsonMappingException, IOException, UnversionedException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ GitCore core = new GitCore();
+ core.findRepInformation();
+
+ assertEquals(core.getChangedFiles(), Arrays.asList());
+ //assertEquals(core.getUntrackedFiles(), Arrays.asList(file2));
+ assertEquals(core.getDeletedFiles(), Arrays.asList());
+
+ try (PrintWriter out = new PrintWriter(new File(file1))) {
+ out.print("commit 3 content");
+ }
+
+ assertEquals(core.getChangedFiles(), Arrays.asList(file1));
+
+ Files.delete(Paths.get(file1));
+
+ assertEquals(core.getChangedFiles(), Arrays.asList(file1));
+
+ }
+
+ @Test
+ public void testAddBranch() throws UnversionedException, JsonParseException, IOException {
+ GitCore core = new GitCore();
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ assertEquals("master", core.getCurrentBranchName());
+
+ GitCli.main(new String[] {"branch", "b1"});
+
+ assertEquals("master", core.getCurrentBranchName());
+
+ GitCli.main(new String[] {"checkout", "b1"});
+
+ assertEquals("b1", core.getCurrentBranchName());
+ }
+
+ @Test
+ public void testFilesInBranches() throws JsonGenerationException, JsonMappingException, FileNotFoundException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ GitCli.main(new String[] {"branch", "b1"});
+ GitCli.main(new String[] {"checkout", "b1"});
+
+ try(PrintWriter out = new PrintWriter(new File(file2))) {
+ out.println("b1 content");
+ }
+ GitCli.main(new String[] {"add", file2});
+ GitCli.main(new String[] {"commit", "message 2"});
+
+ assertTrue(Files.exists(Paths.get(file1)));
+ assertTrue(Files.exists(Paths.get(file2)));
+
+ GitCli.main(new String[] {"checkout", "master"});
+
+ assertFalse(Files.exists(Paths.get(file2)));
+
+ GitCli.main(new String[] {"branch", "b2"});
+ GitCli.main(new String[] {"checkout", "b2"});
+
+ try(PrintWriter out = new PrintWriter(new File(file2))) {
+ out.println("b2 content");
+ }
+ GitCli.main(new String[] {"add", file2});
+ GitCli.main(new String[] {"commit", "message 3"});
+
+ GitCli.main(new String[] {"checkout", "b1"});
+ try (Scanner in = new Scanner(new File(file2))) {
+ assertEquals("b1 content", in.nextLine());
+ }
+ GitCli.main(new String[] {"checkout", "b2"});
+ try (Scanner in = new Scanner(new File(file2))) {
+ assertEquals("b2 content", in.nextLine());
+ }
+ }
+
+ public void testIncorrectBranchRm() throws JsonParseException, IOException, UnversionedException, BranchProblemException {
+ GitCli.main(new String[] {"init"});
+ assertEquals(
+ "You can't delete this branch while staying on it.",
+ GitCli.processArgs(new String[] {"branch", "-d", "master"})
+ .get(0));
+ }
+
+ @Test
+ public void testBranchDeleteAndRestore() throws JsonParseException, IOException, UnversionedException, BranchProblemException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ GitCli.main(new String[] {"branch", "b1"});
+ GitCli.main(new String[] {"checkout", "b1"});
+
+ GitCli.main(new String[] {"add", file2});
+ GitCli.main(new String[] {"commit", "message 2"});
+
+ GitCli.main(new String[] {"checkout", "master"});
+ GitCli.main(new String[] {"branch", "-d", "b1"});
+
+ GitCli.main(new String[] {"checkout", "0"});
+ GitCli.main(new String[] {"branch", "b1"});
+ GitCli.main(new String[] {"checkout", "b1"});
+
+ assertFalse(Files.exists(Paths.get(file2)));
+ assertTrue(Files.exists(Paths.get(file1)));
+ }
+
+ @Test
+ public void testLogBasic() throws JsonParseException, IOException, UnversionedException, BranchProblemException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+
+ assertEquals("Empty log",
+ GitCli.processArgs(new String[] {"log"}).get(1));
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ assertEquals("\nrevision: 1\nmessage 1",
+ GitCli.processArgs(new String[] {"log"}).get(1));
+ assertEquals(
+ GitCli.processArgs(new String[] {"log"}),
+ GitCli.processArgs(new String[] {"log", "1"}));
+ }
+
+
+ public void testIncorrectBigCheckoutRevision() throws JsonParseException, IOException, UnversionedException, BranchProblemException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ assertEquals(
+ "revision number" + 2 + " is incorrect",
+ GitCli.processArgs(new String[] {"checkout", "2"}).get(0));
+
+ assertEquals(
+ "revision number" + 0 + " is incorrect",
+ GitCli.processArgs(new String[] {"checkout", "0"}).get(0));
+
+ assertEquals(
+ "revision number" + 2 + " is incorrect",
+ GitCli.processArgs(new String[] {"reset", "2"}).get(0));
+
+ assertEquals(
+ "revision number" + 0 + " is incorrect",
+ GitCli.processArgs(new String[] {"reset", "0"}).get(0));
+ }
+
+ @Test
+ public void testDetachedState() throws JsonParseException, IOException, UnversionedException, BranchProblemException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 2"});
+
+ assertEquals("HEAD detached on revison 1",
+ GitCli.processArgs(new String[] {"checkout", "1"}).get(1));
+
+ assertEquals("Staying not at end of some branch.",
+ GitCli.processArgs(new String[] {"commit", "abc"}).get(1));
+ }
+
+ @Test
+ public void testEmptyCommitNotFails() throws JsonParseException, IOException, UnversionedException, BranchProblemException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", file1});
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ GitCli.main(new String[] {"commit", "message 2"});
+
+ ArrayList logRes = GitCli.processArgs(new String[] {"log"});
+ assertEquals("\nrevision: 2\nmessage 2", logRes.get(1));
+ assertEquals("\nrevision: 1\nmessage 1", logRes.get(3));
+ }
+
+ @Test
+ public void testCommitFileInRoot() throws JsonParseException, IOException, UnversionedException, BranchProblemException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", "one.txt"});
+ GitCli.main(new String[] {"commit", "message 2"});
+
+ ArrayList logRes = GitCli.processArgs(new String[] {"log"});
+ assertEquals("\nrevision: 1\nmessage 2", logRes.get(1));
+ }
+
+ @Test
+ public void testResetClearsStage() throws JsonGenerationException, JsonMappingException {
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", "one.txt"});
+ GitCli.main(new String[] {"commit", "message 1"});
+
+ GitCli.main(new String[] {"add", "testdir/file.txt"});
+ GitCli.main(new String[] {"rm", "one.txt"});
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "testdir/file.txt",
+ "Deleted files:\n________________",
+ "one.txt",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 8));
+
+ GitCli.main(new String[] {"reset", "1"});
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 6));
+ }
+
+}
diff --git a/hw_git/src/test/java/hw_git/ComplexTests.java b/hw_git/src/test/java/hw_git/ComplexTests.java
new file mode 100644
index 0000000..ac72a78
--- /dev/null
+++ b/hw_git/src/test/java/hw_git/ComplexTests.java
@@ -0,0 +1,572 @@
+package hw_git;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Scanner;
+import java.util.stream.Collectors;
+
+import org.apache.commons.io.FileUtils;
+
+public class ComplexTests extends Assert {
+
+ final String testdir = "testdir/";
+ static ArrayList removeTimestampsFromLog(ArrayList orig) {
+ ArrayList res = new ArrayList<>();
+ res.add(orig.get(0));
+ for (int i = 1; i < orig.size(); i += 2) {
+ res.add(orig.get(i));
+ }
+ return res;
+ }
+
+ @After
+ public void deleteTestFiles() throws IOException {
+ FileUtils.deleteDirectory(new File(testdir));
+ FileUtils.deleteDirectory(new File(AppTest.storageFolder));
+ FileUtils.deleteDirectory(new File(AppTest.stageFolder));
+ FileUtils.forceDelete(new File(AppTest.storageFilename));
+ }
+
+ @Test
+ public void testCheckoutWithLogAndStatus() throws IOException {
+ FileUtils.touch(Paths.get(testdir).resolve("file1").toFile());
+
+ assertEquals("This directory is not versioned",
+ GitCli.processArgs(new String[] {"add", "testdir/file1"}).get(1));
+
+ assertEquals("This directory is not versioned",
+ GitCli.processArgs(new String[] {"status"}).get(0));
+ assertEquals("This directory is not versioned",
+ GitCli.processArgs(new String[] {"log"}).get(1));
+
+ assertEquals("Repository initiated.",
+ GitCli.processArgs(new String[] {"init"}).get(0));
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 6));
+
+ assertEquals("Empty log",
+ GitCli.processArgs(new String[] {"log"}).get(1));
+
+ GitCli.main(new String[] {"add", testdir + "file1"});
+
+ assertEquals("Empty log",
+ GitCli.processArgs(new String[] {"log"}).get(1));
+
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "testdir/file1",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 7));
+
+ GitCli.main(new String[] {"commit", "mes 1"});
+
+ assertEquals(
+ Arrays.asList(
+ "Log:",
+ "\nrevision: 1\nmes 1"),
+ GitCli.processArgs(new String[] {"log"}).subList(0, 2));
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 6));
+
+ assertEquals(Arrays.asList(
+ "Commiting...",
+ "Commit made at revision 2"),
+ GitCli.processArgs(new String[] {"commit", "empty commit"}));
+
+ assertEquals(
+ Arrays.asList(
+ "Log:",
+ "\nrevision: 2\nempty commit",
+ "\nrevision: 1\nmes 1"),
+ removeTimestampsFromLog(GitCli.processArgs(new String[] {"log"})));
+
+ assertEquals(Arrays.asList(
+ "Checkout to revision 1",
+ "HEAD detached on revison 1"),
+ GitCli.processArgs(new String[] {"checkout", "1"}));
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "detached head at revision 1",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 6));
+
+ assertEquals(
+ Arrays.asList(
+ "Log:",
+ "\nrevision: 1\nmes 1"),
+ removeTimestampsFromLog(GitCli.processArgs(new String[] {"log"})));
+
+ assertEquals(Arrays.asList(
+ "Checkout to revision 2",
+ "HEAD detached on revison 2"),
+ GitCli.processArgs(new String[] {"checkout", "2"}));
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "detached head at revision 2",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 6));
+
+ assertEquals(
+ Arrays.asList(
+ "Log:",
+ "\nrevision: 2\nempty commit",
+ "\nrevision: 1\nmes 1"),
+ removeTimestampsFromLog(GitCli.processArgs(new String[] {"log"})));
+
+ assertEquals(Arrays.asList(
+ "Checking out branch..."),
+ GitCli.processArgs(new String[] {"checkout", "master"}));
+
+ assertEquals(
+ Arrays.asList(
+ "Log:",
+ "\nrevision: 2\nempty commit",
+ "\nrevision: 1\nmes 1"),
+ removeTimestampsFromLog(GitCli.processArgs(new String[] {"log"})));
+
+ GitCli.main(new String[] {"checkout", "1"});
+ GitCli.main(new String[] {"branch", "b1"});
+ GitCli.main(new String[] {"checkout", "b1"});
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch b1",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 6));
+
+ assertEquals(
+ Arrays.asList(
+ "Log:",
+ "\nrevision: 1\nmes 1"),
+ removeTimestampsFromLog(GitCli.processArgs(new String[] {"log"})));
+
+ }
+
+ @Test
+ public void testResetWithLogAndStatus() throws IOException {
+ Files.createDirectory(Paths.get(testdir));
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file1"))) {
+ out.println("initial content");
+ }
+
+ assertEquals("Repository initiated.",
+ GitCli.processArgs(new String[] {"init"}).get(0));
+
+ GitCli.main(new String[] {"add", "testdir/file1"});
+
+ GitCli.main(new String[] {"commit", "mes 1"});
+
+ try (PrintWriter out = new PrintWriter("testdir/file1")) {
+ out.println("revision 2 content");
+ }
+
+ GitCli.main(new String[] {"add", "testdir/file1"});
+
+ assertEquals(Arrays.asList(
+ "Commiting...",
+ "Commit made at revision 2"),
+ GitCli.processArgs(new String[] {"commit", "second commit"}));
+
+ try (Scanner in = new Scanner(new File("testdir/file1"))) {
+ assertEquals("revision 2 content", in.nextLine());
+ }
+
+ assertEquals(
+ Arrays.asList(
+ "Performing reset to revision 1"),
+ removeTimestampsFromLog(GitCli.processArgs(new String[] {"reset", "1"})));
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 6));
+
+ assertEquals(
+ Arrays.asList(
+ "Log:",
+ "\nrevision: 1\nmes 1"),
+ removeTimestampsFromLog(GitCli.processArgs(new String[] {"log"})));
+
+ try (Scanner in = new Scanner(new File("testdir/file1"))) {
+ assertEquals("initial content", in.nextLine());
+ }
+
+ try (PrintWriter out = new PrintWriter("testdir/file1")) {
+ out.println("reset state content");
+ }
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "testdir/file1",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 7));
+
+ GitCli.main(new String[] {"add", "testdir/file1"});
+ assertEquals(Arrays.asList(
+ "Commiting...",
+ "Commit made at revision 3"),
+ GitCli.processArgs(new String[] {"commit", "third commit"}));
+
+ try (Scanner in = new Scanner(new File("testdir/file1"))) {
+ assertEquals("reset state content", in.nextLine());
+ }
+
+ assertEquals(
+ Arrays.asList(
+ "Log:",
+ "\nrevision: 3\nthird commit",
+ "\nrevision: 1\nmes 1"),
+ removeTimestampsFromLog(GitCli.processArgs(new String[] {"log"})));
+
+ GitCli.main(new String[] {"reset", "2"});
+
+ try (Scanner in = new Scanner(new File("testdir/file1"))) {
+ assertEquals("revision 2 content", in.nextLine());
+ }
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 6));
+
+ GitCli.main(new String[] {"checkout", "1"});
+ GitCli.main(new String[] {"reset", "3"});
+
+ assertEquals(
+ Arrays.asList(
+ "Log:",
+ "\nrevision: 3\nthird commit",
+ "\nrevision: 1\nmes 1"),
+ removeTimestampsFromLog(GitCli.processArgs(new String[] {"log"})));
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "detached head at revision 1",
+ "Staged files:\n________________",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 6));
+
+ try (Scanner in = new Scanner(new File("testdir/file1"))) {
+ assertEquals("reset state content", in.nextLine());
+ }
+
+ GitCli.main(new String[] {"checkout", "master"});
+
+ try (Scanner in = new Scanner(new File("testdir/file1"))) {
+ assertEquals("revision 2 content", in.nextLine());
+ }
+ }
+
+ @Test
+ public void testBranchRM() throws IOException, UnversionedException, BranchProblemException {
+ Files.createDirectory(Paths.get(testdir));
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file1"))) {
+ out.println("initial content");
+ }
+
+ assertEquals("Repository initiated.",
+ GitCli.processArgs(new String[] {"init"}).get(0));
+
+ GitCli.main(new String[] {"add", "testdir/file1"});
+
+ GitCli.main(new String[] {"commit", "mes 1"});
+
+ try (PrintWriter out = new PrintWriter("testdir/file1")) {
+ out.println("revision 2 content");
+ }
+
+ GitCli.main(new String[] {"add", "testdir/file1"});
+
+ GitCli.main(new String[] {"commit", "mes 2"});
+ GitCli.main(new String[] {"checkout", "1"});
+
+ GitCli.main(new String[] {"branch", "b1"});
+ GitCli.main(new String[] {"checkout", "b1"});
+
+ try (PrintWriter out = new PrintWriter("testdir/file1")) {
+ out.println("revision 3 content");
+ }
+
+ GitCli.main(new String[] {"commit", "mes 3"});
+
+ ArrayList beforeRMLog = GitCli.processArgs(new String[] {"log"});
+ assertEquals(beforeRMLog, GitCli.processArgs(new String[] {"log", "3"}));
+
+ assertEquals(
+ Arrays.asList(
+ "Deleting branch b1",
+ "You can't delete this branch while staying on it."),
+ GitCli.processArgs(new String[] {"branch", "-d", "b1"}));
+
+ GitCli.main(new String[] {"checkout", "master"});
+ try (Scanner in = new Scanner(new File("testdir/file1"))) {
+ assertEquals("revision 2 content", in.nextLine());
+ }
+
+ assertEquals(
+ Arrays.asList(
+ "Deleting branch b1"),
+ GitCli.processArgs(new String[] {"branch", "-d", "b1"}));
+
+ assertEquals(beforeRMLog, GitCli.processArgs(new String[] {"log", "3"}));
+ assertEquals(
+ Arrays.asList(
+ "Checking out branch...",
+ "Branch not exists: b1"),
+ GitCli.processArgs(new String[] {"checkout", "b1"}));
+ GitCli.main(new String[] {"checkout", "3"});
+
+ assertEquals(beforeRMLog, GitCli.processArgs(new String[] {"log"}));
+ GitCore core = new GitCore();
+ core.makeBranch("b1");
+ core.makeCheckout("b1");
+ }
+
+ @Test
+ public void testMergeNoConflict() throws IOException, UnversionedException, BranchProblemException {
+ Files.createDirectory(Paths.get(testdir));
+ try (PrintWriter out = new PrintWriter(new File("testdir/file1"))) {
+ out.println("initial 1 content");
+ }
+ try (PrintWriter out = new PrintWriter(new File("testdir/file2"))) {
+ out.println("initial 2 content");
+ }
+
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", "testdir/file1", "testdir/file2"});
+ GitCli.main(new String[] {"commit", "mes 1"});
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file2"))) {
+ out.println("2 content");
+ }
+
+ GitCli.main(new String[] {"add", "testdir/file2"});
+ GitCli.main(new String[] {"commit", "mes 2"});
+
+ GitCli.main(new String[] {"checkout", "1"});
+ GitCli.main(new String[] {"branch", "b1"});
+ GitCli.main(new String[] {"checkout", "b1"});
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file3"))) {
+ out.println("3 content");
+ }
+
+ GitCli.main(new String[] {"add", "testdir/file3"});
+ GitCli.main(new String[] {"commit", "mes 3"});
+
+ GitCli.main(new String[] {"checkout", "master"});
+
+ assertEquals(Arrays.asList("Merging branch b1 to current state."
+ + "\nYou should make commit then."),
+ GitCli.processArgs(new String[] {"merge", "b1"}));
+
+ //new GitCore().makeMerge("b1");
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "testdir/file3",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 7));
+ }
+
+ @Test
+ public void testMergeWithConflicts() throws IOException, UnversionedException, BranchProblemException {
+ Files.createDirectory(Paths.get(testdir));
+ try (PrintWriter out = new PrintWriter(new File("testdir/file1"))) {
+ out.println("initial 1 content");
+ }
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file2"))) {
+ out.println("initial 2 content");
+ }
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file3"))) {
+ out.println("initial 3 content");
+ }
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file4"))) {
+ out.println("initial 4 content");
+ }
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file5"))) {
+ out.println("initial 5 content");
+ }
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file6"))) {
+ out.println("initial 6 content");
+ }
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file7"))) {
+ out.println("initial 7 content");
+ }
+
+ GitCli.main(new String[] {"init"});
+ GitCli.main(new String[] {"add", "testdir/file1", "testdir/file2", "testdir/file5"});
+ GitCli.main(new String[] {"add", "testdir/file3", "testdir/file4", "testdir/file7"});
+ GitCli.main(new String[] {"commit", "mes 1"});
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file2"))) {
+ out.println("2 content");
+ }
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file4"))) {
+ out.println("4 content");
+ }
+
+ GitCli.main(new String[] {"rm", "testdir/file7"});
+ GitCli.main(new String[] {"add", "testdir/file2", "testdir/file4"});
+ GitCli.main(new String[] {"commit", "mes 2"});
+
+ GitCli.main(new String[] {"checkout", "1"});
+ GitCli.main(new String[] {"branch", "b1"});
+ GitCli.main(new String[] {"checkout", "b1"});
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file3"))) {
+ out.println("3 from b1 content");
+ }
+
+ GitCli.main(new String[] {"rm", "testdir/file5"});
+
+ try (PrintWriter out = new PrintWriter(new File("testdir/file4"))) {
+ out.println("4 b1 content");
+ }
+ GitCli.main(new String[] {"add", "testdir/file3", "testdir/file4", "testdir/file6"});
+ GitCli.main(new String[] {"commit", "mes 3"});
+
+
+ GitCli.main(new String[] {"rm", "testdir/file6"});
+ GitCli.main(new String[] {"commit", "mes 4"});
+
+ try (Scanner in = new Scanner(new File("testdir/file6"))) {
+ assertEquals("initial 6 content", in.nextLine());
+ }
+
+ GitCli.main(new String[] {"checkout", "master"});
+
+ assertEquals(Arrays.asList("Merging branch b1 to current state."
+ + "\nYou should make commit then.",
+ "Please, resolve conflicts in these files, and \"add\" them to commit:",
+ "testdir/file4"),
+ GitCli.processArgs(new String[] {"merge", "b1"}));
+
+ //new GitCore().makeMerge("b1");
+
+ assertEquals(
+ Arrays.asList(
+ "Status:",
+ "branch master",
+ "Staged files:\n________________",
+ "testdir/file3",
+ "testdir/file7",
+ "Deleted files:\n________________",
+ "Changed files:\n________________",
+ "testdir/file3",
+ "testdir/file4",
+ "Untracked files:\n________________"),
+ GitCli.processArgs(new String[] {"status"}).subList(0, 10));
+
+ try (Scanner in = new Scanner(new File("testdir/file1"))) {
+ assertEquals("initial 1 content", in.nextLine());
+ }
+
+ try (Scanner in = new Scanner(new File("testdir/file2"))) {
+ assertEquals("2 content", in.nextLine());
+ }
+
+ try (Scanner in = new Scanner(new File("testdir/file3"))) {
+ assertEquals("3 from b1 content", in.nextLine());
+ }
+
+ try (BufferedReader in = new BufferedReader(new FileReader(new File("testdir/file4")))) {
+
+ assertEquals(Arrays.asList(
+ "===============Content from revision 2 ========",
+ "4 content",
+ "===============Content from revision 3 ========",
+ "4 b1 content")
+ , in.lines().collect(Collectors.toList()));
+ }
+
+ try (Scanner in = new Scanner(new File("testdir/file5"))) {
+ assertEquals("initial 5 content", in.nextLine());
+ }
+
+ assertFalse(Files.exists(Paths.get("testdir/file6")));
+
+ try (Scanner in = new Scanner(new File("testdir/file7"))) {
+ assertEquals("initial 7 content", in.nextLine());
+ }
+ }
+}