2010-07-22 22:09:34 -07:00
using System ;
using System.Collections.Generic ;
2010-07-04 14:14:15 -07:00
using System.IO ;
using System.Linq ;
2010-07-18 12:36:02 -07:00
using System.Net.Mime ;
2010-07-04 14:14:15 -07:00
using System.Reflection ;
using System.Xml.Linq ;
2010-10-29 12:17:26 -07:00
using NuGet ;
2011-03-22 11:34:56 -07:00
using Orchard.Environment ;
2010-07-04 14:14:15 -07:00
using Orchard.Environment.Extensions ;
using Orchard.Environment.Extensions.Models ;
2011-03-21 20:37:10 -07:00
using Orchard.FileSystems.VirtualPath ;
2010-07-04 14:14:15 -07:00
using Orchard.FileSystems.WebSite ;
2011-03-21 20:37:10 -07:00
using Orchard.Utility.Extensions ;
2010-10-29 12:17:26 -07:00
using NuGetPackageBuilder = NuGet . PackageBuilder ;
2010-10-27 11:19:17 -07:00
2010-07-22 22:09:34 -07:00
namespace Orchard.Packaging.Services {
[OrchardFeature("PackagingServices")]
2010-07-04 14:14:15 -07:00
public class PackageBuilder : IPackageBuilder {
private readonly IWebSiteFolder _webSiteFolder ;
2011-03-21 20:37:10 -07:00
private readonly IVirtualPathProvider _virtualPathProvider ;
2011-03-22 11:34:56 -07:00
private readonly IOrchardFrameworkAssemblies _frameworkAssemblies ;
2010-07-04 14:14:15 -07:00
2010-10-04 14:52:46 -07:00
private static readonly string [ ] _ignoredThemeExtensions = new [ ] {
"obj" , "pdb" , "exclude"
} ;
2011-01-07 09:58:17 -08:00
2010-10-04 14:52:46 -07:00
private static readonly string [ ] _ignoredThemePaths = new [ ] {
"/obj/"
} ;
private static bool IgnoreFile ( string filePath ) {
return String . IsNullOrEmpty ( filePath ) | |
_ignoredThemePaths . Any ( filePath . Contains ) | |
_ignoredThemeExtensions . Contains ( Path . GetExtension ( filePath ) ? ? "" ) ;
}
2011-03-21 20:37:10 -07:00
public PackageBuilder ( IWebSiteFolder webSiteFolder ,
2011-03-22 11:34:56 -07:00
IVirtualPathProvider virtualPathProvider ,
IOrchardFrameworkAssemblies frameworkAssemblies ) {
2010-07-04 14:14:15 -07:00
_webSiteFolder = webSiteFolder ;
2011-03-21 20:37:10 -07:00
_virtualPathProvider = virtualPathProvider ;
2011-03-22 11:34:56 -07:00
_frameworkAssemblies = frameworkAssemblies ;
2010-07-04 14:14:15 -07:00
}
2010-07-06 18:56:55 -07:00
public Stream BuildPackage ( ExtensionDescriptor extensionDescriptor ) {
2010-07-04 14:14:15 -07:00
var context = new CreateContext ( ) ;
BeginPackage ( context ) ;
2010-07-06 18:56:55 -07:00
try {
2010-11-18 15:37:47 -08:00
EstablishPaths ( context , _webSiteFolder , extensionDescriptor . Location , extensionDescriptor . Id , extensionDescriptor . ExtensionType ) ;
2010-07-06 18:56:55 -07:00
SetCoreProperties ( context , extensionDescriptor ) ;
2010-07-04 14:14:15 -07:00
2010-11-18 15:37:47 -08:00
string projectFile = extensionDescriptor . Id + ".csproj" ;
2010-07-06 18:56:55 -07:00
if ( LoadProject ( context , projectFile ) ) {
2010-07-18 14:29:31 -07:00
EmbedVirtualFile ( context , projectFile , MediaTypeNames . Text . Xml ) ;
2010-07-06 18:56:55 -07:00
EmbedProjectFiles ( context , "Compile" , "Content" , "None" , "EmbeddedResource" ) ;
EmbedReferenceFiles ( context ) ;
2010-12-01 17:52:10 -08:00
} else if ( DefaultExtensionTypes . IsTheme ( extensionDescriptor . ExtensionType ) ) {
2010-10-04 14:52:46 -07:00
// this is a simple theme with no csproj
EmbedThemeFiles ( context ) ;
}
2010-07-06 18:56:55 -07:00
}
finally {
EndPackage ( context ) ;
2010-07-04 14:14:15 -07:00
}
2010-07-22 22:09:34 -07:00
if ( context . Stream . CanSeek ) {
2010-07-19 18:08:03 -07:00
context . Stream . Seek ( 0 , SeekOrigin . Begin ) ;
2010-07-22 22:09:34 -07:00
}
2010-07-19 18:08:03 -07:00
2010-07-04 14:14:15 -07:00
return context . Stream ;
}
2011-01-07 09:58:17 -08:00
public static string BuildPackageId ( string extensionName , string extensionType ) {
return PackagingSourceManager . GetExtensionPrefix ( extensionType ) + extensionName ;
}
2010-12-07 16:11:29 -08:00
private static void SetCoreProperties ( CreateContext context , ExtensionDescriptor extensionDescriptor ) {
2011-01-07 09:58:17 -08:00
context . Builder . Id = BuildPackageId ( extensionDescriptor . Id , extensionDescriptor . ExtensionType ) ;
2010-10-27 11:19:17 -07:00
context . Builder . Version = new Version ( extensionDescriptor . Version ) ;
2010-11-18 15:37:47 -08:00
context . Builder . Title = extensionDescriptor . Name ? ? extensionDescriptor . Id ;
2010-10-27 11:19:17 -07:00
context . Builder . Description = extensionDescriptor . Description ;
context . Builder . Authors . Add ( extensionDescriptor . Author ) ;
2010-07-04 14:14:15 -07:00
2010-11-03 17:45:35 -07:00
if ( Uri . IsWellFormedUriString ( extensionDescriptor . WebSite , UriKind . Absolute ) ) {
context . Builder . ProjectUrl = new Uri ( extensionDescriptor . WebSite ) ;
}
}
2010-12-07 16:11:29 -08:00
private static void EmbedProjectFiles ( CreateContext context , params string [ ] itemGroupTypes ) {
2010-07-22 22:09:34 -07:00
IEnumerable < XElement > itemGroups = context . Project
2010-07-04 14:14:15 -07:00
. Elements ( Ns ( "Project" ) )
. Elements ( Ns ( "ItemGroup" ) ) ;
2010-07-22 22:09:34 -07:00
foreach ( string itemGroupType in itemGroupTypes ) {
IEnumerable < string > includePaths = itemGroups
2010-07-04 14:14:15 -07:00
. Elements ( Ns ( itemGroupType ) )
. Attributes ( "Include" )
. Select ( x = > x . Value ) ;
2010-07-22 22:09:34 -07:00
foreach ( string includePath in includePaths ) {
2010-07-18 12:36:02 -07:00
EmbedVirtualFile ( context , includePath , MediaTypeNames . Application . Octet ) ;
2010-07-04 14:14:15 -07:00
}
}
}
2011-03-21 20:37:10 -07:00
private void EmbedReferenceFiles ( CreateContext context ) {
2010-07-04 14:14:15 -07:00
var entries = context . Project
. Elements ( Ns ( "Project" ) )
. Elements ( Ns ( "ItemGroup" ) )
. Elements ( Ns ( "Reference" ) )
. Select ( reference = > new {
Include = reference . Attribute ( "Include" ) ,
HintPath = reference . Element ( Ns ( "HintPath" ) )
} )
. Where ( entry = > entry . Include ! = null ) ;
foreach ( var entry in entries ) {
var assemblyName = new AssemblyName ( entry . Include . Value ) ;
2011-03-22 11:34:56 -07:00
// If it is not a core assembly
2011-03-22 12:04:42 -07:00
if ( _frameworkAssemblies . GetFrameworkAssemblies ( ) . FirstOrDefault ( assembly = > assembly . Name . Equals ( assemblyName . Name ) ) = = null ) {
2011-03-22 11:34:56 -07:00
string virtualPath = _virtualPathProvider . GetReferenceVirtualPath ( context . SourcePath , assemblyName . Name , entry . HintPath ! = null ? entry . HintPath . Value : null ) ;
if ( ! string . IsNullOrEmpty ( virtualPath ) ) {
EmbedVirtualFile ( context , virtualPath , MediaTypeNames . Application . Octet ) ;
}
2010-07-04 14:14:15 -07:00
}
}
}
2010-12-07 16:11:29 -08:00
private static void EmbedThemeFiles ( CreateContext context ) {
2010-10-05 11:39:31 -07:00
var basePath = context . SourcePath ;
2010-10-04 14:52:46 -07:00
foreach ( var virtualPath in context . SourceFolder . ListFiles ( context . SourcePath , true ) ) {
// ignore dlls, etc
if ( IgnoreFile ( virtualPath ) ) {
continue ;
}
// full virtual path given but we need the relative path so it can be put into
// the package that way (the package itself is the logical base path).
// Get it by stripping the basePath off including the slash.
var relativePath = virtualPath . Replace ( basePath , "" ) ;
EmbedVirtualFile ( context , relativePath , MediaTypeNames . Application . Octet ) ;
}
}
2010-12-07 16:11:29 -08:00
private static XName Ns ( string localName ) {
2010-07-04 14:14:15 -07:00
return XName . Get ( localName , "http://schemas.microsoft.com/developer/msbuild/2003" ) ;
}
2010-07-22 22:09:34 -07:00
private static void BeginPackage ( CreateContext context ) {
2010-10-29 12:17:26 -07:00
context . Stream = new MemoryStream ( ) ;
context . Builder = new NuGetPackageBuilder ( ) ;
2010-07-04 14:14:15 -07:00
}
2010-10-04 14:52:46 -07:00
private static void EstablishPaths ( CreateContext context , IWebSiteFolder webSiteFolder , string locationPath , string moduleName , string moduleType ) {
2010-07-04 14:14:15 -07:00
context . SourceFolder = webSiteFolder ;
2010-12-01 17:52:10 -08:00
if ( DefaultExtensionTypes . IsTheme ( moduleType ) ) {
2010-10-04 14:52:46 -07:00
context . SourcePath = "~/Themes/" + moduleName + "/" ;
2010-11-10 16:09:20 -08:00
context . TargetPath = "\\Content\\Themes\\" + moduleName + "\\" ;
2010-10-04 14:52:46 -07:00
}
else {
context . SourcePath = "~/Modules/" + moduleName + "/" ;
2010-11-10 16:09:20 -08:00
context . TargetPath = "\\Content\\Modules\\" + moduleName + "\\" ;
2010-10-04 14:52:46 -07:00
}
2010-07-04 14:14:15 -07:00
}
2010-07-22 22:09:34 -07:00
private static bool LoadProject ( CreateContext context , string relativePath ) {
string virtualPath = context . SourcePath + relativePath ;
2010-07-04 14:14:15 -07:00
if ( context . SourceFolder . FileExists ( virtualPath ) ) {
context . Project = XDocument . Parse ( context . SourceFolder . ReadFile ( context . SourcePath + relativePath ) ) ;
return true ;
}
return false ;
}
2010-10-27 11:19:17 -07:00
private static void EmbedVirtualFile ( CreateContext context , string relativePath , string contentType ) {
2010-10-29 12:17:26 -07:00
var file = new VirtualPackageFile (
context . SourceFolder ,
context . SourcePath + relativePath ,
context . TargetPath + relativePath ) ;
2010-10-27 11:19:17 -07:00
context . Builder . Files . Add ( file ) ;
2010-07-04 14:14:15 -07:00
}
2010-07-22 22:09:34 -07:00
private static void EndPackage ( CreateContext context ) {
2010-10-27 11:19:17 -07:00
context . Builder . Save ( context . Stream ) ;
2010-07-04 14:14:15 -07:00
}
2010-07-22 22:09:34 -07:00
#region Nested type : CreateContext
private class CreateContext {
public Stream Stream { get ; set ; }
2010-10-29 12:17:26 -07:00
public NuGetPackageBuilder Builder { get ; set ; }
2010-07-22 22:09:34 -07:00
public IWebSiteFolder SourceFolder { get ; set ; }
public string SourcePath { get ; set ; }
public string TargetPath { get ; set ; }
public XDocument Project { get ; set ; }
}
#endregion
2010-10-27 11:19:17 -07:00
#region Nested type : CreateContext
private class VirtualPackageFile : IPackageFile {
2010-10-29 12:17:26 -07:00
private readonly IWebSiteFolder _webSiteFolder ;
private readonly string _virtualPath ;
private readonly string _packagePath ;
public VirtualPackageFile ( IWebSiteFolder webSiteFolder , string virtualPath , string packagePath ) {
_webSiteFolder = webSiteFolder ;
_virtualPath = virtualPath ;
_packagePath = packagePath ;
2010-10-27 11:19:17 -07:00
}
2010-10-29 12:17:26 -07:00
public string Path { get { return _packagePath ; } }
2010-10-27 11:19:17 -07:00
2010-11-12 12:47:06 -08:00
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Supposed to return an open stream.")]
2010-10-27 11:19:17 -07:00
public Stream GetStream ( ) {
var stream = new MemoryStream ( ) ;
2010-10-29 12:17:26 -07:00
_webSiteFolder . CopyFileTo ( _virtualPath , stream ) ;
2010-10-27 11:19:17 -07:00
stream . Seek ( 0 , SeekOrigin . Begin ) ;
return stream ;
}
}
2010-10-29 12:17:26 -07:00
#endregion
2010-07-04 14:14:15 -07:00
}
2010-07-22 22:09:34 -07:00
}