Skip to content

Commit

Permalink
This monster commit works towards #45
Browse files Browse the repository at this point in the history
This supports the Theia IDE with appropriate endpoints.
  • Loading branch information
Neeraj Sharma committed Apr 10, 2018
1 parent 6d27687 commit d6ef0ce
Show file tree
Hide file tree
Showing 28 changed files with 3,701 additions and 24 deletions.
39 changes: 39 additions & 0 deletions include/beamparticle_constants.hrl
Expand Up @@ -126,3 +126,42 @@
%% limit the maximum number of log events for dynamic function
%% to keep the memory bounded
-define(MAX_LOG_EVENTS, 1000).


-define(DEFAULT_IDE_TERMINAL_WELCOME_1,
<<"\r
____ \r
/ __ ) ___ ____ _ ____ ___ \r
/ __ |/ _ \ / __ `// __ `__ \ \r
/ /_/ // __// /_/ // / / / / / \r
/_____/ \___/ \__,_//_/ /_/ /_/ \r
____ __ _ __ \r
/ __ \ ____ _ _____ / /_ (_)_____ / /___ \r
/ /_/ // __ `// ___// __// // ___// // _ \ \r
/ ____// /_/ // / / /_ / // /__ / // __/ \r
/_/ \__,_//_/ \__//_/ \___//_/ \___/ \r
\r
\r
- BEAM will carry you at the speed of light.\r
\r
">>).
-define(DEFAULT_IDE_TERMINAL_WELCOME,
<<"\r
+-++-++-++-+ \r
|B||e||a||m| \r
+-++-++-++-+ \r
+-++-++-++-++-++-++-++-+ \r
|P||a||r||t||i||c||l||e| \r
+-++-++-++-++-++-++-++-+ \r
\r
\r
- BEAM will carry you at the speed of light.\r
\r
">>).

-define(DEFAULT_IDE_TERMINAL_WELCOME_SHORT, <<"\r
- BEAM will carry you at the speed of light.\r
\r
">>).
-define(DEFAULT_IDE_TERMINAL_PROMPT, <<"$ ">>).

2 changes: 2 additions & 0 deletions priv/ide/readme.md
@@ -0,0 +1,2 @@
Copy the built contents of the following here
https://github.com/theia-ide/theia/examples/browser/lib
3 changes: 3 additions & 0 deletions rebar.config
Expand Up @@ -140,6 +140,9 @@
{forms, {git, "https://github.com/efcasado/forms", {branch, "master"}}},
{meta, {git, "https://github.com/efcasado/meta", {branch, "master"}}},

%% hawk is watching over fs changes
{inotify, {git, "https://github.com/sheyll/inotify", {branch, "master"}}},

{erlexec, {git, "https://github.com/saleyn/erlexec", {branch, "master"}}},

%% sandbox for Erlang (TODO)
Expand Down
4 changes: 4 additions & 0 deletions rebar.lock
Expand Up @@ -123,6 +123,10 @@
{git,"git://github.com/cmullaparthi/ibrowse.git",
{ref,"8c46b108bb648119b90433f9c60ed36bb25e29cd"}},
1},
{<<"inotify">>,
{git,"https://github.com/sheyll/inotify",
{ref,"8d1e97d6db6c9e12573bf75a93fc74979e69e8e8"}},
0},
{<<"jiffy">>,
{git,"https://github.com/davisp/jiffy.git",
{ref,"7602deef034527c136b3bebc006b91ee87e785b4"}},
Expand Down
1 change: 1 addition & 0 deletions src/beamparticle.app.src
Expand Up @@ -59,6 +59,7 @@
enm,
elixir,
syntax_tools,
inotify,
alcove
]},
{included_applications, [
Expand Down
19 changes: 19 additions & 0 deletions src/beamparticle_app.erl
Expand Up @@ -244,6 +244,23 @@ start_http_server(PrivDir, Port, HttpRestConfig) ->
{"/static/[...]", cowboy_static, {dir, PrivDir ++ "/static"}},
{"/", cowboy_static, {file, PrivDir ++ "/index.html"}},
{"/dev", cowboy_static, {file, PrivDir ++ "/index-dev.html"}},
{"/ide", cowboy_static, {file, PrivDir ++ "/ide/index.html"}},
{"/ide/services/filesystem", beamparticle_ide_filesystem_ws_handler, []},
{"/ide/services/workspace", beamparticle_ide_workspace_ws_handler, []},
{"/ide/services/git", beamparticle_ide_git_ws_handler, []},
{"/ide/services/extensions", beamparticle_ide_extensions_ws_handler, []},
{"/ide/services/git-watcher", beamparticle_ide_gitwatcher_ws_handler, []},
{"/ide/services/fs-watcher", beamparticle_ide_fswatcher_ws_handler, []},
{"/ide/services/shell-terminal", beamparticle_ide_shellterminal_ws_handler, []},
{"/ide/services/terminals/[:id]", beamparticle_ide_terminals_ws_handler, []},
{"/ide/search-in-workspace", beamparticle_ide_searchinworkspace_ws_handler, []},
{"/ide/services/messageService", beamparticle_ide_messageservice_ws_handler, []},
{"/ide/services/application", beamparticle_ide_application_ws_handler, []},
{"/ide/services/search", beamparticle_ide_search_ws_handler, []},
{"/ide/services/task", beamparticle_ide_task_ws_handler, []},
{"/ide/services/logger", beamparticle_ide_logger_ws_handler, []},
{"/ide/alive", beamparticle_ide_alive_handler, []},
{"/ide/[...]", cowboy_static, {dir, PrivDir ++ "/ide"}},
{"/auth/google/[...]", beamparticle_google_oauth_handler, []},
{"/fun/[:id]", beamparticle_generic_handler, [beamparticle_dynamic_function_model]},
%% /post is now depricated, instead use /api/[:id] with POST
Expand Down Expand Up @@ -322,6 +339,8 @@ start_http_nlp_server(HttpNLPRestConfig) ->
%%{"/", cowboy_static, {priv_file, beamparticle, "index.html"}},
{"/static/[...]", cowboy_static, {dir, PrivDir ++ "/static"}},
{"/dev", cowboy_static, {file, PrivDir ++ "/index-dev.html"}},
{"/ide", cowboy_static, {file, PrivDir ++ "/ide/index.html"}},
{"/ide/[...]", cowboy_static, {dir, PrivDir ++ "/ide"}},
{"/", beamparticle_nlp_top_page_handler, []},
{"/auth/google/[...]", beamparticle_google_oauth_handler, []},
%% /post is now depricated, instead use /api/[:id] with POST
Expand Down
34 changes: 34 additions & 0 deletions src/beamparticle_dynamic.erl
Expand Up @@ -29,6 +29,7 @@
-export([run_concurrent/2,
async_run_concurrent/2,
run_concurrent_without_log_and_result/2]).
-export([stage/2, release/1]).

%% @doc Get dynamic function configuration from process dictionary
-spec get_config() -> map().
Expand Down Expand Up @@ -254,6 +255,39 @@ receive_concurrent_tasks_without_log_and_result(Ref, Pids, TimeoutMsec) ->
{error, timeout}
end.

-spec stage(GitSrcFilename :: string(), State :: term()) -> ok.
stage(GitSrcFilename, State) when is_list(GitSrcFilename) ->
erlang:put(?CALL_ENV_KEY, stage), %% TODO read the config for prod in sys.config and act accordingly
GitBackendConfig = application:get_env(?APPLICATION_NAME, gitbackend, []),
GitRootPath = proplists:get_value(rootpath, GitBackendConfig, "./"),
GitSrcPath = GitRootPath ++ "/git-src/" ++ GitSrcFilename,
case file:read_file(GitSrcPath) of
{ok, FunctionBody} ->
[FunctionNameStr | _] = string:split(GitSrcFilename, "."),
FunctionName = list_to_binary(FunctionNameStr),
R1 = beamparticle_ws_handler:handle_save_command(FunctionName, FunctionBody, State),
{reply, {text, JsonResp1}, _, _} = R1,
RespMap = jiffy:decode(JsonResp1, [return_maps]),
{proplists, [{<<"html">>, maps:get(<<"html">>, RespMap, <<>>)},
{<<"text">>, maps:get(<<"text">>, RespMap, <<>>)}]};
%% lager:info("beamparticle_ws_handler:handle_save_command(~p, ~p, ~p)", [FunctionName, FunctionBody, State]),
%% Msg = <<"NOT implemented">>,
%% {reply, {text, jiffy:encode(#{<<"speak">> => Msg, <<"text">> => Msg})}, State, hibernate};
_ ->
Msg = iolist_to_binary([<<"Error: Cannot find file ">>, list_to_binary(GitSrcPath)]),
{proplists, [{<<"speak">>, Msg}, {<<"text">>, Msg}]}
%% {reply, {text, jiffy:encode(#{<<"speak">> => Msg, <<"text">> => Msg})}, State, hibernate}
end.

-spec release(State :: term()) -> ok.
release(State) ->
R = beamparticle_ws_handler:handle_release_command(State),
{reply, {text, JsonResp}, _, _} = R,
RespMap = jiffy:decode(JsonResp, [return_maps]),
{proplists, [{<<"html">>, maps:get(<<"html">>, RespMap, <<>>)},
{<<"text">>, maps:get(<<"text">>, RespMap, <<>>)}]}.


%% @doc Create a pool of dynamic function with given configuration
-spec create_pool(PoolName :: atom(),
PoolSize :: pos_integer(),
Expand Down
7 changes: 7 additions & 0 deletions src/beamparticle_erlparser.erl
Expand Up @@ -583,6 +583,13 @@ execute_dynamic_function(FunctionNameBin, Arguments)
apply(beamparticle_dynamic,
async_run_concurrent,
Arguments);
{<<"stage">>, 1} ->
[Arg1] = Arguments,
%% TODO empty State for now
beamparticle_dynamic:stage(Arg1, []);
{<<"release">>, 0} ->
%% TODO empty State for now
beamparticle_dynamic:release([]);
_ ->
lager:debug("FunctionNameBin=~p, Arguments=~p", [RealFunctionNameBin, Arguments]),
R = list_to_binary(io_lib:format("Please teach me what must I do with ~s(~s)", [RealFunctionNameBin, lists:join(",", [io_lib:format("~p", [X]) || X <- Arguments])])),
Expand Down
100 changes: 100 additions & 0 deletions src/beamparticle_git_util.erl
@@ -0,0 +1,100 @@
%%%-------------------------------------------------------------------
%%% @author neerajsharma
%%% @copyright (C) 2017, Neeraj Sharma <neeraj.sharma@alumni.iitg.ernet.in>
%%% @doc
%%%
%%% The inspiration for implementation of these utility functions is
%%% as follows:
%%%
%%%
%%% * https://git-scm.com/docs/git-status#_short_format
%%% * https://github.com/theia-ide/dugite-extra/blob/master/src/command/
%%%
%%% @end
%%%
%%% %CopyrightBegin%
%%%
%%% Copyright Neeraj Sharma <neeraj.sharma@alumni.iitg.ernet.in> 2017.
%%% All Rights Reserved.
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
%%% You may obtain a copy of the License at
%%%
%%% http://www.apache.org/licenses/LICENSE-2.0
%%%
%%% Unless required by applicable law or agreed to in writing, software
%%% distributed under the License is distributed on an "AS IS" BASIS,
%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%%% See the License for the specific language governing permissions and
%%% limitations under the License.
%%%
%%% %CopyrightEnd%
%%%-------------------------------------------------------------------
-module(beamparticle_git_util).

-export([parse_git_status/1]).
-export([git_status_command/0,
git_show_command/3,
git_log_command/1,
git_branch_command/2,
git_branch_command/1]).


%% @doc Git command used for retrieving the repo status
%%
%% Git command which generated the content is as follows:
%% git status --untracked-files=all --branch --porcelain -z
git_status_command() ->
[<<"git">>, <<"status">>, <<"--untracked-files=all">>, <<"--branch">>, <<"--porcelain">>, <<"-z">>].

%% @doc Parse git status output into meaningful information
%%
%%
%% @see git_status_command/0
%%
%%
%% ```
%% A = <<"## master\0M nlpfn_top_page.erl.fun\0 M test.erl\0A test3.erl.fun\0M test_get.erl.fun\0A test_java2.java.fun\0A test_python_simple_http.py.fun\0?? res\0?? test.py\0?? test_conditions.erl.fun\0">>,
%% parse_git_status(A)
%% '''
%%
parse_git_status(GitStatusContent) ->
Lines = string:split(GitStatusContent, <<"\0">>, all),
[BranchLine | Rest] = Lines,
<<"## ", BranchName/binary>> = BranchLine,
ChangedFiles = lists:foldl(fun(<<>>, AccIn) ->
AccIn;
(E, AccIn) ->
[Status, Filename] = binary:split(E, <<" ">>, [global, trim_all]),
FileStatus = maps:get(Filename, AccIn, []),
AccIn#{Filename => [Status | FileStatus]}
end, #{}, Rest),
#{<<"branch">> => BranchName,
<<"changes">> => ChangedFiles}.


%% @doc Get git file contents at a given reference, commit or tree
%%
%% git show COMMITSHA1:PATH
git_show_command(hash, Hash, RelativeFilePath) ->
[<<"git">>, <<"show">>, <<Hash/binary, ":", RelativeFilePath/binary>>].

%% @doc Get git log hash for a given file.
%%
%% For short hash:
%% git log --follow --pretty="%h"
%% For long hash:
%% git log --follow --pretty="%H"
%%
git_log_command(short) ->
[<<"git">>, <<"log">>, <<"--follow">>, <<"--pretty=\"%h\"">>];
git_log_command(full) ->
[<<"git">>, <<"log">>, <<"--follow">>, <<"--pretty=\"%H\"">>].


git_branch_command(list, current) ->
[<<"git">>, <<"rev-parse">>, <<"--abbrev-ref">>, <<"HEAD">>].

git_branch_command(list_branches) ->
[<<"git">>, <<"for-each-ref">>, <<"--format=\"%(refname)%00%(refname:short)%00%(upstream:short)%00%(objectname)%00%(author)%00%(parent)%00%(subject)%00%(body)%00\"">>, <<"HEAD">>].
53 changes: 30 additions & 23 deletions src/beamparticle_gitbackend_server.erl
Expand Up @@ -323,27 +323,34 @@ git_save_file(Drv, Path, FullFilename, Content, Msg, TimeoutMsec) ->
{0, _, _} = execute_command(
Drv, Path, ?GIT_BINARY, ["add", FullFilename],
TimeoutMsec),
CommitResult = execute_command(
Drv, Path, ?GIT_BINARY, ["commit", "-m", Msg],
TimeoutMsec),
case CommitResult of
{0, _, _} ->
{0, HashStdout, _} = execute_command(
Drv, Path, ?GIT_BINARY, ["log", "-n1", "--format=\"%H\"",
"-n", "1"],
TimeoutMsec),
%% when running git command via exec it returns the
%% hash wrapped in double quotes, so remove them.
Hash = re:replace(string:trim(HashStdout), <<"\"">>, <<>>, [{return, binary}, global]),
{0, ChangedFilesWithCommitStdout, _} = execute_command(
Drv, Path, ?GIT_BINARY, ["show", "--oneline",
"--name-only", Hash],
TimeoutMsec),
%% The first line is the abbreviated commit message,
%% so ignore that
[_ | ChangedFiles] = string:split(ChangedFilesWithCommitStdout, "\n", all),
{ok, Hash, ChangedFiles};
{1, _, _} ->
%% nothing to commit, working directory clean
{ok, "", []}
case is_binary(Msg) of
%% commit ony when a valid commit message is provided
%% else just save to disk, which is done already
true ->
CommitResult = execute_command(
Drv, Path, ?GIT_BINARY, ["commit", "-m", Msg],
TimeoutMsec),
case CommitResult of
{0, _, _} ->
{0, HashStdout, _} = execute_command(
Drv, Path, ?GIT_BINARY, ["log", "-n1", "--format=\"%H\"",
"-n", "1"],
TimeoutMsec),
%% when running git command via exec it returns the
%% hash wrapped in double quotes, so remove them.
Hash = re:replace(string:trim(HashStdout), <<"\"">>, <<>>, [{return, binary}, global]),
{0, ChangedFilesWithCommitStdout, _} = execute_command(
Drv, Path, ?GIT_BINARY, ["show", "--oneline",
"--name-only", Hash],
TimeoutMsec),
%% The first line is the abbreviated commit message,
%% so ignore that
[_ | ChangedFiles] = string:split(ChangedFilesWithCommitStdout, "\n", all),
{ok, Hash, ChangedFiles};
{1, _, _} ->
%% nothing to commit, working directory clean
{ok, "", []}
end;
false ->
ok
end.

0 comments on commit d6ef0ce

Please sign in to comment.