11defmodule Testcontainers.Util.PropertiesParser do
22 @ moduledoc false
33
4- @ file_path "~/.testcontainers.properties"
4+ @ user_file "~/.testcontainers.properties"
5+ @ project_file ".testcontainers.properties"
6+ @ env_prefix "TESTCONTAINERS_"
57
6- def read_property_file ( file_path \\ @ file_path ) do
8+ def read_property_file ( file_path \\ @ user_file ) do
79 if File . exists? ( Path . expand ( file_path ) ) do
810 with { :ok , content } <- File . read ( Path . expand ( file_path ) ) ,
911 properties <- parse_properties ( content ) do
@@ -18,6 +20,76 @@ defmodule Testcontainers.Util.PropertiesParser do
1820 end
1921 end
2022
23+ @ doc """
24+ Reads properties from all sources with proper precedence.
25+
26+ Configuration is read from three sources with the following precedence
27+ (highest to lowest):
28+
29+ 1. Environment variables (TESTCONTAINERS_* prefix)
30+ 2. User file (~/.testcontainers.properties)
31+ 3. Project file (.testcontainers.properties)
32+
33+ Environment variables are converted from TESTCONTAINERS_PROPERTY_NAME format
34+ to property.name format (uppercase to lowercase, underscores to dots, prefix removed).
35+
36+ ## Options
37+
38+ - `:user_file` - path to user properties file (default: ~/.testcontainers.properties)
39+ - `:project_file` - path to project properties file (default: .testcontainers.properties)
40+ - `:env_prefix` - environment variable prefix (default: TESTCONTAINERS_)
41+
42+ Returns `{:ok, map}` with merged properties.
43+ """
44+ def read_property_sources ( opts \\ [ ] ) do
45+ user_file = Keyword . get ( opts , :user_file , @ user_file )
46+ project_file = Keyword . get ( opts , :project_file , @ project_file )
47+ env_prefix = Keyword . get ( opts , :env_prefix , @ env_prefix )
48+
49+ project_props = read_file_silent ( project_file )
50+ user_props = read_file_silent ( user_file )
51+ env_props = read_env_vars ( env_prefix )
52+
53+ # Merge in order of lowest to highest precedence
54+ merged =
55+ project_props
56+ |> Map . merge ( user_props )
57+ |> Map . merge ( env_props )
58+
59+ { :ok , merged }
60+ end
61+
62+ defp read_file_silent ( file_path ) do
63+ expanded = Path . expand ( file_path )
64+
65+ if File . exists? ( expanded ) do
66+ case File . read ( expanded ) do
67+ { :ok , content } -> parse_properties ( content )
68+ { :error , _ } -> % { }
69+ end
70+ else
71+ % { }
72+ end
73+ end
74+
75+ defp read_env_vars ( prefix ) do
76+ System . get_env ( )
77+ |> Enum . filter ( fn { key , _value } -> String . starts_with? ( key , prefix ) end )
78+ |> Enum . map ( & env_to_property ( & 1 , prefix ) )
79+ |> Map . new ( )
80+ end
81+
82+ # Converts TESTCONTAINERS_RYUK_CONTAINER_PRIVILEGED to ryuk.container.privileged
83+ defp env_to_property ( { key , value } , prefix ) do
84+ property_key =
85+ key
86+ |> String . replace_prefix ( prefix , "" )
87+ |> String . downcase ( )
88+ |> String . replace ( "_" , "." )
89+
90+ { property_key , value }
91+ end
92+
2193 defp parse_properties ( content ) do
2294 content
2395 |> String . split ( "\n " )
0 commit comments