@@ -635,8 +635,27 @@ let init_checks ?(hard_fail_exn=true) init_config =
635
635
if hard_fail && hard_fail_exn then OpamStd.Sys. exit_because `Configuration_error
636
636
else not (soft_fail || hard_fail)
637
637
638
+ let is_git_for_windows git =
639
+ (* The resource file compiled for Git for Windows sets the ProductVersion
640
+ string to M.m.r.windows.b where M.m.r is the git version and b is the
641
+ revision number of Git for Windows. This differentiates it from very old
642
+ pre-GfW builds and also from Cygwin/MSYS2 builds of Git (which don't have
643
+ version blocks at all). The resource file is not localised cf.:
644
+ - https://github.com/git/git/blob/master/git.rc#L7
645
+ - https://github.com/git-for-windows/git/blob/main/SECURITY.md#L45
646
+ - https://github.com/git/git/blob/master/GIT-VERSION-GEN#L15
647
+ *)
648
+ match OpamStubs. getVersionInfo git with
649
+ | Some {OpamStubsTypes. strings =
650
+ [(_, {productVersionString = Some version; _})]; _} ->
651
+ begin
652
+ try Scanf. sscanf version " %u.%u.%u.windows.%u%!" (fun _ _ _ _ -> true )
653
+ with Scanf. Scan_failure _ | Failure _ | End_of_file -> false
654
+ end
655
+ | _ -> false
656
+
638
657
let git_for_windows_check =
639
- if not Sys. win32 && not Sys. cygwin then fun ?git_location :_ () -> None else
658
+ if not Sys. win32 then fun ?git_location :_ () -> None else
640
659
fun ?git_location () ->
641
660
let header () = OpamConsole. header_msg " Git" in
642
661
let contains_git p =
@@ -651,6 +670,67 @@ let git_for_windows_check =
651
670
Some (git, OpamSystem. bin_contains_bash p)
652
671
| None -> None )
653
672
in
673
+ let abort_action = " install Git for Windows." in
674
+ let gits, gfw_message, abort_action =
675
+ if gits = [] then
676
+ (* Git has not been found in PATH. See if it instead can be found in the
677
+ initial environment. This deals with the possibility that the user
678
+ has installed Git for Windows, but not restarted the terminal (so
679
+ PATH has not been updated) *)
680
+ let env = OpamStubs. get_initial_environment () in
681
+ match OpamSystem. resolve_command ~env: (Array. of_list env) " git" with
682
+ | Some git when is_git_for_windows git ->
683
+ [] , Some " It looks as though Git for Windows has been installed but \
684
+ the shell needs to be restarted. You may wish to abort and \
685
+ re-run opam init from a fresh session." ,
686
+ " restart your shell."
687
+ | _ ->
688
+ (* Git is neither in the current nor the initial PATH. There is one
689
+ further possibility: the user may have installed Git for Windows
690
+ but selected the option not to update the environment. The final
691
+ hint given searches the Windows Registry for both a system-wide
692
+ and user-specific installation and, if found, both displays a
693
+ warning suggesting that the machine be reconfigured to enable them
694
+ in PATH, but also gives the opportunity to use the git-location
695
+ mechanism to select it for opam's internal use. *)
696
+ let test_for_installation ((gits , gfw_message , abort_action ) as acc ) (hive , key ) =
697
+ let process root =
698
+ let git_location = Filename. concat root " cmd" in
699
+ let git = Filename. concat git_location " git.exe" in
700
+ if OpamSystem. resolve_command ~env: [||] git <> None
701
+ && is_git_for_windows git then
702
+ let gits =
703
+ (git, OpamSystem. bin_contains_bash git_location)::gits
704
+ and message, action =
705
+ Some " It looks as though Git for Windows has been installed, \
706
+ but configured not to put the git binary in your PATH. \
707
+ You can either abort and reconfigure your environment \
708
+ (or re-run the Git for Windows installer) to enable \
709
+ this, or you can use the menu below to have opam use \
710
+ this Git installation internally." ,
711
+ " reconfigure Git for Windows."
712
+ in
713
+ if message = None then
714
+ gits, gfw_message, action
715
+ else
716
+ gits, message, abort_action
717
+ else
718
+ acc
719
+ in
720
+ let key = Filename. concat key " GitForWindows" in
721
+ OpamStubs. readRegistry hive key " InstallPath" OpamStubsTypes. REG_SZ
722
+ |> OpamStd.Option. map_default process acc
723
+ in
724
+ let installations = [
725
+ (* Machine-wide installation *)
726
+ (OpamStubsTypes. HKEY_LOCAL_MACHINE , " SOFTWARE" );
727
+ (* User-specific installation *)
728
+ (OpamStubsTypes. HKEY_CURRENT_USER , " Software" );
729
+ ] in
730
+ List. fold_left test_for_installation (gits, None , abort_action) installations
731
+ else
732
+ gits, None , abort_action
733
+ in
654
734
let get_git_location ?git_location () =
655
735
let bin =
656
736
match git_location with
@@ -690,9 +770,10 @@ let git_for_windows_check =
690
770
gits)
691
771
@ [
692
772
`Specify , " Enter the location of installed Git" ;
693
- `Abort , " Abort initialisation to install recommended Git. " ;
773
+ `Abort , ( " Abort initialisation to " ^ abort_action) ;
694
774
]
695
775
in
776
+ OpamStd.Option. iter (OpamConsole. warning " %s\n " ) gfw_message;
696
777
OpamConsole. menu " Which Git should opam use?"
697
778
~default: `Default ~no: `Default ~options
698
779
in
@@ -711,7 +792,12 @@ let git_for_windows_check =
711
792
header () ;
712
793
get_git_location ~git_location: (OpamFilename.Dir. to_string git_location) ()
713
794
| None ->
714
- if OpamStd.Sys. tty_out then
795
+ let git_found =
796
+ match OpamSystem. resolve_command " git" with
797
+ | None -> false
798
+ | Some git -> is_git_for_windows git
799
+ in
800
+ if not git_found && OpamStd.Sys. tty_out then
715
801
(header () ;
716
802
OpamConsole. msg
717
803
" Cygwin Git is functional but can have credentials issues for private repositories, \
0 commit comments