package-classes.psm1 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #-------------------------------------------------------------------------------------------------------
  2. # Copyright (C) Microsoft. All rights reserved.
  3. # Copyright (c) ChakraCore Project Contributors. All rights reserved.
  4. # Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. #-------------------------------------------------------------------------------------------------------
  6. using namespace System.Collections
  7. using namespace System.IO
  8. using namespace System.Security
  9. using namespace System.Text.RegularExpressions
  10. using namespace System.Xml
  11. Set-StrictMode -Version 5.1
  12. class PrimitiveMustacheRenderer {
  13. hidden static [string]$mustacheTagPatternFormat = (
  14. '(?<startDelimiter>\{{{{{0}}})\s*' +
  15. '(?<tokenName>[\w-]+)' +
  16. '\s*(?<endDelimiter>\}}{{{0}}})'
  17. )
  18. hidden static [regex]$mustacheTagsRegex = [regex]::new((
  19. # Tag that is replaced with an unescaped value (e.g. `{{{name}}}`).
  20. ([PrimitiveMustacheRenderer]::mustacheTagPatternFormat -f 3) +
  21. '|' +
  22. # Tag that is replaced with an escaped value (e.g. `{{name}}`).
  23. ([PrimitiveMustacheRenderer]::mustacheTagPatternFormat -f 2)
  24. ))
  25. static [string]RenderTemplate([string]$template, [Hashtable]$data) {
  26. return [PrimitiveMustacheRenderer]::mustacheTagsRegex.Replace(
  27. $template,
  28. {
  29. param([Match]$match)
  30. $startDelimiter = $match.Groups['startDelimiter'].Value
  31. $endDelimiter = $match.Groups['endDelimiter'].Value
  32. $tokenName = $match.Groups['tokenName'].Value
  33. $tokenValue = [string]::Empty
  34. if ($data.Contains($tokenName)) {
  35. $tokenValue = $data[$tokenName]
  36. if ($startDelimiter -eq '{{{' -and $endDelimiter -eq '}}}') {
  37. # Skip escaping of the token value.
  38. return $tokenValue
  39. }
  40. # Converts a token value into an XML-encoded string.
  41. $tokenValue = [SecurityElement]::Escape($tokenValue)
  42. }
  43. return $tokenValue
  44. }
  45. )
  46. }
  47. static [bool]ContainsTag([string]$content) {
  48. return $content.Contains('{{') -and $content.Contains('}}')
  49. }
  50. }
  51. class Package {
  52. [ValidateNotNullOrEmpty()][string]$Id
  53. [ValidateNotNullOrEmpty()][string]$NuspecFile
  54. [Hashtable]$Properties
  55. [PreprocessableFile[]]$PreprocessableFiles
  56. Package([string]$id, [string]$nuspecFile, [Hashtable]$properties,
  57. [PreprocessableFile[]]$preprocessableFiles
  58. ) {
  59. $this.Id = $id
  60. $this.NuspecFile = $nuspecFile
  61. $this.Properties = $properties
  62. $this.PreprocessableFiles = $preprocessableFiles
  63. }
  64. static [Package[]]GetPackages([string]$packageDataFile) {
  65. $packageDataXml = [xml](Get-Content $packageDataFile -Encoding utf8)
  66. $packageDataElem = $packageDataXml.DocumentElement
  67. $commonPropertiesElem = $packageDataElem.commonProperties
  68. $packageElems = $packageDataElem.packages.SelectNodes('child::*')
  69. $packageDataDir = Split-Path -Parent $packageDataFile
  70. $commonProperties = [Package]::GetPackageCommonProperties($commonPropertiesElem)
  71. $packageCount = $packageElems.Count
  72. $packages = [Package[]]::new($packageCount)
  73. for ($packageIndex = 0; $packageIndex -lt $packageCount; $packageIndex++) {
  74. $packageElem = $packageElems[$packageIndex]
  75. $propertyElems = $null
  76. if ($packageElem['properties']) {
  77. $propertyElems = $packageElem.properties.SelectNodes('child::*')
  78. }
  79. $preprocessableFileElems = $null
  80. if ($packageElem['preprocessableFiles']) {
  81. $preprocessableFileElems = $packageElem.preprocessableFiles.SelectNodes('child::*')
  82. }
  83. $packageId = $packageElem.id
  84. $packageNuspecFile = (Join-Path $packageDataDir $packageElem.nuspecFile)
  85. $packageProperties = [Package]::ConvertXmlElementsToHashtable($propertyElems)
  86. $packageProperties = [Package]::MergePackageProperties($commonProperties,
  87. $packageProperties)
  88. $packagePreprocessableFiles = [Package]::GetPreprocessableFiles($preprocessableFileElems,
  89. $packageDataDir)
  90. $packages[$packageIndex] = [Package]::new($packageId, $packageNuspecFile,
  91. $packageProperties, $packagePreprocessableFiles)
  92. }
  93. return $packages
  94. }
  95. hidden static [Hashtable]GetPackageCommonProperties([XmlElement]$commonPropertiesElem) {
  96. if (!$commonPropertiesElem) {
  97. return @{}
  98. }
  99. $defaultPropertyElems = $null
  100. if ($commonPropertiesElem['defaultProperties']) {
  101. $defaultPropertyElems = $commonPropertiesElem.defaultProperties.SelectNodes('child::*')
  102. }
  103. $commonProperties = @{
  104. CommonMetadataElements = $commonPropertiesElem.commonMetadataElements.InnerXml
  105. CommonFileElements = $commonPropertiesElem.commonFileElements.InnerXml
  106. }
  107. $commonProperties += [Package]::ConvertXmlElementsToHashtable($defaultPropertyElems)
  108. return $commonProperties
  109. }
  110. hidden static [PreprocessableFile[]]GetPreprocessableFiles(
  111. [XmlNodeList]$fileElems,
  112. [string]$baseDir
  113. ) {
  114. if (!$fileElems) {
  115. return [PreprocessableFile[]]::new(0)
  116. }
  117. $fileCount = $fileElems.Count
  118. $files = [PreprocessableFile[]]::new($fileCount)
  119. for ($fileIndex = 0; $fileIndex -lt $fileCount; $fileIndex++) {
  120. $fileElem = $fileElems[$fileIndex]
  121. $srcFile = Join-Path $baseDir $fileElem.src
  122. $targetFile = Join-Path $baseDir $fileElem.target
  123. $files[$fileIndex] = [PreprocessableFile]::new($srcFile, $targetFile)
  124. }
  125. return $files
  126. }
  127. hidden static [Hashtable]MergePackageProperties(
  128. [Hashtable]$commonProperties,
  129. [Hashtable]$properties
  130. ) {
  131. $mergedProperties = $commonProperties.Clone()
  132. foreach ($propertyName in $properties.Keys) {
  133. $propertyValue = $properties[$propertyName]
  134. if ($mergedProperties.ContainsKey($propertyName) `
  135. -and [PrimitiveMustacheRenderer]::ContainsTag($propertyValue)
  136. ) {
  137. $basePropertyValue = $mergedProperties[$propertyName]
  138. $propertyValue = [PrimitiveMustacheRenderer]::RenderTemplate($propertyValue,
  139. @{ base = $basePropertyValue })
  140. }
  141. $mergedProperties[$propertyName] = $propertyValue
  142. }
  143. return $mergedProperties
  144. }
  145. hidden static [Hashtable]ConvertXmlElementsToHashtable([XmlNodeList]$elems) {
  146. if (!$elems) {
  147. return @{}
  148. }
  149. $hashtable = @{}
  150. foreach ($elem in $elems) {
  151. $hashtable.Add($elem.Name, $elem.'#text')
  152. }
  153. return $hashtable
  154. }
  155. [void]PreprocessFiles() {
  156. foreach ($file in $this.PreprocessableFiles) {
  157. $file.Preprocess($this.Properties)
  158. }
  159. }
  160. [void]RemovePreprocessedFiles() {
  161. foreach ($file in $this.PreprocessableFiles) {
  162. if ($file.IsPreprocessed) {
  163. Remove-Item $file.Target
  164. }
  165. }
  166. }
  167. }
  168. class PreprocessableFile {
  169. [ValidateNotNullOrEmpty()][string]$Src
  170. [ValidateNotNullOrEmpty()][string]$Target
  171. [bool]$IsPreprocessed
  172. PreprocessableFile([string]$src, [string]$target) {
  173. $this.Src = $src
  174. $this.Target = $target
  175. $this.IsPreprocessed = $false
  176. }
  177. [void]Preprocess([Hashtable]$properties) {
  178. $content = Get-Content $this.Src -Raw -Encoding utf8
  179. $preprocessedContent = [PrimitiveMustacheRenderer]::RenderTemplate($content, $properties)
  180. $targetFile = [PrimitiveMustacheRenderer]::RenderTemplate($this.Target, $properties)
  181. Set-Content $targetFile $preprocessedContent -Encoding utf8 -NoNewline
  182. $this.Target = $targetFile
  183. $this.IsPreprocessed = $true
  184. }
  185. }