dotnetconfig/dotnet-config

Impossible to have an extension-less config file name

Closed this issue · 3 comments

Describe the Bug

It's impossible to have a config file with a simple name without any extension like config via Config.Build. Instead, the file path assumed is .netconfig under a directory named config.

Steps to Reproduce

public class ReproTest
{
  [Fact]
  public void Repro()
  {
    // arrange
    var config = Config.Build("config");
    
    // act
    var fileName = Path.GetFileName(Config.Build("config").FilePath);
    
    // assert
    Assert.Equal("config", fileName);
  }
}

If you have LINQPad 6, you can checkout http://share.linqpad.net/nc6sta.linq for the repro.

Expected Behavior

Expected the file name of Config.FilePath to reflect the initialized file name.

Exception with Stack Trace

N/A

Version Info

1.0.4

Additional Info

I believe the issue is due to the second part of the following condition where if path has no extension then it's assumed to be a directory:

else if (Directory.Exists(path) || !Path.HasExtension(path))

This is contradictory to the comment that follows shortly after:

// If the path does not point to an existing directory
// we consider it a file path as a fallback.

A workaround is to create a blank file before using Config.Build:

var path = @"T:\config";
File.Create(path).Close();
var config = Config.Build(path);
Console.WriteLine(config.FilePath); // prints T:\config
kzu commented

This is basically a design choice I made. Say you initialize with bin\Debug, and the folder doesn't exit. I chose to assume in that case, it would be considered a folder, unless it actually had an extension.

I think it's the more reasonable default, and changing something like that at this point would be a breaking change (and not a very intuitive either IMHO).

Indeed, as you found, you can just create the file ahead of time and things will just work.

I think it's the more reasonable default, and changing something like that at this point would be a breaking change (and not a very intuitive either IMHO).

What's not very intuitive is that a method changes the semantics of its input argument depending on the state of an external system and especially whether you make a certain call before or not (like creating an file empty with the supplied name). A way to avoid the confusion would have been to only default the file name if the path argument ended in a directory separator. Then it would have been clear that the caller's intention is to specify a directory path.

kzu commented

Considering the ending in a directory is a good suggestion. Could you create a separate issue for that? It would still be a breaking change, but I think it's a worthwhile one. I wish I had thought of that up-front 🤷