public string ToYamlString() { return(Name + (string.IsNullOrEmpty(Configuration) ? "" : Helper.ConfigurationDelimiter + Configuration) + (string.IsNullOrEmpty(Treeish) ? "" : "@" + Treeish.Replace("@", "\\@").Replace("/", "\\/"))); }
/// <summary> /// Parse a git revision string and return an object id. /// <para /> /// Currently supported is combinations of these. /// <ul> /// <li>SHA-1 - a SHA-1</li> /// <li>refs/... - a ref name</li> /// <li>ref^n - nth parent reference</li> /// <li>ref~n - distance via parent reference</li> /// <li>ref@{n} - nth version of ref</li> /// <li>ref^{tree} - tree references by ref</li> /// <li>ref^{commit} - commit references by ref</li> /// </ul> /// <para /> /// Not supported is /// <ul> /// <li>timestamps in reflogs, ref@{full or relative timestamp}</li> /// <li>abbreviated SHA-1's</li> /// </ul> /// </summary> /// <param name="revision">A git object references expression.</param> /// <returns> /// An <see cref="ObjectId"/> or null if revstr can't be resolved to any <see cref="ObjectId"/>. /// </returns> /// <exception cref="IOException">On serious errors.</exception> public ObjectId Resolve(string revision) { object oref = null; ObjectId refId = null; // [ammachado] Avoid the loop if the reference is not a special one. if (revision.IndexOfAny(new[] { '^', '~', '@' }) == -1) { return(ResolveSimple(revision)); } for (int i = 0; i < revision.Length; ++i) { switch (revision[i]) { case '^': if (refId == null) { var refstr = new string(revision.ToCharArray(0, i)); refId = ResolveSimple(refstr); if (refId == null) { return(null); } } if (i + 1 < revision.Length) { switch (revision[i + 1]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': int j; oref = MapObject(refId, null); while (oref is Tag) { var tag = (Tag)oref; refId = tag.Id; oref = MapObject(refId, null); } Commit oCom = (oref as Commit); if (oCom == null) { throw new IncorrectObjectTypeException(refId, ObjectType.Commit); } for (j = i + 1; j < revision.Length; ++j) { if (!Char.IsDigit(revision[j])) { break; } } var parentnum = new string(revision.ToCharArray(i + 1, j - i - 1)); int pnum; try { pnum = Convert.ToInt32(parentnum); } catch (FormatException) { throw new RevisionSyntaxException(revision, "Invalid commit parent number"); } if (pnum != 0) { ObjectId[] parents = oCom.ParentIds; if (pnum > parents.Length) { refId = null; } else { refId = parents[pnum - 1]; } } i = j - 1; break; case '{': int k; string item = null; for (k = i + 2; k < revision.Length; ++k) { if (revision[k] != '}') { continue; } item = new string(revision.ToCharArray(i + 2, k - i - 2)); break; } i = k; if (item != null) { if (item.Equals("tree")) { oref = MapObject(refId, null); while (oref is Tag) { var t = (Tag)oref; refId = t.Id; oref = MapObject(refId, null); } Treeish oTree = (oref as Treeish); if (oTree != null) { refId = oTree.TreeId; } else { throw new IncorrectObjectTypeException(refId, ObjectType.Tree); } } else if (item.Equals("commit")) { oref = MapObject(refId, null); while (oref is Tag) { var t = (Tag)oref; refId = t.Id; oref = MapObject(refId, null); } if (!(oref is Commit)) { throw new IncorrectObjectTypeException(refId, ObjectType.Commit); } } else if (item.Equals("blob")) { oref = MapObject(refId, null); while (oref is Tag) { var t = (Tag)oref; refId = t.Id; oref = MapObject(refId, null); } if (!(oref is byte[])) { throw new IncorrectObjectTypeException(refId, ObjectType.Commit); } } else if (string.Empty.Equals(item)) { oref = MapObject(refId, null); while (oref is Tag) { var t = (Tag)oref; refId = t.Id; oref = MapObject(refId, null); } } else { throw new RevisionSyntaxException(revision); } } else { throw new RevisionSyntaxException(revision); } break; default: oref = MapObject(refId, null); Commit oComm = (oref as Commit); if (oComm != null) { ObjectId[] parents = oComm.ParentIds; refId = parents.Length == 0 ? null : parents[0]; } else { throw new IncorrectObjectTypeException(refId, ObjectType.Commit); } break; } } else { oref = MapObject(refId, null); while (oref is Tag) { var tag = (Tag)oref; refId = tag.Id; oref = MapObject(refId, null); } Commit oCom = (oref as Commit); if (oCom != null) { ObjectId[] parents = oCom.ParentIds; refId = parents.Length == 0 ? null : parents[0]; } else { throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT); } } break; case '~': if (oref == null) { var refstr = new string(revision.ToCharArray(0, i)); refId = ResolveSimple(refstr); if (refId == null) { return(null); } oref = MapObject(refId, null); } while (oref is Tag) { var tag = (Tag)oref; refId = tag.Id; oref = MapObject(refId, null); } if (!(oref is Commit)) { throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT); } int l; for (l = i + 1; l < revision.Length; ++l) { if (!Char.IsDigit(revision[l])) { break; } } var distnum = new string(revision.ToCharArray(i + 1, l - i - 1)); int dist; try { dist = Convert.ToInt32(distnum); } catch (FormatException) { throw new RevisionSyntaxException("Invalid ancestry length", revision); } while (dist > 0) { ObjectId[] parents = ((Commit)oref).ParentIds; if (parents.Length == 0) { refId = null; break; } refId = parents[0]; oref = MapCommit(refId); --dist; } i = l - 1; break; case '@': int m; string time = null; for (m = i + 2; m < revision.Length; ++m) { if (revision[m] != '}') { continue; } time = new string(revision.ToCharArray(i + 2, m - i - 2)); break; } if (time != null) { throw new RevisionSyntaxException("reflogs not yet supported by revision parser yet", revision); } i = m - 1; break; default: if (refId != null) { throw new RevisionSyntaxException(revision); } break; } } if (refId == null) { refId = ResolveSimple(revision); } return(refId); }