-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNode.cs
More file actions
212 lines (190 loc) · 8.57 KB
/
Node.cs
File metadata and controls
212 lines (190 loc) · 8.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/*
Author: Maurice Marinus
Position: Symbolic Architect
Company: Symbolic Computing
Project: Source Code Management or (Simple Source Code Management)
Description: Oversimplification of source control management software
License: MIT
*/
using System;
using System.Collections.Generic;
using System.IO;
namespace suscm
{
/*
This represents the virtual storage structure of the source code repository
Each node represents a branch.
Branches are continual if it has the same name
Each branch contains a list of files and directories.
Whether or not a full instance or delta of differences are stored as system entries is up to the implementor
This obviously has an effect on the fetch command implementation
*/
public class Node
{
//TODO: remove name. Branch name only on commit
public Node(string name)
{
this.branchName = name;
this.commitedEntries = new List<SystemEntry>();
this.nodes = new List<Node>();
this.parent = null;
this.key = Guid.Empty;
}
//Every single commit has a unique key (well as unique as guid's get)
private Guid key;
private List<SystemEntry> commitedEntries;
private List<Node> nodes;
private string branchName = "";
private DateTime commitedDate;
//The parent node of the commit
private Node? parent;
//Represents each commit to a parent node
public List<Node>? Nodes => nodes;
//A list of files and folders per commit
public List<SystemEntry>? CommitedEntries => commitedEntries;
//The name of commit. Commits with the same name are seen as the same path e.g. Commits named 'main or trunk' can be seen to represent the (classically known as the) 'trunk' branch
public string BranchName => branchName;
//The date and time a commit took place
public DateTime CommitedDate => commitedDate;
public bool Commit(List<SystemEntry> systemEntries, Node parentNode, string branchName = "")
{
if (systemEntries != null)
this.commitedEntries.AddRange(systemEntries);
this.branchName = branchName;
this.commitedDate = DateTime.UtcNow;
this.key = Guid.NewGuid();
this.parent = parentNode;
if (parentNode != null)
parentNode.nodes.Add(this);
return true;
}
//Makes a localcopy of branch
public Node Checkout(bool includingHistory, bool includeChildNodes)
{
if (includingHistory && includeChildNodes) //includes up to root, current snapshot and all subnodes
{
Node tmpNode = this;
while(tmpNode != null)
{
if (tmpNode.parent == null) //we at tip of graph
{
Node clone = new Node(tmpNode.branchName);
clone.commitedDate = tmpNode.commitedDate;
clone.commitedEntries = new List<SystemEntry>();
clone.commitedEntries.AddRange(tmpNode.CommitedEntries ?? new List<SystemEntry>());
clone.key = tmpNode.key;
clone.nodes = new List<Node>();
clone.nodes.AddRange(tmpNode.nodes);
return tmpNode;
}
tmpNode = tmpNode.parent;
}
}
else if (!includingHistory && !includeChildNodes) //not up to root and no subnodes. i.e. current snapshot only
{
Node clone = new Node(this.branchName);
clone.commitedDate = this.commitedDate;
clone.commitedEntries = new List<SystemEntry>();
clone.commitedEntries.AddRange(this.CommitedEntries ?? new List<SystemEntry>());
clone.key = this.key;
//clone.parent = this.parent;
return clone;
}
else if (includingHistory && !includeChildNodes) //up to root, current snapshot and no subnodes
{
List<Node> tmpNodeStack = new List<Node>();
Node tmpNode = this;
while (tmpNode != null)
{
Node clone = new Node(tmpNode.branchName);
clone.commitedDate = tmpNode.commitedDate;
clone.commitedEntries = new List<SystemEntry>();
clone.commitedEntries.AddRange(tmpNode.CommitedEntries ?? new List<SystemEntry>());
clone.key = tmpNode.key;
clone.parent = tmpNode.parent;
tmpNodeStack.Add(clone);
tmpNode = tmpNode.parent;
}
//Simply add the current node pointer to the previous node list
for (int i = tmpNodeStack.Count-1; i >= 0; i--)
{
if (i > 0)
{
int j = i - 1;
tmpNodeStack[i].nodes.Add(tmpNodeStack[j]);
}
}
//return the last node which should be the root node which now has list of all single line nodes leading to current node
return tmpNodeStack[tmpNodeStack.Count-1];
}
else if (!includingHistory && includeChildNodes) //current snapshot and subnodes
{
Node clone = new Node(this.branchName);
clone.commitedDate = this.commitedDate;
clone.commitedEntries = new List<SystemEntry>();
clone.commitedEntries.AddRange(this.CommitedEntries ?? new List<SystemEntry>());
clone.key = this.key;
//clone.parent = this.parent;
clone.nodes = new List<Node>();
clone.nodes.AddRange(this.nodes);
return clone;
}
return null;
}
//Forking duplicates a point in repositories time and not a history from a point in time. The fork name has to be different to the existing fork and no other fork should exist with same name
public Tuple<bool, object> Fork(string name)
{
if (string.IsNullOrEmpty(name) || name == this.BranchName)
{
return new Tuple<bool, object>(false, "A fork name cannot be empty or be the same name as the current branch");
}
//Test for uniqueness of name. This is applicable only to immediate subnodes
if (this.nodes != null && this.nodes.Count > 0)
{
foreach (Node n in this.nodes)
{
if (n.branchName == name)
{
return new Tuple<bool, object>(false, "A fork with the name exists on the parent already");
}
}
}
//Do not clone sub nodes (fork is duplicating point in time and not history from a point in time)
Node clone = new Node(name);
clone.commitedDate = this.commitedDate;
clone.commitedEntries = new List<SystemEntry>();
clone.commitedEntries.AddRange(this.CommitedEntries ?? new List<SystemEntry>());
//Should key be duplicated or new'd. Going with new.
clone.key = Guid.NewGuid();
clone.parent = this.parent;
this.parent.nodes.Add(clone);
return new Tuple<bool, object>(true, null);
}
}
public class SystemEntry
{
private string name;
private FileOrDirectory fileOrDirectory;
private byte[] data;
private DateTime lastWriteTime;
public SystemEntry(string name, FileOrDirectory fileOrDirectory, DateTime lastWriteTime, byte[] data)
{
this.name = name;
this.fileOrDirectory = fileOrDirectory;
this.lastWriteTime = lastWriteTime;
if (fileOrDirectory == FileOrDirectory.File)
{
this.data = data;
}
}
public FileOrDirectory FileOrDirectory { get => fileOrDirectory; }
public string Name { get => name; }
public byte[] Data { get => data; }
public DateTime LastWriteTime { get => lastWriteTime; }
}
public enum FileOrDirectory
{
File = 0,
Directory = 1
}
}