Skip to content

Commit 46bdaa9

Browse files
romangolevjmcouffin
authored andcommitted
feat: implement pyRevitExtensionParser csproject
1 parent 6964633 commit 46bdaa9

File tree

11 files changed

+232
-159
lines changed

11 files changed

+232
-159
lines changed

dev/Directory.Build.props

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<PropertyGroup>
44
<OutputType>Library</OutputType>
5-
<!-- <TargetFramework>net48</TargetFramework>-->
6-
<!-- <TargetFrameworks>net48;net8.0-windows</TargetFrameworks>-->
75
<PlatformTarget>x64</PlatformTarget>
86
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
97
</PropertyGroup>

dev/pyRevitLoader/Directory.Build.props

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
<UseRevit>true</UseRevit>
55
<UseWpf>true</UseWpf>
66
<UseWindowsForms>true</UseWindowsForms>
7-
<UseAssemblyBuilder>true</UseAssemblyBuilder>
7+
<UseAssemblyBuilder>true</UseAssemblyBuilder>
88
<TargetFrameworks>net48;net8.0-windows</TargetFrameworks>
9-
109
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
1110
</PropertyGroup>
1211

dev/pyRevitLoader/Directory.Build.targets

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<Compile Include="..\Source\ScriptExecutor.cs" Link="Source\ScriptExecutor.cs"/>
1818
</ItemGroup>
1919

20-
<ItemGroup Condition="'$(MSBuildProjectName)' != 'pyRevitAssemblyBuilder' AND $(IronPythonVersion.Contains('PR'))">
20+
<ItemGroup Condition="'$(UseIronPython)' != 'false' AND $(IronPythonVersion.Contains('PR'))">
2121
<Reference Include="IronPython" HintPath="$(PyRevitEnginesDir)\$(IronPythonVersion)\pyRevitLabs.IronPython.dll"/>
2222
<Reference Include="IronPython.Modules" HintPath="$(PyRevitEnginesDir)\$(IronPythonVersion)\pyRevitLabs.IronPython.Modules.dll"/>
2323
<Reference Include="IronPython.SQLite" HintPath="$(PyRevitEnginesDir)\$(IronPythonVersion)\pyRevitLabs.IronPython.SQLite.dll"/>
@@ -26,19 +26,23 @@
2626
<Reference Include="Microsoft.Scripting" HintPath="$(PyRevitEnginesDir)\$(IronPythonVersion)\pyRevitLabs.Microsoft.Scripting.dll"/>
2727
</ItemGroup>
2828

29-
<ItemGroup Condition="'$(MSBuildProjectName)' != 'pyRevitAssemblyBuilder' AND !$(IronPythonVersion.Contains('PR'))">
29+
<ItemGroup Condition="'$(UseIronPython)' != 'false' AND !$(IronPythonVersion.Contains('PR'))">
3030
<PackageReference Include="IronPython" Version="$(Version)"/>
3131
</ItemGroup>
3232

3333
<ItemGroup>
3434
<Reference Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" Include="Microsoft.CSharp"/>
3535
</ItemGroup>
36-
37-
<ItemGroup Condition="'$(UseAssemblyBuilder)' == 'true'">
38-
<ProjectReference Include="..\pyRevitAssemblyBuilder\pyRevitAssemblyBuilder.csproj" />
39-
</ItemGroup>
40-
41-
<ItemGroup Condition="'$(MSBuildProjectName)' != 'pyRevitAssemblyBuilder'">
36+
37+
<ItemGroup Condition="'$(UseAssemblyBuilder)' == 'true'">
38+
<ProjectReference Include="..\pyRevitAssemblyBuilder\pyRevitAssemblyBuilder.csproj" />
39+
</ItemGroup>
40+
41+
<ItemGroup Condition="'$(UseExtensionParser)' == 'true'">
42+
<ProjectReference Include="..\pyRevitExtensionParser\pyRevitExtensionParser.csproj" />
43+
</ItemGroup>
44+
45+
<ItemGroup Condition="'$(UseIronPython)' != 'false'">
4246
<EmbeddedResource Include="$(IronPythonStdLibDir)\$(IronPythonStdLib)"/>
4347
</ItemGroup>
4448

dev/pyRevitLoader/Source/PyRevitLoaderApplication.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using Autodesk.Revit.Attributes;
66
using pyRevitAssemblyBuilder.AssemblyMaker;
77
using pyRevitAssemblyBuilder.SessionManager;
8-
using pyRevitAssemblyBuilder.FolderParser;
98

109
/* Note:
1110
* It is necessary that this code object do not have any references to IronPython.

dev/pyRevitLoader/pyRevitAssemblyBuilder/AssemblyMaker/TypeMakerService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public void DefineCommandType(IExtension extension, ICommandComponent command, M
2626
// Emit a default constructor
2727
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
2828

29-
// Create the type (works in .NET Standard 2.0 via CreateTypeInfo)
29+
// Create the type
3030
_ = typeBuilder.CreateTypeInfo();
3131
}
3232
}
Lines changed: 20 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,44 @@
1-

2-
using System;
3-
using System.Collections.Generic;
4-
using System.IO;
1+
using System.Collections.Generic;
52
using System.Linq;
6-
using pyRevitAssemblyBuilder.Config;
3+
using pyRevitExtensionParser;
74
using pyRevitAssemblyBuilder.Shared;
85

9-
namespace pyRevitAssemblyBuilder.FolderParser
6+
namespace pyRevitAssemblyBuilder.SessionManager
107
{
118
public class ExtensionManagerService
129
{
13-
private readonly List<string> _extensionRoots;
14-
15-
private static readonly string[] BundleTypes = new[]
16-
{
17-
".tab", ".panel", ".stack", ".splitbutton", ".splitpushbutton", ".pulldown", ".smartbutton", ".pushbutton"
18-
};
19-
20-
public ExtensionManagerService()
21-
{
22-
_extensionRoots = GetExtensionRoots();
23-
}
24-
2510
public IEnumerable<IExtension> GetInstalledExtensions()
2611
{
27-
foreach (var root in _extensionRoots)
12+
foreach (var parsedExtension in ExtensionParser.ParseInstalledExtensions())
2813
{
29-
if (!Directory.Exists(root))
30-
continue;
31-
32-
foreach (var dir in Directory.GetDirectories(root))
33-
{
34-
if (!dir.EndsWith(".extension", StringComparison.OrdinalIgnoreCase))
35-
continue;
36-
37-
var extensionName = Path.GetFileNameWithoutExtension(dir);
38-
var metadata = LoadMetadata(dir);
39-
var children = LoadBundleComponents(dir);
40-
41-
if (children.Any())
42-
yield return new FileSystemExtension(extensionName, dir, children, metadata);
43-
}
14+
yield return new FileSystemExtension(
15+
name: parsedExtension.Name,
16+
path: parsedExtension.Directory,
17+
commands: parsedExtension.Children.Select(ConvertComponent).ToList(),
18+
metadata: parsedExtension.Metadata
19+
);
4420
}
4521
}
4622

47-
private List<string> GetExtensionRoots()
23+
private ICommandComponent ConvertComponent(ParsedComponent parsed)
4824
{
49-
var roots = new List<string>();
50-
51-
var current = Path.GetDirectoryName(typeof(ExtensionManagerService).Assembly.Location);
52-
var defaultPath = Path.GetFullPath(Path.Combine(current, "..", "..", "..", "..", "extensions"));
53-
roots.Add(defaultPath);
54-
55-
var configPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "pyRevit", "pyRevit_config.ini");
56-
if (File.Exists(configPath))
57-
{
58-
var config = PyRevitConfig.Load(configPath);
59-
if (config.UserExtensions != null && config.UserExtensions.Count > 0)
60-
roots.AddRange(config.UserExtensions);
61-
}
62-
63-
return roots;
64-
}
65-
66-
private IEnumerable<ICommandComponent> LoadBundleComponents(string baseDir)
67-
{
68-
var components = new List<ICommandComponent>();
69-
70-
foreach (var dir in Directory.GetDirectories(baseDir))
71-
{
72-
var type = Path.GetExtension(dir).ToLowerInvariant();
73-
if (!BundleTypes.Contains(type))
74-
continue;
75-
76-
components.Add(ParseComponent(dir, type));
77-
}
78-
79-
return components;
80-
}
81-
82-
private FileCommandComponent ParseComponent(string dir, string type)
83-
{
84-
var name = Path.GetFileNameWithoutExtension(dir);
85-
var children = LoadBundleComponents(dir);
86-
var scriptPath = Path.Combine(dir, "script.py");
87-
8825
return new FileCommandComponent
8926
{
90-
Name = name,
91-
ScriptPath = File.Exists(scriptPath) ? scriptPath : null,
92-
Tooltip = $"Command: {name}",
93-
UniqueId = $"{Path.GetFileNameWithoutExtension(dir)}.{name}",
94-
ExtensionName = FindExtensionNameFromPath(dir),
95-
Type = type,
96-
Children = children.Cast<object>().ToList()
27+
Name = parsed.Name,
28+
ScriptPath = parsed.ScriptPath,
29+
Tooltip = parsed.Tooltip,
30+
UniqueId = parsed.UniqueId,
31+
ExtensionName = parsed.UniqueId.Split('.')[0],
32+
Type = parsed.Type,
33+
Children = parsed.Children?.Select(ConvertComponent).Cast<object>().ToList() ?? new List<object>()
9734
};
9835
}
9936

100-
private string FindExtensionNameFromPath(string path)
101-
{
102-
var segments = path.Split(Path.DirectorySeparatorChar);
103-
var extDir = segments.FirstOrDefault(s => s.EndsWith(".extension"));
104-
return extDir != null ? Path.GetFileNameWithoutExtension(extDir) : "UnknownExtension";
105-
}
106-
107-
private ExtensionMetadata LoadMetadata(string extensionPath)
108-
{
109-
var yamlPath = Path.Combine(extensionPath, "extension.yaml");
110-
if (!File.Exists(yamlPath))
111-
return null;
112-
113-
try
114-
{
115-
var yamlText = File.ReadAllText(yamlPath);
116-
return ParseYamlToMetadata(yamlText);
117-
}
118-
catch
119-
{
120-
return null;
121-
}
122-
}
123-
124-
private ExtensionMetadata ParseYamlToMetadata(string yaml)
125-
{
126-
var metadata = new ExtensionMetadata();
127-
var lines = yaml.Split('\n');
128-
foreach (var line in lines)
129-
{
130-
var trimmed = line.Trim();
131-
if (trimmed.StartsWith("author:"))
132-
metadata.Author = trimmed.Substring("author:".Length).Trim();
133-
else if (trimmed.StartsWith("version:"))
134-
metadata.Version = trimmed.Substring("version:".Length).Trim();
135-
else if (trimmed.StartsWith("description:"))
136-
metadata.Description = trimmed.Substring("description:".Length).Trim();
137-
}
138-
return metadata;
139-
}
140-
14137
private class FileSystemExtension : IExtension
14238
{
14339
private readonly IEnumerable<ICommandComponent> _commands;
14440

145-
public FileSystemExtension(string name, string path, IEnumerable<ICommandComponent> commands, ExtensionMetadata metadata)
41+
public FileSystemExtension(string name, string path, IEnumerable<ICommandComponent> commands, ParsedExtensionMetadata metadata)
14642
{
14743
Name = name;
14844
Directory = path;
@@ -152,7 +48,7 @@ public FileSystemExtension(string name, string path, IEnumerable<ICommandCompone
15248

15349
public string Name { get; }
15450
public string Directory { get; }
155-
public ExtensionMetadata Metadata { get; }
51+
public ParsedExtensionMetadata Metadata { get; }
15652

15753
public string GetHash() => Directory.GetHashCode().ToString("X");
15854

@@ -174,12 +70,5 @@ private class FileCommandComponent : ICommandComponent
17470
public string Type { get; set; }
17571
public IEnumerable<object> Children { get; set; } = Enumerable.Empty<object>();
17672
}
177-
178-
public class ExtensionMetadata
179-
{
180-
public string Author { get; set; }
181-
public string Version { get; set; }
182-
public string Description { get; set; }
183-
}
18473
}
18574
}

dev/pyRevitLoader/pyRevitAssemblyBuilder/SessionManager/SessionManagerService.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Diagnostics;
33
using System.Threading.Tasks;
44
using pyRevitAssemblyBuilder.AssemblyMaker;
5-
using pyRevitAssemblyBuilder.FolderParser;
65

76
namespace pyRevitAssemblyBuilder.SessionManager
87
{
Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
<Project Sdk="Microsoft.NET.Sdk">
2-
<PropertyGroup>
3-
<DisableImplicitProps>true</DisableImplicitProps>
4-
<DisableImplicitTargets>true</DisableImplicitTargets>
5-
<AssemblyName>pyRevitAssemblyBuilder</AssemblyName>
6-
<RootNamespace>pyRevitAssemblyBuilder</RootNamespace>
7-
<UseRevit>true</UseRevit>
8-
<TargetFrameworks>net48;net8.0-windows</TargetFrameworks>
9-
<IronPythonVersion>IPY342</IronPythonVersion>
10-
<Version>3.4.2</Version>
11-
</PropertyGroup>
12-
<ItemGroup>
13-
<PackageReference Include="Lokad.ILPack" Version="0.3.0" />
14-
</ItemGroup>
2+
<PropertyGroup>
3+
<DisableImplicitProps>true</DisableImplicitProps>
4+
<DisableImplicitTargets>true</DisableImplicitTargets>
5+
<AssemblyName>pyRevitAssemblyBuilder</AssemblyName>
6+
<RootNamespace>pyRevitAssemblyBuilder</RootNamespace>
7+
<UseRevit>true</UseRevit>
8+
<UseIronPython>false</UseIronPython>
9+
<UseExtensionParser>true</UseExtensionParser>
10+
<TargetFrameworks>net48;net8.0-windows</TargetFrameworks>
11+
<IronPythonVersion>IPY342</IronPythonVersion>
12+
<Version>3.4.2</Version>
13+
</PropertyGroup>
14+
<ItemGroup>
15+
<PackageReference Include="Lokad.ILPack" Version="0.3.0" />
16+
</ItemGroup>
1517
</Project>

0 commit comments

Comments
 (0)