├── .github
└── dependabot.yml
├── .gitignore
├── .paket
└── paket.exe
├── Build.ps1
├── LICENSE
├── MSBuildHelper.ps1
├── README.md
├── XamlCombine.msbuild
├── XamlCombine.nuspec
├── XamlCombine.sln
├── appveyor.yml
├── paket.dependencies
├── paket.lock
└── src
├── Combiner.cs
├── Program.cs
├── Properties
└── AssemblyInfo.cs
├── ResourceElement.cs
└── XamlCombine.csproj
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: nuget
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | open-pull-requests-limit: 10
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
290 | # local files
291 | *.local
--------------------------------------------------------------------------------
/.paket/paket.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fluentribbon/XamlCombine/c14352750e0b1d8612578a6fe5ee39e27cb40090/.paket/paket.exe
--------------------------------------------------------------------------------
/Build.ps1:
--------------------------------------------------------------------------------
1 | Param(
2 | [Parameter(Mandatory=$False)]
3 | [string]$Target = "Build",
4 | [Parameter(Mandatory=$False)]
5 | [string]$Configuration = "Release",
6 | [Parameter(Mandatory=$False)]
7 | [string]$PreRelease
8 | )
9 |
10 | $ErrorActionPreference = "Stop"
11 |
12 | . $PSScriptRoot\MSBuildHelper.ps1
13 |
14 | if ($PSBoundParameters['Verbose']) {
15 | $verbosity = "d"
16 | } else {
17 | $verbosity = "m"
18 | }
19 |
20 | Write-Output "Building with verbosity '$verbosity'"
21 |
22 | $msbuild = Get-MSBuild
23 |
24 | $measure = Measure-Command {
25 | &$msbuild XamlCombine.msbuild /target:$Target /property:Configuration=$Configuration /property:Prerelease=$PreRelease /v:$verbosity /nologo | Out-Default
26 | }
27 |
28 | Write-Output "Time elapsed $($measure.ToString())"
29 |
30 | if ($LASTEXITCODE -ne 0) { exit 1 }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 - 2018 Bastian Schmidt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/MSBuildHelper.ps1:
--------------------------------------------------------------------------------
1 | Add-Type -TypeDefinition @"
2 | public enum Platform
3 | {
4 | Current,
5 | x86,
6 | x64
7 | }
8 | "@
9 |
10 | function Using-Object
11 | {
12 | [CmdletBinding()]
13 | param (
14 | [Parameter(Mandatory = $true)]
15 | [AllowEmptyString()]
16 | [AllowEmptyCollection()]
17 | [AllowNull()]
18 | [Object]
19 | $InputObject,
20 |
21 | [Parameter(Mandatory = $true)]
22 | [scriptblock]
23 | $ScriptBlock
24 | )
25 |
26 | try
27 | {
28 | . $ScriptBlock
29 | }
30 | finally
31 | {
32 | if ($null -ne $InputObject -and $InputObject -is [System.IDisposable])
33 | {
34 | $InputObject.Dispose()
35 | }
36 | }
37 | }
38 |
39 | function Get-MSBuildVersion()
40 | {
41 | [CmdletBinding()]
42 | Param(
43 | [Parameter(Mandatory=$False)]
44 | [Version]$Version = $null,
45 | [Parameter(Mandatory=$False)]
46 | [switch]$All = $false
47 | )
48 |
49 | $versions = Get-ChildItem HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\ | ForEach-Object { New-Object System.Version ((Split-Path $_.Name -Leaf)) } | Sort-Object -Descending
50 |
51 | if ($All)
52 | {
53 | return $versions
54 | }
55 |
56 | if ($null -eq $Version)
57 | {
58 | return $versions[0]
59 | }
60 |
61 | foreach ($currentVersion in $versions)
62 | {
63 | if ($currentVersion -eq $Version)
64 | {
65 | return $currentVersion
66 | }
67 | }
68 |
69 | foreach ($currentVersion in $versions)
70 | {
71 | if ($currentVersion.Major -eq $Version)
72 | {
73 | return $currentVersion
74 | }
75 | }
76 |
77 | Write-Error "MSBuild version $Version could not be found"
78 |
79 | return $null
80 | }
81 |
82 | function Get-MSBuildPathLegacy()
83 | {
84 | [CmdletBinding()]
85 | Param(
86 | [Parameter(Mandatory=$False)]
87 | [Version]$Version = $null,
88 | [Parameter(Mandatory=$False)]
89 | [Platform]$Platform = [Platform]::Current
90 | )
91 |
92 | $foundVersion = Get-MSBuildVersion $Version -ErrorAction SilentlyContinue
93 |
94 | if ($null -eq $foundVersion)
95 | {
96 | Write-Error "MSBuild version $Version could not be found"
97 | return
98 | }
99 |
100 | switch ($Platform)
101 | {
102 | Current { $registryView = [Microsoft.Win32.RegistryView]::Default }
103 | x86 { $registryView = [Microsoft.Win32.RegistryView]::Registry32 }
104 | x64 { $registryView = [Microsoft.Win32.RegistryView]::Registry64 }
105 | }
106 |
107 | $path = "MSBuildToolsPath"
108 |
109 | Using-Object ($key = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $registryView)) {
110 | Using-Object ($subKey = $key.OpenSubKey("SOFTWARE\Microsoft\MSBuild\ToolsVersions\$foundVersion")) {
111 | $resolvedPath = $subKey.GetValue($path)
112 |
113 | if ($resolvedPath -eq $null)
114 | {
115 | Write-Error "Could not resolve path for version '$foundVersion' and '$path'"
116 | return $null
117 | }
118 |
119 | Write-Verbose "$path : $resolvedPath"
120 |
121 | return $resolvedPath
122 | }
123 | }
124 | }
125 |
126 | function Get-MSBuildPath()
127 | {
128 | [CmdletBinding()]
129 | Param(
130 | [Parameter(Mandatory=$False)]
131 | [String]$VersionString = $null,
132 | [Parameter(Mandatory=$False)]
133 | [Platform]$Platform = [Platform]::Current
134 | )
135 |
136 | if ($VersionString) {
137 | if (($VersionString -like "*.*") -eq $False) {
138 | $VersionString += ".0"
139 | }
140 |
141 | $version = [Version]$VersionString
142 | }
143 |
144 | if ((Get-Command vswhere -ErrorAction SilentlyContinue) -or $version -ge [Version]"15.0") {
145 | if ($version -eq $null) {
146 | $installationPath = vswhere -latest -products * -requires Microsoft.Component.MSBuild -property installationPath
147 | }
148 | else {
149 | $versionConstraint = "[$($version.Major).$($version.Minor), $($version.Major + 1).$($version.Minor))"
150 | $installationPath = vswhere -version $versionConstraint -products * -requires Microsoft.Component.MSBuild -property installationPath
151 | }
152 |
153 | if ($installationPath) {
154 | $need64Bit = $False
155 | switch ($Platform)
156 | {
157 | Current { $need64Bit = [System.Environment]::Is64BitProcess }
158 | x64 { $need64Bit = $true }
159 | x86 { $need64Bit = $false }
160 | }
161 |
162 | $likePattern = if ($need64Bit) { '*bin\amd64\msbuild.exe' } else { '*bin\msbuild.exe' }
163 | $msbuild = (Get-ChildItem -Path $installationPath -Filter "MSBuild.exe" -Recurse) | Where-Object { $_.FullName -like $likePattern }
164 |
165 | if (Test-Path $msbuild.DirectoryName) {
166 | return $msbuild.DirectoryName
167 | }
168 | }
169 | }
170 |
171 | # If none of the upper branches returned a version we try the legacy path
172 | return Get-MSBuildPathLegacy -Version $version -Platform $Platform
173 | }
174 |
175 | function Get-MSBuild()
176 | {
177 | [CmdletBinding()]
178 | Param(
179 | [Parameter(Mandatory=$False,Position=1)]
180 | [String]$VersionString = $null,
181 | [Parameter(Mandatory=$False)]
182 | [Platform]$Platform = [Platform]::Current
183 | )
184 |
185 | $msbuildPath = Get-MSBuildPath -VersionString $VersionString -Platform $Platform
186 |
187 | if ($null -eq $msbuildPath)
188 | {
189 | Write-Error "MSBuild could not be found"
190 | return
191 | }
192 |
193 | $msbuild = Join-Path $msbuildPath "msbuild.exe"
194 |
195 | Write-Host "Using msbuild from '$msbuild'"
196 |
197 | return $msbuild
198 | }
199 |
200 | #Get-MSBuildVersion -All
201 | #Get-MSBuildPath MSBuildToolsPath -Verbose
202 | #Get-MSBuildPath MSBuildToolsRoot -Verbose
203 |
204 | #Get-MSBuildPath MSBuildToolsPath -Platform x86 -Verbose
205 | #Get-MSBuildPath MSBuildToolsPath -Platform x64 -Verbose
206 | #Get-MSBuild
207 | #Get-MSBuild 1 -ErrorAction Continue
208 | #Get-MSBuild 2
209 | #Get-MSBuild 3
210 | #Get-MSBuild 3.5
211 | #Get-MSBuild 12
212 | #Get-MSBuild 14
213 | #Get-MSBuild "14.0" -Platform x86 -Verbose
214 | #Get-MSBuild -Version 15.0
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Deprecation notice
2 |
3 | This project has been deprecated and superseeded by [XAMLTools](https://github.com/batzen/XAMLTools).
4 |
5 | XamlCombine
6 | ===========
7 | [](https://ci.appveyor.com/project/batzen/xamlcombine)
8 | [](https://github.com/fluentribbon/XamlCombine/releases/latest)
9 | [](https://github.com/fluentribbon/XamlCombine/issues)
10 |
14 | [](https://github.com/fluentribbon/XamlCombine/blob/master/License.txt)
15 |
16 | The original code was writting by [SableRaven](https://www.codeplex.com/site/users/view/SableRaven) and was copied from [xamlcombine.codeplex.com](https://xamlcombine.codeplex.com/).
17 |
18 | Description
19 | ===========
20 | Combines multiple XAML resource dictionaries into one and sort them in order of usage.
21 |
22 | Usage
23 | ===========
24 | XamlCombine.exe list-of-xamls.txt result-xaml.xaml
25 |
26 | Where:
27 | - list-of-xamls.txt - text file which contains list of XAML filenames,
28 | - result-xaml.xaml - filename of result XAML file.
29 |
--------------------------------------------------------------------------------
/XamlCombine.msbuild:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)
5 | Release
6 | $(Root)/Publish
7 | $(appveyor_build_version)
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | -dev$(Prerelease)
30 | $([System.String]::new(%(XamlCombineAssembly.Version)).TrimEnd('0').TrimEnd('.'))$(PrereleaseSuffix)
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/XamlCombine.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | XamlCombine
5 | $Version$
6 | XamlCombine
7 | Generates a single large xaml file from many smaller xaml files.
8 | Generates a single large xaml file from many smaller xaml files.
9 |
10 | 1.0.1:
11 | - Improving protection against issues caused by concurrent invocation of tool
12 | - Fixing file access exceptions during concurrent invocation of tool
13 |
14 | 1.0.0:
15 | - Initial release
16 |
17 | batzen
18 | https://raw.githubusercontent.com/Fluent.Ribbon/XamlCombine/master/LICENSE
19 | https://github.com/Fluent.Ribbon/XamlCombine
20 | false
21 | xaml combine generator
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/XamlCombine.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2024
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamlCombine", "src\XamlCombine.csproj", "{D33D75C4-AA91-4253-8CC0-00971EBF3D5B}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A8D862CD-8367-4523-8920-2576C08F34A1}"
9 | ProjectSection(SolutionItems) = preProject
10 | appveyor.yml = appveyor.yml
11 | pack.ps1 = pack.ps1
12 | README.md = README.md
13 | XamlCombine.nuspec = XamlCombine.nuspec
14 | EndProjectSection
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {D33D75C4-AA91-4253-8CC0-00971EBF3D5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {D33D75C4-AA91-4253-8CC0-00971EBF3D5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {D33D75C4-AA91-4253-8CC0-00971EBF3D5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {D33D75C4-AA91-4253-8CC0-00971EBF3D5B}.Release|Any CPU.Build.0 = Release|Any CPU
26 | EndGlobalSection
27 | GlobalSection(SolutionProperties) = preSolution
28 | HideSolutionNode = FALSE
29 | EndGlobalSection
30 | GlobalSection(ExtensibilityGlobals) = postSolution
31 | SolutionGuid = {7B1D5F2A-571F-430A-8640-15E52AA1553F}
32 | EndGlobalSection
33 | EndGlobal
34 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # http://www.appveyor.com/docs/appveyor-yml
2 |
3 | version: 1.0.1.{build}
4 | configuration: Release
5 | image: Visual Studio 2017
6 |
7 | build_script:
8 | - powershell ./build.ps1 -Target CI
9 |
10 | assembly_info:
11 | patch: true
12 | file: AssemblyInfo.*
13 | assembly_version: "{version}"
14 | assembly_file_version: "{version}"
15 | assembly_informational_version: "{version}"
16 |
17 | artifacts:
18 | - path: Publish\**\*.nupkg
19 | name: NuGet
20 |
21 | - path: Publish\**\*.zip
22 | name: zip
--------------------------------------------------------------------------------
/paket.dependencies:
--------------------------------------------------------------------------------
1 | source https://www.nuget.org/api/v2/
2 |
3 | framework net452
4 | specific_version: false
5 |
6 | nuget 7-Zip.Commandline
7 | nuget gitlink 2.4.0
8 | nuget NuGet.CommandLine
--------------------------------------------------------------------------------
/paket.lock:
--------------------------------------------------------------------------------
1 | SPECIFIC-VERSION: FALSE
2 | RESTRICTION: == net452
3 | NUGET
4 | remote: https://www.nuget.org/api/v2
5 | 7-Zip.CommandLine (16.4)
6 | gitlink (2.4)
7 | NuGet.CommandLine (4.4.1)
8 |
--------------------------------------------------------------------------------
/src/Combiner.cs:
--------------------------------------------------------------------------------
1 | namespace XamlCombine
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Globalization;
7 | using System.IO;
8 | using System.Reflection;
9 | using System.Xml;
10 |
11 | public class Combiner
12 | {
13 | ///
14 | /// Dynamic resource string.
15 | ///
16 | private const string DynamicResourceString = "{DynamicResource ";
17 |
18 | ///
19 | /// Static resource string.
20 | ///
21 | private const string StaticResourceString = "{StaticResource ";
22 |
23 | private Lazy appPath;
24 |
25 | public Combiner()
26 | {
27 | this.appPath = new Lazy(this.GetAppPath);
28 | }
29 |
30 | ///
31 | /// Combines multiple XAML resource dictionaries in one.
32 | ///
33 | /// Filename of list of XAML's.
34 | /// Result XAML filename.
35 | public void Combine(string sourceFile, string resultFile)
36 | {
37 | Trace.WriteLine(string.Format("Loading resources list from \"{0}\"", sourceFile));
38 |
39 | sourceFile = this.GetFilePath(sourceFile);
40 |
41 | // Load resources lists
42 | var resources = File.ReadAllLines(sourceFile);
43 |
44 | // Create result XML document
45 | var finalDocument = new XmlDocument();
46 | var rootNode = finalDocument.CreateElement("ResourceDictionary", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
47 | finalDocument.AppendChild(rootNode);
48 |
49 | // List of existing keys, to avoid duplicates
50 | var keys = new List();
51 |
52 | // Associate key with ResourceElement
53 | var resourceElements = new Dictionary();
54 |
55 | // List of read resources
56 | var resourcesList = new List();
57 |
58 | // For each resource file
59 | for (var i = 0; i < resources.Length; i++)
60 | {
61 | var current = new XmlDocument();
62 | current.Load(this.GetFilePath(resources[i]));
63 |
64 | Debug.WriteLine(string.Format("Loading resource \"{0}\"", resources[i]));
65 |
66 | // Set and fix resource dictionary attributes
67 | var root = current.DocumentElement;
68 | if (root == null)
69 | {
70 | continue;
71 | }
72 |
73 | for (var j = 0; j < root.Attributes.Count; j++)
74 | {
75 | XmlAttribute attr = root.Attributes[j];
76 | if (rootNode.HasAttribute(attr.Name))
77 | {
78 | // If namespace with this name exists and not equal
79 | if (attr.Value != rootNode.Attributes[attr.Name].Value
80 | && attr.Prefix == "xmlns")
81 | {
82 | // Create new namespace name
83 | var index = 0;
84 | string name;
85 | do
86 | {
87 | name = attr.LocalName + "_" + index.ToString(CultureInfo.InvariantCulture);
88 | }
89 | while (rootNode.HasAttribute("xmlns:" + name));
90 |
91 | root.SetAttribute("xmlns:" + name, attr.Value);
92 |
93 | // Change namespace prefixes in resource dictionary
94 | ChangeNamespacePrefix(root, attr.LocalName, name);
95 |
96 | // Add renamed namespace
97 | XmlAttribute a = finalDocument.CreateAttribute("xmlns", name, attr.NamespaceURI);
98 | a.Value = attr.Value;
99 | rootNode.Attributes.Append(a);
100 | }
101 | }
102 | else
103 | {
104 | var exists = false;
105 | if (attr.Prefix == "xmlns")
106 | {
107 | // Try to find equal namespace with different name
108 | foreach (XmlAttribute attribute in rootNode.Attributes)
109 | {
110 | if (attr.Value == attribute.Value)
111 | {
112 | root.SetAttribute(attr.Name, attr.Value);
113 | ChangeNamespacePrefix(root, attr.LocalName, attribute.LocalName);
114 | exists = true;
115 | break;
116 | }
117 | }
118 | }
119 |
120 | if (exists == false)
121 | {
122 | // Add namespace to result resource dictionarty
123 | XmlAttribute a = finalDocument.CreateAttribute(attr.Prefix, attr.LocalName, attr.NamespaceURI);
124 | a.Value = attr.Value;
125 | rootNode.Attributes.Append(a);
126 | }
127 | }
128 | }
129 |
130 | // Extract resources
131 | foreach (XmlNode node in root.ChildNodes)
132 | {
133 | if (node is XmlElement
134 | && node.Name != "ResourceDictionary.MergedDictionaries")
135 | {
136 | // Import XML node from one XML document to result XML document
137 | XmlElement importedElement = finalDocument.ImportNode(node, true) as XmlElement;
138 |
139 | // Find resource key
140 | // TODO: Is any other variants???
141 | var key = string.Empty;
142 | if (importedElement.HasAttribute("Key"))
143 | {
144 | key = importedElement.Attributes["Key"].Value;
145 | }
146 | else if (importedElement.HasAttribute("x:Key"))
147 | {
148 | key = importedElement.Attributes["x:Key"].Value;
149 | }
150 | else if (importedElement.HasAttribute("TargetType"))
151 | {
152 | key = importedElement.Attributes["TargetType"].Value;
153 | }
154 |
155 | if (string.IsNullOrEmpty(key) == false)
156 | {
157 | // Check key unique
158 | if (keys.Contains(key))
159 | {
160 | continue;
161 | }
162 |
163 | keys.Add(key);
164 |
165 | // Create ResourceElement for key and XML node
166 | var res = new ResourceElement(key, importedElement, FillKeys(importedElement));
167 | resourceElements.Add(key, res);
168 | resourcesList.Add(res);
169 | }
170 | }
171 |
172 | // TODO: Add output information.
173 | }
174 | }
175 |
176 | // Result list
177 | var finalOrderList = new List();
178 |
179 | // Add all items with empty UsedKeys
180 | for (var i = 0; i < resourcesList.Count; i++)
181 | {
182 | if (resourcesList[i].UsedKeys.Length == 0)
183 | {
184 | finalOrderList.Add(resourcesList[i]);
185 |
186 | Debug.WriteLine(string.Format("Adding resource \"{0}\"", resourcesList[i].Key));
187 |
188 | resourcesList.RemoveAt(i);
189 | i--;
190 | }
191 | }
192 |
193 | // Add other resources in correct order
194 | while (resourcesList.Count > 0)
195 | {
196 | for (var i = 0; i < resourcesList.Count; i++)
197 | {
198 | // Check used keys is in result list
199 | var containsAll = true;
200 | for (var j = 0; j < resourcesList[i].UsedKeys.Length; j++)
201 | {
202 | if (resourceElements.ContainsKey(resourcesList[i].UsedKeys[j])
203 | && finalOrderList.Contains(resourceElements[resourcesList[i].UsedKeys[j]]) == false)
204 | {
205 | containsAll = false;
206 | break;
207 | }
208 | }
209 |
210 | // If all used keys is in result list ad this resource to result list
211 | if (containsAll)
212 | {
213 | finalOrderList.Add(resourcesList[i]);
214 |
215 | Debug.WriteLine(string.Format("Adding resource \"{0}\"", resourcesList[i].Key));
216 |
217 | resourcesList.RemoveAt(i);
218 | i--;
219 | }
220 | }
221 |
222 | // TODO: Limit iterations count.
223 | }
224 |
225 | // Add nodes to XML document
226 | for (var i = 0; i < finalOrderList.Count; i++)
227 | {
228 | rootNode.AppendChild(finalOrderList[i].Element);
229 | }
230 |
231 | // Save result file
232 | WriteResultFile(Path.Combine(appPath.Value, resultFile), finalDocument);
233 | }
234 |
235 | private string GetAppPath()
236 | {
237 | // Current application path
238 | // TODO: Need to support all types of paths not only relative.
239 | var appPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
240 |
241 | return appPath;
242 | }
243 |
244 | private string GetFilePath(string file)
245 | {
246 | var filePath = file;
247 |
248 | if (File.Exists(filePath) == false)
249 | {
250 | filePath = Path.Combine(appPath.Value, filePath);
251 |
252 | if (File.Exists(filePath) == false)
253 | {
254 | throw new FileNotFoundException("Unable to find file.", file);
255 | }
256 | }
257 |
258 | return filePath;
259 | }
260 |
261 | ///
262 | /// Changes namespace prefix for XML node.
263 | ///
264 | /// XML node.
265 | /// Old namespace prefix.
266 | /// New namespace prefix.
267 | private static void ChangeNamespacePrefix(XmlElement element, string oldPrefix, string newPrefix)
268 | {
269 | // String for search
270 | var oldString = oldPrefix + ":";
271 | var newString = newPrefix + ":";
272 | var oldStringSpaced = " " + oldString;
273 | var newStringSpaced = " " + newString;
274 |
275 | foreach (XmlNode child in element.ChildNodes)
276 | {
277 | var childElement = child as XmlElement;
278 |
279 | if (childElement != null)
280 | {
281 | if (child.Prefix == oldPrefix)
282 | {
283 | child.Prefix = newPrefix;
284 | }
285 |
286 | foreach (XmlAttribute attr in childElement.Attributes)
287 | {
288 | // Check all attributes prefix
289 | if (attr.Prefix == oldPrefix) attr.Prefix = newPrefix;
290 |
291 | // Check {x:Type {x:Static in attributes values
292 | // TODO: Is any other???
293 | if ((attr.Value.Contains("{x:Type") || attr.Value.Contains("{x:Static"))
294 | && attr.Value.Contains(oldStringSpaced))
295 | {
296 | attr.Value = attr.Value.Replace(oldStringSpaced, newStringSpaced);
297 | }
298 |
299 | // Check Property attribute
300 | // TODO: Is any other???
301 | if (attr.Name == "Property"
302 | && attr.Value.StartsWith(oldString))
303 | {
304 | attr.Value = attr.Value.Replace(oldString, newString);
305 | }
306 | }
307 |
308 | // Change namespaces for child node
309 | ChangeNamespacePrefix(childElement, oldPrefix, newPrefix);
310 | }
311 | }
312 | }
313 |
314 | ///
315 | /// Find all used keys for resource.
316 | ///
317 | /// Xml element which contains resource.
318 | /// Array of keys used by resource.
319 | private static string[] FillKeys(XmlElement element)
320 | {
321 | // Result list
322 | var result = new List();
323 |
324 | // Check all attributes
325 | foreach (XmlAttribute attr in element.Attributes)
326 | {
327 | if (attr.Value.StartsWith(DynamicResourceString))
328 | {
329 | // Find key
330 | var key = attr.Value.Substring(DynamicResourceString.Length, attr.Value.Length - DynamicResourceString.Length - 1).Trim();
331 |
332 | // Add key to result
333 | if (result.Contains(key) == false)
334 | {
335 | result.Add(key);
336 | }
337 | }
338 | else if (attr.Value.StartsWith(StaticResourceString))
339 | {
340 | // Find key
341 | var key = attr.Value.Substring(StaticResourceString.Length, attr.Value.Length - StaticResourceString.Length - 1).Trim();
342 |
343 | // Add key to result
344 | if (result.Contains(key) == false)
345 | {
346 | result.Add(key);
347 | }
348 | }
349 | }
350 |
351 | // Check child nodes
352 | foreach (XmlNode node in element.ChildNodes)
353 | {
354 | var nodeElement = node as XmlElement;
355 | if (nodeElement != null)
356 | {
357 | result.AddRange(FillKeys(nodeElement));
358 | }
359 | }
360 |
361 | return result.ToArray();
362 | }
363 |
364 | private static void WriteResultFile(string resultFile, XmlDocument finalDocument)
365 | {
366 | try
367 | {
368 | var tempFile = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.tmp");
369 | finalDocument.Save(tempFile);
370 |
371 | Trace.WriteLine(string.Format("Comparing temp file \"{0}\" to \"{1}\"", tempFile, resultFile));
372 |
373 | if (File.Exists(resultFile) == false
374 | || File.ReadAllText(resultFile) != File.ReadAllText(tempFile))
375 | {
376 | File.Copy(tempFile, resultFile, true);
377 |
378 | Trace.WriteLine(string.Format("Resource Dictionary saved to \"{0}\".", resultFile));
379 | }
380 | else
381 | {
382 | Trace.WriteLine("New Resource Dictionary did not differ from existing file. No new file written.");
383 | }
384 |
385 | if (File.Exists(tempFile))
386 | {
387 | File.Delete(tempFile);
388 | }
389 | }
390 | catch (Exception e)
391 | {
392 | throw new Exception("Error during Resource Dictionary saving: {0}", e);
393 | }
394 | }
395 | }
396 | }
--------------------------------------------------------------------------------
/src/Program.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Rikker Serg 2012 All Right Reserved
3 | //
4 | // Rikker Serg
5 | // serg@rikker.ru
6 | // Simple console app to combine multiple XAML resource dictionaries in one.
7 | namespace XamlCombine
8 | {
9 | using System;
10 | using System.Diagnostics;
11 | using System.Reflection;
12 | using System.Runtime.InteropServices;
13 | using System.Security.Cryptography;
14 | using System.Text;
15 | using System.Threading;
16 |
17 | ///
18 | /// Represents simple console app to combine multiple XAML resource dictionaries in one.
19 | /// Command line syntaxis:
20 | /// XamlCombine.exe [list-of-xamls.txt] [result-xaml.xaml]
21 | /// All paths must be relative to XamlCombine.exe location.
22 | ///
23 | internal class Program
24 | {
25 | ///
26 | /// Main function.
27 | ///
28 | /// Command line args.
29 | private static int Main(string[] args)
30 | {
31 | try
32 | {
33 | var stopwatch = Stopwatch.StartNew();
34 |
35 | // TODO: Add flags for some parameters.
36 | if (args.Length == 2)
37 | {
38 | var sourceFile = args[0];
39 | var resultFile = args[1];
40 |
41 | using (var mutex = Lock(resultFile))
42 | {
43 | try
44 | {
45 | var combiner = new Combiner();
46 | combiner.Combine(sourceFile, resultFile);
47 | }
48 | finally
49 | {
50 | mutex.ReleaseMutex();
51 | }
52 | }
53 | }
54 |
55 | // TODO: Add help output.
56 |
57 | stopwatch.Stop();
58 | Trace.WriteLine(string.Format("Combine time: {0}", stopwatch.Elapsed));
59 |
60 | if (Debugger.IsAttached)
61 | {
62 | Console.ReadLine();
63 | }
64 |
65 | return 0;
66 | }
67 | catch (Exception e)
68 | {
69 | Trace.WriteLine(e);
70 | Console.WriteLine(e);
71 | return 1;
72 | }
73 | }
74 |
75 | private static Mutex Lock(string file)
76 | {
77 | var appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value;
78 | var mutexName = $"Local\\{appGuid}_{GetMD5Hash(file)}";
79 |
80 | var mutex = new Mutex(false, mutexName);
81 |
82 | if (mutex.WaitOne(TimeSpan.FromSeconds(10)) == false)
83 | {
84 | throw new TimeoutException("Another instance of this application blocked the concurrent execution.");
85 | }
86 |
87 | return mutex;
88 | }
89 |
90 | private static string GetMD5Hash(string textToHash)
91 | {
92 | if (string.IsNullOrEmpty(textToHash))
93 | {
94 | return string.Empty;
95 | }
96 |
97 | var md5 = new MD5CryptoServiceProvider();
98 | var bytesToHash = Encoding.Default.GetBytes(textToHash);
99 | var result = md5.ComputeHash(bytesToHash);
100 |
101 | return BitConverter.ToString(result);
102 | }
103 | }
104 | }
--------------------------------------------------------------------------------
/src/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Rikker Serg 2012 All Right Reserved
3 | //
4 | // Rikker Serg
5 | // serg@rikker.ru
6 | // Assembly information.
7 |
8 | using System;
9 | using System.Reflection;
10 | using System.Runtime.InteropServices;
11 |
12 | #if DEBUG
13 | [assembly: AssemblyConfiguration("Debug")]
14 | #else
15 | [assembly: AssemblyConfiguration("Release")]
16 | #endif
17 |
18 | [assembly: AssemblyTitle("XamlCombine")]
19 | [assembly: AssemblyDescription("Combines multiple XAML resource dictionarion in one.")]
20 | [assembly: AssemblyCompany("https://github.com/fluentribbon/XamlCombine")]
21 | [assembly: AssemblyProduct("XamlCombine")]
22 | [assembly: AssemblyCopyright("Copyright © 2012 - 2018 Bastian Schmidt; Copyright © Rikker Serg 2012")]
23 | [assembly: AssemblyTrademark("")]
24 | [assembly: AssemblyCulture("")]
25 |
26 | [assembly: AssemblyVersion("1.0.1")]
27 | [assembly: AssemblyFileVersion("1.0.1")]
28 | [assembly: AssemblyInformationalVersion("SRC")]
29 |
30 | [assembly: ComVisible(false)]
31 | [assembly: CLSCompliant(true)]
32 |
33 | [assembly: Guid("4d91ca8f-f2d4-4ed9-81a5-c75e9f04958f")]
--------------------------------------------------------------------------------
/src/ResourceElement.cs:
--------------------------------------------------------------------------------
1 | namespace XamlCombine
2 | {
3 | using System.Xml;
4 |
5 | ///
6 | /// Represents XAML resource.
7 | ///
8 | public struct ResourceElement
9 | {
10 | public ResourceElement(string key, XmlElement element, string[] usedKeys)
11 | : this()
12 | {
13 | this.Key = key;
14 | this.Element = element;
15 | this.UsedKeys = usedKeys;
16 | }
17 |
18 | ///
19 | /// Resource name.
20 | ///
21 | public string Key { get; private set; }
22 |
23 | ///
24 | /// Resource XML node.
25 | ///
26 | public XmlElement Element { get; private set; }
27 |
28 | ///
29 | /// XAML keys used in this resource.
30 | ///
31 | public string[] UsedKeys { get; private set; }
32 | }
33 | }
--------------------------------------------------------------------------------
/src/XamlCombine.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D33D75C4-AA91-4253-8CC0-00971EBF3D5B}
8 | Exe
9 | Properties
10 | XamlCombine
11 | XamlCombine
12 | v4.5.2
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | ..\bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | true
25 | MinimumRecommendedRules.ruleset
26 |
27 |
28 | AnyCPU
29 | pdbonly
30 | true
31 | ..\bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 | true
36 | MinimumRecommendedRules.ruleset
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------