···1+# repo-tool
2+3+A CLI tool that generates an opam repository and monorepo from a list of git repositories.
4+5+## Overview
6+7+`repo-tool` reads a text file containing git repository URLs and:
8+9+1. Clones each repository into a `vendor/` directory
10+2. Generates an opam repository structure in `opam-repository/`
11+3. Creates a `setup.sh` script to pin packages and install dependencies
12+4. Sets up dune to build everything as a monorepo
13+14+This is useful for creating a local development environment with multiple interdependent packages that may not yet be published to opam.
15+16+## Installation
17+18+```bash
19+opam install . --deps-only
20+dune build
21+dune install
22+```
23+24+Or run directly:
25+26+```bash
27+dune exec repo-tool -- <args>
28+```
29+30+## Usage
31+32+```bash
33+repo-tool INPUT_FILE [-o OUTPUT_DIR] [-v]
34+```
35+36+### Arguments
37+38+- `INPUT_FILE` - Path to a text file containing git repository URLs (one per line)
39+- `-o, --output DIR` - Output directory (default: `opam-repository`)
40+- `-v, --verbose` - Enable verbose output
41+42+### Input File Format
43+44+```
45+# Comments start with #
46+https://github.com/user/repo1.git
47+https://github.com/user/repo2.git main
48+https://tangled.org/user/repo3
49+```
50+51+Each line contains a git URL, optionally followed by a branch name.
52+53+## Output Structure
54+55+```
56+output-dir/
57+├── dune-project # Dune project file
58+├── dune # Top-level dune config
59+├── setup.sh # Setup script for opam switch
60+├── opam-repository/
61+│ ├── repo # opam repository metadata
62+│ └── packages/
63+│ └── <pkg>/
64+│ └── <pkg>.dev/
65+│ └── opam # Package opam file with url stanza
66+└── vendor/
67+ ├── dune # Lists vendor subdirectories
68+ ├── repo1/ # Cloned source code
69+ ├── repo2/
70+ └── ...
71+```
72+73+## Setting Up the Monorepo
74+75+After running `repo-tool`, set up the development environment:
76+77+```bash
78+cd output-dir
79+./setup.sh
80+```
81+82+The setup script will:
83+1. Create a local opam switch with OCaml 5.4.0
84+2. Pin all vendor packages
85+3. Install dependencies (including test dependencies)
86+4. Run `dune build`
87+88+Alternatively, run the steps manually:
89+90+```bash
91+cd output-dir
92+opam switch create . 5.4.0 -y
93+opam pin add -ny <pkg1> vendor/<repo1>
94+opam pin add -ny <pkg2> vendor/<repo2>
95+# ... for each package
96+opam install -y --deps-only --with-test <pkg1> <pkg2> ...
97+opam exec -- dune build --root .
98+```
99+100+## Using the opam Repository as an Overlay
101+102+You can also use just the generated opam repository as an overlay:
103+104+```bash
105+opam repository add local /path/to/output-dir/opam-repository
106+opam update
107+opam install <package-name>
108+```
109+110+## Incremental Updates
111+112+Running `repo-tool` again on an existing output directory will:
113+- Update existing repositories with `git pull`
114+- Clone any new repositories
115+- Regenerate the opam repository and setup script
116+117+## Example
118+119+```bash
120+# Create a repos.txt file
121+cat > repos.txt << EOF
122+https://github.com/user/ocaml-foo
123+https://github.com/user/ocaml-bar
124+https://tangled.org/user/ocaml-baz
125+EOF
126+127+# Generate the monorepo
128+repo-tool repos.txt -o my-monorepo -v
129+130+# Set up and build
131+cd my-monorepo
132+./setup.sh
133+```
···1+open Cmdliner
2+3+let input_file =
4+ let doc = "Path to the input file containing git repository URLs (one per line)." in
5+ Arg.(required & pos 0 (some file) None & info [] ~docv:"INPUT_FILE" ~doc)
6+7+let output_dir =
8+ let doc = "Output directory for the generated opam repository." in
9+ Arg.(value & opt string "opam-repository" & info [ "o"; "output" ] ~docv:"DIR" ~doc)
10+11+let verbose =
12+ let doc = "Enable verbose output." in
13+ Arg.(value & flag & info [ "v"; "verbose" ] ~doc)
14+15+let run input_file output_dir verbose =
16+ let exit_code = Repo_tool.run ~input_file ~output_dir ~verbose in
17+ exit exit_code
18+19+let run_t = Term.(const run $ input_file $ output_dir $ verbose)
20+21+let cmd =
22+ let doc = "Generate an opam repository from git repositories" in
23+ let man =
24+ [
25+ `S Manpage.s_description;
26+ `P
27+ "$(tname) reads a text file containing a list of git repository URLs \
28+ and generates an opam repository structure. Each line in the input \
29+ file should contain a git URL, optionally followed by a branch name.";
30+ `S Manpage.s_examples;
31+ `P "Create an opam repository from repos.txt:";
32+ `Pre " $(tname) repos.txt -o my-opam-repo";
33+ `P "Input file format:";
34+ `Pre
35+ " https://github.com/user/repo1.git\n\
36+ \ https://github.com/user/repo2.git main\n\
37+ \ # This is a comment";
38+ `S Manpage.s_bugs;
39+ `P "Report bugs at https://github.com/mtelvers/repo-tool/issues";
40+ ]
41+ in
42+ let info = Cmd.info "repo-tool" ~version:"0.1.0" ~doc ~man in
43+ Cmd.v info run_t
44+45+let () = exit (Cmd.eval cmd)