@@ -32,6 +32,34 @@ let token_conv =
32
32
(fun fmt t -> Format. pp_print_string fmt (Token. to_string t))
33
33
)
34
34
35
+ module Args_server = struct
36
+ (* Subset of Args_global, to be used if "--token" is irrelevant *)
37
+ type t = {
38
+ server_url : Uri .t option ;
39
+ local : bool ;
40
+ }
41
+
42
+ let server_url =
43
+ value & opt (some url_conv) None &
44
+ info [" s" ;" server" ] ~docv: " URL" ~doc:
45
+ " The URL of the learn-ocaml server."
46
+ ~env: (Term. env_info " LEARNOCAML_SERVER" ~doc:
47
+ " Sets the learn-ocaml server URL. Overridden by $(b,--server)." )
48
+ let local =
49
+ value & flag & info [" local" ] ~doc:
50
+ " Use a configuration file local to the current directory, rather \
51
+ than user-wide."
52
+
53
+ let apply server_url local =
54
+ {server_url; local}
55
+
56
+ let term =
57
+ Term. (const apply $ server_url $ local)
58
+
59
+ let term_server =
60
+ Term. (const (fun x -> x) $ server_url)
61
+ end
62
+
35
63
module Args_global = struct
36
64
type t = {
37
65
server_url : Uri .t option ;
@@ -531,11 +559,11 @@ let check_server_version ?(allow_static=false) server =
531
559
server
532
560
(Api. Version () ) (* TODO: pass more precise requests *)
533
561
> |= function
534
- | Ok _server_version -> true
562
+ | Ok server_version -> Some server_version
535
563
| Error msg -> (* See [Learnocaml_api.is_supported]'s message *)
536
564
Printf. eprintf
537
565
" [ERROR] %s\n Do you use the latest learn-ocaml-client binary?\n " msg;
538
- exit 1 )
566
+ exit 70 )
539
567
@@ fun e ->
540
568
if not allow_static then
541
569
begin
@@ -547,7 +575,7 @@ let check_server_version ?(allow_static=false) server =
547
575
exit 1
548
576
end
549
577
else
550
- Lwt. return_false
578
+ Lwt. return_none
551
579
552
580
let get_server =
553
581
let default_server = Uri. of_string " http://learn-ocaml.org" in
@@ -587,7 +615,7 @@ let get_config_option ?local ?(save_back=false) ?(allow_static=false) server_opt
587
615
| None , None -> c
588
616
in
589
617
check_server_version ~allow_static c.ConfigFile. server
590
- >> = fun _ ->
618
+ >> = fun _version -> (* could use this arg like get_config_option_server *)
591
619
(
592
620
if save_back
593
621
then
@@ -603,6 +631,7 @@ let get_config ?local ?(save_back=false) ?(allow_static=false) server_opt token_
603
631
get_config_option ?local ~save_back ~allow_static server_opt token_opt
604
632
>> = function
605
633
| Some c -> Lwt. return c
634
+ (* TODO: Make it possible to change this error message (from get_config_o) *)
606
635
| None -> Lwt. fail_with " No config file found. Please do `learn-ocaml-client init`"
607
636
608
637
let man p = [
@@ -622,6 +651,48 @@ let get_config_o ?save_back ?(allow_static=false) o =
622
651
let open Args_global in
623
652
get_config ~local: o.local ?save_back ~allow_static o.server_url o.token
624
653
654
+ (* Likewise, but without dealing with tokens *)
655
+
656
+ let get_config_option_server ?local ?(save_back =false ) ?(allow_static =false ) server_opt =
657
+ match ConfigFile. path ?local () with
658
+ | Some f ->
659
+ ConfigFile. read f >> = fun c ->
660
+ let c = match server_opt with
661
+ | Some server -> { c with ConfigFile. server }
662
+ | None -> c
663
+ in
664
+ check_server_version ~allow_static c.ConfigFile. server
665
+ >> = fun server_version ->
666
+ (
667
+ if save_back
668
+ then
669
+ ConfigFile. write f c > |= fun () ->
670
+ Printf. eprintf " Configuration written to %s\n %!" f
671
+ else
672
+ Lwt. return_unit
673
+ )
674
+ > |= fun () -> (Some c, server_version)
675
+ | None ->
676
+ match server_opt with
677
+ | Some server ->
678
+ let c = ConfigFile. {server; token = None } in
679
+ check_server_version ~allow_static server
680
+ >> = fun server_version ->
681
+ (* Note: could raise an error if save_back=true *)
682
+ Lwt. return (Some c, server_version)
683
+ | None -> Lwt. return (None , None )
684
+
685
+ let get_config_server ?local ?(save_back =false ) ?(allow_static =false ) server_opt =
686
+ get_config_option_server ?local ~save_back ~allow_static server_opt
687
+ >> = function
688
+ | Some c , o -> Lwt. return (c, o)
689
+ (* TODO: Make it possible to change this error message (from get_config_o_server) *)
690
+ | None , _ -> Lwt. fail_with " No config file found. Please do `learn-ocaml-client init`, or pass a --server=\" URL\" option"
691
+
692
+ let get_config_o_server ?save_back ?(allow_static =false ) o =
693
+ let open Args_server in
694
+ get_config_server ~local: o.local ?save_back ~allow_static o.server_url
695
+
625
696
module Init = struct
626
697
open Args_global
627
698
open Args_create_token
@@ -643,7 +714,7 @@ module Init = struct
643
714
in
644
715
get_server () >> = fun server ->
645
716
check_server_version ~allow_static: true server >> = fun has_server ->
646
- let token = if has_server then
717
+ let token = if has_server <> None then
647
718
get_token server >> = Lwt. return_some
648
719
else
649
720
Lwt. return_none in
@@ -664,7 +735,7 @@ module Init = struct
664
735
~doc: " Initialize the configuration file."
665
736
" init"
666
737
end
667
-
738
+
668
739
module Grade = struct
669
740
open Args_exercises
670
741
let grade go eo =
@@ -790,7 +861,95 @@ module Print_server = struct
790
861
Term. info ~man ~doc: explanation " print-server"
791
862
792
863
end
793
-
864
+
865
+ module Args_server_version = struct
866
+ type t = {
867
+ minimum : bool ;
868
+ }
869
+
870
+ let minimum =
871
+ value & flag & info [" min" ] ~doc:
872
+ " Return the min of server and learn-ocaml-client versions. \
873
+ This flag is useless for now as we only support backward-compatibility \
874
+ (so an old learn-ocaml-client won't try to reach a more recent server) \
875
+ but it is already provided if we later decide to relax this constraint."
876
+
877
+ let apply minimum = {minimum}
878
+
879
+ let term = Term. (const apply $ minimum)
880
+ end
881
+
882
+ module Server_version = struct
883
+ open Args_server_version
884
+ open Learnocaml_api
885
+
886
+ let server_version server_args server_version_args =
887
+ Lwt. catch
888
+ (fun () ->
889
+ get_config_o_server ~save_back: false ~allow_static: false server_args)
890
+ begin fun e ->
891
+ Lwt_io. eprintf " [ERROR] Input error: %s\n "
892
+ (match e with
893
+ | Unix. Unix_error (err , _ , _ ) -> Unix. error_message err
894
+ | Failure m -> m
895
+ | e -> Printexc. to_string e)
896
+ >> = fun () -> exit 2
897
+ end >> = fun cf ->
898
+ match cf with
899
+ | ConfigFile. {server; token = _ } , server_version ->
900
+ (Lwt. catch (fun () ->
901
+ is_supported_server
902
+ server_version (* some server_version cache *)
903
+ server
904
+ (Api. Version () )
905
+ >> = function
906
+ | Ok server_version ->
907
+ let version =
908
+ let {minimum} = server_version_args in
909
+ if minimum then
910
+ let client_version = Compat. v Learnocaml_version. v in
911
+ if Compat. le server_version client_version
912
+ then server_version
913
+ else client_version
914
+ else server_version in
915
+ Lwt_io. printl (Learnocaml_api.Compat. to_string version)
916
+ > |= fun () -> 0
917
+ (* TODO: Factor-out error messages *)
918
+ | Error msg -> (* See [Learnocaml_api.is_supported]'s message *)
919
+ Lwt_io. eprintf
920
+ " [ERROR] %s\n Do you use the latest learn-ocaml-client binary?\n " msg
921
+ > |= fun () -> 70 )
922
+ @@ fun e ->
923
+ begin
924
+ Lwt_io. eprintf " [ERROR] Could not reach server: %s\n "
925
+ (match e with
926
+ | Unix. Unix_error (err , _ , _ ) -> Unix. error_message err
927
+ | Failure m -> m
928
+ | e -> Printexc. to_string e)
929
+ > |= fun () -> 1
930
+ end)
931
+
932
+ let explanation =
933
+ " Print the version of the server (from CLI or from the cookie file, which is kept untouched anyway)."
934
+
935
+ let man = man explanation
936
+
937
+ let exits =
938
+ let open Term in
939
+ [ exit_info ~doc: " Default exit." exit_status_success
940
+ ; exit_info ~doc: " Unable to reach the server." 1
941
+ ; exit_info ~doc: " Input error: unable to find a server URL." 2
942
+ ; exit_info ~doc: " The client's version is incompatible (too old?) w.r.t. the server." 70
943
+ ]
944
+
945
+ (* TODO: Generalize & Use [use_global] *)
946
+ let cmd =
947
+ Term. (
948
+ const (fun o l -> Stdlib. exit (Lwt_main. run (server_version o l)))
949
+ $ Args_server. term $ Args_server_version. term),
950
+ Term. info ~man ~exits ~doc: explanation " server-version"
951
+ end
952
+
794
953
module Set_options = struct
795
954
let set_opts o =
796
955
get_config_o ~save_back: true ~allow_static: true o
@@ -979,7 +1138,7 @@ module Exercise_list = struct
979
1138
use_global exercise_list,
980
1139
Term. info ~man ~doc: doc " exercise-list"
981
1140
end
982
-
1141
+
983
1142
module Main = struct
984
1143
let man =
985
1144
man
@@ -999,6 +1158,7 @@ let () =
999
1158
; Set_options. cmd
1000
1159
; Fetch. cmd
1001
1160
; Print_server. cmd
1161
+ ; Server_version. cmd
1002
1162
; Template. cmd
1003
1163
; Create_token. cmd
1004
1164
; Exercise_list. cmd]
0 commit comments