Skip to content

Commit 5a817d1

Browse files
authored
Merge pull request #5963 from dra27/gwf-menu
Improvements to `opam init` "Git" menu on Windows
2 parents 21305bb + 410a91d commit 5a817d1

10 files changed

+413
-13
lines changed

configure

+11-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure.ac

+5-4
Original file line numberDiff line numberDiff line change
@@ -342,21 +342,22 @@ default_static=no
342342
AS_CASE([$TARGET],
343343
[*-linux-musl*],[
344344
support_static=yes
345-
platform_dependant_stuff="-cclib -lstdc++ -cclib -static-libgcc -cclib -static"
345+
platform_dependent_stuff="-cclib -lstdc++ -cclib -static-libgcc -cclib -static"
346346
],
347347
[*-*-mingw32*],[
348348
support_static=yes
349-
default_static=yes
349+
AS_IF([test "x${with_private_runtime}" = "xno"],[default_static=yes])
350350
# NOTE: On Windows, the Windows specific dlls should stay dynamic for security reasons
351351
# NOTE: -l:libstdc++.a is necessary (vs. -lstdc++) as flexlink will use libstdc++.dll.a
352352
# which still depends on the DLL at runtime instead of libstdc++.a (that looks like a bug in flexlink)
353-
platform_dependant_stuff="-cclib -lopam_stubs_win32_stubs -cclib -l:libstdc++.a -cclib -l:libpthread.a -cclib -Wl,-static -cclib -ladvapi32 -cclib -lgdi32 -cclib -luser32 -cclib -lshell32 -cclib -lole32 -cclib -luuid"
353+
platform_dependent_stuff="-cclib -lopam_stubs_win32_stubs -cclib -l:libstdc++.a -cclib -l:libpthread.a -cclib -Wl,-static -cclib -ladvapi32 -cclib -lgdi32 -cclib -luser32 -cclib -lshell32 -cclib -lole32 -cclib -luuid -cclib -luserenv"
354+
AS_IF([test "x${SYSTEM}" = "xmingw"], [platform_dependent_stuff="${platform_dependent_stuff} -cclib -lwindowsapp"])
354355
])
355356
AS_CASE([${support_static},${enable_static}],
356357
[no,yes],[AC_MSG_ERROR([--enable-static is not available on this platform (${TARGET}).])],
357358
[*,auto],[enable_static=${default_static}])
358359
AS_IF([test "${enable_static}" = yes],[
359-
echo "(-noautolink -cclib -lunix -cclib -lmccs_stubs -cclib -lmccs_glpk_stubs -cclib -lsha_stubs ${platform_dependant_stuff})" > src/client/linking.sexp
360+
echo "(-noautolink -cclib -lunix -cclib -lmccs_stubs -cclib -lmccs_glpk_stubs -cclib -lsha_stubs ${platform_dependent_stuff})" > src/client/linking.sexp
360361
AC_MSG_RESULT([static])
361362
],[
362363
AC_MSG_RESULT([shared])

master_changes.md

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ users)
2323

2424
## Init
2525
* ◈ New option `opam init --cygwin-extra-packages=CYGWIN_PKGS --cygwin-internal-install`, to specify additional packages for internal Cygwin [#5930, #5964 @moyodiallo - fix #5834]
26+
* Skip Git-for-Windows menu if the Git binary resolved in PATH is Git-for-Windows [#5963 @dra27 - fix #5835]
27+
* Enhance the Git menu by warning if the user appears to need to restart the shell to pick up PATH changes [#5963 @dra27]
28+
* Include Git for Windows installations in the list of possibilities where the user instructed Git-for-Windows setup not to update PATH [#5963 @dra27]
2629

2730
## Config report
2831

@@ -164,3 +167,6 @@ users)
164167
## opam-core
165168
* `OpamStd.String`: add `split_quoted` that preserves quoted separator [#5935 @dra27]
166169
* `OpamSystem.copy_dir` and `OpamSystem.mv` may display a warning on Windows if an invalid symlink (e.g. an LXSS Junction) is found [#5953 @dra27]
170+
* `OpamStubs.getVersionInfo`: on Windows, retrives the version information block of an executable/library [#5963 @dra27]
171+
* `OpamStubs.readRegistry`: on Windows, complements `OpamStubs.writeRegistry` [#5963 @dra27]
172+
* `OpamStubs.get_initial_environment`: on Windows, returns the pristine environment for new shells [#5963 @dra27]

shell/context_flags.ml

+10-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,16 @@ match Sys.argv.(1) with
1515
print_string "i686"
1616
| "clibs" ->
1717
if Sys.win32 then
18-
print_string "(-ladvapi32 -lgdi32 -luser32 -lshell32 -lole32 -luuid)"
18+
let common =
19+
"-ladvapi32 -lgdi32 -luser32 -lshell32 -lole32 -luuid -luserenv"
20+
in
21+
if Config.system = "mingw" then
22+
(* This appears to be a packaging bug in i686-w64-mingw32, as
23+
GetFileVersionInfoEx and friends are include in the x86_64 copy of
24+
libversion.a *)
25+
Printf.printf "(%s -lwindowsapp)" common
26+
else
27+
Printf.printf "(%s)" common
1928
else
2029
print_string "()"
2130
| _ ->

src/client/opamClient.ml

+89-3
Original file line numberDiff line numberDiff line change
@@ -635,8 +635,27 @@ let init_checks ?(hard_fail_exn=true) init_config =
635635
if hard_fail && hard_fail_exn then OpamStd.Sys.exit_because `Configuration_error
636636
else not (soft_fail || hard_fail)
637637

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+
638657
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
640659
fun ?git_location () ->
641660
let header () = OpamConsole.header_msg "Git" in
642661
let contains_git p =
@@ -651,6 +670,67 @@ let git_for_windows_check =
651670
Some (git, OpamSystem.bin_contains_bash p)
652671
| None -> None)
653672
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
654734
let get_git_location ?git_location () =
655735
let bin =
656736
match git_location with
@@ -690,9 +770,10 @@ let git_for_windows_check =
690770
gits)
691771
@ [
692772
`Specify, "Enter the location of installed Git";
693-
`Abort, "Abort initialisation to install recommended Git.";
773+
`Abort, ("Abort initialisation to " ^ abort_action);
694774
]
695775
in
776+
OpamStd.Option.iter (OpamConsole.warning "%s\n") gfw_message;
696777
OpamConsole.menu "Which Git should opam use?"
697778
~default:`Default ~no:`Default ~options
698779
in
@@ -711,7 +792,12 @@ let git_for_windows_check =
711792
header ();
712793
get_git_location ~git_location:(OpamFilename.Dir.to_string git_location) ()
713794
| 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
715801
(header ();
716802
OpamConsole.msg
717803
"Cygwin Git is functional but can have credentials issues for private repositories, \

src/core/opamStubs.dummy.ml

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ let setConsoleMode _ = that's_a_no_no
2323
let getWindowsVersion = that's_a_no_no
2424
let getArchitecture = that's_a_no_no
2525
let waitpids _ = that's_a_no_no
26+
let readRegistry _ _ _ = that's_a_no_no
2627
let writeRegistry _ _ _ = that's_a_no_no
2728
let getConsoleOutputCP = that's_a_no_no
2829
let getCurrentConsoleFontEx _ = that's_a_no_no
@@ -42,3 +43,5 @@ let getConsoleWindowClass = that's_a_no_no
4243
let setErrorMode = that's_a_no_no
4344
let getErrorMode = that's_a_no_no
4445
let setConsoleToUTF8 = that's_a_no_no
46+
let getVersionInfo = that's_a_no_no
47+
let get_initial_environment = that's_a_no_no

src/core/opamStubs.mli

+14
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ val waitpids : int list -> int -> int * Unix.process_status
6363
[waitpids pids length] behaves like [Unix.wait], returning the pid and
6464
exit status of the first process to terminate. *)
6565

66+
val readRegistry : registry_root -> string -> string -> 'a registry_value -> 'a option
67+
(** Windows only. [readRegistry root key name value_type] reads the value
68+
[name] from registry key [key] of [root]. As per Windows Registry
69+
convention, the default value can be read by passing [""] for [name].
70+
71+
@raise Failure If the value in the registry does not have [value_type] *)
72+
6673
val writeRegistry :
6774
registry_root -> string -> string -> 'a registry_value -> 'a -> unit
6875
(** Windows only. [writeRegistry root key name value_type value] sets the
@@ -145,3 +152,10 @@ val getErrorMode : unit -> int
145152

146153
val setConsoleToUTF8 : unit -> unit
147154
(** Windows only. Directly wraps SetConsoleOutputCP(CP_UTF8). *)
155+
156+
val getVersionInfo : string -> win32_version_info option
157+
(** Windows only. Returns the version info block for a file or [None] if the
158+
file either doesn't exist or doesn't have one. *)
159+
160+
val get_initial_environment : unit -> string list
161+
(** Windows only. Returns the environment which new processes would receive. *)

src/core/opamStubsTypes.ml

+33
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,36 @@ type windows_cpu_architecture =
8080
| IA64 (* 0x6 *)
8181
| Intel (* 0x0 *)
8282
| Unknown (* 0xffff *)
83+
84+
85+
(** Predefined version information strings (see VerQueryValueW) *)
86+
type win32_non_fixed_version_info = {
87+
comments: string option;
88+
companyName: string option;
89+
fileDescription: string option;
90+
fileVersionString: string option;
91+
internalName: string option;
92+
legalCopyright: string option;
93+
legalTrademarks: string option;
94+
originalFilename: string option;
95+
productName: string option;
96+
productVersionString: string option;
97+
privateBuild: string option;
98+
specialBuild: string option;
99+
}
100+
101+
(** VS_FIXEDFILEINFO *)
102+
type win32_version_info = {
103+
signature: int; (** [0xFEEF04BD] *)
104+
version: int * int; (** Structure version number *)
105+
fileVersion: int * int * int * int; (** File version *)
106+
productVersion: int * int * int * int; (** Product version *)
107+
fileFlagsMask: int; (** Valid bits in {!fileFlags} *)
108+
fileFlags: int; (** File attributes (see VS_FIXEDFILEINFO) *)
109+
fileOS: int; (** File OS (see VS_FIXEDFILEINFO) *)
110+
fileType: int; (** File Type (see VS_FIXEDFILEINFO) *)
111+
fileSubtype: int; (** File Sub-type (see VS_FIXEDFILEINFO) *)
112+
fileDate: int64; (** File creation time stamp *)
113+
strings: ((int * int) * win32_non_fixed_version_info) list;
114+
(** Non-fixed string table. First field is a pair of Language and Codepage ID. *)
115+
}

src/stubs/win32/opamWin32Stubs.ml

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ external setConsoleMode : 'a -> int -> bool = "OPAMW_SetConsoleMode"
2222
external getWindowsVersion : unit -> int * int * int * int = "OPAMW_GetWindowsVersion"
2323
external getArchitecture : unit -> 'a = "OPAMW_GetArchitecture"
2424
external waitpids : int list -> int -> int * Unix.process_status = "OPAMW_waitpids"
25+
external readRegistry : 'a -> string -> string -> 'b -> 'c option = "OPAMW_ReadRegistry"
2526
external writeRegistry : 'a -> string -> string -> 'b -> 'c -> unit = "OPAMW_WriteRegistry"
2627
external getConsoleOutputCP : unit -> int = "OPAMW_GetConsoleOutputCP"
2728
external getCurrentConsoleFontEx : 'a -> bool -> 'b = "OPAMW_GetCurrentConsoleFontEx"
@@ -40,3 +41,5 @@ external getConsoleWindowClass : unit -> string option = "OPAMW_GetConsoleWindow
4041
external setErrorMode : int -> int = "OPAMW_SetErrorMode"
4142
external getErrorMode : unit -> int = "OPAMW_GetErrorMode"
4243
external setConsoleToUTF8 : unit -> unit = "OPAMW_SetConsoleToUTF8"
44+
external getVersionInfo : string -> 'a option = "OPAMW_GetVersionInfo"
45+
external get_initial_environment : unit -> string list = "OPAMW_CreateEnvironmentBlock"

0 commit comments

Comments
 (0)