View raw

1 (** Git data access layer. *) 2 3 module Store = Git_unix.Store 4 5 type error = 6 | Bad_request of string 7 | Not_found of string 8 | Store_error of Store.error 9 | Internal of string 10 11 val pp_error : Format.formatter -> error -> unit 12 13 (** {1 Validation} *) 14 15 val is_valid_hash_hex : string -> bool 16 val is_valid_repo_name : string -> bool 17 18 (** {1 Repository discovery and context} *) 19 20 type repository_layout = { worktree : string; git_dir : string } 21 type repository 22 23 val repositories : Config.t -> (string list, error) result 24 25 type repo_info = { repo_name : string; description : string } 26 type fs_node = Repo of repo_info | Directory of string * fs_node list 27 28 val scan_project_root : Config.t -> (fs_node list, error) result 29 val open_repository : Config.t -> string -> (repository, error) Lwt_result.t 30 val repository_name : repository -> string 31 val repository_description : repository -> string 32 val close_repository : repository -> unit Lwt.t 33 34 val head_commit_date : 35 repository -> (int64 * Git.User.tz_offset option) option Lwt.t 36 37 val head_hash_hint : Config.t -> string -> string option 38 (** Cheaply resolve the commit hash that HEAD names, using plain file reads and 39 no object store. [None] means "could not tell cheaply" — fall back to 40 opening the repository rather than conclude anything. Intended as a cache 41 key: any new commit on the served branch changes the result. *) 42 43 (** {1 Repository metadata} *) 44 45 val default_repo_description : string 46 val short_hash : string -> string 47 48 (** {1 Commits} *) 49 50 module Commit : sig 51 type user = Git.User.t 52 53 type t = { 54 hash : string; 55 tree : string; 56 parents : string list; 57 author : user; 58 committer : user; 59 message : string option; 60 } 61 62 val of_id : repository -> string -> (t, error) Lwt_result.t 63 val recent_from : repository -> string -> int -> (t list, error) Lwt_result.t 64 65 val recent_matching : 66 ?max_examined:int -> 67 repository -> 68 int -> 69 (t -> bool) -> 70 (t list * bool, error) Lwt_result.t 71 (** Walk history from HEAD, collecting up to [count] commits that satisfy the 72 predicate. The walk reads at most [max_examined] commits (default 5000), 73 so a rare predicate cannot traverse an entire large history per request. 74 The boolean is [true] when the walk stopped at that cap with history left 75 unexplored — older matches may then exist beyond the result. *) 76 end 77 78 (** {1 References} *) 79 80 module Reference : sig 81 type t = { name : string; hash : string } 82 83 val branch_name : string -> string option 84 val tag_name : string -> string option 85 val of_id : repository -> string -> (t, error) Lwt_result.t 86 end 87 88 (** {1 Entries and Trees} *) 89 90 module Entry : sig 91 type perm = Dir | File | Exec | Link | Submodule 92 type t = { hash : string; name : string; perm : perm } 93 end 94 95 module Tree : sig 96 type t = { entries : Entry.t list } 97 type tree_node = { entry : Entry.t; children : tree_node list option } 98 99 val head : repository -> (t, error) Lwt_result.t 100 val expand : repository -> t -> (tree_node list, error) Lwt_result.t 101 102 val find_path : 103 repository -> string -> ((string * string) list, error) Lwt_result.t 104 end 105 106 (** {1 Blobs} *) 107 108 module Blob : sig 109 type t = { content : string } 110 end 111 112 (** {1 Diffs} *) 113 114 module Diff : sig 115 include module type of Line_diff 116 117 val of_commit : repository -> Commit.t -> (file list, error) Lwt_result.t 118 end 119 120 (** {1 Composite lookups} *) 121 122 val blob_or_tree : 123 repository -> 124 string -> 125 ([> `Blob of Blob.t | `Tree of Tree.t ], error) Lwt_result.t 126 127 val object_at_path : 128 repository -> 129 string -> 130 ( [ `Blob of Blob.t | `Tree of Tree.t ] * (string * string) list, 131 error ) 132 Lwt_result.t 133 (** Resolve a slash-separated file path against the HEAD tree. Returns the 134 object and the trail of [(name, hash)] pairs from the root to it. Walks one 135 tree per path segment, so it is cheaper than searching for a hash with 136 {!Tree.find_path}. An empty path is a [Bad_request]; a path that names 137 nothing is [Not_found]. *) 138 139 (** {1 Repository helpers} *) 140 141 module Readme : sig 142 type t = { name : string; content : string } 143 end 144 145 module Repo : sig 146 val readme : repository -> (Readme.t option, error) Lwt_result.t 147 end 148 149 (** {1 Root helpers} *) 150 151 val read_root_readme : Config.t -> Blob.t option 152 val scan_subdirectory : Config.t -> string -> (fs_node list, error) result 153 val read_subdir_readme : Config.t -> string -> Blob.t option 154 155 (** {1 For tests} 156 157 These helpers have no callers in the server. They are exported so the test 158 suite can exercise repository discovery directly. *) 159 160 val is_repository : string -> bool 161 162 val repository_layout_or_none : string -> repository_layout option 163 (** Locate a repository's worktree and git directory. Collapses both "not a 164 repository" and "could not be inspected" to [None]. *) 165 166 val read_description_file : string -> string 167 val fallback_branch_candidates : Config.t -> string list 168