[m-rev.] for review: io.make_temp now reterns a result rather than throw exceptions
Paul Bone
paul at bone.id.au
Wed Apr 27 17:13:25 AEST 2016
On Wed, Apr 20, 2016 at 04:50:32PM +1000, Peter Wang wrote:
> > @@ -1274,7 +1276,15 @@ invoke_mkinit(Globals, InitFileStream, Verbosity,
> > MkInitOK = no
> > )
> > ;
> > - OpenResult = error(_),
> > + 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),
> > MkInitOK = no
> > ).
>
> I think invoke_mkinit should return the error to be presented by its
> callers.
I started trying to make this change. It created a chain reaction of
refactoring throughout this module, I got half-way done and stopped. It's
not worth doing as part of this change, it should be done separately.
> > @@ -1977,8 +1987,12 @@ link_exe_or_shared_lib(Globals, ErrorStream, LinkTargetType, ModuleName,
> > % and thus overflow the command line, so in this case
> > % we first create an archive of all of the object files.
> > RestrictedCommandLine = yes,
> > - io.make_temp(TmpFile, !IO),
> > globals.lookup_string_option(Globals, library_extension, LibExt),
> > + io.get_temp_directory(TempDir, !IO),
> > + io.make_temp_res(TempDir, "", "." ++ LibExt, TmpFileResult, !IO),
> > + (
> > + TmpFileResult = ok(TmpFile),
> > + % XXX: This is why my /tmp directory is always full of crap.
> > TmpArchive = TmpFile ++ LibExt,
> > % Only include actual object files in the temporary archive,
> > % not other files such as other archives.
>
> Delete the comment.
>
> --restricted-command-line is only used on Windows so I doubt that's what
> you're seeing. It is a bug, though.
Whoops, I should have grepped my diff for XXX.
I also introduced a bug here because I failed to revisit the XXX. Fixed
now.
> > diff --git a/compiler/write_deps_file.m b/compiler/write_deps_file.m
> > index e661e06..caac87b 100644
> > --- a/compiler/write_deps_file.m
> > +++ b/compiler/write_deps_file.m
> > @@ -159,8 +159,14 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
> > % parallel makes, we first create the file with a temporary name,
> > % and then rename it to the desired name when we've finished.
> >
> > - io.make_temp(dir.dirname(DependencyFileName), "tmp_d",
> > - TmpDependencyFileName, !IO),
> > + io.make_temp_res(dir.dirname(DependencyFileName), "tmp_d",
> > + "", TmpDependencyFileNameRes, !IO),
> > + (
> > + TmpDependencyFileNameRes = error(Error),
> > + Message = "Could not create temporary file: " ++ error_message(Error),
> > + report_error(Message, !IO)
> > + ;
> > + TmpDependencyFileNameRes = ok(TmpDependencyFileName),
> > maybe_write_string(Verbose, "% Writing auto-dependency file `", !IO),
> > maybe_write_string(Verbose, DependencyFileName, !IO),
> > maybe_write_string(Verbose, "'...", !IO),
>
> [snip!]
>
> I think you should add a helper predicate (just in the compiler
> directory) that does make_temp_file followed by open_output:
>
> :- pred open_temp_output(io.res(pair(string, text_output_stream))::out,
> io::di, io::uo) is det.
>
> then this huge predicate does not need another level of indentation.
>
> Other changes in this diff would benefit from using this predicate as
> well.
It wouldn't help in this case. In this case:
+ The temp file name is chosen and created.
+ A system command is executed to write to the new file.
+ The file is opened for input.
But it'd still be useful, I'll implement it for both patterns.
> > diff --git a/library/io.m b/library/io.m
> > index 41a3f10..a944075 100644
> > --- a/library/io.m
> > +++ b/library/io.m
> > % name is different to the name of any existing file. The file will reside
> > % in the directory specified by Dir and will have a prefix using up to
> > - % the first 5 characters of Prefix. Name is bound to the name of the
> > - % file. It is the responsibility of the caller to delete the file when it
> > - % is no longer required.
> > - %
> > - % Throws an io.error exception if the temporary file could not be created.
> > + % the first 5 characters of Prefix. If successful, Result returns the name
> > + % of the file. It is the responsibility of the caller to delete the file
> > + % when it is no longer required.
> > %
> > % The C# backend has the following limitations:
> > % - Dir is ignored.
> > % - Prefix is ignored.
> > + % - Suffix is ignored.
> > + %
> > + % On the Erlang backend Suffix is ignored.
> > %
> > % On the Erlang and Java backends, this does not attempt to create the file
> > % with restrictive permissions (600 on Unix-like systems) and therefore
> > % should not be used when security is required.
> > %
> > -:- pred make_temp(string::in, string::in, string::out, io::di, io::uo)
> > - is det.
> > +:- pred make_temp_res(string::in, string::in, string::in, io.res(string)::out,
> > + io::di, io::uo) is det.
>
> The list of exceptions gets longer and longer :(
>
> Ignoring the Suffix seems worse than ignoring the Dir and Prefix;
> presumably the caller wants a specific file extension?
> If Suffix can't be supported on C#, perhaps we should just drop it.
> It's only used so far in that --restricted-command-line path, which
> could be handled some other way (e.g. renaming the temp file).
> Unfortunately the log message that added the ++ LibExt does not say why
> it was added.
It seems better to improve the C# implementation. We just haven't done that
yet.
--
Paul Bone
More information about the reviews
mailing list