aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/top/src/erl_html_tools.erl
diff options
context:
space:
mode:
authorLars G Thorsen <[email protected]>2010-02-11 07:13:28 +0000
committerErlang/OTP <[email protected]>2010-02-11 07:13:28 +0000
commit75bc5e521dcc9ab798acefb5400f5f15354f08fd (patch)
tree7d30692d4e91dba347f6fabec4e533df1a1cd998 /system/doc/top/src/erl_html_tools.erl
parente1b759c0863e677527577af7cbf436d0574cbb00 (diff)
downloadotp-75bc5e521dcc9ab798acefb5400f5f15354f08fd.tar.gz
otp-75bc5e521dcc9ab798acefb5400f5f15354f08fd.tar.bz2
otp-75bc5e521dcc9ab798acefb5400f5f15354f08fd.zip
OTP-8343 The documentation is now possible to build in an open source
environment after a number of bugs are fixed and some features are added in the documentation build process. - The arity calculation is updated. - The module prefix used in the function names for bif's are removed in the generated links so the links will look like "http://www.erlang.org/doc/man/erlang.html#append_element-2" instead of "http://www.erlang.org/doc/man/erlang.html#erlang:append_element- 2". - Enhanced the menu positioning in the html documentation when a new page is loaded. - A number of corrections in the generation of man pages (thanks to Sergei Golovan) - The legal notice is taken from the xml book file so OTP's build process can be used for non OTP applications.
Diffstat (limited to 'system/doc/top/src/erl_html_tools.erl')
-rw-r--r--system/doc/top/src/erl_html_tools.erl293
1 files changed, 125 insertions, 168 deletions
diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl
index d93516768e..8a5c744128 100644
--- a/system/doc/top/src/erl_html_tools.erl
+++ b/system/doc/top/src/erl_html_tools.erl
@@ -1,130 +1,66 @@
-%% ``The contents of this file are subject to the Erlang Public License,
+%%--------------------------------------------------------------------
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
+%% retrieved online at http://www.erlang.org/.
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
--module(erl_html_tools).
-
-%% This file contains tools for updating HTML files in an installed system
-%% depending on the installed applications. Currently the only use is
-%% to update the top index file.
-
-
-%% ------ VERY IMPORTANT ------
%%
-%% Original location for this file:
-%% /clearcase/otp/internal_tools/integration/scripts/make_index/
-%% When updating this file, copy the source to
-%% /home/otp/patch/share/program/
-%% and place .beam files (compiled with correct release) in all
-%% /home/otp/patch/share/program/<release>
-%% for releases >= R9C
+%% %CopyrightEnd%
%%
-%% ----------------------------
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-% This program generate the top index files for the OTP documentation.
-% Part of the HTML code is in templates, like "index.html.src" and
-% part is written out from this module. So the program and the templates
-% has to match.
-%
-% The templates are searched from the current directory, a directory
-% "templates" relative to the current directory or at RootDir.
-%
-% RootDir is given as an argument or assumed to be code:root_dir(),
-% i.e. the root of the system running this program.
-%
-% The output is put into DestDir or RootDir if not given.
-%
-% The functions to call are
-%
-% top_index()
-% top_index([RootDir])
-% top_index([RootDir,DestDir,OtpRel])
-% top_index(RootDir)
-% top_index(RootDir, DestDir, OtpRel)
-%
-% where RootDir can be a string or an atom.
-%
-%
-% USING THIS SCRIPT FROM THE UNIX COMMAND LINE
-% --------------------------------------------
-% If the Erlang started is the same as the Erlang to create index.html
-% for the use
-%
-% % erl -noshell -s erl_html_tools top_index
-%
-% If you want to create an index for another Erlang installation or
-% documentation located separate from the object code, then use
-%
-% % erl -noshell -s erl_html_tools top_index /path/to/erlang/root
-%
-%
-% COLLECTING INFORMATION
-% ----------------------
-% This script assumes that all applications have an "info" file
-% in their top directory. This file should have some keywords with
-% values defined. The keys are 'group' and 'short' (for "short
-% description). See the OTP applications for examples.
-%
-% Some HTML code is generated by this program, others are taken from
-% the file "index.html.src" that may be located in the patch directory
-% or in the "$ERLANG_ROOT/doc/" directory.
-%
-% The code for creating the top index page assumes all applications
-% have a file "info" with some fields filled in
-%
-% short: Text Short text describing the application
-% group: tag [Heading] Group tag optionally followed by a description.
-% Only one app need to describe the group but
-% more than one can.
-%
-% FIXME: Check that there is documentation for the application, not just
-% an info file.
-% FIXME: Use records, it is now unreadable :-(
-% FIXME: Use a separate URL and URLIndexFile
-% FIXME: Pass the OTP release name as an argument instead of in
-% process dictionary (for elegance).
+%%-----------------------------------------------------------------
+%% File: erl_html_tools.erl
+%%
+%% Description:
+%% This file generates the top index of the documentation.
+%%
+%%-----------------------------------------------------------------
+-module(erl_html_tools).
-export([top_index/0,top_index/1,top_index/3,top_index_silent/3]).
-% This is the order groups are inserted into the file. Groups
-% not in this list is inserted in undefined order.
+-include_lib("kernel/include/file.hrl").
group_order() ->
[
- basic,
- dat,
- oam,
- orb,
- comm,
- tools
+ {basic, "Basic"},
+ {dat, "Database"},
+ {oam, "Operation & Maintenance"},
+ {comm, "Interface and Communication"},
+ {tools, "Tools"},
+ {test, "Test"},
+ {doc, "Documentation"},
+ {orb, "Object Request Broker & IDL"},
+ {misc, "Miscellaneous"}
].
top_index() ->
- top_index(code:root_dir()).
+ case os:getenv("ERL_TOP") of
+ false ->
+ io:format("Variable ERL_TOP is required\n",[]);
+ Value ->
+ {_,RelName} = init:script_id(),
+ top_index(Value, filename:join(Value, "doc"), RelName)
+ end.
-top_index([RootDir]) when atom(RootDir) ->
- top_index(atom_to_list(RootDir));
-top_index([RootDir,DestDir,OtpRel])
+top_index([RootDir, DestDir, OtpRel])
when is_atom(RootDir), is_atom(DestDir), is_atom(OtpRel) ->
top_index(atom_to_list(RootDir), atom_to_list(DestDir), atom_to_list(OtpRel));
-top_index(RootDir) ->
+top_index(RootDir) when is_atom(RootDir) ->
{_,RelName} = init:script_id(),
top_index(RootDir, filename:join(RootDir, "doc"), RelName).
+
+
top_index(RootDir, DestDir, OtpRel) ->
report("****\nRootDir: ~p", [RootDir]),
report("****\nDestDir: ~p", [DestDir]),
@@ -145,7 +81,9 @@ top_index_silent(RootDir, DestDir, OtpRel) ->
Result = top_index(RootDir, DestDir, OtpRel),
erase(silent),
Result.
-
+
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Main loop - process templates
@@ -173,7 +111,7 @@ process_multi_template(BaseName0, Template, DestDir, Info) ->
BaseName1 = filename:basename(BaseName0, Ext),
[_|BaseName2] = lists:reverse(BaseName1),
BaseName = lists:reverse(BaseName2),
- Groups0 = [{[$_|atom_to_list(G)],G} || G <- group_order()],
+ Groups0 = [{[$_|atom_to_list(G)],G} || {G, _} <- group_order()],
Groups = [{"",basic}|Groups0],
process_multi_template_1(Groups, BaseName, Ext, Template, DestDir, Info).
@@ -240,34 +178,47 @@ find_information(Bases) ->
find_application_paths([]) ->
[];
-find_application_paths([{URL,Dir} | Paths]) ->
+find_application_paths([{URL, Dir} | Paths]) ->
Sub1 = "doc/html/index.html",
%% Sub2 = "doc/index.html",
- case file:list_dir(Dir) of
- {ok, Dirs} ->
- AppDirs =
- lists:filter(
- fun(E) ->
- is_match(E, "^[A-Za-z0-9_]+-[0-9\\.]+")
- end, Dirs),
- AppPaths =
- lists:map(
- fun(AppDir) ->
- {ok,[App,Ver]} = regexp:split(AppDir, "-"),
- DirPath = filename:join(Dir,AppDir),
- AppURL = URL ++ AppDir,
- {App,Ver,DirPath,AppURL ++ "/" ++ Sub1}
-%% case file:read_file_info(
-%% filename:join(DirPath, Sub1)) of
-%% {ok, _} ->
-%% {App,Ver,DirPath,AppURL ++ "/" ++ Sub1};
-%% _ ->
-%% {App,Ver,DirPath,AppURL ++ "/" ++ Sub2}
-%% end
- end, AppDirs),
- AppPaths ++ find_application_paths(Paths)
- end.
+ AppDirs = get_app_dirs(Dir),
+
+ AppPaths =
+ lists:map(
+ fun({App, AppPath}) ->
+ VsnFile = filename:join(AppPath, "vsn.mk"),
+ VsnStr =
+ case file:read_file(VsnFile) of
+ {ok, Bin} ->
+ case re:run(Bin, ".*VSN\s*=\s*([0-9\.]+).*",[{capture,[1],list}]) of
+ {match, [V]} ->
+ V;
+ nomatch ->
+ exit(io_lib:format("No VSN variable found in ~s\n",
+ [VsnFile]))
+ end;
+ {error, Reason} ->
+ exit(io_lib:format("~p : ~s\n", [Reason, VsnFile]))
+ end,
+ AppURL = URL ++ App ++ "-" ++ VsnStr,
+ {App, VsnStr, AppPath, AppURL ++ "/" ++ Sub1}
+ end, AppDirs),
+ AppPaths ++ find_application_paths(Paths).
+
+get_app_dirs(Dir) ->
+ {ok, Files} = file:list_dir(Dir),
+ AFiles =
+ lists:map(fun(File) -> {File, filename:join([Dir, File])} end, Files),
+ lists:zf(fun is_app_with_doc/1, AFiles).
+
+is_app_with_doc({ADir, APath}) ->
+ case file:read_file_info(filename:join([APath, "info"])) of
+ {ok, _FileInfo} ->
+ {true, {ADir, APath}};
+ _ ->
+ false
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Find info for one application.
@@ -281,20 +232,20 @@ find_application_paths([{URL,Dir} | Paths]) ->
find_application_infos([]) ->
[];
-find_application_infos([{App,Ver,AppPath,IndexURL} | Paths]) ->
+find_application_infos([{App, Vsn, AppPath, IndexURL} | Paths]) ->
case read_info(filename:join(AppPath,"info")) of
{error,_Reason} ->
warning("No info for app ~p", [AppPath]),
find_application_infos(Paths);
Db ->
- {Group,Heading} =
+ {Group,_Heading} =
case lists:keysearch("group", 1, Db) of
{value, {_, G0}} ->
% This value may be in two parts,
% tag and desciption
- case string:str(G0," ") of
+ case string:str(G0, " ") of
0 ->
- {list_to_atom(G0),""};
+ {list_to_atom(G0), ""};
N ->
{list_to_atom(string:substr(G0,1,N-1)),
string:substr(G0,N+1)}
@@ -309,7 +260,8 @@ find_application_infos([{App,Ver,AppPath,IndexURL} | Paths]) ->
false ->
""
end,
- [{Group,Heading,{App,{Ver,AppPath,IndexURL,Text}}}
+%% [{Group, Heading, {App, {Vsn, AppPath, IndexURL, Text}}}
+ [{Group, "", {App, {Vsn, AppPath, IndexURL, Text}}}
| find_application_infos(Paths)]
end.
@@ -439,17 +391,17 @@ search_appname(App, [{_Group,_,Apps} | Groups]) ->
search_appname(App, Groups)
end;
search_appname(_App, []) ->
- {error,noapp}.
+ {error, noapp}.
subst_applinks(Info, Group) ->
subst_applinks_1(group_order(), Info, Group).
-subst_applinks_1([G|Gs], Info0, Group) ->
+subst_applinks_1([{G, Heading}|Gs], Info0, Group) ->
case lists:keysearch(G, 1, Info0) of
- {value,{G,Heading,Apps}} ->
+ {value,{G,_Heading,Apps}} ->
Info = lists:keydelete(G, 1, Info0),
- ["\n<li>",Heading,"\n<ul>\n",
- html_applinks(Apps),"\n</ul></li>\n"|
+ ["\n<li>",Heading, "\n<ul>\n",
+ html_applinks(Apps), "\n</ul></li>\n"|
subst_applinks_1(Gs, Info, Group)];
false ->
warning("No applications in group ~w\n", [G]),
@@ -457,7 +409,7 @@ subst_applinks_1([G|Gs], Info0, Group) ->
end;
subst_applinks_1([], [], _) -> [];
subst_applinks_1([], Info, _) ->
- error("Info left:\n", [Info]),
+ error("Info left: ~p\n", [Info]),
[].
html_applinks([{Name,[{_,_,URL,_}|_]}|AppNames]) ->
@@ -482,9 +434,9 @@ subst_groups(Info0) ->
subst_known_groups([], Info, Text) ->
{Text,Info};
-subst_known_groups([Group | Groups], Info0, Text0) ->
+subst_known_groups([{Group, Heading} | Groups], Info0, Text0) ->
case lists:keysearch(Group, 1, Info0) of
- {value,{_,Heading,Apps}} ->
+ {value,{_,_Heading,Apps}} ->
Text = group_table(Heading,Apps),
Info = lists:keydelete(Group, 1, Info0),
subst_known_groups(Groups, Info, Text0 ++ Text);
@@ -634,34 +586,36 @@ combine_key_value([]) ->
lines_to_key_value([]) ->
[];
lines_to_key_value([Line | Lines]) ->
- case regexp:first_match(Line, "^[a-zA-Z_\\-]+:") of
+ case re:run(Line, "^[a-zA-Z_\\-]+:") of
nomatch ->
- case regexp:first_match(Line, "[\041-\377]") of
+ case re:run(Line, "[\041-\377]") of
nomatch ->
lines_to_key_value(Lines);
_ ->
warning("skipping line \"~s\"",[Line]),
lines_to_key_value(Lines)
end;
- {match, _, Length} ->
+ {match, [{0, Length} |_]} ->
Value0 = lists:sublist(Line, Length+1, length(Line) - Length),
- {ok, Value1, _} = regexp:sub(Value0, "^[ \t]*", ""),
- {ok, Value, _} = regexp:sub(Value1, "[ \t]*$", ""),
+ Value1 = re:replace(Value0, "^[ \t]*", "",
+ [{return, list}]),
+ Value = re:replace(Value1, "[ \t]*$", "",
+ [{return, list}]),
Key = lists:sublist(Line, Length-1),
- [{Key,Value} | lines_to_key_value(Lines)]
+ [{Key, Value} | lines_to_key_value(Lines)]
end.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Extensions to the 'regexp' module.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-is_match(Ex, Re) ->
- case regexp:first_match(Ex, Re) of
- {match, _, _} ->
- true;
- nomatch ->
- false
- end.
+%% is_match(Ex, Re) ->
+%% case regexp:first_match(Ex, Re) of
+%% {match, _, _} ->
+%% true;
+%% nomatch ->
+%% false
+%% end.
%% -type gsub(String, RegExp, Fun, Acc) -> subres().
%% Substitute every match of the regular expression RegExp with the
@@ -669,25 +623,27 @@ is_match(Ex, Re) ->
%% regular expressions. Acc is an argument to the Fun. The Fun should return
%% a tuple {Replacement, NewAcc}.
-gsub(String, RegExp, Fun, Acc) when list(RegExp) ->
- case regexp:parse(RegExp) of
- {ok,RE} -> gsub(String, RE, Fun, Acc);
- {error,E} -> {error,E}
+gsub(String, RegExp, Fun, Acc) when is_list(RegExp) ->
+ case re:compile(RegExp) of
+ {ok, RE} ->
+ gsub(String, RE, Fun, Acc);
+ {error, E} ->
+ {error, E}
end;
gsub(String, RE, Fun, Acc) ->
- {match,Ss} = regexp:matches(String, RE),
- {NewString, NewAcc} = sub_repl(Ss, Fun, Acc, String, 1),
- {ok,NewString,NewAcc}.
+ {match, Ss} = re:run(String, RE, [global]),
+ {NewString, NewAcc} = sub_repl(Ss, Fun, Acc, String, 0),
+ {ok, NewString, NewAcc}.
% New code that uses fun for finding the replacement. Also uses accumulator
% to pass argument between the calls to the fun.
-sub_repl([{St,L}|Ss], Fun, Acc0, S, Pos) ->
- Match = string:substr(S, St, L),
+sub_repl([[{St, L}] |Ss], Fun, Acc0, S, Pos) ->
+ Match = string:substr(S, St+1, L),
{Rep, Acc} = Fun(Match, Acc0),
{Rs, NewAcc} = sub_repl(Ss, Fun, Acc, S, St+L),
- {string:substr(S, Pos, St-Pos) ++ Rep ++ Rs, NewAcc};
-sub_repl([], _Fun, Acc, S, Pos) -> {string:substr(S, Pos), Acc}.
+ {string:substr(S, Pos+1, St-Pos) ++ Rep ++ Rs, NewAcc};
+sub_repl([], _Fun, Acc, S, Pos) -> {string:substr(S, Pos+1), Acc}.
@@ -725,3 +681,4 @@ uc([H | T], Acc) when is_integer(H), [97] =< H, H =< $z ->
uc(T, [H - 32 | Acc]);
uc([H | T], Acc) ->
uc(T, [H | Acc]).
+