Created
April 12, 2012 22:35
-
-
Save nulltoken/2371499 to your computer and use it in GitHub Desktop.
[LibGit2Sharp] *Untested* mocked proof of concept of a TreeDefinition - A building block to ease the generation of Trees in the odb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
namespace ConsoleApplication97854 | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
/* | |
Building a Tree with the following structure | |
"/path/to/another/file3" | |
"/path/to/file1" | |
"/path/to/file2" | |
*/ | |
var repo = new Repository(); | |
/* | |
* Nested version | |
*/ | |
var rootInline = | |
new TreeDefinition() | |
.Add("path", new TreeDefinition() | |
.Add("to", new TreeDefinition() | |
.Add("another", new TreeDefinition() | |
.Add("file3", "/path/another/file3")) | |
.Add("file2", "/path/to/file2") | |
.Add("file1", "/path/to/file1"))); | |
Tree inlineTree = repo.ObjectDatabase.Insert(rootInline); | |
/* | |
* Flatened version | |
*/ | |
var another = new TreeDefinition() | |
.Add("file3", "/path/another/file3"); | |
var to = new TreeDefinition() | |
.Add("another", another) | |
.Add("file2", "/path/to/file2") | |
.Add("file1", "/path/to/file1"); | |
var path = new TreeDefinition() | |
.Add("to", to); | |
var root = new TreeDefinition().Add("path", path); | |
Tree tree = repo.ObjectDatabase.Insert(root); | |
/* | |
* Non hierarchical version | |
*/ | |
var flatIsBack = new TreeDefinition2() | |
.Add("path/to/another/file3", "/path/to/another/file3") | |
.Add("path/to/file1", "/path/to/file1") | |
.Add("path/to/file2", "/path/to/file2"); | |
Tree otherTree = repo.ObjectDatabase.Insert(flatIsBack); | |
/* | |
A Tree with the following structure already has just been built in the repo | |
"/path/to/another/file3" | |
"/path/to/file1" | |
"/path/to/file2" | |
A new entry Blob "file4" is added under "/path/to". | |
We want to create a new Tree containing the previous entries and the new one | |
*/ | |
/* Easy one, but not that realistic: update the flatened TreeDefinition */ | |
to.Add("file4", "/path/to/file4"); | |
Tree newTree = repo.ObjectDatabase.Insert(root); | |
/* A bit less cheesy: Build a new TreeDefinition reusing existing Trees and Blobs */ | |
var anotherTreeEntry = tree["path/to/another"]; | |
var file1TreeEntry = tree["path/to/file1"]; | |
var file2TreeEntry = tree["path/to/file2"]; | |
var update = | |
new TreeDefinition() | |
.Add("path", new TreeDefinition() | |
.Add("to", new TreeDefinition() | |
.Add(anotherTreeEntry) | |
.Add(file2TreeEntry) | |
.Add(file1TreeEntry) | |
.Add("file4", "/path/to/file4"))); | |
Tree updatedTree = repo.ObjectDatabase.Insert(update); | |
/* Another option: let's get rid of the hierarchical approach */ | |
var update2 = new TreeDefinition2() | |
.Add(anotherTreeEntry) | |
.Add(file2TreeEntry) | |
.Add(file1TreeEntry) | |
.Add("path/to/file4", "/path/to/file4"); | |
/* Idea: | |
- Find a way to generate a TreeDefinition from a Tree (Not that complex, but could take time on a large DAG, unless it's lazily built) | |
- Signature proposal: TreeDefinition TreeDefinition.From(Tree tree); | |
- Allow Removal and Update of entries | |
- Submodules and Symlinks? | |
*/ | |
// Unfortunately this is... | |
throw new NotImplementedException(); | |
} | |
} | |
class ObjectDatabase | |
{ | |
internal readonly Repository _repo; | |
public ObjectDatabase(Repository repo) | |
{ | |
_repo = repo; | |
} | |
public bool Contains(string oid) | |
{ | |
return true; //Dummy value | |
} | |
public Blob Insert(string path) | |
{ | |
return null; //Dummy action | |
} | |
public Tree Insert(TreeDefinition td) | |
{ | |
return td.Build(this); | |
} | |
public Tree Insert(TreeDefinition2 td) | |
{ | |
return td.Build(this); | |
} | |
} | |
internal class Repository | |
{ | |
public Repository() | |
{ | |
ObjectDatabase = new ObjectDatabase(this); | |
} | |
public ObjectDatabase ObjectDatabase { get; private set; } | |
public T Lookup<T>(string sha) where T : new() | |
{ | |
return new T(); | |
} | |
} | |
internal class TreeDefinition | |
{ | |
private readonly IList<Func<ObjectDatabase, Tuple<string, string, GitObject>>> booh = new List<Func<ObjectDatabase, Tuple<string, string, GitObject>>>(); | |
/// <param name="name">Name of the Blob in the Tree to be created</param> | |
/// <param name="fullpath">Full path to a file which content will be stored in a Blob</param> | |
public TreeDefinition Add(string name, string fullpath) | |
{ | |
booh.Add((odb) => | |
{ | |
var mode = RetrieveAttributes(fullpath); | |
var entry = odb.Insert(fullpath); | |
return new Tuple<string, string, GitObject>(name, mode, entry); | |
}); | |
return this; | |
} | |
private string RetrieveAttributes(string fullpath) | |
{ | |
return "100644"; //Dummy value | |
} | |
public TreeDefinition Add(string name, Blob entry, string mode) | |
{ | |
booh.Add((odb) => new Tuple<string, string, GitObject>(name, mode, entry)); | |
return this; | |
} | |
public TreeDefinition Add(string name, Tree entry) | |
{ | |
booh.Add((odb) => new Tuple<string, string, GitObject>(name, "040000", entry)); | |
return this; | |
} | |
public TreeDefinition Add(TreeEntry entry) | |
{ | |
booh.Add((odb) => new Tuple<string, string, GitObject>(entry.Name, entry.Attributes, entry.Target)); | |
return this; | |
} | |
public TreeDefinition Add(string name, TreeDefinition definition) | |
{ | |
booh.Add((odb) => | |
{ | |
var entry = definition.Build(odb); | |
return new Tuple<string, string, GitObject>(name, "040000", entry); | |
}); | |
return this; | |
} | |
internal Tree Build(ObjectDatabase odb) | |
{ | |
NativeMethods.git_treebuilder_create(); | |
foreach (var func in booh) | |
{ | |
Tuple<string, string, GitObject> tp = func.Invoke(odb); | |
NativeMethods.git_treebuilder_insert(tp.Item1, tp.Item3.Oid, tp.Item2); | |
} | |
string tree_oid; | |
NativeMethods.git_treebuilder_write(out tree_oid); | |
NativeMethods.git_treebuilder_free(); | |
return odb._repo.Lookup<Tree>(tree_oid); | |
} | |
} | |
internal class TreeDefinition2 | |
{ | |
private readonly IList<Func<ObjectDatabase, Tuple<string, string, GitObject>>> booh = new List<Func<ObjectDatabase, Tuple<string, string, GitObject>>>(); | |
private Dictionary<string, TreeDefinition2> definitions = new Dictionary<string, TreeDefinition2>(); | |
/// <param name="targetPath">Path to the Blob within the Tree to be created</param> | |
/// <param name="fullpathOnDisk">Full path to a file which content will be stored in a Blob</param> | |
public TreeDefinition2 Add(string targetPath, string fullpathOnDisk) | |
{ | |
ProcessMultiSegmentsPath(targetPath, | |
(def, subPath) => def.Add(subPath, fullpathOnDisk), | |
name => booh.Add(odb => | |
{ | |
var mode = RetrieveAttributes(fullpathOnDisk); | |
var entry = odb.Insert(fullpathOnDisk); | |
return new Tuple<string, string, GitObject>(name, mode, entry); | |
}) | |
); | |
return this; | |
} | |
private void ProcessMultiSegmentsPath(string path, Action<TreeDefinition2, string> subPathAdder, Action<string> nameAdder) | |
{ | |
var segments = SplitPath(path); | |
// We're dealing with a name | |
if (segments.Item2 == null) | |
{ | |
nameAdder(segments.Item1); | |
return; | |
} | |
// We're dealing with a real path | |
TreeDefinition2 def = AddOrRetrieveTreeDef(segments.Item1); | |
subPathAdder(def, segments.Item2); | |
} | |
private TreeDefinition2 AddOrRetrieveTreeDef(string treeName) | |
{ | |
TreeDefinition2 def; | |
if (definitions.TryGetValue(treeName, out def)) | |
return def; | |
def = new TreeDefinition2(); | |
definitions.Add(treeName, def); | |
return def; | |
} | |
private Tuple<string, string> SplitPath(string targetPath) | |
{ | |
var segments = targetPath.Split(new [] { '/' }, 2); | |
return new Tuple<string, string>(segments[0], segments.Length == 2 ? segments[1]: null); | |
} | |
private string RetrieveAttributes(string fullpath) | |
{ | |
return "100644"; //Dummy value | |
} | |
public TreeDefinition2 Add(string targetPath, Blob entry, string mode) | |
{ | |
ProcessMultiSegmentsPath(targetPath, | |
(def, subPath) => def.Add(subPath, entry, mode), | |
name => booh.Add((odb) => new Tuple<string, string, GitObject>(targetPath, mode, entry)) | |
); | |
return this; | |
} | |
public TreeDefinition2 Add(string targetPath, Tree entry) | |
{ | |
ProcessMultiSegmentsPath(targetPath, | |
(def, subPath) => def.Add(subPath, entry), | |
name => booh.Add(odb => new Tuple<string, string, GitObject>(name, "040000", entry)) | |
); | |
return this; | |
} | |
public TreeDefinition2 Add(TreeEntry entry) | |
{ | |
ProcessMultiSegmentsPath(entry.Path, | |
(def, subPath) => | |
{ | |
if (entry.Target is Blob) | |
def.Add(subPath, (Blob)(entry.Target), entry.Attributes); | |
else | |
def.Add(subPath, (Tree)(entry.Target)); | |
}, | |
name => booh.Add((odb) => new Tuple<string, string, GitObject>(entry.Name, entry.Attributes, entry.Target)) | |
); | |
return this; | |
} | |
internal Tree Build(ObjectDatabase odb) | |
{ | |
NativeMethods.git_treebuilder_create(); | |
foreach (var func in booh) | |
{ | |
Tuple<string, string, GitObject> tp = func.Invoke(odb); | |
NativeMethods.git_treebuilder_insert(tp.Item1, tp.Item3.Oid, tp.Item2); | |
} | |
string tree_oid; | |
NativeMethods.git_treebuilder_write(out tree_oid); | |
NativeMethods.git_treebuilder_free(); | |
return odb._repo.Lookup<Tree>(tree_oid); | |
} | |
} | |
internal class Blob : GitObject | |
{ | |
public string mode; | |
} | |
internal class Tree : GitObject | |
{ | |
public TreeEntry this[string path] | |
{ | |
get { return new TreeEntry(); } | |
} | |
} | |
internal class TreeEntry | |
{ | |
public string Attributes; | |
public string Name; | |
public string Path; | |
public GitObject Target { get { return null; } } | |
} | |
internal class GitObject | |
{ | |
public string Oid; | |
} | |
internal class NativeMethods | |
{ | |
public static int git_treebuilder_create() | |
{ | |
return 0; | |
} | |
public static int git_treebuilder_insert(string filename, string id, string mode) | |
{ | |
return 0; | |
} | |
public static int git_treebuilder_write(out string sha) | |
{ | |
sha = "toto"; | |
return 0; | |
} | |
public static int git_treebuilder_free() | |
{ | |
return 0; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment