Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature to allow reruns with different parameters in GobView #21

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
ae8f8c5
Use textfield instead of raw parameter string
sxprz Apr 8, 2023
834b4a4
Use Input component for better input field in ParameterView
sxprz Apr 15, 2023
621bd6f
Add replay button for different params and add history for prev params
sxprz Apr 22, 2023
da69b7e
Implement history list under param rerun (WIP)
sxprz May 6, 2023
a28ded2
Add keys to each list elem and try to manipulate input on Input compo…
sxprz May 7, 2023
55abb68
Change style of first param row
sxprz May 8, 2023
4233350
Group input and buttons
sxprz May 9, 2023
b74ad43
Implement correct scroll bar behaviour for param history
sxprz May 11, 2023
ec42bf6
Fix missing variable 'current'
sxprz May 11, 2023
6a57708
Move code further down
sxprz May 13, 2023
575f74a
Add checkmark indication for normal run; x symbol WIP for canceled runs
sxprz May 13, 2023
dc2de42
Add time for when run was started and redesign param history
sxprz May 14, 2023
85257ed
Introduce working status system for param runs in history
sxprz May 15, 2023
e6c49a9
Add important state management TODO for whole App
sxprz May 15, 2023
29641bf
Fix non-permanent state of history table after switching tabs
sxprz May 17, 2023
31b35be
Remove logging in Main.re
sxprz May 17, 2023
1d98255
Fix Time.timeToString() not showing leading 0 in minute on clock
sxprz May 17, 2023
fb00202
Impl requests for reruns via REST calls
sxprz May 29, 2023
c7c1fc0
Impl correct success/error indication for rerun
sxprz May 30, 2023
f43193b
Refactor code
sxprz May 30, 2023
fd726fa
Fix CORS errors on API call; WIP on bad requests
sxprz Jun 5, 2023
a1a75b4
Fix for Yojson Type_error
sxprz Jun 5, 2023
3efbb87
Fix errors and introduce tooltip in input WIP
sxprz Jun 5, 2023
9b96091
Introduce tooltip, refactor and WIP fix requests
sxprz Jun 6, 2023
192ace0
Use pill badges & WIP config requests
sxprz Jun 7, 2023
468a590
Impl sorting for parameter history
sxprz Jun 8, 2023
1347bec
Fix API calls WIP, not compilable due to let%lwt
sxprz Jun 13, 2023
d271f26
Impl working config endpoint, analyze WIP
sxprz Jun 14, 2023
eb52852
Remove lwt_ppx usage and unused code
sxprz Jun 14, 2023
d9d0282
Use other icon for history orientation
sxprz Jun 14, 2023
262f184
Add input validation for server opts, UI WIP
sxprz Jun 15, 2023
2e6c6b7
Improve UI design for validation
sxprz Jun 15, 2023
5b3c859
Add fully functioning validation for server opts
sxprz Jun 19, 2023
4c19464
Add bootstrap autocomplete library
sxprz Jun 19, 2023
4aed0fd
Use regexes to parse input
sxprz Jun 28, 2023
29dc719
Fix UI bugs and improve adding items to history
sxprz Jun 28, 2023
b210584
Impl clickable parameter chips
sxprz Jul 2, 2023
5372d08
Improve input feedback and clickable chip
sxprz Jul 2, 2023
7880a37
Introduce better error handling with feedback
sxprz Jul 4, 2023
34c72c3
Improve parameter recognition and fix bugs
sxprz Jul 5, 2023
1cc6942
Rearrange code for headers
sxprz Jul 5, 2023
9d38eca
Fix wrong regex for --set
sxprz Jul 5, 2023
de06648
Refactor code and optimize calls
sxprz Jul 10, 2023
235e2be
Impl updating files when rerun succeeded
sxprz Jul 11, 2023
d115870
Fix config endpoint call to respond correctly
sxprz Jul 11, 2023
b190c66
Clean unused deps
sxprz Jul 13, 2023
7780598
Prepare component ids for selenium tests
sxprz Jul 13, 2023
8a1bc4a
Change behavior when copying parameters
sxprz Jul 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
(name gobview)
(synopsis "Web frontend for Goblint")
(depends
cohttp
cohttp-lwt
cohttp-lwt-jsoo
dune
(ocaml (>= 4.10.0))
batteries
Expand All @@ -37,6 +40,8 @@
ppx_yojson_conv ; TODO: switch to ppx_deriving_yojson like Goblint itself
conduit-lwt-unix
jsoo-react
lwt
uri
(goblint-cil (>= 2.0.0))
ctypes_stubs_js
integers_stubs_js
Expand Down
4 changes: 0 additions & 4 deletions goblint-http-server/goblint.ml
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,7 @@ let config_raw goblint name value =
| Ok _ -> Lwt.return_unit
| Error err -> invalid_arg err.message

let option_whitelist = [] |> Set.of_list

let config goblint name value =
if not (Set.mem name option_whitelist) then
invalid_arg (Printf.sprintf "Option '%s' is not in the whitelist" name);
with_lock goblint (fun () -> config_raw goblint name value)

let temp_dir () = Utils.temp_dir "goblint-http-server." ""
Expand Down
27 changes: 18 additions & 9 deletions goblint-http-server/goblint_http.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ open Cohttp_lwt
open Cohttp_lwt_unix
open Lwt.Infix

module Header = Cohttp.Header
module Yojson_conv = Ppx_yojson_conv_lib.Yojson_conv

let docroot = ref "run"
let index = ref "index.html"
let addr = ref "127.0.0.1"
let port = ref 8080
let port = ref 8000
let goblint = ref "goblint"
let rest = ref []

Expand All @@ -24,31 +25,38 @@ let specs =

let paths = ref []

let cors_headers =
[
("Access-Control-Allow-Origin", "*");
("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers");
("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
] |> Header.of_list

let process state name body =
match Hashtbl.find_option Api.registry name with
| None -> Server.respond_not_found ()
| Some (module R) ->
let%lwt body = Body.to_string body in
let body = if body = "" then "null" else body in
match Yojson.Safe.from_string body with
| exception Yojson.Json_error err -> Server.respond_error ~status:`Bad_request ~body:err ()
| exception Yojson.Json_error err -> Server.respond_error ~headers:cors_headers ~status:`Bad_request ~body:err ()
| json ->
match R.body_of_yojson json with
| exception Yojson_conv.Of_yojson_error (exn, _) ->
Server.respond_error ~status:`Bad_request ~body:(Printexc.to_string exn) ()
Server.respond_error ~headers:cors_headers ~status:`Bad_request ~body:(Printexc.to_string exn) ()
| body ->
Lwt.catch
(fun () ->
R.process state body
>|= R.yojson_of_response
>|= Yojson.Safe.to_string
>>= fun body -> Server.respond_string ~status:`OK ~body ())
(fun exn -> Server.respond_error ~status:`Bad_request ~body:(Printexc.to_string exn) ())
>>= fun body -> Server.respond_string ~headers:cors_headers ~status:`OK ~body ())
(fun exn -> Server.respond_error ~headers:cors_headers ~status:`Bad_request ~body:(Printexc.to_string exn) ())

(* The serving of files is implemented similar as in the binary https://github.com/mirage/ocaml-cohttp/blob/master/cohttp-lwt-unix/bin/cohttp_server_lwt.ml *)
let serve_file ~docroot ~uri =
let fname = Cohttp.Path.resolve_local_file ~docroot ~uri in
Server.respond_file ~fname ()
Server.respond_file ~headers:cors_headers ~fname ()

let sort lst =
let compare_kind = function
Expand Down Expand Up @@ -102,7 +110,7 @@ let serve uri path =
| Unix.S_DIR -> (
let path_len = String.length path in
if path_len <> 0 && path.[path_len - 1] <> '/' then (
Server.respond_redirect ~uri:(Uri.with_path uri (path ^ "/")) ())
Server.respond_redirect ~headers:cors_headers ~uri:(Uri.with_path uri (path ^ "/")) ())
else (
match Sys.file_exists (Filename.concat file_name !index) with
| true -> (
Expand All @@ -122,12 +130,12 @@ let serve uri path =
f ))
(fun _exn -> Lwt.return (None, f))) files in
let body = html_of_listing uri path (sort listing) in
Server.respond_string ~status:`OK ~body ()))
Server.respond_string ~headers:cors_headers ~status:`OK ~body ()))
| Unix.S_REG -> serve_file ~docroot:!docroot ~uri
| _ -> (
let body = Printf.sprintf "<html><body><h2>Forbidden</h2><p><b>%s</b> is not a normal file or \
directory</p><hr/></body></html>" path in
Server.respond_string ~status:`OK ~body ()))
Server.respond_string ~headers:cors_headers ~status:`OK ~body ()))
(function
| Unix.Unix_error (Unix.ENOENT, "stat", p) as e ->
if p = file_name then (
Expand All @@ -143,6 +151,7 @@ let callback state _ req body =
match meth, parts with
| `POST, ["api"; name] -> process state name body
| `GET, _ -> serve uri path
| `OPTIONS, _ -> Server.respond ~headers:cors_headers ~status:`OK ~body:`Empty () (* Used for preflight and CORS requests *)
| _ -> Server.respond_not_found ()

let main () =
Expand Down
5 changes: 5 additions & 0 deletions gobview.opam
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ license: "MIT"
homepage: "https://github.com/goblint/gobview"
bug-reports: "https://github.com/goblint/gobview/issues"
depends: [
"cohttp"
"cohttp-lwt"
"cohttp-lwt-jsoo"
"dune" {>= "2.7"}
"ocaml" {>= "4.10.0"}
"batteries"
Expand All @@ -26,6 +29,8 @@ depends: [
"ppx_yojson_conv"
"conduit-lwt-unix"
"jsoo-react"
"lwt"
"uri"
"goblint-cil" {>= "2.0.0"}
"ctypes_stubs_js"
"integers_stubs_js"
Expand Down
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

94 changes: 3 additions & 91 deletions src/App.re
Original file line number Diff line number Diff line change
@@ -1,100 +1,12 @@
open Goblint_lib;
open Batteries;
open Js_of_ocaml;
open Lwt.Infix;
module Cabs2cil = GoblintCil.Cabs2cil;

exception InitFailed(string);

let init_cil = environment => {
// Restore the environment hash table, which
// syntacticsearch uses to map temporary variables created
// by CIL to their original counterparts.
Hashtbl.clear(Cabs2cil.environment);
environment
|> Hashtbl.enum
|> Enum.iter(((k, v)) => Hashtbl.add(Cabs2cil.environment, k, v));
};

// Each Goblint analysis module is assigned an ID, and this
// ID depends on the module registration order, which might
// differ from build to build. This function reorders the
// analysis list to match the native version of Goblint.
let renumber_goblint_analyses = registered_name => {
let old_registered = Hashtbl.copy(MCP.registered);
let old_registered_name = Hashtbl.copy(MCP.registered_name);
Hashtbl.clear(MCP.registered);
Hashtbl.clear(MCP.registered_name);
Hashtbl.iter((name, id) => {
let old_id = Hashtbl.find(old_registered_name, name);
let spec = Hashtbl.find(old_registered, old_id);
Hashtbl.replace(MCP.registered, id, spec);
Hashtbl.replace(MCP.registered_name, name, id);
}, registered_name);
};

let init_goblint = (solver, spec, registered_name, config, cil) => {
AfterConfig.run(); // This registers the "base" analysis

try(renumber_goblint_analyses(registered_name)) {
| Not_found =>
raise(InitFailed("Failed to renumber Goblint analyses"))
};

Sys.chdir("/"); // Don't remove this

Sys_js.create_file(~name="/goblint/solver.marshalled", ~content=solver);
Sys_js.create_file(~name="/goblint/config.json", ~content=config);
Sys_js.create_file(~name="/goblint/spec_marshal", ~content=spec);

GobConfig.merge_file(Fpath.v("/goblint/config.json"));

GobConfig.set_bool("dbg.verbose", true);
// TODO: Uncomment this to improve performance in future
// GobConfig.set_bool("verify", false);

// For some reason, the standard Batteries output channels
// appear to be closed by default and writing to them
// raises [BatInnerIO.Output_closed]. This fixes it.
let out = IO.output_channel(Stdlib.stdout);
Messages.formatter := Format.formatter_of_output(out);

GobConfig.set_string("load_run", "goblint");

// These two will be set by config.json. Reset them.
GobConfig.set_string("save_run", "");
GobConfig.set_bool("gobview", false);

GobConfig.set_auto("trans.activated[+]", "'expeval'");

Cilfacade.init();
Maingoblint.handle_extraspecials();
Maingoblint.handle_flags();

// NOTE: Commenting this out since it breaks the node view. Semantic search
// may depend on this code but it is currently broken because of unrelated
// (and uknown) reasons anyway.
// Cil.iterGlobals(cil, glob =>
// switch (glob) {
// | GFun(fd, _) =>
// Cil.prepareCFG(fd);
// Cil.computeCFGInfo(fd, true);
// | _ => ()
// }
// );
Cilfacade.current_file := cil;

let goblint = GvGoblint.unmarshal(spec, cil);

(goblint, cil);
};
open Init;

let init = (solver, spec, config, meta, cil, analyses, warnings, stats, file_loc) => {
let cil =
switch (cil) {
| Ok(s) =>
let (c, e) = Marshal.from_string(s, 0);
init_cil(e);
Init.init_cil(e);
c;
| _ => raise(InitFailed("Failed to load CIL state"))
};
Expand Down Expand Up @@ -172,6 +84,6 @@ let handle_error = exc => {
| exc => handle_error(exc)
}
| _ => ()
},
}
)
);
Loading