diff options
-rw-r--r-- | Mono.Addins.Setup/Mono.Addins.Setup/SetupService.cs | 167 | ||||
-rw-r--r-- | Mono.Addins.Setup/Mono.Addins.Setup/SetupTool.cs | 23 | ||||
-rw-r--r-- | Mono.Addins/Mono.Addins.Description/AddinDescription.cs | 97 | ||||
-rw-r--r-- | Mono.Addins/Mono.Addins.Description/PackageFormat.cs | 32 | ||||
-rw-r--r-- | Mono.Addins/Mono.Addins.csproj | 1 |
5 files changed, 290 insertions, 30 deletions
diff --git a/Mono.Addins.Setup/Mono.Addins.Setup/SetupService.cs b/Mono.Addins.Setup/Mono.Addins.Setup/SetupService.cs index ce9ab5c..a05bb84 100644 --- a/Mono.Addins.Setup/Mono.Addins.Setup/SetupService.cs +++ b/Mono.Addins.Setup/Mono.Addins.Setup/SetupService.cs @@ -367,14 +367,49 @@ namespace Mono.Addins.Setup { List<string> outFiles = new List<string> (); foreach (string file in filePaths) { - string f = BuildPackageInternal (statusMonitor, debugSymbols, targetDirectory, file); + string f = BuildPackageInternal (statusMonitor, debugSymbols, targetDirectory, file, PackageFormat.Mpack); + if (f != null) + outFiles.Add (f); + } + return outFiles.ToArray (); + } + + /// <summary> + /// Packages an add-in + /// </summary> + /// <param name="statusMonitor"> + /// Progress monitor where to show progress status + /// </param> + /// <param name="debugSymbols"> + /// True if debug symbols (.pdb or .mdb) should be included in the package, if they exist + /// </param> + /// <param name="targetDirectory"> + /// Directory where to generate the package + /// </param> + /// <param name="format"> + /// Which format to produce .mpack or .vsix + /// </param> + /// <param name="filePaths"> + /// Paths to the add-ins to be packaged. Paths can be either the main assembly of an add-in, or an add-in + /// manifest (.addin or .addin.xml). + /// </param> + /// <remarks> + /// This method can be used to create a package for an add-in, which can then be pushed to an on-line + /// repository. The package will include the main assembly or manifest of the add-in and any external + /// file declared in the add-in metadata. + /// </remarks> + public string [] BuildPackage (IProgressStatus statusMonitor, bool debugSymbols, string targetDirectory, PackageFormat format , params string [] filePaths) + { + List<string> outFiles = new List<string> (); + foreach (string file in filePaths) { + string f = BuildPackageInternal (statusMonitor, debugSymbols, targetDirectory, file, format); if (f != null) outFiles.Add (f); } return outFiles.ToArray (); } - string BuildPackageInternal (IProgressStatus monitor, bool debugSymbols, string targetDirectory, string filePath) + string BuildPackageInternal (IProgressStatus monitor, bool debugSymbols, string targetDirectory, string filePath, PackageFormat format) { AddinDescription conf = registry.GetAddinDescription (monitor, filePath); if (conf == null) { @@ -396,30 +431,59 @@ namespace Mono.Addins.Setup name = conf.LocalId; name = Addin.GetFullId (conf.Namespace, name, conf.Version); name = name.Replace (',','_').Replace (".__", "."); - - string outFilePath = Path.Combine (targetDirectory, name) + ".mpack"; + + string outFilePath = Path.Combine (targetDirectory, name); + switch(format){ + case PackageFormat.Mpack: + outFilePath += ".mpack"; + break; + case PackageFormat.Vsix: + outFilePath += ".vsix"; + break; + default: + throw new NotSupportedException (format.ToString ()); + } ZipOutputStream s = new ZipOutputStream (File.Create (outFilePath)); s.SetLevel(5); - + + if (format == PackageFormat.Vsix) { + XmlDocument doc = new XmlDocument (); + doc.PreserveWhitespace = false; + doc.LoadXml (conf.SaveToVsixXml ().OuterXml); + MemoryStream ms = new MemoryStream (); + XmlTextWriter tw = new XmlTextWriter (ms, System.Text.Encoding.UTF8); + tw.Formatting = Formatting.Indented; + doc.WriteTo (tw); + tw.Flush (); + byte [] data = ms.ToArray (); + + var infoEntry = new ZipEntry ("extension.vsixmanifest") { Size = data.Length }; + s.PutNextEntry (infoEntry); + s.Write (data, 0, data.Length); + s.CloseEntry (); + } + // Generate a stripped down description of the add-in in a file, since the complete // description may be declared as assembly attributes - - XmlDocument doc = new XmlDocument (); - doc.PreserveWhitespace = false; - doc.LoadXml (conf.SaveToXml ().OuterXml); - CleanDescription (doc.DocumentElement); - MemoryStream ms = new MemoryStream (); - XmlTextWriter tw = new XmlTextWriter (ms, System.Text.Encoding.UTF8); - tw.Formatting = Formatting.Indented; - doc.WriteTo (tw); - tw.Flush (); - byte[] data = ms.ToArray (); - - var infoEntry = new ZipEntry ("addin.info") { Size = data.Length }; - s.PutNextEntry (infoEntry); - s.Write (data, 0, data.Length); - s.CloseEntry (); + + if (format == PackageFormat.Mpack || format == PackageFormat.Vsix) { + XmlDocument doc = new XmlDocument (); + doc.PreserveWhitespace = false; + doc.LoadXml (conf.SaveToXml ().OuterXml); + CleanDescription (doc.DocumentElement); + MemoryStream ms = new MemoryStream (); + XmlTextWriter tw = new XmlTextWriter (ms, System.Text.Encoding.UTF8); + tw.Formatting = Formatting.Indented; + doc.WriteTo (tw); + tw.Flush (); + byte [] data = ms.ToArray (); + + var infoEntry = new ZipEntry ("addin.info") { Size = data.Length }; + s.PutNextEntry (infoEntry); + s.Write (data, 0, data.Length); + s.CloseEntry (); + } // Now add the add-in files @@ -473,12 +537,67 @@ namespace Mono.Addins.Setup s.CloseEntry (); } } - - s.Finish(); - s.Close(); + + if (format == PackageFormat.Vsix) { + files.Add ("addin.info"); + files.Add ("extension.vsixmanifest"); + XmlDocument doc = new XmlDocument (); + doc.PreserveWhitespace = false; + XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration ("1.0", "UTF-8", null); + XmlElement root = doc.DocumentElement; + doc.InsertBefore (xmlDeclaration, root); + HashSet<string> alreadyAddedExtensions = new HashSet<string> (); + var typesEl = doc.CreateElement ("Types"); + typesEl.SetAttribute ("xmlns", "http://schemas.openxmlformats.org/package/2006/content-types"); + foreach (var file in files) { + var extension = Path.GetExtension (file); + if (alreadyAddedExtensions.Contains (extension)) + continue; + alreadyAddedExtensions.Add (extension); + var typeEl = doc.CreateElement ("Default"); + typeEl.SetAttribute ("Extension", extension); + typeEl.SetAttribute ("ContentType", GetContentType (extension)); + typesEl.AppendChild (typeEl); + } + doc.AppendChild (typesEl); + MemoryStream ms = new MemoryStream (); + XmlTextWriter tw = new XmlTextWriter (ms, System.Text.Encoding.UTF8); + tw.Formatting = Formatting.Indented; + doc.WriteTo (tw); + tw.Flush (); + byte [] data = ms.ToArray (); + + var infoEntry = new ZipEntry ("[Content_Types].xml") { Size = data.Length }; + s.PutNextEntry (infoEntry); + s.Write (data, 0, data.Length); + s.CloseEntry (); + } + + s.Finish (); + s.Close (); return outFilePath; } + static string GetContentType (string extension) + { + switch (extension) { + case "txt": return "text/plain"; + case "pkgdef": return "text/plain"; + case "xml": return "text/xml"; + case "vsixmanifest": return "text/xml"; + case "htm or html": return "text/html"; + case "rtf": return "application/rtf"; + case "pdf": return "application/pdf"; + case "gif": return "image/gif"; + case "jpg or jpeg": return "image/jpg"; + case "tiff": return "image/tiff"; + case "vsix": return "application/zip"; + case "zip": return "application/zip"; + case "dll": return "application/octet-stream"; + default: return "application/octet-stream"; + } + } + class SatelliteAssemblyFinder { Dictionary<string, List<string>> cultureSubdirCache = new Dictionary<string, List<string>> (); diff --git a/Mono.Addins.Setup/Mono.Addins.Setup/SetupTool.cs b/Mono.Addins.Setup/Mono.Addins.Setup/SetupTool.cs index ab678a7..2b74796 100644 --- a/Mono.Addins.Setup/Mono.Addins.Setup/SetupTool.cs +++ b/Mono.Addins.Setup/Mono.Addins.Setup/SetupTool.cs @@ -469,13 +469,24 @@ namespace Mono.Addins.Setup throw new InstallException ("A directory name is required."); service.BuildRepository (new ConsoleProgressStatus (verbose), args[0]); } - - void BuildPackage (string[] args) + + void BuildPackage (string [] args) { if (args.Length < 1) throw new InstallException ("A file name is required."); - - service.BuildPackage (new ConsoleProgressStatus (verbose), bool.Parse (GetOption ("debugSymbols", "false")), GetOption ("d", "."), GetArguments ()); + var formatString = GetOption ("format", "mpack"); + PackageFormat format; + switch (formatString) { + case "mpack": + format = PackageFormat.Mpack; + break; + case "vsix": + format = PackageFormat.Vsix; + break; + default: + throw new ArgumentException ($"Unsupported package format \"{formatString}\", supported formats are mpack and vsix."); + } + service.BuildPackage (new ConsoleProgressStatus (verbose), bool.Parse (GetOption ("debugSymbols", "false")), GetOption ("d", "."), format, GetArguments ()); } void PrintLibraries (string[] args) @@ -1111,8 +1122,8 @@ namespace Mono.Addins.Setup cmd = new SetupCommand (cat, "pack", "p", new SetupCommandHandler (BuildPackage)); cmd.Description = "Creates a package from an add-in configuration file."; - cmd.Usage = "<file-path> [-d:output-directory] [-debugSymbols:(true|false)]"; - cmd.AppendDesc ("Creates an add-in package (.mpack file) which includes all files "); + cmd.Usage = "<file-path> [-d:output-directory] [-format:(mpack|vsix)] [-debugSymbols:(true|false)]"; + cmd.AppendDesc ("Creates an add-in package (.mpack or .vsix file) which includes all files "); cmd.AppendDesc ("needed to deploy an add-in. The command parameter is the path to"); cmd.AppendDesc ("the add-in's configuration file. If 'debugSymbols' is set to true"); cmd.AppendDesc ("then pdb or mdb debug symbols will automatically be included in the"); diff --git a/Mono.Addins/Mono.Addins.Description/AddinDescription.cs b/Mono.Addins/Mono.Addins.Description/AddinDescription.cs index 158dbec..4d3bf62 100644 --- a/Mono.Addins/Mono.Addins.Description/AddinDescription.cs +++ b/Mono.Addins/Mono.Addins.Description/AddinDescription.cs @@ -892,6 +892,103 @@ namespace Mono.Addins.Description } } } + + public XmlDocument SaveToVsixXml () + { + if (!canWrite) + throw new InvalidOperationException ("Can't write incomplete description."); + + XmlElement packageManifestEl; + + var vsixDoc = new XmlDocument (); + vsixDoc.AppendChild (vsixDoc.CreateElement ("PackageManifest")); + + packageManifestEl = vsixDoc.DocumentElement; + packageManifestEl.SetAttribute ("Version", "2.0.0"); + packageManifestEl.SetAttribute ("xmlns", "http://schemas.microsoft.com/developer/vsx-schema/2011"); + + var metadata = vsixDoc.CreateElement ("Metadata"); + var identity = vsixDoc.CreateElement ("Identity"); + identity.SetAttribute ("Language", "en-US"); + identity.SetAttribute ("Id", LocalId); + identity.SetAttribute ("Version", Version); + identity.SetAttribute ("Publisher", Properties.GetPropertyValue ("VisualStudio.Publisher")); + metadata.AppendChild (identity); + + var displayNameEl = vsixDoc.CreateElement ("DisplayName"); + displayNameEl.InnerText = Name; + metadata.AppendChild (displayNameEl); + + var descriptionEl = vsixDoc.CreateElement ("Description"); + descriptionEl.SetAttribute ("xml:space", "preserve"); + descriptionEl.InnerText = Description; + metadata.AppendChild (descriptionEl); + + var moreInfoEl = vsixDoc.CreateElement ("MoreInfo"); + moreInfoEl.InnerText = Url; + metadata.AppendChild (moreInfoEl); + + var tagsEl = vsixDoc.CreateElement ("Tags"); + if (!string.IsNullOrEmpty (Properties.GetPropertyValue ("VisualStudio.Tags"))) + tagsEl.InnerText = Properties.GetPropertyValue ("VisualStudio.Tags"); + metadata.AppendChild (tagsEl); + + var categoriesEl = vsixDoc.CreateElement ("Categories"); + categoriesEl.InnerText = Category; + metadata.AppendChild (categoriesEl); + + var galleryFlagsEl = vsixDoc.CreateElement ("GalleryFlags"); + var galleryFlags = Properties.GetPropertyValue ("VisualStudio.GalleryFlags"); + if (string.IsNullOrEmpty (galleryFlags)) + galleryFlags = "Public"; + galleryFlagsEl.InnerText = galleryFlags; + metadata.AppendChild (galleryFlagsEl); + + var badgesEl = vsixDoc.CreateElement ("Badges"); + //TODO:Add Badges support + metadata.AppendChild (badgesEl); + + var icon = Properties.GetPropertyValue ("Icon32"); + if (!string.IsNullOrEmpty (icon)) { + var iconEl = vsixDoc.CreateElement ("Icon"); + iconEl.InnerText = icon; + metadata.AppendChild (iconEl); + } + var license = Copyright; + if (!string.IsNullOrEmpty (license)) { + var licenseEl = vsixDoc.CreateElement ("License"); + licenseEl.InnerText = license; + metadata.AppendChild (licenseEl); + } + + packageManifestEl.AppendChild (metadata); + + var installationEl = vsixDoc.CreateElement ("Installation"); + var installationTargetEl = vsixDoc.CreateElement ("InstallationTarget"); + installationTargetEl.SetAttribute ("Id", "Microsoft.VisualStudio.Mac"); + installationEl.AppendChild (installationTargetEl); + packageManifestEl.AppendChild (installationEl); + + packageManifestEl.AppendChild (vsixDoc.CreateElement ("Dependencies")); + + var assetsEl = vsixDoc.CreateElement ("Assets"); + var addinInfoAsset = vsixDoc.CreateElement ("Asset"); + addinInfoAsset.SetAttribute ("Type", "Microsoft.VisualStudio.Mac.AddinInfo"); + addinInfoAsset.SetAttribute ("Path", "addin.info"); + addinInfoAsset.SetAttribute ("Addressable", "true"); + assetsEl.AppendChild (addinInfoAsset); + + if (!string.IsNullOrEmpty (icon)) { + var iconAsset = vsixDoc.CreateElement ("Asset"); + iconAsset.SetAttribute ("Type", "Microsoft.VisualStudio.Services.Icons.Default"); + iconAsset.SetAttribute ("Path", icon); + iconAsset.SetAttribute ("Addressable", "true"); + assetsEl.AppendChild (iconAsset); + } + packageManifestEl.AppendChild (assetsEl); + + return vsixDoc; + } void SaveCoreProperty (XmlElement elem, string val, string attr, string prop) { diff --git a/Mono.Addins/Mono.Addins.Description/PackageFormat.cs b/Mono.Addins/Mono.Addins.Description/PackageFormat.cs new file mode 100644 index 0000000..8a22673 --- /dev/null +++ b/Mono.Addins/Mono.Addins.Description/PackageFormat.cs @@ -0,0 +1,32 @@ +// +// PackageFormat.cs +// +// Author: +// David Karlaš +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +namespace Mono.Addins.Description +{ + public enum PackageFormat + { + Mpack, + Vsix + } +} diff --git a/Mono.Addins/Mono.Addins.csproj b/Mono.Addins/Mono.Addins.csproj index a4522af..e7a1d01 100644 --- a/Mono.Addins/Mono.Addins.csproj +++ b/Mono.Addins/Mono.Addins.csproj @@ -155,6 +155,7 @@ <Compile Include="Mono.Addins\AddinCategoryAttribute.cs" /> <Compile Include="Mono.Addins\AddinFlagsAttribute.cs" /> <Compile Include="Mono.Addins\AddinLocalizerAttribute.cs" /> + <Compile Include="Mono.Addins.Description\PackageFormat.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> </Project> |