···9494 else
9595 s
96969797-(* URL rewriting for known mirrors *)
9898-let rewrite_git_url url =
9999- (* Rewrite erratique.ch repos to GitHub mirrors *)
100100- let erratique_prefix = "https://erratique.ch/repos/" in
101101- if String.length url > String.length erratique_prefix &&
102102- String.sub url 0 (String.length erratique_prefix) = erratique_prefix then
103103- let rest = String.sub url (String.length erratique_prefix)
104104- (String.length url - String.length erratique_prefix) in
105105- "https://github.com/dbuenzli/" ^ rest
106106- else
107107- url
108108-10997(* Source kind selection *)
11098let source_kind_term =
11199 let git =
···331319 | Unpac.Source.GitSource g -> g.url
332320 | _ -> "https://" ^ url_str (* Fallback *)
333321 in
334334- rewrite_git_url raw_url
322322+ Unpac.Git_repo_lookup.rewrite_url raw_url
335323 in
336324337325 Format.printf " Adding %s (%d packages: %s)@."
···802790 ]
803791 in
804792 let vendor_repo_arg =
805805- let doc = "Path to the vendor git repository." in
806806- Arg.(required & opt (some string) None & info ["vendor-repo"] ~docv:"DIR" ~doc)
793793+ let doc = "Path to the vendor git repository (overrides config)." in
794794+ Arg.(value & opt (some string) None & info ["vendor-repo"] ~docv:"DIR" ~doc)
807795 in
808808- let run () config_path cache_dir resolve_deps vendor_repo package_specs =
796796+ let run () config_path cache_dir resolve_deps vendor_repo_arg package_specs =
809797 Eio_main.run @@ fun env ->
810798 let fs = Eio.Stdenv.fs env in
811799 let proc_mgr = Eio.Stdenv.process_mgr env in
812812- let vendor_path = Eio.Path.(fs / vendor_repo) in
813800814801 if package_specs = [] then begin
815802 Format.eprintf "Please specify at least one package.@.";
816803 exit 1
817804 end;
818805806806+ (* Load config and determine vendor repo path *)
807807+ let config = Unpac.Config.load_exn config_path in
808808+ let vendor_repo = match vendor_repo_arg with
809809+ | Some path -> path
810810+ | None -> match config.opam.vendor_repo with
811811+ | Some path -> path
812812+ | None ->
813813+ Format.eprintf "Error: No vendor-repo specified. Use --vendor-repo or set opam.vendor_repo in config.@.";
814814+ exit 1
815815+ in
816816+ let vendor_path = Eio.Path.(fs / vendor_repo) in
817817+819818 (* Initialize vendor repo if needed *)
820819 if not (Unpac.Git.is_repository vendor_path) then begin
821820 Format.printf "Initializing vendor repository at %s@." vendor_repo;
···823822 Unpac.Git.init ~proc_mgr ~cwd:vendor_path
824823 end;
825824825825+ (* Check for vendor-upstream remote in config (for fetching pre-vendored branches) *)
826826+ let vendor_upstream_url = match vendor_repo_arg with
827827+ | Some _ -> config.opam.vendor_repo (* If overriding, use config as upstream *)
828828+ | None -> None (* No separate upstream if using config directly *)
829829+ in
830830+ let has_vendor_upstream = Option.is_some vendor_upstream_url in
831831+832832+ (* Setup vendor-upstream remote if configured *)
833833+ (match vendor_upstream_url with
834834+ | Some url ->
835835+ Format.printf "Setting up vendor-upstream remote -> %s@." url;
836836+ ignore (Unpac.Git.ensure_remote ~proc_mgr ~cwd:vendor_path ~name:"vendor-upstream" ~url);
837837+ Unpac.Git.fetch ~proc_mgr ~cwd:vendor_path ~remote:"vendor-upstream"
838838+ | None -> ());
839839+826840 (* Load opam index and resolve packages *)
827841 let index = load_index ~fs ~cache_dir config_path in
828842 let compiler = get_compiler_spec config_path in
···845859846860 (* Fetch each unique dev-repo *)
847861 let fetched = ref 0 in
862862+ let from_upstream = ref 0 in
848863 let skipped = ref 0 in
849864 List.iter (fun (group : Unpac.Source.grouped_sources) ->
850865 match group.dev_repo with
···859874 | [] -> "unknown"
860875 in
861876862862- (* Get URL with rewrites *)
863863- let url =
864864- let raw_url =
865865- let first_pkg = List.hd group.packages in
866866- match first_pkg.source with
867867- | Unpac.Source.GitSource g -> g.url
868868- | _ -> ""
869869- in
870870- rewrite_git_url raw_url
877877+ let upstream_branch = "opam/upstream/" ^ name in
878878+879879+ (* Check if branch already exists from vendor-upstream *)
880880+ let found_in_vendor_upstream =
881881+ if has_vendor_upstream then
882882+ let ref_name = "vendor-upstream/" ^ upstream_branch in
883883+ Option.is_some (Unpac.Git.rev_parse ~proc_mgr ~cwd:vendor_path ref_name)
884884+ else false
871885 in
872886873873- if url = "" then begin
874874- incr skipped;
875875- Format.printf " [SKIP] No git URL for %s@." name
887887+ if found_in_vendor_upstream then begin
888888+ (* Use branch from vendor-upstream *)
889889+ let ref_point = "vendor-upstream/" ^ upstream_branch in
890890+ Unpac.Git.branch_force ~proc_mgr ~cwd:vendor_path ~name:upstream_branch ~point:ref_point;
891891+ incr fetched;
892892+ incr from_upstream;
893893+ Format.printf " [OK] %s -> %s (from vendor-upstream)@." name upstream_branch
876894 end else begin
877877- Format.printf " Fetching %s from %s@." name url;
895895+ (* Fall back to fetching from original upstream *)
896896+ let url =
897897+ let raw_url =
898898+ let first_pkg = List.hd group.packages in
899899+ match first_pkg.source with
900900+ | Unpac.Source.GitSource g -> g.url
901901+ | _ -> ""
902902+ in
903903+ Unpac.Git_repo_lookup.rewrite_url raw_url
904904+ in
878905879879- let remote = "origin-" ^ name in
880880- let upstream_branch = "upstream/" ^ name in
906906+ if url = "" then begin
907907+ incr skipped;
908908+ Format.printf " [SKIP] No git URL for %s@." name
909909+ end else begin
910910+ Format.printf " Fetching %s from %s@." name url;
881911882882- try
883883- (* Add/update remote *)
884884- ignore (Unpac.Git.ensure_remote ~proc_mgr ~cwd:vendor_path ~name:remote ~url);
912912+ let remote = "origin-" ^ name in
885913886886- (* Fetch from remote *)
887887- Unpac.Git.fetch ~proc_mgr ~cwd:vendor_path ~remote;
914914+ try
915915+ (* Add/update remote *)
916916+ ignore (Unpac.Git.ensure_remote ~proc_mgr ~cwd:vendor_path ~name:remote ~url);
888917889889- (* Detect default branch *)
890890- let default_branch = Unpac.Git.ls_remote_default_branch ~proc_mgr ~url in
891891- let ref_point = remote ^ "/" ^ default_branch in
918918+ (* Fetch from remote *)
919919+ Unpac.Git.fetch ~proc_mgr ~cwd:vendor_path ~remote;
920920+921921+ (* Detect default branch *)
922922+ let default_branch = Unpac.Git.ls_remote_default_branch ~proc_mgr ~url in
923923+ let ref_point = remote ^ "/" ^ default_branch in
892924893893- (* Create/update upstream branch *)
894894- Unpac.Git.branch_force ~proc_mgr ~cwd:vendor_path ~name:upstream_branch ~point:ref_point;
925925+ (* Create/update upstream branch *)
926926+ Unpac.Git.branch_force ~proc_mgr ~cwd:vendor_path ~name:upstream_branch ~point:ref_point;
895927896896- incr fetched;
897897- Format.printf " [OK] %s -> %s@." name upstream_branch
898898- with exn ->
899899- Format.eprintf " [FAIL] %s: %s@." name (format_error exn)
928928+ incr fetched;
929929+ Format.printf " [OK] %s -> %s@." name upstream_branch
930930+ with exn ->
931931+ Format.eprintf " [FAIL] %s: %s@." name (format_error exn)
932932+ end
900933 end
901934 ) grouped;
902935903903- Format.printf "Done: %d fetched, %d skipped@." !fetched !skipped
936936+ if has_vendor_upstream then
937937+ Format.printf "Done: %d fetched (%d from vendor-upstream), %d skipped@." !fetched !from_upstream !skipped
938938+ else
939939+ Format.printf "Done: %d fetched, %d skipped@." !fetched !skipped
904940 in
905941 let info = Cmd.info "vendor-fetch" ~doc ~man in
906942 Cmd.v info
+3-1
lib/config.ml
···1010type opam_config = {
1111 repositories : repo_config list;
1212 compiler : string option; (* e.g., "ocaml.5.4.0" or "5.4.0" *)
1313+ vendor_repo : string option; (* Path or URL to vendor repository *)
1314}
14151516type t = { opam : opam_config }
···4546let opam_config_codec =
4647 let open Tomlt in
4748 let open Table in
4848- obj (fun repositories compiler -> { repositories; compiler })
4949+ obj (fun repositories compiler vendor_repo -> { repositories; compiler; vendor_repo })
4950 |> mem "repositories" (list repo_config_codec)
5051 ~enc:(fun c -> c.repositories)
5152 |> opt_mem "compiler" string ~enc:(fun c -> c.compiler)
5353+ |> opt_mem "vendor_repo" string ~enc:(fun c -> c.vendor_repo)
5254 |> finish
53555456let codec =
+1
lib/config.mli
···1818type opam_config = {
1919 repositories : repo_config list;
2020 compiler : string option; (** Target compiler version, e.g. "5.4.0" or "ocaml.5.4.0" *)
2121+ vendor_repo : string option; (** Path or URL to vendor repository with opam/vendor/* branches *)
2122}
2223(** Opam-specific configuration. *)
2324
+32
lib/git_repo_lookup.ml
···11+(** Git repository URL lookup and rewriting.
22+33+ This module handles URL rewriting for git repositories, mapping known
44+ slow upstream URLs to faster mirrors. *)
55+66+(** Rewrite a git URL to use a faster mirror if available.
77+88+ Currently handles:
99+ - erratique.ch repos are mirrored on GitHub under dbuenzli *)
1010+let rewrite_url url =
1111+ (* Rewrite erratique.ch repos to GitHub mirrors (faster) *)
1212+ let erratique_https = "https://erratique.ch/repos/" in
1313+ let erratique_http = "http://erratique.ch/repos/" in
1414+ let github_mirror = "https://github.com/dbuenzli/" in
1515+ if String.length url > String.length erratique_https
1616+ && String.sub url 0 (String.length erratique_https) = erratique_https
1717+ then
1818+ let rest =
1919+ String.sub url (String.length erratique_https)
2020+ (String.length url - String.length erratique_https)
2121+ in
2222+ github_mirror ^ rest
2323+ else if
2424+ String.length url > String.length erratique_http
2525+ && String.sub url 0 (String.length erratique_http) = erratique_http
2626+ then
2727+ let rest =
2828+ String.sub url (String.length erratique_http)
2929+ (String.length url - String.length erratique_http)
3030+ in
3131+ github_mirror ^ rest
3232+ else url