Incremental work prototyping packaging

Extends Orchard.Modules with Orchard.Modules.Packaging feature
IWebSiteFolder capabilities to test FileExists and pull binaries via CopyFileTo
Adds rough web-based mechanism for command execution

--HG--
branch : dev
This commit is contained in:
Louis DeJardin 2010-07-04 14:14:15 -07:00
parent f100c7c2ad
commit 7e9c238847
21 changed files with 601 additions and 16 deletions

View File

@ -14,6 +14,10 @@ namespace Orchard.Tests.Stubs {
return Directory.GetDirectories(path);
}
public bool FileExists(string virtualPath) {
throw new NotImplementedException();
}
public string ReadFile(string path) {
if (!File.Exists(path))
return null;
@ -21,6 +25,10 @@ namespace Orchard.Tests.Stubs {
return File.ReadAllText(path);
}
public void CopyFileTo(string virtualPath, Stream destination) {
throw new NotImplementedException();
}
public IVolatileToken WhenPathChanges(string path) {
return new Token {IsCurrent = true};
}

View File

@ -0,0 +1,46 @@
using System;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using Orchard.Commands;
using Orchard.DevTools.ViewModels;
using Orchard.Environment.Extensions;
using Orchard.Themes;
using Orchard.UI.Admin;
namespace Orchard.DevTools.Controllers {
[Themed, Admin, OrchardFeature("Orchard.DevTools.WebCommandLine")]
public class CommandsController : Controller {
private readonly ICommandManager _commandManager;
public CommandsController(ICommandManager commandManager) {
_commandManager = commandManager;
}
public ActionResult Index() {
return Execute();
}
public ActionResult Execute() {
return View("Execute", new CommandsExecuteViewModel());
}
[HttpPost]
public ActionResult Execute(CommandsExecuteViewModel model) {
var writer = new StringWriter();
var parameters = new CommandParameters {
Arguments = model.CommandLine.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries),
Output = writer
};
_commandManager.Execute(parameters);
model.History = (model.History ?? Enumerable.Empty<string>())
.Concat(new[] { model.CommandLine })
.Distinct()
.ToArray();
model.Results = writer.ToString();
return View("Execute", model);
}
}
}

View File

@ -16,4 +16,7 @@ features:
Profiling:
Description: Tools to help profile Orchard.
Category: Developer
Dependencies: Orchard.DevTools
Dependencies: Orchard.DevTools
Orchard.DevTools.WebCommandLine:
Description: Enables site administrators to execute Orchard.exe commands via web interface
Category: Developer

View File

@ -72,6 +72,7 @@
<Compile Include="AdminMenu.cs" />
<Compile Include="Commands\ProfilingCommands.cs" />
<Compile Include="Commands\ScaffoldingCommands.cs" />
<Compile Include="Controllers\CommandsController.cs" />
<Compile Include="Controllers\ContentController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\MetadataController.cs" />
@ -81,6 +82,7 @@
<Compile Include="Permissions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings\DevToolsSettings.cs" />
<Compile Include="ViewModels\CommandsExecuteViewModel.cs" />
<Compile Include="ViewModels\ContentIndexViewModel.cs" />
<Compile Include="ViewModels\ContentDetailsViewModel.cs" />
<Compile Include="ViewModels\MetadataIndexViewModel.cs" />
@ -92,6 +94,7 @@
<Content Include="ScaffoldingTemplates\ModuleCsProj.txt" />
<Content Include="ScaffoldingTemplates\ModuleManifest.txt" />
<Content Include="ScaffoldingTemplates\ModuleWebConfig.txt" />
<Content Include="Views\Commands\Execute.ascx" />
<Content Include="Views\DefinitionTemplates\DevToolsSettings.ascx" />
<Content Include="Views\Home\_RenderableAction.ascx" />
<Content Include="Views\Home\Simple.aspx" />

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Orchard.DevTools.ViewModels {
public class CommandsExecuteViewModel {
public string[] History { get; set; }
public string CommandLine { get; set; }
public string Results { get; set; }
}
}

View File

@ -0,0 +1,19 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.DevTools.ViewModels.CommandsExecuteViewModel>" %>
<h1>
<%: Html.TitleForPage(T("Command line").ToString()) %></h1>
<div>
<% using (Html.BeginFormAntiForgeryPost(Url.Action("Execute"))) {%>
<%:Html.ValidationSummary()%>
<ul>
<%for (int index = 0; index != (Model.History ?? new string[0]).Length; ++index) {%><li>
<%:Model.History[index]%>
<%:Html.HiddenFor(m => m.History[index])%>
</li>
<%
}%></ul>
<%:Html.LabelFor(m => m.CommandLine)%>
<%:Html.TextBoxFor(m => m.CommandLine, new { style = "width:100%;" })%>
<%:Html.ValidationMessageFor(m => m.CommandLine)%>
<pre><%: Model.Results%></pre>
<%}%>
</div>

View File

@ -8,4 +8,7 @@ description: The Modules module enables the administrator of the site to manage
features:
Orchard.Modules:
Description: Standard module and feature management.
Category: Core
Category: Core
Orchard.Modules.Packaging:
Description: Standard module and feature management.
Category: Developer

View File

@ -63,6 +63,7 @@
<Reference Include="System.EnterpriseServices" />
<Reference Include="System.Web.Mobile" />
<Reference Include="System.Xml.Linq" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="AdminMenu.cs" />
@ -70,6 +71,11 @@
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="Models\ModuleFeature.cs" />
<Compile Include="Packaging\Commands\PackagingCommands.cs" />
<Compile Include="Packaging\Controllers\PackagingController.cs" />
<Compile Include="Packaging\Services\PackageBuilder.cs" />
<Compile Include="Packaging\Services\PackageRepository.cs" />
<Compile Include="Packaging\ViewModels\PackagingIndexViewModel.cs" />
<Compile Include="ViewModels\FeaturesViewModel.cs" />
<Compile Include="Models\Module.cs" />
<Compile Include="Permissions.cs" />
@ -88,6 +94,8 @@
<Content Include="styles\jquery.switchable.css" />
<Content Include="Views\Admin\Add.ascx" />
<Content Include="Views\Admin\Index.ascx" />
<Content Include="Views\Packaging\Sources.ascx" />
<Content Include="Views\Packaging\Modules.ascx" />
<Content Include="Web.config" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Hosting;
using Orchard.Commands;
using Orchard.Environment.Extensions;
using Orchard.Modules.Packaging.Services;
namespace Orchard.Modules.Packaging.Commands {
[OrchardFeature("Orchard.Modules.Packaging")]
public class PackagingCommands : DefaultOrchardCommandHandler {
private readonly IPackageBuilder _packageBuilder;
public PackagingCommands(IPackageBuilder packageBuilder) {
_packageBuilder = packageBuilder;
}
[CommandHelp("harvest <moduleName>\r\n\t" + "Package a module into a distributable")]
[CommandName("harvest")]
public void PackageCreate(string moduleName) {
var stream = _packageBuilder.Create(moduleName);
if (stream.CanSeek)
stream.Seek(0, SeekOrigin.Begin);
using(var fileStream = new FileStream(HostingEnvironment.MapPath("~/Modules/" + moduleName + ".zip"), FileMode.Create, FileAccess.Write)) {
const int chunk = 512;
var dataBuffer = new byte[3*chunk];
var charBuffer = new char[4*chunk + 2];
for (;;) {
var dataCount = stream.Read(dataBuffer, 0, dataBuffer.Length);
if (dataCount <= 0)
return;
fileStream.Write(dataBuffer, 0, dataCount);
var charCount = Convert.ToBase64CharArray(dataBuffer, 0, dataCount, charBuffer, 0);
Context.Output.Write(charBuffer, 0, charCount);
}
}
}
[CommandHelp("harvest post <moduleName> <feedUrl>\r\n\t" + "Package a module into a distributable and push it to a feed server.")]
[CommandName("harvest post")]
public void PackageCreate(string moduleName, string feed) {
var stream = _packageBuilder.Create(moduleName);
if (stream.CanSeek)
stream.Seek(0, SeekOrigin.Begin);
var request = WebRequest.Create(feed);
request.Method = "POST";
request.ContentType = "application/x-package";
using (var requestStream = request.GetRequestStream()) {
stream.CopyTo(requestStream);
}
try {
using (var response = request.GetResponse()) {
Context.Output.Write("Success: {0}", response.ResponseUri);
}
}
catch (WebException webException) {
var text = new StreamReader(webException.Response.GetResponseStream()).ReadToEnd();
throw new ApplicationException(text);
}
}
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Web.Mvc;
using Orchard.Environment.Extensions;
using Orchard.Modules.Packaging.Services;
using Orchard.Modules.Packaging.ViewModels;
using Orchard.Themes;
using Orchard.UI.Admin;
namespace Orchard.Modules.Packaging.Controllers {
[Admin, Themed, OrchardFeature("Orchard.Modules.Packaging")]
public class PackagingController : Controller {
private readonly IPackageRepository _packageRepository;
public PackagingController(IPackageRepository packageRepository) {
_packageRepository = packageRepository;
}
public ActionResult Index() {
return Modules();
}
public ActionResult Modules() {
return View("Modules", new PackagingIndexViewModel {
Modules = _packageRepository.GetModuleList()
});
}
public ActionResult Sources() {
return View("Sources", new PackagingIndexViewModel {
Sources = _packageRepository.GetSources(),
});
}
public ActionResult AddSource(string url) {
_packageRepository.AddSource(new PackageSource { Id = Guid.NewGuid(), FeedUrl = url });
return RedirectToAction("Index");
}
public ActionResult Update() {
_packageRepository.UpdateLists();
//notifier
return RedirectToAction("Index");
}
}
}

View File

@ -0,0 +1,165 @@
using System;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Linq;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.WebSite;
namespace Orchard.Modules.Packaging.Services {
public interface IPackageBuilder : IDependency {
Stream Create(string moduleName);
}
[OrchardFeature("Orchard.Modules.Packaging")]
public class PackageBuilder : IPackageBuilder {
private readonly IExtensionManager _extensionManager;
private readonly IWebSiteFolder _webSiteFolder;
public PackageBuilder(IExtensionManager extensionManager, IWebSiteFolder webSiteFolder) {
_extensionManager = extensionManager;
_webSiteFolder = webSiteFolder;
}
class CreateContext {
public Stream Stream { get; set; }
public Package Package { get; set; }
public IWebSiteFolder SourceFolder { get; set; }
public string SourcePath { get; set; }
public string TargetPath { get; set; }
public XDocument Project { get; set; }
}
public Stream Create(string moduleName) {
var extensionDescriptor = _extensionManager
.AvailableExtensions()
.FirstOrDefault(x => x.Name == moduleName);
return Create(extensionDescriptor);
}
public Stream Create(ExtensionDescriptor extensionDescriptor) {
var projectFile = extensionDescriptor.Name + ".csproj";
var context = new CreateContext();
BeginPackage(context);
EstablishPaths(context, _webSiteFolder, extensionDescriptor.Location, extensionDescriptor.Name);
SetCoreProperties(context, extensionDescriptor);
if (LoadProject(context, projectFile)) {
EmbedVirtualFile(context, projectFile, System.Net.Mime.MediaTypeNames.Text.Xml);
EmbedProjectFiles(context, "Compile", "Content", "None", "EmbeddedResource");
EmbedReferenceFiles(context);
}
EndPackage(context);
return context.Stream;
}
private void SetCoreProperties(CreateContext context, ExtensionDescriptor extensionDescriptor) {
var properties = context.Package.PackageProperties;
properties.Title = extensionDescriptor.DisplayName ?? extensionDescriptor.Name;
//properties.Subject = "";
properties.Creator = extensionDescriptor.Author;
properties.Keywords = extensionDescriptor.Tags;
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 = "";
}
private void EmbedProjectFiles(CreateContext context, params string[] itemGroupTypes) {
var itemGroups = context.Project
.Elements(Ns("Project"))
.Elements(Ns("ItemGroup"));
foreach (var itemGroupType in itemGroupTypes) {
var includePaths = itemGroups
.Elements(Ns(itemGroupType))
.Attributes("Include")
.Select(x => x.Value);
foreach (var includePath in includePaths) {
EmbedVirtualFile(context, includePath, System.Net.Mime.MediaTypeNames.Application.Octet);
}
}
}
private void EmbedReferenceFiles(CreateContext 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);
var hintPath = entry.HintPath != null ? entry.HintPath.Value : null;
var virtualPath = "bin/" + assemblyName.Name + ".dll";
if (context.SourceFolder.FileExists(context.SourcePath + virtualPath)) {
EmbedVirtualFile(context, virtualPath, System.Net.Mime.MediaTypeNames.Application.Octet);
}
else if (hintPath != null) {
}
}
}
private XName Ns(string localName) {
return XName.Get(localName, "http://schemas.microsoft.com/developer/msbuild/2003");
}
static void BeginPackage(CreateContext context) {
context.Stream = new MemoryStream();
context.Package = Package.Open(context.Stream, FileMode.Create, FileAccess.ReadWrite);
}
static void EstablishPaths(CreateContext context, IWebSiteFolder webSiteFolder, string locationPath, string moduleName) {
context.SourceFolder = webSiteFolder;
context.SourcePath = "~/Modules/" + moduleName + "/";
context.TargetPath = "\\" + moduleName + "\\";
}
static bool LoadProject(CreateContext context, string relativePath) {
var virtualPath = context.SourcePath + relativePath;
if (context.SourceFolder.FileExists(virtualPath)) {
context.Project = XDocument.Parse(context.SourceFolder.ReadFile(context.SourcePath + relativePath));
return true;
}
return false;
}
static Uri EmbedVirtualFile(CreateContext context, string relativePath, string contentType) {
var partUri = PackUriHelper.CreatePartUri(new Uri(context.TargetPath + relativePath, UriKind.Relative));
var packagePart = context.Package.CreatePart(partUri, contentType);
using (var stream = packagePart.GetStream(FileMode.Create, FileAccess.Write)) {
context.SourceFolder.CopyFileTo(context.SourcePath + relativePath, stream);
}
return partUri;
}
static void EndPackage(CreateContext context) {
context.Package.Close();
}
}
}

View File

@ -0,0 +1,141 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Xml.Linq;
using System.Xml.Serialization;
using Orchard.Environment.Extensions;
using Orchard.FileSystems.AppData;
namespace Orchard.Modules.Packaging.Services {
public interface IPackageRepository : IDependency {
IEnumerable<PackageSource> GetSources();
void AddSource(PackageSource source);
void RemoveSource(Guid id);
void UpdateLists();
IEnumerable<PackageInfo> GetModuleList();
}
public class PackageSource {
public Guid Id { get; set; }
public string FeedUrl { get; set; }
}
public class PackageInfo {
public PackageSource Source { get; set; }
public AtomEntry AtomEntry { get; set; }
}
public class AtomEntry {
public string Id { get; set; }
public string Title { get; set; }
public string Updated { get; set; }
}
static class AtomExtensions {
public static string Atom(this XElement entry, string localName) {
var element = entry.Element(AtomXName(localName));
return element != null ? element.Value : null;
}
public static XName AtomXName(string localName) {
return XName.Get(localName, "http://www.w3.org/2005/Atom");
}
}
[OrchardFeature("Orchard.Modules.Packaging")]
public class PackageRepository : IPackageRepository {
private readonly IAppDataFolder _appDataFolder;
private static readonly XmlSerializer _sourceSerializer = new XmlSerializer(typeof(List<PackageSource>), new XmlRootAttribute("Sources"));
public PackageRepository(IAppDataFolder appDataFolder) {
_appDataFolder = appDataFolder;
}
static string GetSourcesPath() {
return ".Packaging/Sources.xml";
}
static string GetFeedCachePath(PackageSource source) {
return ".Packaging/Feed." + source.Id.ToString("n") + ".xml";
}
public IEnumerable<PackageSource> GetSources() {
var text = _appDataFolder.ReadFile(GetSourcesPath());
if (string.IsNullOrEmpty(text))
return Enumerable.Empty<PackageSource>();
var textReader = new StringReader(_appDataFolder.ReadFile(GetSourcesPath()));
return (IEnumerable<PackageSource>)_sourceSerializer.Deserialize(textReader);
}
void SaveSources(IEnumerable<PackageSource> sources) {
var textWriter = new StringWriter();
_sourceSerializer.Serialize(textWriter, sources.ToList());
_appDataFolder.CreateFile(GetSourcesPath(), textWriter.ToString());
}
public void AddSource(PackageSource source) {
UpdateSource(source);
SaveSources(GetSources().Concat(new[] { source }));
}
public void RemoveSource(Guid id) {
SaveSources(GetSources().Where(x => x.Id != id));
}
public void UpdateLists() {
foreach (var source in GetSources()) {
UpdateSource(source);
}
}
private void UpdateSource(PackageSource source) {
var feed = XDocument.Load(source.FeedUrl, LoadOptions.PreserveWhitespace);
_appDataFolder.CreateFile(GetFeedCachePath(source), feed.ToString(SaveOptions.DisableFormatting));
}
static XName Atom(string localName) {
return AtomExtensions.AtomXName(localName);
}
public IEnumerable<PackageInfo> GetModuleList() {
var packageInfos = GetSources()
.SelectMany(
source =>
Bind(_appDataFolder.ReadFile(GetFeedCachePath(source)),
content =>
XDocument.Parse(content)
.Elements(Atom("feed"))
.Elements(Atom("entry"))
.SelectMany(
element =>
Bind(new AtomEntry {
Id = element.Atom("id"),
Title = element.Atom("title"),
Updated = element.Atom("updated"),
},
atom =>
Unit(new PackageInfo {
Source = source,
AtomEntry = atom,
})))));
return packageInfos.ToArray();
}
static IEnumerable<T> Unit<T>(T t) where T : class {
return t != null ? new[] { t } : Enumerable.Empty<T>();
}
static IEnumerable<T2> Bind<T, T2>(T t, Func<T, IEnumerable<T2>> f) where T : class {
return Unit(t).SelectMany(f);
}
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.Modules.Packaging.Services;
namespace Orchard.Modules.Packaging.ViewModels {
public class PackagingIndexViewModel {
public IEnumerable<PackageSource> Sources { get; set; }
public IEnumerable<PackageInfo> Modules { get; set; }
}
}

View File

@ -0,0 +1,7 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Modules.Packaging.ViewModels.PackagingIndexViewModel>" %>
<%@ Import Namespace="Orchard.Mvc.Html"%>
<h1><%: Html.TitleForPage(T("Packages").ToString()) %></h1>
<p><%:Html.ActionLink("Update List", "Update") %> &bull; <%:Html.ActionLink("Edit Sources", "Sources") %></p>
<ul><%foreach (var item in Model.Modules) {%><li><%:item.AtomEntry.Title %></li><%
}%></ul>

View File

@ -0,0 +1,13 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Modules.Packaging.ViewModels.PackagingIndexViewModel>" %>
<%@ Import Namespace="Orchard.Mvc.Html" %>
<h1>
<%: Html.TitleForPage(T("Packages").ToString()) %></h1>
<ul>
<%foreach (var item in Model.Sources) {%><li>
<%:Html.Link(item.FeedUrl, item.FeedUrl)%></li><%
}%></ul>
<%using (Html.BeginFormAntiForgeryPost(Url.Action("AddSource"))) {%>
Url:
<%:Html.TextBox("url") %>
<input type="submit" value="Add Source" />
<%} %>

View File

@ -71,6 +71,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Indexing", "Orchard
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.ContentTypes", "Orchard.Web\Modules\Orchard.ContentTypes\Orchard.ContentTypes.csproj", "{0E7646E8-FE8F-43C1-8799-D97860925EC4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PackageIndexReferenceImplementation", "Tools\PackageIndexReferenceImplementation\PackageIndexReferenceImplementation.csproj", "{8A4E42CE-79F8-4BE2-8B1E-A6B83432123B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -201,6 +203,10 @@ Global
{0E7646E8-FE8F-43C1-8799-D97860925EC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0E7646E8-FE8F-43C1-8799-D97860925EC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0E7646E8-FE8F-43C1-8799-D97860925EC4}.Release|Any CPU.Build.0 = Release|Any CPU
{8A4E42CE-79F8-4BE2-8B1E-A6B83432123B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A4E42CE-79F8-4BE2-8B1E-A6B83432123B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A4E42CE-79F8-4BE2-8B1E-A6B83432123B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A4E42CE-79F8-4BE2-8B1E-A6B83432123B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -233,6 +239,7 @@ Global
{5E5E7A21-C7B2-44D8-8593-2F9541AE041D} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
{4AB4B5B6-277E-4FF6-B69B-7AE9E16D2A56} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
{33B1BC8D-E292-4972-A363-22056B207156} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
{8A4E42CE-79F8-4BE2-8B1E-A6B83432123B} = {383DBA32-4A3E-48D1-AAC3-75377A694452}
{E65E5633-C0FF-453C-A906-481C14F969D6} = {E75A4CE4-CAA6-41E4-B951-33ACC60DC77C}
EndGlobalSection
EndGlobal

View File

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Orchard.Commands {
public class CommandParameters {

View File

@ -1,5 +1,9 @@
namespace Orchard.Environment.Extensions.Models {
public class FeatureDescriptor {
public FeatureDescriptor() {
Dependencies = new string[0];
}
public ExtensionDescriptor Extension { get; set; }
public string Name { get; set; }

View File

@ -93,8 +93,8 @@ namespace Orchard.FileSystems.AppData {
}
public void CreateFile(string path, string content) {
using(var stream = CreateFile(path)) {
using(var tw = new StreamWriter(stream)) {
using (var stream = CreateFile(path)) {
using (var tw = new StreamWriter(stream)) {
tw.Write(content);
}
}
@ -109,7 +109,8 @@ namespace Orchard.FileSystems.AppData {
}
public string ReadFile(string path) {
return File.ReadAllText(CombineToPhysicalPath(path));
var physicalPath = CombineToPhysicalPath(path);
return File.Exists(physicalPath) ? File.ReadAllText(physicalPath) : null;
}
public Stream OpenFile(string path) {
@ -145,9 +146,9 @@ namespace Orchard.FileSystems.AppData {
var files = Directory.GetFiles(directoryPath);
return files.Select(file => {
var fileName = Path.GetFileName(file);
return Combine(path, fileName);
});
var fileName = Path.GetFileName(file);
return Combine(path, fileName);
});
}
public IEnumerable<string> ListDirectories(string path) {
@ -158,9 +159,9 @@ namespace Orchard.FileSystems.AppData {
var files = Directory.GetDirectories(directoryPath);
return files.Select(file => {
var fileName = Path.GetFileName(file);
return Combine(path, fileName);
});
var fileName = Path.GetFileName(file);
return Combine(path, fileName);
});
}
public void CreateDirectory(string path) {

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using Orchard.Caching;
namespace Orchard.FileSystems.WebSite {
@ -8,7 +9,10 @@ namespace Orchard.FileSystems.WebSite {
/// </summary>
public interface IWebSiteFolder : IVolatileProvider {
IEnumerable<string> ListDirectories(string virtualPath);
bool FileExists(string virtualPath);
string ReadFile(string virtualPath);
void CopyFileTo(string virtualPath, Stream destination);
IVolatileToken WhenPathChanges(string virtualPath);
void WhenPathChanges(string virtualPath, Action action);

View File

@ -25,18 +25,28 @@ namespace Orchard.FileSystems.WebSite {
.Select(d => d.VirtualPath)
.ToArray();
}
public bool FileExists(string virtualPath) {
return HostingEnvironment.VirtualPathProvider.FileExists(virtualPath);
}
public string ReadFile(string virtualPath) {
if (!HostingEnvironment.VirtualPathProvider.FileExists(virtualPath))
return null;
using (var stream = VirtualPathProvider.OpenFile(virtualPath)) {
using (var stream = VirtualPathProvider.OpenFile(Normalize(virtualPath))) {
using (var reader = new StreamReader(stream)) {
return reader.ReadToEnd();
}
}
}
public void CopyFileTo(string virtualPath, Stream destination) {
using (var stream = VirtualPathProvider.OpenFile(Normalize(virtualPath))) {
stream.CopyTo(destination);
}
}
public IVolatileToken WhenPathChanges(string virtualPath) {
return _virtualPathMonitor.WhenPathChanges(virtualPath);
}
@ -44,5 +54,9 @@ namespace Orchard.FileSystems.WebSite {
public void WhenPathChanges(string virtualPath, Action action) {
_virtualPathMonitor.WhenPathChanges(virtualPath, action);
}
static string Normalize(string virtualPath) {
return HostingEnvironment.VirtualPathProvider.GetFile(virtualPath).VirtualPath;
}
}
}