From 7af8692c9d56c1f9e354ecffc42719c3ebc4c6d2 Mon Sep 17 00:00:00 2001 From: lergor Date: Sat, 15 Sep 2018 15:51:41 +0300 Subject: [PATCH 01/14] Readme, gitignore and init, add --- task1_git/.gitignore | 32 ++++ task1_git/Readme.md | 38 ++++ task1_git/build.gradle | 18 ++ .../gradle/wrapper/gradle-wrapper.properties | 6 + task1_git/gradlew | 172 ++++++++++++++++++ task1_git/gradlew.bat | 84 +++++++++ task1_git/settings.gradle | 2 + task1_git/src/main/java/ru/ifmo/git/Git.java | 139 ++++++++++++++ .../main/java/ru/ifmo/git/commands/Add.java | 81 +++++++++ .../java/ru/ifmo/git/commands/Checkout.java | 5 + .../java/ru/ifmo/git/commands/Commit.java | 52 ++++++ .../main/java/ru/ifmo/git/commands/Init.java | 87 +++++++++ .../main/java/ru/ifmo/git/commands/Log.java | 15 ++ .../main/java/ru/ifmo/git/commands/Reset.java | 4 + .../java/ru/ifmo/git/util/BranchInfo.java | 21 +++ .../main/java/ru/ifmo/git/util/Command.java | 48 +++++ .../java/ru/ifmo/git/util/CommandResult.java | 41 +++++ .../java/ru/ifmo/git/util/ExitStatus.java | 5 + .../java/ru/ifmo/git/util/GitException.java | 8 + .../main/java/ru/ifmo/git/util/Message.java | 34 ++++ .../src/main/java/ru/ifmo/git/util/Utils.java | 46 +++++ .../java/ru/ifmo/git/utils/TestCommand.java | 100 ++++++++++ .../java/ru/ifmo/git/utils/TestMessage.java | 32 ++++ 23 files changed, 1070 insertions(+) create mode 100644 task1_git/.gitignore create mode 100644 task1_git/Readme.md create mode 100644 task1_git/build.gradle create mode 100644 task1_git/gradle/wrapper/gradle-wrapper.properties create mode 100755 task1_git/gradlew create mode 100644 task1_git/gradlew.bat create mode 100644 task1_git/settings.gradle create mode 100644 task1_git/src/main/java/ru/ifmo/git/Git.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/Add.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/Commit.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/Init.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/Log.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/Reset.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/BranchInfo.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/Command.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/GitException.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/Message.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/Utils.java create mode 100644 task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java create mode 100644 task1_git/src/test/java/ru/ifmo/git/utils/TestMessage.java diff --git a/task1_git/.gitignore b/task1_git/.gitignore new file mode 100644 index 0000000..feb4217 --- /dev/null +++ b/task1_git/.gitignore @@ -0,0 +1,32 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +build +.gradle +.idea +*.iml +out/ + +.m_git +kek/ \ No newline at end of file diff --git a/task1_git/Readme.md b/task1_git/Readme.md new file mode 100644 index 0000000..795551c --- /dev/null +++ b/task1_git/Readme.md @@ -0,0 +1,38 @@ +# Git + +### Description + +This repository contains simple draft of **git** +with the following commands:
+``` +init +add +commit +reset +log [from_revision] +checkout +``` +where *<smth>* means mandatory argument while *[smth]* +implies he optional one. + +### Usage + +### File hierarchy + + /* * + * + * .m_git/ + * logs/ + * {txt_log_files_for_branches} + * storage/ + * {dir_as_hashcode} + * {files} + * index/ + * refs/ + * heads/ + * {txt_files_with_hashcode_for_head} + * info/ + * {json_file_with_info_for_branch} + * HEAD - file with current HEAD + * + * */ diff --git a/task1_git/build.gradle b/task1_git/build.gradle new file mode 100644 index 0000000..9125620 --- /dev/null +++ b/task1_git/build.gradle @@ -0,0 +1,18 @@ +group 'ru.ifmo' +version '1.0-SNAPSHOT' + +apply plugin: 'java' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.12' + compile group: 'net.sourceforge.argparse4j', name: 'argparse4j', version: '0.2.0' + compile group: 'org.apache.commons', name: 'commons-io', version: '1.3.2' + implementation 'com.google.code.gson:gson:2.8.5' +} + diff --git a/task1_git/gradle/wrapper/gradle-wrapper.properties b/task1_git/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..dd32b3d --- /dev/null +++ b/task1_git/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Sep 14 13:38:27 MSK 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip diff --git a/task1_git/gradlew b/task1_git/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/task1_git/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/task1_git/gradlew.bat b/task1_git/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/task1_git/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/task1_git/settings.gradle b/task1_git/settings.gradle new file mode 100644 index 0000000..dd874e4 --- /dev/null +++ b/task1_git/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'task1_git' + diff --git a/task1_git/src/main/java/ru/ifmo/git/Git.java b/task1_git/src/main/java/ru/ifmo/git/Git.java new file mode 100644 index 0000000..8fd1566 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/Git.java @@ -0,0 +1,139 @@ +package ru.ifmo.git; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +//import net.sourceforge.argparse4j.ArgumentParsers; +//import net.sourceforge.argparse4j.inf.*; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import ru.ifmo.git.commands.Add; +import ru.ifmo.git.commands.Init; +import ru.ifmo.git.util.BranchInfo; +import ru.ifmo.git.util.Command; +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.GitException; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class Git { + + private File gitDirectory; + + private void start_session() { + String cwd = Paths.get(".").toAbsolutePath().normalize().toString(); + gitDirectory = new File(cwd + "/.m_git"); + } + +// static private ArgumentParser createParser() { +// ArgumentParser gitParser = ArgumentParsers.newArgumentParser("git"); +// gitParser.defaultHelp(true) +// .description("A version control system created by lergor."); +// +// Subparsers subparsers = gitParser.addSubparsers(); +// +// Subparser parserInit = subparsers.addParser("init") +// .help("Create an empty Git repository or reinitialize an existing one"); +// +// Subparser parserAdd = subparsers.addParser("add") +// .help("Add file contents to the index"); +// parserAdd.addArgument("file").type(String.class) +// .required(true).nargs("+"); +// +// Subparser parserCommit = subparsers.addParser("commit") +// .help("Record changes to the repository"); +// parserCommit.addArgument("message").type(String.class).required(true); +// parserCommit.addArgument("file").type(String.class).nargs("+"); +// +// Subparser parserReset = subparsers.addParser("reset") +// .help("Reset current HEAD to the specified state"); +// parserReset.addArgument("").type(String.class).required(true); +// +// Subparser parserLog = subparsers.addParser("log") +// .help("Show commit logs"); +// parserLog.addArgument("").type(String.class).nargs("?"); +// +// Subparser parserCheckout = subparsers.addParser("checkout") +// .help("Switch branches or restore working tree files"); +// parserCheckout.addArgument("").type(String.class).nargs(1); +// +// return gitParser; +// } +// +// private static void parseArguments(ArgumentParser gitParser, String[] args) { +// Namespace ns = null; +// try { +// ns = gitParser.parseArgs(args); +// } catch (ArgumentParserException e) { +// gitParser.handleError(e); +// System.exit(1); +// } +//// MessageDigest digest = null; +//// try { +//// digest = MessageDigest.getInstance(ns.getString("type")); +//// } catch (NoSuchAlgorithmException e) { +//// System.err.printf("Could not get instance of algorithm %s: %s", +//// ns.getString("type"), e.getMessage()); +//// System.exit(1); +//// } +//// for (String name : ns. getList("file")) { +//// Path path = Paths.get(name); +//// try (ByteChannel channel = Files.newByteChannel(path, +//// StandardOpenOption.READ);) { +//// ByteBuffer buffer = ByteBuffer.allocate(4096); +//// while (channel.read(buffer) > 0) { +//// buffer.flip(); +//// digest.update(buffer); +//// buffer.clear(); +//// } +//// } catch (IOException e) { +//// System.err +//// .printf("%s: failed to read data: %s", e.getMessage()); +//// continue; +//// } +//// byte md[] = digest.digest(); +//// StringBuffer sb = new StringBuffer(); +//// for (int i = 0, len = md.length; i < len; ++i) { +//// String x = Integer.toHexString(0xff & md[i]); +//// if (x.length() == 1) { +//// sb.append("0"); +//// } +//// sb.append(x); +//// } +//// System.out.printf("%s %s\n", sb.toString(), name); +//// } +// } + + public static void main(String[] args) { +// BranchInfo k = new BranchInfo("master", "812932983"); +// System.out.println(new GsonBuilder().create().toJson(k)); + List arguments = Collections.emptyList(); + CommandResult res = null; + arguments = Arrays.asList("./kek", "lol", "ckkc"); + System.out.println(arguments.subList(1, arguments.size()).toString()); + +// Init init = new Init(); +// res = init.execute(Collections.emptyList()); + +// Add add = new Add(); +// res = null; +// try { +// res = add.execute(arguments); +// } catch (GitException e) { +// System.out.println(e.getMessage()); +// } +// System.out.print(res.getMessage().read()); + + } + + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java new file mode 100644 index 0000000..212fb5a --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java @@ -0,0 +1,81 @@ +package ru.ifmo.git.commands; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import ru.ifmo.git.Git; +import ru.ifmo.git.util.*; + +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.*; + +public class Add implements Command { + + @Override + public boolean correctArgs(List args) { + if(args.isEmpty()) { + return false; + } + for (String fileName: args) { + File file = new File(fileName); + if(!file.exists()) { + return false; + } + } + return true; + } + + @Override + public CommandResult execute(List args) throws GitException { + if(!repositoryExists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: Not a git repository: .m_git\n"); + } + if(!correctArgs(args)) { + return new CommandResult(ExitStatus.ERROR, "fatal: did not match some files\n"); + } + return moveAllToIndex(args); + } + + private CommandResult moveAllToIndex(List args) { + File index = new File(getGitPath() + "/index/"); + if(index.exists() || (!index.exists() && index.mkdirs())) { + for (String fileName: args) { + if(fileName.startsWith("./")) { + fileName = fileName.substring(1, fileName.length()); + } + try { + copyToIndex(fileName); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); + } + } + } + return new CommandResult(ExitStatus.SUCCESS, "added.\n"); + + } + + private void copyToIndex(String source) throws GitException { + File sourceFile = new File(getCWD() + source); + File destinationFile = new File(getGitPath() + "/index/" + source); + if(!sourceFile.isHidden()) { + try { + if(sourceFile.isFile()) { + FileUtils.copyFileToDirectory(sourceFile, destinationFile); + } else if(sourceFile.isDirectory()) { + File[] files = sourceFile.listFiles(pathname -> !pathname.isHidden()); + if(files != null) { + for (File file: files) { + String shortPath = "/" + sourceFile.getName() + "/" + file.getName(); + copyToIndex(shortPath); + } + } + } + } catch (IOException e) { + throw new GitException("error while moving " + source + "\n"); + } + } + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java new file mode 100644 index 0000000..9a8092b --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java @@ -0,0 +1,5 @@ +package ru.ifmo.git.commands; + +public class Checkout { + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java new file mode 100644 index 0000000..1f732f0 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -0,0 +1,52 @@ +package ru.ifmo.git.commands; + +import ru.ifmo.git.util.Command; +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.ExitStatus; +import ru.ifmo.git.util.Message; + +import java.io.File; +import java.nio.file.*; +import java.util.List; + +public class Commit implements Command { + + @Override + public boolean correctArgs(List args) { + for(String fileName: args) { + File file = new File(fileName); + if(!file.exists()) { + return false; + } + } + return true; + } + + @Override + public CommandResult execute(List args) { + if(!repositoryExists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: Not a git repository: .m_git\n"); + } + if(args.isEmpty()) { + return new CommandResult(ExitStatus.ERROR, "Aborting commit due to empty commit message.\n"); + } + String message = args.get(0); + boolean needMessage = false; + if(new File(message).exists()) { + needMessage = true; + args = args.subList(1, args.size()); + } + if(!correctArgs(args)) { + return new CommandResult(ExitStatus.ERROR, "fatal: did not match some files to commit\n"); + } + + CommandResult result = new CommandResult(ExitStatus.SUCCESS); + String cwd = getCWD(); + + return result; + } + + private boolean checkLogDir() { + return false; + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java new file mode 100644 index 0000000..38b81f0 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java @@ -0,0 +1,87 @@ +package ru.ifmo.git.commands; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.apache.commons.io.IOUtils; +import ru.ifmo.git.util.*; + +import java.io.*; +import java.util.*; + +public class Init implements Command { + + private File gitDirectory = null; + + @Override + public CommandResult execute(List args) { + if(!correctArgs(args)) { + return new CommandResult(ExitStatus.ERROR, "m_git: init: wrong arguments number"); + } + gitDirectory = getGitDirectory(); + CommandResult result = new CommandResult(ExitStatus.SUCCESS); + Message message = new Message(); + if(repositoryExists()) { + message.write("Reinitialized existing "); + } else { + if(initRepository()) { + message.write("Initialized empty "); + } else { + result.setStatus(ExitStatus.FAILURE); + message.write("Fail to init "); + } + } + message.write("Git repository in " + gitDirectory.getAbsolutePath() + "\n"); + result.setMessage(message); + return result; + } + + private boolean initRepository() { + return gitDirectory.mkdir() && createDirs() && createFiles(); + } + + private boolean createDirs() { + return + createDir("/logs/") && + createDir("/storage/") && + createDir("/index/") && + createDir("/info/") && + createDir("/refs/heads/"); + } + + private boolean createFiles() { + BranchInfo masterInfo = new BranchInfo("master", ""); + String headInfo = (new Gson()).toJson(masterInfo); + return + createFile("/HEAD", headInfo); + } + + private boolean createDir(String dirName) { + File newDir = new File(gitDirectory.getAbsolutePath() + dirName); + return newDir.exists() || newDir.mkdirs(); + } + + private boolean createFile(String fileName, String content) { + File newFile = new File(gitDirectory.getAbsolutePath() + "/" + fileName); + boolean success = newFile.exists(); + if(!success) { + try { + if(newFile.createNewFile()) { + success = newFile.setReadable(true) && newFile.setWritable(true); + } + } catch (IOException e) { + success = false; + } + } + if(success) { + try(FileWriter writer = new FileWriter(newFile)) { + writer.write(content); + writer.flush(); + writer.close(); + } catch (IOException e) { + success = false; + } + } + return success; + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java new file mode 100644 index 0000000..6981d16 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -0,0 +1,15 @@ +package ru.ifmo.git.commands; + +import java.text.*; +import java.util.Calendar; + +public class Log { + // Date: Thu Sep 13 20:56:57 2018 +0300 + private static String currentTime() { + DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZ"); + Calendar calendar = Calendar.getInstance(); + return df.format(calendar.getTime()); + } + + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java new file mode 100644 index 0000000..103cde9 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java @@ -0,0 +1,4 @@ +package ru.ifmo.git.commands; + +public class Reset { +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/BranchInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/BranchInfo.java new file mode 100644 index 0000000..8fe4c9a --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/BranchInfo.java @@ -0,0 +1,21 @@ +package ru.ifmo.git.util; + +public class BranchInfo { + + public String branchName; + public String headHash; + public String historyFilePath; + public String logFilePath; + public String storagePath; + + public BranchInfo() { + } + + public BranchInfo(String branch, String head) { + branchName = branch; + headHash = head; + historyFilePath = "info/hist_" + branchName; + logFilePath = "logs/" + branchName; + storagePath = "storage/" + headHash; + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Command.java b/task1_git/src/main/java/ru/ifmo/git/util/Command.java new file mode 100644 index 0000000..127c53c --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/Command.java @@ -0,0 +1,48 @@ +package ru.ifmo.git.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.*; + +public interface Command { + + default boolean repositoryExists() { + return getGitDirectory().exists(); + } + + default boolean correctArgs(List args) { + return args == null || args.isEmpty(); + } + + + default File getGitDirectory() { + return new File(getGitPath()); + } + + default String getGitPath() { + return getCWD() + "/.m_git"; + } + + default BranchInfo getHead() throws GitException { + String headJson = ""; + try(FileInputStream inputStream = new FileInputStream(getGitPath() + "/HEAD")) { + headJson = IOUtils.toString(inputStream); + } catch (IOException e) { + throw new GitException("error while reading HEAD"); + } + return new GsonBuilder().create().fromJson(headJson, BranchInfo.class); + } + + default String getCWD() { + return Paths.get(".").toAbsolutePath().normalize().toString(); + } + + CommandResult execute(List args) throws GitException; + + } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java b/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java new file mode 100644 index 0000000..ed98fcc --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java @@ -0,0 +1,41 @@ +package ru.ifmo.git.util; + +public class CommandResult { + private ExitStatus status; + private Message message; + + public CommandResult(ExitStatus status) { + this.status = status; + this.message = new Message(); + } + + public CommandResult(ExitStatus status, Message message) { + this.status = status; + this.message = message; + } + + public CommandResult(ExitStatus status, String message) { + this.status = status; + this.message = new Message(message); + } + + public ExitStatus getStatus() { + return status; + } + + public void setStatus(ExitStatus status) { + this.status = status; + } + + public Message getMessage() { + return message; + } + + public void setMessage(Message message) { + this.message = message; + } + + public void setMessage(String message) { + this.message = new Message(message); + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java b/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java new file mode 100644 index 0000000..35de9bd --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java @@ -0,0 +1,5 @@ +package ru.ifmo.git.util; + +public enum ExitStatus { + SUCCESS, FAILURE, WARNING, ERROR +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/GitException.java b/task1_git/src/main/java/ru/ifmo/git/util/GitException.java new file mode 100644 index 0000000..fc7d729 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/GitException.java @@ -0,0 +1,8 @@ +package ru.ifmo.git.util; + +public class GitException extends Exception { + + public GitException(String message) { + super(message); + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Message.java b/task1_git/src/main/java/ru/ifmo/git/util/Message.java new file mode 100644 index 0000000..3ef5ac4 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/Message.java @@ -0,0 +1,34 @@ +package ru.ifmo.git.util; + +import java.io.*; +import java.nio.charset.StandardCharsets; + +public class Message { + + private ByteArrayOutputStream os; + + public Message() { + os = new ByteArrayOutputStream(); + } + + public Message(String text) { + os = new ByteArrayOutputStream(); + write(text); + } + + public void write(String text) { + try (Writer writer = new OutputStreamWriter(os, StandardCharsets.UTF_8)) { + writer.write(text); + } catch (IOException ignored) { + } + } + + public String read() { + return os.toString(); + } + + public void clear() { + os.reset(); + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Utils.java b/task1_git/src/main/java/ru/ifmo/git/util/Utils.java new file mode 100644 index 0000000..62dcb6e --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/Utils.java @@ -0,0 +1,46 @@ +package ru.ifmo.git.util; + +import com.google.gson.GsonBuilder; +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.List; + +public class Utils { + + void checkGitExists() throws GitException { + if(!getGitDirectory().exists()) { + throw new GitException("fatal: Not a git repository: .m_git"); + } + } + + void checkArguments(List args) throws GitException { + if(args.size() > 0) { + String commandName = this.getClass().getSimpleName().toLowerCase(); + throw new GitException("m_git: " + commandName + ": wrong arguments number"); + } + } + + File getGitDirectory() { + return new File(getGitPath()); + } + + String getGitPath() { + return Paths.get(".").toAbsolutePath().normalize().toString() + "/.m_git"; + } + + BranchInfo getHead() throws GitException { + File headFile = new File(getGitPath() + "/HEAD"); + String headJson = ""; + try(FileInputStream inputStream = new FileInputStream(getGitPath() + "/HEAD")) { + headJson = IOUtils.toString(inputStream); + } catch (IOException e) { + throw new GitException("error while reading HEAD"); + } + return new GsonBuilder().create().fromJson(headJson, BranchInfo.class); + } + +} diff --git a/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java b/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java new file mode 100644 index 0000000..1b67c89 --- /dev/null +++ b/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java @@ -0,0 +1,100 @@ +package ru.ifmo.git.utils; + +import org.junit.Test; +import ru.ifmo.git.util.*; + +import static junit.framework.TestCase.*; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class TestCommand { + + private Command command = new Command() { + @Override + public CommandResult execute(List args) throws GitException { + return null; + } + }; + + @Test + public void GetGitPathTest() { + String path = command.getGitPath(); + assertEquals(Paths.get(".").toAbsolutePath().normalize().toString() + "/.m_git", path); + } + + @Test + public void GetGitDirectoryTest() { + File gitDir = command.getGitDirectory(); + assertEquals(command.getGitPath(), gitDir.getAbsolutePath()); + } + + @Test(expected = GitException.class) + public void CheckArgumentsThrowsTest() { + command.correctArgs(Arrays.asList("kek", "kek")); + } + + @Test + public void CheckArgumentsNotThrowTest() { + command.correctArgs(Collections.emptyList()); + } + + @Test + public void CheckGitExistsNotThrowTest() { + File gitDir = command.getGitDirectory(); + if(!gitDir.exists()) { + gitDir.mkdir(); + } + command.repositoryExists(); + } + + @Test + public void GetHeadTest() throws GitException, IOException { +// File headFile = new File(command.getGitPath() + "/HEAD"); +// String json = "{\"branchName\":\"master\"," + +// "\"headHash\":\"812932983\"," + +// "\"historyFilePath\":\"info/hist_master\"," + +// "\"logFilePath\":\"logs/master\"," + +// "\"storagePath\":\"storage/812932983\"}"; +// +// boolean k = headFile.exists(); +// if(!k) { +// System.out.println(headFile.getAbsolutePath()); +// k = headFile.createNewFile() && +// headFile.setReadable(true) && +// headFile.setWritable(true); +// } +// if(k) { +// try(FileWriter writer = new FileWriter(headFile)) { +// writer.write(json); +// writer.flush(); +// writer.close(); +// } catch (IOException ignored) { +// System.out.println("catch"); +// } +// } +// +// +// BranchInfo info = command.getHead(); +// assertEquals("master", info.branchName); +// assertEquals("812932983", info.headHash); +// assertEquals("/info/hist_master", info.historyFilePath); +// assertEquals("/logs/master", info.logFilePath); +// assertEquals("/storage/812932983", info.branchName); +// assertTrue(headFile.delete()); + } + + @Test(expected = GitException.class) + public void CheckGitExistsThrowsTest() throws GitException { + File gitDir = command.getGitDirectory(); + if(gitDir.exists()) { + gitDir.delete(); + } + command.repositoryExists(); + } +} diff --git a/task1_git/src/test/java/ru/ifmo/git/utils/TestMessage.java b/task1_git/src/test/java/ru/ifmo/git/utils/TestMessage.java new file mode 100644 index 0000000..4147c9f --- /dev/null +++ b/task1_git/src/test/java/ru/ifmo/git/utils/TestMessage.java @@ -0,0 +1,32 @@ +package ru.ifmo.git.utils; + +import org.junit.Test; +import ru.ifmo.git.util.Message; + +import static junit.framework.TestCase.*; + +public class TestMessage { + + @Test + public void WriteThenReadTest() { + Message msg = new Message(); + msg.write("kek!"); + assertEquals("kek!", msg.read()); + } + + @Test + public void ConstructorWithStringThenReadTest() { + Message msg = new Message("kek!"); + assertEquals("kek!", msg.read()); + } + + @Test + public void WriteReadClearReadTest() { + Message msg = new Message(); + msg.write("kek!"); + assertEquals("kek!", msg.read()); + msg.clear(); + assertEquals("", msg.read()); + } + +} From 012331a0fa6f77a9ea25c90ac6e9f2203168cfde Mon Sep 17 00:00:00 2001 From: lergor Date: Sat, 15 Sep 2018 18:57:41 +0300 Subject: [PATCH 02/14] commands commit, log --- task1_git/src/main/java/ru/ifmo/git/Git.java | 34 +++--- .../main/java/ru/ifmo/git/commands/Add.java | 46 +------- .../java/ru/ifmo/git/commands/Commit.java | 72 +++++++++--- .../main/java/ru/ifmo/git/commands/Init.java | 37 +------ .../main/java/ru/ifmo/git/commands/Log.java | 58 ++++++++-- .../main/java/ru/ifmo/git/util/Command.java | 103 +++++++++++++++--- .../java/ru/ifmo/git/util/CommitInfo.java | 11 ++ .../java/ru/ifmo/git/util/ExitStatus.java | 2 +- .../util/{BranchInfo.java => HeadInfo.java} | 16 ++- .../src/main/java/ru/ifmo/git/util/Utils.java | 32 ------ 10 files changed, 245 insertions(+), 166 deletions(-) create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java rename task1_git/src/main/java/ru/ifmo/git/util/{BranchInfo.java => HeadInfo.java} (55%) diff --git a/task1_git/src/main/java/ru/ifmo/git/Git.java b/task1_git/src/main/java/ru/ifmo/git/Git.java index 8fd1566..055209e 100644 --- a/task1_git/src/main/java/ru/ifmo/git/Git.java +++ b/task1_git/src/main/java/ru/ifmo/git/Git.java @@ -3,14 +3,16 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -//import net.sourceforge.argparse4j.ArgumentParsers; -//import net.sourceforge.argparse4j.inf.*; +import net.sourceforge.argparse4j.ArgumentParsers; +import net.sourceforge.argparse4j.inf.*; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import ru.ifmo.git.commands.Add; +import ru.ifmo.git.commands.Commit; import ru.ifmo.git.commands.Init; -import ru.ifmo.git.util.BranchInfo; +import ru.ifmo.git.commands.Log; +import ru.ifmo.git.util.HeadInfo; import ru.ifmo.git.util.Command; import ru.ifmo.git.util.CommandResult; import ru.ifmo.git.util.GitException; @@ -20,10 +22,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; public class Git { @@ -116,23 +115,24 @@ private void start_session() { public static void main(String[] args) { // BranchInfo k = new BranchInfo("master", "812932983"); // System.out.println(new GsonBuilder().create().toJson(k)); - List arguments = Collections.emptyList(); - CommandResult res = null; - arguments = Arrays.asList("./kek", "lol", "ckkc"); - System.out.println(arguments.subList(1, arguments.size()).toString()); + + CommandResult res; // Init init = new Init(); // res = init.execute(Collections.emptyList()); +// System.out.print(res.getMessage().read()); // Add add = new Add(); -// res = null; -// try { -// res = add.execute(arguments); -// } catch (GitException e) { -// System.out.println(e.getMessage()); -// } +// res = add.execute(Collections.singletonList("./kek")); +// System.out.print(res.getMessage().read()); + +// Commit commit = new Commit(); +// res = commit.execute(Arrays.asList("message", "kek/")); // System.out.print(res.getMessage().read()); + Log log = new Log(); + res = log.execute(Collections.emptyList()); + System.out.print(res.getMessage().read()); } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java index 212fb5a..859d701 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java @@ -29,53 +29,17 @@ public boolean correctArgs(List args) { } @Override - public CommandResult execute(List args) throws GitException { + public CommandResult execute(List args) { if(!repositoryExists()) { return new CommandResult(ExitStatus.ERROR, "fatal: Not a git repository: .m_git\n"); } if(!correctArgs(args)) { return new CommandResult(ExitStatus.ERROR, "fatal: did not match some files\n"); } - return moveAllToIndex(args); - } - - private CommandResult moveAllToIndex(List args) { - File index = new File(getGitPath() + "/index/"); - if(index.exists() || (!index.exists() && index.mkdirs())) { - for (String fileName: args) { - if(fileName.startsWith("./")) { - fileName = fileName.substring(1, fileName.length()); - } - try { - copyToIndex(fileName); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); - } - } - } - return new CommandResult(ExitStatus.SUCCESS, "added.\n"); - - } - - private void copyToIndex(String source) throws GitException { - File sourceFile = new File(getCWD() + source); - File destinationFile = new File(getGitPath() + "/index/" + source); - if(!sourceFile.isHidden()) { - try { - if(sourceFile.isFile()) { - FileUtils.copyFileToDirectory(sourceFile, destinationFile); - } else if(sourceFile.isDirectory()) { - File[] files = sourceFile.listFiles(pathname -> !pathname.isHidden()); - if(files != null) { - for (File file: files) { - String shortPath = "/" + sourceFile.getName() + "/" + file.getName(); - copyToIndex(shortPath); - } - } - } - } catch (IOException e) { - throw new GitException("error while moving " + source + "\n"); - } + CommandResult result = copyAllToDir(args, "index"); + if(result.getStatus() == ExitStatus.ERROR) { + return result; } + return new CommandResult(ExitStatus.SUCCESS, "add: done!\n"); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index 1f732f0..0ecf4bc 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -1,16 +1,17 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.util.Command; -import ru.ifmo.git.util.CommandResult; -import ru.ifmo.git.util.ExitStatus; -import ru.ifmo.git.util.Message; +import ru.ifmo.git.util.*; -import java.io.File; -import java.nio.file.*; -import java.util.List; +import com.google.gson.Gson; +import java.io.*; +import java.text.*; +import java.util.*; public class Commit implements Command { + private HeadInfo headInfo; + private CommitInfo commitInfo = new CommitInfo(); + @Override public boolean correctArgs(List args) { for(String fileName: args) { @@ -28,25 +29,62 @@ public CommandResult execute(List args) { return new CommandResult(ExitStatus.ERROR, "fatal: Not a git repository: .m_git\n"); } if(args.isEmpty()) { - return new CommandResult(ExitStatus.ERROR, "Aborting commit due to empty commit message.\n"); + return new CommandResult(ExitStatus.ERROR, "aborting commit due to empty commit message.\n"); } - String message = args.get(0); - boolean needMessage = false; - if(new File(message).exists()) { - needMessage = true; + commitInfo.message = args.get(0); + if(new File(commitInfo.message).exists()) { + commitInfo.message = ""; + } else { args = args.subList(1, args.size()); + if(args.isEmpty()) { + return new CommandResult(ExitStatus.ERROR, "no changes added to commit\n"); + } } if(!correctArgs(args)) { return new CommandResult(ExitStatus.ERROR, "fatal: did not match some files to commit\n"); } + try { + headInfo = getHeadInfo(); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); + } + setCommitInfo(); + CommandResult result = copyAllToDir(args, headInfo.storagePath); + if(result.getStatus() == ExitStatus.ERROR) { + return result; + } + return writeLog(); + } + + private void setCommitInfo() { + commitInfo.author = System.getProperty("user.name"); - CommandResult result = new CommandResult(ExitStatus.SUCCESS); - String cwd = getCWD(); + DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZ"); + Calendar calendar = Calendar.getInstance(); + commitInfo.time = df.format(calendar.getTime()); - return result; + String hash = String.valueOf(commitInfo.time.concat(String.valueOf(getCWD())).hashCode()); + commitInfo.hash = (UUID.randomUUID().toString() + hash).replaceAll("-", ""); + + commitInfo.branch = headInfo.branchName; + + headInfo.setHeadHash(commitInfo.hash); } - private boolean checkLogDir() { - return false; + private CommandResult writeLog() { + if(commitInfo.message.isEmpty()) { + try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + System.out.print("please enter message: "); + commitInfo.message = br.readLine(); + } catch (IOException e) { + commitInfo.message = "no message"; + } + } + String logContent = (new Gson()).toJson(commitInfo); + if(!writeToFile(headInfo.logFilePath, logContent, true)) { + return new CommandResult(ExitStatus.FAILURE, "cannot write to log\n"); + } + return new CommandResult(ExitStatus.SUCCESS, "commit: done!"); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java index 38b81f0..710e24f 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java @@ -15,19 +15,19 @@ public class Init implements Command { @Override public CommandResult execute(List args) { if(!correctArgs(args)) { - return new CommandResult(ExitStatus.ERROR, "m_git: init: wrong arguments number"); + return new CommandResult(ExitStatus.ERROR, "m_git: init: wrong arguments number\n"); } gitDirectory = getGitDirectory(); CommandResult result = new CommandResult(ExitStatus.SUCCESS); Message message = new Message(); if(repositoryExists()) { - message.write("Reinitialized existing "); + message.write("reinitialized existing "); } else { if(initRepository()) { - message.write("Initialized empty "); + message.write("initialized empty "); } else { result.setStatus(ExitStatus.FAILURE); - message.write("Fail to init "); + message.write("fail to init "); } } message.write("Git repository in " + gitDirectory.getAbsolutePath() + "\n"); @@ -49,10 +49,9 @@ private boolean createDirs() { } private boolean createFiles() { - BranchInfo masterInfo = new BranchInfo("master", ""); + HeadInfo masterInfo = new HeadInfo("master"); String headInfo = (new Gson()).toJson(masterInfo); - return - createFile("/HEAD", headInfo); + return createFileWithContent("/HEAD", headInfo); } private boolean createDir(String dirName) { @@ -60,28 +59,4 @@ private boolean createDir(String dirName) { return newDir.exists() || newDir.mkdirs(); } - private boolean createFile(String fileName, String content) { - File newFile = new File(gitDirectory.getAbsolutePath() + "/" + fileName); - boolean success = newFile.exists(); - if(!success) { - try { - if(newFile.createNewFile()) { - success = newFile.setReadable(true) && newFile.setWritable(true); - } - } catch (IOException e) { - success = false; - } - } - if(success) { - try(FileWriter writer = new FileWriter(newFile)) { - writer.write(content); - writer.flush(); - writer.close(); - } catch (IOException e) { - success = false; - } - } - return success; - } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index 6981d16..802ba3e 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -1,15 +1,57 @@ package ru.ifmo.git.commands; -import java.text.*; -import java.util.Calendar; +import com.google.gson.GsonBuilder; +import org.apache.commons.io.IOUtils; +import ru.ifmo.git.util.*; -public class Log { - // Date: Thu Sep 13 20:56:57 2018 +0300 - private static String currentTime() { - DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZ"); - Calendar calendar = Calendar.getInstance(); - return df.format(calendar.getTime()); +import java.io.*; +import java.util.List; + +public class Log implements Command { + + @Override + public boolean correctArgs(List args) { + return args.size() <= 1; + } + + @Override + public CommandResult execute(List args) { + if(!repositoryExists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: Not a git repository: .m_git\n"); + } + if(!correctArgs(args)) { + return new CommandResult(ExitStatus.ERROR, "log: too many arguments\n"); + } + String logPath; + try { + logPath = getHeadInfo().logFilePath; + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, "error while reading HEAD\n"); + } + return readLog(new File(getGitPath() + "/" + logPath)); } + private CommandResult readLog(File logFile) { + if(logFile.exists()) { + Message logContent = new Message(); + try(BufferedReader br = new BufferedReader(new FileReader(logFile))) { + for(String line; (line = br.readLine()) != null; ) { + logContent.write(getCommitInfo(line + "\n")); + } + } catch (IOException e) { + return new CommandResult(ExitStatus.ERROR, "error while reading log\n"); + } + return new CommandResult(ExitStatus.SUCCESS, logContent); + } + return new CommandResult(ExitStatus.FAILURE, "fatal: your current branch 'master' does not have any commits yet\n"); + } + + private String getCommitInfo(String commitJson) { + CommitInfo commitInfo = new GsonBuilder().create().fromJson(commitJson, CommitInfo.class); + return "commit " + commitInfo.hash + "\n" + + "Author:\t" + commitInfo.author + "\n" + + "Date:\t" + commitInfo.time + "\n" + + "\t\t" + commitInfo.message + "\n\n"; + } } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Command.java b/task1_git/src/main/java/ru/ifmo/git/util/Command.java index 127c53c..565849c 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/Command.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/Command.java @@ -1,24 +1,22 @@ package ru.ifmo.git.util; -import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.nio.file.Paths; import java.util.*; public interface Command { - default boolean repositoryExists() { - return getGitDirectory().exists(); - } + default boolean repositoryExists() { + return getGitDirectory().exists(); + } - default boolean correctArgs(List args) { - return args == null || args.isEmpty(); - } + default boolean correctArgs(List args) { + return args == null || args.isEmpty(); + } default File getGitDirectory() { @@ -29,20 +27,97 @@ default String getGitPath() { return getCWD() + "/.m_git"; } - default BranchInfo getHead() throws GitException { - String headJson = ""; + default HeadInfo getHeadInfo() throws GitException { + String headJson; try(FileInputStream inputStream = new FileInputStream(getGitPath() + "/HEAD")) { headJson = IOUtils.toString(inputStream); } catch (IOException e) { - throw new GitException("error while reading HEAD"); + throw new GitException("error while reading HEAD\n"); } - return new GsonBuilder().create().fromJson(headJson, BranchInfo.class); + return new GsonBuilder().create().fromJson(headJson, HeadInfo.class); } default String getCWD() { return Paths.get(".").toAbsolutePath().normalize().toString(); } + default CommandResult copyAllToDir(List args, String destDir) { + File destination = new File(getGitPath() + "/" + destDir); + if(destination.exists() || (!destination.exists() && destination.mkdirs())) { + for (String fileName: args) { + if(fileName.startsWith("./")) { + fileName = fileName.substring(1, fileName.length()); + } + if(fileName.endsWith("/")) { + fileName = fileName.substring(0, fileName.length() - 1); + } + try { + copyTo(fileName, destDir); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); + } + } + } + return new CommandResult(ExitStatus.SUCCESS); + + } + + default void copyTo(String source, String destDir) throws GitException { + File sourceFile = new File(getCWD() + source); + File destinationFile = new File(getGitPath() + "/" + destDir + "/" + source); + if(!sourceFile.isHidden()) { + try { + if(sourceFile.isFile()) { + FileUtils.copyFileToDirectory(sourceFile, destinationFile); + } else if(sourceFile.isDirectory()) { + File[] files = sourceFile.listFiles(pathname -> !pathname.isHidden()); + if(files != null) { + for (File file: files) { + String shortPath = "/" + sourceFile.getName() + "/" + file.getName(); + copyTo(shortPath, destDir); + } + } + } + } catch (IOException e) { + String errorMsg = "error while moving " + source + " into " + getGitPath() + destDir + "\n"; + throw new GitException(errorMsg); + } + } + } + + default boolean createFileWithContent(String fileName, String content) { + return checkAndCreateFile(fileName) && writeToFile(fileName, content, false); + } + + default boolean checkAndCreateDir(String dirName) { + File dir = new File(getGitPath() + "/" + dirName); + return dir.exists() || dir.mkdirs(); + } + + default boolean checkAndCreateFile(String fileName) { + File file = new File(getGitPath() + "/" + fileName); + if(!file.exists()) { + try { + if(file.createNewFile()) { + return file.setReadable(true) && file.setWritable(true); + } + } catch (IOException e) { + return false; + } + } + return file.canRead() && file.canWrite(); + } + + default boolean writeToFile(String fileName, String content, boolean append) { + File file = new File(getGitPath() + "/" + fileName); + try(BufferedWriter writer = new BufferedWriter(new FileWriter(file, append))) { + writer.write((append ? "\n" : "") + content); + } catch (IOException e) { + return false; + } + return true; + } + CommandResult execute(List args) throws GitException; } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java new file mode 100644 index 0000000..9a7464a --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java @@ -0,0 +1,11 @@ +package ru.ifmo.git.util; + +public class CommitInfo { + public String author; + public String time; + public String hash; + public String message; + public String branch; + + public CommitInfo() {} +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java b/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java index 35de9bd..365b529 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java @@ -1,5 +1,5 @@ package ru.ifmo.git.util; public enum ExitStatus { - SUCCESS, FAILURE, WARNING, ERROR + SUCCESS, FAILURE, ERROR } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/BranchInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java similarity index 55% rename from task1_git/src/main/java/ru/ifmo/git/util/BranchInfo.java rename to task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java index 8fe4c9a..7931121 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/BranchInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java @@ -1,6 +1,6 @@ package ru.ifmo.git.util; -public class BranchInfo { +public class HeadInfo { public String branchName; public String headHash; @@ -8,14 +8,20 @@ public class BranchInfo { public String logFilePath; public String storagePath; - public BranchInfo() { + public HeadInfo() { } - public BranchInfo(String branch, String head) { + public HeadInfo(String branch) { branchName = branch; - headHash = head; + headHash = ""; historyFilePath = "info/hist_" + branchName; logFilePath = "logs/" + branchName; - storagePath = "storage/" + headHash; + storagePath = "storage"; + } + + public void setHeadHash(String hash) { + headHash = hash; + storagePath = "storage/" + hash; + } } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Utils.java b/task1_git/src/main/java/ru/ifmo/git/util/Utils.java index 62dcb6e..077d5b0 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/Utils.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/Utils.java @@ -11,36 +11,4 @@ public class Utils { - void checkGitExists() throws GitException { - if(!getGitDirectory().exists()) { - throw new GitException("fatal: Not a git repository: .m_git"); - } - } - - void checkArguments(List args) throws GitException { - if(args.size() > 0) { - String commandName = this.getClass().getSimpleName().toLowerCase(); - throw new GitException("m_git: " + commandName + ": wrong arguments number"); - } - } - - File getGitDirectory() { - return new File(getGitPath()); - } - - String getGitPath() { - return Paths.get(".").toAbsolutePath().normalize().toString() + "/.m_git"; - } - - BranchInfo getHead() throws GitException { - File headFile = new File(getGitPath() + "/HEAD"); - String headJson = ""; - try(FileInputStream inputStream = new FileInputStream(getGitPath() + "/HEAD")) { - headJson = IOUtils.toString(inputStream); - } catch (IOException e) { - throw new GitException("error while reading HEAD"); - } - return new GsonBuilder().create().fromJson(headJson, BranchInfo.class); - } - } From 7e565204b084ccaeb7a3fff31123930bcea229d0 Mon Sep 17 00:00:00 2001 From: lergor Date: Sun, 16 Sep 2018 03:04:43 +0300 Subject: [PATCH 03/14] implement all commands --- task1_git/Readme.md | 18 ++- task1_git/src/main/java/ru/ifmo/git/Git.java | 46 ++++--- .../main/java/ru/ifmo/git/commands/Add.java | 26 ++-- .../java/ru/ifmo/git/commands/Checkout.java | 26 +++- .../java/ru/ifmo/git/commands/Commit.java | 76 +++++------ .../main/java/ru/ifmo/git/commands/Init.java | 32 ++--- .../main/java/ru/ifmo/git/commands/Log.java | 66 ++++++---- .../main/java/ru/ifmo/git/commands/Reset.java | 27 +++- .../ru/ifmo/git/masters/StorageMaster.java | 89 +++++++++++++ .../main/java/ru/ifmo/git/util/Command.java | 119 ++---------------- .../java/ru/ifmo/git/util/CommandResult.java | 1 + .../java/ru/ifmo/git/util/CommitInfo.java | 7 ++ .../main/java/ru/ifmo/git/util/GitUtils.java | 90 +++++++++++++ .../main/java/ru/ifmo/git/util/HeadInfo.java | 13 +- .../src/main/java/ru/ifmo/git/util/Utils.java | 14 --- 15 files changed, 391 insertions(+), 259 deletions(-) create mode 100644 task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/GitUtils.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/util/Utils.java diff --git a/task1_git/Readme.md b/task1_git/Readme.md index 795551c..3349ecc 100644 --- a/task1_git/Readme.md +++ b/task1_git/Readme.md @@ -8,12 +8,14 @@ with the following commands:
init add commit -reset -log [from_revision] -checkout +reset +log [from_commit] +checkout ``` where *<smth>* means mandatory argument while *[smth]* -implies he optional one. +implies he optional one.
+*commit* is represented as short (at least 7 symbols) or entire hash code. + ### Usage @@ -28,11 +30,7 @@ implies he optional one. * {dir_as_hashcode} * {files} * index/ - * refs/ - * heads/ - * {txt_files_with_hashcode_for_head} - * info/ - * {json_file_with_info_for_branch} - * HEAD - file with current HEAD + * {files} + * HEAD - file with information about current state * * */ diff --git a/task1_git/src/main/java/ru/ifmo/git/Git.java b/task1_git/src/main/java/ru/ifmo/git/Git.java index 055209e..82d2982 100644 --- a/task1_git/src/main/java/ru/ifmo/git/Git.java +++ b/task1_git/src/main/java/ru/ifmo/git/Git.java @@ -6,21 +6,10 @@ import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.inf.*; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import ru.ifmo.git.commands.Add; -import ru.ifmo.git.commands.Commit; -import ru.ifmo.git.commands.Init; -import ru.ifmo.git.commands.Log; -import ru.ifmo.git.util.HeadInfo; -import ru.ifmo.git.util.Command; -import ru.ifmo.git.util.CommandResult; -import ru.ifmo.git.util.GitException; +import org.apache.commons.io.*; +import ru.ifmo.git.util.*; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; import java.nio.file.Paths; import java.util.*; @@ -113,26 +102,35 @@ private void start_session() { // } public static void main(String[] args) { -// BranchInfo k = new BranchInfo("master", "812932983"); -// System.out.println(new GsonBuilder().create().toJson(k)); - CommandResult res; // Init init = new Init(); // res = init.execute(Collections.emptyList()); // System.out.print(res.getMessage().read()); - +// // Add add = new Add(); // res = add.execute(Collections.singletonList("./kek")); // System.out.print(res.getMessage().read()); - +// // Commit commit = new Commit(); -// res = commit.execute(Arrays.asList("message", "kek/")); +// res = commit.execute(Arrays.asList("lol", "kek/")); +// System.out.print(res.getMessage().read()); +// +// Commit commit2 = new Commit(); +// res = commit2.execute(Arrays.asList("keeek", "kek/")); +// System.out.print(res.getMessage().read()); +// +// Log log = new Log(); +// res = log.execute(Collections.emptyList()); +// System.out.print(res.getMessage().read()); +// +// Checkout checkout = new Checkout(); +// res = checkout.execute(Collections.singletonList("859a0eb99")); +// System.out.print(res.getMessage().read()); +// +// Reset reset = new Reset(); +// res = reset.execute(Collections.singletonList("859a0eb99")); // System.out.print(res.getMessage().read()); - - Log log = new Log(); - res = log.execute(Collections.emptyList()); - System.out.print(res.getMessage().read()); } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java index 859d701..341651e 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java @@ -1,15 +1,9 @@ package ru.ifmo.git.commands; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import ru.ifmo.git.Git; +import ru.ifmo.git.masters.StorageMaster; import ru.ifmo.git.util.*; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Paths; +import java.io.*; import java.util.*; public class Add implements Command { @@ -30,16 +24,12 @@ public boolean correctArgs(List args) { @Override public CommandResult execute(List args) { - if(!repositoryExists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: Not a git repository: .m_git\n"); + try { + checkRepoAndArgs(args); + StorageMaster.copyAll(args, ".", ".m_git/index"); + return new CommandResult(ExitStatus.SUCCESS, "add: done!\n"); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, "add: " + e.getMessage()); } - if(!correctArgs(args)) { - return new CommandResult(ExitStatus.ERROR, "fatal: did not match some files\n"); - } - CommandResult result = copyAllToDir(args, "index"); - if(result.getStatus() == ExitStatus.ERROR) { - return result; - } - return new CommandResult(ExitStatus.SUCCESS, "add: done!\n"); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java index 9a8092b..11e0fa2 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java @@ -1,5 +1,29 @@ package ru.ifmo.git.commands; -public class Checkout { +import ru.ifmo.git.masters.StorageMaster; +import ru.ifmo.git.util.*; +import java.io.File; +import java.util.List; + +public class Checkout implements Command { + + @Override + public boolean correctArgs(List args) { + return args.size() == 1 && args.get(0).length() > 6; + } + + @Override + public CommandResult execute(List args) { + try { + checkRepoAndArgs(args); + File commitDir = GitUtils.findCommitInStorage(args.get(0)); + String storagePath = ".m_git/storage/" + commitDir.getName(); + StorageMaster.copyDirToDir(storagePath, "."); + GitUtils.changeCurHash(commitDir.getName(), true); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); + } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index 0ecf4bc..69ca324 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -1,8 +1,9 @@ package ru.ifmo.git.commands; +import ru.ifmo.git.masters.StorageMaster; import ru.ifmo.git.util.*; - import com.google.gson.Gson; + import java.io.*; import java.text.*; import java.util.*; @@ -11,11 +12,12 @@ public class Commit implements Command { private HeadInfo headInfo; private CommitInfo commitInfo = new CommitInfo(); + List arguments; @Override public boolean correctArgs(List args) { for(String fileName: args) { - File file = new File(fileName); + File file = new File(GitUtils.getGitPath() + "/index/" + fileName); if(!file.exists()) { return false; } @@ -25,35 +27,37 @@ public boolean correctArgs(List args) { @Override public CommandResult execute(List args) { - if(!repositoryExists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: Not a git repository: .m_git\n"); + try { + arguments = args; + checkUserInput(); + checkRepoAndArgs(arguments); + headInfo = GitUtils.getHeadInfo(); + setCommitInfo(); + StorageMaster.copyAll(arguments, ".m_git/index", ".m_git/storage/" + headInfo.currentHash); + writeLog(); + GitUtils.changeCurHash(commitInfo.hash, false); + return new CommandResult(ExitStatus.SUCCESS, "commit: done!\n"); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, "commit: " + e.getMessage()); } - if(args.isEmpty()) { - return new CommandResult(ExitStatus.ERROR, "aborting commit due to empty commit message.\n"); + } + + private void checkUserInput() throws GitException { + if(arguments.isEmpty()) { + throw new GitException("aborting commit due to empty commit message\n"); } - commitInfo.message = args.get(0); + commitInfo.message = arguments.get(0); if(new File(commitInfo.message).exists()) { commitInfo.message = ""; } else { - args = args.subList(1, args.size()); - if(args.isEmpty()) { - return new CommandResult(ExitStatus.ERROR, "no changes added to commit\n"); + arguments = arguments.subList(1, arguments.size()); + if(arguments.isEmpty()) { + throw new GitException("no changes added to commit\n"); } } - if(!correctArgs(args)) { - return new CommandResult(ExitStatus.ERROR, "fatal: did not match some files to commit\n"); - } - try { - headInfo = getHeadInfo(); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); + if(!correctArgs(arguments)) { + throw new GitException("did not match some files to commit\n"); } - setCommitInfo(); - CommandResult result = copyAllToDir(args, headInfo.storagePath); - if(result.getStatus() == ExitStatus.ERROR) { - return result; - } - return writeLog(); } private void setCommitInfo() { @@ -63,28 +67,28 @@ private void setCommitInfo() { Calendar calendar = Calendar.getInstance(); commitInfo.time = df.format(calendar.getTime()); - String hash = String.valueOf(commitInfo.time.concat(String.valueOf(getCWD())).hashCode()); + String hash = String.valueOf(commitInfo.time.concat(String.valueOf(GitUtils.getCWD())).hashCode()); commitInfo.hash = (UUID.randomUUID().toString() + hash).replaceAll("-", ""); commitInfo.branch = headInfo.branchName; - headInfo.setHeadHash(commitInfo.hash); + headInfo.setCurrentHash(commitInfo.hash); } - private CommandResult writeLog() { + private void writeLog() throws GitException { if(commitInfo.message.isEmpty()) { - try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - System.out.print("please enter message: "); - commitInfo.message = br.readLine(); - } catch (IOException e) { - commitInfo.message = "no message"; - } + getUserMessage(); } String logContent = (new Gson()).toJson(commitInfo); - if(!writeToFile(headInfo.logFilePath, logContent, true)) { - return new CommandResult(ExitStatus.FAILURE, "cannot write to log\n"); - } - return new CommandResult(ExitStatus.SUCCESS, "commit: done!"); + GitUtils.writeToFile(GitUtils.getGitPath() + "/" + headInfo.logFilePath, logContent, true); } + private void getUserMessage() { + try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + System.out.print("please enter message: "); + commitInfo.message = br.readLine(); + } catch (IOException e) { + commitInfo.message = "no message"; + } + } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java index 710e24f..cce80b9 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java @@ -1,23 +1,27 @@ package ru.ifmo.git.commands; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import org.apache.commons.io.IOUtils; +import ru.ifmo.git.masters.StorageMaster; import ru.ifmo.git.util.*; import java.io.*; import java.util.*; +import com.google.gson.Gson; public class Init implements Command { private File gitDirectory = null; + @Override + public boolean correctArgs(List args) { + return args == null || args.size() == 0; + } + @Override public CommandResult execute(List args) { if(!correctArgs(args)) { - return new CommandResult(ExitStatus.ERROR, "m_git: init: wrong arguments number\n"); + return new CommandResult(ExitStatus.ERROR, "init: wrong arguments\n"); } - gitDirectory = getGitDirectory(); + gitDirectory = GitUtils.getGitDirectory(); CommandResult result = new CommandResult(ExitStatus.SUCCESS); Message message = new Message(); if(repositoryExists()) { @@ -26,7 +30,7 @@ public CommandResult execute(List args) { if(initRepository()) { message.write("initialized empty "); } else { - result.setStatus(ExitStatus.FAILURE); + result.setStatus(ExitStatus.ERROR); message.write("fail to init "); } } @@ -39,24 +43,22 @@ private boolean initRepository() { return gitDirectory.mkdir() && createDirs() && createFiles(); } + private boolean createDir(String dirName) { + File newDir = new File(GitUtils.getGitPath() + dirName); + return newDir.exists() || newDir.mkdirs(); + } + private boolean createDirs() { return createDir("/logs/") && createDir("/storage/") && - createDir("/index/") && - createDir("/info/") && - createDir("/refs/heads/"); + createDir("/index/"); } private boolean createFiles() { HeadInfo masterInfo = new HeadInfo("master"); String headInfo = (new Gson()).toJson(masterInfo); - return createFileWithContent("/HEAD", headInfo); - } - - private boolean createDir(String dirName) { - File newDir = new File(gitDirectory.getAbsolutePath() + dirName); - return newDir.exists() || newDir.mkdirs(); + return StorageMaster.createFileWithContent(GitUtils.getGitPath() + "/HEAD", headInfo); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index 802ba3e..097ded1 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -1,57 +1,71 @@ package ru.ifmo.git.commands; -import com.google.gson.GsonBuilder; -import org.apache.commons.io.IOUtils; import ru.ifmo.git.util.*; import java.io.*; -import java.util.List; +import java.util.*; +import java.util.function.Predicate; + public class Log implements Command { + private HeadInfo headInfo; + @Override public boolean correctArgs(List args) { - return args.size() <= 1; + return args.size() == 0 || (args.size() == 1 && args.get(0).length() > 6); } @Override public CommandResult execute(List args) { - if(!repositoryExists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: Not a git repository: .m_git\n"); - } - if(!correctArgs(args)) { - return new CommandResult(ExitStatus.ERROR, "log: too many arguments\n"); - } String logPath; try { - logPath = getHeadInfo().logFilePath; + checkRepoAndArgs(args); + headInfo = GitUtils.getHeadInfo(); + logPath = headInfo.logFilePath; } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, "error while reading HEAD\n"); } - return readLog(new File(getGitPath() + "/" + logPath)); + String revisionToStart = ""; + if(args.size() == 1) { + revisionToStart = args.get(0); + } + return readLog(new File(GitUtils.getGitPath() + "/" + logPath), revisionToStart); } - private CommandResult readLog(File logFile) { + private CommandResult readLog(File logFile, String revision) { if(logFile.exists()) { Message logContent = new Message(); - try(BufferedReader br = new BufferedReader(new FileReader(logFile))) { - for(String line; (line = br.readLine()) != null; ) { - logContent.write(getCommitInfo(line + "\n")); - } - } catch (IOException e) { - return new CommandResult(ExitStatus.ERROR, "error while reading log\n"); + List history; + try { + history = GitUtils.getHistory(logFile); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); } + if(history.size() == 0) { + return emptyLogResult(); + } + history.stream().filter( + new Predicate() { + + private boolean include = (revision == null || revision.isEmpty()); + + @Override + public boolean test(CommitInfo commitInfo) { + include = include || commitInfo.hash.startsWith(revision); + return include; + } + } + ).forEach(info -> logContent.write(info.toString())); return new CommandResult(ExitStatus.SUCCESS, logContent); } - return new CommandResult(ExitStatus.FAILURE, "fatal: your current branch 'master' does not have any commits yet\n"); + return emptyLogResult(); + } - private String getCommitInfo(String commitJson) { - CommitInfo commitInfo = new GsonBuilder().create().fromJson(commitJson, CommitInfo.class); - return "commit " + commitInfo.hash + "\n" + - "Author:\t" + commitInfo.author + "\n" + - "Date:\t" + commitInfo.time + "\n" + - "\t\t" + commitInfo.message + "\n\n"; + private CommandResult emptyLogResult() { + String failMessage = "fatal: your current branch '" + headInfo.branchName + "' does not have any commits yet\n"; + return new CommandResult(ExitStatus.FAILURE, failMessage); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java index 103cde9..6e82653 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java @@ -1,4 +1,29 @@ package ru.ifmo.git.commands; -public class Reset { +import ru.ifmo.git.masters.StorageMaster; +import ru.ifmo.git.util.*; + +import java.io.File; +import java.util.List; + +public class Reset implements Command { + + @Override + public boolean correctArgs(List args) { + return args.size() == 1 && args.get(0).length() > 6; + } + + @Override + public CommandResult execute(List args) { + try { + checkRepoAndArgs(args); + File commitDir = GitUtils.findCommitInStorage(args.get(0)); + GitUtils.changeCurHash(commitDir.getName(), false); + String storagePath = ".m_git/storage/" + commitDir.getName(); + StorageMaster.copyDirToDir(storagePath, ".m_git/index/"); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); + } } diff --git a/task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java b/task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java new file mode 100644 index 0000000..3c96093 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java @@ -0,0 +1,89 @@ +package ru.ifmo.git.masters; + +import org.apache.commons.io.FileUtils; +import ru.ifmo.git.util.*; + +import java.io.*; +import java.util.*; + +public class StorageMaster { + + static public void copyAll(List args, String sourceDir, String targetDir) throws GitException { + sourceDir = GitUtils.fixDirName(sourceDir); + targetDir = GitUtils.fixDirName(targetDir); + File destination = new File(GitUtils.getCWD() + "/" + targetDir); + if(destination.exists() || (!destination.exists() && destination.mkdirs())) { + for (String fileName: args) { + fileName = GitUtils.fixFileName(fileName); + copyTo(sourceDir + "/" + fileName, targetDir + "/" + fileName); + } + } + } + + static public void copyDirToDir(String sourceDir, String targetDir) throws GitException { + File[] files = new File(sourceDir).listFiles(); + if(files != null) { + List args = new ArrayList<>(); + Arrays.stream(files).map(File::getName).forEach(args::add); + copyAll(args, sourceDir, targetDir); + } + } + + static public void copyTo(String source, String destination) throws GitException { + File sourceFile = new File(GitUtils.getCWD() + "/" + source); + if(!sourceFile.isHidden()) { + try { + if(sourceFile.isFile()) { + File destinationFile = new File(GitUtils.getCWD() + "/" + destination); + FileUtils.copyFile(sourceFile, destinationFile); + } else if(sourceFile.isDirectory()) { + checkAndCreateDir(GitUtils.getCWD() + "/" + destination); + File[] files = sourceFile.listFiles(); + if(files != null) { + for (File file: files) { + copyTo(source + "/" + file.getName(), destination + "/" + file.getName()); + } + } + } + } catch (IOException e) { + String errorMessage = "error while moving " + source + " into " + destination + "\n"; + throw new GitException(errorMessage); + } + } + } + + static public boolean createFileWithContent(String fileName, String content) { + return checkAndCreateFile(fileName) && writeToFile(fileName, content, false); + } + + static public boolean checkAndCreateDir(String dirName) { + File dir = new File(dirName); + return dir.exists() || dir.mkdirs(); + } + + static public boolean checkAndCreateFile(String fileName) { + File file = new File(fileName); + if(!file.exists()) { + try { + if(file.createNewFile()) { + return file.setReadable(true) && file.setWritable(true); + } + } catch (IOException e) { + return false; + } + } + return file.canRead() && file.canWrite(); + } + + static public boolean writeToFile(String fileName, String content, boolean append) { + File file = new File(fileName); + try(BufferedWriter writer = new BufferedWriter(new FileWriter(file, append))) { + writer.write((append ? "\n" : "") + content); + } catch (IOException e) { + return false; + } + return true; + } + + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Command.java b/task1_git/src/main/java/ru/ifmo/git/util/Command.java index 565849c..f452d3a 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/Command.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/Command.java @@ -1,123 +1,24 @@ package ru.ifmo.git.util; -import com.google.gson.GsonBuilder; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; - -import java.io.*; -import java.nio.file.Paths; import java.util.*; public interface Command { - default boolean repositoryExists() { - return getGitDirectory().exists(); - } - - default boolean correctArgs(List args) { - return args == null || args.isEmpty(); - } - - - default File getGitDirectory() { - return new File(getGitPath()); - } - - default String getGitPath() { - return getCWD() + "/.m_git"; - } - - default HeadInfo getHeadInfo() throws GitException { - String headJson; - try(FileInputStream inputStream = new FileInputStream(getGitPath() + "/HEAD")) { - headJson = IOUtils.toString(inputStream); - } catch (IOException e) { - throw new GitException("error while reading HEAD\n"); - } - return new GsonBuilder().create().fromJson(headJson, HeadInfo.class); - } - - default String getCWD() { - return Paths.get(".").toAbsolutePath().normalize().toString(); - } - - default CommandResult copyAllToDir(List args, String destDir) { - File destination = new File(getGitPath() + "/" + destDir); - if(destination.exists() || (!destination.exists() && destination.mkdirs())) { - for (String fileName: args) { - if(fileName.startsWith("./")) { - fileName = fileName.substring(1, fileName.length()); - } - if(fileName.endsWith("/")) { - fileName = fileName.substring(0, fileName.length() - 1); - } - try { - copyTo(fileName, destDir); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); - } - } - } - return new CommandResult(ExitStatus.SUCCESS); - - } - - default void copyTo(String source, String destDir) throws GitException { - File sourceFile = new File(getCWD() + source); - File destinationFile = new File(getGitPath() + "/" + destDir + "/" + source); - if(!sourceFile.isHidden()) { - try { - if(sourceFile.isFile()) { - FileUtils.copyFileToDirectory(sourceFile, destinationFile); - } else if(sourceFile.isDirectory()) { - File[] files = sourceFile.listFiles(pathname -> !pathname.isHidden()); - if(files != null) { - for (File file: files) { - String shortPath = "/" + sourceFile.getName() + "/" + file.getName(); - copyTo(shortPath, destDir); - } - } - } - } catch (IOException e) { - String errorMsg = "error while moving " + source + " into " + getGitPath() + destDir + "\n"; - throw new GitException(errorMsg); - } - } + default boolean repositoryExists() { + return GitUtils.getGitDirectory().exists(); } - default boolean createFileWithContent(String fileName, String content) { - return checkAndCreateFile(fileName) && writeToFile(fileName, content, false); - } - - default boolean checkAndCreateDir(String dirName) { - File dir = new File(getGitPath() + "/" + dirName); - return dir.exists() || dir.mkdirs(); - } + boolean correctArgs(List args); - default boolean checkAndCreateFile(String fileName) { - File file = new File(getGitPath() + "/" + fileName); - if(!file.exists()) { - try { - if(file.createNewFile()) { - return file.setReadable(true) && file.setWritable(true); - } - } catch (IOException e) { - return false; - } + default void checkRepoAndArgs(List args) throws GitException { + if(!repositoryExists()) { + throw new GitException("fatal: Not a git repository: .m_git\n"); } - return file.canRead() && file.canWrite(); - } - - default boolean writeToFile(String fileName, String content, boolean append) { - File file = new File(getGitPath() + "/" + fileName); - try(BufferedWriter writer = new BufferedWriter(new FileWriter(file, append))) { - writer.write((append ? "\n" : "") + content); - } catch (IOException e) { - return false; + if(!correctArgs(args)) { + throw new GitException("wrong arguments\n"); } - return true; } - CommandResult execute(List args) throws GitException; + CommandResult execute(List args) throws GitException; - } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java b/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java index ed98fcc..b031333 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java @@ -1,6 +1,7 @@ package ru.ifmo.git.util; public class CommandResult { + private ExitStatus status; private Message message; diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java index 9a7464a..a39a3cd 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java @@ -8,4 +8,11 @@ public class CommitInfo { public String branch; public CommitInfo() {} + + public String toString() { + return "commit " + hash + "\n" + + "Author:\t" + author + "\n" + + "Date:\t" + time + "\n" + + "\t\t" + message + "\n\n"; + } } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/GitUtils.java b/task1_git/src/main/java/ru/ifmo/git/util/GitUtils.java new file mode 100644 index 0000000..86d6696 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/GitUtils.java @@ -0,0 +1,90 @@ +package ru.ifmo.git.util; + +import com.google.gson.*; +import org.apache.commons.io.*; +import java.io.*; +import java.nio.file.Paths; +import java.util.*; + +public class GitUtils { + + static public String getCWD() { + return Paths.get(".").toAbsolutePath().normalize().toString(); + } + + static public String getGitPath() { + return GitUtils.getCWD() + "/.m_git"; + } + + static public File getGitDirectory() { + return new File(GitUtils.getGitPath()); + } + + static public List getHistory(File logFile) throws GitException { + List history = new ArrayList<>(); + try(BufferedReader br = new BufferedReader(new FileReader(logFile))) { + for(String line; (line = br.readLine()) != null;) { + history.add(new GsonBuilder().create().fromJson(line, CommitInfo.class)); + } + } catch (IOException e) { + throw new GitException("error while reading log\n"); + } + return history; + } + + public static HeadInfo getHeadInfo() throws GitException { + String headJson; + try(FileInputStream inputStream = new FileInputStream(getGitPath() + "/HEAD")) { + headJson = IOUtils.toString(inputStream); + } catch (IOException e) { + throw new GitException("error while reading HEAD\n"); + } + return new GsonBuilder().create().fromJson(headJson, HeadInfo.class); + } + + static public File findCommitInStorage(String desiredCommit) throws GitException { + File[] allCommits = new File(GitUtils.getGitPath() + "/storage").listFiles(); + if(allCommits == null || allCommits.length == 0) { + throw new GitException("no commits yet\n"); + } + Optional commitDir = Arrays.stream(allCommits) + .filter(file -> file.getName().startsWith(desiredCommit)).findFirst(); + if(!commitDir.isPresent()) { + throw new GitException("no such commit\n"); + } + return commitDir.get(); + } + + static public void writeToFile(String fileName, String content, boolean append) throws GitException { + File file = new File(fileName); + try(BufferedWriter writer = new BufferedWriter(new FileWriter(file, append))) { + writer.write(content + (append ? "\n" : "")); + } catch (IOException e) { + throw new GitException("error while writing to " + file.getName()); + } + } + + static public String fixFileName(String fileName) { + if(fileName.startsWith("./")) { + fileName = fileName.substring(2, fileName.length()); + } + if(fileName.endsWith("/")) { + fileName = fileName.substring(0, fileName.length() - 1); + } + return fileName; + } + + static public String fixDirName(String dirName) { + return (dirName.equalsIgnoreCase(".") ? "" : dirName); + } + + static public void changeCurHash(String newHash, boolean withHead) throws GitException { + HeadInfo headInfo = GitUtils.getHeadInfo(); + headInfo.setCurrentHash(newHash); + if(withHead) { + headInfo.setHeadHash(newHash); + } + String newHeadContent = (new Gson()).toJson(headInfo); + GitUtils.writeToFile(GitUtils.getGitPath() + "/HEAD", newHeadContent, false); + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java index 7931121..8e9a113 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java @@ -4,9 +4,8 @@ public class HeadInfo { public String branchName; public String headHash; - public String historyFilePath; + public String currentHash; public String logFilePath; - public String storagePath; public HeadInfo() { } @@ -14,14 +13,18 @@ public HeadInfo() { public HeadInfo(String branch) { branchName = branch; headHash = ""; - historyFilePath = "info/hist_" + branchName; + currentHash = ""; logFilePath = "logs/" + branchName; - storagePath = "storage"; } public void setHeadHash(String hash) { headHash = hash; - storagePath = "storage/" + hash; + } + public void setCurrentHash(String hash) { + if(currentHash.equals(headHash)) { + headHash = hash; + } + currentHash = hash; } } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Utils.java b/task1_git/src/main/java/ru/ifmo/git/util/Utils.java deleted file mode 100644 index 077d5b0..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/util/Utils.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.ifmo.git.util; - -import com.google.gson.GsonBuilder; -import org.apache.commons.io.IOUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.List; - -public class Utils { - -} From 7aa1823e4426755e5acf3ec2bb319cddd402e9d4 Mon Sep 17 00:00:00 2001 From: lergor Date: Tue, 18 Sep 2018 00:41:58 +0300 Subject: [PATCH 04/14] all commands final --- task1_git/Readme.md | 33 ++- task1_git/src/main/java/ru/ifmo/git/Git.java | 142 ++----------- .../main/java/ru/ifmo/git/commands/Add.java | 23 ++- .../java/ru/ifmo/git/commands/Checkout.java | 27 ++- .../java/ru/ifmo/git/commands/Commit.java | 65 +++--- .../main/java/ru/ifmo/git/commands/Init.java | 24 ++- .../main/java/ru/ifmo/git/commands/Log.java | 31 ++- .../main/java/ru/ifmo/git/commands/Reset.java | 27 ++- .../GitUtils.java => masters/FileMaster.java} | 75 +++---- .../java/ru/ifmo/git/masters/GitParser.java | 65 ++++++ .../ru/ifmo/git/masters/StorageMaster.java | 77 ++----- .../main/java/ru/ifmo/git/util/Command.java | 15 +- .../java/ru/ifmo/git/util/CommandResult.java | 1 + .../java/ru/ifmo/git/util/CommitInfo.java | 6 +- .../java/ru/ifmo/git/util/GitException.java | 1 + .../main/java/ru/ifmo/git/util/GitTree.java | 31 +++ .../main/java/ru/ifmo/git/util/HeadInfo.java | 5 - .../java/ru/ifmo/git/utils/TestCommand.java | 190 +++++++++--------- 18 files changed, 384 insertions(+), 454 deletions(-) rename task1_git/src/main/java/ru/ifmo/git/{util/GitUtils.java => masters/FileMaster.java} (55%) create mode 100644 task1_git/src/main/java/ru/ifmo/git/masters/GitParser.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/GitTree.java diff --git a/task1_git/Readme.md b/task1_git/Readme.md index 3349ecc..2865269 100644 --- a/task1_git/Readme.md +++ b/task1_git/Readme.md @@ -2,13 +2,16 @@ ### Description -This repository contains simple draft of **git** -with the following commands:
+This repository contains simple draft of **git**. + +### Usage + +The following commands are available:
``` init add commit -reset +reset log [from_commit] checkout ``` @@ -17,20 +20,14 @@ implies he optional one.
*commit* is represented as short (at least 7 symbols) or entire hash code. -### Usage - ### File hierarchy - /* * - * - * .m_git/ - * logs/ - * {txt_log_files_for_branches} - * storage/ - * {dir_as_hashcode} - * {files} - * index/ - * {files} - * HEAD - file with information about current state - * - * */ + .m_git/ + logs/ + [log_file_for_branch] + storage/ + [dir_as_hashcode] + [file] + index/ + [file] + HEAD - file with information about current state diff --git a/task1_git/src/main/java/ru/ifmo/git/Git.java b/task1_git/src/main/java/ru/ifmo/git/Git.java index 82d2982..626a22f 100644 --- a/task1_git/src/main/java/ru/ifmo/git/Git.java +++ b/task1_git/src/main/java/ru/ifmo/git/Git.java @@ -1,137 +1,27 @@ package ru.ifmo.git; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import net.sourceforge.argparse4j.ArgumentParsers; -import net.sourceforge.argparse4j.inf.*; - -import org.apache.commons.io.*; +import ru.ifmo.git.masters.GitParser; import ru.ifmo.git.util.*; -import java.io.*; -import java.nio.file.Paths; -import java.util.*; +import net.sourceforge.argparse4j.inf.*; public class Git { - private File gitDirectory; - - private void start_session() { - String cwd = Paths.get(".").toAbsolutePath().normalize().toString(); - gitDirectory = new File(cwd + "/.m_git"); - } - -// static private ArgumentParser createParser() { -// ArgumentParser gitParser = ArgumentParsers.newArgumentParser("git"); -// gitParser.defaultHelp(true) -// .description("A version control system created by lergor."); -// -// Subparsers subparsers = gitParser.addSubparsers(); -// -// Subparser parserInit = subparsers.addParser("init") -// .help("Create an empty Git repository or reinitialize an existing one"); -// -// Subparser parserAdd = subparsers.addParser("add") -// .help("Add file contents to the index"); -// parserAdd.addArgument("file").type(String.class) -// .required(true).nargs("+"); -// -// Subparser parserCommit = subparsers.addParser("commit") -// .help("Record changes to the repository"); -// parserCommit.addArgument("message").type(String.class).required(true); -// parserCommit.addArgument("file").type(String.class).nargs("+"); -// -// Subparser parserReset = subparsers.addParser("reset") -// .help("Reset current HEAD to the specified state"); -// parserReset.addArgument("").type(String.class).required(true); -// -// Subparser parserLog = subparsers.addParser("log") -// .help("Show commit logs"); -// parserLog.addArgument("").type(String.class).nargs("?"); -// -// Subparser parserCheckout = subparsers.addParser("checkout") -// .help("Switch branches or restore working tree files"); -// parserCheckout.addArgument("").type(String.class).nargs(1); -// -// return gitParser; -// } -// -// private static void parseArguments(ArgumentParser gitParser, String[] args) { -// Namespace ns = null; -// try { -// ns = gitParser.parseArgs(args); -// } catch (ArgumentParserException e) { -// gitParser.handleError(e); -// System.exit(1); -// } -//// MessageDigest digest = null; -//// try { -//// digest = MessageDigest.getInstance(ns.getString("type")); -//// } catch (NoSuchAlgorithmException e) { -//// System.err.printf("Could not get instance of algorithm %s: %s", -//// ns.getString("type"), e.getMessage()); -//// System.exit(1); -//// } -//// for (String name : ns. getList("file")) { -//// Path path = Paths.get(name); -//// try (ByteChannel channel = Files.newByteChannel(path, -//// StandardOpenOption.READ);) { -//// ByteBuffer buffer = ByteBuffer.allocate(4096); -//// while (channel.read(buffer) > 0) { -//// buffer.flip(); -//// digest.update(buffer); -//// buffer.clear(); -//// } -//// } catch (IOException e) { -//// System.err -//// .printf("%s: failed to read data: %s", e.getMessage()); -//// continue; -//// } -//// byte md[] = digest.digest(); -//// StringBuffer sb = new StringBuffer(); -//// for (int i = 0, len = md.length; i < len; ++i) { -//// String x = Integer.toHexString(0xff & md[i]); -//// if (x.length() == 1) { -//// sb.append("0"); -//// } -//// sb.append(x); -//// } -//// System.out.printf("%s %s\n", sb.toString(), name); -//// } -// } - public static void main(String[] args) { - CommandResult res; - -// Init init = new Init(); -// res = init.execute(Collections.emptyList()); -// System.out.print(res.getMessage().read()); -// -// Add add = new Add(); -// res = add.execute(Collections.singletonList("./kek")); -// System.out.print(res.getMessage().read()); -// -// Commit commit = new Commit(); -// res = commit.execute(Arrays.asList("lol", "kek/")); -// System.out.print(res.getMessage().read()); -// -// Commit commit2 = new Commit(); -// res = commit2.execute(Arrays.asList("keeek", "kek/")); -// System.out.print(res.getMessage().read()); -// -// Log log = new Log(); -// res = log.execute(Collections.emptyList()); -// System.out.print(res.getMessage().read()); -// -// Checkout checkout = new Checkout(); -// res = checkout.execute(Collections.singletonList("859a0eb99")); -// System.out.print(res.getMessage().read()); -// -// Reset reset = new Reset(); -// res = reset.execute(Collections.singletonList("859a0eb99")); -// System.out.print(res.getMessage().read()); + GitParser gitParser = new GitParser(); + try { + Namespace ns = gitParser.parseArgs(args); + Command command = (Command) ns.getAttrs().remove("cmd"); + CommandResult result = command.execute(ns.getAttrs()); + if(result.getStatus() != ExitStatus.SUCCESS) { + System.out.println("exit with code " + result.getStatus()); + } + System.out.print(result.getMessage().read()); + } catch (ArgumentParserException e) { + gitParser.handleError(e); + } catch (GitException e) { + System.out.print(e.getMessage()); + } } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java index 341651e..cc6fc74 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java @@ -1,35 +1,42 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.masters.StorageMaster; +import ru.ifmo.git.masters.*; import ru.ifmo.git.util.*; import java.io.*; +import java.nio.file.Paths; import java.util.*; public class Add implements Command { + private List files = new LinkedList<>(); + @Override - public boolean correctArgs(List args) { - if(args.isEmpty()) { + public boolean correctArgs(Map args) { + if (args.isEmpty()) { return false; } - for (String fileName: args) { - File file = new File(fileName); - if(!file.exists()) { + //noinspection unchecked + List fileNames = ((List) args.get("")); + for (String fileName : fileNames) { + File file = Paths.get(GitTree.cwd(), fileName).toFile(); + if (!file.exists()) { return false; } + files.add(file); } return true; } @Override - public CommandResult execute(List args) { + public CommandResult execute(Map args) { try { checkRepoAndArgs(args); - StorageMaster.copyAll(args, ".", ".m_git/index"); + StorageMaster.copyAll(files, new File(GitTree.index())); return new CommandResult(ExitStatus.SUCCESS, "add: done!\n"); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, "add: " + e.getMessage()); } } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java index 11e0fa2..e3588ca 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java @@ -1,29 +1,34 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.masters.StorageMaster; +import ru.ifmo.git.masters.*; import ru.ifmo.git.util.*; -import java.io.File; -import java.util.List; +import java.io.*; +import java.util.Map; + +import org.apache.commons.io.FileUtils; public class Checkout implements Command { + private String commit; + @Override - public boolean correctArgs(List args) { - return args.size() == 1 && args.get(0).length() > 6; + public boolean correctArgs(Map args) { + commit = (String) args.get(""); + return commit.length() > 6; } @Override - public CommandResult execute(List args) { + public CommandResult execute(Map args) { try { checkRepoAndArgs(args); - File commitDir = GitUtils.findCommitInStorage(args.get(0)); - String storagePath = ".m_git/storage/" + commitDir.getName(); - StorageMaster.copyDirToDir(storagePath, "."); - GitUtils.changeCurHash(commitDir.getName(), true); - } catch (GitException e) { + File commitDir = FileMaster.findCommitInStorage(commit); + FileUtils.copyDirectory(commitDir, new File(GitTree.cwd())); + FileMaster.changeCurHash(commitDir.getName(), false); + } catch (IOException | GitException e) { return new CommandResult(ExitStatus.ERROR, e.getMessage()); } return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index 69ca324..a85fe2c 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -1,10 +1,11 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.masters.StorageMaster; +import ru.ifmo.git.masters.*; import ru.ifmo.git.util.*; import com.google.gson.Gson; import java.io.*; +import java.nio.file.Paths; import java.text.*; import java.util.*; @@ -12,83 +13,71 @@ public class Commit implements Command { private HeadInfo headInfo; private CommitInfo commitInfo = new CommitInfo(); - List arguments; + private List files = new LinkedList<>(); + private String message; @Override - public boolean correctArgs(List args) { - for(String fileName: args) { - File file = new File(GitUtils.getGitPath() + "/index/" + fileName); - if(!file.exists()) { + public boolean correctArgs(Map args) { + //noinspection unchecked + List fileNames = ((List) args.get("")); + for (String fileName : fileNames) { + File file = Paths.get(GitTree.index(), fileName).toFile(); + if (!file.exists()) { return false; } + files.add(file); } + message = (String) args.get("message"); return true; } @Override - public CommandResult execute(List args) { + public CommandResult execute(Map args) { try { - arguments = args; - checkUserInput(); - checkRepoAndArgs(arguments); - headInfo = GitUtils.getHeadInfo(); + checkRepoAndArgs(args); + headInfo = FileMaster.getHeadInfo(); setCommitInfo(); - StorageMaster.copyAll(arguments, ".m_git/index", ".m_git/storage/" + headInfo.currentHash); + StorageMaster.copyAll(files, Paths.get(GitTree.storage(), headInfo.currentHash).toFile()); writeLog(); - GitUtils.changeCurHash(commitInfo.hash, false); return new CommandResult(ExitStatus.SUCCESS, "commit: done!\n"); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, "commit: " + e.getMessage()); } } - private void checkUserInput() throws GitException { - if(arguments.isEmpty()) { - throw new GitException("aborting commit due to empty commit message\n"); - } - commitInfo.message = arguments.get(0); - if(new File(commitInfo.message).exists()) { - commitInfo.message = ""; - } else { - arguments = arguments.subList(1, arguments.size()); - if(arguments.isEmpty()) { - throw new GitException("no changes added to commit\n"); - } - } - if(!correctArgs(arguments)) { - throw new GitException("did not match some files to commit\n"); - } - } - private void setCommitInfo() { + private void setCommitInfo() throws GitException { commitInfo.author = System.getProperty("user.name"); + commitInfo.message = message; + commitInfo.branch = headInfo.branchName; DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZ"); Calendar calendar = Calendar.getInstance(); commitInfo.time = df.format(calendar.getTime()); - String hash = String.valueOf(commitInfo.time.concat(String.valueOf(GitUtils.getCWD())).hashCode()); + String hash = String.valueOf(commitInfo.time.concat(String.valueOf(GitTree.cwd())).hashCode()); commitInfo.hash = (UUID.randomUUID().toString() + hash).replaceAll("-", ""); - commitInfo.branch = headInfo.branchName; - - headInfo.setCurrentHash(commitInfo.hash); + boolean moveHead = headInfo.headHash.equals(headInfo.currentHash); + FileMaster.changeCurHash(commitInfo.hash, moveHead); } private void writeLog() throws GitException { - if(commitInfo.message.isEmpty()) { + if (commitInfo.message.isEmpty()) { getUserMessage(); } String logContent = (new Gson()).toJson(commitInfo); - GitUtils.writeToFile(GitUtils.getGitPath() + "/" + headInfo.logFilePath, logContent, true); + String logFile = Paths.get(GitTree.log(), headInfo.branchName).toString(); + FileMaster.writeToFile(logFile, logContent, true); } private void getUserMessage() { - try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { System.out.print("please enter message: "); commitInfo.message = br.readLine(); } catch (IOException e) { commitInfo.message = "no message"; } } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java index cce80b9..66d0533 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java @@ -1,10 +1,12 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.masters.StorageMaster; +import ru.ifmo.git.masters.*; import ru.ifmo.git.util.*; import java.io.*; +import java.nio.file.Paths; import java.util.*; + import com.google.gson.Gson; public class Init implements Command { @@ -12,22 +14,22 @@ public class Init implements Command { private File gitDirectory = null; @Override - public boolean correctArgs(List args) { + public boolean correctArgs(Map args) { return args == null || args.size() == 0; } @Override - public CommandResult execute(List args) { - if(!correctArgs(args)) { + public CommandResult execute(Map args) { + if (!correctArgs(args)) { return new CommandResult(ExitStatus.ERROR, "init: wrong arguments\n"); } - gitDirectory = GitUtils.getGitDirectory(); + gitDirectory = Paths.get(GitTree.repo()).toFile(); CommandResult result = new CommandResult(ExitStatus.SUCCESS); Message message = new Message(); - if(repositoryExists()) { + if (repositoryExists()) { message.write("reinitialized existing "); } else { - if(initRepository()) { + if (initRepository()) { message.write("initialized empty "); } else { result.setStatus(ExitStatus.ERROR); @@ -44,21 +46,21 @@ private boolean initRepository() { } private boolean createDir(String dirName) { - File newDir = new File(GitUtils.getGitPath() + dirName); + File newDir = Paths.get(GitTree.repo(), dirName).toFile(); return newDir.exists() || newDir.mkdirs(); } private boolean createDirs() { return createDir("/logs/") && - createDir("/storage/") && - createDir("/index/"); + createDir("/storage/") && + createDir("/index/"); } private boolean createFiles() { HeadInfo masterInfo = new HeadInfo("master"); String headInfo = (new Gson()).toJson(masterInfo); - return StorageMaster.createFileWithContent(GitUtils.getGitPath() + "/HEAD", headInfo); + return StorageMaster.createFileWithContent(GitTree.head(), headInfo); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index 097ded1..0d385c5 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -1,48 +1,48 @@ package ru.ifmo.git.commands; +import ru.ifmo.git.masters.*; import ru.ifmo.git.util.*; import java.io.*; +import java.nio.file.Paths; import java.util.*; import java.util.function.Predicate; - public class Log implements Command { private HeadInfo headInfo; + private String commit; @Override - public boolean correctArgs(List args) { - return args.size() == 0 || (args.size() == 1 && args.get(0).length() > 6); + public boolean correctArgs(Map args) { + if (args.size() == 1) { + commit = (String) args.get(""); + return true; + } + return (args.size() == 0); } @Override - public CommandResult execute(List args) { - String logPath; + public CommandResult execute(Map args) { try { checkRepoAndArgs(args); - headInfo = GitUtils.getHeadInfo(); - logPath = headInfo.logFilePath; + headInfo = FileMaster.getHeadInfo(); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, "error while reading HEAD\n"); } - String revisionToStart = ""; - if(args.size() == 1) { - revisionToStart = args.get(0); - } - return readLog(new File(GitUtils.getGitPath() + "/" + logPath), revisionToStart); + return readLog(Paths.get(GitTree.log(), headInfo.branchName).toFile(), commit); } private CommandResult readLog(File logFile, String revision) { - if(logFile.exists()) { + if (logFile.exists()) { Message logContent = new Message(); List history; try { - history = GitUtils.getHistory(logFile); + history = FileMaster.getHistory(logFile); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, e.getMessage()); } - if(history.size() == 0) { + if (history.size() == 0) { return emptyLogResult(); } history.stream().filter( @@ -60,7 +60,6 @@ public boolean test(CommitInfo commitInfo) { return new CommandResult(ExitStatus.SUCCESS, logContent); } return emptyLogResult(); - } private CommandResult emptyLogResult() { diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java index 6e82653..6c8a311 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java @@ -1,29 +1,34 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.masters.StorageMaster; +import ru.ifmo.git.masters.*; import ru.ifmo.git.util.*; -import java.io.File; -import java.util.List; +import java.io.*; +import java.util.Map; + +import org.apache.commons.io.FileUtils; public class Reset implements Command { + private String commit; + @Override - public boolean correctArgs(List args) { - return args.size() == 1 && args.get(0).length() > 6; + public boolean correctArgs(Map args) { + commit = (String) args.get(""); + return commit.length() > 6; } @Override - public CommandResult execute(List args) { + public CommandResult execute(Map args) { try { checkRepoAndArgs(args); - File commitDir = GitUtils.findCommitInStorage(args.get(0)); - GitUtils.changeCurHash(commitDir.getName(), false); - String storagePath = ".m_git/storage/" + commitDir.getName(); - StorageMaster.copyDirToDir(storagePath, ".m_git/index/"); - } catch (GitException e) { + File commitDir = FileMaster.findCommitInStorage(commit); + FileUtils.copyDirectory(commitDir, new File(GitTree.index())); + FileMaster.changeCurHash(commitDir.getName(), true); + } catch (IOException | GitException e) { return new CommandResult(ExitStatus.ERROR, e.getMessage()); } return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/GitUtils.java b/task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java similarity index 55% rename from task1_git/src/main/java/ru/ifmo/git/util/GitUtils.java rename to task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java index 86d6696..a281417 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/GitUtils.java +++ b/task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java @@ -1,29 +1,19 @@ -package ru.ifmo.git.util; +package ru.ifmo.git.masters; import com.google.gson.*; import org.apache.commons.io.*; -import java.io.*; -import java.nio.file.Paths; -import java.util.*; -public class GitUtils { +import ru.ifmo.git.util.*; - static public String getCWD() { - return Paths.get(".").toAbsolutePath().normalize().toString(); - } - - static public String getGitPath() { - return GitUtils.getCWD() + "/.m_git"; - } +import java.io.*; +import java.util.*; - static public File getGitDirectory() { - return new File(GitUtils.getGitPath()); - } +public class FileMaster { static public List getHistory(File logFile) throws GitException { List history = new ArrayList<>(); - try(BufferedReader br = new BufferedReader(new FileReader(logFile))) { - for(String line; (line = br.readLine()) != null;) { + try (BufferedReader br = new BufferedReader(new FileReader(logFile))) { + for (String line; (line = br.readLine()) != null; ) { history.add(new GsonBuilder().create().fromJson(line, CommitInfo.class)); } } catch (IOException e) { @@ -34,7 +24,7 @@ static public List getHistory(File logFile) throws GitException { public static HeadInfo getHeadInfo() throws GitException { String headJson; - try(FileInputStream inputStream = new FileInputStream(getGitPath() + "/HEAD")) { + try (FileInputStream inputStream = new FileInputStream(GitTree.head())) { headJson = IOUtils.toString(inputStream); } catch (IOException e) { throw new GitException("error while reading HEAD\n"); @@ -42,49 +32,36 @@ public static HeadInfo getHeadInfo() throws GitException { return new GsonBuilder().create().fromJson(headJson, HeadInfo.class); } - static public File findCommitInStorage(String desiredCommit) throws GitException { - File[] allCommits = new File(GitUtils.getGitPath() + "/storage").listFiles(); - if(allCommits == null || allCommits.length == 0) { - throw new GitException("no commits yet\n"); - } - Optional commitDir = Arrays.stream(allCommits) - .filter(file -> file.getName().startsWith(desiredCommit)).findFirst(); - if(!commitDir.isPresent()) { - throw new GitException("no such commit\n"); - } - return commitDir.get(); - } - static public void writeToFile(String fileName, String content, boolean append) throws GitException { File file = new File(fileName); - try(BufferedWriter writer = new BufferedWriter(new FileWriter(file, append))) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file, append))) { writer.write(content + (append ? "\n" : "")); } catch (IOException e) { throw new GitException("error while writing to " + file.getName()); } } - static public String fixFileName(String fileName) { - if(fileName.startsWith("./")) { - fileName = fileName.substring(2, fileName.length()); - } - if(fileName.endsWith("/")) { - fileName = fileName.substring(0, fileName.length() - 1); - } - return fileName; - } - - static public String fixDirName(String dirName) { - return (dirName.equalsIgnoreCase(".") ? "" : dirName); - } - static public void changeCurHash(String newHash, boolean withHead) throws GitException { - HeadInfo headInfo = GitUtils.getHeadInfo(); + HeadInfo headInfo = FileMaster.getHeadInfo(); headInfo.setCurrentHash(newHash); - if(withHead) { + if (withHead) { headInfo.setHeadHash(newHash); } String newHeadContent = (new Gson()).toJson(headInfo); - GitUtils.writeToFile(GitUtils.getGitPath() + "/HEAD", newHeadContent, false); + FileMaster.writeToFile(GitTree.head(), newHeadContent, false); } + + static public File findCommitInStorage(String desiredCommit) throws GitException { + File[] allCommits = new File(GitTree.storage()).listFiles(); + if (allCommits == null || allCommits.length == 0) { + throw new GitException("no commits yet\n"); + } + Optional commitDir = Arrays.stream(allCommits) + .filter(file -> file.getName().startsWith(desiredCommit)).findFirst(); + if (!commitDir.isPresent()) { + throw new GitException("no such commit\n"); + } + return commitDir.get(); + } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/masters/GitParser.java b/task1_git/src/main/java/ru/ifmo/git/masters/GitParser.java new file mode 100644 index 0000000..48e3d8a --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/masters/GitParser.java @@ -0,0 +1,65 @@ +package ru.ifmo.git.masters; + +import net.sourceforge.argparse4j.*; +import net.sourceforge.argparse4j.inf.*; +import ru.ifmo.git.commands.*; + +public class GitParser { + + private ArgumentParser gitParser; + + public GitParser() { + createGitParser(); + } + + private void createGitParser() { + gitParser = ArgumentParsers.newArgumentParser("git"); + gitParser.defaultHelp(true) + .description("A version control system created by lergor."); + + Subparsers subparsers = gitParser.addSubparsers() + .title("These are common Git commands used in various situations:"); + + Subparser parserInit = subparsers.addParser("init") + .setDefault("cmd", new Init()) + .help("Create an empty Git repository or reinitialize an existing one"); + + Subparser parserAdd = subparsers.addParser("add") + .setDefault("cmd", new Add()) + .help("Add file contents to the index"); + parserAdd.addArgument("").type(String.class) + .required(true).nargs("+"); + + Subparser parserCommit = subparsers.addParser("commit") + .setDefault("cmd", new Commit()) + .help("Record changes to the repository"); + parserCommit.addArgument("message").type(String.class); + parserCommit.addArgument("").type(String.class).nargs("+"); + + Subparser parserReset = subparsers.addParser("reset") + .setDefault("cmd", new Reset()) + .help("Reset current HEAD to the specified state"); + parserReset.addArgument("").type(String.class) + .required(true); + + Subparser parserLog = subparsers.addParser("log") + .setDefault("cmd", new Log()) + .help("Show commit logs"); + parserLog.addArgument("").type(String.class).nargs("?"); + + Subparser parserCheckout = subparsers.addParser("checkout") + .setDefault("cmd", new Checkout()) + .help("Switch branches or restore working tree files"); + parserCheckout.addArgument("").type(String.class); + + } + + public Namespace parseArgs(String[] args) throws ArgumentParserException { + return gitParser.parseArgs(args); + } + + public void handleError(ArgumentParserException e) { + gitParser.handleError(e); + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java b/task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java index 3c96093..33608b2 100644 --- a/task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java +++ b/task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java @@ -8,64 +8,38 @@ public class StorageMaster { - static public void copyAll(List args, String sourceDir, String targetDir) throws GitException { - sourceDir = GitUtils.fixDirName(sourceDir); - targetDir = GitUtils.fixDirName(targetDir); - File destination = new File(GitUtils.getCWD() + "/" + targetDir); - if(destination.exists() || (!destination.exists() && destination.mkdirs())) { - for (String fileName: args) { - fileName = GitUtils.fixFileName(fileName); - copyTo(sourceDir + "/" + fileName, targetDir + "/" + fileName); + static public void copyAll(List args, File targetDir) throws GitException { + if (targetDir.exists() || (!targetDir.exists() && targetDir.mkdirs())) { + for (File file : args) { + try { + if (file.isFile()) { + FileUtils.copyFileToDirectory(file, targetDir); + } else if (file.isDirectory()) { + FileUtils.copyDirectoryToDirectory(file, targetDir); + } + } catch (IOException e) { + throw new GitException(e.getMessage()); + } } } } - static public void copyDirToDir(String sourceDir, String targetDir) throws GitException { - File[] files = new File(sourceDir).listFiles(); - if(files != null) { - List args = new ArrayList<>(); - Arrays.stream(files).map(File::getName).forEach(args::add); - copyAll(args, sourceDir, targetDir); - } - } - - static public void copyTo(String source, String destination) throws GitException { - File sourceFile = new File(GitUtils.getCWD() + "/" + source); - if(!sourceFile.isHidden()) { + static public boolean createFileWithContent(String fileName, String content) { + if (checkAndCreateFile(fileName)) { try { - if(sourceFile.isFile()) { - File destinationFile = new File(GitUtils.getCWD() + "/" + destination); - FileUtils.copyFile(sourceFile, destinationFile); - } else if(sourceFile.isDirectory()) { - checkAndCreateDir(GitUtils.getCWD() + "/" + destination); - File[] files = sourceFile.listFiles(); - if(files != null) { - for (File file: files) { - copyTo(source + "/" + file.getName(), destination + "/" + file.getName()); - } - } - } + FileUtils.writeStringToFile(new File(fileName), content, "UTF-8"); } catch (IOException e) { - String errorMessage = "error while moving " + source + " into " + destination + "\n"; - throw new GitException(errorMessage); + return false; } } + return true; } - static public boolean createFileWithContent(String fileName, String content) { - return checkAndCreateFile(fileName) && writeToFile(fileName, content, false); - } - - static public boolean checkAndCreateDir(String dirName) { - File dir = new File(dirName); - return dir.exists() || dir.mkdirs(); - } - - static public boolean checkAndCreateFile(String fileName) { + private static boolean checkAndCreateFile(String fileName) { File file = new File(fileName); - if(!file.exists()) { + if (!file.exists()) { try { - if(file.createNewFile()) { + if (file.createNewFile()) { return file.setReadable(true) && file.setWritable(true); } } catch (IOException e) { @@ -75,15 +49,4 @@ static public boolean checkAndCreateFile(String fileName) { return file.canRead() && file.canWrite(); } - static public boolean writeToFile(String fileName, String content, boolean append) { - File file = new File(fileName); - try(BufferedWriter writer = new BufferedWriter(new FileWriter(file, append))) { - writer.write((append ? "\n" : "") + content); - } catch (IOException e) { - return false; - } - return true; - } - - } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Command.java b/task1_git/src/main/java/ru/ifmo/git/util/Command.java index f452d3a..10bad2b 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/Command.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/Command.java @@ -1,24 +1,25 @@ package ru.ifmo.git.util; +import java.io.File; import java.util.*; public interface Command { default boolean repositoryExists() { - return GitUtils.getGitDirectory().exists(); + return new File(GitTree.repo()).exists(); } - boolean correctArgs(List args); + boolean correctArgs(Map args); - default void checkRepoAndArgs(List args) throws GitException { - if(!repositoryExists()) { + default void checkRepoAndArgs(Map args) throws GitException { + if (!repositoryExists()) { throw new GitException("fatal: Not a git repository: .m_git\n"); } - if(!correctArgs(args)) { - throw new GitException("wrong arguments\n"); + if (!correctArgs(args)) { + throw new GitException("wrong arguments\n"); } } - CommandResult execute(List args) throws GitException; + CommandResult execute(Map args) throws GitException; } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java b/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java index b031333..dc33213 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java @@ -39,4 +39,5 @@ public void setMessage(Message message) { public void setMessage(String message) { this.message = new Message(message); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java index a39a3cd..aa0908a 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java @@ -7,12 +7,14 @@ public class CommitInfo { public String message; public String branch; - public CommitInfo() {} + public CommitInfo() { + } public String toString() { - return "commit " + hash + "\n" + + return "commit " + hash + "\n" + "Author:\t" + author + "\n" + "Date:\t" + time + "\n" + "\t\t" + message + "\n\n"; } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/GitException.java b/task1_git/src/main/java/ru/ifmo/git/util/GitException.java index fc7d729..10cfb2e 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/GitException.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/GitException.java @@ -5,4 +5,5 @@ public class GitException extends Exception { public GitException(String message) { super(message); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/GitTree.java b/task1_git/src/main/java/ru/ifmo/git/util/GitTree.java new file mode 100644 index 0000000..9fd31e0 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/GitTree.java @@ -0,0 +1,31 @@ +package ru.ifmo.git.util; + +import java.nio.file.Paths; + +public class GitTree { + + static public String cwd() { + return Paths.get(".").toAbsolutePath().normalize().toString(); + } + + static public String repo() { + return Paths.get(cwd(), ".m_git").toString(); + } + + static public String index() { + return Paths.get(repo(), "index").toString(); + } + + static public String log() { + return Paths.get(repo(), "logs").toString(); + } + + static public String storage() { + return Paths.get(repo(), "storage").toString(); + } + + static public String head() { + return Paths.get(repo(), "HEAD").toString(); + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java index 8e9a113..88bb53f 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java @@ -5,7 +5,6 @@ public class HeadInfo { public String branchName; public String headHash; public String currentHash; - public String logFilePath; public HeadInfo() { } @@ -14,7 +13,6 @@ public HeadInfo(String branch) { branchName = branch; headHash = ""; currentHash = ""; - logFilePath = "logs/" + branchName; } public void setHeadHash(String hash) { @@ -22,9 +20,6 @@ public void setHeadHash(String hash) { } public void setCurrentHash(String hash) { - if(currentHash.equals(headHash)) { - headHash = hash; - } currentHash = hash; } } diff --git a/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java b/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java index 1b67c89..181a12d 100644 --- a/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java +++ b/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java @@ -1,100 +1,100 @@ -package ru.ifmo.git.utils; - -import org.junit.Test; -import ru.ifmo.git.util.*; - -import static junit.framework.TestCase.*; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class TestCommand { - - private Command command = new Command() { - @Override - public CommandResult execute(List args) throws GitException { - return null; - } - }; - - @Test - public void GetGitPathTest() { - String path = command.getGitPath(); - assertEquals(Paths.get(".").toAbsolutePath().normalize().toString() + "/.m_git", path); - } - - @Test - public void GetGitDirectoryTest() { - File gitDir = command.getGitDirectory(); - assertEquals(command.getGitPath(), gitDir.getAbsolutePath()); - } - - @Test(expected = GitException.class) - public void CheckArgumentsThrowsTest() { - command.correctArgs(Arrays.asList("kek", "kek")); - } - - @Test - public void CheckArgumentsNotThrowTest() { - command.correctArgs(Collections.emptyList()); - } - - @Test - public void CheckGitExistsNotThrowTest() { - File gitDir = command.getGitDirectory(); - if(!gitDir.exists()) { - gitDir.mkdir(); - } - command.repositoryExists(); - } - - @Test - public void GetHeadTest() throws GitException, IOException { -// File headFile = new File(command.getGitPath() + "/HEAD"); -// String json = "{\"branchName\":\"master\"," + -// "\"headHash\":\"812932983\"," + -// "\"historyFilePath\":\"info/hist_master\"," + -// "\"logFilePath\":\"logs/master\"," + -// "\"storagePath\":\"storage/812932983\"}"; +//package ru.ifmo.git.utils; // -// boolean k = headFile.exists(); -// if(!k) { -// System.out.println(headFile.getAbsolutePath()); -// k = headFile.createNewFile() && -// headFile.setReadable(true) && -// headFile.setWritable(true); +//import org.junit.Test; +//import ru.ifmo.git.util.*; +// +//import static junit.framework.TestCase.*; +// +//import java.io.File; +//import java.io.FileWriter; +//import java.io.IOException; +//import java.nio.file.Paths; +//import java.util.Arrays; +//import java.util.Collections; +//import java.util.List; +// +//public class TestCommand { +// +// private Command command = new Command() { +// @Override +// public CommandResult execute(List args) throws GitException { +// return null; // } -// if(k) { -// try(FileWriter writer = new FileWriter(headFile)) { -// writer.write(json); -// writer.flush(); -// writer.close(); -// } catch (IOException ignored) { -// System.out.println("catch"); -// } +// }; +// +// @Test +// public void GetGitPathTest() { +// String path = command.getGitPath(); +// assertEquals(Paths.get(".").toAbsolutePath().normalize().toString() + "/.m_git", path); +// } +// +// @Test +// public void GetGitDirectoryTest() { +// File gitDir = command.getGitDirectory(); +// assertEquals(command.getGitPath(), gitDir.getAbsolutePath()); +// } +// +// @Test(expected = GitException.class) +// public void CheckArgumentsThrowsTest() { +// command.correctArgs(Arrays.asList("kek", "kek")); +// } +// +// @Test +// public void CheckArgumentsNotThrowTest() { +// command.correctArgs(Collections.emptyList()); +// } +// +// @Test +// public void CheckGitExistsNotThrowTest() { +// File gitDir = command.getGitDirectory(); +// if(!gitDir.exists()) { +// gitDir.mkdir(); // } +// command.repositoryExists(); +// } // +// @Test +// public void GetHeadTest() throws GitException, IOException { +//// File headFile = new File(command.getGitPath() + "/HEAD"); +//// String json = "{\"branchName\":\"master\"," + +//// "\"headHash\":\"812932983\"," + +//// "\"historyFilePath\":\"info/hist_master\"," + +//// "\"logFilePath\":\"logs/master\"," + +//// "\"storagePath\":\"storage/812932983\"}"; +//// +//// boolean k = headFile.exists(); +//// if(!k) { +//// System.out.println(headFile.getAbsolutePath()); +//// k = headFile.createNewFile() && +//// headFile.setReadable(true) && +//// headFile.setWritable(true); +//// } +//// if(k) { +//// try(FileWriter writer = new FileWriter(headFile)) { +//// writer.write(json); +//// writer.flush(); +//// writer.close(); +//// } catch (IOException ignored) { +//// System.out.println("catch"); +//// } +//// } +//// +//// +//// BranchInfo info = command.getHead(); +//// assertEquals("master", info.branchName); +//// assertEquals("812932983", info.headHash); +//// assertEquals("/info/hist_master", info.historyFilePath); +//// assertEquals("/logs/master", info.logFilePath); +//// assertEquals("/storage/812932983", info.branchName); +//// assertTrue(headFile.delete()); +// } // -// BranchInfo info = command.getHead(); -// assertEquals("master", info.branchName); -// assertEquals("812932983", info.headHash); -// assertEquals("/info/hist_master", info.historyFilePath); -// assertEquals("/logs/master", info.logFilePath); -// assertEquals("/storage/812932983", info.branchName); -// assertTrue(headFile.delete()); - } - - @Test(expected = GitException.class) - public void CheckGitExistsThrowsTest() throws GitException { - File gitDir = command.getGitDirectory(); - if(gitDir.exists()) { - gitDir.delete(); - } - command.repositoryExists(); - } -} +// @Test(expected = GitException.class) +// public void CheckGitExistsThrowsTest() throws GitException { +// File gitDir = command.getGitDirectory(); +// if(gitDir.exists()) { +// gitDir.delete(); +// } +// command.repositoryExists(); +// } +//} From 2a94b62b80a63fd9798f5cbfa64faa54ecf5acae Mon Sep 17 00:00:00 2001 From: lergor Date: Tue, 18 Sep 2018 01:09:16 +0300 Subject: [PATCH 05/14] make app runnable --- task1_git/Readme.md | 11 +++++++++++ task1_git/build.gradle | 3 +++ 2 files changed, 14 insertions(+) diff --git a/task1_git/Readme.md b/task1_git/Readme.md index 2865269..9d42623 100644 --- a/task1_git/Readme.md +++ b/task1_git/Readme.md @@ -31,3 +31,14 @@ implies he optional one.
index/ [file] HEAD - file with information about current state + + +### How to build and run + +In order to run this app, follow this steps: + +* clone this repository +* checkout on branch *task1_git* +* run `./gradlew installDist` +* go to the `./build/install/task1_git/bin/` +* execute `task1_git` (or `task1_git.bat` on windows) \ No newline at end of file diff --git a/task1_git/build.gradle b/task1_git/build.gradle index 9125620..c22f615 100644 --- a/task1_git/build.gradle +++ b/task1_git/build.gradle @@ -2,6 +2,9 @@ group 'ru.ifmo' version '1.0-SNAPSHOT' apply plugin: 'java' +apply plugin: 'application' + +mainClassName = "ru.ifmo.git.Git" sourceCompatibility = 1.8 From 61f5def1abdf3c2f30042d2d395c7b2a4b2be5f3 Mon Sep 17 00:00:00 2001 From: lergor Date: Tue, 18 Sep 2018 13:28:11 +0300 Subject: [PATCH 06/14] little fix --- task1_git/Readme.md | 2 +- .../java/ru/ifmo/git/commands/Commit.java | 5 +- .../main/java/ru/ifmo/git/commands/Log.java | 2 +- .../java/ru/ifmo/git/masters/FileMaster.java | 6 +- .../java/ru/ifmo/git/utils/TestCommand.java | 100 ------------------ .../java/ru/ifmo/git/utils/TestMessage.java | 32 ------ 6 files changed, 9 insertions(+), 138 deletions(-) delete mode 100644 task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java delete mode 100644 task1_git/src/test/java/ru/ifmo/git/utils/TestMessage.java diff --git a/task1_git/Readme.md b/task1_git/Readme.md index 9d42623..8855357 100644 --- a/task1_git/Readme.md +++ b/task1_git/Readme.md @@ -41,4 +41,4 @@ In order to run this app, follow this steps: * checkout on branch *task1_git* * run `./gradlew installDist` * go to the `./build/install/task1_git/bin/` -* execute `task1_git` (or `task1_git.bat` on windows) \ No newline at end of file +* execute `task1_git` (or `task1_git.bat` on Windows) \ No newline at end of file diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index a85fe2c..d3a8d1f 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -34,8 +34,11 @@ public boolean correctArgs(Map args) { @Override public CommandResult execute(Map args) { try { + if(!correctArgs(args)) { + return new CommandResult(ExitStatus.ERROR, "try git add first\n"); + } checkRepoAndArgs(args); - headInfo = FileMaster.getHeadInfo(); + headInfo = FileMaster.getHeadInfo(new File(GitTree.head())); setCommitInfo(); StorageMaster.copyAll(files, Paths.get(GitTree.storage(), headInfo.currentHash).toFile()); writeLog(); diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index 0d385c5..8cdefdb 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -26,7 +26,7 @@ public boolean correctArgs(Map args) { public CommandResult execute(Map args) { try { checkRepoAndArgs(args); - headInfo = FileMaster.getHeadInfo(); + headInfo = FileMaster.getHeadInfo(new File(GitTree.head())); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, "error while reading HEAD\n"); } diff --git a/task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java b/task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java index a281417..c2907e9 100644 --- a/task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java +++ b/task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java @@ -22,9 +22,9 @@ static public List getHistory(File logFile) throws GitException { return history; } - public static HeadInfo getHeadInfo() throws GitException { + public static HeadInfo getHeadInfo(File headFile) throws GitException { String headJson; - try (FileInputStream inputStream = new FileInputStream(GitTree.head())) { + try (FileInputStream inputStream = new FileInputStream(headFile.getAbsolutePath())) { headJson = IOUtils.toString(inputStream); } catch (IOException e) { throw new GitException("error while reading HEAD\n"); @@ -42,7 +42,7 @@ static public void writeToFile(String fileName, String content, boolean append) } static public void changeCurHash(String newHash, boolean withHead) throws GitException { - HeadInfo headInfo = FileMaster.getHeadInfo(); + HeadInfo headInfo = FileMaster.getHeadInfo(new File(GitTree.head())); headInfo.setCurrentHash(newHash); if (withHead) { headInfo.setHeadHash(newHash); diff --git a/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java b/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java deleted file mode 100644 index 181a12d..0000000 --- a/task1_git/src/test/java/ru/ifmo/git/utils/TestCommand.java +++ /dev/null @@ -1,100 +0,0 @@ -//package ru.ifmo.git.utils; -// -//import org.junit.Test; -//import ru.ifmo.git.util.*; -// -//import static junit.framework.TestCase.*; -// -//import java.io.File; -//import java.io.FileWriter; -//import java.io.IOException; -//import java.nio.file.Paths; -//import java.util.Arrays; -//import java.util.Collections; -//import java.util.List; -// -//public class TestCommand { -// -// private Command command = new Command() { -// @Override -// public CommandResult execute(List args) throws GitException { -// return null; -// } -// }; -// -// @Test -// public void GetGitPathTest() { -// String path = command.getGitPath(); -// assertEquals(Paths.get(".").toAbsolutePath().normalize().toString() + "/.m_git", path); -// } -// -// @Test -// public void GetGitDirectoryTest() { -// File gitDir = command.getGitDirectory(); -// assertEquals(command.getGitPath(), gitDir.getAbsolutePath()); -// } -// -// @Test(expected = GitException.class) -// public void CheckArgumentsThrowsTest() { -// command.correctArgs(Arrays.asList("kek", "kek")); -// } -// -// @Test -// public void CheckArgumentsNotThrowTest() { -// command.correctArgs(Collections.emptyList()); -// } -// -// @Test -// public void CheckGitExistsNotThrowTest() { -// File gitDir = command.getGitDirectory(); -// if(!gitDir.exists()) { -// gitDir.mkdir(); -// } -// command.repositoryExists(); -// } -// -// @Test -// public void GetHeadTest() throws GitException, IOException { -//// File headFile = new File(command.getGitPath() + "/HEAD"); -//// String json = "{\"branchName\":\"master\"," + -//// "\"headHash\":\"812932983\"," + -//// "\"historyFilePath\":\"info/hist_master\"," + -//// "\"logFilePath\":\"logs/master\"," + -//// "\"storagePath\":\"storage/812932983\"}"; -//// -//// boolean k = headFile.exists(); -//// if(!k) { -//// System.out.println(headFile.getAbsolutePath()); -//// k = headFile.createNewFile() && -//// headFile.setReadable(true) && -//// headFile.setWritable(true); -//// } -//// if(k) { -//// try(FileWriter writer = new FileWriter(headFile)) { -//// writer.write(json); -//// writer.flush(); -//// writer.close(); -//// } catch (IOException ignored) { -//// System.out.println("catch"); -//// } -//// } -//// -//// -//// BranchInfo info = command.getHead(); -//// assertEquals("master", info.branchName); -//// assertEquals("812932983", info.headHash); -//// assertEquals("/info/hist_master", info.historyFilePath); -//// assertEquals("/logs/master", info.logFilePath); -//// assertEquals("/storage/812932983", info.branchName); -//// assertTrue(headFile.delete()); -// } -// -// @Test(expected = GitException.class) -// public void CheckGitExistsThrowsTest() throws GitException { -// File gitDir = command.getGitDirectory(); -// if(gitDir.exists()) { -// gitDir.delete(); -// } -// command.repositoryExists(); -// } -//} diff --git a/task1_git/src/test/java/ru/ifmo/git/utils/TestMessage.java b/task1_git/src/test/java/ru/ifmo/git/utils/TestMessage.java deleted file mode 100644 index 4147c9f..0000000 --- a/task1_git/src/test/java/ru/ifmo/git/utils/TestMessage.java +++ /dev/null @@ -1,32 +0,0 @@ -package ru.ifmo.git.utils; - -import org.junit.Test; -import ru.ifmo.git.util.Message; - -import static junit.framework.TestCase.*; - -public class TestMessage { - - @Test - public void WriteThenReadTest() { - Message msg = new Message(); - msg.write("kek!"); - assertEquals("kek!", msg.read()); - } - - @Test - public void ConstructorWithStringThenReadTest() { - Message msg = new Message("kek!"); - assertEquals("kek!", msg.read()); - } - - @Test - public void WriteReadClearReadTest() { - Message msg = new Message(); - msg.write("kek!"); - assertEquals("kek!", msg.read()); - msg.clear(); - assertEquals("", msg.read()); - } - -} From 06cb7a448996b675ce0679296a1e887d653c361c Mon Sep 17 00:00:00 2001 From: lergor Date: Tue, 25 Sep 2018 23:57:55 +0300 Subject: [PATCH 07/14] partly changed --- task1_git/build.gradle | 1 + task1_git/src/main/java/ru/ifmo/git/Git.java | 60 +++++++- .../main/java/ru/ifmo/git/commands/Add.java | 62 ++++---- .../java/ru/ifmo/git/commands/Checkout.java | 68 ++++----- .../java/ru/ifmo/git/commands/Commit.java | 94 +++++++++--- .../java/ru/ifmo/git/commands/GitCommand.java | 40 +++++ .../main/java/ru/ifmo/git/commands/Init.java | 73 ++++----- .../main/java/ru/ifmo/git/commands/Log.java | 140 +++++++++--------- .../java/ru/ifmo/git/commands/Remove.java | 52 +++++++ .../main/java/ru/ifmo/git/commands/Reset.java | 68 ++++----- .../java/ru/ifmo/git/commands/Status.java | 19 +++ .../ru/ifmo/git/entities/Cryptographer.java | 72 +++++++++ .../ifmo/git/entities/FileCryptographer.java | 22 +++ .../java/ru/ifmo/git/entities/GitClerk.java | 140 ++++++++++++++++++ .../ifmo/git/entities/GitCryptographer.java | 95 ++++++++++++ .../ru/ifmo/git/entities/GitFileKeeper.java | 107 +++++++++++++ .../git/{masters => entities}/GitParser.java | 48 +++--- .../java/ru/ifmo/git/entities/GitTree.java | 71 +++++++++ .../{masters => entities}/StorageMaster.java | 11 +- .../ifmo/git/entities/TreeCryptographer.java | 88 +++++++++++ .../java/ru/ifmo/git/masters/FileMaster.java | 67 --------- .../main/java/ru/ifmo/git/util/BlobType.java | 26 ++++ .../main/java/ru/ifmo/git/util/Command.java | 25 ---- .../java/ru/ifmo/git/util/CommitInfo.java | 40 +++++ .../java/ru/ifmo/git/util/ExitStatus.java | 2 +- .../java/ru/ifmo/git/util/FileReference.java | 15 ++ .../main/java/ru/ifmo/git/util/GitTree.java | 31 ---- .../main/java/ru/ifmo/git/util/HeadInfo.java | 10 +- .../java/ru/ifmo/git/util/ListOfFiles.java | 22 +++ .../main/java/ru/ifmo/git/util/Message.java | 4 + 30 files changed, 1195 insertions(+), 378 deletions(-) create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/Remove.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/Status.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/FileCryptographer.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java rename task1_git/src/main/java/ru/ifmo/git/{masters => entities}/GitParser.java (50%) create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java rename task1_git/src/main/java/ru/ifmo/git/{masters => entities}/StorageMaster.java (86%) create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/TreeCryptographer.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/BlobType.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/util/Command.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/FileReference.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/util/GitTree.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/util/ListOfFiles.java diff --git a/task1_git/build.gradle b/task1_git/build.gradle index c22f615..885b2b5 100644 --- a/task1_git/build.gradle +++ b/task1_git/build.gradle @@ -17,5 +17,6 @@ dependencies { compile group: 'net.sourceforge.argparse4j', name: 'argparse4j', version: '0.2.0' compile group: 'org.apache.commons', name: 'commons-io', version: '1.3.2' implementation 'com.google.code.gson:gson:2.8.5' + compile group: 'commons-codec', name: 'commons-codec', version: '1.11' } diff --git a/task1_git/src/main/java/ru/ifmo/git/Git.java b/task1_git/src/main/java/ru/ifmo/git/Git.java index 626a22f..f4c0a72 100644 --- a/task1_git/src/main/java/ru/ifmo/git/Git.java +++ b/task1_git/src/main/java/ru/ifmo/git/Git.java @@ -1,17 +1,67 @@ package ru.ifmo.git; -import ru.ifmo.git.masters.GitParser; +import net.sourceforge.argparse4j.inf.ArgumentParserException; +import net.sourceforge.argparse4j.inf.Namespace; +import ru.ifmo.git.commands.GitCommand; +import ru.ifmo.git.entities.GitParser; import ru.ifmo.git.util.*; -import net.sourceforge.argparse4j.inf.*; - public class Git { public static void main(String[] args) { + +// String hash = "b4c66cf0e6c74712a4fd1344ff90ec52855430320"; +// Optional commit = storage.findCommit(hash); +////// +// if(commit.isPresent()) { +// System.out.println("-----"); +// List refs = cryp.formDecodeReferences(commit.get()); +// for (FileReference i : refs) { +// System.out.println(i.name); +// } +// storage.restoreCommit(refs, clear); +// } + + + /////////////////// +// FileInfo info = GitCryptographer.decodeFile(file); +// System.out.println("-----"); +// System.out.println("type: " + String.valueOf(info.type)); +// System.out.println("name: " + info.name); +// System.out.println("name: " + info.localPath); +// info.content.forEach(s -> System.out.println(s + "!")); +// +// +// List infos = cryp.decodeTree(file); +// for (FileInfo i: infos) { +// System.out.println("type: " + String.valueOf(i.type)); +// System.out.println("name: " + i.name); +// System.out.println("name: " + i.localPath); +// } + +// Path new_file = Paths.get("kek/res"); +// Files.write(new_file, info.content, StandardCharsets.UTF_8); + + + //////////////////////////////// + + + +// } catch (IOException e) { +// e.printStackTrace(); +// } + + +// GitСlerk cl = new GitСlerk(tr); + + + + +// args = new String[]{"init"}; GitParser gitParser = new GitParser(); try { Namespace ns = gitParser.parseArgs(args); - Command command = (Command) ns.getAttrs().remove("cmd"); + GitCommand command = (GitCommand) ns.getAttrs().remove("cmd"); CommandResult result = command.execute(ns.getAttrs()); if(result.getStatus() != ExitStatus.SUCCESS) { System.out.println("exit with code " + result.getStatus()); @@ -19,8 +69,6 @@ public static void main(String[] args) { System.out.print(result.getMessage().read()); } catch (ArgumentParserException e) { gitParser.handleError(e); - } catch (GitException e) { - System.out.print(e.getMessage()); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java index cc6fc74..536f213 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java @@ -1,42 +1,54 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.masters.*; +import ru.ifmo.git.entities.*; import ru.ifmo.git.util.*; -import java.io.*; -import java.nio.file.Paths; +import java.io.IOException; +import java.nio.file.*; import java.util.*; +import java.util.stream.Collectors; -public class Add implements Command { +public class Add implements GitCommand { - private List files = new LinkedList<>(); + private List files; + private GitTree gitTree; + + public Add() { + gitTree = new GitTree(); + } + + public Add(Path cwd) { + gitTree = new GitTree(cwd); + } + + private List getArgs(Map args) { + return ((List) args.get("")) + .stream() + .map(s -> Paths.get(s).normalize()) + .collect(Collectors.toList()); + } @Override - public boolean correctArgs(Map args) { - if (args.isEmpty()) { - return false; - } - //noinspection unchecked - List fileNames = ((List) args.get("")); - for (String fileName : fileNames) { - File file = Paths.get(GitTree.cwd(), fileName).toFile(); - if (!file.exists()) { - return false; - } - files.add(file); + public boolean correctArgs(Map args) throws GitException { + if (!args.isEmpty()) { + List files = getArgs(args); + checkFilesExist(files); + this.files = files; + return true; } - return true; + return false; } @Override - public CommandResult execute(Map args) { + public CommandResult doWork(Map args) throws GitException { + if (!gitTree.exists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); + } try { - checkRepoAndArgs(args); - StorageMaster.copyAll(files, new File(GitTree.index())); - return new CommandResult(ExitStatus.SUCCESS, "add: done!\n"); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, "add: " + e.getMessage()); + GitFileKeeper.copyAll(files, gitTree.index()); + } catch (IOException e) { + throw new GitException(e.getMessage()); } + return new CommandResult(ExitStatus.SUCCESS, "add: done!\n"); } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java index e3588ca..ee1f672 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java @@ -1,34 +1,34 @@ -package ru.ifmo.git.commands; - -import ru.ifmo.git.masters.*; -import ru.ifmo.git.util.*; - -import java.io.*; -import java.util.Map; - -import org.apache.commons.io.FileUtils; - -public class Checkout implements Command { - - private String commit; - - @Override - public boolean correctArgs(Map args) { - commit = (String) args.get(""); - return commit.length() > 6; - } - - @Override - public CommandResult execute(Map args) { - try { - checkRepoAndArgs(args); - File commitDir = FileMaster.findCommitInStorage(commit); - FileUtils.copyDirectory(commitDir, new File(GitTree.cwd())); - FileMaster.changeCurHash(commitDir.getName(), false); - } catch (IOException | GitException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); - } - return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); - } - -} +//package ru.ifmo.git.commands; +// +//import ru.ifmo.git.entities.*; +//import ru.ifmo.git.util.*; +// +//import java.io.*; +//import java.util.Map; +// +//import org.apache.commons.io.FileUtils; +// +//public class Checkout implements GitCommand { +// +// private String commit; +// +// @Override +// public boolean correctArgs(Map args) { +// commit = (String) args.get(""); +// return commit.length() > 6; +// } +// +// @Override +// public CommandResult execute(Map args) { +// try { +// checkRepoAndArgs(args); +// File commitDir = FileMaster.findCommitInStorage(commit); +// FileUtils.copyDirectory(commitDir, new File(GitTree.cwd())); +// FileMaster.changeCurHash(commitDir.getName(), false); +// } catch (IOException | GitException e) { +// return new CommandResult(ExitStatus.ERROR, e.getMessage()); +// } +// return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); +// } +// +//} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index d3a8d1f..c2bfe87 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -1,34 +1,58 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.masters.*; +import ru.ifmo.git.entities.*; import ru.ifmo.git.util.*; import com.google.gson.Gson; import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.text.*; import java.util.*; +import java.util.stream.Collectors; -public class Commit implements Command { +public class Commit implements GitCommand { private HeadInfo headInfo; - private CommitInfo commitInfo = new CommitInfo(); - private List files = new LinkedList<>(); - private String message; + private CommitInfo commitInfo; + private List files = new LinkedList<>(); + private GitTree gitTree; + private GitClerk gitClerk; + private GitFileKeeper gitFileKeeper; + private GitCryptographer gitCrypto; + + public Commit() { + initEntities(GitTree.cwd()); + } + + public Commit(Path cwd) { + initEntities(cwd); + } + + void initEntities(Path cwd) { + gitTree = new GitTree(cwd); + gitClerk = new GitClerk(gitTree); + gitFileKeeper = new GitFileKeeper(gitTree); + gitCrypto = new GitCryptographer(gitTree); + } + + private List getArgs(Map args) { + return ((List) args.get("")) + .stream() + .map(s -> gitTree.index().resolve(s).normalize()) + .collect(Collectors.toList()); + } @Override - public boolean correctArgs(Map args) { - //noinspection unchecked - List fileNames = ((List) args.get("")); - for (String fileName : fileNames) { - File file = Paths.get(GitTree.index(), fileName).toFile(); - if (!file.exists()) { - return false; - } - files.add(file); + public boolean correctArgs(Map args) throws GitException { + if (!args.isEmpty()) { + List files = getArgs(args); + checkFilesExist(files); + this.files = files; + return true; } - message = (String) args.get("message"); - return true; + return false; } @Override @@ -49,6 +73,38 @@ public CommandResult execute(Map args) { } + @Override + public CommandResult doWork(Map args) throws GitException { + if (!gitTree.exists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); + } + + + CommitInfo commitInfo = new CommitInfo(); + commitInfo.setBranch("master"); + commitInfo.setMessage("master?"); + commitInfo.setRootDirectory(tr.repo()); + commitInfo.setAuthor("lergor"); + commitInfo.setTime("1234345678"); + File[] files = tr.repo().toFile().listFiles(); + List filess = Arrays.stream(files).map(File::toPath).filter(s -> !s.toFile().isHidden()).collect(Collectors.toList()); + GitCryptographer cryp = new GitCryptographer(tr); + GitFileKeeper storage = new GitFileKeeper(tr.storage()); + + + + ////////////////// + + List refs1 = cryp.formEncodeReferences(commitInfo, filess); + for (FileReference i : refs1) { + System.out.println(i.name + " " + i.type); + } +// storage.saveCommit(refs1); + + return null; + } + + private void setCommitInfo() throws GitException { commitInfo.author = System.getProperty("user.name"); commitInfo.message = message; @@ -58,11 +114,11 @@ private void setCommitInfo() throws GitException { Calendar calendar = Calendar.getInstance(); commitInfo.time = df.format(calendar.getTime()); - String hash = String.valueOf(commitInfo.time.concat(String.valueOf(GitTree.cwd())).hashCode()); - commitInfo.hash = (UUID.randomUUID().toString() + hash).replaceAll("-", ""); + String name = String.valueOf(commitInfo.time.concat(String.valueOf(GitTree.cwd())).hashCode()); + commitInfo.name = (UUID.randomUUID().toString() + name).replaceAll("-", ""); boolean moveHead = headInfo.headHash.equals(headInfo.currentHash); - FileMaster.changeCurHash(commitInfo.hash, moveHead); + FileMaster.changeCurHash(commitInfo.name, moveHead); } private void writeLog() throws GitException { diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java new file mode 100644 index 0000000..0cca009 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java @@ -0,0 +1,40 @@ +package ru.ifmo.git.commands; + +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.ExitStatus; +import ru.ifmo.git.util.GitException; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +public interface GitCommand { + + boolean correctArgs(Map args) throws GitException; + + CommandResult doWork(Map args) throws GitException; + + default CommandResult execute(Map args) { + String name = this.getClass().getSimpleName().toLowerCase(); + try { + if (!correctArgs(args)) { + return new CommandResult(ExitStatus.ERROR, name + ": wrong arguments"); + } + return doWork(args); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, name + ": " + e.getMessage()); + } + } + + default void checkFilesExist(List files) throws GitException { + for (Path file : files) { + if (!Files.exists(file)) { + String message = "fatal: pathspec " + file.getFileName() + " did not match any files"; + throw new GitException(message); + } + } + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java index 66d0533..5d75984 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java @@ -1,66 +1,47 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.masters.*; +import ru.ifmo.git.entities.GitClerk; +import ru.ifmo.git.entities.GitFileKeeper; +import ru.ifmo.git.entities.GitTree; import ru.ifmo.git.util.*; -import java.io.*; -import java.nio.file.Paths; -import java.util.*; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; -import com.google.gson.Gson; +public class Init implements GitCommand { -public class Init implements Command { - - private File gitDirectory = null; + private GitTree gitTree; @Override public boolean correctArgs(Map args) { - return args == null || args.size() == 0; + return args.size() == 1 && Files.exists((Path) args.get("")); } @Override - public CommandResult execute(Map args) { - if (!correctArgs(args)) { - return new CommandResult(ExitStatus.ERROR, "init: wrong arguments\n"); - } - gitDirectory = Paths.get(GitTree.repo()).toFile(); - CommandResult result = new CommandResult(ExitStatus.SUCCESS); + public CommandResult doWork(Map args) throws GitException { + gitTree = new GitTree((Path) args.get("")); Message message = new Message(); - if (repositoryExists()) { - message.write("reinitialized existing "); - } else { - if (initRepository()) { + if (!gitTree.exists()) { + try { + gitTree.createGitTree(); message.write("initialized empty "); - } else { - result.setStatus(ExitStatus.ERROR); - message.write("fail to init "); + writeHead(); + } catch (IOException e) { + return new CommandResult(ExitStatus.FAILURE, "unable to create repository in " + gitTree.repo()); } + } else { + message.write("reinitialized existing "); } - message.write("Git repository in " + gitDirectory.getAbsolutePath() + "\n"); - result.setMessage(message); - return result; + message.write("Git repository in " + gitTree.repo() + "\n"); + return new CommandResult(ExitStatus.SUCCESS, message); } - private boolean initRepository() { - return gitDirectory.mkdir() && createDirs() && createFiles(); + private void writeHead() throws IOException { + HeadInfo info = new HeadInfo(); + info.branchName = "master"; + GitClerk clerk = new GitClerk(gitTree); + clerk.changeHeadInfo(info); } - - private boolean createDir(String dirName) { - File newDir = Paths.get(GitTree.repo(), dirName).toFile(); - return newDir.exists() || newDir.mkdirs(); - } - - private boolean createDirs() { - return - createDir("/logs/") && - createDir("/storage/") && - createDir("/index/"); - } - - private boolean createFiles() { - HeadInfo masterInfo = new HeadInfo("master"); - String headInfo = (new Gson()).toJson(masterInfo); - return StorageMaster.createFileWithContent(GitTree.head(), headInfo); - } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index 8cdefdb..38c9e06 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -1,70 +1,70 @@ -package ru.ifmo.git.commands; - -import ru.ifmo.git.masters.*; -import ru.ifmo.git.util.*; - -import java.io.*; -import java.nio.file.Paths; -import java.util.*; -import java.util.function.Predicate; - -public class Log implements Command { - - private HeadInfo headInfo; - private String commit; - - @Override - public boolean correctArgs(Map args) { - if (args.size() == 1) { - commit = (String) args.get(""); - return true; - } - return (args.size() == 0); - } - - @Override - public CommandResult execute(Map args) { - try { - checkRepoAndArgs(args); - headInfo = FileMaster.getHeadInfo(new File(GitTree.head())); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, "error while reading HEAD\n"); - } - return readLog(Paths.get(GitTree.log(), headInfo.branchName).toFile(), commit); - } - - private CommandResult readLog(File logFile, String revision) { - if (logFile.exists()) { - Message logContent = new Message(); - List history; - try { - history = FileMaster.getHistory(logFile); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); - } - if (history.size() == 0) { - return emptyLogResult(); - } - history.stream().filter( - new Predicate() { - - private boolean include = (revision == null || revision.isEmpty()); - - @Override - public boolean test(CommitInfo commitInfo) { - include = include || commitInfo.hash.startsWith(revision); - return include; - } - } - ).forEach(info -> logContent.write(info.toString())); - return new CommandResult(ExitStatus.SUCCESS, logContent); - } - return emptyLogResult(); - } - - private CommandResult emptyLogResult() { - String failMessage = "fatal: your current branch '" + headInfo.branchName + "' does not have any commits yet\n"; - return new CommandResult(ExitStatus.FAILURE, failMessage); - } - -} +//package ru.ifmo.git.commands; +// +//import ru.ifmo.git.entities.*; +//import ru.ifmo.git.util.*; +// +//import java.io.*; +//import java.nio.file.Paths; +//import java.util.*; +//import java.util.function.Predicate; +// +//public class Log implements GitCommand { +// +// private HeadInfo headInfo; +// private String commit; +// +// @Override +// public boolean correctArgs(Map args) { +// if (args.size() == 1) { +// commit = (String) args.get(""); +// return true; +// } +// return (args.size() == 0); +// } +// +// @Override +// public CommandResult execute(Map args) { +// try { +// checkRepoAndArgs(args); +// headInfo = FileMaster.getHeadInfo(new File(GitTree.head())); +// } catch (GitException e) { +// return new CommandResult(ExitStatus.ERROR, "error while reading HEAD\n"); +// } +// return readLog(Paths.get(GitTree.log(), headInfo.branchName).toFile(), commit); +// } +// +// private CommandResult readLog(File logFile, String revision) { +// if (logFile.exists()) { +// Message logContent = new Message(); +// List history; +// try { +// history = FileMaster.getHistory(logFile); +// } catch (GitException e) { +// return new CommandResult(ExitStatus.ERROR, e.getMessage()); +// } +// if (history.size() == 0) { +// return emptyLogResult(); +// } +// history.stream().filter( +// new Predicate() { +// +// private boolean include = (revision == null || revision.isEmpty()); +// +// @Override +// public boolean test(CommitInfo commitInfo) { +// include = include || commitInfo.name.startsWith(revision); +// return include; +// } +// } +// ).forEach(info -> logContent.write(info.toString())); +// return new CommandResult(ExitStatus.SUCCESS, logContent); +// } +// return emptyLogResult(); +// } +// +// private CommandResult emptyLogResult() { +// String failMessage = "fatal: your current branch '" + headInfo.branchName + "' does not have any commits yet\n"; +// return new CommandResult(ExitStatus.FAILURE, failMessage); +// } +// +//} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java new file mode 100644 index 0000000..a09c3fa --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java @@ -0,0 +1,52 @@ +package ru.ifmo.git.commands; + +import ru.ifmo.git.entities.GitFileKeeper; +import ru.ifmo.git.entities.GitTree; +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.ExitStatus; +import ru.ifmo.git.util.GitException; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class Remove implements GitCommand { + + private GitTree gitTree; + List files; + + public Remove() { + gitTree = new GitTree(GitTree.cwd()); + } + + public Remove(Path cwd) { + gitTree = new GitTree(cwd); + } + + @Override + public boolean correctArgs(Map args) { + files = ((List) args.get("")); + return !files.isEmpty(); + } + + @Override + public CommandResult doWork(Map args) { + if (!gitTree.exists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); + } + try { + List filesInIndex = files.stream().map(gitTree.index()::resolve).collect(Collectors.toList()); + List filesInCWD = files.stream().map(gitTree.repo()::resolve).collect(Collectors.toList()); + GitFileKeeper.removeAll(filesInIndex); + GitFileKeeper.removeAll(filesInCWD); + } catch (IOException e) { + return new CommandResult(ExitStatus.ERROR, "remove: " + e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "remove: done!\n"); + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java index 6c8a311..3bd7e4e 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java @@ -1,34 +1,34 @@ -package ru.ifmo.git.commands; - -import ru.ifmo.git.masters.*; -import ru.ifmo.git.util.*; - -import java.io.*; -import java.util.Map; - -import org.apache.commons.io.FileUtils; - -public class Reset implements Command { - - private String commit; - - @Override - public boolean correctArgs(Map args) { - commit = (String) args.get(""); - return commit.length() > 6; - } - - @Override - public CommandResult execute(Map args) { - try { - checkRepoAndArgs(args); - File commitDir = FileMaster.findCommitInStorage(commit); - FileUtils.copyDirectory(commitDir, new File(GitTree.index())); - FileMaster.changeCurHash(commitDir.getName(), true); - } catch (IOException | GitException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); - } - return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); - } - -} +//package ru.ifmo.git.commands; +// +//import ru.ifmo.git.entities.*; +//import ru.ifmo.git.util.*; +// +//import java.io.*; +//import java.util.Map; +// +//import org.apache.commons.io.FileUtils; +// +//public class Reset implements GitCommand { +// +// private String commit; +// +// @Override +// public boolean correctArgs(Map args) { +// commit = (String) args.get(""); +// return commit.length() > 6; +// } +// +// @Override +// public CommandResult execute(Map args) { +// try { +// checkRepoAndArgs(args); +// File commitDir = FileMaster.findCommitInStorage(commit); +// FileUtils.copyDirectory(commitDir, new File(GitTree.index())); +// FileMaster.changeCurHash(commitDir.getName(), true); +// } catch (IOException | GitException e) { +// return new CommandResult(ExitStatus.ERROR, e.getMessage()); +// } +// return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); +// } +// +//} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java new file mode 100644 index 0000000..e1ede7e --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java @@ -0,0 +1,19 @@ +package ru.ifmo.git.commands; + +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.GitException; + +import java.util.Map; + +public class Status implements GitCommand { + + @Override + public boolean correctArgs(Map args) { + return args.isEmpty(); + } + + @Override + public CommandResult doWork(Map args) throws GitException { + return null; + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java new file mode 100644 index 0000000..2e8f8bd --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java @@ -0,0 +1,72 @@ +package ru.ifmo.git.entities; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.IOUtils; +import ru.ifmo.git.util.*; + +import java.io.*; +import java.nio.file.*; + +public interface Cryptographer { + + String ENCODING = "UTF-8"; + int markLength = BlobType.size(); + String sep = System.getProperty("line.separator"); + String tab = "\t"; + + String marker(); + InputStream formContent(Path file) throws IOException; + + default BlobType readMarker(String infoString) { + return BlobType.typeOf(infoString.substring(0, BlobType.size())); + } + + default String removeMarker(String string) { + return string.substring(BlobType.size()); + } + + default InputStream formHeader(Path file) throws IOException { + String info = marker() + file.toFile().getName() + sep; + return IOUtils.toInputStream(info, ENCODING); + } + + default String withoutMarker(String infoString) { + return infoString.substring(markLength); + } + + default String getHash(Path file) throws IOException { + InputStream fileContent = formContent(file); + String filePath = file.toAbsolutePath().normalize().toString(); + fileContent = new SequenceInputStream( + fileContent, + IOUtils.toInputStream(filePath) + ); + return DigestUtils.sha1Hex(fileContent); + } + + default InputStream encodeFile(Path file) throws IOException { + return new SequenceInputStream( + formHeader(file), + formContent(file) + ); + } + + default FileReference decodeFile(Path file) throws IOException { + FileReference reference = new FileReference(); + BufferedReader reader = Files.newBufferedReader(file); + String infoLine = reader.readLine(); + reference.type = readMarker(infoLine); + reference.name = withoutMarker(infoLine); + reference.content = IOUtils.toInputStream(IOUtils.toString(reader)); + return reference; + } + + default FileReference formEncodeReference(Path file) throws IOException { + FileReference reference = new FileReference(); + reference.type = BlobType.typeOf(marker()); + reference.name = getHash(file); + reference.content = encodeFile(file); + return reference; + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/FileCryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/FileCryptographer.java new file mode 100644 index 0000000..e9632cd --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/FileCryptographer.java @@ -0,0 +1,22 @@ +package ru.ifmo.git.entities; + +import ru.ifmo.git.util.BlobType; + +import java.io.*; +import java.nio.file.*; + +class FileCryptographer implements Cryptographer { + + private static final BlobType type = BlobType.FILE; + + @Override + public String marker() { + return type.asString(); + } + + @Override + public InputStream formContent(Path file) throws IOException { + return Files.newInputStream(file); + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java new file mode 100644 index 0000000..202f92e --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java @@ -0,0 +1,140 @@ +package ru.ifmo.git.entities; + +import com.google.gson.*; +import org.apache.commons.io.*; + +import ru.ifmo.git.util.*; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +public class GitClerk { + + private final String ENCODING = "UTF-8"; + private Gson gson = new GsonBuilder().create(); + private final GitTree gitTree; + + + public GitClerk(GitTree gitTree){ + this.gitTree = gitTree; + } + + public HeadInfo getHeadInfo() throws GitException { + String headJson; + try { + headJson = FileUtils.readFileToString(gitTree.head().toFile()); + } catch (IOException e) { + throw new GitException("error while reading HEAD"); + } + return gson.fromJson(headJson, HeadInfo.class); + } + + public void changeHeadInfo(HeadInfo newHeadInfo) throws IOException { + String newInfo = gson.toJson(newHeadInfo); + FileUtils.writeStringToFile(gitTree.head().toFile(), newInfo, ENCODING); + } + + public void writeLog(CommitInfo commit) throws GitException { + if (commit.message.isEmpty()) { + commit.message = getUserMessage(); + } + File logFile = gitTree.log().resolve(commit.branch).toFile(); + try { + if(logFile.exists() || logFile.createNewFile()) { + writeToFile(logFile.toPath(), gson.toJson(commit), true); + } + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + } + + private String getUserMessage() { + try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + System.out.print("please enter message: "); + return br.readLine(); + } catch (IOException e) { + return "no message"; + } + } + + static public void writeToFile(Path file, String content, boolean append) throws GitException { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file.toFile(), append))) { + writer.write(content); + } catch (IOException e) { + throw new GitException("error while writing to " + file.getFileName()); + } + } + + public List getHistory() throws GitException { + String branch = getHeadInfo().branchName; + File logFile = gitTree.log().resolve(branch).toFile(); + List history = new ArrayList<>(); + try (BufferedReader br = new BufferedReader(new FileReader(logFile))) { + for (String line; (line = br.readLine()) != null; ) { + history.add(gson.fromJson(line, CommitInfo.class)); + } + } catch (IOException e) { + throw new GitException("error while reading log for " + branch); + } + return history; + } + + public Optional findCommitInfo(String desiredCommit) throws GitException { + for (CommitInfo commit: getHistory()) { + if(commit.hash.startsWith(desiredCommit)) { + return Optional.of(commit); + } + } + return Optional.empty(); + } + + public static String getAuthor() { + return System.getProperty("user.name"); + } + + public static String getCommitMessage() { + try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + System.out.print("please enter message: "); + return br.readLine(); + } catch (IOException e) { + return "no message"; + } + } + + private static String getCurrentTime() { + DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZ"); + return df.format(Calendar.getInstance().getTime()); + } + + + public CommitInfo fillCommitInfo(String message) throws GitException { + CommitInfo info = new CommitInfo(); + info.setAuthor(getAuthor()); + info.setTime(getCurrentTime()); + info.setRootDirectory(gitTree.repo()); + info.setMessage(message.isEmpty() ? getUserMessage() : message); + info.setHash(GitCryptographer.createCommitHash(info)); + info.setBranch(getHeadInfo().branchName); + return info; + } + + public CommitInfo fillAddInfo() throws GitException { + return fillCommitInfo("add"); + } + + public Map collectFilesInfo(Path encodedFile) throws IOException { + Map nameToHash = new HashMap<>(); + List lines = Files.readAllLines(encodedFile, StandardCharsets.UTF_8); + lines.remove(0); + for (String line: lines) { + String[] nameAndHash = line.split("\t"); + nameToHash.put(nameAndHash[0], nameAndHash[1]); + } + return nameToHash; + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java new file mode 100644 index 0000000..aec4f97 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java @@ -0,0 +1,95 @@ +package ru.ifmo.git.entities; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.IOUtils; +import ru.ifmo.git.util.*; + +import java.io.*; +import java.nio.file.*; +import java.util.*; + + +public class GitCryptographer { + + private final BlobType type = BlobType.COMMIT; + private static final TreeCryptographer treeCrypto = new TreeCryptographer(); + private static final FileCryptographer fileCrypto = new FileCryptographer(); + private GitTree gitTree; + + public GitCryptographer(GitTree gitTree) { + this.gitTree = gitTree; + } + + private String marker() { + return type.asString(); + } + + public String getHash(Path file) throws IOException { + if(file.toFile().isFile()) { + return fileCrypto.getHash(file); + } + return treeCrypto.getHash(file); + } + + public static String createHash() { + return DigestUtils.sha1Hex(UUID.randomUUID().toString()); + } + public static String createCommitHash(CommitInfo info) { + String builder = info.time + info.rootDirectory + + info.author + info.branch; + return DigestUtils.sha1Hex(builder); + } + + private BlobType getMarker(Path file) { + if(Files.isDirectory(file)) { + return BlobType.TREE; + } + return BlobType.FILE; + } + + public InputStream encodeFiles(List files) throws IOException { + String sep = System.getProperty("line.separator"); + StringBuilder builder = new StringBuilder(); + builder.append(marker()).append(sep); + for (Path file : files) { + builder.append(getMarker(file).asString()) + .append(getHash(file)) + .append("\t") + .append(file.getFileName()) + .append(sep); + } + return IOUtils.toInputStream(builder.toString(), "UTF-8"); + } + +// private Path getTreePath(List lines) { +// String[] HashAndName = lines.get(1).split("\t"); +// return Paths.get(withoutMarker(HashAndName[0])); +// } + + public List formDecodeReferences(Path commitFile) throws IOException { + return treeCrypto.decodeTree(commitFile, new GitFileKeeper(gitTree)); + } + + public FileReference formHeaderReference(String hash, List files) throws IOException { + FileReference commit = new FileReference(); + commit.type = type; + commit.name = hash; + commit.content = encodeFiles(files); + return commit; + } + + public List formEncodeReferences(List files) throws IOException { + List references = new ArrayList<>(); + for (Path file : files) { + if(!Files.isHidden(file)) { + if(Files.isDirectory(file)) { + references.addAll(treeCrypto.formEncodeReferences(file)); + } else { + references.add(fileCrypto.formEncodeReference(file)); + } + } + } + return references; + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java new file mode 100644 index 0000000..5db403f --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java @@ -0,0 +1,107 @@ +package ru.ifmo.git.entities; + +import org.apache.commons.io.FileUtils; +import ru.ifmo.git.util.*; + +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.util.stream.Collectors; + +public class GitFileKeeper { + + private Path storage; + private GitTree gitTree; + private static final int dirNameLen = 2; + + public GitFileKeeper(GitTree gitTree) { + this.gitTree = gitTree; + storage = gitTree.storage(); + } + + public static Path withDir(Path file) { + String fileName = file.toFile().getName(); + return Paths.get(fileName.substring(0, dirNameLen), + fileName.substring(dirNameLen)).toAbsolutePath(); + } + + public Path getDir(String blob) { + return storage.resolve(blob.substring(0, dirNameLen)); + } + + public Path correctPath(String blob) { + return getDir(blob).resolve(blob.substring(dirNameLen)); + } + + private Path filePath(String blob) throws IOException { + Path directory = getDir(blob); + if(Files.notExists(directory)) { + boolean ignored = directory.toFile().mkdirs(); + } + return directory.resolve(blob.substring(dirNameLen)); + } + + public void saveCommit(List references) throws IOException { + for (FileReference reference : references) { + Path file = filePath(reference.name); + Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); + } + } + + public void saveToIndex(List references) throws IOException { + for (FileReference reference : references) { + Path file = gitTree.index().resolve(reference.name); + Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); + } + } + + public Optional findFileInStorage(String hash) throws IOException { + List blobs = Files.list(getDir(hash)).collect(Collectors.toList()); + for (Path blob: blobs) { + if(blob.getFileName().startsWith(hash.substring(dirNameLen))) { + return Optional.of(blob); + } + } + return Optional.empty(); + } + + public void restoreCommit(List references, Path destination) throws IOException { + for (FileReference reference : references) { + Path file = destination.resolve(reference.name); + if(reference.type.equals(BlobType.FILE)) { + Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); + } else { + boolean ignored = file.toFile().mkdirs(); + } + } + } + + public static boolean removeFile(Path file) { + try { + Files.deleteIfExists(file); + return true; + } catch (IOException e) { + return false; + } + } + + static public void copyAll(List files, Path targetDir) throws IOException { + File destination = targetDir.toFile(); + if (destination.exists() || (!destination.exists() && destination.mkdirs())) { + for (Path f : files) { + File file = f.toFile(); + if (file.isFile()) { + FileUtils.copyFileToDirectory(file, destination); + } else if (file.isDirectory()) { + FileUtils.copyDirectoryToDirectory(file, destination); + } + } + } + } + + static public void removeAll(List files) throws IOException { + for (Path file : files) { + Files.deleteIfExists(file); + } + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/masters/GitParser.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java similarity index 50% rename from task1_git/src/main/java/ru/ifmo/git/masters/GitParser.java rename to task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java index 48e3d8a..32eb502 100644 --- a/task1_git/src/main/java/ru/ifmo/git/masters/GitParser.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java @@ -1,9 +1,11 @@ -package ru.ifmo.git.masters; +package ru.ifmo.git.entities; import net.sourceforge.argparse4j.*; import net.sourceforge.argparse4j.inf.*; import ru.ifmo.git.commands.*; +import java.nio.file.Path; + public class GitParser { private ArgumentParser gitParser; @@ -23,6 +25,8 @@ private void createGitParser() { Subparser parserInit = subparsers.addParser("init") .setDefault("cmd", new Init()) .help("Create an empty Git repository or reinitialize an existing one"); + parserInit.addArgument("") + .type(Path.class).nargs("?").setDefault(GitTree.cwd()); Subparser parserAdd = subparsers.addParser("add") .setDefault("cmd", new Add()) @@ -30,27 +34,37 @@ private void createGitParser() { parserAdd.addArgument("").type(String.class) .required(true).nargs("+"); + Subparser parserRemove = subparsers.addParser("rm") + .setDefault("cmd", new Remove()) + .help("Remove files from the working tree and from the index"); + parserRemove.addArgument("").type(String.class) + .required(true).nargs("+"); + +// Subparser parserStatus = subparsers.addParser("status") +// .setDefault("cmd", new Status()) +// .help("Show current state of the repository"); + Subparser parserCommit = subparsers.addParser("commit") .setDefault("cmd", new Commit()) .help("Record changes to the repository"); - parserCommit.addArgument("message").type(String.class); + parserCommit.addArgument("-m", "--message").nargs(1).type(String.class); parserCommit.addArgument("").type(String.class).nargs("+"); - Subparser parserReset = subparsers.addParser("reset") - .setDefault("cmd", new Reset()) - .help("Reset current HEAD to the specified state"); - parserReset.addArgument("").type(String.class) - .required(true); - - Subparser parserLog = subparsers.addParser("log") - .setDefault("cmd", new Log()) - .help("Show commit logs"); - parserLog.addArgument("").type(String.class).nargs("?"); - - Subparser parserCheckout = subparsers.addParser("checkout") - .setDefault("cmd", new Checkout()) - .help("Switch branches or restore working tree files"); - parserCheckout.addArgument("").type(String.class); +// Subparser parserReset = subparsers.addParser("reset") +// .setDefault("cmd", new Reset()) +// .help("Reset current HEAD to the specified state"); +// parserReset.addArgument("").type(String.class) +// .required(true); +// +// Subparser parserLog = subparsers.addParser("log") +// .setDefault("cmd", new Log()) +// .help("Show commit logs"); +// parserLog.addArgument("").type(String.class).nargs("?"); +// +// Subparser parserCheckout = subparsers.addParser("checkout") +// .setDefault("cmd", new Checkout()) +// .help("Switch branches or restore working tree files"); +// parserCheckout.addArgument("").type(String.class); } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java new file mode 100644 index 0000000..27277ef --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java @@ -0,0 +1,71 @@ +package ru.ifmo.git.entities; + +import java.io.IOException; +import java.nio.file.*; + +public class GitTree { + + private Path rootDir; + private Path gitDir; + private Path logDir; + private Path storageDir; + private Path indexDir; + private Path headFile; + + public GitTree() { + setRepository(cwd()); + } + + public GitTree(Path repository) { + setRepository(repository); + } + + private void setRepository(Path repository) { + rootDir = repository; + gitDir = rootDir.resolve(".m_git"); + headFile = gitDir.resolve("HEAD"); + logDir = gitDir.resolve("log"); + storageDir = gitDir.resolve("storage"); + indexDir = gitDir.resolve("index"); + } + + public void createGitTree() throws IOException { + gitDir = Files.createDirectory(rootDir.resolve(".m_git")); + headFile = Files.createFile(gitDir.resolve("HEAD")); + logDir = Files.createDirectory(gitDir.resolve("log")); + storageDir = Files.createDirectory(gitDir.resolve("storage")); + indexDir = Files.createDirectory(gitDir.resolve("index")); + } + + public Path repo() { + return rootDir; + } + + public Path index() { + return indexDir; + } + + public Path log() { + return logDir; + } + + public Path storage() { + return storageDir; + } + + public Path head() { + return headFile; + } + + public Path git() { + return gitDir; + } + + public boolean exists() { + return Files.exists(gitDir); + } + + public static Path cwd() { + return Paths.get(".").toAbsolutePath().normalize(); + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java b/task1_git/src/main/java/ru/ifmo/git/entities/StorageMaster.java similarity index 86% rename from task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java rename to task1_git/src/main/java/ru/ifmo/git/entities/StorageMaster.java index 33608b2..5d5a034 100644 --- a/task1_git/src/main/java/ru/ifmo/git/masters/StorageMaster.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/StorageMaster.java @@ -1,4 +1,4 @@ -package ru.ifmo.git.masters; +package ru.ifmo.git.entities; import org.apache.commons.io.FileUtils; import ru.ifmo.git.util.*; @@ -8,6 +8,15 @@ public class StorageMaster { + private File storage; + private final String ENCODING = "UTF_8"; + + public StorageMaster(File storage) { + this.storage = storage; + } + + /////////////////////////////////////////////// + static public void copyAll(List args, File targetDir) throws GitException { if (targetDir.exists() || (!targetDir.exists() && targetDir.mkdirs())) { for (File file : args) { diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/TreeCryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/TreeCryptographer.java new file mode 100644 index 0000000..cb2a3fe --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/TreeCryptographer.java @@ -0,0 +1,88 @@ +package ru.ifmo.git.entities; + +import org.apache.commons.io.IOUtils; +import ru.ifmo.git.util.*; + +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.util.stream.Collectors; + +class TreeCryptographer implements Cryptographer { + + private final FileCryptographer fileCrypto = new FileCryptographer(); + private final BlobType type = BlobType.TREE; + + @Override + public String marker() { + return type.asString(); + } + + @Override + public InputStream formContent(Path directory) throws IOException { + List files = Files.list(directory).collect(Collectors.toList()); + StringBuilder builder = new StringBuilder(); + for (Path file : files) { + if(!Files.isHidden(file)) { + if (Files.isRegularFile(file)) { + builder .append(fileCrypto.marker()) + .append(fileCrypto.getHash(file)); + } else { + builder .append(marker()) + .append(getHash(file)); + } + builder .append(tab) + .append(file.getFileName()) + .append(sep); + } + } + return IOUtils.toInputStream(builder.toString(), ENCODING); + } + + public List formEncodeReferences(Path tree) throws IOException { + List references = new ArrayList<>(); + List files = Files.list(tree).collect(Collectors.toList()); + references.add(formEncodeReference(tree)); + for (Path file : files) { + if(!Files.isHidden(file)) { + if(Files.isRegularFile(file)) { + FileReference lll = fileCrypto.formEncodeReference(file); + references.add(lll); + } else { + references.addAll(formEncodeReferences(file)); + } + } + } + return references; + } + + private List decodeComponent(String component, GitFileKeeper storage) throws IOException { + BlobType type = readMarker(component); + String[] HashAndName = removeMarker(component).split(tab); + Path encodedFile = storage.correctPath(HashAndName[0]); + if(type.equals(BlobType.FILE)) { + return Collections.singletonList(fileCrypto.decodeFile(encodedFile)); + } + if(type.equals(BlobType.TREE)) { + return decodeTree(encodedFile, storage); + } + return Collections.emptyList(); + } + + + public List decodeTree(Path treeFile, GitFileKeeper storage) throws IOException { + List decodedFiles = new ArrayList<>(); + FileReference decodedTree = fileCrypto.decodeFile(treeFile); + decodedFiles.add(decodedTree); + List components = IOUtils.readLines(decodedTree.content, ENCODING); + for (String component: components) { + List references = decodeComponent(component, storage); + for(FileReference ref : references) { + ref.name = Paths.get(decodedTree.name, ref.name).toString(); + } + decodedFiles.addAll(references); + } + return decodedFiles; + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java b/task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java deleted file mode 100644 index c2907e9..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/masters/FileMaster.java +++ /dev/null @@ -1,67 +0,0 @@ -package ru.ifmo.git.masters; - -import com.google.gson.*; -import org.apache.commons.io.*; - -import ru.ifmo.git.util.*; - -import java.io.*; -import java.util.*; - -public class FileMaster { - - static public List getHistory(File logFile) throws GitException { - List history = new ArrayList<>(); - try (BufferedReader br = new BufferedReader(new FileReader(logFile))) { - for (String line; (line = br.readLine()) != null; ) { - history.add(new GsonBuilder().create().fromJson(line, CommitInfo.class)); - } - } catch (IOException e) { - throw new GitException("error while reading log\n"); - } - return history; - } - - public static HeadInfo getHeadInfo(File headFile) throws GitException { - String headJson; - try (FileInputStream inputStream = new FileInputStream(headFile.getAbsolutePath())) { - headJson = IOUtils.toString(inputStream); - } catch (IOException e) { - throw new GitException("error while reading HEAD\n"); - } - return new GsonBuilder().create().fromJson(headJson, HeadInfo.class); - } - - static public void writeToFile(String fileName, String content, boolean append) throws GitException { - File file = new File(fileName); - try (BufferedWriter writer = new BufferedWriter(new FileWriter(file, append))) { - writer.write(content + (append ? "\n" : "")); - } catch (IOException e) { - throw new GitException("error while writing to " + file.getName()); - } - } - - static public void changeCurHash(String newHash, boolean withHead) throws GitException { - HeadInfo headInfo = FileMaster.getHeadInfo(new File(GitTree.head())); - headInfo.setCurrentHash(newHash); - if (withHead) { - headInfo.setHeadHash(newHash); - } - String newHeadContent = (new Gson()).toJson(headInfo); - FileMaster.writeToFile(GitTree.head(), newHeadContent, false); - } - - static public File findCommitInStorage(String desiredCommit) throws GitException { - File[] allCommits = new File(GitTree.storage()).listFiles(); - if (allCommits == null || allCommits.length == 0) { - throw new GitException("no commits yet\n"); - } - Optional commitDir = Arrays.stream(allCommits) - .filter(file -> file.getName().startsWith(desiredCommit)).findFirst(); - if (!commitDir.isPresent()) { - throw new GitException("no such commit\n"); - } - return commitDir.get(); - } - -} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/BlobType.java b/task1_git/src/main/java/ru/ifmo/git/util/BlobType.java new file mode 100644 index 0000000..c2ad255 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/BlobType.java @@ -0,0 +1,26 @@ +package ru.ifmo.git.util; + +public enum BlobType { + + FILE, TREE, COMMIT; + + static public BlobType typeOf(String mark) { + return + mark.equals("cm\\") ? COMMIT : + mark.equals("tr\\") ? TREE : + FILE; + } + + public String asString() { + switch (this) { + case FILE: return "fl\\"; + case TREE: return "tr\\"; + case COMMIT: return "cm\\"; + } + return ""; + } + + static public int size() { + return 3; + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Command.java b/task1_git/src/main/java/ru/ifmo/git/util/Command.java deleted file mode 100644 index 10bad2b..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/util/Command.java +++ /dev/null @@ -1,25 +0,0 @@ -package ru.ifmo.git.util; - -import java.io.File; -import java.util.*; - -public interface Command { - - default boolean repositoryExists() { - return new File(GitTree.repo()).exists(); - } - - boolean correctArgs(Map args); - - default void checkRepoAndArgs(Map args) throws GitException { - if (!repositoryExists()) { - throw new GitException("fatal: Not a git repository: .m_git\n"); - } - if (!correctArgs(args)) { - throw new GitException("wrong arguments\n"); - } - } - - CommandResult execute(Map args) throws GitException; - -} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java index aa0908a..f8c94e0 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java @@ -1,15 +1,55 @@ package ru.ifmo.git.util; +import java.nio.file.Path; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.UUID; + public class CommitInfo { public String author; public String time; public String hash; public String message; public String branch; + public String rootDirectory; public CommitInfo() { } + public void setAuthor(String author) { + this.author = author; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public void setAuthor() { + this.author = System.getProperty("user.name"); + } + + public void setTime() { + DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZ"); + this.time = df.format(Calendar.getInstance().getTime()); + } + + public void setTime(String time) { + this.time = time; + } + + public void setRootDirectory(Path rootPath) { + this.rootDirectory = rootPath.toAbsolutePath().toString(); + } + public String toString() { return "commit " + hash + "\n" + "Author:\t" + author + "\n" + diff --git a/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java b/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java index 365b529..beb2f68 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java @@ -1,5 +1,5 @@ package ru.ifmo.git.util; public enum ExitStatus { - SUCCESS, FAILURE, ERROR + SUCCESS, FAILURE, ERROR; } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/FileReference.java b/task1_git/src/main/java/ru/ifmo/git/util/FileReference.java new file mode 100644 index 0000000..36acf1c --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/FileReference.java @@ -0,0 +1,15 @@ +package ru.ifmo.git.util; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; + +public class FileReference { + + public BlobType type; + public String name; + public InputStream content; + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/GitTree.java b/task1_git/src/main/java/ru/ifmo/git/util/GitTree.java deleted file mode 100644 index 9fd31e0..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/util/GitTree.java +++ /dev/null @@ -1,31 +0,0 @@ -package ru.ifmo.git.util; - -import java.nio.file.Paths; - -public class GitTree { - - static public String cwd() { - return Paths.get(".").toAbsolutePath().normalize().toString(); - } - - static public String repo() { - return Paths.get(cwd(), ".m_git").toString(); - } - - static public String index() { - return Paths.get(repo(), "index").toString(); - } - - static public String log() { - return Paths.get(repo(), "logs").toString(); - } - - static public String storage() { - return Paths.get(repo(), "storage").toString(); - } - - static public String head() { - return Paths.get(repo(), "HEAD").toString(); - } - -} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java index 88bb53f..3f061e8 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java @@ -15,11 +15,17 @@ public HeadInfo(String branch) { currentHash = ""; } - public void setHeadHash(String hash) { + public void moveHead(String hash) { headHash = hash; } - public void setCurrentHash(String hash) { + public void moveCurrent(String hash) { currentHash = hash; } + + public void moveBoth(String hash) { + moveHead(hash); + moveCurrent(hash); + } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/ListOfFiles.java b/task1_git/src/main/java/ru/ifmo/git/util/ListOfFiles.java new file mode 100644 index 0000000..224d3fc --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/util/ListOfFiles.java @@ -0,0 +1,22 @@ +package ru.ifmo.git.util; + +import javafx.util.Pair; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ListOfFiles { + public Map namesToHashes; + + public void init() { + namesToHashes = new HashMap<>(); + } + + public void addInfo(String name , String hash) { + namesToHashes.put(name, hash); + } +} + + diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Message.java b/task1_git/src/main/java/ru/ifmo/git/util/Message.java index 3ef5ac4..a83b093 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/Message.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/Message.java @@ -31,4 +31,8 @@ public void clear() { os.reset(); } + public void print() { + System.out.print(read()); + } + } From 5036610b9c8c68386e40b079a43f946aaa771d41 Mon Sep 17 00:00:00 2001 From: lergor Date: Wed, 26 Sep 2018 02:23:04 +0300 Subject: [PATCH 08/14] init, add, commit, log, rm commands --- task1_git/src/main/java/ru/ifmo/git/Git.java | 68 ++------ .../java/ru/ifmo/git/commands/Checkout.java | 112 +++++++++---- .../java/ru/ifmo/git/commands/Commit.java | 97 +++-------- .../java/ru/ifmo/git/commands/GitCommand.java | 7 +- .../main/java/ru/ifmo/git/commands/Init.java | 11 +- .../main/java/ru/ifmo/git/commands/Log.java | 155 ++++++++++-------- .../java/ru/ifmo/git/commands/Remove.java | 2 +- .../java/ru/ifmo/git/commands/Status.java | 38 ++--- .../java/ru/ifmo/git/entities/GitClerk.java | 30 ++-- .../ifmo/git/entities/GitCryptographer.java | 16 +- .../ru/ifmo/git/entities/GitFileKeeper.java | 30 +++- .../java/ru/ifmo/git/entities/GitParser.java | 18 +- 12 files changed, 291 insertions(+), 293 deletions(-) diff --git a/task1_git/src/main/java/ru/ifmo/git/Git.java b/task1_git/src/main/java/ru/ifmo/git/Git.java index f4c0a72..0808ce7 100644 --- a/task1_git/src/main/java/ru/ifmo/git/Git.java +++ b/task1_git/src/main/java/ru/ifmo/git/Git.java @@ -2,67 +2,33 @@ import net.sourceforge.argparse4j.inf.ArgumentParserException; import net.sourceforge.argparse4j.inf.Namespace; -import ru.ifmo.git.commands.GitCommand; +import ru.ifmo.git.commands.*; import ru.ifmo.git.entities.GitParser; import ru.ifmo.git.util.*; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + public class Git { public static void main(String[] args) { -// String hash = "b4c66cf0e6c74712a4fd1344ff90ec52855430320"; -// Optional commit = storage.findCommit(hash); -////// -// if(commit.isPresent()) { -// System.out.println("-----"); -// List refs = cryp.formDecodeReferences(commit.get()); -// for (FileReference i : refs) { -// System.out.println(i.name); -// } -// storage.restoreCommit(refs, clear); -// } - - - /////////////////// -// FileInfo info = GitCryptographer.decodeFile(file); -// System.out.println("-----"); -// System.out.println("type: " + String.valueOf(info.type)); -// System.out.println("name: " + info.name); -// System.out.println("name: " + info.localPath); -// info.content.forEach(s -> System.out.println(s + "!")); -// -// -// List infos = cryp.decodeTree(file); -// for (FileInfo i: infos) { -// System.out.println("type: " + String.valueOf(i.type)); -// System.out.println("name: " + i.name); -// System.out.println("name: " + i.localPath); -// } - -// Path new_file = Paths.get("kek/res"); -// Files.write(new_file, info.content, StandardCharsets.UTF_8); - - - //////////////////////////////// - - - -// } catch (IOException e) { -// e.printStackTrace(); -// } - - -// GitСlerk cl = new GitСlerk(tr); - - - - -// args = new String[]{"init"}; + args = new String[]{"init"}; GitParser gitParser = new GitParser(); try { Namespace ns = gitParser.parseArgs(args); - GitCommand command = (GitCommand) ns.getAttrs().remove("cmd"); - CommandResult result = command.execute(ns.getAttrs()); +// GitCommand command = (GitCommand) ns.getAttrs().remove("cmd"); +// CommandResult result = command.execute(ns.getAttrs()); +// CommandResult result = command.execute(ns.getAttrs()); + GitCommand command = new Checkout(Paths.get("./clear")); + Map arrrgs = new LinkedHashMap<>(); + arrrgs.put("", Collections.singletonList("c0bbb1a5f61c8c457fed673fd")); + + + CommandResult result = command.execute(arrrgs); if(result.getStatus() != ExitStatus.SUCCESS) { System.out.println("exit with code " + result.getStatus()); } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java index ee1f672..5544896 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java @@ -1,34 +1,78 @@ -//package ru.ifmo.git.commands; -// -//import ru.ifmo.git.entities.*; -//import ru.ifmo.git.util.*; -// -//import java.io.*; -//import java.util.Map; -// -//import org.apache.commons.io.FileUtils; -// -//public class Checkout implements GitCommand { -// -// private String commit; -// -// @Override -// public boolean correctArgs(Map args) { -// commit = (String) args.get(""); -// return commit.length() > 6; -// } -// -// @Override -// public CommandResult execute(Map args) { -// try { -// checkRepoAndArgs(args); -// File commitDir = FileMaster.findCommitInStorage(commit); -// FileUtils.copyDirectory(commitDir, new File(GitTree.cwd())); -// FileMaster.changeCurHash(commitDir.getName(), false); -// } catch (IOException | GitException e) { -// return new CommandResult(ExitStatus.ERROR, e.getMessage()); -// } -// return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); -// } -// -//} +package ru.ifmo.git.commands; + +import ru.ifmo.git.entities.*; +import ru.ifmo.git.util.*; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class Checkout implements GitCommand { + + private Path commitFile; + private GitTree gitTree; + private GitClerk gitClerk; + private GitFileKeeper gitFileKeeper; + private GitCryptographer gitCrypto; + + public Checkout() { + initEntities(GitTree.cwd()); + } + + public Checkout(Path cwd) { + initEntities(cwd); + } + + private void initEntities(Path cwd) { + gitTree = new GitTree(cwd); + gitClerk = new GitClerk(gitTree); + gitFileKeeper = new GitFileKeeper(gitTree); + gitCrypto = new GitCryptographer(gitTree); + } + + @Override + public boolean correctArgs(Map args) throws GitException { + String commitHash = (String) args.get(""); + if(commitHash.length() > 6) { + try { + Optional commit = gitFileKeeper.findFileInStorage(commitHash); + if(commit.isPresent()) { + commitFile = commit.get(); + return true; + } + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + } + return false; + } + + @Override + public CommandResult doWork(Map args) throws GitException { + if (!gitTree.exists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); + } + try { + List references = gitCrypto.formDecodeReferences(commitFile); + for (FileReference i : references) { + System.out.println(i.name); + } + GitFileKeeper.clearDirectory(gitTree.repo()); + gitFileKeeper.restoreCommit(references, gitTree.repo()); + changeHeadInfo(); + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); + + } + + private void changeHeadInfo() throws GitException { + HeadInfo headInfo = gitClerk.getHeadInfo(); + headInfo.moveCurrent(commitFile.toFile().getName()); + gitClerk.changeHeadInfo(headInfo); + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index c2bfe87..10c157f 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -14,7 +14,6 @@ public class Commit implements GitCommand { - private HeadInfo headInfo; private CommitInfo commitInfo; private List files = new LinkedList<>(); private GitTree gitTree; @@ -30,7 +29,7 @@ public Commit(Path cwd) { initEntities(cwd); } - void initEntities(Path cwd) { + private void initEntities(Path cwd) { gitTree = new GitTree(cwd); gitClerk = new GitClerk(gitTree); gitFileKeeper = new GitFileKeeper(gitTree); @@ -56,87 +55,33 @@ public boolean correctArgs(Map args) throws GitException { } @Override - public CommandResult execute(Map args) { - try { - if(!correctArgs(args)) { - return new CommandResult(ExitStatus.ERROR, "try git add first\n"); - } - checkRepoAndArgs(args); - headInfo = FileMaster.getHeadInfo(new File(GitTree.head())); - setCommitInfo(); - StorageMaster.copyAll(files, Paths.get(GitTree.storage(), headInfo.currentHash).toFile()); - writeLog(); - return new CommandResult(ExitStatus.SUCCESS, "commit: done!\n"); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, "commit: " + e.getMessage()); - } - } - - - @Override - public CommandResult doWork(Map args) throws GitException { + public CommandResult doWork(Map args) { if (!gitTree.exists()) { return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); } - - - CommitInfo commitInfo = new CommitInfo(); - commitInfo.setBranch("master"); - commitInfo.setMessage("master?"); - commitInfo.setRootDirectory(tr.repo()); - commitInfo.setAuthor("lergor"); - commitInfo.setTime("1234345678"); - File[] files = tr.repo().toFile().listFiles(); - List filess = Arrays.stream(files).map(File::toPath).filter(s -> !s.toFile().isHidden()).collect(Collectors.toList()); - GitCryptographer cryp = new GitCryptographer(tr); - GitFileKeeper storage = new GitFileKeeper(tr.storage()); - - - - ////////////////// - - List refs1 = cryp.formEncodeReferences(commitInfo, filess); - for (FileReference i : refs1) { - System.out.println(i.name + " " + i.type); - } -// storage.saveCommit(refs1); - - return null; - } - - - private void setCommitInfo() throws GitException { - commitInfo.author = System.getProperty("user.name"); - commitInfo.message = message; - commitInfo.branch = headInfo.branchName; - - DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZ"); - Calendar calendar = Calendar.getInstance(); - commitInfo.time = df.format(calendar.getTime()); - - String name = String.valueOf(commitInfo.time.concat(String.valueOf(GitTree.cwd())).hashCode()); - commitInfo.name = (UUID.randomUUID().toString() + name).replaceAll("-", ""); - - boolean moveHead = headInfo.headHash.equals(headInfo.currentHash); - FileMaster.changeCurHash(commitInfo.name, moveHead); - } - - private void writeLog() throws GitException { - if (commitInfo.message.isEmpty()) { - getUserMessage(); + try { + commitInfo = gitClerk.fillCommitInfo((String) args.getOrDefault("message", "")); + List references = gitCrypto.formEncodeReferences(files); + FileReference commitReference = gitCrypto.formHeaderReference(commitInfo.hash, files); + references.add(commitReference); + gitFileKeeper.saveCommit(references); + gitClerk.writeLog(commitInfo); + changeHeadInfo(); + GitFileKeeper.clearDirectory(gitTree.index()); + } catch (IOException | GitException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); } - String logContent = (new Gson()).toJson(commitInfo); - String logFile = Paths.get(GitTree.log(), headInfo.branchName).toString(); - FileMaster.writeToFile(logFile, logContent, true); + return new CommandResult(ExitStatus.SUCCESS, "commit: done!"); } - private void getUserMessage() { - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - System.out.print("please enter message: "); - commitInfo.message = br.readLine(); - } catch (IOException e) { - commitInfo.message = "no message"; + private void changeHeadInfo() throws GitException { + HeadInfo headInfo = gitClerk.getHeadInfo(); + if (headInfo.headHash == null || headInfo.headHash.equals(headInfo.currentHash)) { + headInfo.moveBoth(commitInfo.hash); + } else { + headInfo.moveCurrent(commitInfo.hash); } + gitClerk.changeHeadInfo(headInfo); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java index 0cca009..dabc5a3 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java @@ -19,13 +19,14 @@ public interface GitCommand { default CommandResult execute(Map args) { String name = this.getClass().getSimpleName().toLowerCase(); try { - if (!correctArgs(args)) { - return new CommandResult(ExitStatus.ERROR, name + ": wrong arguments"); + if (correctArgs(args)) { + return doWork(args); } - return doWork(args); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, name + ": " + e.getMessage()); } + return new CommandResult(ExitStatus.ERROR, name + ": wrong args"); + } default void checkFilesExist(List files) throws GitException { diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java index 5d75984..68f4643 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java @@ -14,6 +14,15 @@ public class Init implements GitCommand { private GitTree gitTree; + public Init() { + gitTree = new GitTree(); + } + + public Init(Path cwd) { + gitTree = new GitTree(cwd); + } + + @Override public boolean correctArgs(Map args) { return args.size() == 1 && Files.exists((Path) args.get("")); @@ -38,7 +47,7 @@ public CommandResult doWork(Map args) throws GitException { return new CommandResult(ExitStatus.SUCCESS, message); } - private void writeHead() throws IOException { + private void writeHead() throws GitException { HeadInfo info = new HeadInfo(); info.branchName = "master"; GitClerk clerk = new GitClerk(gitTree); diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index 38c9e06..1e2164e 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -1,70 +1,85 @@ -//package ru.ifmo.git.commands; -// -//import ru.ifmo.git.entities.*; -//import ru.ifmo.git.util.*; -// -//import java.io.*; -//import java.nio.file.Paths; -//import java.util.*; -//import java.util.function.Predicate; -// -//public class Log implements GitCommand { -// -// private HeadInfo headInfo; -// private String commit; -// -// @Override -// public boolean correctArgs(Map args) { -// if (args.size() == 1) { -// commit = (String) args.get(""); -// return true; -// } -// return (args.size() == 0); -// } -// -// @Override -// public CommandResult execute(Map args) { -// try { -// checkRepoAndArgs(args); -// headInfo = FileMaster.getHeadInfo(new File(GitTree.head())); -// } catch (GitException e) { -// return new CommandResult(ExitStatus.ERROR, "error while reading HEAD\n"); -// } -// return readLog(Paths.get(GitTree.log(), headInfo.branchName).toFile(), commit); -// } -// -// private CommandResult readLog(File logFile, String revision) { -// if (logFile.exists()) { -// Message logContent = new Message(); -// List history; -// try { -// history = FileMaster.getHistory(logFile); -// } catch (GitException e) { -// return new CommandResult(ExitStatus.ERROR, e.getMessage()); -// } -// if (history.size() == 0) { -// return emptyLogResult(); -// } -// history.stream().filter( -// new Predicate() { -// -// private boolean include = (revision == null || revision.isEmpty()); -// -// @Override -// public boolean test(CommitInfo commitInfo) { -// include = include || commitInfo.name.startsWith(revision); -// return include; -// } -// } -// ).forEach(info -> logContent.write(info.toString())); -// return new CommandResult(ExitStatus.SUCCESS, logContent); -// } -// return emptyLogResult(); -// } -// -// private CommandResult emptyLogResult() { -// String failMessage = "fatal: your current branch '" + headInfo.branchName + "' does not have any commits yet\n"; -// return new CommandResult(ExitStatus.FAILURE, failMessage); -// } -// -//} +package ru.ifmo.git.commands; + +import ru.ifmo.git.entities.*; +import ru.ifmo.git.util.*; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.Predicate; + +public class Log implements GitCommand { + + private HeadInfo headInfo; + private String commit; + private GitTree gitTree; + private GitClerk gitClerk; + private GitFileKeeper gitFileKeeper; + private GitCryptographer gitCrypto; + + public Log() { + initEntities(GitTree.cwd()); + } + + public Log(Path cwd) { + initEntities(cwd); + } + + private void initEntities(Path cwd) { + gitTree = new GitTree(cwd); + gitClerk = new GitClerk(gitTree); + gitFileKeeper = new GitFileKeeper(gitTree); + gitCrypto = new GitCryptographer(gitTree); + } + + @Override + public boolean correctArgs(Map args) { + commit = (String) args.get(""); + return commit == null || commit.length() > 6; + } + + @Override + public CommandResult doWork(Map args) throws GitException { + if (!gitTree.exists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); + } + return readLog(commit); + } + + + private CommandResult readLog(String revision) { + if (Files.exists(gitTree.log())) { + Message logContent = new Message(); + List history; + try { + history = gitClerk.getLogHistory(); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); + } + if (history.size() == 0) { + return emptyLogResult(); + } + history.stream().filter( + new Predicate() { + + private boolean include = (revision == null || revision.isEmpty()); + + @Override + public boolean test(CommitInfo commitInfo) { + include = include || commitInfo.hash.startsWith(revision); + return include; + } + } + ).forEach(info -> logContent.write(info.toString())); + return new CommandResult(ExitStatus.SUCCESS, logContent); + } + return emptyLogResult(); + } + + private CommandResult emptyLogResult() { + String failMessage = "fatal: your current branch '" + headInfo.branchName + "' does not have any commits yet\n"; + return new CommandResult(ExitStatus.FAILURE, failMessage); + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java index a09c3fa..7a7a8e4 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java @@ -44,7 +44,7 @@ public CommandResult doWork(Map args) { List filesInCWD = files.stream().map(gitTree.repo()::resolve).collect(Collectors.toList()); GitFileKeeper.removeAll(filesInIndex); GitFileKeeper.removeAll(filesInCWD); - } catch (IOException e) { + } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, "remove: " + e.getMessage()); } return new CommandResult(ExitStatus.SUCCESS, "remove: done!\n"); diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java index e1ede7e..8a5389e 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java @@ -1,19 +1,19 @@ -package ru.ifmo.git.commands; - -import ru.ifmo.git.util.CommandResult; -import ru.ifmo.git.util.GitException; - -import java.util.Map; - -public class Status implements GitCommand { - - @Override - public boolean correctArgs(Map args) { - return args.isEmpty(); - } - - @Override - public CommandResult doWork(Map args) throws GitException { - return null; - } -} +//package ru.ifmo.git.commands; +// +//import ru.ifmo.git.util.CommandResult; +//import ru.ifmo.git.util.GitException; +// +//import java.util.Map; +// +//public class Status implements GitCommand { +// +// @Override +// public boolean correctArgs(Map args) { +// return args.isEmpty(); +// } +// +// @Override +// public CommandResult doWork(Map args) throws GitException { +// return null; +// } +//} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java index 202f92e..907bc22 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java @@ -15,6 +15,7 @@ public class GitClerk { private final String ENCODING = "UTF-8"; + private final String sep = System.getProperty("line.separator"); private Gson gson = new GsonBuilder().create(); private final GitTree gitTree; @@ -33,19 +34,21 @@ public HeadInfo getHeadInfo() throws GitException { return gson.fromJson(headJson, HeadInfo.class); } - public void changeHeadInfo(HeadInfo newHeadInfo) throws IOException { + public void changeHeadInfo(HeadInfo newHeadInfo) throws GitException { String newInfo = gson.toJson(newHeadInfo); - FileUtils.writeStringToFile(gitTree.head().toFile(), newInfo, ENCODING); + try { + FileUtils.writeStringToFile(gitTree.head().toFile(), newInfo, ENCODING); + } catch (IOException e) { + throw new GitException(e.getMessage()); + } } + public void writeLog(CommitInfo commit) throws GitException { - if (commit.message.isEmpty()) { - commit.message = getUserMessage(); - } File logFile = gitTree.log().resolve(commit.branch).toFile(); try { if(logFile.exists() || logFile.createNewFile()) { - writeToFile(logFile.toPath(), gson.toJson(commit), true); + writeToFile(logFile.toPath(), gson.toJson(commit) + sep, true); } } catch (IOException e) { throw new GitException(e.getMessage()); @@ -69,7 +72,7 @@ static public void writeToFile(Path file, String content, boolean append) throws } } - public List getHistory() throws GitException { + public List getLogHistory() throws GitException { String branch = getHeadInfo().branchName; File logFile = gitTree.log().resolve(branch).toFile(); List history = new ArrayList<>(); @@ -84,7 +87,7 @@ public List getHistory() throws GitException { } public Optional findCommitInfo(String desiredCommit) throws GitException { - for (CommitInfo commit: getHistory()) { + for (CommitInfo commit: getLogHistory()) { if(commit.hash.startsWith(desiredCommit)) { return Optional.of(commit); } @@ -96,14 +99,7 @@ public static String getAuthor() { return System.getProperty("user.name"); } - public static String getCommitMessage() { - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - System.out.print("please enter message: "); - return br.readLine(); - } catch (IOException e) { - return "no message"; - } - } + private static String getCurrentTime() { DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZ"); @@ -116,7 +112,7 @@ public CommitInfo fillCommitInfo(String message) throws GitException { info.setAuthor(getAuthor()); info.setTime(getCurrentTime()); info.setRootDirectory(gitTree.repo()); - info.setMessage(message.isEmpty() ? getUserMessage() : message); + info.setMessage(message == null ? getUserMessage() : message); info.setHash(GitCryptographer.createCommitHash(info)); info.setBranch(getHeadInfo().branchName); return info; diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java index aec4f97..f296c27 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java @@ -78,15 +78,19 @@ public FileReference formHeaderReference(String hash, List files) throws I return commit; } - public List formEncodeReferences(List files) throws IOException { + public List formEncodeReferences(List files) throws GitException { List references = new ArrayList<>(); for (Path file : files) { - if(!Files.isHidden(file)) { - if(Files.isDirectory(file)) { - references.addAll(treeCrypto.formEncodeReferences(file)); - } else { - references.add(fileCrypto.formEncodeReference(file)); + try { + if(!Files.isHidden(file)) { + if(Files.isDirectory(file)) { + references.addAll(treeCrypto.formEncodeReferences(file)); + } else { + references.add(fileCrypto.formEncodeReference(file)); + } } + } catch (IOException e) { + throw new GitException(e.getMessage()); } } return references; diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java index 5db403f..f55ca51 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java @@ -76,12 +76,11 @@ public void restoreCommit(List references, Path destination) thro } } - public static boolean removeFile(Path file) { + public static void deleteFile(Path file) throws GitException { try { Files.deleteIfExists(file); - return true; } catch (IOException e) { - return false; + throw new GitException(e.getMessage()); } } @@ -99,9 +98,28 @@ static public void copyAll(List files, Path targetDir) throws IOException } } - static public void removeAll(List files) throws IOException { - for (Path file : files) { - Files.deleteIfExists(file); + static public void clearDirectory(Path directory) throws GitException { + try { + List files = Files.list(directory).collect(Collectors.toList()); + removeAll(files); + } catch (IOException e) { + e.printStackTrace(); + throw new GitException("error while removing"); + } + } + + static public void removeAll(List files) throws GitException { + try{ + for (Path file : files) { + if(Files.isRegularFile(file)) { + deleteFile(file); + } else { + clearDirectory(file); + Files.deleteIfExists(file); + } + } + } catch (IOException e) { + throw new GitException(e.getMessage()); } } } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java index 32eb502..8aa10e8 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java @@ -56,15 +56,15 @@ private void createGitParser() { // parserReset.addArgument("").type(String.class) // .required(true); // -// Subparser parserLog = subparsers.addParser("log") -// .setDefault("cmd", new Log()) -// .help("Show commit logs"); -// parserLog.addArgument("").type(String.class).nargs("?"); -// -// Subparser parserCheckout = subparsers.addParser("checkout") -// .setDefault("cmd", new Checkout()) -// .help("Switch branches or restore working tree files"); -// parserCheckout.addArgument("").type(String.class); + Subparser parserLog = subparsers.addParser("log") + .setDefault("cmd", new Log()) + .help("Show commit logs"); + parserLog.addArgument("").type(String.class).nargs("?"); + + Subparser parserCheckout = subparsers.addParser("checkout") + .setDefault("cmd", new Checkout()) + .help("Switch branches or restore working tree files"); + parserCheckout.addArgument("").nargs(1).type(String.class); } From f3819692e2b736bf3977ccff4bd242a91847e766 Mon Sep 17 00:00:00 2001 From: lergor Date: Wed, 26 Sep 2018 06:37:18 +0300 Subject: [PATCH 09/14] all commands --- task1_git/Readme.md | 3 + task1_git/src/main/java/ru/ifmo/git/Git.java | 24 +--- .../main/java/ru/ifmo/git/commands/Add.java | 12 +- .../java/ru/ifmo/git/commands/Checkout.java | 47 +++----- .../java/ru/ifmo/git/commands/Commit.java | 56 +++------ .../java/ru/ifmo/git/commands/GitCommand.java | 13 +-- .../main/java/ru/ifmo/git/commands/Init.java | 31 ++--- .../main/java/ru/ifmo/git/commands/Log.java | 30 ++--- .../java/ru/ifmo/git/commands/Remove.java | 32 ++---- .../main/java/ru/ifmo/git/commands/Reset.java | 102 +++++++++++------ .../java/ru/ifmo/git/commands/Status.java | 107 ++++++++++++++---- .../ru/ifmo/git/entities/Cryptographer.java | 5 +- .../ru/ifmo/git/entities/GitAssembly.java | 39 +++++++ .../java/ru/ifmo/git/entities/GitClerk.java | 11 +- .../ifmo/git/entities/GitCryptographer.java | 19 ++-- .../ru/ifmo/git/entities/GitFileKeeper.java | 42 +++---- .../java/ru/ifmo/git/entities/GitParser.java | 26 ++--- .../java/ru/ifmo/git/entities/GitTree.java | 6 +- .../main/java/ru/ifmo/git/util/BlobType.java | 9 +- .../java/ru/ifmo/git/util/FileReference.java | 4 - .../main/java/ru/ifmo/git/util/HeadInfo.java | 7 -- .../java/ru/ifmo/git/util/ListOfFiles.java | 22 ---- 22 files changed, 321 insertions(+), 326 deletions(-) create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitAssembly.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/util/ListOfFiles.java diff --git a/task1_git/Readme.md b/task1_git/Readme.md index 8855357..f188bb4 100644 --- a/task1_git/Readme.md +++ b/task1_git/Readme.md @@ -10,11 +10,14 @@ The following commands are available:
``` init add +rm +status commit reset log [from_commit] checkout ``` + where *<smth>* means mandatory argument while *[smth]* implies he optional one.
*commit* is represented as short (at least 7 symbols) or entire hash code. diff --git a/task1_git/src/main/java/ru/ifmo/git/Git.java b/task1_git/src/main/java/ru/ifmo/git/Git.java index 0808ce7..49ebc3a 100644 --- a/task1_git/src/main/java/ru/ifmo/git/Git.java +++ b/task1_git/src/main/java/ru/ifmo/git/Git.java @@ -1,41 +1,25 @@ package ru.ifmo.git; -import net.sourceforge.argparse4j.inf.ArgumentParserException; -import net.sourceforge.argparse4j.inf.Namespace; +import net.sourceforge.argparse4j.inf.*; import ru.ifmo.git.commands.*; import ru.ifmo.git.entities.GitParser; import ru.ifmo.git.util.*; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; public class Git { public static void main(String[] args) { - - args = new String[]{"init"}; GitParser gitParser = new GitParser(); try { Namespace ns = gitParser.parseArgs(args); -// GitCommand command = (GitCommand) ns.getAttrs().remove("cmd"); -// CommandResult result = command.execute(ns.getAttrs()); -// CommandResult result = command.execute(ns.getAttrs()); - GitCommand command = new Checkout(Paths.get("./clear")); - Map arrrgs = new LinkedHashMap<>(); - arrrgs.put("", Collections.singletonList("c0bbb1a5f61c8c457fed673fd")); - - - CommandResult result = command.execute(arrrgs); + GitCommand command = (GitCommand) ns.getAttrs().remove("cmd"); + CommandResult result = command.execute(ns.getAttrs()); if(result.getStatus() != ExitStatus.SUCCESS) { System.out.println("exit with code " + result.getStatus()); } - System.out.print(result.getMessage().read()); + System.out.println(result.getMessage().read()); } catch (ArgumentParserException e) { gitParser.handleError(e); } } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java index 536f213..2e8fee2 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java @@ -11,14 +11,14 @@ public class Add implements GitCommand { private List files; - private GitTree gitTree; + private GitAssembly git; public Add() { - gitTree = new GitTree(); + git = new GitAssembly(GitAssembly.cwd()); } public Add(Path cwd) { - gitTree = new GitTree(cwd); + git = new GitAssembly(cwd); } private List getArgs(Map args) { @@ -41,14 +41,14 @@ public boolean correctArgs(Map args) throws GitException { @Override public CommandResult doWork(Map args) throws GitException { - if (!gitTree.exists()) { + if (!git.tree().exists()) { return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); } try { - GitFileKeeper.copyAll(files, gitTree.index()); + GitFileKeeper.copyAll(files, git.tree().index()); } catch (IOException e) { throw new GitException(e.getMessage()); } - return new CommandResult(ExitStatus.SUCCESS, "add: done!\n"); + return new CommandResult(ExitStatus.SUCCESS, "add: done!"); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java index 5544896..b4b93bc 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java @@ -5,44 +5,33 @@ import java.io.IOException; import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; public class Checkout implements GitCommand { private Path commitFile; - private GitTree gitTree; - private GitClerk gitClerk; - private GitFileKeeper gitFileKeeper; - private GitCryptographer gitCrypto; + private GitAssembly git; public Checkout() { - initEntities(GitTree.cwd()); + git = new GitAssembly(GitAssembly.cwd()); } public Checkout(Path cwd) { - initEntities(cwd); - } - - private void initEntities(Path cwd) { - gitTree = new GitTree(cwd); - gitClerk = new GitClerk(gitTree); - gitFileKeeper = new GitFileKeeper(gitTree); - gitCrypto = new GitCryptographer(gitTree); + git = new GitAssembly(cwd); } @Override public boolean correctArgs(Map args) throws GitException { - String commitHash = (String) args.get(""); - if(commitHash.length() > 6) { + String commitHash = (String) args.get(""); + if (commitHash.length() > 6) { try { - Optional commit = gitFileKeeper.findFileInStorage(commitHash); - if(commit.isPresent()) { + Optional commit = git.fileKeeper().findFileInStorage(commitHash); + if (commit.isPresent()) { commitFile = commit.get(); return true; } } catch (IOException e) { + e.printStackTrace(); throw new GitException(e.getMessage()); } } @@ -51,16 +40,13 @@ public boolean correctArgs(Map args) throws GitException { @Override public CommandResult doWork(Map args) throws GitException { - if (!gitTree.exists()) { + if (!git.tree().exists()) { return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); } try { - List references = gitCrypto.formDecodeReferences(commitFile); - for (FileReference i : references) { - System.out.println(i.name); - } - GitFileKeeper.clearDirectory(gitTree.repo()); - gitFileKeeper.restoreCommit(references, gitTree.repo()); + List references = git.crypto().formDecodeReferences(commitFile); + GitFileKeeper.clearDirectory(git.tree().repo()); + git.fileKeeper().restoreCommit(references, git.tree().repo()); changeHeadInfo(); } catch (IOException e) { throw new GitException(e.getMessage()); @@ -70,9 +56,8 @@ public CommandResult doWork(Map args) throws GitException { } private void changeHeadInfo() throws GitException { - HeadInfo headInfo = gitClerk.getHeadInfo(); - headInfo.moveCurrent(commitFile.toFile().getName()); - gitClerk.changeHeadInfo(headInfo); + HeadInfo headInfo = git.clerk().getHeadInfo(); + headInfo.moveCurrent(commitFile.getParent().toFile().getName() + commitFile.toFile().getName()); + git.clerk().changeHeadInfo(headInfo); } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index 10c157f..ff19dfe 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -2,72 +2,45 @@ import ru.ifmo.git.entities.*; import ru.ifmo.git.util.*; -import com.google.gson.Gson; import java.io.*; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.*; import java.util.*; import java.util.stream.Collectors; public class Commit implements GitCommand { private CommitInfo commitInfo; - private List files = new LinkedList<>(); - private GitTree gitTree; - private GitClerk gitClerk; - private GitFileKeeper gitFileKeeper; - private GitCryptographer gitCrypto; + private GitAssembly git; public Commit() { - initEntities(GitTree.cwd()); + git = new GitAssembly(GitAssembly.cwd()); } public Commit(Path cwd) { - initEntities(cwd); - } - - private void initEntities(Path cwd) { - gitTree = new GitTree(cwd); - gitClerk = new GitClerk(gitTree); - gitFileKeeper = new GitFileKeeper(gitTree); - gitCrypto = new GitCryptographer(gitTree); - } - - private List getArgs(Map args) { - return ((List) args.get("")) - .stream() - .map(s -> gitTree.index().resolve(s).normalize()) - .collect(Collectors.toList()); + git = new GitAssembly(cwd); } @Override - public boolean correctArgs(Map args) throws GitException { - if (!args.isEmpty()) { - List files = getArgs(args); - checkFilesExist(files); - this.files = files; - return true; - } - return false; + public boolean correctArgs(Map args) { + return true; } @Override public CommandResult doWork(Map args) { - if (!gitTree.exists()) { + if (!git.tree().exists()) { return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); } try { - commitInfo = gitClerk.fillCommitInfo((String) args.getOrDefault("message", "")); - List references = gitCrypto.formEncodeReferences(files); - FileReference commitReference = gitCrypto.formHeaderReference(commitInfo.hash, files); + List files = Files.list(git.tree().index()).collect(Collectors.toList()); + commitInfo = git.clerk().fillCommitInfo((String) args.getOrDefault("message", "")); + List references = git.crypto().formEncodeReferences(files); + FileReference commitReference = git.crypto().formHeaderReference(commitInfo.hash, files); references.add(commitReference); - gitFileKeeper.saveCommit(references); - gitClerk.writeLog(commitInfo); + git.fileKeeper().saveCommit(references); + git.clerk().writeLog(commitInfo); changeHeadInfo(); - GitFileKeeper.clearDirectory(gitTree.index()); } catch (IOException | GitException e) { return new CommandResult(ExitStatus.ERROR, e.getMessage()); } @@ -75,13 +48,12 @@ public CommandResult doWork(Map args) { } private void changeHeadInfo() throws GitException { - HeadInfo headInfo = gitClerk.getHeadInfo(); + HeadInfo headInfo = git.clerk().getHeadInfo(); if (headInfo.headHash == null || headInfo.headHash.equals(headInfo.currentHash)) { headInfo.moveBoth(commitInfo.hash); } else { headInfo.moveCurrent(commitInfo.hash); } - gitClerk.changeHeadInfo(headInfo); + git.clerk().changeHeadInfo(headInfo); } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java index dabc5a3..7e5b46b 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java @@ -1,14 +1,9 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.util.CommandResult; -import ru.ifmo.git.util.ExitStatus; -import ru.ifmo.git.util.GitException; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; +import ru.ifmo.git.util.*; + +import java.nio.file.*; +import java.util.*; public interface GitCommand { diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java index 68f4643..6e15221 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java @@ -1,27 +1,15 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.entities.GitClerk; -import ru.ifmo.git.entities.GitFileKeeper; -import ru.ifmo.git.entities.GitTree; +import ru.ifmo.git.entities.*; import ru.ifmo.git.util.*; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; +import java.nio.file.*; import java.util.Map; public class Init implements GitCommand { - private GitTree gitTree; - - public Init() { - gitTree = new GitTree(); - } - - public Init(Path cwd) { - gitTree = new GitTree(cwd); - } - + private GitAssembly git; @Override public boolean correctArgs(Map args) { @@ -30,27 +18,28 @@ public boolean correctArgs(Map args) { @Override public CommandResult doWork(Map args) throws GitException { - gitTree = new GitTree((Path) args.get("")); + git = new GitAssembly((Path) args.get("")); Message message = new Message(); - if (!gitTree.exists()) { + if (!git.tree().exists()) { try { - gitTree.createGitTree(); + git.tree().createGitTree(); message.write("initialized empty "); writeHead(); } catch (IOException e) { - return new CommandResult(ExitStatus.FAILURE, "unable to create repository in " + gitTree.repo()); + String msg = "unable to create repository in " + git.tree().repo(); + return new CommandResult(ExitStatus.FAILURE, msg); } } else { message.write("reinitialized existing "); } - message.write("Git repository in " + gitTree.repo() + "\n"); + message.write("Git repository in " + git.tree().repo()); return new CommandResult(ExitStatus.SUCCESS, message); } private void writeHead() throws GitException { HeadInfo info = new HeadInfo(); info.branchName = "master"; - GitClerk clerk = new GitClerk(gitTree); + GitClerk clerk = new GitClerk(git.tree()); clerk.changeHeadInfo(info); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index 1e2164e..1f35a8f 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -3,7 +3,6 @@ import ru.ifmo.git.entities.*; import ru.ifmo.git.util.*; -import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -11,26 +10,15 @@ public class Log implements GitCommand { - private HeadInfo headInfo; private String commit; - private GitTree gitTree; - private GitClerk gitClerk; - private GitFileKeeper gitFileKeeper; - private GitCryptographer gitCrypto; + private GitAssembly git; public Log() { - initEntities(GitTree.cwd()); + git = new GitAssembly(GitAssembly.cwd()); } public Log(Path cwd) { - initEntities(cwd); - } - - private void initEntities(Path cwd) { - gitTree = new GitTree(cwd); - gitClerk = new GitClerk(gitTree); - gitFileKeeper = new GitFileKeeper(gitTree); - gitCrypto = new GitCryptographer(gitTree); + git = new GitAssembly(cwd); } @Override @@ -41,19 +29,19 @@ public boolean correctArgs(Map args) { @Override public CommandResult doWork(Map args) throws GitException { - if (!gitTree.exists()) { + if (!git.tree().exists()) { return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); } return readLog(commit); } - private CommandResult readLog(String revision) { - if (Files.exists(gitTree.log())) { + private CommandResult readLog(String revision) throws GitException { + if (Files.exists(git.tree().log())) { Message logContent = new Message(); List history; try { - history = gitClerk.getLogHistory(); + history = git.clerk().getLogHistory(); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, e.getMessage()); } @@ -77,9 +65,9 @@ public boolean test(CommitInfo commitInfo) { return emptyLogResult(); } - private CommandResult emptyLogResult() { + private CommandResult emptyLogResult() throws GitException { + HeadInfo headInfo = git.clerk().getHeadInfo(); String failMessage = "fatal: your current branch '" + headInfo.branchName + "' does not have any commits yet\n"; return new CommandResult(ExitStatus.FAILURE, failMessage); } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java index 7a7a8e4..4ea3491 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java @@ -1,31 +1,23 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.entities.GitFileKeeper; -import ru.ifmo.git.entities.GitTree; -import ru.ifmo.git.util.CommandResult; -import ru.ifmo.git.util.ExitStatus; -import ru.ifmo.git.util.GitException; - -import java.io.IOException; -import java.nio.file.Files; +import ru.ifmo.git.entities.*; +import ru.ifmo.git.util.*; + import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; public class Remove implements GitCommand { - private GitTree gitTree; - List files; + private List files; + private GitAssembly git; public Remove() { - gitTree = new GitTree(GitTree.cwd()); + git = new GitAssembly(GitAssembly.cwd()); } public Remove(Path cwd) { - gitTree = new GitTree(cwd); + git = new GitAssembly(cwd); } @Override @@ -36,17 +28,17 @@ public boolean correctArgs(Map args) { @Override public CommandResult doWork(Map args) { - if (!gitTree.exists()) { + if (!git.tree().exists()) { return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); } try { - List filesInIndex = files.stream().map(gitTree.index()::resolve).collect(Collectors.toList()); - List filesInCWD = files.stream().map(gitTree.repo()::resolve).collect(Collectors.toList()); + List filesInIndex = files.stream().map(git.tree().index()::resolve).collect(Collectors.toList()); + List filesInCWD = files.stream().map(git.tree().repo()::resolve).collect(Collectors.toList()); GitFileKeeper.removeAll(filesInIndex); GitFileKeeper.removeAll(filesInCWD); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, "remove: " + e.getMessage()); } - return new CommandResult(ExitStatus.SUCCESS, "remove: done!\n"); + return new CommandResult(ExitStatus.SUCCESS, "remove: done!"); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java index 3bd7e4e..09693be 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java @@ -1,34 +1,68 @@ -//package ru.ifmo.git.commands; -// -//import ru.ifmo.git.entities.*; -//import ru.ifmo.git.util.*; -// -//import java.io.*; -//import java.util.Map; -// -//import org.apache.commons.io.FileUtils; -// -//public class Reset implements GitCommand { -// -// private String commit; -// -// @Override -// public boolean correctArgs(Map args) { -// commit = (String) args.get(""); -// return commit.length() > 6; -// } -// -// @Override -// public CommandResult execute(Map args) { -// try { -// checkRepoAndArgs(args); -// File commitDir = FileMaster.findCommitInStorage(commit); -// FileUtils.copyDirectory(commitDir, new File(GitTree.index())); -// FileMaster.changeCurHash(commitDir.getName(), true); -// } catch (IOException | GitException e) { -// return new CommandResult(ExitStatus.ERROR, e.getMessage()); -// } -// return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); -// } -// -//} +package ru.ifmo.git.commands; + +import ru.ifmo.git.entities.*; +import ru.ifmo.git.util.*; + +import java.io.*; +import java.nio.file.Path; +import java.util.*; + +public class Reset implements GitCommand { + + private Path commitFile; + private GitAssembly git; + + public Reset() { + git = new GitAssembly(GitAssembly.cwd()); + } + + public Reset(Path cwd) { + git = new GitAssembly(cwd); + } + + @Override + public boolean correctArgs(Map args) throws GitException { + String commitHash = (String) args.get(""); + if (commitHash.length() > 6) { + try { + Optional commit = git.fileKeeper().findFileInStorage(commitHash); + if (commit.isPresent()) { + commitFile = commit.get(); + return true; + } + } catch (IOException e) { + e.printStackTrace(); + throw new GitException(e.getMessage()); + } + } + return false; + } + + @Override + public CommandResult doWork(Map args) throws GitException { + if (!git.tree().exists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); + } + try { + List references = git.crypto().formDecodeReferences(commitFile); + GitFileKeeper.clearDirectory(git.tree().index()); + git.fileKeeper().restoreCommit(references, git.tree().index()); + changeHeadInfo(); + } catch (IOException | GitException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); + + } + + private void changeHeadInfo() throws GitException { + HeadInfo headInfo = git.clerk().getHeadInfo(); + String hash = commitFile.getParent().toFile().getName() + commitFile.toFile().getName(); + if (!headInfo.currentHash.equals(hash)) { + headInfo.moveCurrent(hash); + git.clerk().changeHeadInfo(headInfo); + } else { + throw new GitException("reset: already on commit " + hash); + } + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java index 8a5389e..0176ab6 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java @@ -1,19 +1,88 @@ -//package ru.ifmo.git.commands; -// -//import ru.ifmo.git.util.CommandResult; -//import ru.ifmo.git.util.GitException; -// -//import java.util.Map; -// -//public class Status implements GitCommand { -// -// @Override -// public boolean correctArgs(Map args) { -// return args.isEmpty(); -// } -// -// @Override -// public CommandResult doWork(Map args) throws GitException { -// return null; -// } -//} +package ru.ifmo.git.commands; + +import ru.ifmo.git.entities.*; +import ru.ifmo.git.util.*; + +import java.io.IOException; +import java.nio.file.*; +import java.util.*; +import java.util.stream.Collectors; + +public class Status implements GitCommand { + + private GitAssembly git; + + public Status() { + git = new GitAssembly(GitAssembly.cwd()); + } + + public Status(Path cwd) { + git = new GitAssembly(cwd); + } + + @Override + public boolean correctArgs(Map args) { + return args.isEmpty(); + } + + @Override + public CommandResult doWork(Map args) throws GitException { + if (!git.tree().exists()) { + return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); + } + try { + HeadInfo headInfo = git.clerk().getHeadInfo(); + Message info = new Message(); + info.write("On branch " + headInfo.branchName + GitClerk.sep); + String changedFiles = getChangedFiles(); + if(changedFiles.isEmpty()) { + info.write("No changed files"); + } else { + info.write("Changed files:"); + info.write(changedFiles); + } + return new CommandResult(ExitStatus.SUCCESS, info); + } catch (IOException e) { + return new CommandResult(ExitStatus.ERROR, e.getMessage()); + } + } + + private String getChangedFiles() throws IOException { + StringBuilder builder = new StringBuilder(); + Map inIndex = collectNameAndHash(git.tree().index()); + for (Map.Entry e : inIndex.entrySet()) { + Path fileInCWD = git.tree().repo().resolve(e.getKey()); + Path fileInIndex = git.tree().index().resolve(e.getKey()); + if (Files.isRegularFile(fileInIndex)) { + if (Files.notExists(fileInCWD)) { + builder.append(GitClerk.sep).append(e.getKey()); + } else { + String hashInIndex = e.getValue(); + String hashInCWD = git.crypto().getHash(fileInCWD); + if (!hashInCWD.equals(hashInIndex)) { + builder.append(GitClerk.sep).append(e.getKey()); + } + } + } + } + return builder.toString(); + } + + private Map collectNameAndHash(Path directory) throws IOException { + List files = Files.list(directory).collect(Collectors.toList()); + Map nameToHash = new HashMap<>(); + for (Path file : files) { + String name = file.toFile().getName(); + if (!Files.isHidden(file)) { + nameToHash.put(name, git.crypto().getHash(file)); + if (Files.isDirectory(file)) { + Set> fromSubDir = collectNameAndHash(file).entrySet(); + for (Map.Entry e : fromSubDir) { + nameToHash.put(Paths.get(name, e.getKey()).toString(), e.getValue()); + } + } + } + } + return nameToHash; + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java index 2e8f8bd..a8aa6f8 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java @@ -15,6 +15,7 @@ public interface Cryptographer { String tab = "\t"; String marker(); + InputStream formContent(Path file) throws IOException; default BlobType readMarker(String infoString) { @@ -36,12 +37,12 @@ default String withoutMarker(String infoString) { default String getHash(Path file) throws IOException { InputStream fileContent = formContent(file); - String filePath = file.toAbsolutePath().normalize().toString(); + String filePath = file.toFile().getName(); fileContent = new SequenceInputStream( fileContent, IOUtils.toInputStream(filePath) ); - return DigestUtils.sha1Hex(fileContent); + return DigestUtils.sha1Hex(fileContent); } default InputStream encodeFile(Path file) throws IOException { diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitAssembly.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitAssembly.java new file mode 100644 index 0000000..25ddb14 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitAssembly.java @@ -0,0 +1,39 @@ +package ru.ifmo.git.entities; + +import java.nio.file.Path; +import java.nio.file.Paths; + +public class GitAssembly { + + private GitTree gitTree; + private GitClerk gitClerk; + private GitFileKeeper gitFileKeeper; + private GitCryptographer gitCrypto; + + public GitAssembly(Path cwd) { + gitTree = new GitTree(cwd); + gitClerk = new GitClerk(gitTree); + gitFileKeeper = new GitFileKeeper(gitTree); + gitCrypto = new GitCryptographer(gitTree); + } + + public GitClerk clerk() { + return gitClerk; + } + + public GitCryptographer crypto() { + return gitCrypto; + } + + public GitFileKeeper fileKeeper() { + return gitFileKeeper; + } + + public GitTree tree() { + return gitTree; + } + + public static Path cwd() { + return Paths.get(".").toAbsolutePath().normalize(); + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java index 907bc22..e57a633 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java @@ -8,14 +8,13 @@ import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.*; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.text.*; import java.util.*; public class GitClerk { - private final String ENCODING = "UTF-8"; - private final String sep = System.getProperty("line.separator"); + public static final String ENCODING = "UTF-8"; + public static final String sep = System.getProperty("line.separator"); private Gson gson = new GsonBuilder().create(); private final GitTree gitTree; @@ -118,10 +117,6 @@ public CommitInfo fillCommitInfo(String message) throws GitException { return info; } - public CommitInfo fillAddInfo() throws GitException { - return fillCommitInfo("add"); - } - public Map collectFilesInfo(Path encodedFile) throws IOException { Map nameToHash = new HashMap<>(); List lines = Files.readAllLines(encodedFile, StandardCharsets.UTF_8); diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java index f296c27..7ac2285 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java @@ -8,7 +8,6 @@ import java.nio.file.*; import java.util.*; - public class GitCryptographer { private final BlobType type = BlobType.COMMIT; @@ -25,7 +24,7 @@ private String marker() { } public String getHash(Path file) throws IOException { - if(file.toFile().isFile()) { + if (file.toFile().isFile()) { return fileCrypto.getHash(file); } return treeCrypto.getHash(file); @@ -34,14 +33,15 @@ public String getHash(Path file) throws IOException { public static String createHash() { return DigestUtils.sha1Hex(UUID.randomUUID().toString()); } + public static String createCommitHash(CommitInfo info) { String builder = info.time + info.rootDirectory + - info.author + info.branch; + info.author + info.branch; return DigestUtils.sha1Hex(builder); } private BlobType getMarker(Path file) { - if(Files.isDirectory(file)) { + if (Files.isDirectory(file)) { return BlobType.TREE; } return BlobType.FILE; @@ -61,13 +61,8 @@ public InputStream encodeFiles(List files) throws IOException { return IOUtils.toInputStream(builder.toString(), "UTF-8"); } -// private Path getTreePath(List lines) { -// String[] HashAndName = lines.get(1).split("\t"); -// return Paths.get(withoutMarker(HashAndName[0])); -// } - public List formDecodeReferences(Path commitFile) throws IOException { - return treeCrypto.decodeTree(commitFile, new GitFileKeeper(gitTree)); + return treeCrypto.decodeTree(commitFile, new GitFileKeeper(gitTree)); } public FileReference formHeaderReference(String hash, List files) throws IOException { @@ -82,8 +77,8 @@ public List formEncodeReferences(List files) throws GitExce List references = new ArrayList<>(); for (Path file : files) { try { - if(!Files.isHidden(file)) { - if(Files.isDirectory(file)) { + if (!Files.isHidden(file)) { + if (Files.isDirectory(file)) { references.addAll(treeCrypto.formEncodeReferences(file)); } else { references.add(fileCrypto.formEncodeReference(file)); diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java index f55ca51..cb247a6 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java @@ -19,13 +19,7 @@ public GitFileKeeper(GitTree gitTree) { storage = gitTree.storage(); } - public static Path withDir(Path file) { - String fileName = file.toFile().getName(); - return Paths.get(fileName.substring(0, dirNameLen), - fileName.substring(dirNameLen)).toAbsolutePath(); - } - - public Path getDir(String blob) { + private Path getDir(String blob) { return storage.resolve(blob.substring(0, dirNameLen)); } @@ -35,7 +29,7 @@ public Path correctPath(String blob) { private Path filePath(String blob) throws IOException { Path directory = getDir(blob); - if(Files.notExists(directory)) { + if (Files.notExists(directory)) { boolean ignored = directory.toFile().mkdirs(); } return directory.resolve(blob.substring(dirNameLen)); @@ -44,21 +38,16 @@ private Path filePath(String blob) throws IOException { public void saveCommit(List references) throws IOException { for (FileReference reference : references) { Path file = filePath(reference.name); - Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); - } - } - - public void saveToIndex(List references) throws IOException { - for (FileReference reference : references) { - Path file = gitTree.index().resolve(reference.name); - Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); + if(Files.notExists(file)) { + Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); + } } } public Optional findFileInStorage(String hash) throws IOException { List blobs = Files.list(getDir(hash)).collect(Collectors.toList()); - for (Path blob: blobs) { - if(blob.getFileName().startsWith(hash.substring(dirNameLen))) { + for (Path blob : blobs) { + if (blob.toFile().getName().startsWith(hash.substring(dirNameLen))) { return Optional.of(blob); } } @@ -68,7 +57,7 @@ public Optional findFileInStorage(String hash) throws IOException { public void restoreCommit(List references, Path destination) throws IOException { for (FileReference reference : references) { Path file = destination.resolve(reference.name); - if(reference.type.equals(BlobType.FILE)) { + if (reference.type.equals(BlobType.FILE)) { Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); } else { boolean ignored = file.toFile().mkdirs(); @@ -103,19 +92,20 @@ static public void clearDirectory(Path directory) throws GitException { List files = Files.list(directory).collect(Collectors.toList()); removeAll(files); } catch (IOException e) { - e.printStackTrace(); throw new GitException("error while removing"); } } static public void removeAll(List files) throws GitException { - try{ + try { for (Path file : files) { - if(Files.isRegularFile(file)) { - deleteFile(file); - } else { - clearDirectory(file); - Files.deleteIfExists(file); + if (!Files.isHidden(file) && !Files.isExecutable(file)) { + if (Files.isRegularFile(file)) { + deleteFile(file); + } else { + clearDirectory(file); + Files.deleteIfExists(file); + } } } } catch (IOException e) { diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java index 8aa10e8..b648b88 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java @@ -26,7 +26,7 @@ private void createGitParser() { .setDefault("cmd", new Init()) .help("Create an empty Git repository or reinitialize an existing one"); parserInit.addArgument("") - .type(Path.class).nargs("?").setDefault(GitTree.cwd()); + .type(Path.class).nargs("?").setDefault(GitAssembly.cwd()); Subparser parserAdd = subparsers.addParser("add") .setDefault("cmd", new Add()) @@ -40,22 +40,20 @@ private void createGitParser() { parserRemove.addArgument("").type(String.class) .required(true).nargs("+"); -// Subparser parserStatus = subparsers.addParser("status") -// .setDefault("cmd", new Status()) -// .help("Show current state of the repository"); + Subparser parserStatus = subparsers.addParser("status") + .setDefault("cmd", new Status()) + .help("Show current state of the repository"); Subparser parserCommit = subparsers.addParser("commit") .setDefault("cmd", new Commit()) .help("Record changes to the repository"); - parserCommit.addArgument("-m", "--message").nargs(1).type(String.class); - parserCommit.addArgument("").type(String.class).nargs("+"); - -// Subparser parserReset = subparsers.addParser("reset") -// .setDefault("cmd", new Reset()) -// .help("Reset current HEAD to the specified state"); -// parserReset.addArgument("").type(String.class) -// .required(true); -// + parserCommit.addArgument("-m", "--message").nargs("?").type(String.class); + + Subparser parserReset = subparsers.addParser("reset") + .setDefault("cmd", new Reset()) + .help("Reset current HEAD to the specified state"); + parserReset.addArgument("").nargs("?").type(String.class); + Subparser parserLog = subparsers.addParser("log") .setDefault("cmd", new Log()) .help("Show commit logs"); @@ -64,7 +62,7 @@ private void createGitParser() { Subparser parserCheckout = subparsers.addParser("checkout") .setDefault("cmd", new Checkout()) .help("Switch branches or restore working tree files"); - parserCheckout.addArgument("").nargs(1).type(String.class); + parserCheckout.addArgument("").nargs("?").type(String.class); } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java index 27277ef..4b4fe37 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java @@ -13,7 +13,7 @@ public class GitTree { private Path headFile; public GitTree() { - setRepository(cwd()); + setRepository(GitAssembly.cwd()); } public GitTree(Path repository) { @@ -64,8 +64,4 @@ public Path git() { public boolean exists() { return Files.exists(gitDir); } - - public static Path cwd() { - return Paths.get(".").toAbsolutePath().normalize(); - } } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/BlobType.java b/task1_git/src/main/java/ru/ifmo/git/util/BlobType.java index c2ad255..3b5f548 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/BlobType.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/BlobType.java @@ -13,9 +13,12 @@ static public BlobType typeOf(String mark) { public String asString() { switch (this) { - case FILE: return "fl\\"; - case TREE: return "tr\\"; - case COMMIT: return "cm\\"; + case FILE: + return "fl\\"; + case TREE: + return "tr\\"; + case COMMIT: + return "cm\\"; } return ""; } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/FileReference.java b/task1_git/src/main/java/ru/ifmo/git/util/FileReference.java index 36acf1c..b125cfa 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/FileReference.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/FileReference.java @@ -1,10 +1,6 @@ package ru.ifmo.git.util; -import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.nio.file.Path; -import java.util.List; -import java.util.stream.Stream; public class FileReference { diff --git a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java index 3f061e8..d4fc9bc 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java @@ -9,12 +9,6 @@ public class HeadInfo { public HeadInfo() { } - public HeadInfo(String branch) { - branchName = branch; - headHash = ""; - currentHash = ""; - } - public void moveHead(String hash) { headHash = hash; } @@ -27,5 +21,4 @@ public void moveBoth(String hash) { moveHead(hash); moveCurrent(hash); } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/util/ListOfFiles.java b/task1_git/src/main/java/ru/ifmo/git/util/ListOfFiles.java deleted file mode 100644 index 224d3fc..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/util/ListOfFiles.java +++ /dev/null @@ -1,22 +0,0 @@ -package ru.ifmo.git.util; - -import javafx.util.Pair; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ListOfFiles { - public Map namesToHashes; - - public void init() { - namesToHashes = new HashMap<>(); - } - - public void addInfo(String name , String hash) { - namesToHashes.put(name, hash); - } -} - - From d91bc8cf03bbaeb9aa43bee448e679b87f7c29da Mon Sep 17 00:00:00 2001 From: lergor Date: Mon, 15 Oct 2018 01:37:20 +0300 Subject: [PATCH 10/14] checkout --, fix bug with file references, use picocli --- task1_git/build.gradle | 1 + task1_git/src/main/java/ru/ifmo/git/Git.java | 25 --- task1_git/src/main/java/ru/ifmo/git/LGit.java | 49 +++++ .../main/java/ru/ifmo/git/commands/Add.java | 63 ++---- .../java/ru/ifmo/git/commands/Checkout.java | 76 +++---- .../java/ru/ifmo/git/commands/Commit.java | 65 ++---- .../main/java/ru/ifmo/git/commands/Git.java | 25 +++ .../java/ru/ifmo/git/commands/GitCommand.java | 37 ++-- .../main/java/ru/ifmo/git/commands/Init.java | 57 +++-- .../main/java/ru/ifmo/git/commands/Log.java | 83 ++----- .../java/ru/ifmo/git/commands/Remove.java | 40 ++-- .../main/java/ru/ifmo/git/commands/Reset.java | 75 ++----- .../java/ru/ifmo/git/commands/Status.java | 86 +------- .../ru/ifmo/git/entities/Cryptographer.java | 73 ------ .../ifmo/git/entities/FileCryptographer.java | 22 -- .../ru/ifmo/git/entities/GitAssembly.java | 39 ---- .../java/ru/ifmo/git/entities/GitClerk.java | 74 ++++++- .../ifmo/git/entities/GitCryptographer.java | 94 -------- .../java/ru/ifmo/git/entities/GitDecoder.java | 73 ++++++ .../java/ru/ifmo/git/entities/GitEncoder.java | 166 ++++++++++++++ .../ru/ifmo/git/entities/GitFileKeeper.java | 31 ++- .../java/ru/ifmo/git/entities/GitManager.java | 208 ++++++++++++++++++ .../java/ru/ifmo/git/entities/GitParser.java | 77 ------- .../java/ru/ifmo/git/entities/GitTree.java | 30 ++- .../ru/ifmo/git/entities/StorageMaster.java | 61 ----- .../ifmo/git/entities/TreeCryptographer.java | 88 -------- .../ru/ifmo/git/executors/GitExecutor.java | 9 + .../ru/ifmo/git/executors/InitExecutor.java | 33 +++ .../java/ru/ifmo/git/util/CommitInfo.java | 1 - .../main/java/ru/ifmo/git/util/HeadInfo.java | 1 + 30 files changed, 841 insertions(+), 921 deletions(-) delete mode 100644 task1_git/src/main/java/ru/ifmo/git/Git.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/LGit.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/commands/Git.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/FileCryptographer.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitAssembly.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/StorageMaster.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/entities/TreeCryptographer.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/executors/GitExecutor.java create mode 100644 task1_git/src/main/java/ru/ifmo/git/executors/InitExecutor.java diff --git a/task1_git/build.gradle b/task1_git/build.gradle index 885b2b5..37a4453 100644 --- a/task1_git/build.gradle +++ b/task1_git/build.gradle @@ -18,5 +18,6 @@ dependencies { compile group: 'org.apache.commons', name: 'commons-io', version: '1.3.2' implementation 'com.google.code.gson:gson:2.8.5' compile group: 'commons-codec', name: 'commons-codec', version: '1.11' + compile group: 'info.picocli', name: 'picocli', version: '3.6.0' } diff --git a/task1_git/src/main/java/ru/ifmo/git/Git.java b/task1_git/src/main/java/ru/ifmo/git/Git.java deleted file mode 100644 index 49ebc3a..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/Git.java +++ /dev/null @@ -1,25 +0,0 @@ -package ru.ifmo.git; - -import net.sourceforge.argparse4j.inf.*; -import ru.ifmo.git.commands.*; -import ru.ifmo.git.entities.GitParser; -import ru.ifmo.git.util.*; - - -public class Git { - - public static void main(String[] args) { - GitParser gitParser = new GitParser(); - try { - Namespace ns = gitParser.parseArgs(args); - GitCommand command = (GitCommand) ns.getAttrs().remove("cmd"); - CommandResult result = command.execute(ns.getAttrs()); - if(result.getStatus() != ExitStatus.SUCCESS) { - System.out.println("exit with code " + result.getStatus()); - } - System.out.println(result.getMessage().read()); - } catch (ArgumentParserException e) { - gitParser.handleError(e); - } - } -} diff --git a/task1_git/src/main/java/ru/ifmo/git/LGit.java b/task1_git/src/main/java/ru/ifmo/git/LGit.java new file mode 100644 index 0000000..d0fcd3b --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/LGit.java @@ -0,0 +1,49 @@ +package ru.ifmo.git; + +import picocli.CommandLine; +//import ru.ifmo.git.entities.GitParser; +import ru.ifmo.git.commands.Git; +//import ru.ifmo.git.commands1.Init; +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.util.*; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +public class LGit { + + private static Path cwd() { + // System.out.println(System.getProperty("user.dir")); + return Paths.get("/home/valeriya/Desktop/AU/III/JAVA_II/task1_git/kek"); + } + + public static void main(String[] args) { + Path repo = Paths.get("/home/valeriya/Desktop/AU/III/JAVA_II/task1_git/kek"); + args = new String[]{"add", + repo.resolve("lol").toString()}; + +// args = new String[]{"checkout", "780228fc7a09bf494f5922c6e310cf36244317c9"}; +// args = new String[]{"checkout", "-r", repo.resolve("lol").toString()}; + args = new String[]{"-h"}; + CommandLine commandLine = new CommandLine(new Git()); + try { + List parsed = commandLine.parse(args); + + // TODO git help + + if (parsed.size() == 2) { + GitManager manager = new GitManager(cwd()); + CommandResult result = manager.executeCommand(parsed.get(1)); + if (result.getStatus() != ExitStatus.SUCCESS) { + System.out.println("Exit with code " + result.getStatus()); + } + System.out.println(result.getMessage().read()); + } else { + commandLine.usage(System.out); + } + } catch (CommandLine.UnmatchedArgumentException e) { + System.out.println("l_git: no such command. See 'l_git --help'."); + } + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java index 2e8fee2..2288bb8 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java @@ -1,54 +1,33 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.entities.*; -import ru.ifmo.git.util.*; - -import java.io.IOException; -import java.nio.file.*; -import java.util.*; -import java.util.stream.Collectors; - +import picocli.CommandLine.Command; +import picocli.CommandLine.Parameters; + +import java.nio.file.Path; +import java.util.List; + +import ru.ifmo.git.entities.GitFileKeeper; +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.GitException; + +@Command( + name = "add", + description = "Add file contents to the index", + helpCommand = true +) public class Add implements GitCommand { + @Parameters(arity = "*", paramLabel = "") private List files; - private GitAssembly git; - - public Add() { - git = new GitAssembly(GitAssembly.cwd()); - } - - public Add(Path cwd) { - git = new GitAssembly(cwd); - } - - private List getArgs(Map args) { - return ((List) args.get("")) - .stream() - .map(s -> Paths.get(s).normalize()) - .collect(Collectors.toList()); - } @Override - public boolean correctArgs(Map args) throws GitException { - if (!args.isEmpty()) { - List files = getArgs(args); - checkFilesExist(files); - this.files = files; - return true; - } - return false; + public boolean incorrectArgs() { + return !GitFileKeeper.checkFilesExist(files, true); } @Override - public CommandResult doWork(Map args) throws GitException { - if (!git.tree().exists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); - } - try { - GitFileKeeper.copyAll(files, git.tree().index()); - } catch (IOException e) { - throw new GitException(e.getMessage()); - } - return new CommandResult(ExitStatus.SUCCESS, "add: done!"); + public CommandResult doWork(GitManager gitManager) throws GitException { + return gitManager.add(files); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java index b4b93bc..9329916 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java @@ -1,63 +1,47 @@ package ru.ifmo.git.commands; +import picocli.CommandLine.Option; +import picocli.CommandLine.Parameters; +import picocli.CommandLine.Command; import ru.ifmo.git.entities.*; import ru.ifmo.git.util.*; -import java.io.IOException; import java.nio.file.Path; -import java.util.*; +import java.util.List; +@Command( + name = "checkout", + description = "Switch branches or restore working tree files", + helpCommand = true +) public class Checkout implements GitCommand { - private Path commitFile; - private GitAssembly git; - - public Checkout() { - git = new GitAssembly(GitAssembly.cwd()); - } - - public Checkout(Path cwd) { - git = new GitAssembly(cwd); - } + @Parameters( + arity = "?", + paramLabel = "" + ) + private String revision; + + @Option( + names = {"--", "-r"}, + arity = "*", + paramLabel = "", + description = "Discard changes in working directory in the given files.", + type = Path.class + ) + private List files; @Override - public boolean correctArgs(Map args) throws GitException { - String commitHash = (String) args.get(""); - if (commitHash.length() > 6) { - try { - Optional commit = git.fileKeeper().findFileInStorage(commitHash); - if (commit.isPresent()) { - commitFile = commit.get(); - return true; - } - } catch (IOException e) { - e.printStackTrace(); - throw new GitException(e.getMessage()); - } - } - return false; + public boolean incorrectArgs() { + return (revision == null || revision.length() < 6) && (files.isEmpty()); } @Override - public CommandResult doWork(Map args) throws GitException { - if (!git.tree().exists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); + public CommandResult doWork(GitManager gitManager) throws GitException { + if(revision != null) { + return gitManager.checkout(revision); + } else { + return gitManager.checkout(files); } - try { - List references = git.crypto().formDecodeReferences(commitFile); - GitFileKeeper.clearDirectory(git.tree().repo()); - git.fileKeeper().restoreCommit(references, git.tree().repo()); - changeHeadInfo(); - } catch (IOException e) { - throw new GitException(e.getMessage()); - } - return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); - - } - - private void changeHeadInfo() throws GitException { - HeadInfo headInfo = git.clerk().getHeadInfo(); - headInfo.moveCurrent(commitFile.getParent().toFile().getName() + commitFile.toFile().getName()); - git.clerk().changeHeadInfo(headInfo); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index ff19dfe..7c5d77b 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -1,59 +1,28 @@ package ru.ifmo.git.commands; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; + import ru.ifmo.git.entities.*; import ru.ifmo.git.util.*; -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.stream.Collectors; - +@Command( + name = "commit", + description = "Record changes to the repository", + helpCommand = true +) public class Commit implements GitCommand { - private CommitInfo commitInfo; - private GitAssembly git; - - public Commit() { - git = new GitAssembly(GitAssembly.cwd()); - } - - public Commit(Path cwd) { - git = new GitAssembly(cwd); - } + @Option( + names = {"-m", "--message"}, + arity = "?", + paramLabel = "", + description = "Use the given as the commit message." + ) + private String message; @Override - public boolean correctArgs(Map args) { - return true; - } - - @Override - public CommandResult doWork(Map args) { - if (!git.tree().exists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); - } - try { - List files = Files.list(git.tree().index()).collect(Collectors.toList()); - commitInfo = git.clerk().fillCommitInfo((String) args.getOrDefault("message", "")); - List references = git.crypto().formEncodeReferences(files); - FileReference commitReference = git.crypto().formHeaderReference(commitInfo.hash, files); - references.add(commitReference); - git.fileKeeper().saveCommit(references); - git.clerk().writeLog(commitInfo); - changeHeadInfo(); - } catch (IOException | GitException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); - } - return new CommandResult(ExitStatus.SUCCESS, "commit: done!"); - } - - private void changeHeadInfo() throws GitException { - HeadInfo headInfo = git.clerk().getHeadInfo(); - if (headInfo.headHash == null || headInfo.headHash.equals(headInfo.currentHash)) { - headInfo.moveBoth(commitInfo.hash); - } else { - headInfo.moveCurrent(commitInfo.hash); - } - git.clerk().changeHeadInfo(headInfo); + public CommandResult doWork(GitManager gitManager) throws GitException { + return gitManager.commit(message); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Git.java b/task1_git/src/main/java/ru/ifmo/git/commands/Git.java new file mode 100644 index 0000000..6732003 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Git.java @@ -0,0 +1,25 @@ +package ru.ifmo.git.commands; + +import picocli.CommandLine; + +@CommandLine.Command( + name = "l_git", + subcommands = { + Init.class, + Add.class, + Remove.class, + Status.class, + Commit.class, + Reset.class, + Log.class, + Checkout.class + }, + description = "A version control system created by lergor." +) +public class Git { + @CommandLine.Option( + names = {"-h", "--help"}, + help = true, + description = "Prints the synopsis and a list of the most commonly used commands.") + boolean isHelpRequested; +} diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java index 7e5b46b..14758e4 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java @@ -1,36 +1,37 @@ package ru.ifmo.git.commands; +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.entities.GitTree; import ru.ifmo.git.util.*; +import java.io.IOException; import java.nio.file.*; import java.util.*; public interface GitCommand { - boolean correctArgs(Map args) throws GitException; + default boolean incorrectArgs() { + return false; + } + + default boolean gitNotInited(GitTree tree) { + return !tree.exists(); + } - CommandResult doWork(Map args) throws GitException; + CommandResult doWork(GitManager gitManager) throws GitException; - default CommandResult execute(Map args) { + default CommandResult execute(GitManager gitManager) { String name = this.getClass().getSimpleName().toLowerCase(); + if(gitNotInited(gitManager.tree())) { + return new CommandResult(ExitStatus.ERROR, "fatal: Not a l_git repository"); + } + if(incorrectArgs()) { + return new CommandResult(ExitStatus.ERROR, name + ": incorrect arguments"); + } try { - if (correctArgs(args)) { - return doWork(args); - } + return doWork(gitManager); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, name + ": " + e.getMessage()); } - return new CommandResult(ExitStatus.ERROR, name + ": wrong args"); - } - - default void checkFilesExist(List files) throws GitException { - for (Path file : files) { - if (!Files.exists(file)) { - String message = "fatal: pathspec " + file.getFileName() + " did not match any files"; - throw new GitException(message); - } - } - } - } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java index 6e15221..52b334f 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java @@ -1,45 +1,40 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.entities.*; -import ru.ifmo.git.util.*; +import picocli.CommandLine.Command; +import picocli.CommandLine.Parameters; + +import java.nio.file.Path; +import java.nio.file.Paths; -import java.io.IOException; -import java.nio.file.*; -import java.util.Map; +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.entities.GitTree; +import ru.ifmo.git.util.*; +@Command( + name = "init", + description = "Create an empty Git repository or reinitialize an existing one", + helpCommand = true +) public class Init implements GitCommand { - private GitAssembly git; + @Parameters(arity = "?", paramLabel = "directory") + private Path repositoryDirectory; - @Override - public boolean correctArgs(Map args) { - return args.size() == 1 && Files.exists((Path) args.get("")); + private Path repositoryDirectory() { + if (repositoryDirectory == null) { + return Paths.get(System.getProperty("user.dir")).normalize().toAbsolutePath(); + } + return repositoryDirectory; } @Override - public CommandResult doWork(Map args) throws GitException { - git = new GitAssembly((Path) args.get("")); - Message message = new Message(); - if (!git.tree().exists()) { - try { - git.tree().createGitTree(); - message.write("initialized empty "); - writeHead(); - } catch (IOException e) { - String msg = "unable to create repository in " + git.tree().repo(); - return new CommandResult(ExitStatus.FAILURE, msg); - } - } else { - message.write("reinitialized existing "); - } - message.write("Git repository in " + git.tree().repo()); - return new CommandResult(ExitStatus.SUCCESS, message); + public boolean gitNotInited(GitTree tree) { + return false; } - private void writeHead() throws GitException { - HeadInfo info = new HeadInfo(); - info.branchName = "master"; - GitClerk clerk = new GitClerk(git.tree()); - clerk.changeHeadInfo(info); + @Override + public CommandResult doWork(GitManager gitManager) throws GitException { + return new GitManager(repositoryDirectory()).init(); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index 1f35a8f..f2d92b6 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -1,73 +1,32 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.entities.*; -import ru.ifmo.git.util.*; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.function.Predicate; - +import picocli.CommandLine.Command; +import picocli.CommandLine.Parameters; +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.GitException; + +@Command( + name = "log", + description = "Show commit logs", + helpCommand = true +) public class Log implements GitCommand { - private String commit; - private GitAssembly git; - - public Log() { - git = new GitAssembly(GitAssembly.cwd()); - } - - public Log(Path cwd) { - git = new GitAssembly(cwd); - } + @Parameters( + arity = "?", + paramLabel = "", + description = "Show only commits since specified ." + ) + private String revision; @Override - public boolean correctArgs(Map args) { - commit = (String) args.get(""); - return commit == null || commit.length() > 6; + public boolean incorrectArgs() { + return (revision == null || revision.length() < 6); } @Override - public CommandResult doWork(Map args) throws GitException { - if (!git.tree().exists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); - } - return readLog(commit); - } - - - private CommandResult readLog(String revision) throws GitException { - if (Files.exists(git.tree().log())) { - Message logContent = new Message(); - List history; - try { - history = git.clerk().getLogHistory(); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); - } - if (history.size() == 0) { - return emptyLogResult(); - } - history.stream().filter( - new Predicate() { - - private boolean include = (revision == null || revision.isEmpty()); - - @Override - public boolean test(CommitInfo commitInfo) { - include = include || commitInfo.hash.startsWith(revision); - return include; - } - } - ).forEach(info -> logContent.write(info.toString())); - return new CommandResult(ExitStatus.SUCCESS, logContent); - } - return emptyLogResult(); - } - - private CommandResult emptyLogResult() throws GitException { - HeadInfo headInfo = git.clerk().getHeadInfo(); - String failMessage = "fatal: your current branch '" + headInfo.branchName + "' does not have any commits yet\n"; - return new CommandResult(ExitStatus.FAILURE, failMessage); + public CommandResult doWork(GitManager gitManager) throws GitException { + return gitManager.log(revision); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java index 4ea3491..7825b96 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java @@ -1,44 +1,30 @@ package ru.ifmo.git.commands; +import picocli.CommandLine.Command; +import picocli.CommandLine.Parameters; import ru.ifmo.git.entities.*; import ru.ifmo.git.util.*; import java.nio.file.Path; import java.util.*; -import java.util.stream.Collectors; +@Command( + name = "rm", + description = "Remove files from the working tree and from the index", + helpCommand = true +) public class Remove implements GitCommand { - private List files; - private GitAssembly git; - - public Remove() { - git = new GitAssembly(GitAssembly.cwd()); - } - - public Remove(Path cwd) { - git = new GitAssembly(cwd); - } + @Parameters(arity = "*", paramLabel = "") + private List files; @Override - public boolean correctArgs(Map args) { - files = ((List) args.get("")); - return !files.isEmpty(); + public boolean incorrectArgs() { + return files.isEmpty(); } @Override - public CommandResult doWork(Map args) { - if (!git.tree().exists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); - } - try { - List filesInIndex = files.stream().map(git.tree().index()::resolve).collect(Collectors.toList()); - List filesInCWD = files.stream().map(git.tree().repo()::resolve).collect(Collectors.toList()); - GitFileKeeper.removeAll(filesInIndex); - GitFileKeeper.removeAll(filesInCWD); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, "remove: " + e.getMessage()); - } - return new CommandResult(ExitStatus.SUCCESS, "remove: done!"); + public CommandResult doWork(GitManager gitManager) { + return gitManager.remove(files); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java index 09693be..9e8ac15 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java @@ -1,68 +1,29 @@ package ru.ifmo.git.commands; -import ru.ifmo.git.entities.*; -import ru.ifmo.git.util.*; - -import java.io.*; -import java.nio.file.Path; -import java.util.*; - +import picocli.CommandLine.Command; +import picocli.CommandLine.Parameters; + +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.GitException; + +@Command( + name = "reset", + description = "Reset current HEAD to the specified state", + helpCommand = true +) public class Reset implements GitCommand { - private Path commitFile; - private GitAssembly git; - - public Reset() { - git = new GitAssembly(GitAssembly.cwd()); - } - - public Reset(Path cwd) { - git = new GitAssembly(cwd); - } + @Parameters(arity = "1", paramLabel = "") + private String revision; @Override - public boolean correctArgs(Map args) throws GitException { - String commitHash = (String) args.get(""); - if (commitHash.length() > 6) { - try { - Optional commit = git.fileKeeper().findFileInStorage(commitHash); - if (commit.isPresent()) { - commitFile = commit.get(); - return true; - } - } catch (IOException e) { - e.printStackTrace(); - throw new GitException(e.getMessage()); - } - } - return false; + public boolean incorrectArgs() { + return (revision.length() < 6); } @Override - public CommandResult doWork(Map args) throws GitException { - if (!git.tree().exists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); - } - try { - List references = git.crypto().formDecodeReferences(commitFile); - GitFileKeeper.clearDirectory(git.tree().index()); - git.fileKeeper().restoreCommit(references, git.tree().index()); - changeHeadInfo(); - } catch (IOException | GitException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); - } - return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); - - } - - private void changeHeadInfo() throws GitException { - HeadInfo headInfo = git.clerk().getHeadInfo(); - String hash = commitFile.getParent().toFile().getName() + commitFile.toFile().getName(); - if (!headInfo.currentHash.equals(hash)) { - headInfo.moveCurrent(hash); - git.clerk().changeHeadInfo(headInfo); - } else { - throw new GitException("reset: already on commit " + hash); - } + public CommandResult doWork(GitManager gitManager) throws GitException { + return gitManager.reset(revision); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java index 0176ab6..55fafea 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java @@ -1,88 +1,18 @@ package ru.ifmo.git.commands; +import picocli.CommandLine.Command; import ru.ifmo.git.entities.*; import ru.ifmo.git.util.*; -import java.io.IOException; -import java.nio.file.*; -import java.util.*; -import java.util.stream.Collectors; - +@Command( + name = "status", + description = "Show current state of the repository", + helpCommand = true +) public class Status implements GitCommand { - private GitAssembly git; - - public Status() { - git = new GitAssembly(GitAssembly.cwd()); - } - - public Status(Path cwd) { - git = new GitAssembly(cwd); - } - @Override - public boolean correctArgs(Map args) { - return args.isEmpty(); - } - - @Override - public CommandResult doWork(Map args) throws GitException { - if (!git.tree().exists()) { - return new CommandResult(ExitStatus.ERROR, "fatal: not a m_git repository"); - } - try { - HeadInfo headInfo = git.clerk().getHeadInfo(); - Message info = new Message(); - info.write("On branch " + headInfo.branchName + GitClerk.sep); - String changedFiles = getChangedFiles(); - if(changedFiles.isEmpty()) { - info.write("No changed files"); - } else { - info.write("Changed files:"); - info.write(changedFiles); - } - return new CommandResult(ExitStatus.SUCCESS, info); - } catch (IOException e) { - return new CommandResult(ExitStatus.ERROR, e.getMessage()); - } - } - - private String getChangedFiles() throws IOException { - StringBuilder builder = new StringBuilder(); - Map inIndex = collectNameAndHash(git.tree().index()); - for (Map.Entry e : inIndex.entrySet()) { - Path fileInCWD = git.tree().repo().resolve(e.getKey()); - Path fileInIndex = git.tree().index().resolve(e.getKey()); - if (Files.isRegularFile(fileInIndex)) { - if (Files.notExists(fileInCWD)) { - builder.append(GitClerk.sep).append(e.getKey()); - } else { - String hashInIndex = e.getValue(); - String hashInCWD = git.crypto().getHash(fileInCWD); - if (!hashInCWD.equals(hashInIndex)) { - builder.append(GitClerk.sep).append(e.getKey()); - } - } - } - } - return builder.toString(); - } - - private Map collectNameAndHash(Path directory) throws IOException { - List files = Files.list(directory).collect(Collectors.toList()); - Map nameToHash = new HashMap<>(); - for (Path file : files) { - String name = file.toFile().getName(); - if (!Files.isHidden(file)) { - nameToHash.put(name, git.crypto().getHash(file)); - if (Files.isDirectory(file)) { - Set> fromSubDir = collectNameAndHash(file).entrySet(); - for (Map.Entry e : fromSubDir) { - nameToHash.put(Paths.get(name, e.getKey()).toString(), e.getValue()); - } - } - } - } - return nameToHash; + public CommandResult doWork(GitManager gitManager) throws GitException { + return gitManager.status(); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java deleted file mode 100644 index a8aa6f8..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/entities/Cryptographer.java +++ /dev/null @@ -1,73 +0,0 @@ -package ru.ifmo.git.entities; - -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.IOUtils; -import ru.ifmo.git.util.*; - -import java.io.*; -import java.nio.file.*; - -public interface Cryptographer { - - String ENCODING = "UTF-8"; - int markLength = BlobType.size(); - String sep = System.getProperty("line.separator"); - String tab = "\t"; - - String marker(); - - InputStream formContent(Path file) throws IOException; - - default BlobType readMarker(String infoString) { - return BlobType.typeOf(infoString.substring(0, BlobType.size())); - } - - default String removeMarker(String string) { - return string.substring(BlobType.size()); - } - - default InputStream formHeader(Path file) throws IOException { - String info = marker() + file.toFile().getName() + sep; - return IOUtils.toInputStream(info, ENCODING); - } - - default String withoutMarker(String infoString) { - return infoString.substring(markLength); - } - - default String getHash(Path file) throws IOException { - InputStream fileContent = formContent(file); - String filePath = file.toFile().getName(); - fileContent = new SequenceInputStream( - fileContent, - IOUtils.toInputStream(filePath) - ); - return DigestUtils.sha1Hex(fileContent); - } - - default InputStream encodeFile(Path file) throws IOException { - return new SequenceInputStream( - formHeader(file), - formContent(file) - ); - } - - default FileReference decodeFile(Path file) throws IOException { - FileReference reference = new FileReference(); - BufferedReader reader = Files.newBufferedReader(file); - String infoLine = reader.readLine(); - reference.type = readMarker(infoLine); - reference.name = withoutMarker(infoLine); - reference.content = IOUtils.toInputStream(IOUtils.toString(reader)); - return reference; - } - - default FileReference formEncodeReference(Path file) throws IOException { - FileReference reference = new FileReference(); - reference.type = BlobType.typeOf(marker()); - reference.name = getHash(file); - reference.content = encodeFile(file); - return reference; - } - -} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/FileCryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/FileCryptographer.java deleted file mode 100644 index e9632cd..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/entities/FileCryptographer.java +++ /dev/null @@ -1,22 +0,0 @@ -package ru.ifmo.git.entities; - -import ru.ifmo.git.util.BlobType; - -import java.io.*; -import java.nio.file.*; - -class FileCryptographer implements Cryptographer { - - private static final BlobType type = BlobType.FILE; - - @Override - public String marker() { - return type.asString(); - } - - @Override - public InputStream formContent(Path file) throws IOException { - return Files.newInputStream(file); - } - -} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitAssembly.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitAssembly.java deleted file mode 100644 index 25ddb14..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitAssembly.java +++ /dev/null @@ -1,39 +0,0 @@ -package ru.ifmo.git.entities; - -import java.nio.file.Path; -import java.nio.file.Paths; - -public class GitAssembly { - - private GitTree gitTree; - private GitClerk gitClerk; - private GitFileKeeper gitFileKeeper; - private GitCryptographer gitCrypto; - - public GitAssembly(Path cwd) { - gitTree = new GitTree(cwd); - gitClerk = new GitClerk(gitTree); - gitFileKeeper = new GitFileKeeper(gitTree); - gitCrypto = new GitCryptographer(gitTree); - } - - public GitClerk clerk() { - return gitClerk; - } - - public GitCryptographer crypto() { - return gitCrypto; - } - - public GitFileKeeper fileKeeper() { - return gitFileKeeper; - } - - public GitTree tree() { - return gitTree; - } - - public static Path cwd() { - return Paths.get(".").toAbsolutePath().normalize(); - } -} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java index e57a633..e441ef1 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java @@ -3,6 +3,7 @@ import com.google.gson.*; import org.apache.commons.io.*; +import ru.ifmo.git.commands.Git; import ru.ifmo.git.util.*; import java.io.*; @@ -10,6 +11,7 @@ import java.nio.file.*; import java.text.*; import java.util.*; +import java.util.stream.Collectors; public class GitClerk { @@ -33,7 +35,7 @@ public HeadInfo getHeadInfo() throws GitException { return gson.fromJson(headJson, HeadInfo.class); } - public void changeHeadInfo(HeadInfo newHeadInfo) throws GitException { + void writeHeadInfo(HeadInfo newHeadInfo) throws GitException { String newInfo = gson.toJson(newHeadInfo); try { FileUtils.writeStringToFile(gitTree.head().toFile(), newInfo, ENCODING); @@ -42,6 +44,15 @@ public void changeHeadInfo(HeadInfo newHeadInfo) throws GitException { } } + void changeHeadInfo(String hash) throws GitException { + HeadInfo headInfo = getHeadInfo(); + if (headInfo.headHash == null || headInfo.headHash.equals(headInfo.currentHash)) { + headInfo.moveBoth(hash); + } else { + headInfo.moveCurrent(hash); + } + writeHeadInfo(headInfo); + } public void writeLog(CommitInfo commit) throws GitException { File logFile = gitTree.log().resolve(commit.branch).toFile(); @@ -82,6 +93,7 @@ public List getLogHistory() throws GitException { } catch (IOException e) { throw new GitException("error while reading log for " + branch); } + Collections.reverse(history); return history; } @@ -98,8 +110,6 @@ public static String getAuthor() { return System.getProperty("user.name"); } - - private static String getCurrentTime() { DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy ZZ"); return df.format(Calendar.getInstance().getTime()); @@ -112,7 +122,7 @@ public CommitInfo fillCommitInfo(String message) throws GitException { info.setTime(getCurrentTime()); info.setRootDirectory(gitTree.repo()); info.setMessage(message == null ? getUserMessage() : message); - info.setHash(GitCryptographer.createCommitHash(info)); + info.setHash(GitEncoder.createCommitHash(info)); info.setBranch(getHeadInfo().branchName); return info; } @@ -128,4 +138,60 @@ public Map collectFilesInfo(Path encodedFile) throws IOException return nameToHash; } + String emptyLogResult() throws GitException { + HeadInfo headInfo = getHeadInfo(); + return "fatal: your current branch '" + + headInfo.branchName + + "' does not have any commits yet\n"; + } + + public Map compareRepoAndIndex() throws GitException { + try { + Map fileToStatus = new HashMap<>(); + Map inIndex = collectNameAndHash(gitTree.index()); + for (Map.Entry e : inIndex.entrySet()) { + Path fileInCWD = gitTree.repo().resolve(e.getKey()); + Path fileInIndex = gitTree.index().resolve(e.getKey()); + if (Files.isRegularFile(fileInIndex)) { + if (!Files.exists(fileInCWD)) { + fileToStatus.put(e.getKey(), "deleted"); + } else { + String hashInIndex = e.getValue(); + String hashInCWD = GitEncoder.getHash(fileInCWD, gitTree.repo()); + if (!hashInCWD.equals(hashInIndex)) { + fileToStatus.put(e.getKey(), "modified"); + } + } + } + } + Files.list(gitTree.repo()).forEach(f -> { + String fileName = gitTree.repo().relativize(f).toString(); + if(!fileName.equals(".l_git") && !Files.exists(gitTree.index().resolve(fileName))) { + fileToStatus.put(fileName, "new"); + } + } + ); + return fileToStatus; + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + } + + private Map collectNameAndHash(Path directory) throws IOException { + Map nameToHash = new HashMap<>(); + List files = Files.list(directory).collect(Collectors.toList()); + for (Path file : files) { + String name = file.toFile().getName(); + if (!name.equals(".l_git")) { + nameToHash.put(name, GitEncoder.getHash(file, directory)); + if (Files.isDirectory(file)) { + Set> fromSubDir = collectNameAndHash(file).entrySet(); + for (Map.Entry e : fromSubDir) { + nameToHash.put(Paths.get(name, e.getKey()).toString(), e.getValue()); + } + } + } + } + return nameToHash; + } } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java deleted file mode 100644 index 7ac2285..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitCryptographer.java +++ /dev/null @@ -1,94 +0,0 @@ -package ru.ifmo.git.entities; - -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.io.IOUtils; -import ru.ifmo.git.util.*; - -import java.io.*; -import java.nio.file.*; -import java.util.*; - -public class GitCryptographer { - - private final BlobType type = BlobType.COMMIT; - private static final TreeCryptographer treeCrypto = new TreeCryptographer(); - private static final FileCryptographer fileCrypto = new FileCryptographer(); - private GitTree gitTree; - - public GitCryptographer(GitTree gitTree) { - this.gitTree = gitTree; - } - - private String marker() { - return type.asString(); - } - - public String getHash(Path file) throws IOException { - if (file.toFile().isFile()) { - return fileCrypto.getHash(file); - } - return treeCrypto.getHash(file); - } - - public static String createHash() { - return DigestUtils.sha1Hex(UUID.randomUUID().toString()); - } - - public static String createCommitHash(CommitInfo info) { - String builder = info.time + info.rootDirectory + - info.author + info.branch; - return DigestUtils.sha1Hex(builder); - } - - private BlobType getMarker(Path file) { - if (Files.isDirectory(file)) { - return BlobType.TREE; - } - return BlobType.FILE; - } - - public InputStream encodeFiles(List files) throws IOException { - String sep = System.getProperty("line.separator"); - StringBuilder builder = new StringBuilder(); - builder.append(marker()).append(sep); - for (Path file : files) { - builder.append(getMarker(file).asString()) - .append(getHash(file)) - .append("\t") - .append(file.getFileName()) - .append(sep); - } - return IOUtils.toInputStream(builder.toString(), "UTF-8"); - } - - public List formDecodeReferences(Path commitFile) throws IOException { - return treeCrypto.decodeTree(commitFile, new GitFileKeeper(gitTree)); - } - - public FileReference formHeaderReference(String hash, List files) throws IOException { - FileReference commit = new FileReference(); - commit.type = type; - commit.name = hash; - commit.content = encodeFiles(files); - return commit; - } - - public List formEncodeReferences(List files) throws GitException { - List references = new ArrayList<>(); - for (Path file : files) { - try { - if (!Files.isHidden(file)) { - if (Files.isDirectory(file)) { - references.addAll(treeCrypto.formEncodeReferences(file)); - } else { - references.add(fileCrypto.formEncodeReference(file)); - } - } - } catch (IOException e) { - throw new GitException(e.getMessage()); - } - } - return references; - } - -} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java new file mode 100644 index 0000000..c08eed1 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java @@ -0,0 +1,73 @@ +package ru.ifmo.git.entities; + +import org.apache.commons.io.IOUtils; +import ru.ifmo.git.util.BlobType; +import ru.ifmo.git.util.FileReference; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class GitDecoder { + + private static String ENCODING = "UTF-8"; + private static int markLength = BlobType.size(); + private static String sep = System.getProperty("line.separator"); + private static String tab = "\t"; + + + private static BlobType readMarker(String infoString) { + return BlobType.typeOf(infoString.substring(0, BlobType.size())); + } + + private static String removeMarker(String string) { + return string.substring(BlobType.size()); + } + + + public static List formCommitReferences(Path commitFile, GitFileKeeper storage) throws IOException { + return decodeTree(commitFile, storage); + } + + static private String withoutMarker(String infoString) { + return infoString.substring(markLength); + } + + private static List decodeTree(Path treeFile, GitFileKeeper storage) throws IOException { + List references = new ArrayList<>(); + FileReference decodedTree = decodeFile(treeFile); + references.add(decodedTree); + List components = IOUtils.readLines(decodedTree.content, ENCODING); + for (String component : components) { + references.addAll(decodeComponent(component, storage)); + } + return references; + } + + private static FileReference decodeFile(Path file) throws IOException { + FileReference reference = new FileReference(); + BufferedReader reader = Files.newBufferedReader(file); + String infoLine = reader.readLine(); + reference.type = readMarker(infoLine); + reference.name = withoutMarker(infoLine); + reference.content = IOUtils.toInputStream(IOUtils.toString(reader)); + return reference; + } + + private static List decodeComponent(String component, GitFileKeeper storage) throws IOException { + BlobType type = readMarker(component); + String[] HashAndName = removeMarker(component).split(tab); + Path encodedFile = storage.correctPath(HashAndName[0]); + if(type.equals(BlobType.FILE)) { + return Collections.singletonList(decodeFile(encodedFile)); + } + if(type.equals(BlobType.TREE)) { + return decodeTree(encodedFile, storage); + } + return Collections.emptyList(); + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java new file mode 100644 index 0000000..7485b34 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java @@ -0,0 +1,166 @@ +package ru.ifmo.git.entities; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.IOUtils; +import ru.ifmo.git.util.BlobType; +import ru.ifmo.git.util.CommitInfo; +import ru.ifmo.git.util.FileReference; +import ru.ifmo.git.util.GitException; + +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class GitEncoder { + + private Path root; + GitEncoder(Path root) { + this.root = root; + } + + public void setRoot(Path root) { + this.root = root; + } + + private static String ENCODING = "UTF-8"; + private static String sep = System.getProperty("line.separator"); + private static String tab = "\t"; + + private static String marker(Path path) { + if(Files.isRegularFile(path)) { + return BlobType.FILE.asString(); + } + return BlobType.TREE.asString(); + } + + static String getHash(Path file, Path root) throws IOException { + InputStream fileContent = formContent(file, root); + String filePath = file.toFile().getName(); + fileContent = new SequenceInputStream( + fileContent, + IOUtils.toInputStream(filePath) + ); + return DigestUtils.sha1Hex(fileContent); + } + + private static InputStream formContent(Path path, Path root) throws IOException { + if(Files.isRegularFile(path)) { + return Files.newInputStream(path); + } + List files = Files.list(path).collect(Collectors.toList()); + StringBuilder builder = new StringBuilder(); + for (Path file : files) { + if(!file.toFile().getName().equals(".l_git")) { + writeInfoString(builder, file, root); + } + } + return IOUtils.toInputStream(builder.toString(), ENCODING); + } + + private static void writeInfoString(StringBuilder builder, Path file, Path root) throws IOException { + builder .append(marker(file)) + .append(getHash(file, root)) + .append(tab) + .append(root.relativize(file)) + .append(sep); + } + + private static InputStream formHeader(Path file, Path root) throws IOException { + String info = marker(file) + root.relativize(file) + sep; + return IOUtils.toInputStream(info, ENCODING); + } + + private static InputStream encodeFile(Path file, Path root) throws IOException { + return new SequenceInputStream( + formHeader(file, root), + formContent(file, root) + ); + } + + static FileReference formEncodeReference(Path file, Path root) throws IOException { + FileReference reference = new FileReference(); + reference.type = BlobType.typeOf(marker(file)); + reference.name = getHash(file, root); + reference.content = encodeFile(file, root); + return reference; + } + + private static List formEncodeReferences(Path file, Path root) throws IOException { + if(Files.isRegularFile(file)) { + return Collections.singletonList(formEncodeReference(file, root)); + } else { + List references = new ArrayList<>(); + List files = Files.list(file).collect(Collectors.toList()); + references.add(formEncodeReference(file, root)); + for (Path f : files) { + if(Files.isRegularFile(f)) { + FileReference lll = formEncodeReference(f, root); + references.add(lll); + } else { + references.addAll(formEncodeReferences(f, root)); + } + } + return references; + } + } + + public static String createHash() { + return DigestUtils.sha1Hex(UUID.randomUUID().toString()); + } + + public static String createCommitHash(CommitInfo info) { + String builder = info.time + info.rootDirectory + + info.author + info.branch; + return DigestUtils.sha1Hex(builder); + } + + public static FileReference formCommitReference(String hash, List files, Path root) throws IOException { + FileReference commit = new FileReference(); + commit.type = BlobType.COMMIT; + commit.name = hash; + commit.content = encodeCommitFiles(files, root); + return commit; + } + + public static List formEncodeReferences(List files, Path root) throws GitException { + List references = new ArrayList<>(); + for (Path file : files) { + try { + if (!file.getFileName().toString().equals(".l_git")) { + references.addAll(formEncodeReferences(file, root)); + } + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + } + return references; + } + + static public InputStream encodeCommitFiles(List files, Path root) throws IOException { + StringBuilder builder = new StringBuilder(); + builder.append(BlobType.COMMIT.asString()).append(sep); + for (Path file : files) { + writeInfoString(builder, file, root); + } + return IOUtils.toInputStream(builder.toString(), ENCODING); + } + + static public List formCommitReferences(String hash, Path root) throws GitException { + try { + List files = Files.list(root).collect(Collectors.toList()); + List references = formEncodeReferences(files, root); + FileReference commitReference = formCommitReference(hash, files, root); + references.add(commitReference); + return references; + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + } +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java index cb247a6..3b8479f 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java @@ -1,6 +1,7 @@ package ru.ifmo.git.entities; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import ru.ifmo.git.util.*; import java.io.*; @@ -38,9 +39,7 @@ private Path filePath(String blob) throws IOException { public void saveCommit(List references) throws IOException { for (FileReference reference : references) { Path file = filePath(reference.name); - if(Files.notExists(file)) { - Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); - } + Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); } } @@ -91,7 +90,7 @@ static public void clearDirectory(Path directory) throws GitException { try { List files = Files.list(directory).collect(Collectors.toList()); removeAll(files); - } catch (IOException e) { + } catch (IOException | GitException e) { throw new GitException("error while removing"); } } @@ -99,17 +98,27 @@ static public void clearDirectory(Path directory) throws GitException { static public void removeAll(List files) throws GitException { try { for (Path file : files) { - if (!Files.isHidden(file) && !Files.isExecutable(file)) { - if (Files.isRegularFile(file)) { - deleteFile(file); - } else { - clearDirectory(file); - Files.deleteIfExists(file); - } + if (Files.isRegularFile(file)) { + deleteFile(file); + } else { + clearDirectory(file); + Files.deleteIfExists(file); } } } catch (IOException e) { throw new GitException(e.getMessage()); } } + + static public boolean checkFilesExist(List files, boolean verbose) { + for (Path file : files) { + if (!Files.exists(file)) { + if(verbose) { + System.out.println("fatal: pathspec " + file.getFileName() + " did not match any files"); + } + return false; + } + } + return true; + } } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java new file mode 100644 index 0000000..f1cfc2f --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java @@ -0,0 +1,208 @@ +package ru.ifmo.git.entities; + +import picocli.CommandLine; +import ru.ifmo.git.commands.GitCommand; +import ru.ifmo.git.util.*; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class GitManager { + + private GitTree tree; + private GitClerk clerk; + private GitFileKeeper fileKeeper; + + private static final String ENCODING = "UTF-8"; + private static final String sep = System.getProperty("line.separator"); + + public GitManager(Path directory) { + this.tree = new GitTree(directory); + clerk = new GitClerk(tree); + fileKeeper = new GitFileKeeper(tree); + } + + public GitClerk clerk() { + return clerk; + } + + public GitTree tree() { + return tree; + } + + public CommandResult executeCommand(CommandLine commandLine) { + GitCommand command = commandLine.getCommand(); + return command.execute(this); +// if(commandLine.getCommand() instanceof Init) { +// System.out.println("INIT"); +// Init initCommand = (Init) commandLine.getCommand(); +// } + } + + public CommandResult init() throws GitException { + Message message = new Message(); + if (!tree.exists()) { + try { + tree.createGitTree(); + message.write("initialized empty "); + clerk.writeHeadInfo(new HeadInfo()); + } catch (IOException e) { + String msg = "unable to create repository in " + tree.repo(); + return new CommandResult(ExitStatus.FAILURE, msg); + } + } else { + message.write("reinitialized existing "); + } + message.write("lGit repository in " + tree.repo()); + return new CommandResult(ExitStatus.SUCCESS, message); + } + + public CommandResult add(List files) throws GitException { + try { + GitFileKeeper.copyAll(files, tree.index()); + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "l_git: add: done!"); + } + + public CommandResult commit(String message) throws GitException { + CommitInfo commitInfo; + try { + commitInfo = clerk.fillCommitInfo(message); + List references = GitEncoder.formCommitReferences(commitInfo.hash, tree.index()); + fileKeeper.saveCommit(references); + clerk.writeLog(commitInfo); + clerk.changeHeadInfo(commitInfo.hash); + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "l_git: commit: done!"); + } + + public CommandResult log(String revision) throws GitException { + CommandResult emptyLog = new CommandResult(ExitStatus.SUCCESS, clerk.emptyLogResult()); + if (Files.notExists(tree.log())) { + return emptyLog; + } + List history = clerk.getLogHistory(); + if (history.size() == 0) { + return emptyLog; + } + history = history.stream().filter( + new Predicate() { + private boolean include = (revision == null || revision.isEmpty()); + + @Override + public boolean test(CommitInfo commitInfo) { + include = include || commitInfo.hash.startsWith(revision); + return include; + } + } + ).collect(Collectors.toList()); + if(history.size() == 0) { + String failMessage = "l_git: log: '" + revision + "' unknown revision"; + return new CommandResult(ExitStatus.FAILURE, failMessage); + } + Message logContent = new Message(); + history.forEach(info -> logContent.write(info.toString())); + return new CommandResult(ExitStatus.SUCCESS, logContent); + } + + public CommandResult reset(String revision) throws GitException { + if (clerk.getHeadInfo().currentHash.equals(revision)) { + return new CommandResult(ExitStatus.FAILURE, "reset: already on commit " + revision); + } + try{ + Optional commit = fileKeeper.findFileInStorage(revision); + if (commit.isPresent()) { + Path commitFile = commit.get(); + List references = GitDecoder.formCommitReferences(commitFile, fileKeeper); + GitFileKeeper.clearDirectory(tree.index()); + fileKeeper.restoreCommit(references, tree.index()); + clerk.changeHeadInfo(revision); + return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); + } + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + String failMessage = "l_git: reset: '" + revision + "' unknown revision"; + return new CommandResult(ExitStatus.FAILURE, failMessage); + } + + public CommandResult checkout(String revision) throws GitException { + if (clerk.getHeadInfo().currentHash.equals(revision)) { + return new CommandResult(ExitStatus.FAILURE, "reset: already on commit " + revision); + } + try { + Optional commit = fileKeeper.findFileInStorage(revision); + if (commit.isPresent()) { + Path commitFile = commit.get(); + List references = GitDecoder.formCommitReferences(commitFile, fileKeeper); + fileKeeper.restoreCommit(references, tree.repo()); + clerk.changeHeadInfo(revision); + } + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); + } + + public CommandResult checkout(List files) throws GitException { + files = files.stream() + .map(f -> tree.index().resolve(tree.repo().relativize(f))) + .collect(Collectors.toList()); + if(!GitFileKeeper.checkFilesExist(files, true)) { + return new CommandResult(ExitStatus.FAILURE, ""); + } + try{ + GitFileKeeper.copyAll(files, tree.repo()); + } catch (IOException e) { + throw new GitException(e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); + } + + public CommandResult checkoutBranch(String branch) throws GitException { + return new CommandResult(ExitStatus.SUCCESS, "kek"); + } + + public CommandResult status() throws GitException { + HeadInfo headInfo = clerk.getHeadInfo(); + Message info = new Message(); + info.write("On branch " + headInfo.branchName + GitClerk.sep); + Map fileToStatus = clerk.compareRepoAndIndex(); + if(fileToStatus.isEmpty()) { + info.write("No changed files"); + } else { + for (Map.Entry e : fileToStatus.entrySet()) { + info.write(sep); + info.write(e.getValue() + ": "); + info.write("\t"); + info.write(e.getKey()); + } + } + return new CommandResult(ExitStatus.SUCCESS, info); + } + + public CommandResult remove(List files) { + try { + List filesInIndex = files.stream() + .map(f -> tree.index().resolve(tree.repo().relativize(f))) + .collect(Collectors.toList()); + GitFileKeeper.removeAll(filesInIndex); + List filesInCWD = files.stream() + .map(tree.repo()::resolve) + .collect(Collectors.toList()); + GitFileKeeper.removeAll(filesInCWD); + } catch (GitException e) { + return new CommandResult(ExitStatus.ERROR, "rm: " + e.getMessage()); + } + return new CommandResult(ExitStatus.SUCCESS, "rm: done!"); + } + +} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java deleted file mode 100644 index b648b88..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitParser.java +++ /dev/null @@ -1,77 +0,0 @@ -package ru.ifmo.git.entities; - -import net.sourceforge.argparse4j.*; -import net.sourceforge.argparse4j.inf.*; -import ru.ifmo.git.commands.*; - -import java.nio.file.Path; - -public class GitParser { - - private ArgumentParser gitParser; - - public GitParser() { - createGitParser(); - } - - private void createGitParser() { - gitParser = ArgumentParsers.newArgumentParser("git"); - gitParser.defaultHelp(true) - .description("A version control system created by lergor."); - - Subparsers subparsers = gitParser.addSubparsers() - .title("These are common Git commands used in various situations:"); - - Subparser parserInit = subparsers.addParser("init") - .setDefault("cmd", new Init()) - .help("Create an empty Git repository or reinitialize an existing one"); - parserInit.addArgument("") - .type(Path.class).nargs("?").setDefault(GitAssembly.cwd()); - - Subparser parserAdd = subparsers.addParser("add") - .setDefault("cmd", new Add()) - .help("Add file contents to the index"); - parserAdd.addArgument("").type(String.class) - .required(true).nargs("+"); - - Subparser parserRemove = subparsers.addParser("rm") - .setDefault("cmd", new Remove()) - .help("Remove files from the working tree and from the index"); - parserRemove.addArgument("").type(String.class) - .required(true).nargs("+"); - - Subparser parserStatus = subparsers.addParser("status") - .setDefault("cmd", new Status()) - .help("Show current state of the repository"); - - Subparser parserCommit = subparsers.addParser("commit") - .setDefault("cmd", new Commit()) - .help("Record changes to the repository"); - parserCommit.addArgument("-m", "--message").nargs("?").type(String.class); - - Subparser parserReset = subparsers.addParser("reset") - .setDefault("cmd", new Reset()) - .help("Reset current HEAD to the specified state"); - parserReset.addArgument("").nargs("?").type(String.class); - - Subparser parserLog = subparsers.addParser("log") - .setDefault("cmd", new Log()) - .help("Show commit logs"); - parserLog.addArgument("").type(String.class).nargs("?"); - - Subparser parserCheckout = subparsers.addParser("checkout") - .setDefault("cmd", new Checkout()) - .help("Switch branches or restore working tree files"); - parserCheckout.addArgument("").nargs("?").type(String.class); - - } - - public Namespace parseArgs(String[] args) throws ArgumentParserException { - return gitParser.parseArgs(args); - } - - public void handleError(ArgumentParserException e) { - gitParser.handleError(e); - } - -} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java index 4b4fe37..5f77784 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java @@ -6,35 +6,31 @@ public class GitTree { private Path rootDir; - private Path gitDir; + private Path metaDir; private Path logDir; private Path storageDir; private Path indexDir; private Path headFile; - public GitTree() { - setRepository(GitAssembly.cwd()); - } - public GitTree(Path repository) { setRepository(repository); } private void setRepository(Path repository) { rootDir = repository; - gitDir = rootDir.resolve(".m_git"); - headFile = gitDir.resolve("HEAD"); - logDir = gitDir.resolve("log"); - storageDir = gitDir.resolve("storage"); - indexDir = gitDir.resolve("index"); + metaDir = rootDir.resolve(".l_git"); + headFile = metaDir.resolve("HEAD"); + logDir = metaDir.resolve("log"); + storageDir = metaDir.resolve("storage"); + indexDir = metaDir.resolve("index"); } public void createGitTree() throws IOException { - gitDir = Files.createDirectory(rootDir.resolve(".m_git")); - headFile = Files.createFile(gitDir.resolve("HEAD")); - logDir = Files.createDirectory(gitDir.resolve("log")); - storageDir = Files.createDirectory(gitDir.resolve("storage")); - indexDir = Files.createDirectory(gitDir.resolve("index")); + metaDir = Files.createDirectory(rootDir.resolve(".l_git")); + headFile = Files.createFile(metaDir.resolve("HEAD")); + logDir = Files.createDirectory(metaDir.resolve("log")); + storageDir = Files.createDirectory(metaDir.resolve("storage")); + indexDir = Files.createDirectory(metaDir.resolve("index")); } public Path repo() { @@ -58,10 +54,10 @@ public Path head() { } public Path git() { - return gitDir; + return metaDir; } public boolean exists() { - return Files.exists(gitDir); + return Files.exists(metaDir); } } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/StorageMaster.java b/task1_git/src/main/java/ru/ifmo/git/entities/StorageMaster.java deleted file mode 100644 index 5d5a034..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/entities/StorageMaster.java +++ /dev/null @@ -1,61 +0,0 @@ -package ru.ifmo.git.entities; - -import org.apache.commons.io.FileUtils; -import ru.ifmo.git.util.*; - -import java.io.*; -import java.util.*; - -public class StorageMaster { - - private File storage; - private final String ENCODING = "UTF_8"; - - public StorageMaster(File storage) { - this.storage = storage; - } - - /////////////////////////////////////////////// - - static public void copyAll(List args, File targetDir) throws GitException { - if (targetDir.exists() || (!targetDir.exists() && targetDir.mkdirs())) { - for (File file : args) { - try { - if (file.isFile()) { - FileUtils.copyFileToDirectory(file, targetDir); - } else if (file.isDirectory()) { - FileUtils.copyDirectoryToDirectory(file, targetDir); - } - } catch (IOException e) { - throw new GitException(e.getMessage()); - } - } - } - } - - static public boolean createFileWithContent(String fileName, String content) { - if (checkAndCreateFile(fileName)) { - try { - FileUtils.writeStringToFile(new File(fileName), content, "UTF-8"); - } catch (IOException e) { - return false; - } - } - return true; - } - - private static boolean checkAndCreateFile(String fileName) { - File file = new File(fileName); - if (!file.exists()) { - try { - if (file.createNewFile()) { - return file.setReadable(true) && file.setWritable(true); - } - } catch (IOException e) { - return false; - } - } - return file.canRead() && file.canWrite(); - } - -} diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/TreeCryptographer.java b/task1_git/src/main/java/ru/ifmo/git/entities/TreeCryptographer.java deleted file mode 100644 index cb2a3fe..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/entities/TreeCryptographer.java +++ /dev/null @@ -1,88 +0,0 @@ -package ru.ifmo.git.entities; - -import org.apache.commons.io.IOUtils; -import ru.ifmo.git.util.*; - -import java.io.*; -import java.nio.file.*; -import java.util.*; -import java.util.stream.Collectors; - -class TreeCryptographer implements Cryptographer { - - private final FileCryptographer fileCrypto = new FileCryptographer(); - private final BlobType type = BlobType.TREE; - - @Override - public String marker() { - return type.asString(); - } - - @Override - public InputStream formContent(Path directory) throws IOException { - List files = Files.list(directory).collect(Collectors.toList()); - StringBuilder builder = new StringBuilder(); - for (Path file : files) { - if(!Files.isHidden(file)) { - if (Files.isRegularFile(file)) { - builder .append(fileCrypto.marker()) - .append(fileCrypto.getHash(file)); - } else { - builder .append(marker()) - .append(getHash(file)); - } - builder .append(tab) - .append(file.getFileName()) - .append(sep); - } - } - return IOUtils.toInputStream(builder.toString(), ENCODING); - } - - public List formEncodeReferences(Path tree) throws IOException { - List references = new ArrayList<>(); - List files = Files.list(tree).collect(Collectors.toList()); - references.add(formEncodeReference(tree)); - for (Path file : files) { - if(!Files.isHidden(file)) { - if(Files.isRegularFile(file)) { - FileReference lll = fileCrypto.formEncodeReference(file); - references.add(lll); - } else { - references.addAll(formEncodeReferences(file)); - } - } - } - return references; - } - - private List decodeComponent(String component, GitFileKeeper storage) throws IOException { - BlobType type = readMarker(component); - String[] HashAndName = removeMarker(component).split(tab); - Path encodedFile = storage.correctPath(HashAndName[0]); - if(type.equals(BlobType.FILE)) { - return Collections.singletonList(fileCrypto.decodeFile(encodedFile)); - } - if(type.equals(BlobType.TREE)) { - return decodeTree(encodedFile, storage); - } - return Collections.emptyList(); - } - - - public List decodeTree(Path treeFile, GitFileKeeper storage) throws IOException { - List decodedFiles = new ArrayList<>(); - FileReference decodedTree = fileCrypto.decodeFile(treeFile); - decodedFiles.add(decodedTree); - List components = IOUtils.readLines(decodedTree.content, ENCODING); - for (String component: components) { - List references = decodeComponent(component, storage); - for(FileReference ref : references) { - ref.name = Paths.get(decodedTree.name, ref.name).toString(); - } - decodedFiles.addAll(references); - } - return decodedFiles; - } - -} diff --git a/task1_git/src/main/java/ru/ifmo/git/executors/GitExecutor.java b/task1_git/src/main/java/ru/ifmo/git/executors/GitExecutor.java new file mode 100644 index 0000000..6b4e9e6 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/executors/GitExecutor.java @@ -0,0 +1,9 @@ +package ru.ifmo.git.executors; + +import ru.ifmo.git.commands.GitCommand; +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.util.CommandResult; + +public interface GitExecutor { + CommandResult execute(GitManager manager, GitCommand command); +} diff --git a/task1_git/src/main/java/ru/ifmo/git/executors/InitExecutor.java b/task1_git/src/main/java/ru/ifmo/git/executors/InitExecutor.java new file mode 100644 index 0000000..642c6b1 --- /dev/null +++ b/task1_git/src/main/java/ru/ifmo/git/executors/InitExecutor.java @@ -0,0 +1,33 @@ +//package ru.ifmo.git.executors; +// +//import ru.ifmo.git.commands1.GitCommand; +//import ru.ifmo.git.commands1.Init; +//import ru.ifmo.git.entities.GitManager; +//import ru.ifmo.git.util.CommandResult; +//import ru.ifmo.git.util.ExitStatus; +//import ru.ifmo.git.util.HeadInfo; +//import ru.ifmo.git.util.Message; +// +//import java.io.IOException; +// +//public class InitExecutor implements GitExecutor { +// +// @Override +// public CommandResult execute(GitManager manager, GitCommand command) { +// Message message = new Message(); +// if (!manager.tree().exists()) { +// try { +// manager.tree().createGitTree(); +// message.write("initialized empty "); +// manager.clerk().writeHeadInfo(new HeadInfo()); +// } catch (IOException e) { +// String msg = "unable to create repository in " + tree.repo(); +// return new CommandResult(ExitStatus.FAILURE, msg); +// } +// } else { +// message.write("reinitialized existing "); +// } +// message.write("lGit repository in " + tree.repo()); +// return new CommandResult(ExitStatus.SUCCESS, message); +// } +//} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java index f8c94e0..d3cb588 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java @@ -4,7 +4,6 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; -import java.util.UUID; public class CommitInfo { public String author; diff --git a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java index d4fc9bc..2085e51 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java @@ -7,6 +7,7 @@ public class HeadInfo { public String currentHash; public HeadInfo() { + branchName = "master"; } public void moveHead(String hash) { From c60512e9431f98a1610960c55b59316042af23fd Mon Sep 17 00:00:00 2001 From: lergor Date: Mon, 15 Oct 2018 04:24:02 +0300 Subject: [PATCH 11/14] refactor --- task1_git/Readme.md | 15 +- task1_git/build.gradle | 2 +- task1_git/src/main/java/ru/ifmo/git/LGit.java | 25 +--- .../main/java/ru/ifmo/git/commands/Add.java | 9 +- .../java/ru/ifmo/git/commands/Checkout.java | 20 +-- .../java/ru/ifmo/git/commands/Commit.java | 10 +- .../main/java/ru/ifmo/git/commands/Git.java | 5 +- .../java/ru/ifmo/git/commands/GitCommand.java | 15 +- .../main/java/ru/ifmo/git/commands/Log.java | 7 +- .../java/ru/ifmo/git/commands/Remove.java | 11 +- .../main/java/ru/ifmo/git/commands/Reset.java | 5 +- .../java/ru/ifmo/git/commands/Status.java | 11 +- .../java/ru/ifmo/git/entities/GitClerk.java | 133 ++++++++--------- .../java/ru/ifmo/git/entities/GitDecoder.java | 27 ++-- .../java/ru/ifmo/git/entities/GitEncoder.java | 68 ++++----- .../ru/ifmo/git/entities/GitFileKeeper.java | 89 ++++++----- .../java/ru/ifmo/git/entities/GitManager.java | 141 ++++++++---------- .../java/ru/ifmo/git/entities/GitTree.java | 23 +-- .../ru/ifmo/git/executors/GitExecutor.java | 9 -- .../ru/ifmo/git/executors/InitExecutor.java | 33 ---- .../java/ru/ifmo/git/util/CommandResult.java | 24 +++ 21 files changed, 313 insertions(+), 369 deletions(-) delete mode 100644 task1_git/src/main/java/ru/ifmo/git/executors/GitExecutor.java delete mode 100644 task1_git/src/main/java/ru/ifmo/git/executors/InitExecutor.java diff --git a/task1_git/Readme.md b/task1_git/Readme.md index f188bb4..a6544f7 100644 --- a/task1_git/Readme.md +++ b/task1_git/Readme.md @@ -9,19 +9,20 @@ This repository contains simple draft of **git**. The following commands are available:
``` init -add -rm +add +rm status commit -reset -log [from_commit] -checkout +reset +log [from_revision] +checkout +checkout -r ``` where *<smth>* means mandatory argument while *[smth]* implies he optional one.
-*commit* is represented as short (at least 7 symbols) or entire hash code. - +*commit* is represented as short (at least 7 symbols) or entire hash code.
+*checkout -r * is the replacement of *checkout -- *.
### File hierarchy diff --git a/task1_git/build.gradle b/task1_git/build.gradle index 37a4453..89755e9 100644 --- a/task1_git/build.gradle +++ b/task1_git/build.gradle @@ -4,7 +4,7 @@ version '1.0-SNAPSHOT' apply plugin: 'java' apply plugin: 'application' -mainClassName = "ru.ifmo.git.Git" +mainClassName = "ru.ifmo.git.LGit" sourceCompatibility = 1.8 diff --git a/task1_git/src/main/java/ru/ifmo/git/LGit.java b/task1_git/src/main/java/ru/ifmo/git/LGit.java index d0fcd3b..9faa197 100644 --- a/task1_git/src/main/java/ru/ifmo/git/LGit.java +++ b/task1_git/src/main/java/ru/ifmo/git/LGit.java @@ -1,31 +1,24 @@ package ru.ifmo.git; import picocli.CommandLine; -//import ru.ifmo.git.entities.GitParser; -import ru.ifmo.git.commands.Git; -//import ru.ifmo.git.commands1.Init; -import ru.ifmo.git.entities.GitManager; -import ru.ifmo.git.util.*; import java.nio.file.Path; import java.nio.file.Paths; + import java.util.List; +import ru.ifmo.git.commands.Git; +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.util.CommandResult; + public class LGit { private static Path cwd() { - // System.out.println(System.getProperty("user.dir")); +// return Paths.get(System.getProperty("user.dir")); return Paths.get("/home/valeriya/Desktop/AU/III/JAVA_II/task1_git/kek"); } public static void main(String[] args) { - Path repo = Paths.get("/home/valeriya/Desktop/AU/III/JAVA_II/task1_git/kek"); - args = new String[]{"add", - repo.resolve("lol").toString()}; - -// args = new String[]{"checkout", "780228fc7a09bf494f5922c6e310cf36244317c9"}; -// args = new String[]{"checkout", "-r", repo.resolve("lol").toString()}; - args = new String[]{"-h"}; CommandLine commandLine = new CommandLine(new Git()); try { List parsed = commandLine.parse(args); @@ -35,10 +28,7 @@ public static void main(String[] args) { if (parsed.size() == 2) { GitManager manager = new GitManager(cwd()); CommandResult result = manager.executeCommand(parsed.get(1)); - if (result.getStatus() != ExitStatus.SUCCESS) { - System.out.println("Exit with code " + result.getStatus()); - } - System.out.println(result.getMessage().read()); + result.print(); } else { commandLine.usage(System.out); } @@ -46,4 +36,5 @@ public static void main(String[] args) { System.out.println("l_git: no such command. See 'l_git --help'."); } } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java index 2288bb8..c933bd1 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java @@ -3,13 +3,15 @@ import picocli.CommandLine.Command; import picocli.CommandLine.Parameters; +import java.io.IOException; + import java.nio.file.Path; + import java.util.List; import ru.ifmo.git.entities.GitFileKeeper; import ru.ifmo.git.entities.GitManager; import ru.ifmo.git.util.CommandResult; -import ru.ifmo.git.util.GitException; @Command( name = "add", @@ -23,11 +25,12 @@ public class Add implements GitCommand { @Override public boolean incorrectArgs() { - return !GitFileKeeper.checkFilesExist(files, true); + return !GitFileKeeper.checkFilesExist(files); } @Override - public CommandResult doWork(GitManager gitManager) throws GitException { + public CommandResult doWork(GitManager gitManager) throws IOException { return gitManager.add(files); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java index 9329916..8fc49c4 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java @@ -3,12 +3,16 @@ import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; import picocli.CommandLine.Command; -import ru.ifmo.git.entities.*; -import ru.ifmo.git.util.*; + +import java.io.IOException; import java.nio.file.Path; + import java.util.List; +import ru.ifmo.git.entities.*; +import ru.ifmo.git.util.*; + @Command( name = "checkout", description = "Switch branches or restore working tree files", @@ -16,14 +20,11 @@ ) public class Checkout implements GitCommand { - @Parameters( - arity = "?", - paramLabel = "" - ) + @Parameters(arity = "?", paramLabel = "") private String revision; @Option( - names = {"--", "-r"}, + names = {"-r"}, arity = "*", paramLabel = "", description = "Discard changes in working directory in the given files.", @@ -37,11 +38,12 @@ public boolean incorrectArgs() { } @Override - public CommandResult doWork(GitManager gitManager) throws GitException { - if(revision != null) { + public CommandResult doWork(GitManager gitManager) throws GitException, IOException { + if (revision != null) { return gitManager.checkout(revision); } else { return gitManager.checkout(files); } } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index 7c5d77b..9e945b9 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -3,8 +3,11 @@ import picocli.CommandLine.Command; import picocli.CommandLine.Option; -import ru.ifmo.git.entities.*; -import ru.ifmo.git.util.*; +import java.io.IOException; + +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.GitException; @Command( name = "commit", @@ -22,7 +25,8 @@ public class Commit implements GitCommand { private String message; @Override - public CommandResult doWork(GitManager gitManager) throws GitException { + public CommandResult doWork(GitManager gitManager) throws GitException, IOException { return gitManager.commit(message); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Git.java b/task1_git/src/main/java/ru/ifmo/git/commands/Git.java index 6732003..c0cab9d 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Git.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Git.java @@ -17,9 +17,12 @@ description = "A version control system created by lergor." ) public class Git { + @CommandLine.Option( names = {"-h", "--help"}, help = true, - description = "Prints the synopsis and a list of the most commonly used commands.") + description = "Prints the synopsis and a list of the most commonly used commands." + ) boolean isHelpRequested; + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java index 14758e4..b22386e 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java @@ -1,13 +1,11 @@ package ru.ifmo.git.commands; +import java.io.IOException; + import ru.ifmo.git.entities.GitManager; import ru.ifmo.git.entities.GitTree; import ru.ifmo.git.util.*; -import java.io.IOException; -import java.nio.file.*; -import java.util.*; - public interface GitCommand { default boolean incorrectArgs() { @@ -18,20 +16,23 @@ default boolean gitNotInited(GitTree tree) { return !tree.exists(); } - CommandResult doWork(GitManager gitManager) throws GitException; + CommandResult doWork(GitManager gitManager) throws GitException, IOException; default CommandResult execute(GitManager gitManager) { String name = this.getClass().getSimpleName().toLowerCase(); - if(gitNotInited(gitManager.tree())) { + if (gitNotInited(gitManager.tree())) { return new CommandResult(ExitStatus.ERROR, "fatal: Not a l_git repository"); } - if(incorrectArgs()) { + if (incorrectArgs()) { return new CommandResult(ExitStatus.ERROR, name + ": incorrect arguments"); } try { return doWork(gitManager); } catch (GitException e) { return new CommandResult(ExitStatus.ERROR, name + ": " + e.getMessage()); + } catch (IOException e) { + return new CommandResult(ExitStatus.ERROR, name + ": error appeared", e); } } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index f2d92b6..20aa5e9 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -2,6 +2,7 @@ import picocli.CommandLine.Command; import picocli.CommandLine.Parameters; + import ru.ifmo.git.entities.GitManager; import ru.ifmo.git.util.CommandResult; import ru.ifmo.git.util.GitException; @@ -20,13 +21,9 @@ public class Log implements GitCommand { ) private String revision; - @Override - public boolean incorrectArgs() { - return (revision == null || revision.length() < 6); - } - @Override public CommandResult doWork(GitManager gitManager) throws GitException { return gitManager.log(revision); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java index 7825b96..38d7ad1 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java @@ -2,12 +2,16 @@ import picocli.CommandLine.Command; import picocli.CommandLine.Parameters; -import ru.ifmo.git.entities.*; -import ru.ifmo.git.util.*; + +import java.io.IOException; import java.nio.file.Path; + import java.util.*; +import ru.ifmo.git.entities.*; +import ru.ifmo.git.util.*; + @Command( name = "rm", description = "Remove files from the working tree and from the index", @@ -24,7 +28,8 @@ public boolean incorrectArgs() { } @Override - public CommandResult doWork(GitManager gitManager) { + public CommandResult doWork(GitManager gitManager) throws IOException { return gitManager.remove(files); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java index 9e8ac15..3e7bf7a 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java @@ -3,6 +3,8 @@ import picocli.CommandLine.Command; import picocli.CommandLine.Parameters; +import java.io.IOException; + import ru.ifmo.git.entities.GitManager; import ru.ifmo.git.util.CommandResult; import ru.ifmo.git.util.GitException; @@ -23,7 +25,8 @@ public boolean incorrectArgs() { } @Override - public CommandResult doWork(GitManager gitManager) throws GitException { + public CommandResult doWork(GitManager gitManager) throws GitException, IOException { return gitManager.reset(revision); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java index 55fafea..c43ec58 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java @@ -1,8 +1,12 @@ package ru.ifmo.git.commands; import picocli.CommandLine.Command; -import ru.ifmo.git.entities.*; -import ru.ifmo.git.util.*; + +import java.io.IOException; + +import ru.ifmo.git.entities.GitManager; +import ru.ifmo.git.util.CommandResult; +import ru.ifmo.git.util.GitException; @Command( name = "status", @@ -12,7 +16,8 @@ public class Status implements GitCommand { @Override - public CommandResult doWork(GitManager gitManager) throws GitException { + public CommandResult doWork(GitManager gitManager) throws GitException, IOException { return gitManager.status(); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java index e441ef1..4084af6 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java @@ -1,27 +1,34 @@ package ru.ifmo.git.entities; -import com.google.gson.*; -import org.apache.commons.io.*; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; -import ru.ifmo.git.commands.Git; -import ru.ifmo.git.util.*; +import org.apache.commons.io.FileUtils; import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.*; -import java.text.*; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; + import java.util.*; import java.util.stream.Collectors; +import ru.ifmo.git.util.CommitInfo; +import ru.ifmo.git.util.GitException; +import ru.ifmo.git.util.HeadInfo; + public class GitClerk { - public static final String ENCODING = "UTF-8"; - public static final String sep = System.getProperty("line.separator"); - private Gson gson = new GsonBuilder().create(); + private static final String ENCODING = "UTF-8"; + private static final String sep = System.getProperty("line.separator"); + private final Gson gson = new GsonBuilder().create(); private final GitTree gitTree; - - public GitClerk(GitTree gitTree){ + GitClerk(GitTree gitTree) { this.gitTree = gitTree; } @@ -40,7 +47,7 @@ void writeHeadInfo(HeadInfo newHeadInfo) throws GitException { try { FileUtils.writeStringToFile(gitTree.head().toFile(), newInfo, ENCODING); } catch (IOException e) { - throw new GitException(e.getMessage()); + throw new GitException("error while writing log " + e.getMessage()); } } @@ -57,11 +64,11 @@ void changeHeadInfo(String hash) throws GitException { public void writeLog(CommitInfo commit) throws GitException { File logFile = gitTree.log().resolve(commit.branch).toFile(); try { - if(logFile.exists() || logFile.createNewFile()) { + if (logFile.exists() || logFile.createNewFile()) { writeToFile(logFile.toPath(), gson.toJson(commit) + sep, true); } } catch (IOException e) { - throw new GitException(e.getMessage()); + throw new GitException("error while creating log " + e.getMessage()); } } @@ -70,11 +77,11 @@ private String getUserMessage() { System.out.print("please enter message: "); return br.readLine(); } catch (IOException e) { - return "no message"; + return ""; } } - static public void writeToFile(Path file, String content, boolean append) throws GitException { + private static void writeToFile(Path file, String content, boolean append) throws GitException { try (BufferedWriter writer = new BufferedWriter(new FileWriter(file.toFile(), append))) { writer.write(content); } catch (IOException e) { @@ -86,6 +93,9 @@ public List getLogHistory() throws GitException { String branch = getHeadInfo().branchName; File logFile = gitTree.log().resolve(branch).toFile(); List history = new ArrayList<>(); + if(!logFile.exists()) { + return history; + } try (BufferedReader br = new BufferedReader(new FileReader(logFile))) { for (String line; (line = br.readLine()) != null; ) { history.add(gson.fromJson(line, CommitInfo.class)); @@ -97,16 +107,7 @@ public List getLogHistory() throws GitException { return history; } - public Optional findCommitInfo(String desiredCommit) throws GitException { - for (CommitInfo commit: getLogHistory()) { - if(commit.hash.startsWith(desiredCommit)) { - return Optional.of(commit); - } - } - return Optional.empty(); - } - - public static String getAuthor() { + private static String getAuthor() { return System.getProperty("user.name"); } @@ -115,7 +116,6 @@ private static String getCurrentTime() { return df.format(Calendar.getInstance().getTime()); } - public CommitInfo fillCommitInfo(String message) throws GitException { CommitInfo info = new CommitInfo(); info.setAuthor(getAuthor()); @@ -127,17 +127,6 @@ public CommitInfo fillCommitInfo(String message) throws GitException { return info; } - public Map collectFilesInfo(Path encodedFile) throws IOException { - Map nameToHash = new HashMap<>(); - List lines = Files.readAllLines(encodedFile, StandardCharsets.UTF_8); - lines.remove(0); - for (String line: lines) { - String[] nameAndHash = line.split("\t"); - nameToHash.put(nameAndHash[0], nameAndHash[1]); - } - return nameToHash; - } - String emptyLogResult() throws GitException { HeadInfo headInfo = getHeadInfo(); return "fatal: your current branch '" + @@ -145,53 +134,49 @@ String emptyLogResult() throws GitException { "' does not have any commits yet\n"; } - public Map compareRepoAndIndex() throws GitException { - try { - Map fileToStatus = new HashMap<>(); - Map inIndex = collectNameAndHash(gitTree.index()); - for (Map.Entry e : inIndex.entrySet()) { - Path fileInCWD = gitTree.repo().resolve(e.getKey()); - Path fileInIndex = gitTree.index().resolve(e.getKey()); - if (Files.isRegularFile(fileInIndex)) { - if (!Files.exists(fileInCWD)) { - fileToStatus.put(e.getKey(), "deleted"); - } else { - String hashInIndex = e.getValue(); - String hashInCWD = GitEncoder.getHash(fileInCWD, gitTree.repo()); - if (!hashInCWD.equals(hashInIndex)) { - fileToStatus.put(e.getKey(), "modified"); - } + public Map compareRepoAndIndex() throws GitException, IOException { + Map fileToStatus = new HashMap<>(); + List inIndex = collectNames(gitTree.index()); + List inCWD = collectNames(gitTree.repo()); + for (String file : inIndex) { + Path fileInCWD = gitTree.repo().resolve(file); + Path fileInIndex = gitTree.index().resolve(file); + if (Files.isRegularFile(fileInIndex)) { + if (!Files.exists(fileInCWD)) { + fileToStatus.put(file, "deleted"); + } else { + String hashInIndex = GitEncoder.getHash(fileInIndex, gitTree.index()); + String hashInCWD = GitEncoder.getHash(fileInCWD, gitTree.repo()); + if (!hashInCWD.equals(hashInIndex)) { + fileToStatus.put(file, "modified"); } } } - Files.list(gitTree.repo()).forEach(f -> { - String fileName = gitTree.repo().relativize(f).toString(); - if(!fileName.equals(".l_git") && !Files.exists(gitTree.index().resolve(fileName))) { - fileToStatus.put(fileName, "new"); - } - } - ); - return fileToStatus; - } catch (IOException e) { - throw new GitException(e.getMessage()); } + inCWD.forEach(f -> { + if(!f.contains(".l_git") && !Files.exists(gitTree.index().resolve(f))) { + fileToStatus.put(f, "new"); + } + }); + return fileToStatus; } - private Map collectNameAndHash(Path directory) throws IOException { - Map nameToHash = new HashMap<>(); + List collectNames(Path directory) throws IOException { + List fileNames = new ArrayList<>(); List files = Files.list(directory).collect(Collectors.toList()); for (Path file : files) { - String name = file.toFile().getName(); - if (!name.equals(".l_git")) { - nameToHash.put(name, GitEncoder.getHash(file, directory)); + String fileName = file.toFile().getName(); + if (!fileName.equals(".l_git")) { + fileNames.add(fileName); if (Files.isDirectory(file)) { - Set> fromSubDir = collectNameAndHash(file).entrySet(); - for (Map.Entry e : fromSubDir) { - nameToHash.put(Paths.get(name, e.getKey()).toString(), e.getValue()); + List fromSubDir = collectNames(file); + for (String f : fromSubDir) { + fileNames.add(Paths.get(fileName, f).toString()); } } } } - return nameToHash; + return fileNames; } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java index c08eed1..365fbe5 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java @@ -1,23 +1,25 @@ package ru.ifmo.git.entities; import org.apache.commons.io.IOUtils; + import ru.ifmo.git.util.BlobType; import ru.ifmo.git.util.FileReference; import java.io.BufferedReader; import java.io.IOException; + import java.nio.file.Files; import java.nio.file.Path; + import java.util.ArrayList; import java.util.Collections; import java.util.List; public class GitDecoder { - private static String ENCODING = "UTF-8"; - private static int markLength = BlobType.size(); - private static String sep = System.getProperty("line.separator"); - private static String tab = "\t"; + private static final String ENCODING = "UTF-8"; + private static final int markLength = BlobType.size(); + private static final String tab = "\t"; private static BlobType readMarker(String infoString) { @@ -28,22 +30,20 @@ private static String removeMarker(String string) { return string.substring(BlobType.size()); } - - public static List formCommitReferences(Path commitFile, GitFileKeeper storage) throws IOException { + static List formCommitReferences(Path commitFile, GitFileKeeper storage) throws IOException { return decodeTree(commitFile, storage); } - static private String withoutMarker(String infoString) { + private static String withoutMarker(String infoString) { return infoString.substring(markLength); } private static List decodeTree(Path treeFile, GitFileKeeper storage) throws IOException { List references = new ArrayList<>(); FileReference decodedTree = decodeFile(treeFile); - references.add(decodedTree); - List components = IOUtils.readLines(decodedTree.content, ENCODING); - for (String component : components) { - references.addAll(decodeComponent(component, storage)); + List components = IOUtils.readLines(decodedTree.content, ENCODING); + for (Object component : components) { + references.addAll(decodeComponent((String) component, storage)); } return references; } @@ -62,12 +62,13 @@ private static List decodeComponent(String component, GitFileKeep BlobType type = readMarker(component); String[] HashAndName = removeMarker(component).split(tab); Path encodedFile = storage.correctPath(HashAndName[0]); - if(type.equals(BlobType.FILE)) { + if (type.equals(BlobType.FILE)) { return Collections.singletonList(decodeFile(encodedFile)); } - if(type.equals(BlobType.TREE)) { + if (type.equals(BlobType.TREE)) { return decodeTree(encodedFile, storage); } return Collections.emptyList(); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java index 7485b34..54e8068 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java @@ -2,16 +2,18 @@ import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; + import ru.ifmo.git.util.BlobType; import ru.ifmo.git.util.CommitInfo; import ru.ifmo.git.util.FileReference; -import ru.ifmo.git.util.GitException; import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; + import java.nio.file.Files; import java.nio.file.Path; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -20,21 +22,11 @@ public class GitEncoder { - private Path root; - GitEncoder(Path root) { - this.root = root; - } - - public void setRoot(Path root) { - this.root = root; - } - - private static String ENCODING = "UTF-8"; - private static String sep = System.getProperty("line.separator"); - private static String tab = "\t"; + private static final String ENCODING = "UTF-8"; + private static final String sep = System.getProperty("line.separator"); private static String marker(Path path) { - if(Files.isRegularFile(path)) { + if (Files.isRegularFile(path)) { return BlobType.FILE.asString(); } return BlobType.TREE.asString(); @@ -51,13 +43,13 @@ static String getHash(Path file, Path root) throws IOException { } private static InputStream formContent(Path path, Path root) throws IOException { - if(Files.isRegularFile(path)) { + if (Files.isRegularFile(path)) { return Files.newInputStream(path); } List files = Files.list(path).collect(Collectors.toList()); StringBuilder builder = new StringBuilder(); for (Path file : files) { - if(!file.toFile().getName().equals(".l_git")) { + if (!file.toFile().getName().equals(".l_git")) { writeInfoString(builder, file, root); } } @@ -65,7 +57,8 @@ private static InputStream formContent(Path path, Path root) throws IOException } private static void writeInfoString(StringBuilder builder, Path file, Path root) throws IOException { - builder .append(marker(file)) + String tab = "\t"; + builder.append(marker(file)) .append(getHash(file, root)) .append(tab) .append(root.relativize(file)) @@ -84,7 +77,7 @@ private static InputStream encodeFile(Path file, Path root) throws IOException { ); } - static FileReference formEncodeReference(Path file, Path root) throws IOException { + private static FileReference formEncodeReference(Path file, Path root) throws IOException { FileReference reference = new FileReference(); reference.type = BlobType.typeOf(marker(file)); reference.name = getHash(file, root); @@ -93,14 +86,14 @@ static FileReference formEncodeReference(Path file, Path root) throws IOExceptio } private static List formEncodeReferences(Path file, Path root) throws IOException { - if(Files.isRegularFile(file)) { + if (Files.isRegularFile(file)) { return Collections.singletonList(formEncodeReference(file, root)); } else { List references = new ArrayList<>(); List files = Files.list(file).collect(Collectors.toList()); references.add(formEncodeReference(file, root)); for (Path f : files) { - if(Files.isRegularFile(f)) { + if (Files.isRegularFile(f)) { FileReference lll = formEncodeReference(f, root); references.add(lll); } else { @@ -111,17 +104,17 @@ private static List formEncodeReferences(Path file, Path root) th } } - public static String createHash() { + static String createHash() { return DigestUtils.sha1Hex(UUID.randomUUID().toString()); } - public static String createCommitHash(CommitInfo info) { + static String createCommitHash(CommitInfo info) { String builder = info.time + info.rootDirectory + info.author + info.branch; return DigestUtils.sha1Hex(builder); } - public static FileReference formCommitReference(String hash, List files, Path root) throws IOException { + private static FileReference formCommitReference(String hash, List files, Path root) throws IOException { FileReference commit = new FileReference(); commit.type = BlobType.COMMIT; commit.name = hash; @@ -129,21 +122,17 @@ public static FileReference formCommitReference(String hash, List files, P return commit; } - public static List formEncodeReferences(List files, Path root) throws GitException { + private static List formEncodeReferences(List files, Path root) throws IOException { List references = new ArrayList<>(); for (Path file : files) { - try { - if (!file.getFileName().toString().equals(".l_git")) { - references.addAll(formEncodeReferences(file, root)); - } - } catch (IOException e) { - throw new GitException(e.getMessage()); + if (!file.getFileName().toString().equals(".l_git")) { + references.addAll(formEncodeReferences(file, root)); } } return references; } - static public InputStream encodeCommitFiles(List files, Path root) throws IOException { + private static InputStream encodeCommitFiles(List files, Path root) throws IOException { StringBuilder builder = new StringBuilder(); builder.append(BlobType.COMMIT.asString()).append(sep); for (Path file : files) { @@ -152,15 +141,12 @@ static public InputStream encodeCommitFiles(List files, Path root) throws return IOUtils.toInputStream(builder.toString(), ENCODING); } - static public List formCommitReferences(String hash, Path root) throws GitException { - try { - List files = Files.list(root).collect(Collectors.toList()); - List references = formEncodeReferences(files, root); - FileReference commitReference = formCommitReference(hash, files, root); - references.add(commitReference); - return references; - } catch (IOException e) { - throw new GitException(e.getMessage()); - } + static List formCommitReferences(String hash, Path root) throws IOException { + List files = Files.list(root).collect(Collectors.toList()); + List references = formEncodeReferences(files, root); + FileReference commitReference = formCommitReference(hash, files, root); + references.add(commitReference); + return references; } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java index 3b8479f..57f5077 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java @@ -2,21 +2,27 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import ru.ifmo.git.util.*; +import ru.ifmo.git.util.BlobType; +import ru.ifmo.git.util.FileReference; -import java.io.*; -import java.nio.file.*; -import java.util.*; +import java.io.File; +import java.io.IOException; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; public class GitFileKeeper { - private Path storage; - private GitTree gitTree; + private final Path storage; private static final int dirNameLen = 2; - public GitFileKeeper(GitTree gitTree) { - this.gitTree = gitTree; + GitFileKeeper(GitTree gitTree) { storage = gitTree.storage(); } @@ -28,7 +34,7 @@ public Path correctPath(String blob) { return getDir(blob).resolve(blob.substring(dirNameLen)); } - private Path filePath(String blob) throws IOException { + private Path filePath(String blob) { Path directory = getDir(blob); if (Files.notExists(directory)) { boolean ignored = directory.toFile().mkdirs(); @@ -44,7 +50,8 @@ public void saveCommit(List references) throws IOException { } public Optional findFileInStorage(String hash) throws IOException { - List blobs = Files.list(getDir(hash)).collect(Collectors.toList()); + List blobs; + blobs = Files.list(getDir(hash)).collect(Collectors.toList()); for (Path blob : blobs) { if (blob.toFile().getName().startsWith(hash.substring(dirNameLen))) { return Optional.of(blob); @@ -57,6 +64,13 @@ public void restoreCommit(List references, Path destination) thro for (FileReference reference : references) { Path file = destination.resolve(reference.name); if (reference.type.equals(BlobType.FILE)) { + if(Files.notExists(file)) { + Path dirs = file.getParent(); + if(!destination.equals(dirs)) { + boolean ignored = dirs.toFile().mkdirs(); + } + Files.createFile(file); + } Files.copy(reference.content, file, StandardCopyOption.REPLACE_EXISTING); } else { boolean ignored = file.toFile().mkdirs(); @@ -64,61 +78,42 @@ public void restoreCommit(List references, Path destination) thro } } - public static void deleteFile(Path file) throws GitException { - try { - Files.deleteIfExists(file); - } catch (IOException e) { - throw new GitException(e.getMessage()); - } - } - - static public void copyAll(List files, Path targetDir) throws IOException { + static public void copyAll(List files, Path source, Path targetDir) throws IOException { File destination = targetDir.toFile(); if (destination.exists() || (!destination.exists() && destination.mkdirs())) { - for (Path f : files) { - File file = f.toFile(); - if (file.isFile()) { - FileUtils.copyFileToDirectory(file, destination); - } else if (file.isDirectory()) { - FileUtils.copyDirectoryToDirectory(file, destination); + for (Path file : files) { + Path newFile = targetDir.resolve(source.relativize(file)); + if (Files.isRegularFile(file)) { + FileUtils.writeLines(newFile.toFile(), Files.readAllLines(file), System.lineSeparator()); + } else if (Files.isDirectory(file)) { + FileUtils.copyDirectoryToDirectory(file.toFile(), newFile.getParent().toFile()); } } } } - static public void clearDirectory(Path directory) throws GitException { - try { - List files = Files.list(directory).collect(Collectors.toList()); - removeAll(files); - } catch (IOException | GitException e) { - throw new GitException("error while removing"); - } + static public void clearDirectory(Path directory) throws IOException { + List files = Files.list(directory).collect(Collectors.toList()); + removeAll(files); } - static public void removeAll(List files) throws GitException { - try { - for (Path file : files) { - if (Files.isRegularFile(file)) { - deleteFile(file); - } else { - clearDirectory(file); - Files.deleteIfExists(file); - } + static public void removeAll(List files) throws IOException { + for (Path file : files) { + if (Files.isDirectory(file)) { + clearDirectory(file); } - } catch (IOException e) { - throw new GitException(e.getMessage()); + Files.deleteIfExists(file); } } - static public boolean checkFilesExist(List files, boolean verbose) { + static public boolean checkFilesExist(List files) { for (Path file : files) { if (!Files.exists(file)) { - if(verbose) { - System.out.println("fatal: pathspec " + file.getFileName() + " did not match any files"); - } + System.out.println("fatal: pathspec " + file.getFileName() + " did not match any files"); return false; } } return true; } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java index f1cfc2f..1c932db 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java @@ -1,13 +1,19 @@ package ru.ifmo.git.entities; import picocli.CommandLine; + import ru.ifmo.git.commands.GitCommand; import ru.ifmo.git.util.*; import java.io.IOException; + import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; + +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -17,7 +23,6 @@ public class GitManager { private GitClerk clerk; private GitFileKeeper fileKeeper; - private static final String ENCODING = "UTF-8"; private static final String sep = System.getProperty("line.separator"); public GitManager(Path directory) { @@ -26,10 +31,6 @@ public GitManager(Path directory) { fileKeeper = new GitFileKeeper(tree); } - public GitClerk clerk() { - return clerk; - } - public GitTree tree() { return tree; } @@ -37,10 +38,6 @@ public GitTree tree() { public CommandResult executeCommand(CommandLine commandLine) { GitCommand command = commandLine.getCommand(); return command.execute(this); -// if(commandLine.getCommand() instanceof Init) { -// System.out.println("INIT"); -// Init initCommand = (Init) commandLine.getCommand(); -// } } public CommandResult init() throws GitException { @@ -52,7 +49,7 @@ public CommandResult init() throws GitException { clerk.writeHeadInfo(new HeadInfo()); } catch (IOException e) { String msg = "unable to create repository in " + tree.repo(); - return new CommandResult(ExitStatus.FAILURE, msg); + return new CommandResult(ExitStatus.FAILURE, msg, e); } } else { message.write("reinitialized existing "); @@ -61,27 +58,18 @@ public CommandResult init() throws GitException { return new CommandResult(ExitStatus.SUCCESS, message); } - public CommandResult add(List files) throws GitException { - try { - GitFileKeeper.copyAll(files, tree.index()); - } catch (IOException e) { - throw new GitException(e.getMessage()); - } - return new CommandResult(ExitStatus.SUCCESS, "l_git: add: done!"); + public CommandResult add(List files) throws IOException { + GitFileKeeper.copyAll(files, tree.repo(), tree.index()); + return new CommandResult(ExitStatus.SUCCESS, "add: done!"); } - public CommandResult commit(String message) throws GitException { - CommitInfo commitInfo; - try { - commitInfo = clerk.fillCommitInfo(message); - List references = GitEncoder.formCommitReferences(commitInfo.hash, tree.index()); - fileKeeper.saveCommit(references); - clerk.writeLog(commitInfo); - clerk.changeHeadInfo(commitInfo.hash); - } catch (IOException e) { - throw new GitException(e.getMessage()); - } - return new CommandResult(ExitStatus.SUCCESS, "l_git: commit: done!"); + public CommandResult commit(String message) throws GitException, IOException { + CommitInfo commitInfo = clerk.fillCommitInfo(message); + List references = GitEncoder.formCommitReferences(commitInfo.hash, tree.index()); + fileKeeper.saveCommit(references); + clerk.writeLog(commitInfo); + clerk.changeHeadInfo(commitInfo.hash); + return new CommandResult(ExitStatus.SUCCESS, "commit: done!"); } public CommandResult log(String revision) throws GitException { @@ -104,8 +92,8 @@ public boolean test(CommitInfo commitInfo) { } } ).collect(Collectors.toList()); - if(history.size() == 0) { - String failMessage = "l_git: log: '" + revision + "' unknown revision"; + if (history.size() == 0) { + String failMessage = "log: '" + revision + "' unknown revision"; return new CommandResult(ExitStatus.FAILURE, failMessage); } Message logContent = new Message(); @@ -113,57 +101,50 @@ public boolean test(CommitInfo commitInfo) { return new CommandResult(ExitStatus.SUCCESS, logContent); } - public CommandResult reset(String revision) throws GitException { + public CommandResult reset(String revision) throws GitException, IOException { if (clerk.getHeadInfo().currentHash.equals(revision)) { - return new CommandResult(ExitStatus.FAILURE, "reset: already on commit " + revision); + return new CommandResult(ExitStatus.FAILURE, + "reset: already on commit " + revision); } - try{ - Optional commit = fileKeeper.findFileInStorage(revision); - if (commit.isPresent()) { - Path commitFile = commit.get(); - List references = GitDecoder.formCommitReferences(commitFile, fileKeeper); - GitFileKeeper.clearDirectory(tree.index()); - fileKeeper.restoreCommit(references, tree.index()); - clerk.changeHeadInfo(revision); - return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); - } - } catch (IOException e) { - throw new GitException(e.getMessage()); + Optional commit = fileKeeper.findFileInStorage(revision); + if (commit.isPresent()) { + Path commitFile = commit.get(); + List references = GitDecoder.formCommitReferences(commitFile, fileKeeper); + GitFileKeeper.clearDirectory(tree.index()); + fileKeeper.restoreCommit(references, tree.index()); + clerk.changeHeadInfo(revision); + return new CommandResult(ExitStatus.SUCCESS, "reset: done!"); } - String failMessage = "l_git: reset: '" + revision + "' unknown revision"; + String failMessage = "reset: '" + revision + "' unknown revision"; return new CommandResult(ExitStatus.FAILURE, failMessage); } - public CommandResult checkout(String revision) throws GitException { + public CommandResult checkout(String revision) throws GitException, IOException { if (clerk.getHeadInfo().currentHash.equals(revision)) { - return new CommandResult(ExitStatus.FAILURE, "reset: already on commit " + revision); + return new CommandResult(ExitStatus.FAILURE, + "checkout: already on commit " + revision); } - try { - Optional commit = fileKeeper.findFileInStorage(revision); - if (commit.isPresent()) { - Path commitFile = commit.get(); - List references = GitDecoder.formCommitReferences(commitFile, fileKeeper); - fileKeeper.restoreCommit(references, tree.repo()); - clerk.changeHeadInfo(revision); - } - } catch (IOException e) { - throw new GitException(e.getMessage()); + Optional commit = fileKeeper.findFileInStorage(revision); + if (commit.isPresent()) { + Path commitFile = commit.get(); + List references = GitDecoder.formCommitReferences(commitFile, fileKeeper); + GitFileKeeper.clearDirectory(tree.index()); + fileKeeper.restoreCommit(references, tree.index()); + GitFileKeeper.copyAll(Files.list(tree.index()).collect(Collectors.toList()), + tree.index(), tree.repo()); + clerk.changeHeadInfo(revision); } return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); } - public CommandResult checkout(List files) throws GitException { + public CommandResult checkout(List files) throws IOException { files = files.stream() .map(f -> tree.index().resolve(tree.repo().relativize(f))) .collect(Collectors.toList()); - if(!GitFileKeeper.checkFilesExist(files, true)) { + if (!GitFileKeeper.checkFilesExist(files)) { return new CommandResult(ExitStatus.FAILURE, ""); } - try{ - GitFileKeeper.copyAll(files, tree.repo()); - } catch (IOException e) { - throw new GitException(e.getMessage()); - } + GitFileKeeper.copyAll(files, tree.index(), tree.repo()); return new CommandResult(ExitStatus.SUCCESS, "checkout: done!"); } @@ -171,12 +152,12 @@ public CommandResult checkoutBranch(String branch) throws GitException { return new CommandResult(ExitStatus.SUCCESS, "kek"); } - public CommandResult status() throws GitException { + public CommandResult status() throws GitException, IOException { HeadInfo headInfo = clerk.getHeadInfo(); Message info = new Message(); - info.write("On branch " + headInfo.branchName + GitClerk.sep); + info.write("On branch " + headInfo.branchName + sep); Map fileToStatus = clerk.compareRepoAndIndex(); - if(fileToStatus.isEmpty()) { + if (fileToStatus.isEmpty()) { info.write("No changed files"); } else { for (Map.Entry e : fileToStatus.entrySet()) { @@ -189,19 +170,15 @@ public CommandResult status() throws GitException { return new CommandResult(ExitStatus.SUCCESS, info); } - public CommandResult remove(List files) { - try { - List filesInIndex = files.stream() - .map(f -> tree.index().resolve(tree.repo().relativize(f))) - .collect(Collectors.toList()); - GitFileKeeper.removeAll(filesInIndex); - List filesInCWD = files.stream() - .map(tree.repo()::resolve) - .collect(Collectors.toList()); - GitFileKeeper.removeAll(filesInCWD); - } catch (GitException e) { - return new CommandResult(ExitStatus.ERROR, "rm: " + e.getMessage()); - } + public CommandResult remove(List files) throws IOException { + List filesInIndex = files.stream() + .map(f -> tree.index().resolve(tree.repo().relativize(f))) + .collect(Collectors.toList()); + GitFileKeeper.removeAll(filesInIndex); +// List filesInCWD = files.stream() +// .map(tree.repo()::resolve) +// .collect(Collectors.toList()); +// GitFileKeeper.removeAll(filesInCWD); return new CommandResult(ExitStatus.SUCCESS, "rm: done!"); } diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java b/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java index 5f77784..11fd833 100644 --- a/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java +++ b/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java @@ -1,7 +1,9 @@ package ru.ifmo.git.entities; import java.io.IOException; -import java.nio.file.*; + +import java.nio.file.Files; +import java.nio.file.Path; public class GitTree { @@ -12,7 +14,7 @@ public class GitTree { private Path indexDir; private Path headFile; - public GitTree(Path repository) { + GitTree(Path repository) { setRepository(repository); } @@ -25,7 +27,7 @@ private void setRepository(Path repository) { indexDir = metaDir.resolve("index"); } - public void createGitTree() throws IOException { + void createGitTree() throws IOException { metaDir = Files.createDirectory(rootDir.resolve(".l_git")); headFile = Files.createFile(metaDir.resolve("HEAD")); logDir = Files.createDirectory(metaDir.resolve("log")); @@ -33,31 +35,32 @@ public void createGitTree() throws IOException { indexDir = Files.createDirectory(metaDir.resolve("index")); } - public Path repo() { + Path repo() { return rootDir; } - public Path index() { + Path index() { return indexDir; } - public Path log() { + Path log() { return logDir; } - public Path storage() { + Path storage() { return storageDir; } - public Path head() { + Path head() { return headFile; } - public Path git() { + Path git() { return metaDir; } - + public boolean exists() { return Files.exists(metaDir); } + } diff --git a/task1_git/src/main/java/ru/ifmo/git/executors/GitExecutor.java b/task1_git/src/main/java/ru/ifmo/git/executors/GitExecutor.java deleted file mode 100644 index 6b4e9e6..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/executors/GitExecutor.java +++ /dev/null @@ -1,9 +0,0 @@ -package ru.ifmo.git.executors; - -import ru.ifmo.git.commands.GitCommand; -import ru.ifmo.git.entities.GitManager; -import ru.ifmo.git.util.CommandResult; - -public interface GitExecutor { - CommandResult execute(GitManager manager, GitCommand command); -} diff --git a/task1_git/src/main/java/ru/ifmo/git/executors/InitExecutor.java b/task1_git/src/main/java/ru/ifmo/git/executors/InitExecutor.java deleted file mode 100644 index 642c6b1..0000000 --- a/task1_git/src/main/java/ru/ifmo/git/executors/InitExecutor.java +++ /dev/null @@ -1,33 +0,0 @@ -//package ru.ifmo.git.executors; -// -//import ru.ifmo.git.commands1.GitCommand; -//import ru.ifmo.git.commands1.Init; -//import ru.ifmo.git.entities.GitManager; -//import ru.ifmo.git.util.CommandResult; -//import ru.ifmo.git.util.ExitStatus; -//import ru.ifmo.git.util.HeadInfo; -//import ru.ifmo.git.util.Message; -// -//import java.io.IOException; -// -//public class InitExecutor implements GitExecutor { -// -// @Override -// public CommandResult execute(GitManager manager, GitCommand command) { -// Message message = new Message(); -// if (!manager.tree().exists()) { -// try { -// manager.tree().createGitTree(); -// message.write("initialized empty "); -// manager.clerk().writeHeadInfo(new HeadInfo()); -// } catch (IOException e) { -// String msg = "unable to create repository in " + tree.repo(); -// return new CommandResult(ExitStatus.FAILURE, msg); -// } -// } else { -// message.write("reinitialized existing "); -// } -// message.write("lGit repository in " + tree.repo()); -// return new CommandResult(ExitStatus.SUCCESS, message); -// } -//} diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java b/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java index dc33213..20e7528 100644 --- a/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java +++ b/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java @@ -4,6 +4,7 @@ public class CommandResult { private ExitStatus status; private Message message; + private Throwable error; public CommandResult(ExitStatus status) { this.status = status; @@ -20,6 +21,12 @@ public CommandResult(ExitStatus status, String message) { this.message = new Message(message); } + public CommandResult(ExitStatus status, String message, Throwable error) { + this.status = status; + this.message = new Message(message); + this.error = error; + } + public ExitStatus getStatus() { return status; } @@ -40,4 +47,21 @@ public void setMessage(String message) { this.message = new Message(message); } + public void setError(Throwable error) { + this.error = error; + } + + public Throwable getError() { + return error; + } + + public void print() { + if (status != ExitStatus.SUCCESS) { + System.out.println("Exit with code " + status); + } + System.out.println(message.read()); + if(error != null) { + error.printStackTrace(); + } + } } From 00dc5881ac3526def34833e4b4a53d95ec3aa40f Mon Sep 17 00:00:00 2001 From: lergor Date: Mon, 15 Oct 2018 04:35:54 +0300 Subject: [PATCH 12/14] add help info --- task1_git/src/main/java/ru/ifmo/git/LGit.java | 14 ++++++++------ .../src/main/java/ru/ifmo/git/commands/Add.java | 8 ++++++++ .../main/java/ru/ifmo/git/commands/Checkout.java | 7 +++++++ .../src/main/java/ru/ifmo/git/commands/Commit.java | 7 +++++++ .../src/main/java/ru/ifmo/git/commands/Init.java | 8 ++++++++ .../src/main/java/ru/ifmo/git/commands/Log.java | 8 ++++++++ .../src/main/java/ru/ifmo/git/commands/Remove.java | 8 ++++++++ .../src/main/java/ru/ifmo/git/commands/Reset.java | 8 ++++++++ .../src/main/java/ru/ifmo/git/commands/Status.java | 8 ++++++++ 9 files changed, 70 insertions(+), 6 deletions(-) diff --git a/task1_git/src/main/java/ru/ifmo/git/LGit.java b/task1_git/src/main/java/ru/ifmo/git/LGit.java index 9faa197..074a030 100644 --- a/task1_git/src/main/java/ru/ifmo/git/LGit.java +++ b/task1_git/src/main/java/ru/ifmo/git/LGit.java @@ -14,20 +14,22 @@ public class LGit { private static Path cwd() { -// return Paths.get(System.getProperty("user.dir")); - return Paths.get("/home/valeriya/Desktop/AU/III/JAVA_II/task1_git/kek"); + return Paths.get(System.getProperty("user.dir")); } public static void main(String[] args) { CommandLine commandLine = new CommandLine(new Git()); try { List parsed = commandLine.parse(args); - - // TODO git help - + if (parsed.size() == 2) { + CommandLine command = parsed.get(1); GitManager manager = new GitManager(cwd()); - CommandResult result = manager.executeCommand(parsed.get(1)); + if (command.isUsageHelpRequested()) { + command.usage(System.out); + return; + } + CommandResult result = manager.executeCommand(command); result.print(); } else { commandLine.usage(System.out); diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java index c933bd1..591c222 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Add.java @@ -1,6 +1,7 @@ package ru.ifmo.git.commands; import picocli.CommandLine.Command; +import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; import java.io.IOException; @@ -20,6 +21,13 @@ ) public class Add implements GitCommand { + @Option( + names = {"-h", "--help"}, + usageHelp = true, + description = "Display more info about command add." + ) + boolean usageHelpRequested; + @Parameters(arity = "*", paramLabel = "") private List files; diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java index 8fc49c4..499d7f0 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java @@ -20,6 +20,13 @@ ) public class Checkout implements GitCommand { + @Option( + names = {"-h", "--help"}, + usageHelp = true, + description = "Display more info about command checkout." + ) + boolean usageHelpRequested; + @Parameters(arity = "?", paramLabel = "") private String revision; diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java index 9e945b9..740b356 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java @@ -16,6 +16,13 @@ ) public class Commit implements GitCommand { + @Option( + names = {"-h", "--help"}, + usageHelp = true, + description = "Display more info about command commit." + ) + boolean usageHelpRequested; + @Option( names = {"-m", "--message"}, arity = "?", diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java index 52b334f..b153df6 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Init.java @@ -1,6 +1,7 @@ package ru.ifmo.git.commands; import picocli.CommandLine.Command; +import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; import java.nio.file.Path; @@ -17,6 +18,13 @@ ) public class Init implements GitCommand { + @Option( + names = {"-h", "--help"}, + usageHelp = true, + description = "Display more info about command init." + ) + boolean usageHelpRequested; + @Parameters(arity = "?", paramLabel = "directory") private Path repositoryDirectory; diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java index 20aa5e9..c397454 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Log.java @@ -1,6 +1,7 @@ package ru.ifmo.git.commands; import picocli.CommandLine.Command; +import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; import ru.ifmo.git.entities.GitManager; @@ -14,6 +15,13 @@ ) public class Log implements GitCommand { + @Option( + names = {"-h", "--help"}, + usageHelp = true, + description = "Display more info about command log." + ) + boolean usageHelpRequested; + @Parameters( arity = "?", paramLabel = "", diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java index 38d7ad1..e8966a4 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java @@ -1,6 +1,7 @@ package ru.ifmo.git.commands; import picocli.CommandLine.Command; +import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; import java.io.IOException; @@ -19,6 +20,13 @@ ) public class Remove implements GitCommand { + @Option( + names = {"-h", "--help"}, + usageHelp = true, + description = "Display more info about command rm." + ) + boolean usageHelpRequested; + @Parameters(arity = "*", paramLabel = "") private List files; diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java index 3e7bf7a..0f6557a 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java @@ -1,6 +1,7 @@ package ru.ifmo.git.commands; import picocli.CommandLine.Command; +import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; import java.io.IOException; @@ -16,6 +17,13 @@ ) public class Reset implements GitCommand { + @Option( + names = {"-h", "--help"}, + usageHelp = true, + description = "Display more info about command reset." + ) + boolean usageHelpRequested; + @Parameters(arity = "1", paramLabel = "") private String revision; diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java index c43ec58..3433135 100644 --- a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java +++ b/task1_git/src/main/java/ru/ifmo/git/commands/Status.java @@ -1,6 +1,7 @@ package ru.ifmo.git.commands; import picocli.CommandLine.Command; +import picocli.CommandLine.Option; import java.io.IOException; @@ -15,6 +16,13 @@ ) public class Status implements GitCommand { + @Option( + names = {"-h", "--help"}, + usageHelp = true, + description = "Display more info about command checkout." + ) + boolean usageHelpRequested; + @Override public CommandResult doWork(GitManager gitManager) throws GitException, IOException { return gitManager.status(); From dfcbd8177da34497d195ff81ebb0d2b237c23ec1 Mon Sep 17 00:00:00 2001 From: lergor Date: Mon, 15 Oct 2018 04:52:20 +0300 Subject: [PATCH 13/14] make app runnable --- {task1_git => lgit}/build.gradle | 1 - .../gradle/wrapper/gradle-wrapper.properties | 2 +- {task1_git => lgit}/gradlew | 0 {task1_git => lgit}/gradlew.bat | 0 lgit/settings.gradle | 2 + .../src/main/java/ru/ifmo/git/LGit.java | 2 +- .../main/java/ru/ifmo/git/commands/Add.java | 0 .../java/ru/ifmo/git/commands/Checkout.java | 0 .../java/ru/ifmo/git/commands/Commit.java | 0 .../main/java/ru/ifmo/git/commands/Git.java | 0 .../java/ru/ifmo/git/commands/GitCommand.java | 0 .../main/java/ru/ifmo/git/commands/Init.java | 0 .../main/java/ru/ifmo/git/commands/Log.java | 0 .../java/ru/ifmo/git/commands/Remove.java | 0 .../main/java/ru/ifmo/git/commands/Reset.java | 0 .../java/ru/ifmo/git/commands/Status.java | 0 .../java/ru/ifmo/git/entities/GitClerk.java | 0 .../java/ru/ifmo/git/entities/GitDecoder.java | 0 .../java/ru/ifmo/git/entities/GitEncoder.java | 0 .../ru/ifmo/git/entities/GitFileKeeper.java | 0 .../java/ru/ifmo/git/entities/GitManager.java | 0 .../java/ru/ifmo/git/entities/GitTree.java | 0 .../main/java/ru/ifmo/git/util/BlobType.java | 0 .../java/ru/ifmo/git/util/CommandResult.java | 0 .../java/ru/ifmo/git/util/CommitInfo.java | 0 .../java/ru/ifmo/git/util/ExitStatus.java | 0 .../java/ru/ifmo/git/util/FileReference.java | 0 .../java/ru/ifmo/git/util/GitException.java | 0 .../main/java/ru/ifmo/git/util/HeadInfo.java | 0 .../main/java/ru/ifmo/git/util/Message.java | 0 task1_git/.gitignore | 32 ------------- task1_git/Readme.md | 48 ------------------- task1_git/settings.gradle | 2 - 33 files changed, 4 insertions(+), 85 deletions(-) rename {task1_git => lgit}/build.gradle (99%) rename {task1_git => lgit}/gradle/wrapper/gradle-wrapper.properties (86%) rename {task1_git => lgit}/gradlew (100%) rename {task1_git => lgit}/gradlew.bat (100%) create mode 100644 lgit/settings.gradle rename {task1_git => lgit}/src/main/java/ru/ifmo/git/LGit.java (98%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/Add.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/Checkout.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/Commit.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/Git.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/GitCommand.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/Init.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/Log.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/Remove.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/Reset.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/commands/Status.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/entities/GitClerk.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/entities/GitDecoder.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/entities/GitEncoder.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/entities/GitManager.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/entities/GitTree.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/util/BlobType.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/util/CommandResult.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/util/CommitInfo.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/util/ExitStatus.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/util/FileReference.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/util/GitException.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/util/HeadInfo.java (100%) rename {task1_git => lgit}/src/main/java/ru/ifmo/git/util/Message.java (100%) delete mode 100644 task1_git/.gitignore delete mode 100644 task1_git/Readme.md delete mode 100644 task1_git/settings.gradle diff --git a/task1_git/build.gradle b/lgit/build.gradle similarity index 99% rename from task1_git/build.gradle rename to lgit/build.gradle index 89755e9..5888999 100644 --- a/task1_git/build.gradle +++ b/lgit/build.gradle @@ -20,4 +20,3 @@ dependencies { compile group: 'commons-codec', name: 'commons-codec', version: '1.11' compile group: 'info.picocli', name: 'picocli', version: '3.6.0' } - diff --git a/task1_git/gradle/wrapper/gradle-wrapper.properties b/lgit/gradle/wrapper/gradle-wrapper.properties similarity index 86% rename from task1_git/gradle/wrapper/gradle-wrapper.properties rename to lgit/gradle/wrapper/gradle-wrapper.properties index dd32b3d..ef57f61 100644 --- a/task1_git/gradle/wrapper/gradle-wrapper.properties +++ b/lgit/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Fri Sep 14 13:38:27 MSK 2018 +#Mon Oct 15 04:46:20 MSK 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/task1_git/gradlew b/lgit/gradlew similarity index 100% rename from task1_git/gradlew rename to lgit/gradlew diff --git a/task1_git/gradlew.bat b/lgit/gradlew.bat similarity index 100% rename from task1_git/gradlew.bat rename to lgit/gradlew.bat diff --git a/lgit/settings.gradle b/lgit/settings.gradle new file mode 100644 index 0000000..8c41d34 --- /dev/null +++ b/lgit/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'l_git' + diff --git a/task1_git/src/main/java/ru/ifmo/git/LGit.java b/lgit/src/main/java/ru/ifmo/git/LGit.java similarity index 98% rename from task1_git/src/main/java/ru/ifmo/git/LGit.java rename to lgit/src/main/java/ru/ifmo/git/LGit.java index 074a030..0a78c95 100644 --- a/task1_git/src/main/java/ru/ifmo/git/LGit.java +++ b/lgit/src/main/java/ru/ifmo/git/LGit.java @@ -21,7 +21,7 @@ public static void main(String[] args) { CommandLine commandLine = new CommandLine(new Git()); try { List parsed = commandLine.parse(args); - + if (parsed.size() == 2) { CommandLine command = parsed.get(1); GitManager manager = new GitManager(cwd()); diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Add.java b/lgit/src/main/java/ru/ifmo/git/commands/Add.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/Add.java rename to lgit/src/main/java/ru/ifmo/git/commands/Add.java diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java b/lgit/src/main/java/ru/ifmo/git/commands/Checkout.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/Checkout.java rename to lgit/src/main/java/ru/ifmo/git/commands/Checkout.java diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Commit.java b/lgit/src/main/java/ru/ifmo/git/commands/Commit.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/Commit.java rename to lgit/src/main/java/ru/ifmo/git/commands/Commit.java diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Git.java b/lgit/src/main/java/ru/ifmo/git/commands/Git.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/Git.java rename to lgit/src/main/java/ru/ifmo/git/commands/Git.java diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java b/lgit/src/main/java/ru/ifmo/git/commands/GitCommand.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/GitCommand.java rename to lgit/src/main/java/ru/ifmo/git/commands/GitCommand.java diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Init.java b/lgit/src/main/java/ru/ifmo/git/commands/Init.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/Init.java rename to lgit/src/main/java/ru/ifmo/git/commands/Init.java diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Log.java b/lgit/src/main/java/ru/ifmo/git/commands/Log.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/Log.java rename to lgit/src/main/java/ru/ifmo/git/commands/Log.java diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Remove.java b/lgit/src/main/java/ru/ifmo/git/commands/Remove.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/Remove.java rename to lgit/src/main/java/ru/ifmo/git/commands/Remove.java diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Reset.java b/lgit/src/main/java/ru/ifmo/git/commands/Reset.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/Reset.java rename to lgit/src/main/java/ru/ifmo/git/commands/Reset.java diff --git a/task1_git/src/main/java/ru/ifmo/git/commands/Status.java b/lgit/src/main/java/ru/ifmo/git/commands/Status.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/commands/Status.java rename to lgit/src/main/java/ru/ifmo/git/commands/Status.java diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java b/lgit/src/main/java/ru/ifmo/git/entities/GitClerk.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/entities/GitClerk.java rename to lgit/src/main/java/ru/ifmo/git/entities/GitClerk.java diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java b/lgit/src/main/java/ru/ifmo/git/entities/GitDecoder.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/entities/GitDecoder.java rename to lgit/src/main/java/ru/ifmo/git/entities/GitDecoder.java diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java b/lgit/src/main/java/ru/ifmo/git/entities/GitEncoder.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/entities/GitEncoder.java rename to lgit/src/main/java/ru/ifmo/git/entities/GitEncoder.java diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java b/lgit/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java rename to lgit/src/main/java/ru/ifmo/git/entities/GitFileKeeper.java diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java b/lgit/src/main/java/ru/ifmo/git/entities/GitManager.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/entities/GitManager.java rename to lgit/src/main/java/ru/ifmo/git/entities/GitManager.java diff --git a/task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java b/lgit/src/main/java/ru/ifmo/git/entities/GitTree.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/entities/GitTree.java rename to lgit/src/main/java/ru/ifmo/git/entities/GitTree.java diff --git a/task1_git/src/main/java/ru/ifmo/git/util/BlobType.java b/lgit/src/main/java/ru/ifmo/git/util/BlobType.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/util/BlobType.java rename to lgit/src/main/java/ru/ifmo/git/util/BlobType.java diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java b/lgit/src/main/java/ru/ifmo/git/util/CommandResult.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/util/CommandResult.java rename to lgit/src/main/java/ru/ifmo/git/util/CommandResult.java diff --git a/task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java b/lgit/src/main/java/ru/ifmo/git/util/CommitInfo.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/util/CommitInfo.java rename to lgit/src/main/java/ru/ifmo/git/util/CommitInfo.java diff --git a/task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java b/lgit/src/main/java/ru/ifmo/git/util/ExitStatus.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/util/ExitStatus.java rename to lgit/src/main/java/ru/ifmo/git/util/ExitStatus.java diff --git a/task1_git/src/main/java/ru/ifmo/git/util/FileReference.java b/lgit/src/main/java/ru/ifmo/git/util/FileReference.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/util/FileReference.java rename to lgit/src/main/java/ru/ifmo/git/util/FileReference.java diff --git a/task1_git/src/main/java/ru/ifmo/git/util/GitException.java b/lgit/src/main/java/ru/ifmo/git/util/GitException.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/util/GitException.java rename to lgit/src/main/java/ru/ifmo/git/util/GitException.java diff --git a/task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java b/lgit/src/main/java/ru/ifmo/git/util/HeadInfo.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/util/HeadInfo.java rename to lgit/src/main/java/ru/ifmo/git/util/HeadInfo.java diff --git a/task1_git/src/main/java/ru/ifmo/git/util/Message.java b/lgit/src/main/java/ru/ifmo/git/util/Message.java similarity index 100% rename from task1_git/src/main/java/ru/ifmo/git/util/Message.java rename to lgit/src/main/java/ru/ifmo/git/util/Message.java diff --git a/task1_git/.gitignore b/task1_git/.gitignore deleted file mode 100644 index feb4217..0000000 --- a/task1_git/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -# Compiled class file -*.class - -# Log file -*.log - -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -build -.gradle -.idea -*.iml -out/ - -.m_git -kek/ \ No newline at end of file diff --git a/task1_git/Readme.md b/task1_git/Readme.md deleted file mode 100644 index a6544f7..0000000 --- a/task1_git/Readme.md +++ /dev/null @@ -1,48 +0,0 @@ -# Git - -### Description - -This repository contains simple draft of **git**. - -### Usage - -The following commands are available:
-``` -init -add -rm -status -commit -reset -log [from_revision] -checkout -checkout -r -``` - -where *<smth>* means mandatory argument while *[smth]* -implies he optional one.
-*commit* is represented as short (at least 7 symbols) or entire hash code.
-*checkout -r * is the replacement of *checkout -- *.
- -### File hierarchy - - .m_git/ - logs/ - [log_file_for_branch] - storage/ - [dir_as_hashcode] - [file] - index/ - [file] - HEAD - file with information about current state - - -### How to build and run - -In order to run this app, follow this steps: - -* clone this repository -* checkout on branch *task1_git* -* run `./gradlew installDist` -* go to the `./build/install/task1_git/bin/` -* execute `task1_git` (or `task1_git.bat` on Windows) \ No newline at end of file diff --git a/task1_git/settings.gradle b/task1_git/settings.gradle deleted file mode 100644 index dd874e4..0000000 --- a/task1_git/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'task1_git' - From e87145266a4473ee9dfcef98c511e443bab9d75c Mon Sep 17 00:00:00 2001 From: lergor Date: Mon, 15 Oct 2018 04:54:49 +0300 Subject: [PATCH 14/14] add Readme --- lgit/Readme.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 lgit/Readme.md diff --git a/lgit/Readme.md b/lgit/Readme.md new file mode 100644 index 0000000..e328909 --- /dev/null +++ b/lgit/Readme.md @@ -0,0 +1,48 @@ +# LGit + +### Description + +This repository contains simple draft of **git**. + +### Usage + +The following commands are available:
+``` +init +add +rm +status +commit +reset +log [from_revision] +checkout +checkout -r +``` + +where *<smth>* means mandatory argument while *[smth]* +implies he optional one.
+*revision* is represented as short (at least 7 symbols) or entire hash code.
+*checkout -r * is the replacement of *checkout -- *.
+ +### File hierarchy + + .l_git/ + logs/ + [log_file_for_branch] + storage/ + [dir_as_hashcode] + [file] + index/ + [file] + HEAD - file with information about current state + + +### How to build and run + +In order to run this app, follow this steps: + +* clone this repository +* checkout on branch *git_milestone_2* +* run `./gradlew installDist` +* go to the `./build/install/l_git/bin/` +* execute `l_git` (or `l_git.bat` on Windows) \ No newline at end of file