public async Task <Tuple <Parts, TreeResponse> > TreeFrom(Parts source, bool throwsIfNotFound) { Debug.Assert(source.Type == TreeEntryTargetType.Tree); if (treeCachePerPath.TryGetValue(source.Url, out var treeResponse)) { return(treeResponse); } string sha; if (source.Path == null) { var commit = await RootCommitFrom(source); sha = commit.Tree.Sha; } else { var parentTreePart = source.ParentTreePart; var parentTreeResponse = await TreeFrom(parentTreePart, throwsIfNotFound); if (parentTreeResponse == null) { return(null); } var name = source.Path.Split('/').Last(); var treeItem = parentTreeResponse.Item2.Tree.FirstOrDefault(ti => ti.Type == TreeType.Tree && ti.Path == name); if (treeItem == null) { if (throwsIfNotFound) { throw new Exception($"[{source.Type}: {source.Url}] doesn't exist."); } return(null); } sha = treeItem.Sha; } log(string.Format("API Query - Retrieve tree '{0}' ({3}) details from '{1}/{2}'.", sha.Substring(0, 7), source.Owner, source.Repository, source.Url)); var tree = await client.Git.Tree.Get(source.Owner, source.Repository, sha); var parts = new Parts(source.Owner, source.Repository, TreeEntryTargetType.Tree, source.Branch, source.Path, tree.Sha); var treeFrom = AddToPathCache(parts, tree); AddToKnown <TreeResponse>(parts.Sha, parts.Owner, parts.Repository); foreach (var i in tree.Tree) { switch (i.Type.Value) { case TreeType.Blob: var p = parts.Combine(TreeEntryTargetType.Blob, i.Path, i.Sha); AddToPathCache(p, i); AddToKnown <Blob>(i.Sha, source.Owner, source.Repository); break; case TreeType.Tree: AddToKnown <TreeResponse>(i.Sha, parts.Owner, parts.Repository); break; default: throw new NotSupportedException(); } } return(treeFrom); }