···1616 let doc = "Enable verbose output." in
1717 Arg.(value & flag & info [ "v"; "verbose" ] ~doc)
18181919-let run input_file opam_overlay output_dir verbose =
2020- let exit_code = Repo_tool.run ~input_file ~opam_overlay ~output_dir ~verbose in
1919+let use_submodules =
2020+ let doc = "Add vendored repositories as git submodules instead of cloning them. This initializes the output directory as a git repository if needed." in
2121+ Arg.(value & flag & info [ "submodules" ] ~doc)
2222+2323+let run input_file opam_overlay output_dir use_submodules verbose =
2424+ let exit_code = Repo_tool.run ~input_file ~opam_overlay ~output_dir ~use_submodules ~verbose in
2125 exit exit_code
22262323-let run_t = Term.(const run $ input_file $ opam_overlay $ output_dir $ verbose)
2727+let run_t = Term.(const run $ input_file $ opam_overlay $ output_dir $ use_submodules $ verbose)
24282529let cmd =
2630 let doc = "Generate an opam repository from git repositories" in
···3842 `Pre " $(tname) --opam-overlay ~/opam-repo -o my-opam-repo";
3943 `P "Combine both sources (deduplicates by URL):";
4044 `Pre " $(tname) repos.txt --opam-overlay ~/opam-repo -o my-opam-repo";
4545+ `P "Use git submodules instead of cloning:";
4646+ `Pre " $(tname) repos.txt --submodules -o my-opam-repo";
4147 `P "Input file format:";
4248 `Pre
4349 " https://github.com/user/repo1.git\n\
+73-2
lib/repo_tool.ml
···6262 Unix.mkdir path 0o755
6363 end
64646565+let is_git_repo dir =
6666+ let git_dir = Filename.concat dir ".git" in
6767+ Sys.file_exists git_dir
6868+6969+let init_git_repo dir =
7070+ if not (is_git_repo dir) then begin
7171+ log "Initializing git repository in %s" dir;
7272+ let cmd = Printf.sprintf "git -C %s init" dir in
7373+ ignore (run_command cmd)
7474+ end
7575+7676+let add_or_update_submodule ~output_dir ~vendor_dir entry =
7777+ let name = extract_repo_name entry.url in
7878+ let target = Filename.concat vendor_dir name in
7979+ let rel_path = "vendor/" ^ name in
8080+ if Sys.file_exists target then begin
8181+ log "Updating submodule %s" rel_path;
8282+ let cmd = Printf.sprintf "git -C %s submodule update --remote %s 2>/dev/null" output_dir rel_path in
8383+ match run_command cmd with
8484+ | Ok () -> Ok target
8585+ | Error _ ->
8686+ (* Try to re-add the submodule *)
8787+ log "Submodule update failed, trying to re-add %s" entry.url;
8888+ let rm_cmd = Printf.sprintf "git -C %s rm -f %s 2>/dev/null" output_dir rel_path in
8989+ ignore (run_command rm_cmd);
9090+ let rm_dir_cmd = Printf.sprintf "rm -rf %s" target in
9191+ ignore (run_command rm_dir_cmd);
9292+ let branch_args =
9393+ match entry.branch with
9494+ | Some b -> Printf.sprintf "--branch %s" b
9595+ | None -> ""
9696+ in
9797+ let add_cmd =
9898+ Printf.sprintf "git -C %s submodule add --depth 1 %s %s %s"
9999+ output_dir branch_args entry.url rel_path
100100+ in
101101+ match run_command add_cmd with
102102+ | Ok () -> Ok target
103103+ | Error msg ->
104104+ Printf.eprintf "Failed to add submodule %s: %s\n%!" entry.url msg;
105105+ Error msg
106106+ end
107107+ else begin
108108+ log "Adding submodule %s to %s" entry.url rel_path;
109109+ let branch_args =
110110+ match entry.branch with
111111+ | Some b -> Printf.sprintf "--branch %s" b
112112+ | None -> ""
113113+ in
114114+ let cmd =
115115+ Printf.sprintf "git -C %s submodule add --depth 1 %s %s %s"
116116+ output_dir branch_args entry.url rel_path
117117+ in
118118+ match run_command cmd with
119119+ | Ok () -> Ok target
120120+ | Error msg ->
121121+ Printf.eprintf "Failed to add submodule %s: %s\n%!" entry.url msg;
122122+ Error msg
123123+ end
124124+65125let clone_or_update_repo ~vendor_dir entry =
66126 let name = extract_repo_name entry.url in
67127 let target = Filename.concat vendor_dir name in
···305365 let packages = collect_all_packages vendor_dirs in
306366 create_setup_script output_dir packages
307367308308-let run ~input_file ~opam_overlay ~output_dir ~verbose:v =
368368+let run ~input_file ~opam_overlay ~output_dir ~use_submodules ~verbose:v =
309369 verbose := v;
310370 let entries =
311371 match (input_file, opam_overlay) with
···337397 let vendor_dir = Filename.concat output_dir "vendor" in
338398 mkdir_p vendor_dir;
339399 log "Using vendor directory %s" vendor_dir;
400400+ (* Initialize git repo if using submodules *)
401401+ if use_submodules then begin
402402+ init_git_repo output_dir;
403403+ Printf.printf "Using git submodules for vendor dependencies\n%!"
404404+ end;
340405 let results =
341406 List.map
342407 (fun entry ->
343343- match clone_or_update_repo ~vendor_dir entry with
408408+ let result =
409409+ if use_submodules then
410410+ add_or_update_submodule ~output_dir ~vendor_dir entry
411411+ else
412412+ clone_or_update_repo ~vendor_dir entry
413413+ in
414414+ match result with
344415 | Ok repo_path ->
345416 generate_repo_structure ~output_dir:opam_repo_dir ~repo_path ~git_url:entry.url;
346417 Ok repo_path