Skip to content

Commit

Permalink
Merge pull request #20 from mbarbin/graph
Browse files Browse the repository at this point in the history
Rename tree => graph
  • Loading branch information
mbarbin authored Sep 20, 2024
2 parents 1e967bf + ddbbceb commit 882c054
Show file tree
Hide file tree
Showing 18 changed files with 208 additions and 210 deletions.
23 changes: 9 additions & 14 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
## 0.0.7 (unreleased)

### Added
## 0.0.7 (2024-09-20)

### Changed

- Rename `tree` to `graph` to designate the commit graph of a repository (breaking change).
- Upgrade to `cmdlang.0.0.5`.

### Deprecated

### Fixed

- Retrieve some code coverage lost during the last release.

### Removed

## 0.0.6 (2024-09-07)

### Changed
Expand Down Expand Up @@ -48,28 +43,28 @@ Release a version compatible with the latest renames in the provider library.
### Added

- Expose gca function in the `ocaml-vcs` command line.
- Add function and tests to compute GCAs in `Vcs.Tree`.
- Add function and tests to compute GCAs in `Vcs.Graph`.

### Changed

- Rename `Vcs.Descendance.t` constructors for clarity.
- Improve `Vcs.Tree.Node` interface.
- Improve `Vcs.Tree.sexp_of_t` to help with debugging.
- Improve `Vcs.Graph.Node` interface.
- Improve `Vcs.Graph.sexp_of_t` to help with debugging.
- Rename `git_cli` library to `vcs_git_cli` for consistency.
- Remove type parameter for `Vcs.Tree.Node_kind` (simplify interface).
- Renamed constructors for root nodes in vcs trees (`Init` => `Root`).
- Remove type parameter for `Vcs.Graph.Node_kind` (simplify interface).
- Renamed constructors for root nodes in vcs graphs (`Init` => `Root`).

### Fixed

- Fix `Vcs.Tree.add_nodes` raising when adding nodes incrementally.
- Fix `Vcs.Graph.add_nodes` raising when adding nodes incrementally.

## 0.0.2 (2024-07-26)

### Added

- Add documentation website powered by Docusaurus. (#7, @mbarbin)
- Initiate a library `vcs-test-helpers` to help writing tests. (#4, @mbarbin)
- Add test showing how to do revision lookup from references using `Vcs.refs` and `Vcs.tree`.
- Add test showing how to do revision lookup from references using `Vcs.refs` and `Vcs.graph`.
- Added dependabot config for automatically upgrading action files.

### Changed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<a href="https://github.com/mbarbin/vcs/actions/workflows/deploy-doc.yml"><img src="https://github.com/mbarbin/vcs/workflows/deploy-doc/badge.svg" alt="Deploy Doc Status"/></a>
</p>

Vcs is an OCaml library for interacting with Git repositories. It provides a type-safe and direct-style API to programmatically perform Git operations - ranging from creating commits and branches, to loading and navigating commit trees in memory, computing diffs between revisions, and more.
Vcs is an OCaml library for interacting with Git repositories. It provides a type-safe and direct-style API to programmatically perform Git operations - ranging from creating commits and branches, to loading and navigating commit graphs in memory, computing diffs between revisions, and more.

Designed as an interface composed of traits, Vcs dynamically dispatches its implementation at runtime. It is currently distributed with two distinct backends: a non-blocking version built atop Eio, and a blocking variant based on OCaml's standard library. Both backends operate by executing git as an external process.

Expand Down
6 changes: 3 additions & 3 deletions doc/docs/tests/exploratory_tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ COMMANDS
git [OPTION]… [ARG]…
run the git cli

graph [OPTION]…
compute graph of current repo

init [--quiet] [OPTION]… file
initialize a new repository

Expand Down Expand Up @@ -81,9 +84,6 @@ COMMANDS
show-file-at-rev [--rev=REV] [OPTION]… file
show the contents of file at a given revision

tree [OPTION]…
compute tree of current repo

COMMON OPTIONS
--help[=FMT] (default=auto)
Show this help in format FMT. The value FMT must be one of auto,
Expand Down
2 changes: 1 addition & 1 deletion doc/src/pages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
<a href="https://github.com/mbarbin/vcs/actions/workflows/deploy-doc.yml"><img src="https://github.com/mbarbin/vcs/workflows/deploy-doc/badge.svg" alt="Deploy Doc Status"/></a>
</p>

Vcs is an OCaml library for interacting with Git repositories. It provides a type-safe and direct-style API to programmatically perform Git operations - ranging from creating commits and branches, to loading and navigating commit trees in memory, computing diffs between revisions, and more.
Vcs is an OCaml library for interacting with Git repositories. It provides a type-safe and direct-style API to programmatically perform Git operations - ranging from creating commits and branches, to loading and navigating commit graphs in memory, computing diffs between revisions, and more.

Designed as an interface composed of traits, Vcs dynamically dispatches its implementation at runtime. It is currently distributed with two distinct backends: a non-blocking version built atop Eio, and a blocking variant based on OCaml's standard library. Both backends operate by executing git as an external process.
20 changes: 10 additions & 10 deletions lib/vcs/src/tree.ml → lib/vcs/src/graph.ml
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ let tips t =

let log t = Array.mapi t.nodes ~f:(fun node _ -> log_line t node) |> Array.to_list

module Subtree = struct
module Subgraph = struct
module T = struct
[@@@coverage off]

Expand All @@ -383,14 +383,14 @@ module Subtree = struct
let is_empty { log; refs } = List.is_empty log && List.is_empty refs
end

let of_subtree { Subtree.log; refs } =
let of_subgraph { Subgraph.log; refs } =
let t = create () in
add_nodes t ~log;
set_refs t ~refs;
t
;;

let subtrees t =
let subgraphs t =
let dummy_cell = Union_find.create (-1) in
let components = Array.map t.nodes ~f:(fun _ -> dummy_cell) in
let component_id = ref 0 in
Expand All @@ -415,8 +415,8 @@ let subtrees t =
let id = Union_find.get components.(index) in
Queue.enqueue refs.(id) { Refs.Line.rev = Node_kind.rev t.$(index); ref_kind });
Array.map2_exn logs refs ~f:(fun log refs ->
{ Subtree.log = Queue.to_list log; refs = Queue.to_list refs })
|> Array.filter ~f:(fun subtree -> not (Subtree.is_empty subtree))
{ Subgraph.log = Queue.to_list log; refs = Queue.to_list refs })
|> Array.filter ~f:(fun subgraph -> not (Subgraph.is_empty subgraph))
|> Array.to_list
;;

Expand All @@ -427,7 +427,7 @@ module Summary = struct
{ refs : (Rev.t * string) list
; roots : Rev.t list
; tips : (Rev.t * string list) list
; subtrees : t list [@sexp_drop_if List.is_empty]
; subgraphs : t list [@sexp_drop_if List.is_empty]
}
[@@deriving sexp_of]
end
Expand All @@ -441,12 +441,12 @@ let rec summary t =
List.map (tips t) ~f:(fun node ->
rev t node, node_refs t node |> List.map ~f:Ref_kind.to_string)
in
let subtrees =
match subtrees t with
let subgraphs =
match subgraphs t with
| [] | [ _ ] -> []
| subtrees -> List.map subtrees ~f:(fun subtree -> summary (of_subtree subtree))
| subgraphs -> List.map subgraphs ~f:(fun subgraph -> summary (of_subgraph subgraph))
in
{ Summary.refs; roots = roots t |> List.map ~f:(fun id -> rev t id); tips; subtrees }
{ Summary.refs; roots = roots t |> List.map ~f:(fun id -> rev t id); tips; subgraphs }
;;

let check_index_exn t ~index =
Expand Down
60 changes: 30 additions & 30 deletions lib/vcs/src/tree.mli → lib/vcs/src/graph.mli
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,41 @@
(*_ <http://www.gnu.org/licenses/> and <https://spdx.org>, respectively. *)
(*_******************************************************************************)

(** Building an in-memory representation of a git tree, for queries about
history contents.
(** Building an in-memory representation of the commit graph of a git repository
for queries related to the structure of its nodes and edges.
This data structure only contains the nodes, as well as the location of
known branches (local and remotes) and tags.
The design is such that it is easy to add new nodes, and to compute the diff
of what needs to be sent to a process holding such a value in memory to
complete its view of a tree. *)
complete its view of a graph. *)

type t [@@deriving sexp_of]

(** Create an empty tree that has no nodes. *)
(** Create an empty graph that has no nodes. *)
val create : unit -> t

(** {1 Initializing the tree}
(** {1 Initializing the graph}
This part of the interface is the only part that mutates the tree. The tree
This part of the interface is the only part that mutates the graph. The graph
manipulated in memory needs to know about the nodes and refs that are present in
the git log.
The calls to the functions [add_nodes] and [set_refs] are typically handled
for you by the function [Vcs.tree], however they are exposed if you want to
manually build trees in more advanced ways (such as incrementally), or for
for you by the function [Vcs.graph], however they are exposed if you want to
manually build graphs in more advanced ways (such as incrementally), or for
testing purposes.
Adding nodes or refs to a tree does not affect the git repository. These are
Adding nodes or refs to a graph does not affect the git repository. These are
simply operations that needs to be called to feed to [t] the information
that already exists in the git log. *)

(** [add t ~log] add to [t] all the nodes from the tree log. This is idempotent
(** [add t ~log] add to [t] all the nodes from the log. This is idempotent
this doesn't add the nodes that if [t] already knows.*)
val add_nodes : t -> log:Log.t -> unit

(** [set_refs t ~refs] add to [t] all the refs from the tree log. *)
(** [set_refs t ~refs] add to [t] all the refs from the log. *)
val set_refs : t -> refs:Refs.t -> unit

(** Same as [set_refs], but one ref at a time. *)
Expand All @@ -62,17 +62,17 @@ val set_ref : t -> rev:Rev.t -> ref_kind:Ref_kind.t -> unit
(** {1 Nodes}
The node itself doesn't carry much information, rather it is simply a
pointer to a location in the tree. Thus the functions operating on nodes
typically also require to be supplied the tree.
pointer to a location in the graph. Thus the functions operating on nodes
typically also require to be supplied the graph.
For convenience to users writing algorithms on git trees, the type [t]
For convenience to users writing algorithms on git graphs, the type [t]
exposes an efficient comparable signature, meaning you can e.g. manipulate
containers indexed by nodes.
{1:ordering_invariant Ordering invariant}
An invariant that holds in the structure and on which you can rely is that
the parents of a node are always inserted in the tree before the node itself
the parents of a node are always inserted in the graph before the node itself
(from left to right), and thus if [n1 > n2] (using the node comparison
function) then you can be certain that [n1] is not a parent of [n2]. *)

Expand Down Expand Up @@ -108,21 +108,21 @@ val rev : t -> Node.t -> Rev.t
merge nodes. *)
val parents : t -> Node.t -> Node.t list

(** [prepend_parents tree node nodes] is an equivalent but more efficient
version of [parents tree node @ nodes]. It may be useful for recursive
(** [prepend_parents graph node nodes] is an equivalent but more efficient
version of [parents graph node @ nodes]. It may be useful for recursive
traversal algorithms. *)
val prepend_parents : t -> Node.t -> Node.t list -> Node.t list

(** Access the given node from the tree and return its node kind. *)
(** Access the given node from the graph and return its node kind. *)
val node_kind : t -> Node.t -> Node_kind.t

(** If the tree has refs (such as tags or branches) attached to this node,
they will all be returned by [refs tree node]. The order of the refs in
(** If the graph has refs (such as tags or branches) attached to this node,
they will all be returned by [refs graph node]. The order of the refs in
the resulting list is not specified. *)
val node_refs : t -> Node.t -> Ref_kind.t list

module Descendance : sig
(** Descendance is a relation between 2 nodes of the tree. Matching on it is
(** Descendance is a relation between 2 nodes of the graph. Matching on it is
useful for example when considering the status of a branch head with
respect to its upstream counterpart. *)
type t =
Expand All @@ -135,7 +135,7 @@ end

val descendance : t -> Node.t -> Node.t -> Descendance.t

(** Return the number of nodes the tree currently holds. *)
(** Return the number of nodes the graph currently holds. *)
val node_count : t -> int

(** {1 Refs} *)
Expand All @@ -151,7 +151,7 @@ val find_ref : t -> ref_kind:Ref_kind.t -> Node.t option
(** Find the node pointed by the rev if any. *)
val find_rev : t -> rev:Rev.t -> Node.t option

(** Tell if a revision points to a valid node of the tree. *)
(** Tell if a revision points to a valid node of the graph. *)
val mem_rev : t -> rev:Rev.t -> bool

(** {1 Roots & Tips} *)
Expand All @@ -174,7 +174,7 @@ val is_strict_ancestor : t -> ancestor:Node.t -> descendant:Node.t -> bool
val is_ancestor_or_equal : t -> ancestor:Node.t -> descendant:Node.t -> bool

(** [greatest_common_ancestors t nodes] returns the list of nodes that are the
greatest common ancestors of the nodes in the list [nodes] in the tree [t].
greatest common ancestors of the nodes in the list [nodes] in the graph [t].
A greatest common ancestor of a set of nodes is a node that is an ancestor
of all the nodes in the set and is not a strict ancestor of any other common
Expand All @@ -197,9 +197,9 @@ val log_line : t -> Node.t -> Log.Line.t
(** Rebuild the entire log. *)
val log : t -> Log.t

(** {1 Subtree} *)
(** {1 Subgraph} *)

module Subtree : sig
module Subgraph : sig
type t =
{ log : Log.t
; refs : Refs.t
Expand All @@ -209,8 +209,8 @@ module Subtree : sig
val is_empty : t -> bool
end

val subtrees : t -> Subtree.t list
val of_subtree : Subtree.t -> t
val subgraphs : t -> Subgraph.t list
val of_subgraph : Subgraph.t -> t

(** {1 Summary} *)

Expand All @@ -228,9 +228,9 @@ val summary : t -> Summary.t
We make no guarantee about the stability of node ordering across vcs
versions. The order in which nodes be inserted is not fully specified,
outside of the ordering invariant discussed {{!ordering_invariant} here}. It
is considered to be only valid for the lifetime of the tree.
is considered to be only valid for the lifetime of the graph.
This is exposed if you want to write algorithms working on tree that take
This is exposed if you want to write algorithms working on graph that take
advantage of operations working on int, if the rest of the exposed API isn't
enough for your use case. *)

Expand Down
2 changes: 1 addition & 1 deletion lib/vcs/src/non_raising.ml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ module Make (M : M) :

let log vcs ~repo_root = try_with (fun () -> Vcs0.log vcs ~repo_root)
let refs vcs ~repo_root = try_with (fun () -> Vcs0.refs vcs ~repo_root)
let tree vcs ~repo_root = try_with (fun () -> Vcs0.tree vcs ~repo_root)
let graph vcs ~repo_root = try_with (fun () -> Vcs0.graph vcs ~repo_root)

let current_branch vcs ~repo_root =
try_with (fun () -> Vcs0.current_branch vcs ~repo_root)
Expand Down
4 changes: 2 additions & 2 deletions lib/vcs/src/refs.mli
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ val remote_branches : t -> Remote_branch_name.t list
quite cheap to get all refs using {!val:Vcs.refs}, turn the result into a
map with this function, and use the map for the lookups rather than trying
to run one git command per lookup. You may also use
{!val:Vcs.Tree.find_ref} if you build the complete tree with
{!val:Vcs.tree}. *)
{!val:Vcs.Graph.find_ref} if you build the complete graph with
{!val:Vcs.graph}. *)
val to_map : t -> Rev.t Map.M(Ref_kind).t
2 changes: 1 addition & 1 deletion lib/vcs/src/vcs.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module Exn = Vcs_exn
module File_contents = File_contents
module For_test = For_test
module Git = Git
module Graph = Graph
module Log = Log
module Mock_rev_gen = Mock_rev_gen
module Mock_revs = Mock_revs
Expand All @@ -47,7 +48,6 @@ module Result = Vcs_result
module Rev = Rev
module Tag_name = Tag_name
module Trait = Trait
module Tree = Tree
module Url = Url
module User_email = User_email
module User_handle = User_handle
Expand Down
6 changes: 3 additions & 3 deletions lib/vcs/src/vcs.mli
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,16 @@ val num_status
-> changed:Num_status.Changed.t
-> Num_status.t

(** {1 Manipulating the tree in memory} *)
(** {1 Manipulating the graph in memory} *)

module Log = Log
module Ref_kind = Ref_kind
module Refs = Refs
module Tree = Tree
module Graph = Graph

val log : [> Trait.log ] t -> repo_root:Repo_root.t -> Log.t
val refs : [> Trait.refs ] t -> repo_root:Repo_root.t -> Refs.t
val tree : [> Trait.log | Trait.refs ] t -> repo_root:Repo_root.t -> Tree.t
val graph : [> Trait.log | Trait.refs ] t -> repo_root:Repo_root.t -> Graph.t

(** {1 Rev parse utils} *)

Expand Down
12 changes: 6 additions & 6 deletions lib/vcs/src/vcs0.ml
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,16 @@ let refs (Provider.T { t; handler }) ~repo_root =
|> of_result ~step:(lazy [%sexp "Vcs.refs", { repo_root : Repo_root.t }])
;;

let tree (Provider.T { t; handler }) ~repo_root =
let graph (Provider.T { t; handler }) ~repo_root =
let module L = (val Provider.Handler.lookup handler ~trait:Trait.Log) in
let module R = (val Provider.Handler.lookup handler ~trait:Trait.Refs) in
let tree = Tree.create () in
let graph = Graph.create () in
(let%bind log = L.all t ~repo_root in
let%bind refs = R.show_ref t ~repo_root in
Tree.add_nodes tree ~log;
Tree.set_refs tree ~refs;
return tree)
|> of_result ~step:(lazy [%sexp "Vcs.tree", { repo_root : Repo_root.t }])
Graph.add_nodes graph ~log;
Graph.set_refs graph ~refs;
return graph)
|> of_result ~step:(lazy [%sexp "Vcs.graph", { repo_root : Repo_root.t }])
;;

let set_user_name (Provider.T { t; handler }) ~repo_root ~user_name =
Expand Down
Loading

0 comments on commit 882c054

Please sign in to comment.