diff --git a/HOCON.md b/HOCON.md index 82221b0f..dc3dcd64 100644 --- a/HOCON.md +++ b/HOCON.md @@ -1095,6 +1095,11 @@ Implementations need not support files, Java resources, or URLs; and they need not support particular URL protocols. However, if they do support them they should do so as described above. +Note that at present, if `url()`/`file()`/`classpath()` are +specified, the included items are NOT interpreted relative to the +including items. Relative-to-including-file paths only work with +the heuristic `include "foo.conf"`. This may change in the future. + ### Conversion of numerically-indexed objects to arrays In some file formats and contexts, such as Java properties files, diff --git a/config/src/main/java/com/typesafe/config/impl/Parseable.java b/config/src/main/java/com/typesafe/config/impl/Parseable.java index 684d8f95..68d2c6f1 100644 --- a/config/src/main/java/com/typesafe/config/impl/Parseable.java +++ b/config/src/main/java/com/typesafe/config/impl/Parseable.java @@ -594,8 +594,10 @@ public abstract class Parseable implements ConfigParseable { if (sibling == null) return null; if (sibling.exists()) { + trace(sibling + " exists, so loading it as a file"); return newFile(sibling, options().setOriginDescription(null)); } else { + trace(sibling + " does not exist, so trying it as a classpath resource"); return super.relativeTo(filename); } } diff --git a/config/src/main/java/com/typesafe/config/impl/SimpleIncludeContext.java b/config/src/main/java/com/typesafe/config/impl/SimpleIncludeContext.java index 9920ef0e..73ef3004 100644 --- a/config/src/main/java/com/typesafe/config/impl/SimpleIncludeContext.java +++ b/config/src/main/java/com/typesafe/config/impl/SimpleIncludeContext.java @@ -24,6 +24,8 @@ class SimpleIncludeContext implements ConfigIncludeContext { @Override public ConfigParseable relativeTo(String filename) { + if (ConfigImpl.traceLoadsEnabled()) + ConfigImpl.trace("Looking for '" + filename + "' relative to " + parseable); if (parseable != null) return parseable.relativeTo(filename); else diff --git a/config/src/test/resources/file-include.conf b/config/src/test/resources/file-include.conf new file mode 100644 index 00000000..36d4efea --- /dev/null +++ b/config/src/test/resources/file-include.conf @@ -0,0 +1,5 @@ +base=41 +# included without file() in a subdir +include "subdir/foo.conf" +# included using file() in a subdir +include file("subdir/baz.conf") diff --git a/config/src/test/resources/subdir/bar-file.conf b/config/src/test/resources/subdir/bar-file.conf new file mode 100644 index 00000000..cd2058d8 --- /dev/null +++ b/config/src/test/resources/subdir/bar-file.conf @@ -0,0 +1 @@ +bar-file=44 diff --git a/config/src/test/resources/subdir/bar.conf b/config/src/test/resources/subdir/bar.conf new file mode 100644 index 00000000..567e6b4d --- /dev/null +++ b/config/src/test/resources/subdir/bar.conf @@ -0,0 +1 @@ +bar=43 diff --git a/config/src/test/resources/subdir/baz.conf b/config/src/test/resources/subdir/baz.conf new file mode 100644 index 00000000..dc9b6f51 --- /dev/null +++ b/config/src/test/resources/subdir/baz.conf @@ -0,0 +1 @@ +baz=45 diff --git a/config/src/test/resources/subdir/foo.conf b/config/src/test/resources/subdir/foo.conf new file mode 100644 index 00000000..e75cf7bb --- /dev/null +++ b/config/src/test/resources/subdir/foo.conf @@ -0,0 +1,5 @@ +foo=42 +# included without file() +include "bar.conf" +# included using file() +include file("bar-file.conf") diff --git a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala index 98f86f16..0150d271 100644 --- a/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala +++ b/config/src/test/scala/com/typesafe/config/impl/PublicApiTest.scala @@ -1039,4 +1039,22 @@ include "onclasspath" assertEquals(42, conf.getInt("onclasspath")) } } + + @Test + def fileIncludeStatements(): Unit = { + val file = resourceFile("file-include.conf") + val conf = ConfigFactory.parseFile(file) + assertEquals("got file-include.conf", 41, conf.getInt("base")) + assertEquals("got subdir/foo.conf", 42, conf.getInt("foo")) + assertEquals("got bar.conf", 43, conf.getInt("bar")) + + // these two do not work right now, because we do not + // treat the filename as relative to the including file + // if file() is specified, so `include file("bar-file.conf")` + // fails. + //assertEquals("got bar-file.conf", 44, conf.getInt("bar-file")) + //assertEquals("got subdir/baz.conf", 45, conf.getInt("baz")) + assertFalse("did not get bar-file.conf", conf.hasPath("bar-file")) + assertFalse("did not get subdir/baz.conf", conf.hasPath("baz")) + } }