123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- (******************************************************************************)
- (* Copyright © Joly Clément, 2014-2015 *)
- (* *)
- (* leowzukw@vmail.me *)
- (* *)
- (* Ce logiciel est un programme informatique servant à exécuter *)
- (* automatiquement des programmes à l'ouverture du terminal. *)
- (* *)
- (* Ce logiciel est régi par la licence CeCILL soumise au droit français et *)
- (* respectant les principes de diffusion des logiciels libres. Vous pouvez *)
- (* utiliser, modifier et/ou redistribuer ce programme sous les conditions *)
- (* de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA *)
- (* sur le site "http://www.cecill.info". *)
- (* *)
- (* En contrepartie de l'accessibilité au code source et des droits de copie, *)
- (* de modification et de redistribution accordés par cette licence, il n'est *)
- (* offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, *)
- (* seule une responsabilité restreinte pèse sur l'auteur du programme, le *)
- (* titulaire des droits patrimoniaux et les concédants successifs. *)
- (* *)
- (* A cet égard l'attention de l'utilisateur est attirée sur les risques *)
- (* associés au chargement, à l'utilisation, à la modification et/ou au *)
- (* développement et à la reproduction du logiciel par l'utilisateur étant *)
- (* donné sa spécificité de logiciel libre, qui peut le rendre complexe à *)
- (* manipuler et qui le réserve donc à des développeurs et des professionnels *)
- (* avertis possédant des connaissances informatiques approfondies. Les *)
- (* utilisateurs sont donc invités à charger et tester l'adéquation du *)
- (* logiciel à leurs besoins dans des conditions permettant d'assurer la *)
- (* sécurité de leurs systèmes et ou de leurs données et, plus généralement, *)
- (* à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. *)
- (* *)
- (* Le fait que vous puissiez accéder à cet en-tête signifie que vous avez *)
- (* pris connaissance de la licence CeCILL, et que vous en avez accepté les *)
- (* termes. *)
- (******************************************************************************)
- open Core.Std;;
- open Command;;
- (* Module containing the definition of the interface of OcLaunch *)
- (* Type to return result of the work with common arguments *)
- type return_arg = {
- rc : Settings_t.rc_file Lazy.t;
- }
- (* A set of default arguments, usable with most of the commands *)
- let shared_params =
- let open Param in
- (* Way to treat common args *)
- return (fun verbosity assume_yes no_color rc_file_name handle_signal ->
- (* Set the level of verbosity *)
- Const.verbosity := verbosity;
- (* Ask question or not, see Const.ask for details *)
- Const.ask := Option.(
- merge
- (some_if assume_yes true)
- !Const.ask
- ~f:( || )
- );
- (* Do not use color *)
- Const.no_color := no_color || !Const.no_color;
- (* Use given rc file, preserving lazyness, since Const.rc_file is not
- * yet evaluated *)
- Const.rc_file :=
- Option.value_map ~f:(fun rfn -> Lazy.return rfn)
- ~default:!Const.rc_file rc_file_name
- ;
- (* Active signal handling *)
- if handle_signal then
- Signals.handle ();
- (* Debugging *)
- let d = Messages.debug in
- d (sprintf "Verbosity set to %i" !Const.verbosity);
- d (match !Const.ask with
- | None -> "Assume nothing"
- | Some false -> "Assume No"
- | Some true -> "Assume Yes");
- d (sprintf "Color %s" (match !Const.no_color with true -> "off" | false -> "on"));
- begin
- match Option.try_with (fun () -> Lazy.force !Const.rc_file) with
- | None -> d "Configuration file will fail if used";
- | Some rc -> d (sprintf "Configuration file is %s" rc);
- end;
- d (sprintf "Tmp file is %s" Const.tmp_file);
- (* Obtain data from rc_file *)
- d "Reading rc_file...";
- let rc_content = lazy (File_com.init_rc ()) in
- d "Read rc_file";
- { rc = rc_content } (* We use type for futur use *)
- )
- (* Flag to set verbosity level *)
- <*> flag "-v" (optional_with_default !Const.verbosity int)
- ~aliases:["--verbose" ; "-verbose"]
- ~doc:"[n] Set verbosity level. \
- The higher n is, the most verbose the program is."
- (* Flag to assume yes *)
- <*> flag "-y" no_arg
- ~aliases:["--yes" ; "-yes"]
- ~doc:" Assume yes, never ask anything. \
- Setting OC_YES environment variable to '1' is the same. \
- Set it to '0' to assume no. \
- Set it to '-1' to be asked every time."
- (* Flag to set colors *)
- <*> flag "--no-color" no_arg
- ~aliases:["-no-color"]
- ~doc:" Use this flag to disable color usage."
- (* Flag to use different rc file *)
- <*> flag "-c" (optional file)
- ~aliases:["--rc" ; "-rc"]
- ~doc:"file Read configuration from the given file and continue parsing."
- (* Flag to handle signals *)
- <*> flag "-s" no_arg
- ~aliases:["--signals" ; "-signals"]
- ~doc:" Handle signals. Warning, this is not much tested and not \
- implemented the best way."
- ;;
- (* basic-commands *)
- (* To reset tmp file *)
- let reset =
- basic
- ~summary:"Reinitialises launches for the command number [command] to [n]. \
- With both the [command] and the [n] argumennt, the command number \
- [command] is resetted to [n]. \
- With only the [n] argument, every entry in current tmp file is resetted to [n]."
- Spec.(
- empty
- +> shared_params
- +> anon ("target_number" %: int)
- +> anon (maybe ("command_number" %: int))
- )
- (fun { rc } num cmd () ->
- (* Call the right function, according to optionnal argument.
- * Since it's arguments passed on command line, we can not have
- * num = None
- * cmd = Some n
- * cmd: number of the command to be reseted
- * num: number to reset *)
- let rc = Lazy.force rc in
- match ( num, cmd ) with
- | ( num, Some cmd ) -> Tmp_file.reset_cmd ~rc num cmd
- | ( num, None ) -> Tmp_file.reset2num ~rc num
- )
- ;;
- let reset_all =
- basic
- ~summary:" Reinitialises launches for everything."
- Spec.(
- empty
- +> shared_params
- )
- (fun { rc } () ->
- Tmp_file.reset_all ()
- )
- ;;
- (* To list each commands with its number *)
- let list =
- basic
- ~summary:"Print a list of all commands with their number. Useful to launch with number. \
- Displays a star next to next command to launch."
- Spec.(
- empty
- +> shared_params
- +> flag "-l" (optional int)
- ~aliases:[ "--length" ; "-length" ; "--elength" ; "-elength" ]
- ~doc:" Max length of displayed entries, 0 keeps as-is"
- )
- (fun { rc } elength () ->
- let rc = Lazy.force rc in
- List_rc.run ~rc ?elength ())
- ;;
- (* To clean-up rc file *)
- let clean =
- basic
- ~summary:"Remove doubled entries, trailing spaces in them... \
- Useful after manual editing or with rc file from old version."
- Spec.(
- empty
- +> shared_params
- )
- (fun { rc } () ->
- let rc = Lazy.force rc in
- Clean_command.run ~rc ()
- )
- ;;
- (* To add a command to rc file, from stdin or directly *)
- let add =
- basic
- ~summary:"Add the command given on stdin to the configuration file at a \
- given position ([NUMBER]). If nothing is given, append it at the \
- end."
- Spec.(
- empty
- +> shared_params
- +> anon (maybe ("number" %: int))
- )
- (fun { rc } num_cmd () ->
- let rc = Lazy.force rc in
- Add_command.run ~rc num_cmd
- )
- ;;
- (* To remove a command from rc file *)
- let delete =
- basic
- ~summary:"Remove the [COMMAND_NUMBER]th command from configuration file. \
- If [COMMAND_NUMBER] is absent, remove last one."
- Spec.(
- empty
- +> shared_params
- +> anon (maybe ("command_number" %: int))
- )
- (fun { rc } num_cmd () ->
- let rc = Lazy.force rc in
- (*Tmp_file.reset ~rc reset_cmd 0)*)
- Remove_command.run ~rc num_cmd)
- ;;
- (* To display current state *)
- let state =
- basic
- ~summary:"Display current state of the program."
- Spec.(
- empty
- +> shared_params
- )
- (fun { rc } () ->
- let rc = Lazy.force rc in
- State.print_current ~rc ())
- ;;
- (* To edit the nth command *)
- let edit =
- basic
- ~summary:"Edit the [COMMAND_NUMBER]th command of the rc file in your \
- $EDITOR. May be used to add new entries, without argument, one new \
- command per line."
- Spec.(
- empty
- +> shared_params
- +> anon (maybe ("command_number" %: int))
- )
- (fun { rc } n () ->
- let rc = Lazy.force rc in
- let position = Option.value
- ~default:(List.length (rc.Settings_t.progs) - 1) n
- in
- Edit_command.run ~rc position)
- ;;
- (* To display informations about the licence *)
- let licence =
- basic
- ~summary:"Display the licence of the program"
- Spec.(
- empty
- +> shared_params
- +> flag "-header" no_arg
- ~doc:" Display the header associated to the licence"
- )
- (fun _ header () ->
- (* When cecill is false, it displays the header *)
- let cecill = not(header) in
- Licencing.print ~cecill
- )
- ;;
- (* Run nth command, default use *)
- let default =
- basic
- ~summary:"Run the [COMMAND_NUMBER]th command"
- Spec.(
- empty
- +> shared_params
- +> anon (maybe ("command_number" %: int))
- )
- (fun { rc } n () ->
- let rc = Lazy.force rc in
- Default.run ~rc n)
- let run ~version ~build_info () =
- (* Store begin time *)
- let start = Time.now () in
- (* XXX Hack to allow to run 'oclaunch 5' or 'oclaunch' as before, i.e. do not
- * display help for sub commands but use the program directly *)
- let hack_parse () =
- let run_default () =
- default
- |> run ~version ~build_info
- in
- match Sys.argv with
- | [| _ |] -> Result.Ok (run_default ()) (* Program called with nothing *)
- | _ -> (* Program followed by a number *)
- Or_error.try_with (fun () ->
- (* Verify the fist argument is a number, not a subcommand (string) *)
- ignore (Int.of_string (Sys.argv.(1)));
- run_default ())
- in
- (* Parsing with subcommands *)
- let parse_sub () =
- group
- ~summary:"OcLaunch program is published under CeCILL licence.\n\
- You may run the program with 'licence' command or see \
- http://cecill.info/licences/Licence_CeCILL_V2.1-en.html \
- (https://lnch.ml/cecill) for details. More here: \
- https://oclaunch.eu.org/floss-under-cecill (https://lnch.ml/l)."
- ~readme:(fun () -> File_com.welcome_msg)
- ~preserve_subcommand_order:()
- [ ("run", default) ; ("licence", licence) ; ("add", add) ; ("edit", edit)
- ; ("list", list) ; ("cleanup", clean) ; ("delete", delete)
- ; ("state", state) ; ( "reset", reset) ; ( "reset-all", reset_all) ]
- |> run ~version ~build_info
- in
- (* Return error code with exceptions *)
- let exit_code =
- match
- hack_parse ()
- |> (function
- Result.Ok () -> ()
- | Error _ -> parse_sub ())
- with
- | () -> `Exit 0
- | exception message ->
- "Exception: " ^ (Exn.to_string message)
- |> Messages.warning;
- `Exit 20
- in
- (* Unlock, should be done before *)
- Lock.(status ()
- |> (function
- Locked ->
- Messages.warning "Removing lockfile, should be removed before. \
- It's a bug!"; remove ()
- | Free -> ()
- | Error -> Messages.warning "Error with lockfile"
- ));
- (* Display total running time, pretty printing is handled by Time module *)
- Messages.debug Time.(diff (now ()) start
- |> Span.to_string_hum (* Round the value, 3 digits *)
- |> sprintf "Duration: %s");
- (* Reset display *)
- Messages.reset ();
- exit_code
- ;;
|