55
66import java .io .BufferedReader ;
77import java .io .IOException ;
8+ import java .io .StringReader ;
9+ import java .io .StringWriter ;
810import java .nio .file .Files ;
911import java .nio .file .Path ;
1012import java .text .MessageFormat ;
1113import java .util .ArrayList ;
1214import java .util .HashMap ;
1315import java .util .List ;
1416import java .util .Map ;
17+ import java .util .concurrent .Callable ;
1518import java .util .regex .Pattern ;
1619import java .util .stream .Collectors ;
1720
21+ import com .github .mustachejava .DefaultMustacheFactory ;
22+ import com .github .mustachejava .Mustache ;
23+ import com .github .mustachejava .MustacheFactory ;
1824import com .oracle .weblogic .imagetool .logging .LoggingFacade ;
1925import com .oracle .weblogic .imagetool .logging .LoggingFactory ;
2026
@@ -30,10 +36,16 @@ public class AdditionalBuildCommands {
3036 public static final String AFTER_WDT = "after-wdt-command" ;
3137 public static final String FINAL_BLD = "final-build-commands" ;
3238
33- private List <NamedPattern > sections ;
34- private Map <String , List <String >> contents ;
39+ private final List <NamedPattern > sections ;
40+ private final Map <String , List <String >> contents ;
3541
36- private AdditionalBuildCommands () {
42+ /**
43+ * Load the contents of the additional build commands file into this object.
44+ * Existing data in this instance are replaced.
45+ * @param file Path to the additional build commands file that should be loaded.
46+ * @throws IOException if an issue occurs locating or opening the file provided
47+ */
48+ public AdditionalBuildCommands (Path file ) throws IOException {
3749 sections = new ArrayList <>();
3850 sections .add (getPattern (PACKAGES ));
3951 sections .add (getPattern (BEFORE_JDK ));
@@ -43,6 +55,8 @@ private AdditionalBuildCommands() {
4355 sections .add (getPattern (BEFORE_WDT ));
4456 sections .add (getPattern (AFTER_WDT ));
4557 sections .add (getPattern (FINAL_BLD ));
58+ contents = new HashMap <>();
59+ load (file );
4660 }
4761
4862 private static NamedPattern getPattern (String key ) {
@@ -61,8 +75,38 @@ public int size() {
6175 return contents .size ();
6276 }
6377
64- public Map <String ,List <String >> getContents () {
65- return contents ;
78+ /**
79+ * Get the contents of the file provided on the command line as additional build commands.
80+ * The file is parsed into a map based on the sections in the file. The returned map
81+ * will have one entry per section found in the provided file (such as "final-build-commands").
82+ * The Callable list value for each entry is for late resolution of the contents. If the user
83+ * provides mustache placeholders in the file, those placeholders will get resolved when the call
84+ * method is invoked and not when getContents is returned. This allows getContents to be called
85+ * before DockerfileOptions is completely populated.
86+ *
87+ * @param options The backing file that will be used to resolve any mustache placeholders in the file
88+ * @return a map by section name of the additional build file contents
89+ */
90+ public Map <String , Callable <List <String >>> getContents (DockerfileOptions options ) {
91+ Map <String , Callable <List <String >>> callableResult = new HashMap <>();
92+ for (Map .Entry <String , List <String >> entry : contents .entrySet ()) {
93+ // implements the "call" method so that the contents are resolved at the time they are retrieved
94+ Callable <List <String >> value = () -> {
95+ List <String > resolvedLines = new ArrayList <>();
96+ MustacheFactory mf = new DefaultMustacheFactory ();
97+ // Parse each line in the file contents using mustache and the provided "options"
98+ for (String line : entry .getValue ()) {
99+ StringWriter writer = new StringWriter ();
100+ Mustache mustache = mf .compile (new StringReader (line ), "x" );
101+ mustache .execute (writer , options );
102+ writer .flush ();
103+ resolvedLines .add (writer .toString ());
104+ }
105+ return resolvedLines ;
106+ };
107+ callableResult .put (entry .getKey (), value );
108+ }
109+ return callableResult ;
66110 }
67111
68112 /**
@@ -80,26 +124,23 @@ public List<String> getSection(String name) {
80124 * @param file Path to the additional build commands file that should be loaded.
81125 * @throws IOException if an issue occurs locating or opening the file provided
82126 */
83- public static AdditionalBuildCommands load (Path file ) throws IOException {
127+ private void load (Path file ) throws IOException {
84128 logger .entering (file );
85- AdditionalBuildCommands result = new AdditionalBuildCommands ();
86- result .contents = new HashMap <>();
87-
88129 try (BufferedReader reader = Files .newBufferedReader (file )) {
89130 List <String > buffer = new ArrayList <>();
90131 String currentSection = null ;
91132 String line ;
92133 while ((line = reader .readLine ()) != null ) {
93134 logger .finest (line );
94- String sectionStart = result . checkForSectionHeader (line );
135+ String sectionStart = checkForSectionHeader (line );
95136 //skip any lines that come before the first section header
96137 if (currentSection != null && sectionStart == null ) {
97138 //collect lines inside current section
98139 buffer .add (line );
99140 } else if (currentSection != null ) {
100141 //while in a section, found next section start (save last section, and start new section)
101142 logger .fine ("IMG-0015" , buffer .size (), currentSection );
102- result . contents .put (currentSection , buffer );
143+ contents .put (currentSection , buffer );
103144 buffer = new ArrayList <>();
104145 currentSection = sectionStart ;
105146 } else if (sectionStart != null ) {
@@ -111,15 +152,14 @@ public static AdditionalBuildCommands load(Path file) throws IOException {
111152 if (currentSection != null && !buffer .isEmpty ()) {
112153 //finished reading file, store the remaining lines that were read for the section
113154 logger .fine ("IMG-0015" , buffer .size (), currentSection );
114- result . contents .put (currentSection , buffer );
155+ contents .put (currentSection , buffer );
115156 }
116157 } catch (IOException ioe ) {
117158 logger .severe ("IMG-0013" , file .getFileName ());
118159 throw ioe ;
119160 }
120161
121162 logger .exiting ();
122- return result ;
123163 }
124164
125165 private String checkForSectionHeader (String line ) {
0 commit comments