@@ -292,9 +292,15 @@ let process_html_file orig_file dest_file base_url no_secret =
292292 Lwt_io. close ofile >> = fun () ->
293293 Lwt_io. close wfile
294294
295+ let temp_app_dir o =
296+ let open Filename in
297+ concat
298+ (dirname o.app_dir)
299+ ((basename o.app_dir) ^ " .temp" )
300+
295301let main o =
296- Printf. printf " Learnocaml v.%s running.\n " Learnocaml_api. version;
297- let grade () =
302+ Printf. printf " Learnocaml v.%s running.\n %! " Learnocaml_api. version;
303+ let grade o =
298304 if List. mem Grade o.commands then
299305 (if List. mem Build o.commands || List. mem Serve o.commands then
300306 failwith " The 'grade' command is incompatible with 'build' and \
@@ -322,9 +328,34 @@ let main o =
322328 > |= fun i -> Some i)
323329 else Lwt. return_none
324330 in
325- let generate () =
331+ let generate o =
326332 if List. mem Build o.commands then
327- (Printf. printf " Updating app at %s\n %!" o.app_dir;
333+ (let get_app_dir o =
334+ if not (List. mem Serve o.commands) then
335+ Lwt. return o.app_dir
336+ else if o.server.Server. replace then
337+ let app_dir = temp_app_dir o in
338+ (if Sys. file_exists app_dir then
339+ (Printf. eprintf " Warning: temporary directory %s already exists\n %!"
340+ app_dir;
341+ Lwt. return_unit)
342+ else if Sys. file_exists o.app_dir then
343+ Lwt_utils. copy_tree o.app_dir app_dir
344+ else
345+ Lwt. return_unit)
346+ >> = fun () -> Lwt. return app_dir
347+ else if Learnocaml_server. check_running () <> None then
348+ (Printf. eprintf
349+ " Error: another server is already running on port %d \
350+ (consider using option `--replace`)\n %!"
351+ ! Learnocaml_server. port;
352+ exit 10 )
353+ else Lwt. return o.app_dir
354+ in
355+ get_app_dir o >> = fun app_dir ->
356+ let o = { o with app_dir } in
357+ Learnocaml_store. static_dir := app_dir;
358+ Printf. printf " Updating app at %s\n %!" o.app_dir;
328359 Lwt. catch
329360 (fun () -> Lwt_utils. copy_tree o.builder.Builder. contents_dir o.app_dir)
330361 (function
@@ -404,8 +435,44 @@ let main o =
404435 else
405436 Lwt. return true
406437 in
407- let run_server () =
438+ let run_server o =
408439 if List. mem Serve o.commands then
440+ let () =
441+ if o.server.Server. replace then
442+ let running = Learnocaml_server. check_running () in
443+ Option. iter Learnocaml_server. kill_running running;
444+ let temp = temp_app_dir o in
445+ let app_dir =
446+ if Filename. is_relative o.app_dir
447+ then Filename. concat (Sys. getcwd () ) o.app_dir
448+ else o.app_dir
449+ in
450+ let bak =
451+ let f =
452+ Filename. temp_file
453+ ~temp_dir: (Filename. dirname app_dir)
454+ (Filename. basename app_dir ^ " .bak." )
455+ " "
456+ in
457+ Unix. unlink f; f
458+ in
459+ if Sys. file_exists app_dir then Sys. rename app_dir bak;
460+ Sys. rename temp o.app_dir;
461+ Learnocaml_store. static_dir := app_dir;
462+ if Sys. file_exists bak then
463+ Lwt. dont_wait (fun () ->
464+ Lwt. pause () >> = fun () ->
465+ Lwt_process. exec (" rm" ,[|" rm" ;" -rf" ;bak|]) >> = fun r ->
466+ if r <> Unix. WEXITED 0 then
467+ Lwt. fail_with " Remove command failed"
468+ else Lwt. return_unit
469+ )
470+ (fun ex ->
471+ Printf. eprintf
472+ " Warning: while cleaning up older application \
473+ directory %s:\n %s\n %!"
474+ bak (Printexc. to_string ex))
475+ in
409476 let native_server = Sys. executable_name ^ " -server" in
410477 if Sys. file_exists native_server then
411478 let server_args =
@@ -416,30 +483,39 @@ let main o =
416483 (" --port=" ^ string_of_int o.server.port) ::
417484 (match o.server.cert with None -> [] | Some c -> [" --cert=" ^ c])
418485 in
419- Unix. execv native_server (Array. of_list (native_server::server_args))
486+ Lwt. return
487+ (`Continuation
488+ (fun () ->
489+ Unix. execv native_server
490+ (Array. of_list (native_server::server_args))))
420491 else begin
421492 Printf. printf " Starting server on port %d\n %!"
422493 ! Learnocaml_server. port;
423494 if o.builder.Builder. base_url <> " " then
424495 Printf. printf " Base URL: %s\n %!" o.builder.Builder. base_url;
425- Learnocaml_server. launch ()
496+ Learnocaml_server. launch () >> = fun ret ->
497+ Lwt. return (`Success ret)
426498 end
427499 else
428- Lwt. return true
500+ Lwt. return ( `Success true )
429501 in
430502 let ret =
431503 Lwt_main. run
432- (grade () >> = function
433- | Some i -> Lwt. return i
504+ (grade o >> = function
505+ | Some i -> Lwt. return ( `Code i)
434506 | None ->
435- generate () >> = fun success ->
507+ generate o >> = fun success ->
436508 if success then
437- run_server () >> = fun r ->
438- if r then Lwt. return 0 else Lwt. return 10
509+ run_server o >> = function
510+ | `Success true -> Lwt. return (`Code 0 )
511+ | `Success false -> Lwt. return (`Code 10 )
512+ | `Continuation f -> Lwt. return (`Continuation f)
439513 else
440- Lwt. return 1 )
514+ Lwt. return ( `Code 1 ) )
441515 in
442- exit ret
516+ match ret with
517+ | `Code n -> exit n
518+ | `Continuation f -> f ()
443519
444520let man =
445521 let open Manpage in
0 commit comments