by Indra
10. November 2011 05:54
These are file and directory manipulation tasks that I use during continuous integration process at MAP Teams(a really cool .NET shop in Jakarta, Indonesia).
List of tasks:
- Change Inheritance of some classes before compiling the project(solution)
- Copy all files named "copy of app.config" to "app.config" or web.config before compiling
solution.
- Change version number in assemblyInfo file before committing source code back to repository.
- Deleting and creating temp directory hierarchy.
- Will be added later.
1. Change Inheritance of some classes before compiling the project(solution)
task :Change_Class_Inheritance do
classFiles = File.join(LOC_WORKING_DIRECTORY,"another\\folders/hierarchy","../foldersA/folderB\\MapTeamsPolls/Admin*.aspx.cs")
# glob with the pattern for files with " Admin*.aspx.cs" in the directory location
fileCollection = Dir[classFiles]
fileCollection.each do|sourceFile|
#read file content to string variable
text = File.read( sourceFile)
#change the line matching the pattern
text = text.gsub(/(^\s*public partial class .*:\s*)(.*)/, '\1UmbracoEnsuredPage')
#write the modified content back to file
File.open(sourceFile, 'w') { |f| f.write(text) }
end
End
(Back to index.)
2. Copy all files named "copy of app.config" to "app.config" or web.config before compiling solution.
def CommonUtils.rename_config_files(sourcePath)
#replace backslash to forward slash; glob doesn't work with backslash!!!
sourceFolder = sourcePath.gsub(/\\/, '/')
pattern1 = sourceFolder+'/**/copy of *.config'
pattern2 = sourceFolder+'/**/*copy.config'
#search recursive directory below solution folder; search for "copy of " files ; remove the "copy of "
Dir[pattern1, pattern2].each { |configFile|
FileUtils.cp(configFile, configFile.gsub(/copy of | - Copy/i,'') , :verbose=>true )
}
end
(Back to index.)
3. Change version number in assemblyInfo file before committing source code back to repository
### sourceFolder = project folder containing assemblyInfo; multiple folder
### "1.2.4.5"
def CommonUtils.update_assemblyInfo(sourceFolder, version)
sourceFolder = sourceFolder.gsub(/\\/, '/') #replace backslash ke forward slash; glob tidak bekerja kalau pakai backslash!!!
pattern1 = sourceFolder+"/**/Properties/AssemblyInfo.cs"
fileCollection = Dir[pattern1]
raise "No Assembly info found in (#{sourceFolder}) ; please check folder" if fileCollection.count == 0
fileCollection.each { |configFile|
text = File.read(configFile)
newContent = text.gsub!(/Assembly(|File)Version\(\".*\"\)/, "Assembly\\1Version(\"#{version}\")")
File.open(configFile, 'w') { |f| f.write(newContent) }
}
end
(Back to index.)
4. Deleting and creating temp directory hierarchy.
#target can be folders hierarchy (d:\\folderA/folderB\\folderC/folderD)
def RecreateEmptyFolder(target)
FileUtils.rm_rf(target, :verbose=>true) if (Dir[target] != [] and Dir[target] != nil )
#make sure no other process is holding the folder
#sometimes will fail as if rm_rf still not finished while mkdir_p is working
sleep 3
FileUtils.mkdir_p target , :verbose=>true
end
(Back to index.)
by Indra
12. September 2011 04:31
I need to execute InstallUtil.exe at the end of a MSI installation created using WIX.
At that moment this link is down (How to Invoke InstallUtil.exe in WiX Custom Action to Call Your Managed Installer Class).
I found out that what I need was Custom Action Type 34 (running an exe with a working directory) from these threads:
These are the code snippets incase the first link is down again.
<!-- create custom action -->
<CustomAction Id="AfterCopyingFiles" Directory="DirectoryID_Where_InstallUtil_Is_Copied"
ExeCommand="[DirectoryID_Where_InstallUtil_Is_Copied]installutil.exe File_Containing_RunInstaller_Attribute.exe" Return="check" Impersonate="yes" Execute="deferred" />
<CustomAction Id="ForUninstall" Directory="DirectoryID_Where_InstallUtil_Is_Copied"
ExeCommand="[DirectoryID_Where_InstallUtil_Is_Copied]installutil.exe /u File_Containing_RunInstaller_Attribute.exe" Return="check" Impersonate="yes" Execute="immediate" />
<!-- set when custom action will execute -->
<InstallExecuteSequence>
<!--install-->
<Custom Action="AfterCopyingFiles" After="InstallFiles">NOT Installed</Custom>
<!--uninstall-->
<Custom Action="ForUninstall" Before="RemoveFiles">REMOVE="ALL"</Custom>
</InstallExecuteSequence>
After reading Chapter 5 from WIX A Developers Guide to Windows Installer I found out 2 more ways to trigger an executable during installation:
- Custom Action Type 2: using Binary element for storing executable in MSI.
- Custom Action Type 18: using File element for copying the executable first to the target machine.
code snippet:
<CustomAction Id="CustomActionType2"
BinaryKey="BinaryElementId_For_The_Executable"
ExeCommand=""
Execute="commit"
Return="ignore" />
<CustomAction Id="CustomActionType18"
FileKey="FileElementId_For_The_Executable"
ExeCommand=""
Execute="commit"
Return="ignore" />
by Indra
19. January 2011 05:53
It's time to upgrade our Continuous Integration platform; I am updating CCNET 1.5 to CCNET 1.6 beta. Configuration Preprocessor with Conditional logic is awesome, I can refactor our distributed build system better with this.
The first error message I got after running the beta version:
[CCNet Server:ERROR] INTERNAL ERROR: Could not evaluate expression 'major}.{mino r}.{build}.{revision'
Reason: Syntax error
----------
The svnrevisionlabeller plugin from http://code.google.com/p/svnrevisionlabeller/ is not compatible with CCNET beta 1.6.
My quick fix is to edit and recompile the SVN Revision Labeller plugin. You can download the compiled dll here: ccnet.SvnRevisionLabeller.plugin.dll.zip (4.89 kb) and copy to the CCNET installation folder (WARNING! you must change the labeller pattern using '(' and ')' instead of '{' and '}' ).
or follow my steps to recompile:
- 1. Download the labeller plugin source code.
- 2. Copy 2 dlls from CCNET 1.6 installation folder to source code's Lib folder :
-
- ThoughtWorks.CruiseControl.Core.dll
- ThoughtWorks.CruiseControl.Remote.dll
- 3. Change the regex pattern from { } to ( ) . you can use other pattern.
- 4. Change your Labeller section in CCNET configuration to use the new token.
This is just my own solution; I haven't contacted the developer for this plugin.