Laboratory 6: Enumerable, LINQ and Extension Methods #
Starting code #
The lab assignment is divided into two parts.
- The first part concerns extension methods,
Enumerable, and theyieldstatement.- The second part covers LINQ queries and lambda expressions.
These parts are independent of each other and can be completed in any order.
Commit Graph #
The Repository class represents a simplified version of a version control system repository. The repository includes the following properties:
Objects: A dictionary of objects, indexed by their hash.Branches: A dictionary of branches (pointers to objects stored in the repository), indexed by the branch name.HEAD: A pointer to the current point in the change history where the user is located.Authors: A dictionary of authors, indexed by their ID.
One of the object types stored in the version control system is a commit. In our simplified model, it has a ParentHashes array containing the hashes of its parents. Note that a structure defined this way is not a tree, but a directed graph.
Implement the following extension methods:
TryGetCommit, which has ahashparameter and anoutparametercommit. It returnstrueif an object with the given hash is in the repository and is of typeCommit. Otherwise, it returnsfalse.GetCommitOrThrow, which has ahashparameter. If a commit object with the given hash is in the repository, the method returns the commit object, otherwise it throws an exception with message:$"Commit {hash} not found".
Next, implement the following extension methods:
TraverseBranchByFirstParent, which lazily returns a sequence ofCommitobjects by iterating through the first parents, starting from the object with thestartHash(a method parameter, defaulting to the value of theHEADpointer in the repository).TraverseByRevision, which works similarly toTraverseBranchByFirstParent, but iterates through theCommitobjects as defined by thepatternstring.
To implement the
TraverseByRevisionmethod, use the providedRevisionclass and its staticParsemethod. Familiarize yourself with the model representing aRevision. In our simplified model, the pattern will consist of aBaseRef, which can be:
- an object hash (e.g.,
9ea45df2a43d1df035b20e211ce771785e59e12b),- a branch name (e.g.,
master),- or the
HEADsymbol,as well as a collection of modifiers denoted by the symbols
~and^. These symbols have the following meanings:
~N, whereNis a positive integer, moves backNcommits in the history, following the first parents.^N, whereNis a positive integer, moves back one commit to a specific parent, whereNspecifies which parent it is (1-indexed).Examples:
HEAD~refers to the first parent of the object pointed to byHEAD(the same asHEAD~1,HEAD^, andHEAD^1).HEAD~2refers to the “grandparent” of the object pointed to byHEAD, following the first parent.HEAD^2refers to the second parent of the object pointed to byHEAD.The
~and^symbols can be combined, e.g.,HEAD~3^2~^2.The
TraverseByRevisionmethod should operate according to the following steps:
- Convert the input string
patterninto an instance of theRevisionclass.- Try to find the identifier (hash) corresponding to
BaseRefin the following order:
- if
BaseRefmatches a branch name – use the hash value that the branch points to,- if
BaseRefisHEAD– use the currentHEADvalue of the repository,- if
BaseRefexists as a key in the repository’s objects – treat it as a direct hash value,- otherwise – raise an error
Base reference not found.
Based on the obtained hash, retrieve the corresponding object from the repository and return it as the first element of the result sequence.
For each modifier in the
Modifierscollection, apply theApplymethod, iterating and returning subsequent commits from the repository.In case of errors while retrieving objects, raise an error.
Implement the IRevisionModifier interface for ParentModifier and AncestorModifier to simplify the implementation of TraverseByRevision. The Apply method uses the repository to lazily return a collection of object hashes according to the semantics of the implementing modifiers.
Report errors in the graph structure (missing parents/ancestors or objects not found) by throwing an exception of your choice with sample messages like:
"Commit '{hash}' not found""Commit {hash} does not have parent #{index}""Commit 'hash' has no parent"
Scoring #
TryGetCommitandGetCommitOrThrow- 1 pt.TraverseBranchByFirstParent- 1 pt.ParentModifierandAncestorModifier- 0.5 pts each.TraverseByRevision- 1.5 pts.
Repository Queries #
In this part of the assignment, we want to obtain significant information about our repository:
- Which commit had the most changed lines (additions + deletions)?
- On average, how many files do individual authors change per commit?
- Who is the author of the most commits?
- Which commit was the first to add a given file to the repository?
- Which files have the most collaborating authors?
The queries are independent of each other and can be completed in any order.
Details for each query, i.e., the information to be returned and its order, are provided in the XML comments above each method in the
RepositoryQueriesclass. Additionally, the output of each query for the sample repository is included in theoutput.txtfile.
Scoring #
Each query is worth 1.5 pts. You can receive a maximum of 7.5 pts for all queries.
Sample Repository #
The history of the sample repository is shown in the diagram below:
gitGraph
commit id: "c1"
commit id: "c2"
branch feature/users
checkout feature/users
commit id: "c3"
commit id: "c6"
commit id: "c7"
checkout main
commit id: "c4"
commit id: "c5"
merge feature/users id: "c8"
commit id: "c9"
commit id: "c10"
commit id: "c11"
commit id: "c12"Detailed information about the contents of each commit can be found in the SampleRepository.cs file.
Example solution #