From 0d3e1b1ac9180215b4853bbd6ff0641056a64ff7 Mon Sep 17 00:00:00 2001 From: David Gardiner Date: Tue, 3 Jul 2018 20:04:58 +0930 Subject: [PATCH] Parse and use cake.config (if it exists) for configuration - Bash parsing cake.config for Tools path - Make use of https://github.com/lipkau/PsIni/blob/master/Functions/Get-IniContent.ps1 - Implements #15 for build.ps1 --- build.ps1 | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ build.sh | 131 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 281 insertions(+), 8 deletions(-) diff --git a/build.ps1 b/build.ps1 index a336e29..8e3500a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -101,13 +101,171 @@ function GetProxyEnabledWebClient return $wc } +Function Get-IniContent { + <# + .Synopsis + Gets the content of an INI file + .Description + Gets the content of an INI file and returns it as a hashtable + .Notes + Author : Oliver Lipkau + Source : https://github.com/lipkau/PsIni + http://gallery.technet.microsoft.com/scriptcenter/ea40c1ef-c856-434b-b8fb-ebd7a76e8d91 + Version : 1.0.0 - 2010/03/12 - OL - Initial release + 1.0.1 - 2014/12/11 - OL - Typo (Thx SLDR) + Typo (Thx Dave Stiff) + 1.0.2 - 2015/06/06 - OL - Improvment to switch (Thx Tallandtree) + 1.0.3 - 2015/06/18 - OL - Migrate to semantic versioning (GitHub issue#4) + 1.0.4 - 2015/06/18 - OL - Remove check for .ini extension (GitHub Issue#6) + 1.1.0 - 2015/07/14 - CB - Improve round-tripping and be a bit more liberal (GitHub Pull #7) + OL - Small Improvments and cleanup + 1.1.1 - 2015/07/14 - CB - changed .outputs section to be OrderedDictionary + 1.1.2 - 2016/08/18 - SS - Add some more verbose outputs as the ini is parsed, + allow non-existent paths for new ini handling, + test for variable existence using local scope, + added additional debug output. + #Requires -Version 2.0 + .Inputs + System.String + .Outputs + System.Collections.Specialized.OrderedDictionary + .Parameter FilePath + Specifies the path to the input file. + .Parameter CommentChar + Specify what characters should be describe a comment. + Lines starting with the characters provided will be rendered as comments. + Default: ";" + .Parameter IgnoreComments + Remove lines determined to be comments from the resulting dictionary. + .Example + $FileContent = Get-IniContent "C:\myinifile.ini" + ----------- + Description + Saves the content of the c:\myinifile.ini in a hashtable called $FileContent + .Example + $inifilepath | $FileContent = Get-IniContent + ----------- + Description + Gets the content of the ini file passed through the pipe into a hashtable called $FileContent + .Example + C:\PS>$FileContent = Get-IniContent "c:\settings.ini" + C:\PS>$FileContent["Section"]["Key"] + ----------- + Description + Returns the key "Key" of the section "Section" from the C:\settings.ini file + .Link + Out-IniFile + #> + + [CmdletBinding()] + Param( + [ValidateNotNullOrEmpty()] + [Parameter(ValueFromPipeline=$True,Mandatory=$True)] + [string]$FilePath, + [char[]]$CommentChar = @(";"), + [switch]$IgnoreComments + ) + + Begin + { + Write-Debug "PsBoundParameters:" + $PSBoundParameters.GetEnumerator() | ForEach-Object { Write-Debug $_ } + if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } + Write-Debug "DebugPreference: $DebugPreference" + + Write-Verbose "$($MyInvocation.MyCommand.Name):: Function started" + + $commentRegex = "^([$($CommentChar -join '')].*)$" + Write-Debug ("commentRegex is {0}." -f $commentRegex) + } + + Process + { + Write-Verbose "$($MyInvocation.MyCommand.Name):: Processing file: $Filepath" + + $ini = New-Object System.Collections.Specialized.OrderedDictionary([System.StringComparer]::OrdinalIgnoreCase) + + if (!(Test-Path $Filepath)) + { + Write-Verbose ("Warning: `"{0}`" was not found." -f $Filepath) + return $ini + } + + $commentCount = 0 + switch -regex -file $FilePath + { + "^\s*\[(.+)\]\s*$" # Section + { + $section = $matches[1] + Write-Verbose "$($MyInvocation.MyCommand.Name):: Adding section : $section" + $ini[$section] = New-Object System.Collections.Specialized.OrderedDictionary([System.StringComparer]::OrdinalIgnoreCase) + $CommentCount = 0 + continue + } + $commentRegex # Comment + { + if (!$IgnoreComments) + { + if (!(test-path "variable:local:section")) + { + $section = "_" + $ini[$section] = New-Object System.Collections.Specialized.OrderedDictionary([System.StringComparer]::OrdinalIgnoreCase) + } + $value = $matches[1] + $CommentCount++ + Write-Debug ("Incremented CommentCount is now {0}." -f $CommentCount) + $name = "Comment" + $CommentCount + Write-Verbose "$($MyInvocation.MyCommand.Name):: Adding $name with value: $value" + $ini[$section][$name] = $value + } + else { Write-Debug ("Ignoring comment {0}." -f $matches[1]) } + + continue + } + "(.+?)\s*=\s*(.*)" # Key + { + if (!(test-path "variable:local:section")) + { + $section = "_" + $ini[$section] = New-Object System.Collections.Specialized.OrderedDictionary([System.StringComparer]::OrdinalIgnoreCase) + } + $name,$value = $matches[1..2] + Write-Verbose "$($MyInvocation.MyCommand.Name):: Adding key $name with value: $value" + $ini[$section][$name] = $value + continue + } + } + Write-Verbose "$($MyInvocation.MyCommand.Name):: Finished Processing file: $FilePath" + Return $ini + } + + End + {Write-Verbose "$($MyInvocation.MyCommand.Name):: Function ended"} +} + Write-Host "Preparing to run build script..." if(!$PSScriptRoot){ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent } +$CAKE_CONFIG = Join-Path $PSScriptRoot "cake.config" + $TOOLS_DIR = Join-Path $PSScriptRoot "tools" + +if (Test-Path $CAKE_CONFIG) { + $ini = Get-IniContent $CAKE_CONFIG + + if ($ini["Paths"] -and $ini["Paths"]["Tools"]) { + $TOOLS_DIR = $ini["Paths"]["Tools"] + + # Ensure absolute path + if (-not [IO.Path]::IsPathRooted($TOOLS_DIR)) { + $TOOLS_DIR = Join-Path $PSScriptRoot $TOOLS_DIR + } + } +} + $ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" $MODULES_DIR = Join-Path $TOOLS_DIR "Modules" $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" diff --git a/build.sh b/build.sh index b9e1252..1d952b9 100755 --- a/build.sh +++ b/build.sh @@ -9,14 +9,6 @@ # Define directories. SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) TOOLS_DIR=$SCRIPT_DIR/tools -ADDINS_DIR=$TOOLS_DIR/Addins -MODULES_DIR=$TOOLS_DIR/Modules -NUGET_EXE=$TOOLS_DIR/nuget.exe -CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe -PACKAGES_CONFIG=$TOOLS_DIR/packages.config -PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum -ADDINS_PACKAGES_CONFIG=$ADDINS_DIR/packages.config -MODULES_PACKAGES_CONFIG=$MODULES_DIR/packages.config # Define md5sum or md5 depending on Linux/OSX MD5_EXE= @@ -40,6 +32,129 @@ for i in "$@"; do shift done +# INI file parsing is from https://github.com/albfan/bash-ini-parser/blob/master/bash-ini-parser +PREFIX="cfg_section_" + +function debug { + return #abort debug + echo $* + echo --start-- + echo "${ini[*]}" + echo --end-- + echo +} + +function cfg_parser { + shopt -p extglob &> /dev/null + CHANGE_EXTGLOB=$? + if [ $CHANGE_EXTGLOB = 1 ] + then + shopt -s extglob + fi + ini="$(<$1)" # read the file + ini="${ini//[/\\[}" # escape [ + debug + ini="${ini//]/\\]}" # escape ] + debug + IFS=$'\n' && ini=( ${ini} ) # convert to line-array + debug + ini=( ${ini[*]//;*/} ) # remove comments with ; + debug + ini=( ${ini[*]/#+([[:space:]])/} ) # remove init whitespace + debug "whitespace around" + ini=( ${ini[*]/*([[:space:]])=*([[:space:]])/=} ) # remove whitespace around = + debug + ini=( ${ini[*]/#\\[/\}$'\n'"$PREFIX"} ) # set section prefix + debug + ini=( ${ini[*]/%\\]/ \(} ) # convert text2function (1) + debug + ini=( ${ini[*]/=/=\( } ) # convert item to array + debug + ini=( ${ini[*]/%/ \)} ) # close array parenthesis + debug + ini=( ${ini[*]/%\\ \)/ \\} ) # the multiline trick + debug + ini=( ${ini[*]/%\( \)/\(\) \{} ) # convert text2function (2) + debug + ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis + ini=( ${ini[*]/%\{/\{$'\n''cfg_unset ${FUNCNAME/#'$PREFIX'}'$'\n'} ) # clean previous definition of section + debug + ini[0]="" # remove first element + debug + ini[${#ini[*]} + 1]='}' # add the last brace + debug + eval "$(echo "${ini[*]}")" # eval the result + EVAL_STATUS=$? + if [ $CHANGE_EXTGLOB = 1 ] + then + shopt -u extglob + fi + return $EVAL_STATUS +} + +function cfg_unset { + SECTION=$1 + OLDIFS="$IFS" + IFS=' '$'\n' + if [ -z "$SECTION" ] + then + fun="$(declare -F)" + else + fun="$(declare -F $PREFIX$SECTION)" + if [ -z "$fun" ] + then + echo "section $SECTION not found" >2 + return + fi + fi + fun="${fun//declare -f/}" + for f in $fun; do + [ "${f#$PREFIX}" == "${f}" ] && continue + item="$(declare -f ${f})" + item="${item##*\{}" # remove function definition + item="${item##*FUNCNAME*$PREFIX\};}" # remove clear section + item="${item/\}}" # remove function close + item="${item%)*}" # remove everything after parenthesis + item="${item});" # add close parenthesis + vars="" + while [ "$item" != "" ] + do + newvar="${item%%=*}" # get item name + vars="$vars $newvar" # add name to collection + item="${item#*;}" # remove readed line + done + for var in $vars; do + unset $var + done + done + IFS="$OLDIFS" +} + + +# Parse cake.config +if [ -f "cake.config" ]; then + + cfg_parser cake.config + cfg_section_Paths + + if [ ! -z ${Tools+x} ]; then + + # Make absolute and normalise + TOOLS_DIR=$( python -c "import os,sys; print os.path.realpath(sys.argv[1])" $Tools) + + echo "Parsed cake.config. TOOLS_DIR updated to $TOOLS_DIR" + fi +fi + +ADDINS_DIR=$TOOLS_DIR/Addins +MODULES_DIR=$TOOLS_DIR/Modules +NUGET_EXE=$TOOLS_DIR/nuget.exe +CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe +PACKAGES_CONFIG=$TOOLS_DIR/packages.config +PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum +ADDINS_PACKAGES_CONFIG=$ADDINS_DIR/packages.config +MODULES_PACKAGES_CONFIG=$MODULES_DIR/packages.config + # Make sure the tools folder exist. if [ ! -d "$TOOLS_DIR" ]; then mkdir "$TOOLS_DIR"