diff --git a/AvaloniaILSpy.Controls/Themes/TreeView.xaml b/AvaloniaILSpy.Controls/Themes/TreeView.xaml index ff5d229..8c42a78 100644 --- a/AvaloniaILSpy.Controls/Themes/TreeView.xaml +++ b/AvaloniaILSpy.Controls/Themes/TreeView.xaml @@ -233,7 +233,7 @@ + ToolTip.Tip="{Binding ToolTip}"> + + + Exe + netcoreapp2.1 + + true + true + true + win7-x64;ubuntu.14.04-x64;debian.8-x64;osx.10.12-x64 + true + + False + + false + + AvaloniaILSpy + + True + + AvaloniaILSpy.NetCore.Program + + false + + + + full + true + True + + + + pdbonly + true + + + + ..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.ruleset + + + + + + + + + + + \ No newline at end of file diff --git a/AvaloniaILSpy/Program.cs b/AvaloniaILSpy.NetCore/Program.cs similarity index 64% rename from AvaloniaILSpy/Program.cs rename to AvaloniaILSpy.NetCore/Program.cs index 17173dd..78385eb 100644 --- a/AvaloniaILSpy/Program.cs +++ b/AvaloniaILSpy.NetCore/Program.cs @@ -1,17 +1,13 @@ -using System; -using System.Collections.Generic; +using Avalonia; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Reflection; -using Avalonia; using Avalonia.Logging.Serilog; -namespace AvaloniaILSpy +namespace AvaloniaILSpy.NetCore { - class Program + static class Program { + static void Main(string[] args) { Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); @@ -19,13 +15,14 @@ namespace AvaloniaILSpy BuildAvaloniaApp().Start(); } + /// + /// This method is needed for IDE previewer infrastructure + /// public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() + => AppBuilder.Configure() #if DEBUG .LogToDebug() #endif .UsePlatformDetect(); - - } -} +} \ No newline at end of file diff --git a/AvaloniaILSpy.sln b/AvaloniaILSpy.sln index 5056849..67ac409 100644 --- a/AvaloniaILSpy.sln +++ b/AvaloniaILSpy.sln @@ -10,11 +10,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E7 doc\IntPtr.txt = doc\IntPtr.txt EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvaloniaILSpy.Controls", "AvaloniaILSpy.Controls\AvaloniaILSpy.Controls.csproj", "{0A3DA152-0729-4540-973C-11583009520F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaILSpy.Controls", "AvaloniaILSpy.Controls\AvaloniaILSpy.Controls.csproj", "{0A3DA152-0729-4540-973C-11583009520F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvaloniaILSpy", "AvaloniaILSpy\AvaloniaILSpy.csproj", "{7BB39313-8FC6-40A4-A06F-FD2A10817256}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaILSpy", "AvaloniaILSpy\AvaloniaILSpy.csproj", "{7BB39313-8FC6-40A4-A06F-FD2A10817256}" EndProject -Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "AvaloniaEdit", "AvaloniaEdit\src\AvaloniaEdit\AvaloniaEdit.csproj", "{CC3151F6-C080-4E17-9F50-58C3FED64F28}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaEdit", "AvaloniaEdit\src\AvaloniaEdit\AvaloniaEdit.csproj", "{CC3151F6-C080-4E17-9F50-58C3FED64F28}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestPlugin", "TestPlugin\TestPlugin.csproj", "{5C561A81-4427-418A-B773-3840D2B32C4D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaILSpy.NetCore", "AvaloniaILSpy.NetCore\AvaloniaILSpy.NetCore.csproj", "{3AAA340D-7BED-4B26-BDD3-992D8B6D7779}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -34,6 +38,14 @@ Global {CC3151F6-C080-4E17-9F50-58C3FED64F28}.Debug|Any CPU.Build.0 = Debug|Any CPU {CC3151F6-C080-4E17-9F50-58C3FED64F28}.Release|Any CPU.ActiveCfg = Release|Any CPU {CC3151F6-C080-4E17-9F50-58C3FED64F28}.Release|Any CPU.Build.0 = Release|Any CPU + {5C561A81-4427-418A-B773-3840D2B32C4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C561A81-4427-418A-B773-3840D2B32C4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C561A81-4427-418A-B773-3840D2B32C4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C561A81-4427-418A-B773-3840D2B32C4D}.Release|Any CPU.Build.0 = Release|Any CPU + {3AAA340D-7BED-4B26-BDD3-992D8B6D7779}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AAA340D-7BED-4B26-BDD3-992D8B6D7779}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AAA340D-7BED-4B26-BDD3-992D8B6D7779}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AAA340D-7BED-4B26-BDD3-992D8B6D7779}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/AvaloniaILSpy/AvaloniaILSpy.csproj b/AvaloniaILSpy/AvaloniaILSpy.csproj index a776f0c..b80dea6 100644 --- a/AvaloniaILSpy/AvaloniaILSpy.csproj +++ b/AvaloniaILSpy/AvaloniaILSpy.csproj @@ -2,26 +2,9 @@ - Exe - netcoreapp2.1 - - true - true - true - win7-x64;ubuntu.14.04-x64;debian.8-x64;osx.10.12-x64 - true - + netstandard2.0 False - false - - AvaloniaILSpy - - True - - Images\ILSpy-Large.ico - AvaloniaILSpy.Program - false diff --git a/AvaloniaILSpy/Images/Images.cs b/AvaloniaILSpy/Images/Images.cs index 75d1645..aba7d04 100644 --- a/AvaloniaILSpy/Images/Images.cs +++ b/AvaloniaILSpy/Images/Images.cs @@ -103,16 +103,15 @@ namespace AvaloniaILSpy public static IBitmap LoadImage(object part, string icon) { - String uri; - var assembly = part.GetType().Assembly; + IBitmap image; + var assembly = part.GetType().Assembly; if (assembly == typeof(Images).Assembly) { - uri = (icon); + image = new Bitmap(icon); } else { var name = assembly.GetName(); - uri = (name.Name + ";component/" + icon); - } - IBitmap image = new Bitmap(uri); - //image.Freeze(); + var embededResourceStream = assembly.GetManifestResourceStream(icon); + image = new Bitmap(embededResourceStream); + } return image; } diff --git a/AvaloniaILSpy/MainWindow.xaml.cs b/AvaloniaILSpy/MainWindow.xaml.cs index 2dc7202..cfa5d97 100644 --- a/AvaloniaILSpy/MainWindow.xaml.cs +++ b/AvaloniaILSpy/MainWindow.xaml.cs @@ -46,7 +46,7 @@ namespace AvaloniaILSpy /// /// The main window of the application. /// - partial class MainWindow : Window, IRoutedCommandBindable + public partial class MainWindow : Window, IRoutedCommandBindable { readonly NavigationHistory history = new NavigationHistory(); ILSpySettings spySettings; diff --git a/TestPlugin/AboutPageAddition.cs b/TestPlugin/AboutPageAddition.cs new file mode 100644 index 0000000..6d473ae --- /dev/null +++ b/TestPlugin/AboutPageAddition.cs @@ -0,0 +1,35 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System.ComponentModel.Composition; +using Avalonia; +using Avalonia.Media; + +using AvaloniaEdit.Highlighting; +using AvaloniaILSpy; + +namespace TestPlugin +{ + [Export(typeof(IAboutPageAddition))] + public class AboutPageAddition : IAboutPageAddition + { + public void Write(ISmartTextOutput textOutput) + { + textOutput.WriteLine(); + textOutput.Write("This is a test."); + textOutput.WriteLine(); + textOutput.WriteLine(); + textOutput.BeginSpan(new HighlightingColor { + Background = new SimpleHighlightingBrush(Colors.Black), + FontStyle = FontStyle.Italic, + Foreground = new SimpleHighlightingBrush(Colors.Aquamarine) + }); + textOutput.Write("DO NOT PRESS THIS BUTTON --> "); + textOutput.AddButton(null, "Test!", (sender, args) => MessageBox.Show("Naughty Naughty!", "Naughty!", MessageBoxButton.OK, MessageBoxImage.Exclamation)); + textOutput.Write(" <--"); + textOutput.WriteLine(); + textOutput.EndSpan(); + textOutput.WriteLine(); + } + } +} diff --git a/TestPlugin/Clear.png b/TestPlugin/Clear.png new file mode 100644 index 0000000..47e7d60 Binary files /dev/null and b/TestPlugin/Clear.png differ diff --git a/TestPlugin/ContextMenuCommand.cs b/TestPlugin/ContextMenuCommand.cs new file mode 100644 index 0000000..efeac06 --- /dev/null +++ b/TestPlugin/ContextMenuCommand.cs @@ -0,0 +1,42 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) +using System.Collections.Generic; +using System.Linq; +using Avalonia.Controls; +using AvaloniaILSpy; +using AvaloniaILSpy.TreeNodes; +using Mono.Cecil; + +namespace TestPlugin +{ + [ExportContextMenuEntryAttribute(Header = "_Save Assembly")] + public class SaveAssembly : IContextMenuEntry + { + public bool IsVisible(TextViewContext context) + { + return context.SelectedTreeNodes != null && context.SelectedTreeNodes.All(n => n is AssemblyTreeNode); + } + + public bool IsEnabled(TextViewContext context) + { + return context.SelectedTreeNodes != null && context.SelectedTreeNodes.Length == 1; + } + + public async void Execute(TextViewContext context) + { + if (context.SelectedTreeNodes == null) + return; + AssemblyTreeNode node = (AssemblyTreeNode)context.SelectedTreeNodes[0]; + AssemblyDefinition asm = node.LoadedAssembly.GetAssemblyDefinitionOrNull(); + if (asm != null) { + SaveFileDialog dlg = new SaveFileDialog(); + dlg.InitialFileName = node.LoadedAssembly.FileName; + dlg.Filters = new List { new FileDialogFilter { Name = "Assembly", Extensions = { "dll", "exe" } } }; + var filename = await dlg.ShowAsync(MainWindow.Instance); + if (filename != null) { + asm.MainModule.Write(filename); + } + } + } + } +} diff --git a/TestPlugin/CustomLanguage.cs b/TestPlugin/CustomLanguage.cs new file mode 100644 index 0000000..0425098 --- /dev/null +++ b/TestPlugin/CustomLanguage.cs @@ -0,0 +1,59 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System.ComponentModel.Composition; +using Avalonia.Controls; +using ICSharpCode.Decompiler; +using AvaloniaILSpy; +using Mono.Cecil; + +namespace TestPlugin +{ + /// + /// Adds a new language to the decompiler. + /// + [Export(typeof(Language))] + public class CustomLanguage : Language + { + public override string Name { + get { + return "Custom"; + } + } + + public override string FileExtension { + get { + // used in 'Save As' dialog + return ".txt"; + } + } + + // There are several methods available to override; in this sample, we deal with methods only + + public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) + { + if (method.Body != null) { + output.WriteLine("Size of method: {0} bytes", method.Body.CodeSize); + + ISmartTextOutput smartOutput = output as ISmartTextOutput; + if (smartOutput != null) { + // when writing to the text view (but not when writing to a file), we can even add UI elements such as buttons: + smartOutput.AddButton(null, "Click me!", (sender, e) => (sender as Button).Content = "I was clicked!"); + smartOutput.WriteLine(); + } + + // ICSharpCode.Decompiler.CSharp.CSharpDecompiler can be used to decompile to C#. + /* + ModuleDefinition module = LoadModule(assemblyFileName); + var typeSystem = new DecompilerTypeSystem(module); + CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, new DecompilerSettings()); + + decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers()); + SyntaxTree syntaxTree = decompiler.DecompileWholeModuleAsSingleFile(); + var visitor = new CSharpOutputVisitor(output, FormattingOptionsFactory.CreateSharpDevelop()); + syntaxTree.AcceptVisitor(visitor); + */ + } + } + } +} diff --git a/TestPlugin/CustomOptionPage.xaml b/TestPlugin/CustomOptionPage.xaml new file mode 100644 index 0000000..8c19077 --- /dev/null +++ b/TestPlugin/CustomOptionPage.xaml @@ -0,0 +1,8 @@ + + + Useless option 1 + + + \ No newline at end of file diff --git a/TestPlugin/CustomOptionPage.xaml.cs b/TestPlugin/CustomOptionPage.xaml.cs new file mode 100644 index 0000000..ec70af7 --- /dev/null +++ b/TestPlugin/CustomOptionPage.xaml.cs @@ -0,0 +1,94 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System.ComponentModel; +using Avalonia.Controls; +using System.Xml.Linq; +using AvaloniaILSpy; +using AvaloniaILSpy.Options; +using System; +using Avalonia.Markup.Xaml; + +namespace TestPlugin +{ + [ExportOptionPage(Title = "TestPlugin", Order = 0)] + partial class CustomOptionPage : UserControl, IOptionPage + { + static readonly XNamespace ns = "http://www.ilspy.net/testplugin"; + + public CustomOptionPage() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + public void Load(ILSpySettings settings) + { + // For loading options, use ILSpySetting's indexer. + // If the specified section does exist, the indexer will return a new empty element. + XElement e = settings[ns + "CustomOptions"]; + // Now load the options from the XML document: + Options s = new Options(); + s.UselessOption1 = (bool?)e.Attribute("useless1") ?? s.UselessOption1; + s.UselessOption2 = (double?)e.Attribute("useless2") ?? s.UselessOption2; + this.DataContext = s; + } + + public void Save(XElement root) + { + Options s = (Options)this.DataContext; + // Save the options back into XML: + XElement section = new XElement(ns + "CustomOptions"); + section.SetAttributeValue("useless1", s.UselessOption1); + section.SetAttributeValue("useless2", s.UselessOption2); + + // Replace the existing section in the settings file, or add a new section, + // if required. + XElement existingElement = root.Element(ns + "CustomOptions"); + if (existingElement != null) + existingElement.ReplaceWith(section); + else + root.Add(section); + } + } + + class Options : INotifyPropertyChanged + { + bool uselessOption1; + + public bool UselessOption1 { + get { return uselessOption1; } + set { + if (uselessOption1 != value) { + uselessOption1 = value; + OnPropertyChanged("UselessOption1"); + } + } + } + + double uselessOption2; + + public double UselessOption2 { + get { return uselessOption2; } + set { + if (uselessOption2 != value) { + uselessOption2 = value; + OnPropertyChanged("UselessOption2"); + } + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void OnPropertyChanged(string propertyName) + { + if (PropertyChanged != null) { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + } +} \ No newline at end of file diff --git a/TestPlugin/MainMenuCommand.cs b/TestPlugin/MainMenuCommand.cs new file mode 100644 index 0000000..8f5c971 --- /dev/null +++ b/TestPlugin/MainMenuCommand.cs @@ -0,0 +1,28 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using AvaloniaILSpy; + +namespace TestPlugin +{ + // Menu: menu into which the item is added + // MenuIcon: optional, icon to use for the menu item. Must be embedded as "Resource" (WPF-style resource) in the same assembly as the command type. + // Header: text on the menu item + // MenuCategory: optional, used for grouping related menu items together. A separator is added between different groups. + // MenuOrder: controls the order in which the items appear (items are sorted by this value) + [ExportMainMenuCommand(Menu = "_File", MenuIcon = "TestPlugin.Clear.png", Header = "_Clear List", MenuCategory = "Open", MenuOrder = 1.5)] + // ToolTip: the tool tip + // ToolbarIcon: The icon. Must be embedded as "Resource" (WPF-style resource) in the same assembly as the command type. + // ToolbarCategory: optional, used for grouping related toolbar items together. A separator is added between different groups. + // ToolbarOrder: controls the order in which the items appear (items are sorted by this value) + [ExportToolbarCommand(ToolTip = "Clears the current assembly list", ToolbarIcon = "TestPlugin.Clear.png", ToolbarCategory = "Open", ToolbarOrder = 1.5)] + public class UnloadAllAssembliesCommand : SimpleCommand + { + public override void Execute(object parameter) + { + foreach (var loadedAssembly in MainWindow.Instance.CurrentAssemblyList.GetAssemblies()) { + loadedAssembly.AssemblyList.Unload(loadedAssembly); + } + } + } +} diff --git a/TestPlugin/Properties/AssemblyInfo.cs b/TestPlugin/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..600568b --- /dev/null +++ b/TestPlugin/Properties/AssemblyInfo.cs @@ -0,0 +1,30 @@ +#region Using directives + +using System.Reflection; +using System.Runtime.InteropServices; + +#endregion + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestPlugin")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestPlugin")] +[assembly: AssemblyCopyright("Copyright 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all the values or you can use the default the Revision and +// Build Numbers by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] diff --git a/TestPlugin/Properties/launchSettings.json b/TestPlugin/Properties/launchSettings.json new file mode 100644 index 0000000..3578e8a --- /dev/null +++ b/TestPlugin/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "profiles": { + "TestPlugin": { + "commandName": "Executable", + "executablePath": "$(OutDir)ILSpy.exe", + "commandLineArgs": "/separate" + } + } +} \ No newline at end of file diff --git a/TestPlugin/Readme.txt b/TestPlugin/Readme.txt new file mode 100644 index 0000000..ab910e5 --- /dev/null +++ b/TestPlugin/Readme.txt @@ -0,0 +1,69 @@ +ILSpy uses MEF (Managed Extensibility Framework) for plugins. +Plugins must be placed in the same directory as ILSpy.exe, and must be called "*.Plugin.dll". + +To write a plugin, you need to add a reference to ILSpy.exe and to System.ComponentModel.Composition. +Depending on what your plugin is doing, you might also need references to the other libraries shipping with ILSpy. + +Plugins work by exporting types for certain extension points. +Here is a list of extension points: + +Adding another language: + + [Export(typeof(Language))] + public class CustomLanguage : Language + + This adds an additional language to the combobox in the toolbar. + The language has to implement its own decompiler (all the way from IL), but it can also re-use + the ICSharpCode.Decompiler library to decompile to C#, and then translate the C# code to the target language. + +--- + +Adding an entry to the main menu: + + [ExportMainMenuCommand(Menu = "_File", MenuIcon = "Clear.png", Header = "_Clear List", MenuCategory = "Open", MenuOrder = 1.5)] + public class UnloadAllAssembliesCommand : SimpleCommand + + Menu: menu into which the item is added + MenuIcon: optional, icon to use for the menu item. Must be embedded as "Resource" (WPF-style resource) in the same assembly as the command type. + Header: text on the menu item + MenuCategory: optional, used for grouping related menu items together. A separator is added between different groups. + MenuOrder: controls the order in which the items appear (items are sorted by this value) + + The command class must implement WPF's ICommand interface. + +--- + +Adding an entry to the tool bar: + + [ExportToolbarCommand(ToolTip = "Clears the current assembly list", ToolbarIcon = "Clear.png", ToolbarCategory = "Open", ToolbarOrder = 1.5)] + public class UnloadAllAssembliesCommand : SimpleCommand + + ToolTip: the tool tip + ToolbarIcon: The icon. Must be embedded as "Resource" (WPF-style resource) in the same assembly as the command type. + ToolbarCategory: optional, used for grouping related toolbar items together. A separator is added between different groups. + ToolbarOrder: controls the order in which the items appear (items are sorted by this value) + + The command class must implement WPF's ICommand interface. + +--- + +Adding an entry to the context menu: + + [ExportContextMenuEntry(Header = "_Save Assembly")] + public class SaveAssembly : IContextMenuEntry + + Icon: optional, icon to use for the menu item. Must be embedded as "Resource" (WPF-style resource) in the same assembly as the command type. + Header: text on the menu item + Category: optional, used for grouping related menu items together. A separator is added between different groups. + Order: controls the order in which the items appear (items are sorted by this value) + + Context menu entries must implement IContextMenuEntry, which defines 3 methods: + bool IsVisible, bool IsEnabled, and void Execute. + +--- + +Adding an option page: + + [ExportOptionPage("TestPlugin")] + partial class CustomOptionPage : UserControl, IOptionPage + diff --git a/TestPlugin/TestPlugin.csproj b/TestPlugin/TestPlugin.csproj new file mode 100644 index 0000000..107f495 --- /dev/null +++ b/TestPlugin/TestPlugin.csproj @@ -0,0 +1,50 @@ + + + + + netstandard2.0 + Test.Plugin + + False + + False + + + + full + true + True + + + + pdbonly + true + + + + + + + + + %(Filename) + Code + + + Designer + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.cake b/build.cake index afaa102..bc993fc 100644 --- a/build.cake +++ b/build.cake @@ -11,12 +11,12 @@ var zipRootDir = artifactsDir.Combine("zips"); var fileZipSuffix = ".zip"; var netCoreAppsRoot= "."; -var netCoreApp = "AvaloniaILSpy"; +var netCoreApp = "AvaloniaILSpy.NetCore"; var buildDirs = GetDirectories($"{netCoreAppsRoot}/**/bin/**") + GetDirectories($"{netCoreAppsRoot}/**/obj/**") + - GetDirectories($"{netCoreAppsRoot}/artifacts/**/zips/**"); + GetDirectories($"{netCoreAppsRoot}/artifacts/**"); var netCoreProject = new { Path = $"{netCoreAppsRoot}/{netCoreApp}",