├── .gitattributes ├── .gitignore ├── CSProjToXProj.sln ├── LICENSE.txt ├── README.md ├── build.cake ├── build.cmd ├── build.ps1 └── src ├── CSProjToXProj ├── CSProjToXProj.xproj ├── Plumbing │ ├── EnumerableExtensions.cs │ └── FileSystem.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── SolutionAdjuster.cs ├── SourceFiles │ ├── FileReader.cs │ ├── PackageEntry.cs │ └── ProjectMetadata.cs ├── Writer.cs └── project.json └── Tests ├── FileReaderTests.cs ├── Plumbing ├── FakeFileSystem.cs └── StringExtensions.cs ├── Properties └── AssemblyInfo.cs ├── SolutionAdjusterTests.cs ├── Tests.xproj ├── WriterTests.cs └── project.json /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #ignore thumbnails created by windows 3 | Thumbs.db 4 | #Ignore files build by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | .vs 31 | *.ipr 32 | *.iws 33 | .idea/ 34 | node_modules/ 35 | bower_components/ 36 | packages/ 37 | *.received.* 38 | Publish/ 39 | project.lock.json 40 | /tools/ 41 | /artifacts/ -------------------------------------------------------------------------------- /CSProjToXProj.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7B75C713-EA67-479A-80E7-9150DB5BF60C}" 7 | EndProject 8 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CSProjToXProj", "src\CSProjToXProj\CSProjToXProj.xproj", "{84AA132C-5097-4F1B-9161-6B91D06ADB9C}" 9 | EndProject 10 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Tests", "src\Tests\Tests.xproj", "{F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{58E98EEF-4516-4C66-BA97-68172E3482A6}" 13 | ProjectSection(SolutionItems) = preProject 14 | build.cake = build.cake 15 | build.cmd = build.cmd 16 | build.ps1 = build.ps1 17 | EndProjectSection 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Release|Any CPU.Build.0 = Release|Any CPU 33 | EndGlobalSection 34 | GlobalSection(SolutionProperties) = preSolution 35 | HideSolutionNode = FALSE 36 | EndGlobalSection 37 | GlobalSection(NestedProjects) = preSolution 38 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C} = {7B75C713-EA67-479A-80E7-9150DB5BF60C} 39 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C} = {7B75C713-EA67-479A-80E7-9150DB5BF60C} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Octopus Deploy and contributors. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | these files except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/9lvn8n52yq4oc663/branch/master?svg=true)](https://ci.appveyor.com/project/OctopusDeploy/csprojtoxproj/branch/master) 2 | 3 | # CSProjToXProj 4 | Converts .csproj files (and packages.config) to .xproj and project.json and optionally updates the solution. 5 | 6 | Usage: 7 | `CSProjToXProj [/ReplaceExisting] [/Force]` 8 | 9 | If `/ReplaceExisting` is specified: 10 | - The project GUID is retained 11 | - The sln file is updated 12 | - The `csproj` and `package.config` files are deleted 13 | 14 | Omit this flag if you are intending to have side by side csproj and xproj project file. You will need to rename either the csproj or xproj and then add the xproj to the solution. 15 | 16 | `/Force` overwrites existing xproj files 17 | -------------------------------------------------------------------------------- /build.cake: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // TOOLS 3 | ////////////////////////////////////////////////////////////////////// 4 | #tool "nuget:?package=GitVersion.CommandLine" 5 | #addin "MagicChunks" 6 | 7 | ////////////////////////////////////////////////////////////////////// 8 | // ARGUMENTS 9 | ////////////////////////////////////////////////////////////////////// 10 | var target = Argument("target", "Default"); 11 | var configuration = Argument("configuration", "Release"); 12 | 13 | /////////////////////////////////////////////////////////////////////////////// 14 | // GLOBAL VARIABLES 15 | /////////////////////////////////////////////////////////////////////////////// 16 | var artifactsDir = "./artifacts"; 17 | var globalAssemblyFile = "./src/GlobalAssemblyInfo.cs"; 18 | var projectToPackage = "./src/CSProjToXProj"; 19 | var directoryToZip = $"{projectToPackage}/bin/{configuration}/netcoreapp1.0/win7-x64"; 20 | 21 | var isContinuousIntegrationBuild = !BuildSystem.IsLocalBuild; 22 | 23 | var gitVersionInfo = GitVersion(new GitVersionSettings { 24 | OutputType = GitVersionOutput.Json 25 | }); 26 | 27 | var nugetVersion = isContinuousIntegrationBuild ? gitVersionInfo.NuGetVersion : "0.0.0"; 28 | 29 | /////////////////////////////////////////////////////////////////////////////// 30 | // SETUP / TEARDOWN 31 | /////////////////////////////////////////////////////////////////////////////// 32 | Setup(context => 33 | { 34 | Information("Building DotNetCoreBuild v{0}", nugetVersion); 35 | }); 36 | 37 | Teardown(context => 38 | { 39 | Information("Finished running tasks."); 40 | }); 41 | 42 | ////////////////////////////////////////////////////////////////////// 43 | // PRIVATE TASKS 44 | ////////////////////////////////////////////////////////////////////// 45 | 46 | Task("__Default") 47 | .IsDependentOn("__Clean") 48 | .IsDependentOn("__Restore") 49 | .IsDependentOn("__UpdateAssemblyVersionInformation") 50 | .IsDependentOn("__Build") 51 | .IsDependentOn("__Test") 52 | .IsDependentOn("__UpdateProjectJsonVersion") 53 | .IsDependentOn("__Zip"); 54 | 55 | Task("__Clean") 56 | .Does(() => 57 | { 58 | CleanDirectory(artifactsDir); 59 | CleanDirectories("./src/**/bin"); 60 | CleanDirectories("./src/**/obj"); 61 | }); 62 | 63 | Task("__Restore") 64 | .Does(() => DotNetCoreRestore()); 65 | 66 | Task("__UpdateAssemblyVersionInformation") 67 | .WithCriteria(isContinuousIntegrationBuild) 68 | .Does(() => 69 | { 70 | GitVersion(new GitVersionSettings { 71 | UpdateAssemblyInfo = true, 72 | UpdateAssemblyInfoFilePath = globalAssemblyFile 73 | }); 74 | 75 | Information("AssemblyVersion -> {0}", gitVersionInfo.AssemblySemVer); 76 | Information("AssemblyFileVersion -> {0}", $"{gitVersionInfo.MajorMinorPatch}.0"); 77 | Information("AssemblyInformationalVersion -> {0}", gitVersionInfo.InformationalVersion); 78 | }); 79 | 80 | Task("__Build") 81 | .Does(() => 82 | { 83 | DotNetCoreBuild("**/project.json", new DotNetCoreBuildSettings 84 | { 85 | Configuration = configuration 86 | }); 87 | }); 88 | 89 | Task("__Test") 90 | .Does(() => 91 | { 92 | GetFiles("**/*Tests/project.json") 93 | .ToList() 94 | .ForEach(testProjectFile => 95 | { 96 | DotNetCoreTest(testProjectFile.ToString(), new DotNetCoreTestSettings 97 | { 98 | Configuration = configuration 99 | }); 100 | }); 101 | }); 102 | 103 | Task("__UpdateProjectJsonVersion") 104 | .WithCriteria(isContinuousIntegrationBuild) 105 | .Does(() => 106 | { 107 | var projectToPackagePackageJson = $"{projectToPackage}/project.json"; 108 | Information("Updating {0} version -> {1}", projectToPackagePackageJson, nugetVersion); 109 | 110 | TransformConfig(projectToPackagePackageJson, projectToPackagePackageJson, new TransformationCollection { 111 | { "version", nugetVersion } 112 | }); 113 | }); 114 | 115 | 116 | Task("__Zip") 117 | .Does(() => 118 | { 119 | Zip(directoryToZip, $"{artifactsDir}/CSProjToXProj.zip", $"{directoryToZip}/**/*"); 120 | }); 121 | 122 | ////////////////////////////////////////////////////////////////////// 123 | // TASKS 124 | ////////////////////////////////////////////////////////////////////// 125 | Task("Default") 126 | .IsDependentOn("__Default"); 127 | 128 | ////////////////////////////////////////////////////////////////////// 129 | // EXECUTION 130 | ////////////////////////////////////////////////////////////////////// 131 | RunTarget(target); -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | REM see http://joshua.poehls.me/powershell-batch-file-wrapper/ 3 | 4 | SET SCRIPTNAME=%~d0%~p0%~n0.ps1 5 | SET ARGS=%* 6 | IF [%ARGS%] NEQ [] GOTO ESCAPE_ARGS 7 | 8 | :POWERSHELL 9 | PowerShell.exe -NoProfile -NonInteractive -NoLogo -ExecutionPolicy Unrestricted -Command "& { $ErrorActionPreference = 'Stop'; & '%SCRIPTNAME%' @args; EXIT $LASTEXITCODE }" %ARGS% 10 | EXIT /B %ERRORLEVEL% 11 | 12 | :ESCAPE_ARGS 13 | SET ARGS=%ARGS:"=\"% 14 | SET ARGS=%ARGS:`=``% 15 | SET ARGS=%ARGS:'=`'% 16 | SET ARGS=%ARGS:$=`$% 17 | SET ARGS=%ARGS:{=`}% 18 | SET ARGS=%ARGS:}=`}% 19 | SET ARGS=%ARGS:(=`(% 20 | SET ARGS=%ARGS:)=`)% 21 | SET ARGS=%ARGS:,=`,% 22 | SET ARGS=%ARGS:^%=% 23 | 24 | GOTO POWERSHELL -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | ########################################################################## 2 | # This is the Cake bootstrapper script for PowerShell. 3 | # This file was downloaded from https://github.com/cake-build/resources 4 | # Feel free to change this file to fit your needs. 5 | ########################################################################## 6 | 7 | <# 8 | 9 | .SYNOPSIS 10 | This is a Powershell script to bootstrap a Cake build. 11 | 12 | .DESCRIPTION 13 | This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) 14 | and execute your Cake build script with the parameters you provide. 15 | 16 | .PARAMETER Script 17 | The build script to execute. 18 | .PARAMETER Target 19 | The build script target to run. 20 | .PARAMETER Configuration 21 | The build configuration to use. 22 | .PARAMETER Verbosity 23 | Specifies the amount of information to be displayed. 24 | .PARAMETER Experimental 25 | Tells Cake to use the latest Roslyn release. 26 | .PARAMETER WhatIf 27 | Performs a dry run of the build script. 28 | No tasks will be executed. 29 | .PARAMETER Mono 30 | Tells Cake to use the Mono scripting engine. 31 | .PARAMETER SkipToolPackageRestore 32 | Skips restoring of packages. 33 | .PARAMETER ScriptArgs 34 | Remaining arguments are added here. 35 | 36 | .LINK 37 | http://cakebuild.net 38 | 39 | #> 40 | 41 | [CmdletBinding()] 42 | Param( 43 | [string]$Script = "build.cake", 44 | [string]$Target = "Default", 45 | [ValidateSet("Release", "Debug")] 46 | [string]$Configuration = "Release", 47 | [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] 48 | [string]$Verbosity = "Verbose", 49 | [switch]$Experimental = $true, 50 | [Alias("DryRun","Noop")] 51 | [switch]$WhatIf, 52 | [switch]$Mono, 53 | [switch]$SkipToolPackageRestore, 54 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] 55 | [string[]]$ScriptArgs 56 | ) 57 | 58 | [Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null 59 | function MD5HashFile([string] $filePath) 60 | { 61 | if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) 62 | { 63 | return $null 64 | } 65 | 66 | [System.IO.Stream] $file = $null; 67 | [System.Security.Cryptography.MD5] $md5 = $null; 68 | try 69 | { 70 | $md5 = [System.Security.Cryptography.MD5]::Create() 71 | $file = [System.IO.File]::OpenRead($filePath) 72 | return [System.BitConverter]::ToString($md5.ComputeHash($file)) 73 | } 74 | finally 75 | { 76 | if ($file -ne $null) 77 | { 78 | $file.Dispose() 79 | } 80 | } 81 | } 82 | 83 | Write-Host "Preparing to run build script..." 84 | 85 | if(!$PSScriptRoot){ 86 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent 87 | } 88 | 89 | $TOOLS_DIR = Join-Path $PSScriptRoot "tools" 90 | $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" 91 | $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" 92 | $NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" 93 | $PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" 94 | $PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" 95 | 96 | # Should we use mono? 97 | $UseMono = ""; 98 | if($Mono.IsPresent) { 99 | Write-Verbose -Message "Using the Mono based scripting engine." 100 | $UseMono = "-mono" 101 | } 102 | 103 | # Should we use the new Roslyn? 104 | $UseExperimental = ""; 105 | if($Experimental.IsPresent -and !($Mono.IsPresent)) { 106 | Write-Verbose -Message "Using experimental version of Roslyn." 107 | $UseExperimental = "-experimental" 108 | } 109 | 110 | # Is this a dry run? 111 | $UseDryRun = ""; 112 | if($WhatIf.IsPresent) { 113 | $UseDryRun = "-dryrun" 114 | } 115 | 116 | # Make sure tools folder exists 117 | if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { 118 | Write-Verbose -Message "Creating tools directory..." 119 | New-Item -Path $TOOLS_DIR -Type directory | out-null 120 | } 121 | 122 | # Make sure that packages.config exist. 123 | if (!(Test-Path $PACKAGES_CONFIG)) { 124 | Write-Verbose -Message "Downloading packages.config..." 125 | try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { 126 | Throw "Could not download packages.config." 127 | } 128 | } 129 | 130 | # Try find NuGet.exe in path if not exists 131 | if (!(Test-Path $NUGET_EXE)) { 132 | Write-Verbose -Message "Trying to find nuget.exe in PATH..." 133 | $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } 134 | $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 135 | if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { 136 | Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." 137 | $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName 138 | } 139 | } 140 | 141 | # Try download NuGet.exe if not exists 142 | if (!(Test-Path $NUGET_EXE)) { 143 | Write-Verbose -Message "Downloading NuGet.exe..." 144 | try { 145 | (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) 146 | } catch { 147 | Throw "Could not download NuGet.exe." 148 | } 149 | } 150 | 151 | # Save nuget.exe path to environment to be available to child processed 152 | $ENV:NUGET_EXE = $NUGET_EXE 153 | 154 | # Restore tools from NuGet? 155 | if(-Not $SkipToolPackageRestore.IsPresent) { 156 | Push-Location 157 | Set-Location $TOOLS_DIR 158 | 159 | # Check for changes in packages.config and remove installed tools if true. 160 | [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) 161 | if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or 162 | ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { 163 | Write-Verbose -Message "Missing or changed package.config hash..." 164 | Remove-Item * -Recurse -Exclude packages.config,nuget.exe 165 | } 166 | 167 | Write-Verbose -Message "Restoring tools from NuGet..." 168 | $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" 169 | 170 | if ($LASTEXITCODE -ne 0) { 171 | Throw "An error occured while restoring NuGet tools." 172 | } 173 | else 174 | { 175 | $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" 176 | } 177 | Write-Verbose -Message ($NuGetOutput | out-string) 178 | Pop-Location 179 | } 180 | 181 | # Make sure that Cake has been installed. 182 | if (!(Test-Path $CAKE_EXE)) { 183 | Throw "Could not find Cake.exe at $CAKE_EXE" 184 | } 185 | 186 | # Start Cake 187 | Write-Host "Running build script..." 188 | Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" 189 | exit $LASTEXITCODE -------------------------------------------------------------------------------- /src/CSProjToXProj/CSProjToXProj.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 10 | 84aa132c-5097-4f1b-9161-6b91d06adb9c 11 | CSProjToXProj 12 | .\obj 13 | .\bin\ 14 | v4.6.1 15 | 16 | 17 | 18 | 2.0 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/CSProjToXProj/Plumbing/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace CSProjToXProj.Plumbing 5 | { 6 | public static class EnumerableExtensions 7 | { 8 | public static bool None(this IEnumerable items) 9 | { 10 | return !items.Any(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/CSProjToXProj/Plumbing/FileSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | 4 | namespace CSProjToXProj.Plumbing 5 | { 6 | 7 | public interface IFileSystem 8 | { 9 | Stream OpenRead(string path); 10 | bool Exists(string path); 11 | void WriteAllText(string path, string contents); 12 | void Delete(string path); 13 | string[] ReadAllLines(string path); 14 | void WriteAllLines(string path, IEnumerable lines); 15 | } 16 | 17 | public class FileSystem : IFileSystem 18 | { 19 | public Stream OpenRead(string path) 20 | { 21 | return File.OpenRead(path); 22 | } 23 | 24 | public bool Exists(string path) 25 | { 26 | return File.Exists(path); 27 | } 28 | 29 | public void WriteAllText(string path, string contents) 30 | { 31 | File.WriteAllText(path, contents); 32 | } 33 | 34 | public void Delete(string path) 35 | { 36 | File.Delete(path); 37 | } 38 | 39 | public string[] ReadAllLines(string path) 40 | { 41 | return File.ReadAllLines(path); 42 | } 43 | 44 | public void WriteAllLines(string path, IEnumerable lines) 45 | { 46 | File.WriteAllLines(path, lines); 47 | } 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/CSProjToXProj/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Threading.Tasks; 6 | using System.Xml; 7 | using CSProjToXProj.Plumbing; 8 | using CSProjToXProj.SourceFiles; 9 | using System.Linq; 10 | 11 | namespace CSProjToXProj 12 | { 13 | public class Program 14 | { 15 | private const string ReplaceExistingOption = "/ReplaceExisting"; 16 | private const string ForceOption = "/Force"; 17 | 18 | private static readonly HashSet AllOptions = new HashSet(StringComparer.OrdinalIgnoreCase) 19 | { 20 | ReplaceExistingOption, 21 | ForceOption 22 | }; 23 | 24 | public static int Main(string[] args) 25 | { 26 | if (args.Length == 0) 27 | { 28 | PrintUsage(); 29 | return 1; 30 | } 31 | 32 | var root = args[0]; 33 | var flags = new HashSet(args.Skip(1), StringComparer.OrdinalIgnoreCase); 34 | if(!flags.All(f => AllOptions.Contains(f))) 35 | { 36 | PrintUsage(); 37 | return 1; 38 | } 39 | var replaceExisting = flags.Contains(ReplaceExistingOption); 40 | var force = flags.Contains(ForceOption); 41 | 42 | 43 | if (!Directory.Exists(root)) 44 | { 45 | Console.WriteLine($"The directory {root} does not exist"); 46 | return 2; 47 | } 48 | 49 | try 50 | { 51 | Run(root, replaceExisting, force); 52 | return 0; 53 | } 54 | catch (Exception ex) 55 | { 56 | Console.WriteLine(ex); 57 | Debugger.Break(); 58 | return 3; 59 | } 60 | } 61 | 62 | private static void PrintUsage() 63 | { 64 | Console.WriteLine("Usage: CSProjToXProj [/ReplaceExisting] [/Force]"); 65 | Console.WriteLine(); 66 | Console.WriteLine( 67 | "if /ReplaceExisting is specified, the project GUID is retained, the sln file is updated and the csproj and package.config are deleted"); 68 | Console.WriteLine( 69 | "omit this flag if you are intending to have side by side csproj and xproj. You will need to rename either the csproj or xproj and then add the xproj to the solution."); 70 | Console.WriteLine(); 71 | Console.WriteLine("/Force overwrites existing xproj files"); 72 | } 73 | 74 | public static void Run(string directory, bool replaceExisting, bool force) 75 | { 76 | foreach (var csprojPath in Directory.GetFiles(directory, "*.csproj", SearchOption.AllDirectories)) 77 | { 78 | RunForCSProjFile(csprojPath, replaceExisting, force); 79 | } 80 | } 81 | 82 | private static void RunForCSProjFile(string csprojPath, bool replaceExisting, bool force) 83 | { 84 | csprojPath = Path.GetFullPath(csprojPath); 85 | var fs = new FileSystem(); 86 | var fileReader = new FileReader(fs); 87 | var directory = Path.GetDirectoryName(csprojPath); 88 | var packagesPath = Path.Combine(directory, "packages.config"); 89 | var xprojPath = Path.ChangeExtension(csprojPath, "xproj"); 90 | 91 | if (!force && File.Exists(xprojPath)) 92 | { 93 | Console.Error.WriteLine($"{xprojPath} exists, skipping {csprojPath}"); 94 | return; 95 | } 96 | 97 | Console.WriteLine($"{csprojPath} found"); 98 | Console.WriteLine($"Reading {csprojPath}"); 99 | var projectMetaData = fileReader.ReadCSProj(csprojPath); 100 | Console.WriteLine($"Reading {packagesPath}"); 101 | var packages = fileReader.ReadPackagesConfig(packagesPath); 102 | 103 | var writer = new Writer(fs); 104 | Console.WriteLine($"Writing xproj to {directory}"); 105 | writer.WriteXProj(xprojPath, projectMetaData, replaceExisting); 106 | Console.WriteLine($"Writing project.json to {directory}"); 107 | writer.WriteProjectJson(directory, projectMetaData, packages); 108 | 109 | if (replaceExisting) 110 | { 111 | foreach (var slnFile in FindSlnFiles(directory)) 112 | { 113 | Console.WriteLine($"Adjusting {slnFile}"); 114 | new SolutionAdjuster(fs).Adjust(slnFile, projectMetaData.Guid); 115 | } 116 | 117 | Console.WriteLine($"Deleting {csprojPath}"); 118 | fs.Delete(csprojPath); 119 | Console.WriteLine($"Deleting {packagesPath}"); 120 | fs.Delete(packagesPath); 121 | Console.WriteLine(); 122 | } 123 | } 124 | 125 | private static IEnumerable FindSlnFiles(string directory) 126 | { 127 | var slnFiles = Directory.EnumerateFiles(directory, "*.sln"); 128 | 129 | if (Directory.GetDirectoryRoot(directory) == directory) 130 | return slnFiles; 131 | 132 | return slnFiles.Concat(FindSlnFiles(Path.GetDirectoryName(directory))); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/CSProjToXProj/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("CSProjToXProj")] 11 | [assembly: AssemblyTrademark("")] 12 | 13 | // Setting ComVisible to false makes the types in this assembly not visible 14 | // to COM components. If you need to access a type in this assembly from 15 | // COM, set the ComVisible attribute to true on that type. 16 | [assembly: ComVisible(false)] 17 | 18 | // The following GUID is for the ID of the typelib if this project is exposed to COM 19 | [assembly: Guid("84aa132c-5097-4f1b-9161-6b91d06adb9c")] 20 | -------------------------------------------------------------------------------- /src/CSProjToXProj/SolutionAdjuster.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CSProjToXProj.Plumbing; 3 | using CSProjToXProj.SourceFiles; 4 | using System.Linq; 5 | 6 | namespace CSProjToXProj 7 | { 8 | public class SolutionAdjuster 9 | { 10 | private const string CSProjTypeGuid = "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"; 11 | private const string XProjTypeGuid = "8BB2217D-0F2D-49D1-97BC-3654ED321F3B"; 12 | 13 | private readonly IFileSystem _fileSystem; 14 | 15 | 16 | 17 | 18 | public SolutionAdjuster(IFileSystem fileSystem) 19 | { 20 | _fileSystem = fileSystem; 21 | } 22 | public void Adjust(string slnFile, Guid projectGuid) 23 | { 24 | var projectGuidStr = projectGuid.ToString("D").ToUpper(); 25 | var lines = _fileSystem.ReadAllLines(slnFile) 26 | .Select( 27 | l => l.Contains(CSProjTypeGuid) && l.Contains(projectGuidStr) 28 | ? l.Replace(CSProjTypeGuid, XProjTypeGuid).Replace("csproj", "xproj") 29 | : l 30 | ); 31 | _fileSystem.WriteAllLines(slnFile, lines); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/CSProjToXProj/SourceFiles/FileReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Xml.Linq; 6 | using CSProjToXProj.Plumbing; 7 | 8 | namespace CSProjToXProj.SourceFiles 9 | { 10 | public class FileReader 11 | { 12 | private readonly IFileSystem _fileSystem; 13 | 14 | public FileReader(IFileSystem fileSystem) 15 | { 16 | _fileSystem = fileSystem; 17 | } 18 | 19 | public ProjectMetadata ReadCSProj(string csprojPath) 20 | { 21 | using (var s = _fileSystem.OpenRead(csprojPath)) 22 | { 23 | var doc = XDocument.Load(s); 24 | const string ns = "http://schemas.microsoft.com/developer/msbuild/2003"; 25 | 26 | var projectReferences = doc.Descendants(XName.Get("ProjectReference", ns)) 27 | .Select(r => r.Attribute("Include").Value) 28 | .Select(p => Path.GetFileName(Path.GetDirectoryName(p))) 29 | .ToArray(); 30 | 31 | var frameworkReferences = doc.Descendants(XName.Get("Reference", ns)) 32 | .Where(r => r.Descendants(XName.Get("HintPath", ns)).None()) 33 | .Select(r => r.Attribute("Include").Value) 34 | .Except(new [] {"System"}) 35 | .ToArray(); 36 | 37 | var projectTypeGuids = doc 38 | .Descendants(XName.Get("ProjectTypeGuids", ns)) 39 | .FirstOrDefault()?.Value 40 | .Split(';') 41 | .Select(Guid.Parse) 42 | .ToArray() ?? Array.Empty(); 43 | 44 | var resources = doc.Descendants(XName.Get("EmbeddedResource", ns)) 45 | .Select(r => r.Attribute("Include").Value) 46 | .Select(path => path.Replace(" ", "%20")) //doesn't like spaces in the name. Possibly related to https://github.com/dotnet/roslyn/issues/4021? 47 | .ToArray(); 48 | 49 | return new ProjectMetadata( 50 | targetFrameworkVersion: doc.Descendants(XName.Get("TargetFrameworkVersion", ns)).FirstOrDefault()?.Value, 51 | rootNamespace: doc.Descendants(XName.Get("RootNamespace", ns)).FirstOrDefault()?.Value, 52 | guid: Guid.Parse(doc.Descendants(XName.Get("ProjectGuid", ns)).FirstOrDefault()?.Value), 53 | projectTypeGuids: projectTypeGuids, 54 | projectReferences: projectReferences, 55 | frameworkReferences: frameworkReferences, 56 | embeddedResources: resources, 57 | outputType: doc.Descendants(XName.Get("OutputType", ns)).FirstOrDefault()?.Value 58 | ); 59 | } 60 | } 61 | 62 | public IReadOnlyList ReadPackagesConfig(string packagesPath) 63 | { 64 | if (!_fileSystem.Exists(packagesPath)) 65 | return new PackageEntry[0]; 66 | 67 | using (var s = _fileSystem.OpenRead(packagesPath)) 68 | { 69 | var doc = XDocument.Load(s); 70 | return doc.Descendants(XName.Get("package")) 71 | .Select(e => new PackageEntry( 72 | e.Attribute("id").Value, 73 | e.Attribute("version").Value 74 | )) 75 | .ToArray(); 76 | } 77 | } 78 | 79 | } 80 | } -------------------------------------------------------------------------------- /src/CSProjToXProj/SourceFiles/PackageEntry.cs: -------------------------------------------------------------------------------- 1 | namespace CSProjToXProj.SourceFiles 2 | { 3 | public class PackageEntry 4 | { 5 | public PackageEntry(string id, string version) 6 | { 7 | Id = id; 8 | Version = version; 9 | } 10 | public string Id { get; } 11 | public string Version { get; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/CSProjToXProj/SourceFiles/ProjectMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace CSProjToXProj.SourceFiles 5 | { 6 | public class ProjectMetadata 7 | { 8 | 9 | public ProjectMetadata(string targetFrameworkVersion, string rootNamespace, Guid guid, string[] projectReferences, string[] frameworkReferences, 10 | string[] embeddedResources, string outputType, Guid[] projectTypeGuids) 11 | { 12 | TargetFrameworkVersion = targetFrameworkVersion; 13 | RootNamespace = rootNamespace; 14 | Guid = guid; 15 | ProjectReferences = projectReferences; 16 | FrameworkReferences = frameworkReferences; 17 | EmbeddedResources = embeddedResources; 18 | OutputType = outputType; 19 | ProjectTypeGuids = new HashSet(projectTypeGuids); 20 | } 21 | 22 | public string TargetFrameworkVersion { get; } 23 | public string RootNamespace { get; } 24 | public Guid Guid { get; } 25 | public IReadOnlyList ProjectReferences { get; } 26 | public IReadOnlyList FrameworkReferences { get; } 27 | public IReadOnlyList EmbeddedResources { get; } 28 | public string OutputType { get;} 29 | public ISet ProjectTypeGuids { get; } 30 | } 31 | } -------------------------------------------------------------------------------- /src/CSProjToXProj/Writer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using CSProjToXProj.Plumbing; 5 | using System.Linq; 6 | using CSProjToXProj.SourceFiles; 7 | using Newtonsoft.Json; 8 | using Newtonsoft.Json.Linq; 9 | 10 | namespace CSProjToXProj 11 | { 12 | public class Writer 13 | { 14 | public static readonly Guid WebProjectGuid = Guid.Parse("349C5851-65DF-11DA-9384-00065B846F21"); 15 | 16 | private readonly IFileSystem _fileSystem; 17 | 18 | public Writer(IFileSystem fileSystem) 19 | { 20 | _fileSystem = fileSystem; 21 | } 22 | 23 | public void WriteXProj(string xprojPath, ProjectMetadata projectMetaData, bool replaceExisting) 24 | { 25 | var projectGuid = replaceExisting ? projectMetaData.Guid : Guid.NewGuid(); 26 | var targetsFilePath = projectMetaData.ProjectTypeGuids.Contains(WebProjectGuid) 27 | ? "DotNet.Web\\Microsoft.DotNet.Web.targets" 28 | : "DotNet\\Microsoft.DotNet.targets"; 29 | 30 | var contents = $@" 31 | 32 | 33 | 14.0 34 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 35 | 36 | 37 | 38 | {projectGuid:D} 39 | {projectMetaData.RootNamespace} 40 | .\obj 41 | .\bin\ 42 | 43 | 44 | 2.0 45 | 46 | 47 | "; 48 | 49 | _fileSystem.WriteAllText(xprojPath, contents); 50 | } 51 | 52 | public void WriteProjectJson(string directory, ProjectMetadata projectMetadata, IReadOnlyList packages) 53 | { 54 | var doc = new JObject 55 | { 56 | ["version"] = "0.0.0-*", 57 | ["dependencies"] = new JObject() 58 | }; 59 | 60 | foreach (var package in packages) 61 | doc["dependencies"][package.Id] = package.Version; 62 | foreach (var reference in projectMetadata.ProjectReferences) 63 | doc["dependencies"][reference] = new JObject() { ["target"] = "project" }; 64 | 65 | var framework = "net" + projectMetadata.TargetFrameworkVersion.Replace("v", "").Replace(".", ""); 66 | var frameworkElement = new JObject(); 67 | doc["frameworks"] = new JObject { [framework] = frameworkElement }; 68 | 69 | if (projectMetadata.FrameworkReferences.Any()) 70 | { 71 | frameworkElement["frameworkAssemblies"] = new JObject(); 72 | foreach (var reference in projectMetadata.FrameworkReferences) 73 | frameworkElement["frameworkAssemblies"][reference] = "*"; 74 | } 75 | 76 | if (projectMetadata.OutputType.Equals("Exe", StringComparison.CurrentCultureIgnoreCase)) 77 | { 78 | doc["buildOptions"] = new JObject { ["emitEntryPoint"] = true }; 79 | } 80 | 81 | if (projectMetadata.EmbeddedResources.Any()) 82 | { 83 | if (doc["buildOptions"] == null) 84 | { 85 | doc["buildOptions"] = new JObject(); 86 | } 87 | var buildOptions = doc["buildOptions"]; 88 | buildOptions["embed"] = new JObject 89 | { 90 | ["include"] = new JArray(projectMetadata.EmbeddedResources.ToArray()) 91 | }; 92 | } 93 | 94 | var json = JsonConvert.SerializeObject(doc, Formatting.Indented); 95 | _fileSystem.WriteAllText(Path.Combine(directory, "project.json"), json); 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /src/CSProjToXProj/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-*", 3 | "buildOptions": { 4 | "emitEntryPoint": true 5 | }, 6 | 7 | "dependencies": { 8 | "Microsoft.NETCore.App": { 9 | "version": "1.0.0" 10 | }, 11 | "Newtonsoft.Json": "9.0.1" 12 | }, 13 | 14 | "frameworks": { 15 | "netcoreapp1.0": { 16 | } 17 | }, 18 | "runtimes": { 19 | "win7-x64": {} 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Tests/FileReaderTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CSProjToXProj.SourceFiles; 3 | using FluentAssertions; 4 | using NUnit.Framework; 5 | using Tests.Plumbing; 6 | 7 | namespace Tests 8 | { 9 | [TestFixture] 10 | public class FileReaderTests 11 | { 12 | [Test] 13 | public void TargetFrameworkIsRead() 14 | { 15 | ExecuteReadCsProj().TargetFrameworkVersion.Should().Be("v4.5"); 16 | } 17 | 18 | [Test] 19 | public void RootNamespaceIsRead() 20 | { 21 | ExecuteReadCsProj().RootNamespace.Should().Be("MyProject.Namespace"); 22 | } 23 | 24 | [Test] 25 | public void GuidIsRead() 26 | { 27 | ExecuteReadCsProj().Guid.Should().Be(Guid.Parse("C54911F0-365C-4F52-8634-A17F7A8815AC")); 28 | } 29 | 30 | [Test] 31 | public void ProjectReferencesAreRead() 32 | { 33 | ExecuteReadCsProj().ProjectReferences.Should().BeEquivalentTo("MyProj.Lib"); 34 | } 35 | 36 | [Test] 37 | public void FrameworkReferencesAreRead() 38 | { 39 | ExecuteReadCsProj().FrameworkReferences.Should().BeEquivalentTo("System.Data"); 40 | } 41 | 42 | [Test] 43 | public void EmbeddedResourcesAreRead() 44 | { 45 | ExecuteReadCsProj().EmbeddedResources.Should().BeEquivalentTo("resources\\myresource.html"); 46 | } 47 | 48 | [Test] 49 | public void OutputTypeIsRead() 50 | { 51 | ExecuteReadCsProj().OutputType.Should().BeEquivalentTo("Exe"); 52 | } 53 | 54 | private ProjectMetadata ExecuteReadCsProj() 55 | { 56 | var projFileName = @"x:\foo\my.csproj"; 57 | var fs = new FakeFileSystem() 58 | { 59 | { projFileName, CSProjContents } 60 | }; 61 | return new FileReader(fs).ReadCSProj(projFileName); 62 | } 63 | 64 | [Test] 65 | public void PackagesConfigFileCanBeRead() 66 | { 67 | const string packagesFile = @"x:\foo\packages.config"; 68 | var fs = new FakeFileSystem() 69 | { 70 | { packagesFile, PackagesConfigContents } 71 | }; 72 | var results = new FileReader(fs).ReadPackagesConfig(packagesFile); 73 | results.Should() 74 | .Contain(p => p.Id == "BouncyCastle" && p.Version == "1.7.0") 75 | .And 76 | .Contain(p => p.Id == "GitVersionTask" && p.Version == "3.5.4"); 77 | } 78 | 79 | 80 | [Test] 81 | public void NoPackagesConfigFileReturnsEmptyList() 82 | { 83 | var results = new FileReader(new FakeFileSystem()).ReadPackagesConfig(@"x:\foo\my.csproj"); 84 | results.Should().BeEmpty(); 85 | } 86 | 87 | private const string CSProjContents = 88 | #region Mucho XML 89 | @" 90 | 91 | 92 | Debug 93 | x86 94 | 12.0.0 95 | 2.0 96 | {C54911F0-365C-4F52-8634-A17F7A8815AC} 97 | Exe 98 | MyProject.Namespace 99 | MyProject 100 | ..\ 101 | true 102 | v4.5 103 | 104 | 105 | 106 | 107 | 108 | True 109 | full 110 | False 111 | bin\Debug 112 | DEBUG; 113 | prompt 114 | 4 115 | True 116 | x86 117 | false 118 | 119 | 120 | none 121 | True 122 | bin\Release 123 | prompt 124 | 4 125 | True 126 | x86 127 | false 128 | 129 | 130 | 131 | ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll 132 | 133 | 134 | 135 | 136 | {FAF9A6DD-C669-4F5B-88AF-8AB2B8F3B7C4} 137 | Lib.Core 138 | 139 | 140 | 141 | 142 | Properties\SolutionInfo.cs 143 | 144 | 145 | Properties\VersionInfo.cs 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 164 | 165 | 166 | 167 | "; 168 | #endregion 169 | 170 | private const string PackagesConfigContents = @" 171 | 172 | 173 | 174 | "; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/Tests/Plumbing/FakeFileSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using CSProjToXProj.Plumbing; 6 | 7 | namespace Tests.Plumbing 8 | { 9 | public class FakeFileSystem : Dictionary, IFileSystem 10 | { 11 | public FakeFileSystem() : base(StringComparer.CurrentCultureIgnoreCase) 12 | { 13 | 14 | } 15 | public Stream OpenRead(string filename) 16 | { 17 | return new MemoryStream(Encoding.UTF8.GetBytes(this[filename])); 18 | } 19 | 20 | public bool Exists(string path) 21 | { 22 | return ContainsKey(path); 23 | } 24 | 25 | public void WriteAllText(string path, string contents) 26 | { 27 | this[path] = contents; 28 | } 29 | 30 | public void Delete(string path) 31 | { 32 | this.Remove(path); 33 | } 34 | 35 | public string[] ReadAllLines(string path) 36 | { 37 | return this[path].Split(new[] {Environment.NewLine}, StringSplitOptions.None); 38 | } 39 | 40 | public void WriteAllLines(string path, IEnumerable lines) 41 | { 42 | this[path] = string.Join(Environment.NewLine, lines); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Tests/Plumbing/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Tests.Plumbing 2 | { 3 | public static class StringExtensions 4 | { 5 | public static string NormalizeLineEndings(this string str) 6 | { 7 | return str.Replace("\r", "").Replace("\n", "\r\n"); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("Tests")] 11 | [assembly: AssemblyTrademark("")] 12 | 13 | // Setting ComVisible to false makes the types in this assembly not visible 14 | // to COM components. If you need to access a type in this assembly from 15 | // COM, set the ComVisible attribute to true on that type. 16 | [assembly: ComVisible(false)] 17 | 18 | // The following GUID is for the ID of the typelib if this project is exposed to COM 19 | [assembly: Guid("f87a0ba7-5550-4fbf-bdf2-d4b1e57f387c")] 20 | -------------------------------------------------------------------------------- /src/Tests/SolutionAdjusterTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CSProjToXProj; 3 | using FluentAssertions; 4 | using NUnit.Framework; 5 | using Tests.Plumbing; 6 | 7 | namespace Tests 8 | { 9 | public class SolutionAdjusterTests 10 | { 11 | private const string Before = @" 12 | Microsoft Visual Studio Solution File, Format Version 12.00 13 | # Visual Studio 14 14 | VisualStudioVersion = 14.0.25420.1 15 | MinimumVisualStudioVersion = 10.0.40219.1 16 | Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""src"", ""src"", ""{7B75C713-EA67-479A-80E7-9150DB5BF60C}"" 17 | EndProject 18 | Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""CSProjToXProj"", ""src\CSProjToXProj\CSProjToXProj.csproj"", ""{84AA132C-5097-4F1B-9161-6B91D06ADB9C}"" 19 | EndProject 20 | Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""Tests"", ""src\Tests\Tests.csproj"", ""{F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}"" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(NestedProjects) = preSolution 41 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C} = {7B75C713-EA67-479A-80E7-9150DB5BF60C} 42 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C} = {7B75C713-EA67-479A-80E7-9150DB5BF60C} 43 | EndGlobalSection 44 | EndGlobal 45 | "; 46 | 47 | private const string After = @" 48 | Microsoft Visual Studio Solution File, Format Version 12.00 49 | # Visual Studio 14 50 | VisualStudioVersion = 14.0.25420.1 51 | MinimumVisualStudioVersion = 10.0.40219.1 52 | Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""src"", ""src"", ""{7B75C713-EA67-479A-80E7-9150DB5BF60C}"" 53 | EndProject 54 | Project(""{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}"") = ""CSProjToXProj"", ""src\CSProjToXProj\CSProjToXProj.xproj"", ""{84AA132C-5097-4F1B-9161-6B91D06ADB9C}"" 55 | EndProject 56 | Project(""{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"") = ""Tests"", ""src\Tests\Tests.csproj"", ""{F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}"" 57 | EndProject 58 | Global 59 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 60 | Debug|Any CPU = Debug|Any CPU 61 | Release|Any CPU = Release|Any CPU 62 | EndGlobalSection 63 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 64 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 65 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Debug|Any CPU.Build.0 = Debug|Any CPU 66 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 69 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Debug|Any CPU.Build.0 = Debug|Any CPU 70 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Release|Any CPU.ActiveCfg = Release|Any CPU 71 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C}.Release|Any CPU.Build.0 = Release|Any CPU 72 | EndGlobalSection 73 | GlobalSection(SolutionProperties) = preSolution 74 | HideSolutionNode = FALSE 75 | EndGlobalSection 76 | GlobalSection(NestedProjects) = preSolution 77 | {84AA132C-5097-4F1B-9161-6B91D06ADB9C} = {7B75C713-EA67-479A-80E7-9150DB5BF60C} 78 | {F87A0BA7-5550-4FBF-BDF2-D4B1E57F387C} = {7B75C713-EA67-479A-80E7-9150DB5BF60C} 79 | EndGlobalSection 80 | EndGlobal 81 | "; 82 | 83 | 84 | [Test] 85 | public void SolutionIsAdjustedCorrectly() 86 | { 87 | const string slnFile = @"x:\foo\bar.sln"; 88 | var guid = Guid.Parse("84AA132C-5097-4F1B-9161-6B91D06ADB9C"); 89 | var fs = new FakeFileSystem 90 | { 91 | { slnFile, Before.NormalizeLineEndings()} 92 | }; 93 | 94 | new SolutionAdjuster(fs).Adjust(slnFile, guid); 95 | 96 | fs[slnFile].NormalizeLineEndings().Should().Be(After.NormalizeLineEndings()); 97 | } 98 | 99 | 100 | 101 | } 102 | } -------------------------------------------------------------------------------- /src/Tests/Tests.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | f87a0ba7-5550-4fbf-bdf2-d4b1e57f387c 10 | Tests 11 | .\obj 12 | .\bin\ 13 | v4.6.1 14 | 15 | 16 | 2.0 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Tests/WriterTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CSProjToXProj; 3 | using CSProjToXProj.SourceFiles; 4 | using FluentAssertions; 5 | using NUnit.Framework; 6 | using Tests.Plumbing; 7 | 8 | namespace Tests 9 | { 10 | public class WriterTests 11 | { 12 | private readonly ProjectMetadata _metadata = new ProjectMetadata( 13 | targetFrameworkVersion: "v4.5.1", 14 | rootNamespace: "MyProject.Namespace", 15 | guid: Guid.Parse("50da3bcc-0fbb-4b69-8c7a-077f01fd6e4e"), 16 | projectReferences: new[] { "MyLib" }, 17 | frameworkReferences: new[] { "System.Data" }, 18 | embeddedResources: new[] { "resources\\myresource.txt" }, 19 | outputType: "Exe", 20 | projectTypeGuids: new[] { Writer.WebProjectGuid }); 21 | 22 | [Test] 23 | public void XProjIsWrittenCorrectly() 24 | { 25 | const string xprojFile = @"x:\path\myproj.xproj"; 26 | 27 | var fs = new FakeFileSystem(); 28 | new Writer(fs).WriteXProj(xprojFile, _metadata, true); 29 | 30 | fs[xprojFile].NormalizeLineEndings().Should().Be(@" 31 | 32 | 33 | 14.0 34 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 35 | 36 | 37 | 38 | 50da3bcc-0fbb-4b69-8c7a-077f01fd6e4e 39 | MyProject.Namespace 40 | .\obj 41 | .\bin\ 42 | 43 | 44 | 2.0 45 | 46 | 47 | ".NormalizeLineEndings()); 48 | } 49 | 50 | [Test] 51 | public void ProjectJsonIsWrittenCorrectly() 52 | { 53 | var fs = new FakeFileSystem(); 54 | var packages = new[] { new PackageEntry("Foo", "3.4.1"), new PackageEntry("Bar", "0.0.1-alpha.2"), }; 55 | new Writer(fs).WriteProjectJson(@"x:\path", _metadata, packages); 56 | 57 | fs[@"x:\path\project.json"].NormalizeLineEndings().Should().Be(@"{ 58 | ""version"": ""0.0.0-*"", 59 | ""dependencies"": { 60 | ""Foo"": ""3.4.1"", 61 | ""Bar"": ""0.0.1-alpha.2"", 62 | ""MyLib"": { 63 | ""target"": ""project"" 64 | } 65 | }, 66 | ""frameworks"": { 67 | ""net451"": { 68 | ""frameworkAssemblies"": { 69 | ""System.Data"": ""*"" 70 | } 71 | } 72 | }, 73 | ""buildOptions"": { 74 | ""emitEntryPoint"": true, 75 | ""embed"": { 76 | ""include"": [ 77 | ""resources\\myresource.txt"" 78 | ] 79 | } 80 | } 81 | }".NormalizeLineEndings()); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /src/Tests/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-*", 3 | 4 | "dependencies": { 5 | "Microsoft.NETCore.App": { 6 | "type": "platform", 7 | "version": "1.0.0" 8 | }, 9 | "NUnit": "3.4.1", 10 | "dotnet-test-nunit": "3.4.0-beta-1", 11 | "FluentAssertions": "4.12.0", 12 | "CSProjToXProj": "*" 13 | }, 14 | "testRunner": "nunit", 15 | "frameworks": { 16 | "netcoreapp1.0": { 17 | "imports": [ 18 | "portable-net45+win8" 19 | ] 20 | } 21 | } 22 | } 23 | --------------------------------------------------------------------------------