-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProjectFileService.cs
More file actions
171 lines (145 loc) · 6.72 KB
/
ProjectFileService.cs
File metadata and controls
171 lines (145 loc) · 6.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
namespace CodingWithCalvin.ProjectRenamifier.Services
{
/// <summary>
/// Service for updating project file (.csproj) elements.
/// </summary>
internal static class ProjectFileService
{
/// <summary>
/// Renames the project file on disk.
/// </summary>
/// <param name="projectFilePath">Full path to the current .csproj file.</param>
/// <param name="newName">The new project name (without extension).</param>
/// <returns>The new full path to the renamed project file.</returns>
public static string RenameProjectFile(string projectFilePath, string newName)
{
var directory = Path.GetDirectoryName(projectFilePath);
var extension = Path.GetExtension(projectFilePath);
var newFileName = newName + extension;
var newFilePath = Path.Combine(directory, newFileName);
File.Move(projectFilePath, newFilePath);
return newFilePath;
}
/// <summary>
/// Renames sibling files that share the project file name as a prefix.
/// For example, renaming Foo.csproj also renames Foo.csproj.user, Foo.csproj.filters, etc.
/// </summary>
/// <param name="projectFilePath">Full path to the already-renamed project file.</param>
/// <param name="oldName">The old project name (without extension).</param>
/// <returns>A list of the old file paths that were renamed.</returns>
public static IReadOnlyList<string> RenameSiblingFiles(string projectFilePath, string oldName)
{
var directory = Path.GetDirectoryName(projectFilePath);
var extension = Path.GetExtension(projectFilePath);
var newName = Path.GetFileNameWithoutExtension(projectFilePath);
var oldProjectFileName = oldName + extension;
var newProjectFileName = newName + extension;
var siblingFiles = Directory.GetFiles(directory)
.Where(f =>
{
var fileName = Path.GetFileName(f);
return fileName.StartsWith(oldProjectFileName + ".", StringComparison.OrdinalIgnoreCase);
})
.ToList();
var renamed = new List<string>();
foreach (var filePath in siblingFiles)
{
var fileName = Path.GetFileName(filePath);
var suffix = fileName.Substring(oldProjectFileName.Length);
var newFileName = newProjectFileName + suffix;
var newFilePath = Path.Combine(directory, newFileName);
File.Move(filePath, newFilePath);
renamed.Add(filePath);
}
return renamed;
}
/// <summary>
/// Renames the parent directory if its name matches the old project name.
/// </summary>
/// <param name="projectFilePath">Full path to the .csproj file.</param>
/// <param name="oldName">The old project name to match against.</param>
/// <param name="newName">The new project name.</param>
/// <returns>The new full path to the project file after directory rename, or the original path if no rename occurred.</returns>
public static string RenameParentDirectoryIfMatches(string projectFilePath, string oldName, string newName)
{
var projectDirectory = Path.GetDirectoryName(projectFilePath);
var parentDirectory = Directory.GetParent(projectDirectory);
if (parentDirectory == null)
{
return projectFilePath;
}
var directoryName = new DirectoryInfo(projectDirectory).Name;
// Only rename if directory name matches the old project name
if (!directoryName.Equals(oldName, StringComparison.OrdinalIgnoreCase))
{
return projectFilePath;
}
var newDirectoryPath = Path.Combine(parentDirectory.FullName, newName);
Directory.Move(projectDirectory, newDirectoryPath);
// Return the new project file path
var fileName = Path.GetFileName(projectFilePath);
return Path.Combine(newDirectoryPath, fileName);
}
/// <summary>
/// Updates the RootNamespace and AssemblyName elements in a project file
/// if they match the old project name.
/// </summary>
/// <param name="projectFilePath">Full path to the .csproj file.</param>
/// <param name="oldName">The old project name to match against.</param>
/// <param name="newName">The new project name to set.</param>
/// <returns>True if any changes were made, false otherwise.</returns>
public static bool UpdateProjectFile(string projectFilePath, string oldName, string newName)
{
var doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(projectFilePath);
var modified = false;
modified |= UpdateElement(doc, "RootNamespace", oldName, newName);
modified |= UpdateElement(doc, "AssemblyName", oldName, newName);
if (modified)
{
doc.Save(projectFilePath);
}
return modified;
}
/// <summary>
/// Updates a specific element in the project file if its value matches the old name.
/// </summary>
private static bool UpdateElement(XmlDocument doc, string elementName, string oldName, string newName)
{
// Handle both SDK-style (no namespace) and legacy (with namespace) project files
var namespaceManager = new XmlNamespaceManager(doc.NameTable);
var msbuildNs = "http://schemas.microsoft.com/developer/msbuild/2003";
// Check if document uses the MSBuild namespace
var hasNamespace = doc.DocumentElement?.NamespaceURI == msbuildNs;
XmlNodeList nodes;
if (hasNamespace)
{
namespaceManager.AddNamespace("ms", msbuildNs);
nodes = doc.SelectNodes($"//ms:{elementName}", namespaceManager);
}
else
{
nodes = doc.SelectNodes($"//{elementName}");
}
if (nodes == null || nodes.Count == 0)
{
return false;
}
var modified = false;
foreach (XmlNode node in nodes)
{
if (node.InnerText.Equals(oldName, StringComparison.OrdinalIgnoreCase))
{
node.InnerText = newName;
modified = true;
}
}
return modified;
}
}
}