Current section
Files
Jump to
Current section
Files
src/utils/executable_utils.erl
% Copyright (C) 2008-2020 Olivier Boudeville
%
% This file is part of the Ceylan-Myriad library.
%
% This library is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License or
% the GNU General Public License, as they are published by the Free Software
% Foundation, either version 3 of these Licenses, or (at your option)
% any later version.
% You can also redistribute it and/or modify it under the terms of the
% Mozilla Public License, version 1.1 or later.
%
% This library is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU Lesser General Public License and the GNU General Public License
% for more details.
%
% You should have received a copy of the GNU Lesser General Public
% License, of the GNU General Public License and of the Mozilla Public License
% along with this library.
% If not, see <http://www.gnu.org/licenses/> and
% <http://www.mozilla.org/MPL/>.
%
% Author: Olivier Boudeville [olivier (dot) boudeville (at) esperide (dot) com]
% Creation date: Saturday, July 12, 2008.
% Gathering of various convenient facilities regarding executing of third-party
% tools.
%
% See executable_utils_test.erl for the corresponding test.
%
-module(executable_utils).
% Section for the searching and checking of executables:
-export([ lookup_executable/1, find_executable/1 ]).
% Section for command-line facilities:
-export([ protect_from_shell/1 ]).
% Section for most usual commands:
-export([ generate_png_from_graph_file/2,
generate_png_from_graph_file/3, display_png_file/1,
browse_images_in/1, display_pdf_file/1, display_text_file/1,
display_wide_text_file/2, get_ssh_mute_option/0,
compute_md5_sum/1, compute_sha1_sum/1, compute_sha_sum/2 ]).
% Section about default tools:
-export([
get_default_image_viewer_name/0,
get_default_image_viewer_path/0,
get_default_image_browser_name/0,
get_default_image_browser_path/0,
get_default_web_browser_name/0,
get_default_web_browser_path/0,
get_default_pdf_viewer_name/0,
get_default_pdf_viewer_path/0,
get_default_text_viewer_name/0,
get_default_text_viewer_path/0,
get_default_wide_text_viewer_name/1,
get_default_wide_text_viewer_path/1,
get_default_trace_viewer_name/0,
get_default_trace_viewer_path/0,
get_default_erlang_root/0,
get_default_erlang_interpreter_name/0,
get_default_erlang_interpreter_path/0,
get_default_ssh_client_name/0,
get_default_ssh_client_path/0,
get_default_scp_executable_name/0,
get_default_scp_executable_path/0,
get_gnuplot_path/0,
get_current_gnuplot_version/0,
get_default_zip_compress_tool/0,
get_default_zip_decompress_tool/0,
get_default_bzip2_compress_tool/0,
get_default_bzip2_decompress_tool/0,
get_default_xz_compress_tool/0,
get_default_xz_decompress_tool/0,
get_default_md5_tool/0,
get_default_sha_tool/0,
get_default_java_runtime/0,
get_default_jinterface_path/0 ]).
% MD5 sum, a 128-bit hash value:
-type md5_sum() :: non_neg_integer().
% SHA1 sum, a 160-bit hash value:
-type sha1_sum() :: non_neg_integer().
% SHA sum, a hash value of unspecified size:
-type sha_sum() :: non_neg_integer().
% Command-line managed like init:get_argument/1:
% The name of a command-line option (ex: '-color', for an actual option that is
% "--color"):
%
% (a flag, for the init standard module)
%
-type command_line_option() :: atom().
% The name of a command-line value (ex: "blue"):
-type command_line_value() :: text_utils:ustring().
% The association between an option and the various values associated to its
% instances.
%
% Ex: if arguments were "--color blue red [...] --color yellow", then the
% corresponding argument is { '-color', [ [ "blue", "red" ]; [ "yellow" ] ] }.
%
-type command_line_argument() ::
{ command_line_option(), [ command_line_value() ] }.
% A table storing command-line user arguments conveniently (a bit like getopt),
% in a format in the spirit of init:get_arguments/0.
%
% Useful to manage arguments more easily, and also to handle uniformly the
% arguments specified for erl-based executions and escript ones alike.
%
-type argument_table() :: list_table:list_table( command_line_option(),
[ command_line_value() ] ).
-export_type([ md5_sum/0, sha1_sum/0, sha_sum/0,
command_line_option/0, command_line_value/0,
command_line_argument/0, argument_table/0 ]).
% Command-line argument section:
-export([ get_argument_table/0, get_argument_table/1, generate_argument_table/1,
extract_command_argument/1, extract_command_argument/2,
argument_table_to_string/1 ]).
% Miscellaneous section:
-export([ is_batch/0 ]).
% Looks-up specified executable program, whose name is specified as a string
% (ex: "gcc") in the current user PATH.
%
% Returns an absolute filename of the executable program (ex: "/usr/bin/gcc"),
% or the 'false' atom if it was not found.
%
-spec lookup_executable( file_utils:file_name() ) ->
file_utils:path() | 'false'.
lookup_executable( ExecutableName ) ->
% Similar to a call to 'type':
os:find_executable( ExecutableName ).
% Finds specified executable program, whose name is specified as a string (ex:
% "gcc") in the current user PATH.
%
% Returns an absolute filename of the executable program (ex: "/usr/bin/gcc") or
% throws an exception {executable_not_found,ExecutableName} if it was not found.
%
-spec find_executable( file_utils:file_name() ) -> file_utils:path().
find_executable( ExecutableName ) ->
case lookup_executable( ExecutableName) of
false ->
throw( { executable_not_found, ExecutableName } );
Path ->
Path
end.
% Section for command-line facilities.
% Protects specified argument from shell parsing, typically if specifying a
% filename including a single quote.
%
-spec protect_from_shell( text_utils:ustring() ) -> text_utils:ustring().
protect_from_shell( ArgumentString ) ->
% Not sufficient (ex: "echo 'aaa\'bbb'"):
%text_utils:protect_from_shell( ArgumentString ).
protect_from_shell_helper( ArgumentString, _Acc=[] ).
% (helper)
protect_from_shell_helper( _Text=[], Acc ) ->
lists:reverse( Acc );
protect_from_shell_helper( _Text=[ $' | T ], Acc ) ->
% As will be reversed:
protect_from_shell_helper( T, "''\\'" ++ Acc );
protect_from_shell_helper( _Text=[ C | T ], Acc ) ->
protect_from_shell_helper( T, [ C | Acc ] ).
% Section for most usual commands.
% By default does not crash if dot outputs some warnings but does not yield an
% error exit status.
%
-spec generate_png_from_graph_file( file_utils:path(), file_utils:path() ) ->
text_utils:ustring().
generate_png_from_graph_file( PNGFilename, GraphFilename ) ->
generate_png_from_graph_file( PNGFilename, GraphFilename,
_HaltOnDotOutput=false ).
% Generates a PNG image file from specified graph file, that must respect the
% dot (graphviz) syntax:
%
% - PNGFilename the filename of the PNG to generate
%
% - GraphFilename the filename corresponding to the source graph
%
% - HaltOnDotOutput tells whether the process should throw an exception should
% dot output an error or a warning
%
% Returns the (possibly empty) string output by dot, or throws an exception.
%
-spec generate_png_from_graph_file( file_utils:path(), file_utils:path(),
boolean() ) -> string().
generate_png_from_graph_file( PNGFilename, GraphFilename,
_HaltOnDotOutput=true ) ->
case execute_dot( PNGFilename, GraphFilename ) of
[] ->
% Most correct case:
[];
ErrorMessage ->
throw( { graph_generation_failed, PNGFilename, GraphFilename,
ErrorMessage } )
end;
% Any output remains available to the caller.
generate_png_from_graph_file( PNGFilename, GraphFilename,
_HaltOnDotOutput=false ) ->
execute_dot( PNGFilename, GraphFilename ).
% Displays (without blocking) to the user the specified PNG, using an external
% viewer.
%
% Returns the text output by the tool (if any).
%
% Throws an exception if an error occurs.
%
-spec display_png_file( file_utils:path() ) -> void().
display_png_file( PNGFilename ) ->
% Viewer output is ignored:
system_utils:run_background_executable( get_default_image_viewer_path()
++ " " ++ PNGFilename ).
% Allows to browse (without blocking) the images available in specified
% directory (specified as a plain string)
%
% Returns the text output by the tool (if any).
%
% Throws an exception if an error occurs.
%
-spec browse_images_in( file_utils:path() ) -> void().
browse_images_in( DirectoryName ) ->
system_utils:run_background_executable( get_default_image_browser_path()
++ " " ++ DirectoryName ).
% Displays (without blocking) to the user the specified PNG, using an external
% viewer.
%
% Returns the text output by the tool (if any).
%
% Throws an exception if an error occurs.
%
-spec display_pdf_file( file_utils:path() ) -> void().
display_pdf_file( PDFFilename ) ->
system_utils:run_background_executable( get_default_pdf_viewer_path()
++ " " ++ PDFFilename ).
% Displays, with blocking, a text file.
%
% Returns the text output by the tool (if any).
%
% Throws an exception if an error occurs.
%
-spec display_text_file( file_utils:path() ) -> string().
display_text_file( TextFilename ) ->
case system_utils:run_executable( get_default_text_viewer_path()
++ " " ++ TextFilename ) of
{ _ExitCode=0, Output } ->
Output;
{ ExitCode, ErrorOutput } ->
throw( { display_failed_for_text_file, ExitCode, ErrorOutput } )
end.
% Displays, with blocking, a wide text file.
%
% Returns the text output by the tool (if any).
%
% Throws an exception if an error occurs.
%
-spec display_wide_text_file( file_utils:path(), pos_integer() ) -> string().
display_wide_text_file( TextFilename, CharacterWidth ) ->
case system_utils:run_executable(
get_default_wide_text_viewer_path( CharacterWidth )
++ " " ++ TextFilename ) of
{ _ExitCode=0, Output } ->
Output;
{ ExitCode, ErrorOutput } ->
throw( { wide_display_failed_for_text_file, ExitCode,
ErrorOutput } )
end.
% Returns a string to be inserted into a command-line call to ssh/scp so that it
% can run as much as possible non-interactively.
%
% Tries notably to avoid following message: "The authenticity of host 'Server
% (XXXXX)' can't be established. RSA key fingerprint is YYYYY. Are you sure you
% want to continue connecting (yes/no)?".
%
% Note: only to be used in a trusted environment.
%
% Returns the text output by the tool (if any).
%
% Throws an exception if an error occurs.
%
-spec get_ssh_mute_option() -> string().
get_ssh_mute_option() ->
" -o \"StrictHostKeyChecking no\" ".
% Returns the MD5 sum computed from the content of the specified file, as an
% unsigned integer, actually of 128 bits (ex:
% 96950473382892364268626543336313804804, corresponding to hexadecimal string
% "48effb631c66e93c7054c10f798f5804").
%
-spec compute_md5_sum( file_utils:path() ) -> md5_sum().
compute_md5_sum( Filename ) ->
case file_utils:is_existing_file( Filename ) of
true ->
ok;
false ->
throw( { file_for_md5_not_found, Filename } )
end,
% erlang:md5/1 not used here, would be probably slower:
% Removes the filename after the MD5 code:
Cmd = system_utils:run_executable( get_default_md5_tool() ++ " '"
++ protect_from_shell( Filename ) ++ "' | sed 's| .*$||1'" ),
case Cmd of
{ _ExitCode=0, OutputString } ->
list_to_integer( OutputString, _Base=16 );
{ ExitCode, ErrorOutput } ->
throw( { md5_computation_failed, ExitCode, ErrorOutput, Filename } )
end.
% Returns the SHA1 sum computed from the content of the specified file, as an
% unsigned integer, actually of 160 bits (ex:
% 189271338729529876450691804503218393830331783574, corresponding to hexadecimal
% string "212738699f721d8d8c3e58dac2b113bb8d0c1996").
%
-spec compute_sha1_sum( file_utils:path() ) -> sha1_sum().
compute_sha1_sum( Filename ) ->
%trace_utils:trace_fmt( "Computing SHA1 sum of '~s'.", [ Filename ] ),
compute_sha_sum( Filename, _SizeOfSHAAlgorithm=1 ).
% Returns the SHA sum computed from the content of the specified file, as an
% unsigned integer, whose size depends on the specified algorithm: 1, 224, 256,
% 384, 512, 512224, 512256 (see 'man shasum' for more details).
%
-spec compute_sha_sum( file_utils:path(), basic_utils:count() ) -> sha_sum().
compute_sha_sum( Filename, SizeOfSHAAlgorithm )
when is_integer( SizeOfSHAAlgorithm ) ->
case file_utils:is_existing_file( Filename ) of
true ->
ok;
false ->
throw( { file_for_sha_not_found, Filename } )
end,
%trace_utils:trace_fmt( "Computing SHA~B sum of '~s'.",
% [ SizeOfSHAAlgorithm, Filename ] ),
% Removes the filename after the SHA code:
Cmd = system_utils:run_executable( get_default_sha_tool()
++ " --algorithm "
++ text_utils:format( "~B '", [ SizeOfSHAAlgorithm ] )
++ protect_from_shell( Filename )
++ "' | sed 's| .*$||1'" ),
case Cmd of
{ _ExitCode=0, OutputString } ->
case text_utils:try_string_to_integer( OutputString, _Base=16 ) of
undefined ->
throw( { sha_computation_failed, invalid_result,
OutputString } );
Sum ->
Sum
end;
{ ExitCode, ErrorOutput } ->
throw( { sha_computation_failed, ExitCode, ErrorOutput, Filename } )
end.
% Section about default tools.
% For each supported third-party feature X (ex: X=image_viewer), two functions
% are to be defined:
%
% - get_default_X_name() -> string() that returns the name of the tool (useful
% for error messages)
%
% - get_default_X_path() -> file_utils:file_name() that returns the full path
% to the corresponding executable
% Returns the name of the default image viewer tool.
%
% Could be also: xv, firefox, etc.
%
-spec get_default_image_viewer_name() -> string().
get_default_image_viewer_name() ->
% Viewer is 'eye of gnome' here:
"eog".
% Returns an absolute path to the default image viewer tool.
-spec get_default_image_viewer_path() -> file_utils:path().
get_default_image_viewer_path() ->
find_executable( get_default_image_viewer_name() ).
% Returns the name of the default image browser tool.
%
% Used to be: gqview (renamed since then).
%
-spec get_default_image_browser_name() -> string().
get_default_image_browser_name() ->
% Was a mere compatibility alias for gqview:
"geeqie".
% Returns an absolute path to the default image browser tool.
-spec get_default_image_browser_path() -> file_utils:file_name().
get_default_image_browser_path() ->
find_executable( get_default_image_browser_name() ).
% Returns the name of the default web browser.
-spec get_default_web_browser_name() -> string().
get_default_web_browser_name() ->
"firefox".
% Returns an absolute path to the default web browser tool.
-spec get_default_web_browser_path() -> file_utils:file_name().
get_default_web_browser_path() ->
find_executable( get_default_web_browser_name() ).
% Returns the name of the default PDF viewer tool.
% Could be also: xpdf, acroread, etc.
-spec get_default_pdf_viewer_name() -> string().
get_default_pdf_viewer_name() ->
"evince".
% Returns an absolute path to the default PDF viewer tool.
-spec get_default_pdf_viewer_path() -> file_utils:file_name().
get_default_pdf_viewer_path() ->
find_executable( get_default_pdf_viewer_name() ).
% Returns the name of the default text viewer tool.
% Could be also: nedit, emacs, etc.
-spec get_default_text_viewer_name() -> string().
get_default_text_viewer_name() ->
"gedit".
% Returns an absolute path to the default text viewer tool.
-spec get_default_text_viewer_path() -> file_utils:file_name().
get_default_text_viewer_path() ->
find_executable( get_default_text_viewer_name() ).
% Returns the name of the default viewer tool for wider texts.
-spec get_default_wide_text_viewer_name( non_neg_integer() ) -> string().
get_default_wide_text_viewer_name( _CharacterWidth ) ->
% Could be: "nedit":
"gedit".
% Returns an absolute path to the default viewer tool for wider texts.
-spec get_default_wide_text_viewer_path( non_neg_integer() )
-> file_utils:file_name().
get_default_wide_text_viewer_path( CharacterWidth ) ->
% Could be: io_lib:format( "nedit -column ~B", [ CharacterWidth ] )
find_executable( get_default_wide_text_viewer_name( CharacterWidth ) ).
% Returns the name of the default trace viewer tool.
%
% Could be also: nedit, gedit, etc.
%
-spec get_default_trace_viewer_name() -> string().
get_default_trace_viewer_name() ->
case system_utils:has_graphical_output() of
true ->
find_executable( "logmx.sh" );
false ->
% Poor's man solution:
"/bin/cat"
end.
% Returns an absolute path to the default trace viewer tool.
%
% Could be also: nedit, gedit, etc.
%
-spec get_default_trace_viewer_path() -> file_utils:file_name().
get_default_trace_viewer_path() ->
% Note: expected to be on the PATH:
find_executable( get_default_trace_viewer_name() ).
% Returns an absolute path to the root directory of the current Erlang
% installation.
%
% Ex: if 'erl' is to be found in
% ~/Software/Erlang/Erlang-current-install/bin/erl, will return:
% ~/Software/Erlang/Erlang-current-install.
%
-spec get_default_erlang_root() -> file_utils:directory_name().
get_default_erlang_root() ->
file_utils:normalise_path( file_utils:join( [
get_default_erlang_interpreter_path(), "..", "..", "..", "..", ".." ]
) ).
% Returns the name of the default Erlang interpreter.
-spec get_default_erlang_interpreter_name() -> string().
get_default_erlang_interpreter_name() ->
"erl".
% Returns an absolute path to the default Erlang interpreter.
-spec get_default_erlang_interpreter_path() -> file_utils:file_name().
get_default_erlang_interpreter_path() ->
% Note: expected to be on the PATH:
find_executable( get_default_erlang_interpreter_name() ).
% Returns the name of the default SSH client.
-spec get_default_ssh_client_name() -> string().
get_default_ssh_client_name() ->
"ssh".
% Returns an absolute path to the default SSH client.
-spec get_default_ssh_client_path() -> file_utils:file_name().
get_default_ssh_client_path() ->
% Note: expected to be on the PATH:
find_executable( get_default_ssh_client_name() ).
% Returns the name default SSH-based scp executable.
-spec get_default_scp_executable_name() -> string().
get_default_scp_executable_name() ->
"scp".
% Returns an absolute path to the default SSH-based scp executable.
-spec get_default_scp_executable_path() -> file_utils:file_name().
get_default_scp_executable_path() ->
% Note: expected to be on the PATH:
find_executable( get_default_scp_executable_name() ).
% Returns an absolute path to a gnuplot executable.
-spec get_gnuplot_path() -> file_utils:file_name().
get_gnuplot_path() ->
% Note: expected to be on the PATH:
find_executable( "gnuplot" ).
% Returns, as a tuple (ex: {4,2} for the 4.2 version), the gnuplot version
% actually available on the computer.
%
-spec get_current_gnuplot_version() -> basic_utils:two_digit_version().
get_current_gnuplot_version() ->
% gnuplot -V returns information like "gnuplot 4.4 patchlevel 0"; rather
% that evaluation a shell expression like:
%
% Cmd = get_gnuplot_path() ++ " -V | awk '{print $2}'",
%
% we prefer executing directly gnuplot, have then the exit status, and parse
% the result in Erlang:
%
Cmd = get_gnuplot_path() ++ " -V",
% The returned value of following command is like "4.2":
%
case system_utils:run_executable( Cmd ) of
{ _ExitCode=0, Output } ->
GnuplotVersionInString = lists:nth( _IndexVersion=2,
text_utils:split( Output, " " ) ),
basic_utils:parse_version( GnuplotVersionInString );
{ ExitCode, ErrorOutput } ->
throw( { gnuplot_version_detection_failed, ExitCode,
ErrorOutput } )
end.
% Returns the default tool to use to compress in the ZIP format.
-spec get_default_zip_compress_tool() -> file_utils:file_name().
get_default_zip_compress_tool() ->
find_executable( "zip" ).
% Returns the default tool to use to decompress in the ZIP format.
-spec get_default_zip_decompress_tool() -> file_utils:file_name().
get_default_zip_decompress_tool() ->
find_executable( "unzip" ).
% Returns the default tool to use to decompress in the BZIP2 format.
-spec get_default_bzip2_compress_tool() -> file_utils:file_name().
get_default_bzip2_compress_tool() ->
find_executable( "bzip2" ).
% Returns the default tool to use to decompress in the BZIP2 format.
-spec get_default_bzip2_decompress_tool() -> file_utils:file_name().
get_default_bzip2_decompress_tool() ->
find_executable( "bunzip2" ).
% Returns the default tool to use to compress in the XZ format.
-spec get_default_xz_compress_tool() -> file_utils:file_name().
get_default_xz_compress_tool() ->
find_executable( "xz" ).
% Returns the default tool to use to decompress in the XZ format.
-spec get_default_xz_decompress_tool() -> file_utils:file_name().
get_default_xz_decompress_tool() ->
find_executable( "unxz" ).
% Returns the default tool to compute MD5 sums.
-spec get_default_md5_tool() -> file_utils:file_name().
get_default_md5_tool() ->
find_executable( "md5sum" ).
% Returns the default tool to compute SHA sums.
-spec get_default_sha_tool() -> file_utils:file_name().
get_default_sha_tool() ->
find_executable( "shasum" ).
% Returns the default tool to execute Java programs.
-spec get_default_java_runtime() -> file_utils:file_name().
get_default_java_runtime() ->
find_executable( "java" ).
% Returns the default path to the .jar file implementing JInterface,
% i.e. 'OtpErlang.jar'.
%
% Indeed, to make use of JInterface, OtpErlang.jar must be found by the
% counterpart Java program.
%
% We chose conventionally its location to be
% $(ERLANG_ROOT)/lib/erlang/jinterface/priv/OtpErlang.jar,
% with ERLANG_ROOT being typically ~/Software/Erlang/Erlang-current-install.
%
% Indeed, we expect that in $(ERLANG_ROOT)/lib/erlang/ a symbolic link named
% 'jinterface' has been specifically created in order to point to the directory
% of the corresponding version of JInterface (ex: lib/jinterface-1.8/); our
% install-erlang.sh script automatically enforces that convention.
%
-spec get_default_jinterface_path() -> file_utils:file_name().
get_default_jinterface_path() ->
JInterfaceBase = file_utils:join(
[ get_default_erlang_root(), "lib", "erlang", "jinterface" ] ),
% Can be directory or, more probably, symlink:
case file_utils:is_existing_directory_or_link( JInterfaceBase ) of
true ->
JInterfaceJar = file_utils:join( [ JInterfaceBase, "priv",
"OtpErlang.jar" ] ),
case file_utils:is_existing_file( JInterfaceJar ) of
true ->
JInterfaceJar;
false ->
throw( { jinterface_jar_not_found, JInterfaceJar } )
end;
false ->
trace_utils:error_fmt( "The JInterface base path (~s) does not "
"exist; conventionally this is a symbolic "
"link pointing to, typically, "
"'lib/jinterface-x.y/'.",
[ JInterfaceBase ] ),
throw( { jinterface_base_path_not_found, JInterfaceBase } )
end.
% Command-line argument section:
% Returns a canonical argument table, obtained from the user command-line
% arguments supplied to the interpreter.
%
% Note:
%
% - only the arguments specified on the command-line after the '-extra' marker
% will be taken into account; ex:
% make ui_run CMD_LINE_OPT="-extra --use-ui-backend text_ui"
%
% - to be called in the context of a standard erl execution (as opposed to
% an escript one)
%
-spec get_argument_table() -> argument_table().
get_argument_table() ->
% We do not want to include the VM-specific arguments (such as -noshell,
% -pz, etc.); use, in the command-line, '-extra', before arguments to
% consider as plain ones:
%
%Args = init:get_arguments(),
Args = init:get_plain_arguments(),
%trace_utils:debug_fmt( "Arguments obtained: ~p.", [ Args ] ),
% To convert a list of strings into per-option list of values:
get_argument_table( Args ).
% Returns a canonical argument table, obtained from the user command-line
% arguments supplied to this escript.
%
% Note: to be called in the context of an escript (as opposed to a standard erl
% execution), specifying the argument list that its main/1 function received.
%
-spec get_argument_table( [ string() ] ) -> argument_table().
get_argument_table( ArgStrings ) ->
script_utils:get_arguments( ArgStrings ).
% Returns a canonical argument table, obtained from the specified single string
% containing all options, verbatim ; ex: "--color red --set-foo".
%
% Note: useful for testing, to introduce specific command lines.
%
-spec generate_argument_table( string() ) -> argument_table().
generate_argument_table( ArgString ) ->
CommandLineArgs = text_utils:split( ArgString, _Delimiters=[ $ ] ),
get_argument_table( CommandLineArgs ).
% Extracts specified option, i.e. its various associated values (if any), from
% the arguments specified to this executable.
%
% Returns a pair made of these values and of the shrunk argument table.
%
-spec extract_command_argument( command_line_option() ) ->
{ [ command_line_value() ], argument_table() }.
extract_command_argument( Option ) ->
ArgumentTable = get_argument_table(),
extract_command_argument( Option, ArgumentTable ).
% Extracts specified option, i.e. its various associated values (if any), from
% the specified argument table.
%
% Returns a pair made of these values and of the shrunk argument table.
%
-spec extract_command_argument( command_line_option(), argument_table() ) ->
{ [ command_line_value() ], argument_table() }.
extract_command_argument( Option, ArgumentTable ) ->
list_table:extract_entry_with_defaults( _K=Option, _DefaultValue=[],
ArgumentTable ).
% Returns a textual representation of the specified argument table.
-spec argument_table_to_string( argument_table() ) -> string().
argument_table_to_string( ArgTable ) ->
% No-op:
case list_table:enumerate( ArgTable ) of
[] ->
"no command-line option specified";
ArgPairs ->
ArgStrings = [ case ArgumentLists of
[] ->
text_utils:format( "option '-~s'", [ Option ] );
_ ->
text_utils:format( "option '-~s', with argument lists: ~p",
[ Option, ArgumentLists ] )
end || { Option, ArgumentLists } <- ArgPairs ],
text_utils:format( "~B command-line option(s) specified "
"(listed alphabetically): ~s",
[ length( ArgPairs ),
text_utils:strings_to_sorted_string( ArgStrings ) ] )
end.
% Miscellaneous section:
% Tells whether the program is run in batch mode.
%
% By default, a program is not in batch mode (hence is in interactive mode,
% meaning it might trigger graphical displays).
%
% The most prioritary setting is if the "--batch" command line argument has been
% set.
%
% Otherwise, the application configuration will be read (typically set from any
% conf/sys.config file defined by the application).
%
% Note that, if relying on application configuration, the result will depend on
% the {application name, callsite} pair. Indeed, if application foo depends on
% application bar, and foo defined in its conf/sys.config file {is_batch,false}
% whereas bar defined in its own configuration file {is_batch,true}, should a
% process belonging to bar call this function, it will return false.
%
-spec is_batch() -> boolean().
is_batch() ->
% Corresponds to the --batch command-line option:
case init:get_argument( '-batch' ) of
{ ok, _ } ->
trace_utils:debug( "Batch mode activated through command line." ),
true;
_ ->
case application:get_env( is_batch ) of
{ ok, true } ->
trace_utils:debug(
"Batch mode enabled through configuration." ),
true;
{ ok, false } ->
trace_utils:debug(
"Batch mode disabled through configuration." ),
false;
undefined ->
trace_utils:debug("Batch mode disabled (default)." ),
% Default then is:
false
end
end.
% Helper functions.
-spec execute_dot( file_utils:file_name(), file_utils:file_name() ) ->
text_utils:ustring().
execute_dot( PNGFilename, GraphFilename ) ->
DotExec = find_executable( "dot" ),
Cmd = DotExec ++ " -o" ++ PNGFilename ++ " -Tpng " ++ GraphFilename,
% Dot might issue non-serious warnings:
case system_utils:run_executable( Cmd ) of
{ _ExitCode=0, Output } ->
Output;
{ ExitCode, ErrorOutput } ->
throw( { rendering_failed, GraphFilename, PNGFilename, ExitCode,
ErrorOutput } )
end.