forked from daveaglick/Scripty
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProjectRoot.cs
More file actions
155 lines (144 loc) · 6.03 KB
/
Copy pathProjectRoot.cs
File metadata and controls
155 lines (144 loc) · 6.03 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
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.MSBuild;
namespace Scripty.Core.ProjectTree
{
public class ProjectRoot : ProjectNode
{
private readonly object _projectLock = new object();
private readonly string _solutionFilePath;
private readonly Dictionary<string, string> _properties;
private MSBuildWorkspace _workspace;
private Microsoft.CodeAnalysis.Project _analysisProject;
private Microsoft.Build.Evaluation.Project _buildProject;
private bool _generatedTree;
public ProjectRoot(string filePath)
: this(filePath, null, null)
{
}
public ProjectRoot(string projectFilePath, string solutionFilePath, IReadOnlyDictionary<string, string> properties)
: base(null, string.Empty, null, null)
{
FilePath = projectFilePath;
_solutionFilePath = solutionFilePath;
_properties = new Dictionary<string, string>();
// Convert the given properties from a read-only
// dictionary into a read-write dictionary because
// that is what the MSBuildWorkspace will require.
if (properties != null)
{
foreach (var pair in properties)
{
_properties[pair.Key] = pair.Value;
}
}
}
public string FilePath { get; }
public MSBuildWorkspace Workspace
{
get
{
if (_workspace == null && !string.IsNullOrEmpty(FilePath))
{
lock (_projectLock)
{
_workspace = MSBuildWorkspace.Create(_properties);
}
}
return _workspace;
}
}
public Microsoft.CodeAnalysis.Project Analysis
{
get
{
if (_analysisProject == null && !string.IsNullOrEmpty(FilePath))
{
lock (_projectLock)
{
// If we have been given a solution path, load the solution and find the project.
// This ensures that if the project references the solution directory (via the
// "$(SolutionDir)" property), that it will load correctly. If we only loaded the project,
// then the solution directory would not be defined and the project can fail to load.
if (_solutionFilePath != null)
{
Solution solution = Workspace.OpenSolutionAsync(_solutionFilePath).Result;
_analysisProject = solution.Projects.FirstOrDefault(x => string.Equals(x.FilePath, FilePath, System.StringComparison.OrdinalIgnoreCase));
if (_analysisProject == null)
{
throw new System.InvalidOperationException($"Could not find the project '{FilePath}' in the solution.");
}
}
else
{
_analysisProject = Workspace.OpenProjectAsync(FilePath).Result;
}
}
}
return _analysisProject;
}
}
public Microsoft.Build.Evaluation.Project Build
{
get
{
if (_buildProject == null && !string.IsNullOrEmpty(FilePath))
{
lock (_projectLock)
{
_buildProject = new Microsoft.Build.Evaluation.Project(FilePath);
}
}
return _buildProject;
}
}
public override Document Document => null;
public override IReadOnlyDictionary<string, ProjectNode> Children
{
get
{
if(!_generatedTree)
{
Microsoft.Build.Evaluation.Project buildProject = Build;
if(buildProject != null)
{
var groups = buildProject.AllEvaluatedItems
.Where(x => x.ItemType == "None"
|| x.ItemType == "Compile"
|| x.ItemType == "EmbeddedResource"
|| x.ItemType == "Content")
.Where(x => !Path.IsPathRooted(x.EvaluatedInclude))
.Select(x => new
{
DirectoryName = Path.GetDirectoryName(x.EvaluatedInclude),
FileName = Path.GetFileName(x.EvaluatedInclude),
ProjectItem = x
})
.GroupBy(x => x.DirectoryName);
foreach (var group in groups)
{
string[] segments = group.Key.Split(
Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
ProjectNode current = this;
if (segments.Length > 1 || !string.IsNullOrEmpty(segments[0]))
{
foreach (string segment in segments)
{
current = current.GetOrAddChild(segment);
}
}
foreach (var item in group)
{
current.AddChild(item.FileName, item.ProjectItem);
}
}
}
_generatedTree = true;
}
return base.Children;
}
}
}
}