This is a long post. The simple question is what methods have you
chosen to maintain config files when deployed to multiple environments?
I am in the process of reworking a set of build, package, install NAnt
scripts that mainly use Token Replace and I am trying to decide if it is
better to switch to a method I have used before of XMLPoke.
The current method is to take the existing config file and replace the
AppSettings with a version of the AppSettings that have all of the
values replaced as tokens with the token name being the same name as the
key. When the script comes to the part where it needs to set the values
for the environment it will pass the each config file to a single
target. In the target it has all of the replacestokens for each file
seperated by an if in the
<replacetokens if="${output.config.name == 'MailerService.exe.config'}">
and then it sets the tokens for that specific config file. Once it has
gone through all the ones it know s about it has a section that it tries
to catch the ones that might be there.
I see some good things and bad things with this method.
Bad
1) I don't really like the Target being the all in one place for each
config file (this could be fixed with refactoring)
2) Lots of repeated values (this could be fixed with refactoring)
3) If new appsettings are added the token will need to be added.
Good
1) Each config could have unique values
2) When a appsetting is missed the build will fail allowing new
appsettings to not be forgotten
3) it is already built
4) The name of the token is always the name of the appsetting
A method I came up with to handle config files would work here but I am
not sure it is worth the effort in the long run. I will share the basic
method below.
There are 4 files.
1) Run.build is where you will be determining what values need to be set
in the config file and what config file to work with
2) config.helper.build is where the actual replacement happens.
3) config.xpath.build is where the actual xpaths of where the specific
item is located in the config file
4) env.properties.build is where the specific values are set for each
value. This is the file you would be changing for each environment.
change all you need in one file.
The over view of the process is that you create a file that holds all
the xpath to each of the settings. if the values need to be different
in different config files for the same key and xpath you will need to
create a unique property/target combo name that is unique. Each item
that you want to set in a config file has a property and a target of the
same name. This way you can easily find the property and xpath match.
For each time you want to set the property in your config file you
simply need to set the config file you want to change and call the
target of the item you want to replace. This is really clean and easy
to read.
Bad
1) need to track down all the valid XPaths
2) need seperate property / target when the same xpath and different
values are needed
3) could miss values set for keys that are not specifically called out
leaving dev or other values in the deployed version.
Good
1) easy to see what all the values are
2) know specifically what is being replaced for each config file
3) one file for each environment
4) no need to create and replace tokens
5) can replace any attribute in the config file as long as you can
create an XPath to it.
6) more likely to reuse properties for configs
Run.build
<project name="SupportConfig" default="config.update">
<property name="property.values.file" value="env.properties.build" />
<include buildfile="${property.values.file}" />
<include buildfile="config.xpath.build" />
<include buildfile="config.helper.build" />
<target name="support.config.update">
<property name="this.config.file"
value="${Depot_Path}\projects\Support\web.config" />
<call target="PUBLIC_SITE_URL" />
<call target="PUBLIC_SITE_SECURE_URL" />
</target>
</project>
config.helper.build
<project name="config.helper">
<property name="this.config.file" value="" />
<property name="this.xpath" value="" />
<property name="this.value" value="" />
<target name="config.poke">
<if test="${file::exists(this.config.file)}">
<xmlpoke file="${this.config.file}" value="${this.value}"
xpath="${this.xpath}" />
<echo message="Poked ${this.config.file}. Changed value @
${this.xpath} to ${this.value}" />
</if>
<if test="${not file::exists(this.config.file)}">
<echo message="The version file ${this.config.file} doesn't
exist!" />
</if>
</target>
</project>
config.xpath.build
<project name="config.xpath">
<target name="PUBLIC_SITE_URL">
<property name="this.xpath"
value="/configuration/appSettings/add[@key='PUBLIC_SITE_URL']/@value" />
<property name="this.value" value=" ${target::get-current-target()}"
/>
<call target="config.poke" />
</target>
<target name="PUBLIC_SITE_SECURE_URL">
<property name="this.xpath"
value="/configuration/appSettings/add[@key='PUBLIC_SITE_SECURE_URL']/@va
lue" />
<property name="this.value" value="${target::get-current-target()}"
/>
<call target="config.poke" />
</target>
</project>
env.properties.build
<project name="env.properties">
<property name="Platform_Domain"
value="wwww.mydomain.com" />
<property name="Depot_Path"
value="c:\perforce-depot\Branch" />
<property name="PUBLIC_SITE_URL"
value="http://${Platform_Domain}"/>
<property name="PUBLIC_SITE_SECURE_URL"
value="https://${Platform_Domain}"/>
</project>
Scott Pennington
Senior Software Engineer
Prosper Marketplace, Inc.
111 Sutter Street, 22nd Floor
San Francisco CA 94104
www.prosper.com <http://www.prosper.com/>
------------------------------------------------------------------------------
Special Offer -- Download ArcSight Logger for FREE!
Finally, a world-class log management solution at an even better
price-free! And you'll get a free "Love Thy Logs" t-shirt when you
download Logger. Secure your free ArcSight Logger TODAY!
http://p.sf.net/sfu/arcsisghtdev2dev
_______________________________________________
NAnt-users mailing list
NAnt-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nant-users