From f8046ed758b9cf8d3d4dac768d3d7ebb36d52329 Mon Sep 17 00:00:00 2001 From: Alex Hirsch Date: Tue, 29 Sep 2020 13:16:19 +0200 Subject: [PATCH] Add assignment1 draft --- .clang-format | 14 ++++ .editorconfig | 17 ++++ assignment1/README.md | 184 ++++++++++++++++++++++++++++++++++++++++++ assignment1/lit-test | 181 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 396 insertions(+) create mode 100644 .clang-format create mode 100644 .editorconfig create mode 100644 assignment1/README.md create mode 100755 assignment1/lit-test diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..6e93917 --- /dev/null +++ b/.clang-format @@ -0,0 +1,14 @@ +--- +BasedOnStyle: LLVM +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +UseTab: ForIndentation +AlignEscapedNewlines: DontAlign +AllowShortFunctionsOnASingleLine: Inline +AlwaysBreakTemplateDeclarations: true +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Custom +BraceWrapping: + AfterFunction: true +... diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5de72eb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = tab +indent_size = 8 + +[*.md] +indent_style = space +indent_size = 2 + +[*.{hpp,cpp,h,c}] +indent_style = tab +indent_size = 4 diff --git a/assignment1/README.md b/assignment1/README.md new file mode 100644 index 0000000..cba14d3 --- /dev/null +++ b/assignment1/README.md @@ -0,0 +1,184 @@ +# Assignment 1 (draft) + +*due on 18 November 2020* + +In this first assignment you are tasked to create a very basic version control system (VCS) similar to [Git](https://git-scm.com/) or [Mercurial](https://www.mercurial-scm.org/). + +For this assignment you are *not* allowed to work in teams. +You are not allowed to use code from other people participating in this course. +Always state the origin of non-original code and ideas. + +It is recommend to be familiar Git to understand the intensions behind the following commands. + +## `lit` + +All functionality of your VCS is bundled into one executable named `lit`. +Similar to `git`, it provides multiple *sub-commands* like `checkout` and `status`. +These sub-commands are always provided as first argument to `lit` and explained below. + +### `lit help` + +Displays a concise usage information. +Each sub-command is listed and described briefly. + +### `lit init` + +To initialize a repository run `lit init` inside some directory. +This directory is now the root of the repository. +Additionally, the VCS creates a new folder `.lit` containing all internal data. + +All files of the directory are tracked. +There is no need to explicitly add them as you'd do with Git. + +### `lit status` + +Lists all files that have been added, removed, or modified, with respect to the currently checked out commit. + +Keep the output concise, similar to `git status --short`. + +### `lit commit` + +Creates a new commit containing *all* changes. +In contrast to Git, there is no staging area. + +A commit is comprised of a unique identifier, the identifier of the previous commit, a timestamp, a message, and the recorded changes. +The message is provided to the `commit` sub-command as additional argument. + +As unique identifier use a counter (starting from 0) and prefix the value with `r` (for revision). + +``` +$ lit commit 'Commit message goes here' +Commit: r42 +Date: Mon Sep 28 23:27:53 CEST 2020 +``` + +### `lit show` + +This sub-command is used to inspect the given commit. +If no commit is specified, display the currently checked out one. + +``` +$ lit show r42 +Commit: r42 +Date: Mon Sep 28 23:27:53 CEST 2020 + +Commit message goes here + +--- a/Assets/Generic/Logic/Utils/Math.cs ++++ b/Assets/Generic/Logic/Utils/Math.cs +@@ -1,5 +1,10 @@ + using UnityEngine; + ++static class Vector2Extensions ++{ ++ public static Vector3 AsVector3(this Vector2 v) => new Vector3(v.x, v.y); ++} ++ + static class Vector3Extensions + { + public static Vector2 AsVector2(this Vector3 v) => new Vector2(v.x, v.y); +``` + +### `lit checkout` + +This resets the state of all files to the given commit's state. +All un-commited changes are dropped upon checkout. + +If no commit is specified, reset the current state to the currently checked out commit. + +You can add new branches by first checking out a previous commit, and then creating a new commit. + +### `lit merge` + +This command initiates a merge with the currently checked out commit and the specified commit. +A merge is only initiated if there are no un-commited changes. + +Auto-merging files that have been touched in both branches is not supported. +If a file has been modified in both branches, the whole file is treated as a conflict. + +If a conflict is encountered, stop the merge process and provide the respective files of the other branch as well as the common base. + +``` +$ lit merge r1 +Merge conflict(s) detected: + - robot.c + +$ ls +robot.c # currently checked out version. +robot.c.r1 # version of the other branch +robot.c.r0 # common base of both branches + +# Manually resolving the merge conflict: +$ vimdiff robot.c robot.c.r1 robot.c.r0 + +# Cleanup +$ rm robot.c.r1 robot.c.r0 + +$ lit commit +``` + +To complete the merge after manually resolving a conflict, invoke the `commit` sub-command. +To abort the merge, use `checkout`. + +### `lit log` + +Displays a graph of all commits, one line per commit. +The currently checked out commit is highlighted. + +You don't have to follow the exact format of this example: + +``` +$ lit log +o─┐ < r3 "Merge r2 with r1" +│ o r2 "Add chocolate egg dispenser" +o │ r1 "Add coin operated self destruct feature" +o─┘ r0 "First Commit" +``` + +## Implementation + +You are only allowed to use: +- C++ standard library (C++17 standard) +- C standard library (as fallback) +- POSIX standard library +- `diff` / `patch` command + +You must use CMake as build system. + +Use [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) to automatically format your code using the provided `.clang-format` configuration. +There is probably a plugin for your text editor / IDE to automate this process. + +Your VCS must store the differences (as reported by `diff -u`). +Storing a full copy of the repository's files for each commit is not allowed. +You don't need to track empty folders, yet files located in sub-directories. + +You may assume that only one instance of your VCS operators on a repository at any point in time. +Hence, you don't need to add some form of locking mechanism to prevent concurrent access. + +The executable does not depend on any additional resources (except for `diff` and `patch`). +You may assume that `diff` and `patch` are present and available via `PATH`. + +**Hint:** It may be a good idea to create a dedicated class for invoking shell commands like `diff` and `patch`. +Simply using `system(3)` may not give you enough control over the process as you also need to interactive with `stdin` / `stdout`. +Consider using `popen(3)` and getting some inspiration from [Go's `exec` package](https://golang.org/pkg/os/exec/) or [Python's `subprocess` module](https://docs.python.org/3/library/subprocess.html). + +## Testing + +Along with this specification a rudimentary test script [`lit-test`](lit-test) is provided, have a look at it. +It assumes that the `lit` executable is in your path. +Remember that you can use `bash -x` to debug the test script. + +You are encouraged to setup some more test cases for your implementation. + +## Evaluation (9 points) + +- (3) Can create new commits and checkout old ones (no branches) +- (2) Can create new branches and switch between branches +- (1) Can inspect a commit using `lit show` +- (1) Can merge two branches (no conflict) +- (1) Can merge two branches (with conflict) +- (1) Can display a graph with all commits and their relationships + +## Submission + +TBD diff --git a/assignment1/lit-test b/assignment1/lit-test new file mode 100755 index 0000000..4ed836e --- /dev/null +++ b/assignment1/lit-test @@ -0,0 +1,181 @@ +#!/bin/bash + +set -euo pipefail + +readonly TEST_DIR=$(mktemp --tmpdir --directory lit-test.XXXXXX) + +echo "== Using $TEST_DIR" +pushd "$TEST_DIR" + +echo "== Initializing repository" +lit init + +echo "== Creating the first commit" +cat >file1 <<-EOF + This is the first line of the first file. 🚀 + This is the second line of the first file. +EOF + +# Let's check the status. Should look something like this: +# Changes: +# Add file1 +lit status + +# We expect the first commit to be identified as r0. +lit commit "Add file1" + +echo "== Creating more commits" +echo >>file1 "A third line is added to the first file." + +# Let's check the status again, just to be sure. +lit status + +# This one would be r1. +lit commit "Extend file1" + +echo >>file1 "A forth line is added." + +# This should be r2. +lit commit "Extend file1 even further" + +echo "== Displaying graph" +# o < r2 Extend file1 even further +# o r1 Extend file1 +# o r0 Add file1 +lit log + +echo "== Switching to r0" +lit checkout r0 + +# Checking the file content. +diff -s file1 - <<-EOF + This is the first line of the first file. 🚀 + This is the second line of the first file. +EOF + +echo "== Switching back to r2" +lit checkout r2 + +# Checking the file content again. +diff -s file1 - <<-EOF + This is the first line of the first file. 🚀 + This is the second line of the first file. + A third line is added to the first file. + A forth line is added. +EOF + +echo "== Adding and discarding changes" +echo >>file1 "This fifth line should be gone in an instant." +lit checkout + +# Let's confirm. +diff -s file1 - <<-EOF + This is the first line of the first file. 🚀 + This is the second line of the first file. + A third line is added to the first file. + A forth line is added. +EOF + +echo "== Creating another branch" +lit checkout r0 +mkdir subfolder +cat >subfolder/file2 <<-EOF + This is the first line of the second file. + And another line in the second file. +EOF + +# This should be r3. +lit commit "Add file2" + +# o < r3 Add file2 +# │ o r2 Extend file1 even further +# │ o r1 Extend file1 +# o─┘ r0 Add file1 +lit log + +echo "== Going back" +lit checkout r2 + +# file2 should be gone. +test ! -f subfolder/file2 + +echo "== Merging (no conflict)" + +# This creates a merge commit r4. +lit merge r3 + +# file2 should now be present. +diff -s subfolder/file2 <<-EOF + This is the first line of the second file. + And another line in the second file. +EOF + +# o─┐ < r4 Merge r3 into r2 +# │ o r3 Add file2 +# o │ r2 Extend file1 even further +# o │ r1 Extend file1 +# o─┘ r0 Add file1 +lit log + +echo "== Setting up a conflict" +echo >>file1 "Fifth line ontop of r4." +lit commit "Extend file1 one way" # r5 + +lit checkout r3 +echo >>file1 "Third line ontop of r3." +lit commit "Extend file1 another way" # r6 + +# o < r6 Extend file1 another way +# o │ r5 Extend file1 one way +# o─┤ r4 Merge r3 into r2 +# │ o r3 Add file2 +# o │ r2 Extend file1 even further +# o │ r1 Extend file1 +# o─┘ r0 Add file1 +lit log + +# Going back and merging. +lit checkout r5 +lit merge r6 || true + +# Let's check all file versions: +# Current commit +diff -s file1 - <<-EOF + This is the first line of the first file. 🚀 + This is the second line of the first file. + A third line is added to the first file. + A forth line is added. + Fifth line ontop of r4. +EOF + +# other breanch +diff -s file1.r6 - <<-EOF + This is the first line of the first file. 🚀 + This is the second line of the first file. + Third line ontop of r3. +EOF + +# common base +diff -s file1.r3 - <<-EOF + This is the first line of the first file. 🚀 + This is the second line of the first file. +EOF + +# To resolve the conflict, we simply take the version of the current commit. +rm file1.r6 file1.r3 + +lit commit # r7 + +# o─┐ < r7 Merge r6 into r5 +# │ o r6 Extend file1 another way +# o │ r5 Extend file1 one way +# o─┤ r4 Merge r3 into r2 +# │ o r3 Add file2 +# o │ r2 Extend file1 even further +# o │ r1 Extend file1 +# o─┘ r0 Add file1 +lit log + +echo "== Cleanup" +popd +rm -r "$TEST_DIR"