Browse Source

Merge branch 'cmd-parsing' into dev

Almost the same problem as with commit bd739b21a3c868e02a12ab8ece082814196c3ca0

Thus, the conflict resolution is the same.

 Conflicts:
	CHANGELOG.md
	src/oclaunch.ml
	src/tmp_file.ml

Here is the message of commit bd739b21a3c868e02a12ab8ece082814196c3ca0

---
commit bd739b21a3c868e02a12ab8ece082814196c3ca0
Merge: 24368c3 650c477
Author: Leo <leowzukw@vmail.me>
Date:   Wed Dec 23 11:50:17 2015 +0100

    Merge branch 'cmd-parsing' into dev

    Hope nothing was forgotten, since some code was moved, creating a lot of merge
    problems
---
Leo 9 years ago
parent
commit
a252b4d2fd
24 changed files with 2025 additions and 169 deletions
  1. 17 1
      CHANGELOG.md
  2. 1 0
      TODO.md
  3. 3 3
      dev.json
  4. 1 1
      src/add_command.ml
  5. 249 91
      src/command_def.ml
  6. 4 3
      src/default.ml
  7. 27 11
      src/edit_command.ml
  8. 27 1
      src/exec_cmd.ml
  9. 4 0
      src/file_com.ml
  10. 1236 0
      src/licencing.ml
  11. 27 15
      src/list_rc.ml
  12. 42 1
      src/messages.ml
  13. 4 0
      src/messages.mli
  14. 3 14
      src/oclaunch.ml
  15. 1 1
      src/remove_command.ml
  16. 67 0
      src/signals.ml
  17. 38 0
      src/signals.mli
  18. 21 4
      src/state.ml
  19. 75 10
      src/test/exec_t.ml
  20. 46 9
      src/tmp_file.ml
  21. 4 1
      src/tmp_file.mli
  22. 80 0
      src/tools.ml
  23. 45 0
      src/tools.mli
  24. 3 3
      test.sh

+ 17 - 1
CHANGELOG.md

@@ -1,5 +1,8 @@
 # Changelog of OcLaunch
 
+>Note: XXX Means that the functionality needs test and TODO means that its
+>implementation is partial
+
 ## 0.3.x
 
 ### 0.3.0
@@ -9,8 +12,21 @@
  + To limit future problem with lockers, two things were done:
    + Remove automatically lock file at the end of the program (See commit 075c5b7074ea62ec337fe45309fbc3d808ad74fc)
    + Add delay when waiting for locker, to avoid endless loop (See commit cd7fdc0c022aa36b39f02813c4ebe54a533f0041 and bd712c97c788922aabdda15f75e78cb05882c53f)
+ + Rewrite command line parsing, in a cleaner and safer way. It now handles
+   `exit`, would be able to deal with auto completion and display more accurate
+   help messages. Though, for backward compatibility reasons, a hack has been
+   setted up, allowing to call the program with a number as first argument or
+   without any argument. This way, the program tries to launch the corresponding
+   command or the next one. The problem is that you can't call it with an
+   option. To do this, use the `run` subcommand.
+ + Improve list subcommand, now using Textutils library, displaying in an array
+ + Improve editing command (explain how to use to add commands, improve
+   messages, offer to reedit when nothing was done).
  + Code clean up
- + Add unit tests
+ + Add unit tests and clean them up
+ + Add licence warning
+ + TODO XXX Add basic signal handling (`--signals`), to relaunch when doing
+   ctrl-C. See issue #14 for known problems
  + Changed tmp file format, the new one would allow to do more things:
    + Restart edited command (reset number of launch)
    + Support multiple configuration file

+ 1 - 0
TODO.md

@@ -18,6 +18,7 @@
 
  + Add command --edit-rc to edit configuration file
  + Add command to exchange item
+ + Change config file format (Sexp ?)
 
 ### Configuration value
  + Allow to run infinitely or say when it is finish

+ 3 - 3
dev.json

@@ -1,7 +1,7 @@
 {
   "progs": [
-    "task", "task +next", "task +rdv", "echo \"Finish\"",
-    "bdump -w daemon,rc,commands /tmp/v033"
+    "ydump dev.json", "task", "task +next", "task +rdv", "echo \"Finish\"",
+    "bdump -w daemon,rc,commands /tmp/v033", "ydump dev.json"
   ],
   "settings": []
-}
+}

+ 1 - 1
src/add_command.ml

@@ -63,6 +63,6 @@ let run ~(rc:File_com.t) position =
     File_com.write updated_rc;
     (* Display the result *)
     let reread_rc = File_com.init_rc () in
-    List_rc.run ~rc:reread_rc
+    List_rc.run ~rc:reread_rc ()
 ;;
 

+ 249 - 91
src/command_def.ml

@@ -36,105 +36,263 @@
 
 open Core.Std;;
 
+open Command;;
+
 (* Module containing the definition of the interface of OcLaunch *)
 
-(* Arguments *)
-let args =
-    let open Command.Spec in
-    (empty
-    (* Flag to set verbosity level *)
-    +> flag "-v" (optional_with_default !Const.verbosity int)
-        ~aliases:["--verbose" ; "-verbose"]
-        ~doc:"[n] Set verbosity level. \
+(* Type to return result of the work with common arguments *)
+type return_arg = {
+  rc : Settings_t.rc_file;
+}
+
+(* 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 no_color rc_file_name handle_signal ->
+    (* Set the level of verbosity *)
+    Const.verbosity := verbosity;
+    (* Do not use color *)
+    Const.no_color := no_color;
+    (* Use given rc file, should run the nth argument if present *)
+    Const.rc_file := (Lazy.return rc_file_name);
+    (* Active signal handling *)
+    if handle_signal then
+      Signals.handle ();
+
+    (* Debugging *)
+    Messages.debug (sprintf "Verbosity set to %i" !Const.verbosity);
+    Messages.debug (sprintf "Color %s" (match !Const.no_color with true -> "off" | false -> "on"));
+    Messages.debug (sprintf "Configuration file is %s" (Lazy.force !Const.rc_file));
+    Messages.debug (sprintf "Tmp file is %s" Const.tmp_file);
+
+    (* Obtain data from rc_file *)
+    let rc_content = File_com.init_rc () in
+    { 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 set colors *)
-    +> flag "--no-color" no_arg
+    <*> 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_with_default (Lazy.force !Const.rc_file) file)
-    ~aliases:["--rc" ; "-rc"]
-    ~doc:"file Read configuration from the given file and continue parsing."
-    (* Flag to reset tmp file *)
-    +> flag "-r" (optional int)
-        ~aliases:["-reset-tmp" ; "--reset-tmp"]
-        ~doc:"[n][command] Reinitialises launches of a given [command] to [n]. \
-        If no [n] is given, the entry is deleted. With neither [command] nor [n], all entries are reseted."
-    (* Flag to list each commands with its number *)
-    +> flag "-l" no_arg
-    ~aliases:["-list" ; "--list"]
-    ~doc:" Print a list of all commands with their number. Useful to launch with number. \
+    <*> flag "-c" (optional_with_default (Lazy.force !Const.rc_file) file)
+      ~aliases:["--rc" ; "-rc"]
+      ~doc:"file Read configuration from the given file and continue parsing."
+    (* Flag to handle signals *)
+    <*> flag "-s" no_arg
+      ~aliases:["--sinals" ; "-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 *)
+        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."
-    (* Flag to add a command to rc file, from stdin or directly *)
-    +> flag "-a" no_arg
-    ~aliases:["-add" ; "--add"]
-    ~doc:"[n] Add the command given on stdin to the configuration file at a given position. If nothing is given, append it."
-    (* Flag to remove a command from rc file *)
-    +> flag "-d" no_arg
-    ~aliases:["-delete" ; "--delete"]
-    ~doc:"[n] remove the nth command from configuration file. If n is absent, remove last one."
-    (* Flag to display current number *)
-    +> flag "-n" no_arg
-    ~aliases:["-number" ; "--number"]
-    ~doc:" Display current state of the program."
-    (* Flag to edit the nth command *)
-    +> flag "-m" no_arg
-    ~aliases:["-modify" ; "--modify" ; "--edit" ; "-edit"]
-    ~doc:"[n] Edit the nth command of the rc file in your $EDITOR. May be used to add new entries."
-
-    +> anon (maybe ("Command number" %: int)))
+    Spec.(
+      empty
+      +> shared_params
+    )
+    (fun { rc } () ->
+      List_rc.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."
+    Spec.(
+      empty
+      +> shared_params
+      +> anon  (maybe ("number" %: int))
+    )
+    (fun { rc } num_cmd () ->
+      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 () ->
+      (*Tmp_file.reset ~rc reset_cmd 0)*)
+      Remove_command.run ~rc num_cmd)
 ;;
 
-(* Define commands *)
-let commands =
-  Command.basic
-    ~summary:"OcLaunch program is published under CeCILL licence.\nSee \
-    http://cecill.info/licences/Licence_CeCILL_V2.1-en.html (http://huit.re/TmdOFmQT) for details."
-    ~readme:(fun () -> "See http://oclaunch.tuxfamily.org for help.")
-    args
-
-    (fun verbosity no_color rc_file_name reset_cmd list_commands add delete number modify num_cmd () ->
-       (* Set the level of verbosity *)
-       Const.verbosity := verbosity;
-       (* Do not use color *)
-       Const.no_color := no_color;
-       (* Use given rc file, should run the nth argument if present *)
-       Const.rc_file := (Lazy.return rc_file_name);
-
-       (* Debugging *)
-       Messages.debug (sprintf "Verbosity set to %i" !Const.verbosity);
-       Messages.debug (sprintf "Color %s" (match !Const.no_color with true -> "off" | false -> "on"));
-       Messages.debug (sprintf "Configuration file is %s" (Lazy.force !Const.rc_file));
-       Messages.debug (sprintf "Tmp file is %s" Const.tmp_file);
-
-       (* Obtain data from rc_file *)
-       let rc_content = File_com.init_rc () in
-       (* A default number, corresponding to first item *)
-       let default_n = (Option.value ~default:0 num_cmd) in
-       (* First try to list *)
-       if list_commands then List_rc.run ~rc:rc_content
-       (* To add command to rc file *)
-       else if add then Add_command.run ~rc:rc_content num_cmd
-       (* To delete command from rc file *)
-       else if delete then Remove_command.run ~rc:rc_content num_cmd
-       (* To print current state *)
-       else if number then State.print_current ()
-       (* Edit the nth command *)
-       else if modify then Edit_command.run ~rc:rc_content default_n
-       else
-         begin
-           (* Other things to test, especially flags with arguments *)
-           (* Reset to a value *)
-           reset_cmd |> (function
-             | Some reset_cmd -> Tmp_file.reset ~rc:rc_content reset_cmd default_n
-             | None -> ());
-
-           (* Else: Run the nth command *)
-           sprintf "Default: run nth command: %s"
-             (match num_cmd with None -> "None"
-                | Some n -> "Some " ^ (Int.to_string n)) |> Messages.debug;
-           Default.run ~rc:rc_content num_cmd;
-           Messages.debug "Default: end"
-         end
-        )
+(* To display current state *)
+let state =
+  basic
+    ~summary:"Display current state of the program."
+    Spec.(
+      empty
+      +> shared_params
+    )
+    (fun { rc } () ->
+      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 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 of the licence"
+    )
+    (fun _ header () ->
+      let cecill = not(header) in (* When cecill is false, it displays the header *)
+      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 () ->
+      Default.run ~rc n)
+
+let run ~version ~build_info () =
+
+  (* 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 \
+      (http://huit.re/TmdOFmQT) for details."
+      ~readme:(fun () -> "Use 'help' subcommand to get help (it works both \
+      after the name of the software and with another subcommand). For \
+      further help, see http://oclaunch.eu.org.")
+      ~preserve_subcommand_order:()
+      [ ("run", default) ; ("licence", licence) ; ("add", add) ; ("edit", edit)
+      ; ("list", list) ; ("delete", delete) ; ("state", state)
+      ; ( "reset", reset) ; ( "reset-all", reset_all) ]
+    |> run ~version ~build_info
+  in
+
+  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"
+  ));
+
+  (* Reset display *)
+  Messages.reset ();
+
+  exit_code
 ;;

+ 4 - 3
src/default.ml

@@ -36,8 +36,8 @@
 
 open Core.Std;;
 
-(* The module containing the step runned when the program is
- * used without argument *)
+(* The module containing the step run when the program is
+ * used without argument or with run command *)
 
 (* cmd_number is the number of the command the user wants
  * to execute *)
@@ -57,7 +57,8 @@ let run ~rc cmd_number =
           |> function
             | None -> (* If no command was found, all has been launched *)
                 Messages.ok "All has been launched!";
-                Messages.tips "You can reset with '-r'";
+                Messages.tips "You can reset with 'reset' subcommand";
+                Lock.remove ()
             | Some cmd_to_exec -> Exec_cmd.execute cmd_to_exec;
       end
     | Some num -> begin

+ 27 - 11
src/edit_command.ml

@@ -74,11 +74,11 @@ let gen_modification items =
 
 (* Function which get the nth element, put it in a file, let the user edit it,
  * and then remplace with the new result *)
-let run ~(rc:File_com.t) position =
+let rec run ~(rc:File_com.t) position =
     (* Current list of commands *)
     let current_list = rc.Settings_t.progs in
 
-    (* Creating tmp file *)
+    (* Creating tmp file, for editing *)
     let tmp_filename = [
         "/tmp/oc_edit_" ;
         (Int.to_string (Random.int 100_000)) ;
@@ -86,8 +86,9 @@ let run ~(rc:File_com.t) position =
     ] in
     let tmp_edit = String.concat tmp_filename in
     (* Remove item to be edited *)
-    let original_command,shorter_list = Remove_command.remove current_list
-    position in
+    let original_command,shorter_list =
+      Remove_command.remove current_list position
+    in
     Out_channel.write_all tmp_edit original_command;
 
 
@@ -105,11 +106,26 @@ let run ~(rc:File_com.t) position =
     let cmd_list = new_list shorter_list position new_commands in
     let updated_rc = { rc with Settings_t.progs = cmd_list} in
     File_com.write updated_rc;
-    (* Display the result *)
-    sprintf "'%s' -> '%s'\n" original_command
-        (gen_modification new_commands)
-        |> Messages.ok;
-    let reread_rc = File_com.init_rc () in
-    (* Display new rc file *)
-    List_rc.run ~rc:reread_rc
+    (* Display the result, only if modified *)
+    let new_cmd_mod = gen_modification new_commands in
+    (* We are doing things in this order to avoid multiple listing of rc file
+     * when reediting. *)
+    if ( original_command = new_cmd_mod )
+    then (* Nothing change, try reediting *)
+      begin
+        let open Messages in
+        warning "Nothing changed.";
+        confirm "Do you want to reedit?"
+        |> function
+          | Yes -> run ~rc position
+          | No -> ()
+      end
+
+    else (* Display summary of changes *)
+      begin
+        sprintf "'%s' -> '%s'\n" original_command new_cmd_mod |> Messages.ok;
+        (* Display new rc file *)
+        let reread_rc = File_com.init_rc () in
+        List_rc.run ~rc:reread_rc ()
+      end;
 ;;

+ 27 - 1
src/exec_cmd.ml

@@ -46,7 +46,7 @@ let set_title new_title =
 ;;
 
 (* Function to return the less launched command, at least the first one *)
-(* Log is a list of entry (commands) asociated with numbers *)
+(* Log is a list of entry (commands) associated with numbers *)
 let less_launched (log : (string * int) list) =
   let max = Const.default_launch in (* Number of launch, maximum *)
   (* Return smallest, n is the smaller key *)
@@ -59,6 +59,32 @@ let less_launched (log : (string * int) list) =
       | None -> None)
 ;;
 
+(* Function to get the number corresponding to the next command to launch (less
+ * launched) *)
+let less_launched_num log =
+  (* Debug *)
+  Messages.debug "less_launched_num: LOG:";
+  Tools.spy1_log log
+
+  (* Function to return nothing (None) when max launch number is reached, Some
+   * number otherwise *)
+  |> List.filter_mapi ~f:(fun entry_number ( _, launch_number ) ->
+      if launch_number >= Const.default_launch
+      then None
+      else Some ( entry_number, launch_number ))
+  (* Find the less launched by sorting and taking the first *)
+  |> List.sort ~cmp:(fun ( _, launch_number1 ) ( _, launch_number2 ) -> Int.compare launch_number1 launch_number2)
+  |> List.hd
+  |> function
+    | Some ( entry_number, launch_number) ->
+        launch_number |> sprintf "Launch number found: %i" |> Messages.debug;
+        Messages.debug "Return launch number (printed bellow):";
+        Some ( Tools.spy1_int entry_number )
+    | None ->
+        Messages.debug "No less launched cmd.";
+        None
+;;
+
 (* Function to determinate what is the next command to
  * execute. It takes the current numbers from tmp file. *)
 let what_next ~tmp =

+ 4 - 0
src/file_com.ml

@@ -62,6 +62,10 @@ let create_rc_file ~name =
   (* Notify that we initialise config file *)
   sprintf "Initializing empty configuration file in %s\n" name |> Messages.warning;
   Messages.tips "Feedback is welcomed at leowzukw@vmail.me\n";
+
+  (* Display licence information *)
+  Licencing.print ~cecill:false;
+
   let compact_rc_file = Settings_j.string_of_rc_file (rc_template () ()) in
   let readable_rc_file = Yojson.Basic.prettify compact_rc_file in (* Create human readable string for rc file *)
   let out_file = Out_channel.create name in

File diff suppressed because it is too large
+ 1236 - 0
src/licencing.ml


+ 27 - 15
src/list_rc.ml

@@ -38,20 +38,32 @@ open Core.Std;;
 
 (* This modules contains function to list the content of the rc file *)
 
-(* Display the command with its number, with a '*' and different color if it is the current one *)
-let disp_cmd_num current_number number command =
-    (* If number is the global current one print a '*' *)
-    let prepend = (if current_number = number then "* " else "  ") in
-    sprintf "%s%i: %s" prepend number command
-    |> (fun concatenated_msg ->
-            match prepend with
-            | "* " -> Messages.ok concatenated_msg
-            | "  " -> Messages.tips concatenated_msg
-            | _ -> assert false)
+(* Function which list, rc would be automatically reread, this optional
+ * argument is kept for backward compatibility *)
+(* FIXME Remove ?rc or use it *)
+(* TODO:
+  * Test it, esp. ordering
+  * Allow to set form of the table, multiple rc file, display next to be
+    * launched… *)
+let run ?rc () =
+  let rc_numbered =
+    File_com.init_rc ()
+    |> fun rc -> rc.Settings_t.progs
+    |> List.mapi ~f:(fun i item -> ( item, i ))
+  in
+  let tmp : Tmp_file.t = Tmp_file.init () in
+  Tmp_file.get_accurate_log ~tmp ()
+  (* Generate list to feed the table,
+   * XXX assuming all will be in the right order *)
+  |> List.map ~f:(function
+    ( cmd, number ) ->
+      [ (* Number of a command in rc file, command, number of launch *)
+        (List.Assoc.find_exn rc_numbered cmd |> Int.to_string);
+        cmd;
+        (Int.to_string number)
+      ])
+  |> Textutils.Ascii_table.simple_list_table
+    ~display:Textutils.Ascii_table.Display.column_titles
+    [ "Id" ; "Command" ; "Number of launch" ]
 ;;
 
-(* Function which list *)
-let run ~(rc:File_com.t) =
-    List.iteri rc.Settings_t.progs ~f:(fun i item ->
-        disp_cmd_num (Tmp_file.get_current ()) i item)
-;;

+ 42 - 1
src/messages.ml

@@ -60,6 +60,7 @@ type color =
     | Yellow
     | White
     | Plum
+    | Cyan
 ;;
 
 type style =
@@ -84,6 +85,7 @@ let print ~color ~style message =
             | Yellow -> Color_print.color ~color:`Yellow message
             | White -> Color_print.color ~color:`White message
             | Plum -> Color_print.color ~color:`Plum message
+            | Cyan -> Color_print.color ~color:`Cyan message
         ) |> (* Finaly print escaped string *)
         (fun colored_msg ->
             match style with
@@ -104,6 +106,7 @@ let check_verbosity ~f function_number =
     | false -> ()
 ;;
 
+
 (* Print debugging, information, important... messages *)
 let debug message =
     check_verbosity ~f:(fun () ->
@@ -126,6 +129,44 @@ let warning message =
     ) 1
 ;;
 
+(* Type for the answers *)
+type answer = Yes | No;;
+(* Usefull to display result *)
+let answer2str = function
+  Yes -> "Yes" | No -> "No"
+;;
+(* State of the program, if you should always answer yes, no or ask to the user
+ * (default)*)
+(* TODO Put it in Const *)
+let assume_yes = None;;
+(* Allow to assume yes or no like with a --yes option *)
+let check_assume_yes ~f =
+  match assume_yes with
+  | Some true -> Yes (* --yes *)
+  | Some false -> No (* --no *)
+  | None -> f ()
+;;
+
+(* Get confirmation
+ * TODO:
+   * allow option like -y
+   * test it (display, line return, etc...) *)
+let rec confirm info =
+  check_assume_yes ~f:(fun () ->
+    print ~color:Cyan ~style:Normal info;
+    print ~color:Cyan ~style:Normal "\n(Yes/No): ";
+    (* XXX Be sure to show the message *)
+    Out_channel.(flush stdout);
+    let str_answer = In_channel.(input_line ~fix_win_eol:true stdin) in
+    str_answer |> (function
+      | Some "Y" | Some "y" | Some "Yes" | Some "YES" | Some "yes" -> Yes
+      | Some "N" | Some "n" | Some "No" | Some "NO" | Some "no" -> No
+      | Some _ | None ->
+        warning "Please enter 'yes' or 'no' or 'y' or 'n'.";
+        confirm info)
+    )
+;;
+
 let ok message =
     check_verbosity ~f:(fun () ->
         let mess = message ^ "\n" in
@@ -144,7 +185,7 @@ let tips message =
 (* Reset printing, to avoid color problem on some terminal (Konsole), the  *)
 let reset () =
     match !already with
-    | true -> debug "Resetted colors";
+    | true -> debug "Reseted colors";
         Core_extended.Color_print.normal "" |> printf "%s\n"
     | false -> debug "Not resetted"; ()
 ;;

+ 4 - 0
src/messages.mli

@@ -40,4 +40,8 @@ val warning : string -> unit
 val ok : string -> unit
 val tips : string -> unit
 
+type answer = Yes | No
+val answer2str : answer -> string
+val confirm : string -> answer
+
 val reset : unit -> unit

+ 3 - 14
src/oclaunch.ml

@@ -46,18 +46,7 @@ let version_number = "0.3.1-dev";;
 let build_info = ( "Build with OCaml version " ^ (Sys.ocaml_version) ^ " on " ^ (Sys.os_type) );;
 
 let () =
-  Command.run ~version:version_number ~build_info:build_info
-  Command_def.commands;
-
-  (* 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"
-  ));
-  (* Reset display *)
-  Messages.reset ()
+  Command_def.run ~version:version_number ~build_info:build_info ()
+  |> function
+    `Exit n -> exit n
 ;;

+ 1 - 1
src/remove_command.ml

@@ -75,5 +75,5 @@ let run ~(rc:File_com.t) n_to_remove =
     File_com.write updated_rc;
     (* Display the result *)
     let reread_rc = File_com.init_rc () in
-    List_rc.run ~rc:reread_rc
+    List_rc.run ~rc:reread_rc ()
 ;;

+ 67 - 0
src/signals.ml

@@ -0,0 +1,67 @@
+(******************************************************************************)
+(* Copyright © Joly Clément, 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;;
+
+(* Working with signals and behave according to it *)
+(* XXX May use async for this. Here is what the Core's doc say
+ * An OCaml signal handler can run at any time, which introduces all the
+ * semantic complexities of multithreading. *)
+
+(* TODO Finish it! Handle sigint (ctrl-C) and ask to launch next command *)
+let handle_sigint () =
+  let launch_next () =
+    Messages.(confirm "Would you like to launch next command?"
+    |> function
+      | Yes -> (* Launch next *)
+        failwith "TODO Relaunch"
+      | No -> (* Quit *)
+        failwith "TODO Quit"
+    )
+  in
+  let open Signal in
+  Expert.handle int (fun signal ->
+    if signal = int
+    then
+      launch_next ()
+    else ())
+;;
+
+(* Called from external to activate signal handling *)
+let handle () =
+  handle_sigint ()
+;;
+

+ 38 - 0
src/signals.mli

@@ -0,0 +1,38 @@
+(******************************************************************************)
+(* Copyright © Joly Clément, 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.                                                                   *)
+(******************************************************************************)
+
+(* Handle signals (i.e. do things according to them) *)
+val handle : unit -> unit

+ 21 - 4
src/state.ml

@@ -39,8 +39,25 @@ open Core.Std;;
 (* Module to display the current state of the program *)
 
 (* Display current number *)
-let print_current () =
-    (* Display the number *)
-    sprintf "Current state: %i" (Tmp_file.get_current ())
-    |> Messages.ok
+let print_current ~rc () =
+  Tmp_file.(init ()
+    |> (fun tmp -> get_accurate_log ~tmp ())
+    |> Exec_cmd.less_launched_num
+    |> Tools.spy1_int_option)
+  |> Option.value_map
+    ~default:"Nothing next"
+    ~f:(fun ( num : int ) ->
+
+      (* XXX Debug *)
+      sprintf "Num: %i" num |> Messages.debug;
+
+      File_com.num_cmd2cmd ~rc num
+      |> (function
+        | Some cmd -> cmd
+        | None -> Messages.warning "Error, should not append, this is a bug";
+          assert false)
+      |> (fun ( cmd : string ) ->
+          Messages.debug cmd; (* TODO Use tools.spy1 *)
+          sprintf "Next: command %i, '%s'" num cmd))
+  |> Messages.ok
 ;;

+ 75 - 10
src/test/exec_t.ml

@@ -44,23 +44,88 @@ let less_launched test solution () =
   OUnit.assert_equal actual solution
 ;;
 
-(* Data for above test *)
+(* Function less_launched_num *)
+let less_launched_num test solution () =
+  let actual = Exec_cmd.less_launched_num test in
+  OUnit.assert_equal actual solution
+;;
+
+(* Maximum number of launch *)
+let max = Const.default_launch;;
+(* Data for above test, common data provided to both function since there
+ * purpose are very close from one to the other *)
+let common_data =
+  [
+    ( [ ( "cmd1", 4 ) ; ( "cmd2", 0 ) ], "Canonical case 1" );
+    ( [ ( "cmd1", 0 ) ; ( "cmd2", 5 ) ], "Canonical case 2" );
+    ( [], "Empty list" );
+    ( [ ( "cmd1", 0 ) ; ( "cmd2", 3 ) ; ( "cmd3", 4 )  ; ( "cmd4", 5 ) ], "Canonical case 3" );
+    ( [ ( "cmd1", 0 ) ; ( "cmd2", 4 ) ; ( "cmd3", 4 )  ; ( "cmd5", 5 ) ],
+      "Twice the same number, with others" );
+    ( [ ( "cmd1", 4 ) ; ( "cmd2", 4 ) ], "Twice the same number" );
+    ( [ ( "cmd1", max ) ; ( "cmd2", (max + 5) ) ],
+      "Everything (strictly) superior to maximum" );
+    (* To prevent >= and > misuse in code *)
+    ( [ ( "cmd1", max - 1 ) ; ( "cmd2", max ) ; ( "cmd3", max + 1 ) ;
+      ( "cmd3", max + 2) ], "Around maximum (ordered)" );
+    ( [ ( "cmd1", max + 1 ) ; ( "cmd2", max ) ; ( "cmd3", max - 1 ) ;
+      ( "cmd3", max + 2) ], "Around maximum (disordered)" )
+  ]
+;;
+(* Add expected result to corresponding to the data provided common set *)
+let add_solutions data expected =
+  List.map2_exn data expected ~f:(fun ( log, name ) solution ->
+    ( log, solution, name ))
+;;
+
+(* Data customized for the tests *)
 let ll_data =
-  let max = Const.default_launch in
+  add_solutions common_data
   [
-  ( [ ( "cmd1", 4 ) ; ( "cmd2", 0 ) ], Some "cmd2", "Canonical case 1" );
-  ( [ ( "cmd1", 0 ) ; ( "cmd2", 5 ) ], Some "cmd1", "Canonical case 2" );
-  ( [], None, "Empty list" );
-  ( [ ( "cmd1", max ) ; ( "cmd2", (max + 5) ) ], None, "Everything (strcitly) superior to max" );
-  ( [ ( "cmd1", 4 ) ; ( "cmd2", 4 ) ], None, "Twice the same number" );
-]
+      Some "cmd2";
+      Some "cmd1";
+      None;
+      Some "cmd1";
+      Some "cmd1";
+      None;
+      None;
+      Some "cmd1";
+      Some "cmd3"
+  ]
+;;
+let ll_data2 =
+  add_solutions common_data
+  [
+    Some 1;
+    Some 0;
+    None;
+    Some 0;
+    Some 0;
+    None;
+    None;
+    Some 0;
+    Some 2
+  ]
+;;
 
 let llt_l =
-  List.map ll_data ~f:(fun (t, s, name) -> ( (less_launched t s), name))
+  let less_launched_suit =
+    List.map ll_data ~f:(fun (t, s, name) -> ( (less_launched t s), name))
+  in
+  less_launched_suit
+  |> List.map ~f:(fun ( f,name ) -> (name, `Quick, f))
+;;
+
+let llt_l2 =
+  let less_launched_num_suit =
+    List.map ll_data2 ~f:(fun (t, s, name) -> ( (less_launched_num t s), name))
+  in
+  less_launched_num_suit
   |> List.map ~f:(fun ( f,name ) -> (name, `Quick, f))
 ;;
 
 (* To be used in test.ml *)
-let alco = [( "Exec_cmd.ml", llt_l );];;
+let alco = [( "Exec_cmd.ml.less_launched", llt_l ) ;
+  ( "Exec_cmd.ml.less_launched_num", llt_l2 )];;
 
 

+ 46 - 9
src/tmp_file.ml

@@ -1,5 +1,5 @@
 (******************************************************************************)
-(* Copyright © Joly Clément, 2014                                             *)
+(* Copyright © Joly Clément, 2014-2015                                        *)
 (*                                                                            *)
 (*  leowzukw@vmail.me                                                         *)
 (*                                                                            *)
@@ -144,7 +144,8 @@ let get_current () =
     failwith "Deprecated"
 ;;
 
-(* Get number of launch for each command in rc file *)
+(* Get number of launch for each command in rc file, as follow:
+  * (command:string, number of the command:int) list *)
 let get_accurate_log ?rc_name ~tmp () =
   let open List in
 
@@ -167,7 +168,7 @@ let get_accurate_log ?rc_name ~tmp () =
 (* Reset number of launch for a given command
  * cmd: number of the command to be reseted
  * num: number to reset *)
-let reset ~rc cmd num =
+let reset_cmd ~rc num cmd =
   (* Debugging *)
   [(num,"num") ; (cmd,"cmd")]
     |> List.map ~f:(fun (i , str) -> str ^ ": " ^ (Int.to_string i))
@@ -175,8 +176,12 @@ let reset ~rc cmd num =
 
   let ac_log = get_accurate_log ~tmp:(init ()) () in
   (* The command (string) corresponding to the number *)
-  let cmd_str = (File_com.num_cmd2cmd ~rc num |> function Some s -> s
-                                  | None -> failwith "Out of bound") in
+  let cmd_str =
+    File_com.num_cmd2cmd ~rc cmd
+    |> function
+      Some s -> s
+      | None -> failwith "Out of bound"
+  in
 
   (* Current number of launch for that cmd *)
   let i = List.Assoc.find_exn ac_log cmd_str in
@@ -184,12 +189,44 @@ let reset ~rc cmd num =
       cmd_str
       i
     |> Messages.info;
-    sprintf  "Restore with 'oclaunch -r %i %i'" i num
+    sprintf  "Restore with 'oclaunch reset %i %i'" i cmd
     |> Messages.tips;
 
-    (* Do the work *)
-    (* Set the number *)
-    log ~func:(fun a -> num) ~cmd:cmd_str ();
+    (* Do the work, set the number *)
+    log ~func:(fun _ -> num) ~cmd:cmd_str ();
     sprintf "Reseted command '%s' to %i successfully" cmd_str num |> Messages.ok
 ;;
 
+(* Reset all commands to a number
+ * num: number to reset *)
+let reset2num ~rc num =
+  (* Debugging *)
+  "Num: " ^ (Int.to_string num)
+  |> Messages.debug;
+
+  let ac_log = get_accurate_log ~tmp:(init ()) () in
+
+  (* Erase number of launch for each command *)
+  List.iter ac_log ~f:(fun ( cmd, _ ) ->
+    log ~func:(fun _ -> num) ~cmd ())
+;;
+
+(* Reset all command *)
+let reset_all () =
+  Messages.debug "Preparing to reset all";
+  let reset_without_ask () =
+    (* Make sure that file exists, otherwise strange things appears *)
+    let tmp = init () in
+    (* Get rc_file name *)
+    let name = Lazy.force !Const.rc_file in
+    write Tmp_biniou_t.{ tmp with rc = List.Assoc.add tmp.rc name [] }
+  in
+  Messages.debug "Asking question";
+  Messages.confirm "You will lose number of launch for every command.\
+    Are you sure?"
+  |> (fun answer -> sprintf "Answer %s" (Messages.answer2str answer) |> Messages.debug; answer) (* Spy *)
+    |> function
+      Messages.Yes -> reset_without_ask ()
+      | Messages.No -> ()
+;;
+

+ 4 - 1
src/tmp_file.mli

@@ -45,5 +45,8 @@ val is_prog_in_rc : 'a list -> 'a -> bool
 val log : cmd:string -> ?func:(int -> int) -> unit -> unit
 (** Return current state *)
 val get_current : unit -> int
-val reset : rc:Settings_t.rc_file -> int -> int -> unit
 val get_accurate_log : ?rc_name:string -> tmp:t -> unit -> (string * int) list
+(* Resetting command *)
+val reset_cmd : rc:Settings_t.rc_file -> int -> int -> unit
+val reset2num : rc:Settings_t.rc_file -> int -> unit
+val reset_all : unit -> unit

+ 80 - 0
src/tools.ml

@@ -0,0 +1,80 @@
+(******************************************************************************)
+(* Copyright © Joly Clément, 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;;
+
+(* Various tools for the program *)
+
+(* Printing methods, common to all function in this modules *)
+let printing = Messages.debug;;
+
+(* Spying expression, template for the others. Takes the string corespondig to
+ * the original value and return the original one *)
+let spy orig (value : string) =
+  printing value;
+  orig
+;;
+
+(* Functions exposed to spy special types *)
+let spy1_int i =
+  sprintf "%i" i
+  |> spy i
+;;
+let spy1_int_option io =
+  let i = io |> (function
+    None -> "None"
+    | Some i -> sprintf "Some %i" i)
+  in
+  spy io i
+;;
+let spy1_string str =
+  spy str str
+;;
+let spy1_float f =
+  sprintf "%f" f
+  |> spy f
+;;
+let spy1_log (log : (string * int) list) =
+  let log_str = List.map log ~f:(fun (s, i) ->
+    sprintf "( \"%s\", %i ); " s i)
+  in
+  "[ " ^ (String.concat log_str) ^ " ]"
+  |> printing;
+  log
+;;
+let spy1_rc rc =
+  failwith "Not implemented"
+;;

+ 45 - 0
src/tools.mli

@@ -0,0 +1,45 @@
+(******************************************************************************)
+(* Copyright © Joly Clément, 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;;
+
+(* Spying expression *)
+val spy1_int : int -> int
+val spy1_int_option : int option -> int option
+val spy1_string : string -> string
+val spy1_float : float -> float
+val spy1_log : (string * int) list -> (string * int) list
+val spy1_rc : 'a -> 'a

+ 3 - 3
test.sh

@@ -1,5 +1,5 @@
 #!/bin/bash
 
-# Some script to test the behavior of the programe with custom rc file
-
-OC_TMP=/tmp/v033 ./oclaunch.native -v 5 --rc ./dev.json $*
+# Some script to test the behavior of the program with custom rc file
+# FIXME Better behavior when launched without arguments
+OC_TMP=/tmp/v033 ./oclaunch.native $* -v 5 -c ./dev.json