Add assignment1 draft

This commit is contained in:
Alex Hirsch 2020-09-29 13:16:19 +02:00
parent b6d70bc6b6
commit f8046ed758
4 changed files with 396 additions and 0 deletions

14
.clang-format Normal file
View File

@ -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
...

17
.editorconfig Normal file
View File

@ -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

184
assignment1/README.md Normal file
View File

@ -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

181
assignment1/lit-test Executable file
View File

@ -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"