[m-rev.] diff: Refactor code that works with temporary files.
Paul Bone
paul at bone.id.au
Wed Apr 27 17:22:46 AEST 2016
Refactor code that works with temporary files.
It is common to create a temporary file then open it for writing; or create
the temporary file, call another program, then open the file for reading.
This patch implements both these patterns as predicates in file_util.m
compiler/file_util.m:
Add new utility predicates.
compiler/compile_target_code.m:
compiler/fact_table.m:
compiler/make.util.m:
compiler/prog_event.m:
Make use of open_temp_input.
---
compiler/compile_target_code.m | 57 ++++++++--------------------
compiler/fact_table.m | 21 ++---------
compiler/file_util.m | 85 ++++++++++++++++++++++++++++++++++++++++++
compiler/make.util.m | 26 ++++---------
compiler/prog_event.m | 52 ++++++++++----------------
5 files changed, 132 insertions(+), 109 deletions(-)
diff --git a/compiler/compile_target_code.m b/compiler/compile_target_code.m
index 698398a..fd8770a 100644
--- a/compiler/compile_target_code.m
+++ b/compiler/compile_target_code.m
@@ -1254,12 +1254,9 @@ invoke_mkinit(Globals, InitFileStream, Verbosity,
% mkinit expects unquoted file names.
join_string_list(FileNames, "", "\n", "", TargetFileNames),
- io.make_temp_file(TmpFileResult, !IO),
+ open_temp_output(TmpFileResult, !IO),
(
- TmpFileResult = ok(TmpFile),
- io.open_output(TmpFile, OpenResult, !IO),
- (
- OpenResult = ok(TmpStream),
+ TmpFileResult = ok({TmpFile, TmpStream}),
io.write_string(TmpStream, TargetFileNames, !IO),
io.close_output(TmpStream, !IO),
@@ -1276,15 +1273,9 @@ invoke_mkinit(Globals, InitFileStream, Verbosity,
MkInitOK = no
)
;
- OpenResult = error(Error),
- io.format(io.stderr_stream, "%s: %s\n",
- [s(TmpFile), s(error_message(Error))], !IO),
- MkInitOK = no
- )
- ;
- TmpFileResult = error(Error),
- io.format(io.stderr_stream, "Could not create temporary file: %s\n",
- [s(error_message(Error))], !IO),
+ TmpFileResult = error(ErrorMessage),
+ io.write_string(io.stderr_stream, ErrorMessage, !IO),
+ io.nl(!IO),
MkInitOK = no
).
@@ -3065,12 +3056,9 @@ create_java_exe_or_lib(Globals, ErrorStream, LinkTargetType, MainModuleName,
% extremely long. We create the temporary file in the current directory to
% avoid problems under Cygwin, where absolute paths will be interpreted
% incorrectly when passed to a non-Cygwin jar program.
- io.make_temp_file(".", "mtmp", "", TempFileNameResult, !IO),
- (
- TempFileNameResult = ok(TempFileName),
- io.open_output(TempFileName, OpenResult, !IO),
+ open_temp_output(".", "mtmp", "", TempFileResult, !IO),
(
- OpenResult = ok(Stream),
+ TempFileResult = ok({TempFileName, Stream}),
list.foldl(write_jar_class_argument(Stream, ClassSubDir),
ListClassFiles, !IO),
io.close_output(Stream, !IO),
@@ -3087,15 +3075,9 @@ create_java_exe_or_lib(Globals, ErrorStream, LinkTargetType, MainModuleName,
io.remove_file(JarFileName, _, !IO)
)
;
- OpenResult = error(Error),
- io.format(ErrorStream, "Error creating `%s': %s\n",
- [s(TempFileName), s(error_message(Error))], !IO),
- Succeeded0 = no
- )
- ;
- TempFileNameResult = error(Error),
- io.format(ErrorStream, "Could not create temporary file: %s\n",
- [s(error_message(Error))], !IO),
+ TempFileResult = error(ErrorMessage),
+ io.write_string(ErrorStream, ErrorMessage, !IO),
+ io.nl(!IO),
Succeeded0 = no
),
( if
@@ -3492,12 +3474,9 @@ invoke_long_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
RestrictedCommandLine = yes,
% Avoid generating very long command lines by using @files.
- io.make_temp_file(TmpFileResult, !IO),
+ open_temp_output(TmpFileResult, !IO),
(
- TmpFileResult = ok(TmpFile),
- io.open_output(TmpFile, OpenResult, !IO),
- (
- OpenResult = ok(TmpStream),
+ TmpFileResult = ok({TmpFile, TmpStream}),
% We need to escape any \ before writing them to the file,
% otherwise we lose them.
@@ -3535,15 +3514,9 @@ invoke_long_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
Succeeded = no
)
;
- OpenResult = error(Error),
- io.format(stderr_stream, "%s: %s\n",
- [s(TmpFile), s(error_message(Error))], !IO),
- Succeeded = no
- )
- ;
- TmpFileResult = error(Error),
- io.format(stderr_stream, "Could not create temporary file: %s\n",
- [s(error_message(Error))], !IO),
+ TmpFileResult = error(ErrorMessage),
+ io.write_string(stderr_stream, ErrorMessage, !IO),
+ io.nl(!IO),
Succeeded = no
)
;
diff --git a/compiler/fact_table.m b/compiler/fact_table.m
index 6f884a7..8b35060 100644
--- a/compiler/fact_table.m
+++ b/compiler/fact_table.m
@@ -979,28 +979,15 @@ fact_table_mode_type([Mode | Modes], ModuleInfo, ModeType) :-
open_sort_files([], [], !Errors, !IO).
open_sort_files([ProcID | ProcIDs], ProcStreams, !Errors, !IO) :-
- io.make_temp_file(SortFileNameResult, !IO),
+ open_temp_output(SortFileNameResult, !IO),
(
- SortFileNameResult = ok(SortFileName),
- io.open_output(SortFileName, Result, !IO),
- (
- Result = ok(Stream),
+ SortFileNameResult = ok({_SortFileName, Stream}),
open_sort_files(ProcIDs, ProcStreams0, !Errors, !IO),
ProcStreams = [proc_stream(ProcID, Stream) | ProcStreams0]
;
- Result = error(ErrorCode),
- ProcStreams = [],
- io.error_message(ErrorCode, Message),
- string.format("Error opening file `%s' for output: %s.",
- [s(SortFileName), s(Message)], Msg),
- add_error_report([words(Msg)], !Errors)
- )
- ;
- SortFileNameResult = error(Error),
+ SortFileNameResult = error(ErrorMessage),
ProcStreams = [],
- string.format("Could not create temporary file: %s.",
- [s(error_message(Error))], Msg),
- add_error_report([words(Msg)], !Errors)
+ add_error_report([words(ErrorMessage)], !Errors)
).
% close_sort_files(ProcStreams, ProcFiles, !IO):
diff --git a/compiler/file_util.m b/compiler/file_util.m
index 04c7aa2..d3ab552 100644
--- a/compiler/file_util.m
+++ b/compiler/file_util.m
@@ -132,6 +132,30 @@
:- func make_install_dir_command(globals, string, string) = string.
%-----------------------------------------------------------------------------%
+
+ % open_temp_output(Dir, Prefix, Suffix, Result, !IO)
+ %
+ % Create a temporary file and open it for writing. If successful Result
+ % returns the file's name and output stream. On error any temporary
+ % file will be removed.
+ %
+:- pred open_temp_output(string::in, string::in, string::in,
+ maybe_error({string, text_output_stream})::out, io::di, io::uo) is det.
+
+:- pred open_temp_output(maybe_error({string, text_output_stream})::out,
+ io::di, io::uo) is det.
+
+ % open_temp_input(Result, WritePred, !IO)
+ %
+ % Create a temporary file and call WritePred which will write data to
+ % it. If successful Result returns the file's name and a freshly opened
+ % input stream. On error any temporary file will be removed.
+ %
+:- pred open_temp_input(maybe_error({string, text_input_stream})::out,
+ pred(string, maybe_error, io, io)::in(pred(in, out, di, uo) is det),
+ io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
@@ -438,5 +462,66 @@ make_install_dir_command(Globals, SourceDirName, InstallDir) = Command :-
[InstallCmd, InstallCmdDirOpt, SourceDirName, InstallDir])).
%-----------------------------------------------------------------------------%
+
+open_temp_output(Dir, Prefix, Suffix, Result, !IO) :-
+ make_temp_file(Dir, Prefix, Suffix, TempFileResult, !IO),
+ open_temp_output_2(TempFileResult, Result, !IO).
+
+open_temp_output(Result, !IO) :-
+ make_temp_file(TempFileResult, !IO),
+ open_temp_output_2(TempFileResult, Result, !IO).
+
+:- pred open_temp_output_2(io.res(string)::in,
+ maybe_error({string, text_output_stream})::out, io::di, io::uo) is det.
+
+open_temp_output_2(TempFileResult, Result, !IO) :-
+ (
+ TempFileResult = ok(TempFileName),
+ open_output(TempFileName, OpenResult, !IO),
+ (
+ OpenResult = ok(Stream),
+ Result = ok({TempFileName, Stream})
+ ;
+ OpenResult = error(Error),
+ remove_file(TempFileName, _, !IO),
+ Result = error(format(
+ "could not open temporary file `%s': %s",
+ [s(TempFileName), s(error_message(Error))]))
+ )
+ ;
+ TempFileResult = error(Error),
+ Result = error(format("could not create temporary file: %s",
+ [s(error_message(Error))]))
+ ).
+
+open_temp_input(Result, Pred, !IO) :-
+ make_temp_file(TempFileResult, !IO),
+ (
+ TempFileResult = ok(TempFileName),
+ Pred(TempFileName, PredResult, !IO),
+ (
+ PredResult = ok,
+ open_input(TempFileName, OpenResult, !IO),
+ (
+ OpenResult = ok(Stream),
+ Result = ok({TempFileName, Stream})
+ ;
+ OpenResult = error(Error),
+ Result = error(format("could not open `%s': %s",
+ [s(TempFileName), s(error_message(Error))])),
+ remove_file(TempFileName, _, !IO)
+ )
+ ;
+ PredResult = error(ErrorMessage),
+ remove_file(TempFileName, _, !IO),
+ Result = error(ErrorMessage)
+ )
+ ;
+ TempFileResult = error(Error),
+ Result = error(format("could not create temporary file: %s",
+ [s(error_message(Error))]))
+ ).
+
+%-----------------------------------------------------------------------------%
:- end_module libs.file_util.
%-----------------------------------------------------------------------------%
diff --git a/compiler/make.util.m b/compiler/make.util.m
index b137904..2703a95 100644
--- a/compiler/make.util.m
+++ b/compiler/make.util.m
@@ -1073,25 +1073,15 @@ redirect_output(_ModuleName, MaybeErrorStream, !Info, !IO) :-
% Write the output to a temporary file first, so it's easy to just print
% the part of the error file that relates to the current command. It will
% be appended to the error file later.
-
- io.make_temp_file(ErrorFileNameResult, !IO),
- (
- ErrorFileNameResult = ok(ErrorFileName),
- io.open_output(ErrorFileName, ErrorFileRes, !IO),
+ open_temp_output(ErrorFileResult, !IO),
(
- ErrorFileRes = ok(ErrorOutputStream),
+ ErrorFileResult = ok({_ErrorFileName, ErrorOutputStream}),
MaybeErrorStream = yes(ErrorOutputStream)
;
- ErrorFileRes = error(IOError),
+ ErrorFileResult = error(ErrorMessage),
MaybeErrorStream = no,
with_locked_stdout(!.Info,
- write_error_opening_output(ErrorFileName, IOError), !IO)
- )
- ;
- ErrorFileNameResult = error(IOError),
- MaybeErrorStream = no,
- with_locked_stdout(!.Info, write_error_creating_temp_file(IOError),
- !IO)
+ write_error_creating_temp_file(ErrorMessage), !IO)
).
unredirect_output(Globals, ModuleName, ErrorOutputStream, !Info, !IO) :-
@@ -1190,11 +1180,11 @@ write_error_opening_file(FileName, Error, !IO) :-
io.format("Error opening `%s': %s\n",
[s(FileName), s(io.error_message(Error))], !IO).
-:- pred write_error_creating_temp_file(io.error::in, io::di, io::uo) is det.
+:- pred write_error_creating_temp_file(string::in, io::di, io::uo) is det.
-write_error_creating_temp_file(Error, !IO) :-
- io.format("Error creating temporary file: %s\n",
- [s(io.error_message(Error))], !IO).
+write_error_creating_temp_file(ErrorMessage, !IO) :-
+ io.write_string(ErrorMessage, !IO),
+ io.nl(!IO).
%-----------------------------------------------------------------------------%
diff --git a/compiler/prog_event.m b/compiler/prog_event.m
index 2c471e7..2558e63 100644
--- a/compiler/prog_event.m
+++ b/compiler/prog_event.m
@@ -60,6 +60,7 @@
:- implementation.
+:- import_module libs.file_util.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.builtin_lib_types.
:- import_module parse_tree.prog_mode.
@@ -92,14 +93,9 @@ read_event_set(SpecsFileName, EventSetName, EventSpecMap, ErrorSpecs, !IO) :-
% those tools are not yet mature enough. When they are, we should switch
% to using them.
- io.make_temp_file(TermFileNameResult, !IO),
+ open_temp_input(TermFileResult, read_specs_file(SpecsFileName), !IO),
(
- TermFileNameResult = ok(TermFileName),
- read_specs_file(SpecsFileName, TermFileName, Problem, !IO),
- ( if Problem = "" then
- io.open_input(TermFileName, TermOpenRes, !IO),
- (
- TermOpenRes = ok(TermStream),
+ TermFileResult = ok({TermFileName, TermStream}),
io.read(TermStream, TermReadRes, !IO),
(
TermReadRes = ok(EventSetTerm),
@@ -128,40 +124,32 @@ read_event_set(SpecsFileName, EventSetName, EventSpecMap, ErrorSpecs, !IO) :-
[always(Pieces)])]),
ErrorSpecs = [ErrorSpec]
),
- io.close_input(TermStream, !IO)
+ io.close_input(TermStream, !IO),
+ io.remove_file(TermFileName, _RemoveRes, !IO)
;
- TermOpenRes = error(TermOpenError),
+ TermFileResult = error(ErrorMessage),
EventSetName = "",
EventSpecMap = map.init,
- Pieces = [words("Could not open"), quote(TermFileName),
- words(":"), words_quote(error_message(TermOpenError)), nl],
+ Pieces = [words(ErrorMessage), nl],
ErrorSpec = error_spec(severity_error,
phase_term_to_parse_tree,
[error_msg(no, do_not_treat_as_first, 0,
[always(Pieces)])]),
ErrorSpecs = [ErrorSpec]
- )
+ ).
+
+:- pred read_specs_file(string::in, string::in, maybe_error::out,
+ io::di, io::uo) is det.
+
+read_specs_file(SpecsFile, TermFile, Result, !IO) :-
+ read_specs_file_2(SpecsFile, TermFile, Problem, !IO),
+ ( if Problem = "" then
+ Result = ok
else
- EventSetName = "",
- EventSpecMap = map.init,
- Pieces = [words(Problem), nl],
- ErrorSpec = error_spec(severity_error, phase_term_to_parse_tree,
- [error_msg(no, do_not_treat_as_first, 0, [always(Pieces)])]),
- ErrorSpecs = [ErrorSpec]
- ),
- io.remove_file(TermFileName, _RemoveRes, !IO)
- ;
- TermFileNameResult = error(TermFileNameError),
- EventSetName = "",
- EventSpecMap = map.init,
- Pieces = [words("Could not create temporary file:"),
- words_quote(error_message(TermFileNameError)), nl],
- ErrorSpec = error_spec(severity_error, phase_term_to_parse_tree,
- [error_msg(no, do_not_treat_as_first, 0, [always(Pieces)])]),
- ErrorSpecs = [ErrorSpec]
+ Result = error(Problem)
).
-:- pred read_specs_file(string::in, string::in, string::out,
+:- pred read_specs_file_2(string::in, string::in, string::out,
io::di, io::uo) is det.
:- pragma foreign_decl("C",
@@ -179,7 +167,7 @@ MR_String read_specs_file_4(MR_AllocSiteInfoPtr alloc_id,
").
:- pragma foreign_proc("C",
- read_specs_file(SpecsFileName::in, TermFileName::in, Problem::out,
+ read_specs_file_2(SpecsFileName::in, TermFileName::in, Problem::out,
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
"
@@ -192,7 +180,7 @@ MR_String read_specs_file_4(MR_AllocSiteInfoPtr alloc_id,
MR_restore_transient_hp();
").
-read_specs_file(_, _, _, _, _) :-
+read_specs_file_2(_, _, _, _, _) :-
unexpected($file, $pred, "non-C backend").
:- pragma foreign_code("C", "
--
2.8.0.rc3
More information about the reviews
mailing list