[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