Using Ant to merge two different properties files

2019-04-26 13:51发布

I have a default properties file, and some deployment specific properties files that override certain settings from the default, based on deployment environment. I would like my Ant build script to merge the two properties files (overwriting default values with deployment specific values), and then output the resulting properties to a new file.

I tried doing it like so but I was unsuccessful:

<target depends="init" name="configure-target-environment">
    <filterset id="application-properties-filterset">
        <filtersfile file="${build.config.path}/${target.environment}/application.properties" />
    </filterset>

    <copy todir="${web-inf.path}/conf" file="${build.config.path}/application.properties" overwrite="true" failonerror="true" >
        <filterset refid="application-properties-filterset" />
    </copy>
</target>

5条回答
等我变得足够好
2楼-- · 2019-04-26 14:36

I did it like this:

<property prefix="app.properties" file="custom.application.properties" />
<property prefix="app.properties" file="default.application.properties" />
<echoproperties destfile="application.properties">
   <propertyset>
      <propertyref prefix="app.properties"/>
      <mapper type="glob" from="app.properties.*" to="*"/>
   </propertyset>
</echoproperties>
查看更多
Fickle 薄情
3楼-- · 2019-04-26 14:44

I personally use this:

<copy todir="${web-inf.path}/conf" filtering="true">
  <fileset dir="${build.config.path}" includes="*.properties" /> 
  <filterset>
    <filtersfile file="application-properties-filterset" /> 
  </filterset>
</copy>
查看更多
Juvenile、少年°
4楼-- · 2019-04-26 14:47

I figured this one out. There needs to be an extra properties file created, with each key/value in the following format: mail.server.host=@mail.server.host@ etc...

Then specify this "template" file to the "file" attribute of the task. Also in the filterset, specify multiple with the least important one listed first.

So it would look like this:

<copy todir="${web-inf.path}/conf" file="${build.config.path}/template.application.properties" overwrite="true" failonerror="true" >
    <filterset refid="application-properties-filterset" />
</copy>

查看更多
祖国的老花朵
5楼-- · 2019-04-26 14:48

Perhaps you should look at the concat task of ant for this.

查看更多
小情绪 Triste *
6楼-- · 2019-04-26 14:50

The other answers are okay, but I needed one without these limitations:

  • The need for all properties to be specified as templates with @tokens@ (first answer)
  • Property expansion - e.g. I have properties defined as prop2=${prop1} which will get expanded by any solution that loads and echos properties
  • EchoProperties (@user2500146) escapes characters like colons which is annoying for URL properties (not Ant's fault, that's standard Java Properties, which allow : in place of =)
  • Repeated properties from concat-based solutions (this works, because the 2nd definition is ignored, but I didn't want repeats

In the end I had to resort to javascript in a filter, but my solution brings in default properties if and only if they are not defined in the main properties file. It works by loading the main properties with an obscure prefix, then copying it to the destination, then concat'ing the default properties while filtering out any default properties that were loaded in the first step.

You can use this verbatim but will probably want to take out the log statements or change them to debug level, once you're convinced

<!-- merge the main.properties.file with the default.properties.file
     into the output.properties.file (make sure these are defined) -->
<target name="merge">
    <!--Obscure enough prefix to ensure the right props are handled-->
    <property name="prefix" value="__MY_PREFIX__"/>
    <!--Load the main properties so we can tell if the default is needed-->
    <property prefix="${prefix}" file="${main.properties.file}"/>

    <!--Copy the main properties, then append the defaults selectively-->
    <copy file="${main.properties.file}" tofile="${output.properties.file}" overwrite="true"/>
    <concat destfile="${output.properties.file}" append="true">
        <fileset file="${default.properties.file}"/>
        <filterchain>
            <!--Filter out lines with properties that were already in the main properties -->
            <scriptfilter language="javascript"> <![CDATA[
            var line = self.getToken();
            project.log("line: " + line);
            var skipLine = false;
            // lines that do not define properties are concatenated
            if (line.indexOf("=") != -1) {
                // get the property name from the line
                var propName = line.substr(0, line.indexOf('='));
                project.log("line prop: " + propName);
                var loadedPropName = "__MY_PREFIX__" + propName;
                if (project.getProperty(loadedPropName) != null) {
                    project.log("prop has original: " + project.getProperty(loadedPropName));
                   // skip this line, the property is defined
                   skipLine = true;
                }
            }

            if (skipLine) {
                project.log("skipping line: " + line);
                self.setToken(null);
            }
            else {
                // else leave the line in as it was
                project.log("adding default line: " + line);
                self.setToken(line);
            }

]]> </scriptfilter>
        </filterchain>
    </concat>
</target>
查看更多
登录 后发表回答