Skip to content

fix Issue 15771 - FileLogger should create the output directory if it…#5370

Closed
burner wants to merge 1 commit intodlang:masterfrom
burner:filelogger_mkdir
Closed

fix Issue 15771 - FileLogger should create the output directory if it…#5370
burner wants to merge 1 commit intodlang:masterfrom
burner:filelogger_mkdir

Conversation

@burner
Copy link
Member

@burner burner commented May 7, 2017

… does not exist

@dlang-bot
Copy link
Contributor

dlang-bot commented May 7, 2017

Thanks for your pull request, @burner!

Bugzilla references

Auto-close Bugzilla Description
15771 FileLogger should create the output directory if it does not exist

Copy link
Contributor

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found the documentation quite hard to read and I added a couple of small nits.

if (createFileNameFolder && !exists(d))
{
() @trusted { mkdirRecurse(d); }();
assert(exists(d));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert should always come with a helpful error message.

Copy link
Member

@schveiguy schveiguy May 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... mkdirRecurse is already telling you whether it made the directory or not. Why not just assert that? Edit: no it's not. I misread the code. But it is already checking that the directory exists, see https://github.com/dlang/phobos/blob/master/std/file.d#L2308, so we can probably remove the assert altogether.

As far as a helpful message, I don't know the requirements, but isn't printing the line number and file (as asserts always do) helpful enough? No need if we remove the assert.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asserting on I/O errors is almost always a mistake. If mkdirRecurse's contract is that on its successful return (and barring any race conditions you can't avoid anyway) the directory exists, then the program should assume the directory exists - thus the assert is redundant.

auto d = dirName(this.filename);
if (createFileNameFolder && !exists(d))
{
() @trusted { mkdirRecurse(d); }();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the underlying assumption that mkdirRecurse will be @safe.
Imho we should eat our dogfood and make Phobos usable with @safe and not create more holes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

none, but the Issue can't be fixed without mkdirRecurse. It is not safe as it uses a C function again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but we can't simply add @trusted just to make functions @safe ...
CC @schveiguy

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to suggestions

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at mkdirRecurse, I think the trusted escape is OK. However, the best solution is to actually make mkdirRecurse @safe, and put the trusted escape on the C call inside there. If you want to do that, it would benefit others as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why mkdirRecurse shouldn't @safe - mkdir is already @safe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, the best solution is to actually make mkdirRecurse @safe

Shouldn't be too difficult: #5386

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping @burner, mkdirRecurse is now @safe.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, I'll change this PR

file can not be opened for writting an exception will be thrown.
lv = The $(D LogLevel) for the $(D FileLogger). By default the
$(D LogLevel) for $(D FileLogger) is $(D LogLevel.all).
createFileNameFolder = if true and fn contains a folder name, this
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nits:

  • How about using a Flag instead of a boolean?
  • How about naming it to sth. similar to make -p
    makeParentDirectories = If set to true`, parent directories will be created as needed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely use Flag. We've essentially decided that all new Phobos APIs that take bool parameters to take Flags instead.

this(fn, lv, false);
}

this(in string fn, const LogLevel lv, bool createFileNameFolder) @safe
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw CircleCi is failing due to

std/experimental/logger/filelogger.d(34): Warning: Ddoc: function declaration has no parameter 'createFileNameFolder'
std/experimental/logger/filelogger.d(34): Warning: Ddoc: parameter count mismatch
make: *** [style] Error 1

(you will need /// ditto to fix this)


this.filename = fn;
auto d = dirName(this.filename);
if (createFileNameFolder && !exists(d))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mkdirRecurse will already check for existence. The exists check is redundant, remove it.

super(lv);

this.filename = fn;
auto d = dirName(this.filename);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this into the if (createFileNameFolder) block to avoid a calculation that's unnecessary for the default case.

@burner burner force-pushed the filelogger_mkdir branch from add130e to f9c5f5c Compare May 17, 2017 19:07
@burner
Copy link
Member Author

burner commented May 17, 2017

all fixed up I hope

@burner burner force-pushed the filelogger_mkdir branch from f9c5f5c to 1986714 Compare June 1, 2017 12:12
{
import std.file : exists, rmdirRecurse;

string logpath = "super/long/path/";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please prepend with std.file.deleteme, don't just create test files in the local directory.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: deleteme just returns a string sth. like /tmp/deleteme.dmd.unittest.pid1234 - it can be used to construct temporary folders as well.

Copy link
Contributor

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@burner - how about a final rebase to get this in?

auto d = dirName(this.filename);
mkdirRecurse(d);
assert(exists(d), "The folder the FileLogger should have been"
~ " created in '" ~ d ~ "' could not be created.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use std.conv.text to make this a bit more efficient and legible (text uses an appender)

{
import std.file : exists, rmdirRecurse;

string logpath = "super/long/path/";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: deleteme just returns a string sth. like /tmp/deleteme.dmd.unittest.pid1234 - it can be used to construct temporary folders as well.


fl.file.close();
() @trusted { rmdirRecurse(logpath); }();
assert(!exists(logpath));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems unnecessary - you don't need to test rmdirRecurse

assert(exists(logpath));

fl.file.close();
() @trusted { rmdirRecurse(logpath); }();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about scope(exit) in the beginning, s.t. the temporary folder is removed even in case of failures?

super(lv);
this.filename = fn;

if (createFileNameFolder == CreateFolder.yes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (createFileNameFolder)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, this feels like it would defeats the purpose of the Flag type.

@JackStouffer
Copy link
Contributor

Ping @burner

@burner
Copy link
Member Author

burner commented Jul 12, 2017

@wilzbach I can't use deleteme as need a bunch of subdirs to check if this patch actually fixes the problem.

@wilzbach
Copy link
Contributor

@wilzbach I can't use deleteme as need a bunch of subdirs to check if this patch actually fixes the problem.

As mentioned before: "FYI: deleteme just returns a string sth. like /tmp/deleteme.dmd.unittest.pid1234 - it can be used to construct temporary folders as well."

See also: https://github.com/dlang/phobos/pull/5594/files

@wilzbach
Copy link
Contributor

@burner @RazvanN7 - I saw that you both rebased your PRs within the last hour. I don't mind which PR you finalize, but I think you both have permissions to push to each other's PR - use them (and close the other)!

@RazvanN7
Copy link
Collaborator

RazvanN7 commented Jul 12, 2017

@burner My PR uses deleteme and addresses the rest of the comments, but I copy-pasted your implementation. I'm down with whatever option you prefer, but I think it would be less pain for you to just close this one as mine is already in a mergeable condition

@burner burner closed this Jul 12, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants