Skip to content

Instantly share code, notes, and snippets.

@3F
Created September 7, 2015 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 3F/b1f613511737121a4bd1 to your computer and use it in GitHub Desktop.
Save 3F/b1f613511737121a4bd1 to your computer and use it in GitHub Desktop.
How to detect the first & last project of build-order in solution of Visual Studio. And how to use directly SBE-Scripts engine from C# Mode. / Example for vsSolutionBuildEvent users
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using ICommand = net.r_eg.vsSBE.Actions.ICommand;
using ISolutionEvent = net.r_eg.vsSBE.Events.ISolutionEvent;
namespace vsSolutionBuildEvent
{
public class CSharpMode
{
/// <summary>
/// based on https://gist.github.com/3F/a77129e3978841241927
/// </summary>
private class ProjectsMap
{
protected List<string> order = new List<string>();
protected Dictionary<string, Project> projects = new Dictionary<string, Project>();
public Project getLast()
{
if(order.Count < 1) {
return new Project() { name = "The Last project is Undefined", path = "?" };
}
return projects[order[order.Count - 1]];
}
public Project getFirst()
{
if(order.Count < 1) {
return new Project() { name = "The First project is Undefined", path = "?" };
}
return projects[order[0]];
}
/// <param name="sln">Full path to solution</param>
public ProjectsMap(string sln)
{
Regex rProject = new Regex("^Project\\(\"(?<TypeGuid>.*)\"\\)\\s*=\\s*\"(?<Name>.*)\"\\s*,\\s*\"(?<Path>.*)\"\\s*,\\s*\"(?<Guid>.*)\"$");
Regex rProperty = new Regex("^(?<PName>[^=]*)\\s*=\\s*(?<PValue>[^=]*)$");
Dictionary<string, List<string>> map = new Dictionary<string, List<string>>();
using(StreamReader reader = new StreamReader(sln, Encoding.Default))
{
string line;
while((line = reader.ReadLine()) != null)
{
line = line.Trim();
if(!line.StartsWith("Project(", StringComparison.Ordinal)) {
continue;
}
Match m = rProject.Match(line);
if(!m.Success) {
throw new Exception("incorrect line");
}
if(String.Equals("{2150E333-8FDC-42A3-9474-1A3956D46DE8}", m.Groups["TypeGuid"].Value.Trim(), StringComparison.OrdinalIgnoreCase)) {
continue; //SolutionFolder
}
string pGuid = m.Groups["Guid"].Value.Trim();
projects[pGuid] = new Project() { name = m.Groups["Name"].Value, path = m.Groups["Path"].Value };
map[pGuid] = new List<string>();
while((line = reader.ReadLine()) != null && (line != "EndProject"))
{
line = line.Trim();
if(line.StartsWith("ProjectSection(ProjectDependencies)", StringComparison.Ordinal))
{
for(line = reader.ReadLine(); line != null; line = reader.ReadLine())
{
line = line.Trim();
if(line.StartsWith("EndProjectSection", StringComparison.Ordinal)) {
break;
}
map[pGuid].Add(rProperty.Match(line).Groups["PName"].Value.Trim());
}
}
}
}
}
// Build order
Func<string, bool> h = null;
h = delegate(string id)
{
map[id].ForEach(dep => h(dep));
if(!order.Contains(id)) {
order.Add(id);
}
return true;
};
foreach(KeyValuePair<string, List<string>> project in map)
{
h(project.Key);
if(!order.Contains(project.Key)) {
order.Add(project.Key);
}
}
}
}
private struct Project
{
public string name;
public string path;
}
public static int Init(ICommand cmd, ISolutionEvent evt)
{
ProjectsMap map = new ProjectsMap(@"$(SolutionPath)");
// it should be in reverse order for 'Clean' type
string data = @"
#[( #[Build type] != Clean )
{{
#[var firstProject = {0}] #[var lastProject = {1}]
}}
else {{
#[var firstProject = {1}] #[var lastProject = {0}]
}}]
";
cmd.SBEScript.parse(String.Format(data, map.getFirst().name, map.getLast().name));
return 0;
}
}
}
@3F
Copy link
Author

3F commented Sep 7, 2015

@3F
Copy link
Author

3F commented Sep 30, 2015

v0.12.4+ is already contains similar logic in BuildComponent.

Now it should be easier, for example:

#[Build solution.path("app.sln").First.name]
#[Build solution.current.Last.path]
...
#[( #[Build solution.current.GuidList] ~= "{4262A1DC-768F-43CC-85F5-A4ED9CD034CC}" )
{
   ...
}]
...

etc.

Available a few variants for different modes.

http://vssbe.r-eg.net/doc/Scripts/SBE-Scripts/
http://vssbe.r-eg.net/doc/Modes/CSharp/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment