--HG--
branch : dev
This commit is contained in:
Sebastien Ros
2010-11-11 14:40:09 -08:00
40 changed files with 983 additions and 604 deletions

1
.hgsub
View File

@@ -0,0 +1 @@
external/nuget = https://hg01.codeplex.com/nuget

View File

@@ -0,0 +1 @@
faab9e4b2d3b9615fe9ac3b9eae71555a4e13131 external/nuget

View File

@@ -122,11 +122,15 @@
</Reference> </Reference>
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CodeGeneration\Commands\CodeGenerationCommandsTests.cs" /> <Compile Include="CodeGeneration\Commands\CodeGenerationCommandsTests.cs" />
<Compile Include="DatabaseEnabledTestsBase.cs" /> <Compile Include="DatabaseEnabledTestsBase.cs" />
<Compile Include="Media\Extensions\LongExtensionsTests.cs" /> <Compile Include="Media\Extensions\LongExtensionsTests.cs" />
<EmbeddedResource Include="Packaging\HelloDriver.cs.txt" />
<Compile Include="Packaging\PackageExpanderTests.cs" />
<Compile Include="Packaging\PackageBuilderTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Roles\Controllers\AdminControllerTests.cs" /> <Compile Include="Roles\Controllers\AdminControllerTests.cs" />
<Compile Include="Roles\Services\RoleServiceTests.cs" /> <Compile Include="Roles\Services\RoleServiceTests.cs" />
@@ -164,6 +168,10 @@
<Project>{17F86780-9A1F-4AA1-86F1-875EEC2730C7}</Project> <Project>{17F86780-9A1F-4AA1-86F1-875EEC2730C7}</Project>
<Name>Orchard.Modules</Name> <Name>Orchard.Modules</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.Packaging\Orchard.Packaging.csproj">
<Project>{DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}</Project>
<Name>Orchard.Packaging</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.Roles\Orchard.Roles.csproj"> <ProjectReference Include="..\Orchard.Web\Modules\Orchard.Roles\Orchard.Roles.csproj">
<Project>{D10AD48F-407D-4DB5-A328-173EC7CB010F}</Project> <Project>{D10AD48F-407D-4DB5-A328-173EC7CB010F}</Project>
<Name>Orchard.Roles</Name> <Name>Orchard.Roles</Name>
@@ -206,7 +214,9 @@
<Install>true</Install> <Install>true</Install>
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<EmbeddedResource Include="Packaging\Hello.World.csproj.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Hello.World</RootNamespace>
<AssemblyName>Hello.World</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.ComponentModel.DataAnnotations">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web.Abstractions" />
<Reference Include="System.Web.Routing" />
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
</ItemGroup>
<ItemGroup>
<Compile Include="AdminMenu.cs" />
<Compile Include="Commands\GalleryCommands.cs" />
<Compile Include="Commands\PackagingCommands.cs" />
<Compile Include="Controllers\DownloadStreamResult.cs" />
<Compile Include="Controllers\GalleryController.cs" />
<Compile Include="DefaultPackagingUpdater.cs" />
<Compile Include="ResourceManifest.cs" />
<Compile Include="Services\AtomExtensions.cs" />
<Compile Include="Services\IPackageBuilder.cs" />
<Compile Include="Services\IPackageExpander.cs" />
<Compile Include="Services\IPackageManager.cs" />
<Compile Include="Services\IPackagingSourceManager.cs" />
<Compile Include="Services\PackageBuilder.cs" />
<Compile Include="Services\PackageData.cs" />
<Compile Include="Services\PackageExpander.cs" />
<Compile Include="Services\PackageManager.cs" />
<Compile Include="Services\PackagingEntry.cs" />
<Compile Include="Services\PackagingSource.cs" />
<Compile Include="Services\PackagingSourceManager.cs" />
<Compile Include="ViewModels\PackagingAddSourceViewModel.cs" />
<Compile Include="ViewModels\PackagingHarvestViewModel.cs" />
<Compile Include="ViewModels\PackagingModulesViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewModels\PackagingSourcesViewModel.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Module.txt" />
<Content Include="Styles\admin.css" />
<Content Include="Views\Gallery\AddSource.cshtml" />
<Content Include="Views\Gallery\Harvest.cshtml" />
<Content Include="Views\Gallery\Modules.cshtml" />
<Content Include="Views\Gallery\Sources.cshtml" />
<Content Include="Views\Gallery\_Subnav.cshtml" />
<Content Include="Views\Web.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="Content\" />
<Folder Include="Models\" />
<Folder Include="Scripts\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\external\nupack\NuPack.Core\NuPack.Core.csproj">
<Project>{F879F274-EFA0-4157-8404-33A19B4E6AEC}</Project>
<Name>NuPack.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
<Name>Orchard.Framework</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Gallery\Themes.cshtml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target> -->
<Target Name="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)" />
</Target>
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>40980</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>
</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>True</UseCustomServer>
<CustomServerUrl>http://orchard.codeplex.com</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>

View File

@@ -0,0 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Orchard.Tests.Modules.Packaging {
class HelloDriver {
}
}

View File

@@ -0,0 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Orchard.Tests.Modules.Packaging {
class Migrations {
}
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using Autofac;
using NUnit.Framework;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.WebSite;
using Orchard.Packaging.Services;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.Modules.Packaging {
[TestFixture]
public class PackageBuilderTests : ContainerTestBase {
protected override void Register(Autofac.ContainerBuilder builder) {
builder.RegisterType<PackageBuilder>().As<IPackageBuilder>();
builder.RegisterType<InMemoryWebSiteFolder>().As<IWebSiteFolder>()
.As<InMemoryWebSiteFolder>().InstancePerLifetimeScope();
}
private Stream BuildHelloWorld(IPackageBuilder packageBuilder) {
return packageBuilder.BuildPackage(new ExtensionDescriptor {
ExtensionType = "Module",
Name = "Hello.World",
Version = "1.0",
Description = "a",
Author = "b"
});
}
[Test]
public void PackageForModuleIsOpcPackage() {
var packageBuilder = _container.Resolve<IPackageBuilder>();
var stream = BuildHelloWorld(packageBuilder);
var package = Package.Open(stream);
Assert.That(package, Is.Not.Null);
Assert.That(package.PackageProperties.Identifier, Is.EqualTo("Orchard.Module.Hello.World"));
}
[Test]
public void PropertiesPassThroughAsExpected() {
var packageBuilder = _container.Resolve<IPackageBuilder>();
var stream = BuildHelloWorld(packageBuilder);
var package = Package.Open(stream);
Assert.That(package.PackageProperties.Description, Is.EqualTo("a"));
Assert.That(package.PackageProperties.Creator, Is.EqualTo("b"));
Assert.That(package.PackageProperties.Version, Is.EqualTo("1.0"));
}
[Test]
public void ProjectFileIsAdded() {
var packageBuilder = _container.Resolve<IPackageBuilder>();
var folder = _container.Resolve<InMemoryWebSiteFolder>();
string content;
using (var sourceStream = GetType().Assembly.GetManifestResourceStream(GetType(), "Hello.World.csproj.txt")) {
content = new StreamReader(sourceStream).ReadToEnd();
}
folder.AddFile("~/Modules/Hello.World/Hello.World.csproj", content);
var stream = BuildHelloWorld(packageBuilder);
var package = Package.Open(stream);
var projectUri = PackUriHelper.CreatePartUri(new Uri("/Content/Modules/Hello.World/Hello.World.csproj", UriKind.Relative));
var projectPart = package.GetPart(projectUri);
using (var projectStream = projectPart.GetStream()) {
var projectContent = new StreamReader(projectStream).ReadToEnd();
Assert.That(projectContent, Is.EqualTo(content));
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using Autofac;
using NUnit.Framework;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.VirtualPath;
using Orchard.FileSystems.WebSite;
using Orchard.Packaging.Services;
using Orchard.Services;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.Modules.Packaging {
[TestFixture]
public class PackageExpanderTests : ContainerTestBase {
protected override void Register(Autofac.ContainerBuilder builder) {
builder.RegisterType<PackageBuilder>().As<IPackageBuilder>();
builder.RegisterType<PackageInstaller>().As<IPackageInstaller>();
builder.RegisterInstance<IVirtualPathProvider>(new StubVirtualPathProvider(new StubFileSystem(new Clock())));
builder.RegisterType<InMemoryWebSiteFolder>().As<IWebSiteFolder>()
.As<InMemoryWebSiteFolder>().InstancePerLifetimeScope();
}
private Stream BuildHelloWorld(IPackageBuilder packageBuilder) {
return packageBuilder.BuildPackage(new ExtensionDescriptor {
ExtensionType = "Module",
Name = "Hello.World",
Version = "1.0",
Description = "a",
Author = "b"
});
}
}
}

View File

@@ -246,6 +246,7 @@
<Compile Include="Mvc\Routes\UrlPrefixTests.cs" /> <Compile Include="Mvc\Routes\UrlPrefixTests.cs" />
<Compile Include="Records\BigRecord.cs" /> <Compile Include="Records\BigRecord.cs" />
<Compile Include="Scripting\ScriptingTests.cs" /> <Compile Include="Scripting\ScriptingTests.cs" />
<Compile Include="Stubs\InMemoryWebSiteFolder.cs" />
<Compile Include="Stubs\StubHttpContextAccessor.cs" /> <Compile Include="Stubs\StubHttpContextAccessor.cs" />
<Compile Include="Stubs\StubWorkContextAccessor.cs" /> <Compile Include="Stubs\StubWorkContextAccessor.cs" />
<Compile Include="Stubs\StubExtensionManager.cs" /> <Compile Include="Stubs\StubExtensionManager.cs" />

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Orchard.Caching;
using Orchard.FileSystems.WebSite;
namespace Orchard.Tests.Stubs {
public class InMemoryWebSiteFolder : IWebSiteFolder {
Dictionary<string, string> _contents = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public void AddFile(string virtualPath, string contents) {
_contents[Canonical(virtualPath)] = contents;
}
private string Canonical(string virtualPath) {
return virtualPath.Replace("\\", "/");
}
public IEnumerable<string> ListDirectories(string virtualPath) {
throw new NotImplementedException();
}
public IEnumerable<string> ListFiles(string virtualPath, bool recursive) {
throw new NotImplementedException();
}
public bool FileExists(string virtualPath) {
return _contents.ContainsKey(virtualPath);
}
public string ReadFile(string virtualPath) {
string value;
return _contents.TryGetValue(Canonical(virtualPath), out value) ? value : null;
}
public string ReadFile(string virtualPath, bool actualContent) {
throw new NotImplementedException();
}
public void CopyFileTo(string virtualPath, Stream destination) {
string value;
if (_contents.TryGetValue(Canonical(virtualPath), out value)) {
var bytes = Encoding.Default.GetBytes(value);
destination.Write(bytes, 0, bytes.Length);
}
}
public void CopyFileTo(string virtualPath, Stream destination, bool actualContent) {
throw new NotImplementedException();
}
public IVolatileToken WhenPathChanges(string virtualPath) {
throw new NotImplementedException();
}
}
}

View File

@@ -76,10 +76,12 @@ namespace Orchard.Modules.Controllers {
foreach (string fileName in Request.Files) { foreach (string fileName in Request.Files) {
var file = Request.Files[fileName]; var file = Request.Files[fileName];
#if REFACTORING
var info = _packageManager.Install(file.InputStream); var info = _packageManager.Install(file.InputStream);
Services.Notifier.Information(T("Installed package \"{0}\", version {1} of type \"{2}\" at location \"{3}\"", Services.Notifier.Information(T("Installed package \"{0}\", version {1} of type \"{2}\" at location \"{3}\"",
info.ExtensionName, info.ExtensionVersion, info.ExtensionType, info.ExtensionPath)); info.ExtensionName, info.ExtensionVersion, info.ExtensionType, info.ExtensionPath));
#endif
} }
return RedirectToAction("index"); return RedirectToAction("index");

View File

@@ -12,9 +12,9 @@ namespace Orchard.Packaging {
public void GetNavigation(NavigationBuilder builder) { public void GetNavigation(NavigationBuilder builder) {
builder.Add(T("Gallery"), "30", menu => menu builder.Add(T("Gallery"), "30", menu => menu
.Add(T("Modules"), "1.0", item => item .Add(T("Modules"), "1.0", item => item
.Action("ModulesIndex", "Gallery", new { area = "Orchard.Packaging" })) .Action("Modules", "Gallery", new { area = "Orchard.Packaging" }))
.Add(T("Themes"), "2.0", item => item .Add(T("Themes"), "2.0", item => item
.Action("ThemesIndex", "Gallery", new { area = "Orchard.Packaging" })) .Action("Themes", "Gallery", new { area = "Orchard.Packaging" }))
.Add(T("Feeds"), "3.0", item => item .Add(T("Feeds"), "3.0", item => item
.Action("Sources", "Gallery", new { area = "Orchard.Packaging" }))); .Action("Sources", "Gallery", new { area = "Orchard.Packaging" })));
} }

View File

@@ -1,105 +0,0 @@
using System;
using System.IO;
using System.Net;
using Orchard.Commands;
using Orchard.Environment.Extensions;
using Orchard.Packaging.Services;
namespace Orchard.Packaging.Commands {
[OrchardFeature("Gallery")]
public class GalleryCommands : DefaultOrchardCommandHandler {
private readonly IPackageManager _packageManager;
[OrchardSwitch]
public string User { get; set; }
[OrchardSwitch]
public string Password { get; set; }
public GalleryCommands(IPackageManager packageManager) {
_packageManager = packageManager;
}
#if false
[CommandHelp("harvest <moduleName>\r\n\t" + "Package a module into a distributable")]
[CommandName("harvest")]
public void PackageCreate(string moduleName) {
var packageData = _packageManager.Harvest(moduleName);
if (packageData.PackageStream.CanSeek)
packageData.PackageStream.Seek(0, SeekOrigin.Begin);
const int chunk = 512;
var dataBuffer = new byte[3 * chunk];
var charBuffer = new char[4 * chunk + 2];
for (; ; ) {
var dataCount = packageData.PackageStream.Read(dataBuffer, 0, dataBuffer.Length);
if (dataCount <= 0)
return;
var charCount = Convert.ToBase64CharArray(dataBuffer, 0, dataCount, charBuffer, 0);
Context.Output.Write(charBuffer, 0, charCount);
}
}
#endif
[CommandHelp("gallery submit module <moduleName> <feedUrl> /User:<user> /Password:<password>\r\n\t" + "Package a module into a distributable and push it to a feed server.")]
[CommandName("gallery submit module")]
[OrchardSwitches("User,Password")]
public void SubmitModule(string moduleName, string feedUrl) {
var packageData = _packageManager.Harvest(moduleName);
if ( String.IsNullOrWhiteSpace(User) ) {
Context.Output.WriteLine(T("Missing or incorrect User"));
return;
}
if ( String.IsNullOrWhiteSpace(Password) ) {
Context.Output.WriteLine(T("Missing or incorrect Password"));
return;
}
try {
_packageManager.Push(packageData, feedUrl, User, Password);
Context.Output.WriteLine(T("Success"));
}
catch (WebException webException) {
string text = "";
if (webException.Response != null) {
text = new StreamReader(webException.Response.GetResponseStream()).ReadToEnd();
}
throw new ApplicationException(text);
}
}
[CommandHelp("gallery submit package <filePath> <feedUrl> /User:<user> /Password:<password>\r\n\t" + "Push a packaged module to a feed server.")]
[CommandName("gallery submit package")]
[OrchardSwitches("User,Password")]
public void SubmitPackage(string filePath, string feedUrl) {
using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read)) {
var packageData = new PackageData {
PackageStream = stream
};
if ( String.IsNullOrWhiteSpace(User) ) {
Context.Output.WriteLine(T("Missing or incorrect User"));
return;
}
if ( String.IsNullOrWhiteSpace(Password) ) {
Context.Output.WriteLine(T("Missing or incorrect Password"));
return;
}
try {
_packageManager.Push(packageData, feedUrl, User, Password);
Context.Output.WriteLine(T("Success"));
}
catch (WebException webException) {
var text = new StreamReader(webException.Response.GetResponseStream()).ReadToEnd();
throw new ApplicationException(text);
}
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System.IO; using System.IO;
using System.Web.Hosting;
using Orchard.Commands; using Orchard.Commands;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Packaging.Services; using Orchard.Packaging.Services;
@@ -7,28 +8,40 @@ using Orchard.UI.Notify;
namespace Orchard.Packaging.Commands { namespace Orchard.Packaging.Commands {
[OrchardFeature("Orchard.Packaging")] [OrchardFeature("Orchard.Packaging")]
public class PackagingCommands : DefaultOrchardCommandHandler { public class PackagingCommands : DefaultOrchardCommandHandler {
private readonly IPackageManager _packageManager; private static readonly string OrchardWebProj = HostingEnvironment.MapPath("~/Orchard.Web.csproj");
private const string CreatePackagePath = "CreatedPackages";
public PackagingCommands(IPackageManager packageManager) { private readonly IPackageManager _packageManager;
private readonly INotifier _notifier;
public PackagingCommands(IPackageManager packageManager, INotifier notifier) {
_packageManager = packageManager; _packageManager = packageManager;
_notifier = notifier;
} }
[OrchardSwitch] [OrchardSwitch]
public string Filename { get; set; } public string Version { get; set; }
[CommandHelp("package create <moduleName>\r\n\t" + "Create a package for the module <moduleName>. The default filename is <moduleName>-<moduleVersion>.zip.")] [CommandHelp("package create <extensionName> <path> \r\n\t" + "Create a package for the module <moduleName>. The default filename is Orchard.<extension>.<extensionName>.<moduleVersion>.nupkg.")]
[CommandName("package create")] [CommandName("package create")]
[OrchardSwitches("Filename")] public void CreatePackage(string extensionName, string path) {
public void CreatePackage(string moduleName) { var packageData = _packageManager.Harvest(extensionName);
var packageData = _packageManager.Harvest(moduleName);
if (packageData == null) { if (packageData == null) {
Context.Output.WriteLine(T("Module \"{0}\" does not exist in this Orchard installation.", moduleName)); Context.Output.WriteLine(T("Module or Theme \"{0}\" does not exist in this Orchard installation.", extensionName));
return; return;
} }
var filename = string.Format("{0}-{1}.zip", packageData.ExtensionName, packageData.ExtensionVersion); // append "Orchard.[ExtensionType]" to prevent conflicts with other packages (e.g, TinyMce, jQuery, ...)
var filename = string.Format("Orchard.{0}.{1}.{2}.nupkg", packageData.ExtensionType, packageData.ExtensionName, packageData.ExtensionVersion);
using(var stream = File.Create(filename)) { if ( !Directory.Exists(path) ) {
Directory.CreateDirectory(path);
}
// packages are created in a specific folder otherwise they are in /bin, which crashed the current shell
filename = Path.Combine(path, filename);
using ( var stream = File.Create(filename) ) {
packageData.PackageStream.CopyTo(stream); packageData.PackageStream.CopyTo(stream);
stream.Close(); stream.Close();
} }
@@ -37,17 +50,41 @@ namespace Orchard.Packaging.Commands {
Context.Output.WriteLine(T("Package \"{0}\" successfully created", fileInfo.FullName)); Context.Output.WriteLine(T("Package \"{0}\" successfully created", fileInfo.FullName));
} }
[CommandHelp("package install <filename>\r\n\t" + "Install a module from a package <filename>.")] [CommandHelp("package install <packageId> <location> /Version:<version> \r\n\t" + "Install a module or a theme from a package file.")]
[CommandName("package install")] [CommandName("package install")]
public void InstallPackage(string filename) { [OrchardSwitches("Version")]
if (!File.Exists(filename)) { public void InstallPackage(string packageId, string location) {
Context.Output.WriteLine(T("File \"{0}\" does not exist.", filename)); var solutionFolder = GetSolutionFolder();
if(solutionFolder == null) {
Context.Output.WriteLine(T("The project's location is not supported"));
} }
using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read)) { _packageManager.Install(packageId, Version, Path.GetFullPath(location), solutionFolder);
var packageInfo = _packageManager.Install(stream);
Context.Output.WriteLine(T("Package \"{0}\" successfully installed at \"{1}\"", packageInfo.ExtensionName, packageInfo.ExtensionPath)); foreach(var message in _notifier.List()) {
Context.Output.WriteLine(message.Message);
} }
} }
[CommandHelp("package uninstall <packageId> \r\n\t" + "Uninstall a module or a theme.")]
[CommandName("package uninstall")]
public void UninstallPackage(string packageId) {
var solutionFolder = GetSolutionFolder();
if ( solutionFolder == null ) {
Context.Output.WriteLine(T("The project's location is not supported"));
}
_packageManager.Uninstall(packageId, solutionFolder);
foreach ( var message in _notifier.List() ) {
Context.Output.WriteLine(message.Message);
}
}
private static string GetSolutionFolder() {
var orchardDirectory = Directory.GetParent(OrchardWebProj);
return orchardDirectory.Parent == null ? null : orchardDirectory.Parent.FullName;
}
} }
} }

View File

@@ -15,6 +15,7 @@ namespace Orchard.Packaging.Controllers {
[OrchardFeature("Gallery")] [OrchardFeature("Gallery")]
[Themed, Admin] [Themed, Admin]
public class GalleryController : Controller { public class GalleryController : Controller {
private readonly IPackageManager _packageManager; private readonly IPackageManager _packageManager;
private readonly IPackagingSourceManager _packagingSourceManager; private readonly IPackagingSourceManager _packagingSourceManager;
private readonly IExtensionManager _extensionManager; private readonly IExtensionManager _extensionManager;
@@ -34,24 +35,15 @@ namespace Orchard.Packaging.Controllers {
Localizer T { get; set; } Localizer T { get; set; }
public ActionResult ModulesIndex() {
return Modules(Guid.Empty);
}
public ActionResult ThemesIndex() {
return Themes(Guid.Empty);
}
public ActionResult Sources() { public ActionResult Sources() {
return View(new PackagingSourcesViewModel { return View(new PackagingSourcesViewModel {
Sources = _packagingSourceManager.GetSources(), Sources = _packagingSourceManager.GetSources(),
}); });
} }
public ActionResult Remove(Guid id) { public ActionResult Remove(int id) {
_packagingSourceManager.RemoveSource(id); _packagingSourceManager.RemoveSource(id);
_notifier.Information(T("The feed has been removed successfully.")); _notifier.Information(T("The feed has been removed successfully."));
Update(null);
return RedirectToAction("Sources"); return RedirectToAction("Sources");
} }
@@ -92,9 +84,9 @@ namespace Orchard.Packaging.Controllers {
if ( !ModelState.IsValid ) if ( !ModelState.IsValid )
return View(new PackagingAddSourceViewModel { Url = url }); return View(new PackagingAddSourceViewModel { Url = url });
_packagingSourceManager.AddSource(new PackagingSource { Id = Guid.NewGuid(), FeedUrl = url, FeedTitle = title }); _packagingSourceManager.AddSource(title, url);
_notifier.Information(T("The feed has been added successfully.")); _notifier.Information(T("The feed has been added successfully."));
Update(null);
return RedirectToAction("Sources"); return RedirectToAction("Sources");
} }
catch ( Exception exception ) { catch ( Exception exception ) {
@@ -104,32 +96,36 @@ namespace Orchard.Packaging.Controllers {
} }
public ActionResult Modules(Guid? sourceId) { public ActionResult Modules(int? sourceId) {
var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault(); var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault();
return View("Modules", new PackagingModulesViewModel { var sources = selectedSource != null
Modules = _packagingSourceManager.GetModuleList(selectedSource).Where(p => p.SyndicationItem.Categories.All(c => c.Name == "Orchard Module" || c.Name != "Orchard Theme")), ? new [] { selectedSource }
: _packagingSourceManager.GetSources()
;
return View("Modules", new PackagingExtensionsViewModel {
Extensions = sources.SelectMany(source => _packagingSourceManager.GetModuleList(source)),
Sources = _packagingSourceManager.GetSources().OrderBy(s => s.FeedTitle), Sources = _packagingSourceManager.GetSources().OrderBy(s => s.FeedTitle),
SelectedSource = selectedSource SelectedSource = selectedSource
}); });
} }
public ActionResult Themes(Guid? sourceId) { public ActionResult Themes(int? sourceId) {
var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault(); var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault();
return View("Themes", new PackagingModulesViewModel { var sources = selectedSource != null
Modules = _packagingSourceManager.GetModuleList(selectedSource).Where(p => p.SyndicationItem.Categories.Any(c => c.Name == "Orchard Theme")), ? new[] { selectedSource }
: _packagingSourceManager.GetSources()
;
return View("Themes", new PackagingExtensionsViewModel {
Extensions = sources.SelectMany(source => _packagingSourceManager.GetThemeList(source)),
Sources = _packagingSourceManager.GetSources().OrderBy(s => s.FeedTitle), Sources = _packagingSourceManager.GetSources().OrderBy(s => s.FeedTitle),
SelectedSource = selectedSource SelectedSource = selectedSource
}); });
} }
public ActionResult Update(string cameFrom) {
_packagingSourceManager.UpdateLists();
_notifier.Information(T("List of available modules and themes is updated."));
return RedirectToAction(cameFrom == "Themes" ? "ThemesIndex" : "ModulesIndex");
}
public ActionResult Harvest(string extensionName, string feedUrl) { public ActionResult Harvest(string extensionName, string feedUrl) {
return View(new PackagingHarvestViewModel { return View(new PackagingHarvestViewModel {
ExtensionName = extensionName, ExtensionName = extensionName,
@@ -141,6 +137,7 @@ namespace Orchard.Packaging.Controllers {
[HttpPost] [HttpPost]
public ActionResult Harvest(PackagingHarvestViewModel model) { public ActionResult Harvest(PackagingHarvestViewModel model) {
#if REFACTORING
model.Sources = _packagingSourceManager.GetSources(); model.Sources = _packagingSourceManager.GetSources();
model.Extensions = _extensionManager.AvailableExtensions(); model.Extensions = _extensionManager.AvailableExtensions();
@@ -164,12 +161,18 @@ namespace Orchard.Packaging.Controllers {
Update(null); Update(null);
return RedirectToAction("Harvest", new { model.ExtensionName, model.FeedUrl }); return RedirectToAction("Harvest", new { model.ExtensionName, model.FeedUrl });
#else
return View();
#endif
} }
public ActionResult Install(string syndicationId, string cameFrom) { public ActionResult Install(string syndicationId, string cameFrom) {
#if REFACTORING
var packageData = _packageManager.Download(syndicationId); var packageData = _packageManager.Download(syndicationId);
_packageManager.Install(packageData.PackageStream); _packageManager.Install(packageData.PackageStream);
_notifier.Information(T("Installed module")); _notifier.Information(T("Installed module"));
#endif
return RedirectToAction(cameFrom == "Themes" ? "ThemesIndex" : "ModulesIndex"); return RedirectToAction(cameFrom == "Themes" ? "ThemesIndex" : "ModulesIndex");
} }
} }

View File

@@ -4,23 +4,20 @@ using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Packaging.Services; using Orchard.Packaging.Services;
using Orchard.UI.Notify;
namespace Orchard.Packaging { namespace Orchard.Packaging {
[OrchardFeature("Gallery")] [OrchardFeature("PackagingServices")]
public class DefaultPackagingUpdater : IFeatureEventHandler { public class DefaultPackagingUpdater : IFeatureEventHandler {
private readonly IPackagingSourceManager _packagingSourceManager; private readonly IPackagingSourceManager _packagingSourceManager;
private readonly INotifier _notifier;
public DefaultPackagingUpdater(IPackagingSourceManager packagingSourceManager, INotifier notifier) { public DefaultPackagingUpdater(IPackagingSourceManager packagingSourceManager) {
_packagingSourceManager = packagingSourceManager; _packagingSourceManager = packagingSourceManager;
_notifier = notifier;
} }
public Localizer T { get; set; } public Localizer T { get; set; }
public void Install(Feature feature) { public void Install(Feature feature) {
_packagingSourceManager.AddSource(new PackagingSource { Id = Guid.NewGuid(), FeedTitle = "Orchard Module Gallery", FeedUrl = "http://orchardproject.net/gallery08/feed" }); _packagingSourceManager.AddSource( "Orchard Extensions Gallery", "http://feed.nuget.org/ctp2/odata/v1" );
} }
public void Enable(Feature feature) { public void Enable(Feature feature) {

View File

@@ -0,0 +1,18 @@
using Orchard.Data.Migration;
using Orchard.Environment.Extensions;
namespace Orchard.Packaging {
[OrchardFeature("PackagingServices")]
public class Migrations: DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("PackagingSourceRecord",
table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<string>("FeedTitle", c => c.WithLength(255))
.Column<string>("FeedUrl", c => c.WithLength(2048))
);
return 1;
}
}
}

View File

@@ -0,0 +1,7 @@
namespace Orchard.Packaging.Models {
public class PackagingSource {
public virtual int Id { get; set; }
public virtual string FeedTitle { get; set; }
public virtual string FeedUrl { get; set; }
}
}

View File

@@ -37,7 +37,9 @@
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Data.Services.Client" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" /> <Reference Include="System.ServiceModel" />
<Reference Include="System.Web.DynamicData" /> <Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" /> <Reference Include="System.Web.Entity" />
@@ -68,33 +70,32 @@
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" /> <Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" /> <Reference Include="System.EnterpriseServices" />
<Reference Include="WindowsBase">
<Private>True</Private>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AdminMenu.cs" /> <Compile Include="AdminMenu.cs" />
<Compile Include="Commands\GalleryCommands.cs" />
<Compile Include="Commands\PackagingCommands.cs" /> <Compile Include="Commands\PackagingCommands.cs" />
<Compile Include="Controllers\DownloadStreamResult.cs" /> <Compile Include="Controllers\DownloadStreamResult.cs" />
<Compile Include="Controllers\GalleryController.cs" /> <Compile Include="Controllers\GalleryController.cs" />
<Compile Include="DefaultPackagingUpdater.cs" /> <Compile Include="DefaultPackagingUpdater.cs" />
<Compile Include="Migrations.cs" />
<Compile Include="Models\PackagingSource.cs" />
<Compile Include="ResourceManifest.cs" /> <Compile Include="ResourceManifest.cs" />
<Compile Include="Services\AtomExtensions.cs" /> <Compile Include="Services\AtomExtensions.cs" />
<Compile Include="Services\FileBaseProjectSystem.cs" />
<Compile Include="Services\IPackageBuilder.cs" /> <Compile Include="Services\IPackageBuilder.cs" />
<Compile Include="Services\IPackageExpander.cs" /> <Compile Include="Services\IPackageInstaller.cs" />
<Compile Include="Services\IPackageManager.cs" /> <Compile Include="Services\IPackageManager.cs" />
<Compile Include="Services\IPackagingSourceManager.cs" /> <Compile Include="Services\IPackagingSourceManager.cs" />
<Compile Include="Services\NugetLogger.cs" />
<Compile Include="Services\PackageBuilder.cs" /> <Compile Include="Services\PackageBuilder.cs" />
<Compile Include="Services\PackageData.cs" /> <Compile Include="Services\PackageData.cs" />
<Compile Include="Services\PackageExpander.cs" /> <Compile Include="Services\PackageInstaller.cs" />
<Compile Include="Services\PackageManager.cs" /> <Compile Include="Services\PackageManager.cs" />
<Compile Include="Services\PackagingEntry.cs" /> <Compile Include="Services\PackagingEntry.cs" />
<Compile Include="Services\PackagingSource.cs" />
<Compile Include="Services\PackagingSourceManager.cs" /> <Compile Include="Services\PackagingSourceManager.cs" />
<Compile Include="ViewModels\PackagingAddSourceViewModel.cs" /> <Compile Include="ViewModels\PackagingAddSourceViewModel.cs" />
<Compile Include="ViewModels\PackagingHarvestViewModel.cs" /> <Compile Include="ViewModels\PackagingHarvestViewModel.cs" />
<Compile Include="ViewModels\PackagingModulesViewModel.cs" /> <Compile Include="ViewModels\PackagingExtensionsViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewModels\PackagingSourcesViewModel.cs" /> <Compile Include="ViewModels\PackagingSourcesViewModel.cs" />
</ItemGroup> </ItemGroup>
@@ -108,18 +109,17 @@
<Content Include="Views\Gallery\_Subnav.cshtml" /> <Content Include="Views\Gallery\_Subnav.cshtml" />
<Content Include="Views\Web.config" /> <Content Include="Views\Web.config" />
</ItemGroup> </ItemGroup>
<ItemGroup />
<ItemGroup> <ItemGroup>
<Folder Include="Models\" /> <ProjectReference Include="..\..\..\..\external\nuget\NuPack.Core\NuPack.Core.csproj">
</ItemGroup> <Project>{F879F274-EFA0-4157-8404-33A19B4E6AEC}</Project>
<ItemGroup> <Name>NuPack.Core</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj"> <ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project> <Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
<Name>Orchard.Framework</Name> <Name>Orchard.Framework</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="Views\Gallery\Themes.cshtml" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Content\Web.config"> <Content Include="Content\Web.config">
<SubType>Designer</SubType> <SubType>Designer</SubType>
@@ -135,6 +135,12 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<WCFMetadata Include="Service References\" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Gallery\Themes.cshtml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.UI.Resources; using Orchard.UI.Resources;

View File

@@ -0,0 +1,225 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Versioning;
using NuGet;
namespace Orchard.Packaging.Services {
public class FileBasedProjectSystem : IProjectSystem {
private const string NetFrameworkIdentifier = ".NETFramework";
private const string BinDir = "bin";
private string _root;
public FileBasedProjectSystem(string root) {
if (String.IsNullOrEmpty(root)) {
throw new ArgumentException("root");
}
_root = root;
}
public string Root {
get {
return _root;
}
}
public virtual string ProjectName {
get {
return Root;
}
}
private FrameworkName _targetFramework;
private ILogger _logger;
public ILogger Logger {
get {
return _logger ?? NullLogger.Instance;
}
set {
_logger = value;
}
}
public virtual FrameworkName TargetFramework {
get {
if (_targetFramework == null) {
_targetFramework = new FrameworkName(NetFrameworkIdentifier, typeof(string).Assembly.GetNameSafe().Version);;
}
return _targetFramework;
}
}
public string GetFullPath(string path) {
return Path.Combine(Root, path);
}
protected virtual string GetReferencePath(string name) {
return Path.Combine(BinDir, name);
}
public void AddFile(string path, Stream stream) {
EnsureDirectory(Path.GetDirectoryName(path));
using (Stream outputStream = File.Create(GetFullPath(path))) {
stream.CopyTo(outputStream);
}
}
public void DeleteFile(string path) {
if (!FileExists(path)) {
return;
}
try {
path = GetFullPath(path);
File.Delete(path);
}
catch (FileNotFoundException) {}
}
public void DeleteDirectory(string path) {
DeleteDirectory(path, recursive: false);
}
public void DeleteDirectory(string path, bool recursive) {
if (!DirectoryExists(path)) {
return;
}
try {
path = GetFullPath(path);
Directory.Delete(path, recursive);
}
catch (DirectoryNotFoundException) {
}
}
public void AddReference(string referencePath) {
// Copy to bin by default
string src = referencePath;
string referenceName = Path.GetFileName(referencePath);
string dest = GetFullPath(GetReferencePath(referenceName));
// Ensure the destination path exists
Directory.CreateDirectory(Path.GetDirectoryName(dest));
// Copy the reference over
File.Copy(src, dest, overwrite: true);
}
public void RemoveReference(string name) {
DeleteFile(GetReferencePath(name));
// Delete the bin directory if this was the last reference
if (!GetFiles(BinDir).Any()) {
DeleteDirectory(BinDir);
}
}
public dynamic GetPropertyValue(string propertyName) {
if(propertyName == null) {
return null;
}
// Return empty string for the root namespace of this project.
if (propertyName.Equals("RootNamespace", StringComparison.OrdinalIgnoreCase)) {
return String.Empty;
}
return null;
}
public IEnumerable<string> GetFiles(string path) {
return GetFiles(path, "*.*");
}
public IEnumerable<string> GetFiles(string path, string filter) {
path = EnsureTrailingSlash(GetFullPath(path));
try {
if (!Directory.Exists(path)) {
return Enumerable.Empty<string>();
}
return Directory.EnumerateFiles(path, filter)
.Select(MakeRelativePath);
}
catch (UnauthorizedAccessException) {
}
catch (DirectoryNotFoundException) {
}
return Enumerable.Empty<string>();
}
public IEnumerable<string> GetDirectories(string path) {
try {
path = EnsureTrailingSlash(GetFullPath(path));
if (!Directory.Exists(path)) {
return Enumerable.Empty<string>();
}
return Directory.EnumerateDirectories(path)
.Select(MakeRelativePath);
}
catch (UnauthorizedAccessException) {
}
catch (DirectoryNotFoundException) {
}
return Enumerable.Empty<string>();
}
public DateTimeOffset GetLastModified(string path) {
if (DirectoryExists(path)) {
return new DirectoryInfo(GetFullPath(path)).LastWriteTimeUtc;
}
return new FileInfo(GetFullPath(path)).LastWriteTimeUtc;
}
public bool FileExists(string path) {
path = GetFullPath(path);
return File.Exists(path);
}
public bool DirectoryExists(string path) {
path = GetFullPath(path);
return Directory.Exists(path);
}
public Stream OpenFile(string path) {
path = GetFullPath(path);
return File.OpenRead(path);
}
public bool ReferenceExists(string name) {
string path = GetReferencePath(name);
return FileExists(path);
}
public virtual bool IsSupportedFile(string path) {
return true;
}
protected string MakeRelativePath(string fullPath) {
return fullPath.Substring(Root.Length).TrimStart(Path.DirectorySeparatorChar);
}
private void EnsureDirectory(string path) {
path = GetFullPath(path);
Directory.CreateDirectory(path);
}
private static string EnsureTrailingSlash(string path) {
if (!path.EndsWith("\\", StringComparison.Ordinal)) {
path += "\\";
}
return path;
}
}
}

View File

@@ -1,6 +1,3 @@
using System.IO;
using Orchard.Environment.Extensions;
namespace Orchard.Packaging.Services { namespace Orchard.Packaging.Services {
public class PackageInfo { public class PackageInfo {
public string ExtensionName { get; set; } public string ExtensionName { get; set; }
@@ -9,7 +6,8 @@ namespace Orchard.Packaging.Services {
public string ExtensionPath { get; set; } public string ExtensionPath { get; set; }
} }
public interface IPackageExpander : IDependency { public interface IPackageInstaller : IDependency {
PackageInfo ExpandPackage(Stream packageStream); PackageInfo Install(string packageId, string version, string location, string solutionFolder);
void Uninstall(string packageId, string solutionFolder);
} }
} }

View File

@@ -1,11 +1,7 @@
using System.IO;
namespace Orchard.Packaging.Services { namespace Orchard.Packaging.Services {
public interface IPackageManager : IDependency { public interface IPackageManager : IDependency {
PackageData Harvest(string extensionName); PackageData Harvest(string extensionName);
PackageData Download(string feedItemId); PackageInfo Install(string packageId, string version, string location, string solutionFolder);
void Uninstall(string packageId, string solutionFolder);
void Push(PackageData packageData, string feedUrl, string login, string password);
PackageInfo Install(Stream packageStream);
} }
} }

View File

@@ -1,13 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.Packaging.Models;
namespace Orchard.Packaging.Services { namespace Orchard.Packaging.Services {
public interface IPackagingSourceManager : IDependency { public interface IPackagingSourceManager : IDependency {
IEnumerable<PackagingSource> GetSources(); IEnumerable<PackagingSource> GetSources();
void AddSource(PackagingSource source); void AddSource(string feedTitle, string feedUrl);
void RemoveSource(Guid id); void RemoveSource(int id);
void UpdateLists();
IEnumerable<PackagingEntry> GetModuleList(PackagingSource packagingSource = null); IEnumerable<PackagingEntry> GetModuleList(PackagingSource packagingSource = null);
IEnumerable<PackagingEntry> GetThemeList(PackagingSource packagingSource = null);
} }
} }

View File

@@ -0,0 +1,27 @@
using System;
using NuGet;
using Orchard.Localization;
using Orchard.UI.Notify;
namespace Orchard.Packaging.Services {
public class NugetLogger : ILogger {
private readonly INotifier _notifier;
public NugetLogger(INotifier notifier) {
_notifier = notifier;
}
public void Log(MessageLevel level, string message, params object[] args) {
switch ( level ) {
case MessageLevel.Debug:
break;
case MessageLevel.Info:
_notifier.Information(new LocalizedString(String.Format(message, args)));
break;
case MessageLevel.Warning:
_notifier.Warning(new LocalizedString(String.Format(message, args)));
break;
}
}
}
}

View File

@@ -1,21 +1,20 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Packaging;
using System.Linq; using System.Linq;
using System.Net.Mime; using System.Net.Mime;
using System.Reflection; using System.Reflection;
using System.Web;
using System.Web.Hosting;
using System.Xml.Linq; using System.Xml.Linq;
using NuGet;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.WebSite; using Orchard.FileSystems.WebSite;
using NuGetPackageBuilder = NuGet.PackageBuilder;
namespace Orchard.Packaging.Services { namespace Orchard.Packaging.Services {
[OrchardFeature("PackagingServices")] [OrchardFeature("PackagingServices")]
public class PackageBuilder : IPackageBuilder { public class PackageBuilder : IPackageBuilder {
private readonly IExtensionManager _extensionManager;
private readonly IWebSiteFolder _webSiteFolder; private readonly IWebSiteFolder _webSiteFolder;
private static readonly string[] _ignoredThemeExtensions = new[] { private static readonly string[] _ignoredThemeExtensions = new[] {
@@ -31,13 +30,10 @@ namespace Orchard.Packaging.Services {
_ignoredThemeExtensions.Contains(Path.GetExtension(filePath) ?? ""); _ignoredThemeExtensions.Contains(Path.GetExtension(filePath) ?? "");
} }
public PackageBuilder(IExtensionManager extensionManager, IWebSiteFolder webSiteFolder) { public PackageBuilder(IWebSiteFolder webSiteFolder) {
_extensionManager = extensionManager;
_webSiteFolder = webSiteFolder; _webSiteFolder = webSiteFolder;
} }
#region IPackageBuilder Members
public Stream BuildPackage(ExtensionDescriptor extensionDescriptor) { public Stream BuildPackage(ExtensionDescriptor extensionDescriptor) {
var context = new CreateContext(); var context = new CreateContext();
BeginPackage(context); BeginPackage(context);
@@ -67,28 +63,17 @@ namespace Orchard.Packaging.Services {
return context.Stream; return context.Stream;
} }
#endregion
private void SetCoreProperties(CreateContext context, ExtensionDescriptor extensionDescriptor) { private void SetCoreProperties(CreateContext context, ExtensionDescriptor extensionDescriptor) {
PackageProperties properties = context.Package.PackageProperties; context.Builder.Id = "Orchard." + extensionDescriptor.ExtensionType + "." + extensionDescriptor.Name;
properties.Title = extensionDescriptor.DisplayName ?? extensionDescriptor.Name; context.Builder.Version = new Version(extensionDescriptor.Version);
//properties.Subject = ""; context.Builder.Title = extensionDescriptor.DisplayName ?? extensionDescriptor.Name;
properties.Creator = extensionDescriptor.Author; context.Builder.Description = extensionDescriptor.Description;
properties.Keywords = extensionDescriptor.Tags; context.Builder.Authors.Add(extensionDescriptor.Author);
properties.Description = extensionDescriptor.Description;
//properties.LastModifiedBy = "";
//properties.Revision = "";
//properties.LastPrinted = "";
//properties.Created = "";
//properties.Modified = "";
properties.Category = extensionDescriptor.Features.Where(f => f.Name == extensionDescriptor.Name).Select(f => f.Category).FirstOrDefault();
properties.Identifier = extensionDescriptor.Name;
properties.ContentType = "Orchard " + extensionDescriptor.ExtensionType;
//properties.Language = "";
properties.Version = extensionDescriptor.Version;
properties.ContentStatus = "";
}
if(Uri.IsWellFormedUriString(extensionDescriptor.WebSite, UriKind.Absolute)) {
context.Builder.ProjectUrl = new Uri(extensionDescriptor.WebSite);
}
}
private void EmbedProjectFiles(CreateContext context, params string[] itemGroupTypes) { private void EmbedProjectFiles(CreateContext context, params string[] itemGroupTypes) {
IEnumerable<XElement> itemGroups = context.Project IEnumerable<XElement> itemGroups = context.Project
@@ -125,7 +110,7 @@ namespace Orchard.Packaging.Services {
if (context.SourceFolder.FileExists(context.SourcePath + virtualPath)) { if (context.SourceFolder.FileExists(context.SourcePath + virtualPath)) {
EmbedVirtualFile(context, virtualPath, MediaTypeNames.Application.Octet); EmbedVirtualFile(context, virtualPath, MediaTypeNames.Application.Octet);
} }
else if (hintPath != null) {} else if (hintPath != null) { }
} }
} }
@@ -151,18 +136,19 @@ namespace Orchard.Packaging.Services {
private static void BeginPackage(CreateContext context) { private static void BeginPackage(CreateContext context) {
context.Stream = new MemoryStream(); context.Stream = new MemoryStream();
context.Package = Package.Open(context.Stream, FileMode.Create, FileAccess.ReadWrite); context.Builder = new NuGetPackageBuilder();
} }
private static void EstablishPaths(CreateContext context, IWebSiteFolder webSiteFolder, string locationPath, string moduleName, string moduleType) { private static void EstablishPaths(CreateContext context, IWebSiteFolder webSiteFolder, string locationPath, string moduleName, string moduleType) {
context.SourceFolder = webSiteFolder; context.SourceFolder = webSiteFolder;
if (moduleType == "Theme") { if (moduleType == "Theme") {
context.SourcePath = "~/Themes/" + moduleName + "/"; context.SourcePath = "~/Themes/" + moduleName + "/";
context.TargetPath = "\\Content\\Themes\\" + moduleName + "\\";
} }
else { else {
context.SourcePath = "~/Modules/" + moduleName + "/"; context.SourcePath = "~/Modules/" + moduleName + "/";
context.TargetPath = "\\Content\\Modules\\" + moduleName + "\\";
} }
context.TargetPath = "\\" + moduleName + "\\";
} }
private static bool LoadProject(CreateContext context, string relativePath) { private static bool LoadProject(CreateContext context, string relativePath) {
@@ -174,24 +160,24 @@ namespace Orchard.Packaging.Services {
return false; return false;
} }
private static Uri EmbedVirtualFile(CreateContext context, string relativePath, string contentType) { private static void EmbedVirtualFile(CreateContext context, string relativePath, string contentType) {
Uri partUri = PackUriHelper.CreatePartUri(new Uri(context.TargetPath + relativePath, UriKind.Relative)); var file = new VirtualPackageFile(
PackagePart packagePart = context.Package.CreatePart(partUri, contentType); context.SourceFolder,
using (Stream stream = packagePart.GetStream(FileMode.Create, FileAccess.Write)) { context.SourcePath + relativePath,
context.SourceFolder.CopyFileTo(context.SourcePath + relativePath, stream, true /*actualContent*/); context.TargetPath + relativePath);
} context.Builder.Files.Add(file);
return partUri;
} }
private static void EndPackage(CreateContext context) { private static void EndPackage(CreateContext context) {
context.Package.Close(); context.Builder.Save(context.Stream);
} }
#region Nested type: CreateContext #region Nested type: CreateContext
private class CreateContext { private class CreateContext {
public Stream Stream { get; set; } public Stream Stream { get; set; }
public Package Package { get; set; } public NuGetPackageBuilder Builder { get; set; }
public IWebSiteFolder SourceFolder { get; set; } public IWebSiteFolder SourceFolder { get; set; }
public string SourcePath { get; set; } public string SourcePath { get; set; }
@@ -201,5 +187,32 @@ namespace Orchard.Packaging.Services {
} }
#endregion #endregion
#region Nested type: CreateContext
private class VirtualPackageFile : IPackageFile {
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;
}
public string Path { get { return _packagePath; } }
public Stream GetStream() {
var stream = new MemoryStream();
_webSiteFolder.CopyFileTo(_virtualPath, stream);
stream.Seek(0, SeekOrigin.Begin);
return stream;
}
}
#endregion
} }
} }

View File

@@ -2,6 +2,7 @@ using System.IO;
namespace Orchard.Packaging.Services { namespace Orchard.Packaging.Services {
public class PackageData { public class PackageData {
public string ExtensionType { get; set; }
public string ExtensionName { get; set; } public string ExtensionName { get; set; }
public string ExtensionVersion { get; set; } public string ExtensionVersion { get; set; }

View File

@@ -1,203 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using Orchard.Environment.Extensions;
using Orchard.FileSystems.VirtualPath;
using Orchard.Localization;
namespace Orchard.Packaging.Services {
[OrchardFeature("PackagingServices")]
public class PackageExpander : IPackageExpander {
private const string ContentTypePrefix = "Orchard ";
private readonly IVirtualPathProvider _virtualPathProvider;
public PackageExpander(IVirtualPathProvider virtualPathProvider) {
_virtualPathProvider = virtualPathProvider;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
#region IPackageExpander Members
public PackageInfo ExpandPackage(Stream packageStream) {
var context = new ExpandContext();
BeginPackage(context, packageStream);
try {
GetCoreProperties(context);
EstablishPaths(context, _virtualPathProvider);
string projectFile = context.ExtensionName + ".csproj";
if (LoadProject(context, projectFile)) {
ExtractFile(context, projectFile);
ExtractProjectFiles(context, "Compile", "Content", "None", "EmbeddedResource");
ExtractReferenceFiles(context);
}
else if (context.ExtensionType == "Theme") {
// this is a simple theme with no csproj
ExtractThemeFiles(context);
}
}
finally {
EndPackage(context);
}
return new PackageInfo {
ExtensionName = context.ExtensionName,
ExtensionVersion = context.ExtensionVersion,
ExtensionType = context.ExtensionType,
ExtensionPath = context.TargetPath
};
}
#endregion
private void ExtractFile(ExpandContext context, string relativePath) {
Uri partUri = PackUriHelper.CreatePartUri(new Uri(context.SourcePath + relativePath, UriKind.Relative));
PackagePart packagePart = context.Package.GetPart(partUri);
using (Stream packageStream = packagePart.GetStream(FileMode.Open, FileAccess.Read)) {
string filePath = _virtualPathProvider.Combine(context.TargetPath, relativePath);
string folderPath = _virtualPathProvider.GetDirectoryName(filePath);
if (!_virtualPathProvider.DirectoryExists(folderPath)) {
_virtualPathProvider.CreateDirectory(folderPath);
}
using (Stream fileStream = _virtualPathProvider.CreateFile(filePath)) {
packageStream.CopyTo(fileStream);
}
}
}
private void ExtractProjectFiles(ExpandContext context, params string[] itemGroupTypes) {
IEnumerable<XElement> itemGroups = context.Project
.Elements(Ns("Project"))
.Elements(Ns("ItemGroup"));
foreach (string itemGroupType in itemGroupTypes) {
IEnumerable<string> includePaths = itemGroups
.Elements(Ns(itemGroupType))
.Attributes("Include")
.Select(x => x.Value);
foreach (string includePath in includePaths) {
ExtractFile(context, includePath);
}
}
}
private void ExtractReferenceFiles(ExpandContext context) {
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);
string hintPath = entry.HintPath != null ? entry.HintPath.Value : null;
string virtualPath = "bin/" + assemblyName.Name + ".dll";
if (PartExists(context, virtualPath)) {
ExtractFile(context, virtualPath);
}
else if (hintPath != null) {}
}
}
private void ExtractThemeFiles(ExpandContext context) {
foreach (var relativePath in from p in context.Package.GetParts()
where p.Uri.ToString().StartsWith("/" + context.ExtensionName + "/", StringComparison.OrdinalIgnoreCase)
select p.Uri.ToString().Substring(("/" + context.ExtensionName + "/").Length)) {
ExtractFile(context, relativePath);
}
}
private bool PartExists(ExpandContext context, string relativePath) {
Uri projectUri = PackUriHelper.CreatePartUri(new Uri(context.SourcePath + relativePath, UriKind.Relative));
return context.Package.PartExists(projectUri);
}
private XName Ns(string localName) {
return XName.Get(localName, "http://schemas.microsoft.com/developer/msbuild/2003");
}
private static bool LoadProject(ExpandContext context, string relativePath) {
Uri projectUri = PackUriHelper.CreatePartUri(new Uri(context.SourcePath + relativePath, UriKind.Relative));
if (!context.Package.PartExists(projectUri)) {
return false;
}
PackagePart part = context.Package.GetPart(projectUri);
using (Stream stream = part.GetStream(FileMode.Open, FileAccess.Read)) {
context.Project = XDocument.Load(stream);
}
return true;
}
private void BeginPackage(ExpandContext context, Stream packageStream) {
if (packageStream.CanSeek) {
context.Stream = packageStream;
}
else {
context.Stream = new MemoryStream();
packageStream.CopyTo(context.Stream);
}
context.Package = Package.Open(context.Stream, FileMode.Open, FileAccess.Read);
}
private void EndPackage(ExpandContext context) {
context.Package.Close();
}
private void GetCoreProperties(ExpandContext context) {
context.ExtensionName = context.Package.PackageProperties.Identifier;
context.ExtensionVersion = context.Package.PackageProperties.Version;
string contentType = context.Package.PackageProperties.ContentType;
if (contentType.StartsWith(ContentTypePrefix)) {
context.ExtensionType = contentType.Substring(ContentTypePrefix.Length);
}
}
private void EstablishPaths(ExpandContext context, IVirtualPathProvider virtualPathProvider) {
context.SourcePath = "\\" + context.ExtensionName + "\\";
switch (context.ExtensionType) {
case "Theme":
context.TargetPath = virtualPathProvider.Combine("~/Themes/" + context.ExtensionName);
break;
case "Module":
context.TargetPath = virtualPathProvider.Combine("~/Modules/" + context.ExtensionName);
break;
default:
throw new OrchardCoreException(T("Unknown extension type \"{0}\"", context.ExtensionType));
}
}
#region Nested type: ExpandContext
private class ExpandContext {
public Stream Stream { get; set; }
public Package Package { get; set; }
public string ExtensionName { get; set; }
public string ExtensionVersion { get; set; }
public string ExtensionType { get; set; }
public string TargetPath { get; set; }
public string SourcePath { get; set; }
public XDocument Project { get; set; }
}
#endregion
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.IO;
using NuGet;
using Orchard.Environment.Extensions;
using Orchard.Localization;
using Orchard.UI.Notify;
using NuGetPackageManager = NuGet.PackageManager;
namespace Orchard.Packaging.Services {
[OrchardFeature("PackagingServices")]
public class PackageInstaller : IPackageInstaller {
private const string PackagesPath = "packages";
private const string ProjectPath = "Orchard.Web";
private readonly INotifier _notifier;
public PackageInstaller(INotifier notifier) {
_notifier = notifier;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public PackageInfo Install(string packageId, string version, string location, string solutionFolder) {
var packagesPath = Path.Combine(solutionFolder, PackagesPath); // where to download/uncompress packages
var projectPath = Path.Combine(solutionFolder, ProjectPath); // where to install packages (in the project's folder)
var logger = new NugetLogger(_notifier);
// instantiates the appropriate package repository
var packageRepository = PackageRepositoryFactory.Default.CreateRepository(new PackageSource("Default", location));
// gets an IPackage instance from the repository
var packageVersion = String.IsNullOrEmpty(version) ? null : new Version(version);
var package = packageRepository.FindPackage(packageId, packageVersion);
if ( package == null ) {
throw new ArgumentException(T("The specified package could not be found, id:{0} version:{1}", packageId, String.IsNullOrEmpty(version) ? T("No version").Text : version).Text);
}
var packageManager = new NuGetPackageManager(
packageRepository,
new DefaultPackagePathResolver(location),
new PhysicalFileSystem(packagesPath) { Logger = logger }
) {Logger = logger};
// specifically tells to ignore dependencies
packageManager.InstallPackage(package, ignoreDependencies: true);
var projectManager = new ProjectManager(
new LocalPackageRepository(packagesPath), // source repository for the package to install
new DefaultPackagePathResolver(location),
new FileBasedProjectSystem(projectPath) { Logger = logger } // the location of the project (where to copy the content files)
) {Logger = logger};
// add the package to the project
projectManager.AddPackageReference(packageId, packageVersion);
return new PackageInfo {
ExtensionName = package.Title ?? package.Id,
ExtensionVersion = package.Version.ToString(),
ExtensionType = String.Empty, // todo: assign value
ExtensionPath = projectPath
};
}
public void Uninstall(string packageId, string solutionFolder) {
var packagesPath = Path.Combine(solutionFolder, PackagesPath); // where to download/uncompress packages
var projectPath = Path.Combine(solutionFolder, ProjectPath); // where to install packages (in the project's folder)
var logger = new NugetLogger(_notifier);
// instantiates the appropriate package repository
var packageRepository = PackageRepositoryFactory.Default.CreateRepository(new PackageSource("Default", packagesPath));
var projectManager = new ProjectManager(
new LocalPackageRepository(packagesPath),
new DefaultPackagePathResolver(packagesPath),
new FileBasedProjectSystem(projectPath) { Logger = logger }
) { Logger = logger };
// removes the package from the project
projectManager.RemovePackageReference(packageId);
var packageManager = new NuGetPackageManager(
packageRepository,
new DefaultPackagePathResolver(packagesPath),
new PhysicalFileSystem(packagesPath) { Logger = logger }
) { Logger = logger };
packageManager.UninstallPackage(packageId);
}
}
}

View File

@@ -1,9 +1,4 @@
using System;
using System.IO;
using System.IO.Packaging;
using System.Linq; using System.Linq;
using System.Net;
using System.Text;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
@@ -12,16 +7,13 @@ namespace Orchard.Packaging.Services {
public class PackageManager : IPackageManager { public class PackageManager : IPackageManager {
private readonly IExtensionManager _extensionManager; private readonly IExtensionManager _extensionManager;
private readonly IPackageBuilder _packageBuilder; private readonly IPackageBuilder _packageBuilder;
private readonly IPackageExpander _packageExpander; private readonly IPackageInstaller _packageExpander;
private readonly IPackagingSourceManager _packagingSourceManager;
public PackageManager( public PackageManager(
IExtensionManager extensionManager, IExtensionManager extensionManager,
IPackagingSourceManager packagingSourceManager,
IPackageBuilder packageBuilder, IPackageBuilder packageBuilder,
IPackageExpander packageExpander) { IPackageInstaller packageExpander) {
_extensionManager = extensionManager; _extensionManager = extensionManager;
_packagingSourceManager = packagingSourceManager;
_packageBuilder = packageBuilder; _packageBuilder = packageBuilder;
_packageExpander = packageExpander; _packageExpander = packageExpander;
} }
@@ -34,54 +26,20 @@ namespace Orchard.Packaging.Services {
return null; return null;
} }
return new PackageData { return new PackageData {
ExtensionType = extensionDescriptor.ExtensionType,
ExtensionName = extensionDescriptor.Name, ExtensionName = extensionDescriptor.Name,
ExtensionVersion = extensionDescriptor.Version, ExtensionVersion = extensionDescriptor.Version,
PackageStream = _packageBuilder.BuildPackage(extensionDescriptor), PackageStream = _packageBuilder.BuildPackage(extensionDescriptor),
}; };
} }
public void Push(PackageData packageData, string feedUrl, string user, string password) { public PackageInfo Install(string packageId, string version, string location, string solutionFolder) {
WebRequest request = WebRequest.Create(feedUrl); return _packageExpander.Install(packageId, version, location, solutionFolder);
request.Method = "POST";
request.ContentType = "application/x-package";
request.Headers.Add("user", Convert.ToBase64String(Encoding.UTF8.GetBytes(user)));
request.Headers.Add("password", Convert.ToBase64String(Encoding.UTF8.GetBytes(password)));
using ( Stream requestStream = request.GetRequestStream() ) {
packageData.PackageStream.Seek(0, SeekOrigin.Begin);
packageData.PackageStream.CopyTo(requestStream);
} }
using (request.GetResponse()) { public void Uninstall(string packageId, string solutionFolder) {
// forces request and disposes results _packageExpander.Uninstall(packageId, solutionFolder);
} }
}
public PackageData Download(string feedItemId) {
PackagingEntry entry = _packagingSourceManager.GetModuleList().Single(x => x.SyndicationItem.Id == feedItemId);
WebRequest request = WebRequest.Create(entry.PackageStreamUri);
using (WebResponse response = request.GetResponse()) {
using (Stream responseStream = response.GetResponseStream()) {
var stream = new MemoryStream();
responseStream.CopyTo(stream);
Package package = Package.Open(stream);
try {
return new PackageData {
ExtensionName = package.PackageProperties.Identifier,
ExtensionVersion = package.PackageProperties.Version,
PackageStream = stream
};
}
finally {
package.Close();
}
}
}
}
public PackageInfo Install(Stream packageStream) {
return _packageExpander.ExpandPackage(packageStream);
}
#endregion #endregion
} }
} }

View File

@@ -1,10 +1,16 @@
using System.ServiceModel.Syndication;
using System;
using Orchard.Packaging.Models;
namespace Orchard.Packaging.Services { namespace Orchard.Packaging.Services {
public class PackagingEntry { public class PackagingEntry {
public PackagingSource Source { get; set; } public PackagingSource Source { get; set; }
public SyndicationFeed SyndicationFeed { get; set; } public string Title { get; set; }
public SyndicationItem SyndicationItem { get; set; } public string PackageId { get; set; }
public string Version { get; set; }
public string PackageStreamUri { get; set; } public string PackageStreamUri { get; set; }
public DateTime LastUpdated { get; set; }
public string Authors { get; set; }
public string Description { get; set; }
} }
} }

View File

@@ -1,9 +0,0 @@
using System;
namespace Orchard.Packaging.Services {
public class PackagingSource {
public Guid Id { get; set; }
public string FeedTitle { get; set; }
public string FeedUrl { get; set; }
}
}

View File

@@ -1,26 +1,22 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.ServiceModel.Syndication; using NuGet;
using System.Xml; using Orchard.Data;
using System.Xml.Linq;
using System.Xml.Serialization;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.FileSystems.AppData;
using Orchard.Localization; using Orchard.Localization;
using Orchard.UI.Notify; using Orchard.Packaging.Models;
namespace Orchard.Packaging.Services { namespace Orchard.Packaging.Services {
[OrchardFeature("PackagingServices")] [OrchardFeature("PackagingServices")]
public class PackagingSourceManager : IPackagingSourceManager { public class PackagingSourceManager : IPackagingSourceManager {
private static readonly XmlSerializer _sourceSerializer = new XmlSerializer(typeof(List<PackagingSource>), new XmlRootAttribute("Sources")); private const string ModulesFilter = "Orchard.Module.";
private readonly IAppDataFolder _appDataFolder; private const string ThemesFilter = "Orchard.Theme.";
private readonly INotifier _notifier;
public PackagingSourceManager(IAppDataFolder appDataFolder, INotifier notifier) { private readonly IRepository<PackagingSource> _packagingSourceRecordRepository;
_appDataFolder = appDataFolder;
_notifier = notifier; public PackagingSourceManager(IRepository<PackagingSource> packagingSourceRecordRepository) {
_packagingSourceRecordRepository = packagingSourceRecordRepository;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
@@ -29,99 +25,49 @@ namespace Orchard.Packaging.Services {
#region IPackagingSourceManager Members #region IPackagingSourceManager Members
public IEnumerable<PackagingSource> GetSources() { public IEnumerable<PackagingSource> GetSources() {
string text = _appDataFolder.ReadFile(GetSourcesPath()); return _packagingSourceRecordRepository.Table.ToList();
if ( string.IsNullOrEmpty(text) ) {
return Enumerable.Empty<PackagingSource>();
} }
var textReader = new StringReader(_appDataFolder.ReadFile(GetSourcesPath())); public void AddSource(string feedTitle, string feedUrl) {
return (IEnumerable<PackagingSource>)_sourceSerializer.Deserialize(textReader); var packagingSource = new PackagingSource {FeedTitle = feedTitle, FeedUrl = feedUrl};
_packagingSourceRecordRepository.Create(packagingSource);
} }
public void AddSource(PackagingSource source) { public void RemoveSource(int id) {
SaveSources(GetSources().Concat(new[] { source }).GroupBy(x => x.FeedUrl).Select(g => g.First())); var packagingSource = _packagingSourceRecordRepository.Get(id);
} if(packagingSource != null) {
_packagingSourceRecordRepository.Delete(packagingSource);
public void RemoveSource(Guid id) {
SaveSources(GetSources().Where(x => x.Id != id));
}
public void UpdateLists() {
foreach ( PackagingSource source in GetSources() ) {
UpdateSource(source);
} }
} }
public IEnumerable<PackagingEntry> GetModuleList(PackagingSource packagingSource = null) { public IEnumerable<PackagingEntry> GetModuleList(PackagingSource packagingSource = null) {
return (packagingSource == null ? GetSources() : new[] {packagingSource}) return GetExtensionList(ModulesFilter, packagingSource);
.SelectMany( }
source => public IEnumerable<PackagingEntry> GetThemeList(PackagingSource packagingSource = null) {
Bind(ParseFeed(GetModuleListForSource(source)), return GetExtensionList(ThemesFilter, packagingSource);
feed =>
feed.Items.SelectMany(
item =>
Unit(new PackagingEntry {
Source = source,
SyndicationFeed = feed,
SyndicationItem = item,
PackageStreamUri = item.Links.Where(l => String.IsNullOrEmpty(l.RelationshipType)).FirstOrDefault().GetAbsoluteUri().AbsoluteUri,
})))).ToArray();
} }
private string GetModuleListForSource(PackagingSource source) { private IEnumerable<PackagingEntry> GetExtensionList(string filter = null, PackagingSource packagingSource = null) {
if ( !_appDataFolder.FileExists(GetFeedCachePath(source)) ) { return ( packagingSource == null ? GetSources() : new[] { packagingSource } )
UpdateSource(source); .SelectMany(
} source =>
return _appDataFolder.ReadFile(GetFeedCachePath(source)); new DataServicePackageRepository(new Uri(source.FeedUrl))
.GetPackages()
.Where(p => p.Id.StartsWith(filter ?? String.Empty))
.ToList()
.Select(p => new PackagingEntry {
Title = String.IsNullOrWhiteSpace(p.Title) ? p.Id : p.Title,
PackageId = p.Id,
PackageStreamUri = p.ProjectUrl != null ? p.ProjectUrl.ToString() : String.Empty,
Source = source,
Version = p.Version != null ? p.Version.ToString() : String.Empty,
Description = p.Description,
Authors = p.Authors != null ? String.Join(", ", p.Authors) : String.Empty,
})
).ToArray();
} }
#endregion #endregion
private static string GetSourcesPath() {
return ".Packaging/Sources.xml";
}
private static string GetFeedCachePath(PackagingSource source) {
return ".Packaging/Feed." + source.Id.ToString("n") + ".xml";
}
private void SaveSources(IEnumerable<PackagingSource> sources) {
var textWriter = new StringWriter();
_sourceSerializer.Serialize(textWriter, sources.ToList());
_appDataFolder.CreateFile(GetSourcesPath(), textWriter.ToString());
}
private void UpdateSource(PackagingSource source) {
try {
XDocument feed = XDocument.Load(source.FeedUrl, LoadOptions.PreserveWhitespace);
_appDataFolder.CreateFile(GetFeedCachePath(source), feed.ToString(SaveOptions.DisableFormatting));
}
catch ( Exception e ) {
_notifier.Warning(T("Error loading content of feed '{0}': {1}", source.FeedUrl, e.Message));
}
}
private static XName Atom(string localName) {
return AtomExtensions.AtomXName(localName);
}
private static IEnumerable<T> Unit<T>(T t) where T : class {
return t != null ? new[] { t } : Enumerable.Empty<T>();
}
private static IEnumerable<T2> Bind<T, T2>(T t, Func<T, IEnumerable<T2>> f) where T : class {
return Unit(t).SelectMany(f);
}
private SyndicationFeed ParseFeed(string content) {
if ( string.IsNullOrEmpty(( content )) )
return new SyndicationFeed();
var formatter = new Atom10FeedFormatter<SyndicationFeed>();
formatter.ReadFrom(XmlReader.Create(new StringReader(content)));
return formatter.Feed;
}
} }
} }

View File

@@ -1,9 +1,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.Packaging.Models;
using Orchard.Packaging.Services; using Orchard.Packaging.Services;
namespace Orchard.Packaging.ViewModels { namespace Orchard.Packaging.ViewModels {
public class PackagingModulesViewModel { public class PackagingExtensionsViewModel {
public IEnumerable<PackagingEntry> Modules { get; set; } public IEnumerable<PackagingEntry> Extensions { get; set; }
public IEnumerable<PackagingSource> Sources { get; set; } public IEnumerable<PackagingSource> Sources { get; set; }
public PackagingSource SelectedSource { get; set; } public PackagingSource SelectedSource { get; set; }
} }

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
using Orchard.Packaging.Services; using Orchard.Packaging.Models;
namespace Orchard.Packaging.ViewModels { namespace Orchard.Packaging.ViewModels {
public class PackagingHarvestViewModel { public class PackagingHarvestViewModel {

View File

@@ -1,5 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.Packaging.Services; using Orchard.Packaging.Models;
namespace Orchard.Packaging.ViewModels { namespace Orchard.Packaging.ViewModels {
public class PackagingSourcesViewModel { public class PackagingSourcesViewModel {

View File

@@ -23,7 +23,7 @@
} }
<fieldset> <fieldset>
@Html.LabelFor(m => m.FeedUrl, T("Feed Url")) @Html.LabelFor(m => m.FeedUrl, T("Feed Url"))
@Html.DropDownListFor(m => m.FeedUrl, new[]{new SelectListItem{Text=T("Download").ToString(),Value="Download"}}.Concat( Model.Sources.Select(x => new SelectListItem { Text = T("Push to {0}", x.FeedUrl).ToString(), Value = x.FeedUrl }))) @Html.DropDownListFor(m => m.FeedUrl, new[]{new SelectListItem{Text=T("Download").ToString(),Value=""}}.Concat( Model.Sources.Select(x => new SelectListItem { Text = T("Push to {0}", x.FeedUrl).ToString(), Value = x.FeedUrl })))
@Html.ValidationMessageFor(m=>m.FeedUrl) @Html.ValidationMessageFor(m=>m.FeedUrl)
</fieldset> </fieldset>
<fieldset> <fieldset>

View File

@@ -1,11 +1,10 @@
@model Orchard.Packaging.ViewModels.PackagingModulesViewModel @model Orchard.Packaging.ViewModels.PackagingExtensionsViewModel
@using System.Linq; @using System.Linq;
@{ Style.Require("PackagingAdmin"); } @{ Style.Require("PackagingAdmin"); }
<h1>@Html.TitleForPage(T("Browse Gallery - Modules").ToString())</h1> <h1>@Html.TitleForPage(T("Browse Gallery - Modules").Text)</h1>
<div class="manage">@Html.ActionLink(T("Refresh").ToString(), "Update", new { cameFrom = "Modules" }, new { @class = "button primaryAction" })</div>
@using ( Html.BeginFormAntiForgeryPost(Url.Action("Modules", "Gallery")) ) { @using ( Html.BeginFormAntiForgeryPost(Url.Action("Modules", "Gallery")) ) {
<fieldset class="bulk-actions"> <fieldset class="bulk-actions">
<label for="filterResults" class="bulk-filter">@T("Feed:")</label> <label for="filterResults" class="bulk-filter">@T("Feed:")</label>
@@ -20,24 +19,24 @@
} }
@if (Model.Modules.Count() > 0) { @if (Model.Extensions.Count() > 0) {
<ul class="contentItems"> <ul class="contentItems">
@foreach (var item in Model.Modules) { @foreach (var item in Model.Extensions) {
<li> <li>
<div class="moduleName"> <div class="moduleName">
<h2>@(item.SyndicationItem.Title == null ? T("(No title)").Text : item.SyndicationItem.Title.Text)<span> - @T("Version: {0}", item.SyndicationItem.ElementExtensions.ReadElementExtensions<string>("Version", "http://orchardproject.net").FirstOrDefault() ?? T("N/A").Text)</span></h2> <h2>@item.Title<span> - @T("Version: {0}", item.Version)</span></h2>
</div> </div>
<div class="related"> <div class="related">
@Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary {{"SyndicationId",item.SyndicationItem.Id},{"cameFrom", "Modules"}})@T(" | ") @Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary {{"SyndicationId", item.PackageId},{"cameFrom", "Modules"}})@T(" | ")
<a href="@item.PackageStreamUri">@T("Download")</a> <a href="@item.PackageStreamUri">@T("Download")</a>
</div> </div>
<div class="properties"> <div class="properties">
<p>@(item.SyndicationItem.Summary == null ? T("(No description").Text : item.SyndicationItem.Summary.Text)</p> <p>@(item.Description == null ? T("(No description").Text : item.Description)</p>
<ul class="pageStatus"> <ul class="pageStatus">
<li>@T("Last Updated: {0}", item.SyndicationItem.LastUpdatedTime.ToLocalTime())</li> @*todo: (sebros) find a way to get the update date*@<li style="color:red">@T("Last Updated: {0}", DateTime.Now.ToLocalTime())</li>
<li>&nbsp;&#124;&nbsp;@T("Author: {0}", item.SyndicationItem.Authors.Any() ? String.Join(", ", item.SyndicationItem.Authors.Select(a => a.Name)) : T("Unknown").Text)</li> <li>&nbsp;&#124;&nbsp;@T("Author: {0}", item.Authors)</li>
</ul> </ul>
</div> </div>
</li>} </li>}

View File

@@ -1,4 +1,4 @@
@model Orchard.Packaging.ViewModels.PackagingModulesViewModel @model Orchard.Packaging.ViewModels.PackagingExtensionsViewModel
@{ @{
Style.Require("PackagingAdmin"); Style.Require("PackagingAdmin");
Style.Require("ThemesAdmin"); Style.Require("ThemesAdmin");

View File

@@ -94,6 +94,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.PublishLater", "Orc
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Lists", "Orchard.Web\Modules\Orchard.Lists\Orchard.Lists.csproj", "{137906EA-15FE-4AD8-A6A0-27528F0477D6}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Lists", "Orchard.Web\Modules\Orchard.Lists\Orchard.Lists.csproj", "{137906EA-15FE-4AD8-A6A0-27528F0477D6}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "External", "External", "{104288A3-382E-4032-AF50-FBB5FDAB9EBB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuPack.Core", "..\external\nuget\NuPack.Core\NuPack.Core.csproj", "{F879F274-EFA0-4157-8404-33A19B4E6AEC}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
CodeCoverage|Any CPU = CodeCoverage|Any CPU CodeCoverage|Any CPU = CodeCoverage|Any CPU
@@ -542,5 +546,6 @@ Global
{8A4E42CE-79F8-4BE2-8B1E-A6B83432123B} = {383DBA32-4A3E-48D1-AAC3-75377A694452} {8A4E42CE-79F8-4BE2-8B1E-A6B83432123B} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
{0DFA2E10-96C8-4E05-BC10-B710B97ECCDE} = {383DBA32-4A3E-48D1-AAC3-75377A694452} {0DFA2E10-96C8-4E05-BC10-B710B97ECCDE} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
{CB70A642-8CEC-4DDE-8C9F-AD08900EC98D} = {74492CBC-7201-417E-BC29-28B4C25A58B0} {CB70A642-8CEC-4DDE-8C9F-AD08900EC98D} = {74492CBC-7201-417E-BC29-28B4C25A58B0}
{F879F274-EFA0-4157-8404-33A19B4E6AEC} = {104288A3-382E-4032-AF50-FBB5FDAB9EBB}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal