From b61d6fcc634a95b655257a386b9f2844fae3df07 Mon Sep 17 00:00:00 2001 From: Renaud Paquay Date: Sat, 24 Jul 2010 13:43:38 -0700 Subject: [PATCH] Interactive orchard command line tool --HG-- branch : dev --- src/Orchard.Web/Orchard.Web.csproj | 4 + src/Orchard.sln | 7 + src/Tools/Orchard/ApplicationObject.cs | 7 +- src/Tools/Orchard/Host/CommandHost.cs | 56 ++++- .../ResponseFiles/ResponseFileReader.cs | 2 +- src/Tools/OrchardCli/CLIHost.cs | 63 ++++++ src/Tools/OrchardCli/CommandHostContext.cs | 16 ++ .../OrchardCli/CommandHostContextProvider.cs | 200 ++++++++++++++++++ .../OrchardCli/ICommandHostContextProvider.cs | 6 + src/Tools/OrchardCli/OrchardCLI.csproj | 147 +++++++++++++ src/Tools/OrchardCli/Program.cs | 7 + .../OrchardCli/Properties/AssemblyInfo.cs | 36 ++++ src/Tools/OrchardCli/app.config | 6 + 13 files changed, 543 insertions(+), 14 deletions(-) create mode 100644 src/Tools/OrchardCli/CLIHost.cs create mode 100644 src/Tools/OrchardCli/CommandHostContext.cs create mode 100644 src/Tools/OrchardCli/CommandHostContextProvider.cs create mode 100644 src/Tools/OrchardCli/ICommandHostContextProvider.cs create mode 100644 src/Tools/OrchardCli/OrchardCLI.csproj create mode 100644 src/Tools/OrchardCli/Program.cs create mode 100644 src/Tools/OrchardCli/Properties/AssemblyInfo.cs create mode 100644 src/Tools/OrchardCli/app.config diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index f163cd1fa..1fae8dd81 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -118,6 +118,10 @@ {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} Orchard.Framework + + {71A006E0-85BD-4CC4-ADF9-B548D5CA72A7} + OrchardCLI + {33B1BC8D-E292-4972-A363-22056B207156} Orchard diff --git a/src/Orchard.sln b/src/Orchard.sln index 5513613d2..b38424da6 100644 --- a/src/Orchard.sln +++ b/src/Orchard.sln @@ -73,6 +73,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene", "Orchard.Web\Modul EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Packaging", "Orchard.Web\Modules\Orchard.Packaging\Orchard.Packaging.csproj", "{DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCLI", "Tools\OrchardCli\OrchardCLI.csproj", "{71A006E0-85BD-4CC4-ADF9-B548D5CA72A7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -207,6 +209,10 @@ Global {DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}.Debug|Any CPU.Build.0 = Debug|Any CPU {DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}.Release|Any CPU.ActiveCfg = Release|Any CPU {DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}.Release|Any CPU.Build.0 = Release|Any CPU + {71A006E0-85BD-4CC4-ADF9-B548D5CA72A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71A006E0-85BD-4CC4-ADF9-B548D5CA72A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71A006E0-85BD-4CC4-ADF9-B548D5CA72A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71A006E0-85BD-4CC4-ADF9-B548D5CA72A7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -240,6 +246,7 @@ Global {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} + {71A006E0-85BD-4CC4-ADF9-B548D5CA72A7} = {383DBA32-4A3E-48D1-AAC3-75377A694452} {E65E5633-C0FF-453C-A906-481C14F969D6} = {E75A4CE4-CAA6-41E4-B951-33ACC60DC77C} EndGlobalSection EndGlobal diff --git a/src/Tools/Orchard/ApplicationObject.cs b/src/Tools/Orchard/ApplicationObject.cs index d1755945c..f73b5bdf0 100644 --- a/src/Tools/Orchard/ApplicationObject.cs +++ b/src/Tools/Orchard/ApplicationObject.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Orchard { +namespace Orchard { public class ApplicationObject { public string ApplicationId { get; set; } public object ObjectInstance { get; set; } diff --git a/src/Tools/Orchard/Host/CommandHost.cs b/src/Tools/Orchard/Host/CommandHost.cs index 1620ffe7a..ac3735f1d 100644 --- a/src/Tools/Orchard/Host/CommandHost.cs +++ b/src/Tools/Orchard/Host/CommandHost.cs @@ -7,7 +7,14 @@ using Orchard.Parameters; using Orchard.ResponseFiles; namespace Orchard.Host { - class CommandHost : MarshalByRefObject, IRegisteredObject { + /// + /// The CommandHost runs inside the ASP.NET AppDomain and serves as an intermediate + /// between the command line and the CommandHostAgent, which is known to the Orchard + /// Framework and has the ability to execute commands. + /// + public class CommandHost : MarshalByRefObject, IRegisteredObject { + private object _agent; + public CommandHost() { HostingEnvironment.RegisterObject(this); } @@ -17,12 +24,24 @@ namespace Orchard.Host { return null; } - public void Stop(bool immediate) { + void IRegisteredObject.Stop(bool immediate) { HostingEnvironment.UnregisterObject(this); } + public void StartSession(TextReader input, TextWriter output) { + _agent = CreateAgent(); + StartHost(_agent, input, output); + } + + public void StopSession(TextReader input, TextWriter output) { + if (_agent != null) { + StopHost(_agent, input, output); + _agent = null; + } + } + public int RunCommand(TextReader input, TextWriter output, Logger logger, OrchardParameters args) { - var agent = Activator.CreateInstance("Orchard.Framework", "Orchard.Commands.CommandHostAgent").Unwrap(); + var agent = CreateAgent(); int result = (int)agent.GetType().GetMethod("RunSingleCommand").Invoke(agent, new object[] { input, output, @@ -33,10 +52,21 @@ namespace Orchard.Host { return result; } - public int RunCommands(TextReader input, TextWriter output, Logger logger, IEnumerable responseLines) { - var agent = Activator.CreateInstance("Orchard.Framework", "Orchard.Commands.CommandHostAgent").Unwrap(); + public int RunCommandInSession(TextReader input, TextWriter output, Logger logger, OrchardParameters args) { + int result = (int)_agent.GetType().GetMethod("RunCommand").Invoke(_agent, new object[] { + input, + output, + args.Tenant, + args.Arguments.ToArray(), + args.Switches}); - int result = (int)agent.GetType().GetMethod("StartHost").Invoke(agent, new object[] { input, output }); + return result; + } + + public int RunCommands(TextReader input, TextWriter output, Logger logger, IEnumerable responseLines) { + var agent = CreateAgent(); + + int result = StartHost(agent, input, output); if (result != 0) return result; @@ -58,8 +88,20 @@ namespace Orchard.Host { } } - result = (int)agent.GetType().GetMethod("StopHost").Invoke(agent, new object[] { input, output }); + result = StopHost(agent, input, output); return result; } + + private object CreateAgent() { + return Activator.CreateInstance("Orchard.Framework", "Orchard.Commands.CommandHostAgent").Unwrap(); + } + + private int StopHost(object agent, TextReader input, TextWriter output) { + return (int)agent.GetType().GetMethod("StopHost").Invoke(agent, new object[] { input, output }); + } + + private int StartHost(object agent, TextReader input, TextWriter output) { + return (int)agent.GetType().GetMethod("StartHost").Invoke(agent, new object[] { input, output }); + } } } diff --git a/src/Tools/Orchard/ResponseFiles/ResponseFileReader.cs b/src/Tools/Orchard/ResponseFiles/ResponseFileReader.cs index 4209e065e..037039c41 100644 --- a/src/Tools/Orchard/ResponseFiles/ResponseFileReader.cs +++ b/src/Tools/Orchard/ResponseFiles/ResponseFileReader.cs @@ -30,7 +30,7 @@ namespace Orchard.ResponseFiles { } } - private IEnumerable SplitArgs(string text) { + public static IEnumerable SplitArgs(string text) { var sb = new StringBuilder(); bool inString = false; foreach (char ch in text) { diff --git a/src/Tools/OrchardCli/CLIHost.cs b/src/Tools/OrchardCli/CLIHost.cs new file mode 100644 index 000000000..eed4be53a --- /dev/null +++ b/src/Tools/OrchardCli/CLIHost.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using Orchard; +using Orchard.Parameters; +using Orchard.ResponseFiles; + +namespace OrchardCLI { + class CLIHost { + private readonly TextWriter _output; + private readonly TextReader _input; + private readonly ICommandHostContextProvider _commandHostContextProvider; + + public CLIHost(string[] args) { + _input = Console.In; + _output = Console.Out; + _commandHostContextProvider = new CommandHostContextProvider(args); + } + + public int Run() { + var context = _commandHostContextProvider.CreateContext(); + + while (true) { + var command = ReadCommand(context); + switch (command.ToLowerInvariant()) { + case "quit": + case "q": + case "exit": + case "e": + _commandHostContextProvider.Shutdown(context); + return 0; + default: + context = RunCommand(context, command); + break; + } + } + } + + private string ReadCommand(CommandHostContext context) { + Console.WriteLine(); + Console.Write("orchard> "); + return Console.ReadLine(); + } + + private CommandHostContext RunCommand(CommandHostContext context, string command) { + int result = RunCommandInSession(context, command); + if(result == 240) { + if (result == 240/*special return code for "Retry"*/) { + _commandHostContextProvider.Shutdown(context); + context = _commandHostContextProvider.CreateContext(); + result = RunCommandInSession(context, command); + if (result != 0) + Console.WriteLine("Command returned non-zero result: {0}", result); + } + } + return context; + } + + private int RunCommandInSession(CommandHostContext context, string command) { + var args = new OrchardParametersParser().Parse(new CommandParametersParser().Parse(ResponseFileReader.SplitArgs(command))); + return context.CommandHost.RunCommandInSession(_input, _output, context.Logger, args); + } + } +} diff --git a/src/Tools/OrchardCli/CommandHostContext.cs b/src/Tools/OrchardCli/CommandHostContext.cs new file mode 100644 index 000000000..b716caf73 --- /dev/null +++ b/src/Tools/OrchardCli/CommandHostContext.cs @@ -0,0 +1,16 @@ +using System; +using System.IO; +using System.Web.Hosting; +using Orchard; +using Orchard.Host; + +namespace OrchardCLI { + public class CommandHostContext { + public OrchardParameters Arguments { get; set; } + public DirectoryInfo OrchardDirectory { get; set; } + public ApplicationManager AppManager { get; set; } + public ApplicationObject AppObject { get; set; } + public CommandHost CommandHost { get; set; } + public Logger Logger { get; set; } + } +} \ No newline at end of file diff --git a/src/Tools/OrchardCli/CommandHostContextProvider.cs b/src/Tools/OrchardCli/CommandHostContextProvider.cs new file mode 100644 index 000000000..038ccd973 --- /dev/null +++ b/src/Tools/OrchardCli/CommandHostContextProvider.cs @@ -0,0 +1,200 @@ +using System; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Web; +using System.Web.Hosting; +using Orchard; +using Orchard.Host; +using Orchard.Parameters; + +namespace OrchardCLI { + public class CommandHostContextProvider : ICommandHostContextProvider{ + private readonly string[] _args; + private TextWriter _output; + private TextReader _input; + + public CommandHostContextProvider(string[] args) { + _input = Console.In; + _output = Console.Out; + _args = args; + } + + public CommandHostContext CreateContext() { + var context = new CommandHostContext(); + Initialize(context); + return context; + } + + public void Shutdown(CommandHostContext context) { + ShutdownHost(context); + } + + private void Initialize(CommandHostContext context) { + context.Arguments = new OrchardParametersParser().Parse(new CommandParametersParser().Parse(_args)); + context.Logger = new Logger(context.Arguments.Verbose, _output); + + // Perform some argument validation and display usage if something is incorrect + bool showHelp = context.Arguments.Switches.ContainsKey("?"); + if (!showHelp) { + //showHelp = (!_arguments.Arguments.Any() && !_arguments.ResponseFiles.Any()); + } + + if (!showHelp) { + //showHelp = (_arguments.Arguments.Any() && _arguments.ResponseFiles.Any()); + //if (showHelp) { + // _output.WriteLine("Incorrect syntax: Response files cannot be used in conjunction with commands"); + //} + } + + if (showHelp) { + GeneralHelp(); + return; + } + + if (string.IsNullOrEmpty(context.Arguments.VirtualPath)) + context.Arguments.VirtualPath = "/"; + LogInfo(context, "Virtual path: \"{0}\"", context.Arguments.VirtualPath); + + if (string.IsNullOrEmpty(context.Arguments.WorkingDirectory)) + context.Arguments.WorkingDirectory = Environment.CurrentDirectory; + LogInfo(context, "Working directory: \"{0}\"", context.Arguments.WorkingDirectory); + + LogInfo(context, "Detecting orchard installation root directory..."); + context.OrchardDirectory = GetOrchardDirectory(context.Arguments.WorkingDirectory); + LogInfo(context, "Orchard root directory: \"{0}\"", context.OrchardDirectory.FullName); + + CreateHost(context); + context.CommandHost.StartSession(_input, _output); + } + + private void CreateHost(CommandHostContext context) { + context.AppManager = ApplicationManager.GetApplicationManager(); + + LogInfo(context, "Creating ASP.NET AppDomain for command agent..."); + context.AppObject = CreateWorkerAppDomainWithHost(context.AppManager, context.Arguments.VirtualPath, context.OrchardDirectory.FullName, typeof(CommandHost)); + context.CommandHost = (CommandHost)context.AppObject.ObjectInstance; + } + + private void ShutdownHost(CommandHostContext context) { + if (context.CommandHost != null) { + context.CommandHost.StopSession(_input, _output); + } + + if (context.AppObject != null) { + LogInfo(context, "Shutting down ASP.NET AppDomain..."); + context.AppManager.ShutdownApplication(context.AppObject.ApplicationId); + } + } + + private int GeneralHelp() { + _output.WriteLine("Executes Orchard commands from a Orchard installation directory."); + _output.WriteLine(""); + _output.WriteLine("Usage:"); + _output.WriteLine(" orchard.exe command [arg1] ... [argn] [/switch1[:value1]] ... [/switchn[:valuen]]"); + _output.WriteLine(" orchard.exe @response-file1 ... [@response-filen] [/switch1[:value1]] ... [/switchn[:valuen]]"); + _output.WriteLine(""); + _output.WriteLine(" command"); + _output.WriteLine(" Specify the command to execute"); + _output.WriteLine(""); + _output.WriteLine(" [arg1] ... [argn]"); + _output.WriteLine(" Specify additional arguments for the command"); + _output.WriteLine(""); + _output.WriteLine(" [/switch1[:value1]] ... [/switchn[:valuen]]"); + _output.WriteLine(" Specify switches to apply to the command. Available switches generally "); + _output.WriteLine(" depend on the command executed, with the exception of a few built-in ones."); + _output.WriteLine(""); + _output.WriteLine(" [@response-file1] ... [@response-filen]"); + _output.WriteLine(" Specify one or more response files to be used for reading commands and switches."); + _output.WriteLine(" A response file is a text file that contains one line per command to execute."); + _output.WriteLine(""); + _output.WriteLine(" Built-in commands"); + _output.WriteLine(" ================="); + _output.WriteLine(""); + _output.WriteLine(" help commands"); + _output.WriteLine(" Display the list of available commands."); + _output.WriteLine(""); + _output.WriteLine(" help "); + _output.WriteLine(" Display help for a given command."); + _output.WriteLine(""); + _output.WriteLine(" Built-in switches"); + _output.WriteLine(" ================="); + _output.WriteLine(""); + _output.WriteLine(" /WorkingDirectory:"); + _output.WriteLine(" /wd:"); + _output.WriteLine(" Specifies the orchard installation directory. The current directory is the default."); + _output.WriteLine(""); + _output.WriteLine(" /Verbose"); + _output.WriteLine(" /v"); + _output.WriteLine(" Turn on verbose output"); + _output.WriteLine(""); + _output.WriteLine(" /VirtualPath:"); + _output.WriteLine(" /vp:"); + _output.WriteLine(" Virtual path to pass to the WebHost. Empty (i.e. root path) by default."); + _output.WriteLine(""); + _output.WriteLine(" /Tenant:tenant-name"); + _output.WriteLine(" /t:tenant-name"); + _output.WriteLine(" Specifies which tenant to run the command into. \"Default\" tenant by default."); + _output.WriteLine(""); + return 1; + } + + private void LogInfo(CommandHostContext context, string format, params object[] args) { + if (context.Logger != null) + context.Logger.LogInfo(format, args); + } + + private DirectoryInfo GetOrchardDirectory(string directory) { + for (var directoryInfo = new DirectoryInfo(directory); directoryInfo != null; directoryInfo = directoryInfo.Parent) { + if (!directoryInfo.Exists) { + throw new ApplicationException(string.Format("Directory \"{0}\" does not exist", directoryInfo.FullName)); + } + + // We look for + // 1) .\web.config + // 2) .\bin\Orchard.Framework.dll + var webConfigFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, "web.config")); + if (!webConfigFileInfo.Exists) + continue; + + var binDirectoryInfo = new DirectoryInfo(Path.Combine(directoryInfo.FullName, "bin")); + if (!binDirectoryInfo.Exists) + continue; + + var orchardFrameworkFileInfo = new FileInfo(Path.Combine(binDirectoryInfo.FullName, "Orchard.Framework.dll")); + if (!orchardFrameworkFileInfo.Exists) + continue; + + return directoryInfo; + } + + throw new ApplicationException( + string.Format("Directory \"{0}\" doesn't seem to contain an Orchard installation", new DirectoryInfo(directory).FullName)); + } + + private static ApplicationObject CreateWorkerAppDomainWithHost(ApplicationManager appManager, string virtualPath, string physicalPath, Type hostType) { + // this creates worker app domain in a way that host doesn't need to be in GAC or bin + // using BuildManagerHost via private reflection + string uniqueAppString = string.Concat(virtualPath, physicalPath).ToLowerInvariant(); + string appId = (uniqueAppString.GetHashCode()).ToString("x", CultureInfo.InvariantCulture); + + // create BuildManagerHost in the worker app domain + var buildManagerHostType = typeof(HttpRuntime).Assembly.GetType("System.Web.Compilation.BuildManagerHost"); + var buildManagerHost = appManager.CreateObject(appId, buildManagerHostType, virtualPath, physicalPath, false); + + // call BuildManagerHost.RegisterAssembly to make Host type loadable in the worker app domain + buildManagerHostType.InvokeMember( + "RegisterAssembly", + BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, + null, + buildManagerHost, + new object[] { hostType.Assembly.FullName, hostType.Assembly.Location }); + + // create Host in the worker app domain + return new ApplicationObject { + ApplicationId = appId, + ObjectInstance = appManager.CreateObject(appId, hostType, virtualPath, physicalPath, false) + }; + } + } +} diff --git a/src/Tools/OrchardCli/ICommandHostContextProvider.cs b/src/Tools/OrchardCli/ICommandHostContextProvider.cs new file mode 100644 index 000000000..8a75c4309 --- /dev/null +++ b/src/Tools/OrchardCli/ICommandHostContextProvider.cs @@ -0,0 +1,6 @@ +namespace OrchardCLI { + public interface ICommandHostContextProvider { + CommandHostContext CreateContext(); + void Shutdown(CommandHostContext context); + } +} \ No newline at end of file diff --git a/src/Tools/OrchardCli/OrchardCLI.csproj b/src/Tools/OrchardCli/OrchardCLI.csproj new file mode 100644 index 000000000..400875631 --- /dev/null +++ b/src/Tools/OrchardCli/OrchardCLI.csproj @@ -0,0 +1,147 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {71A006E0-85BD-4CC4-ADF9-B548D5CA72A7} + Exe + Properties + OrchardCLI + OrchardCLI + v4.0 + 512 + + + 3.5 + + false + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + AnyCPU + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + AllRules.ruleset + + + + + 3.5 + + + + 3.5 + + + 3.5 + + + + + + + ApplicationObject.cs + + + Host\CommandHost.cs + + + IOrchardParametersParser.cs + + + Logger.cs + + + OrchardParameters.cs + + + OrchardParametersParser.cs + + + Parameters\CommandParameters.cs + + + Parameters\CommandParametersParser.cs + + + Parameters\CommandSwitch.cs + + + Parameters\ICommandParametersParser.cs + + + ResponseFiles\ResponseFileReader.cs + + + ResponseFiles\ResponseFiles.cs + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + Designer + + + + + \ No newline at end of file diff --git a/src/Tools/OrchardCli/Program.cs b/src/Tools/OrchardCli/Program.cs new file mode 100644 index 000000000..4f4eb0588 --- /dev/null +++ b/src/Tools/OrchardCli/Program.cs @@ -0,0 +1,7 @@ +namespace OrchardCLI { + public class Program { + public static int Main(string[] args) { + return new CLIHost(args).Run(); + } + } +} diff --git a/src/Tools/OrchardCli/Properties/AssemblyInfo.cs b/src/Tools/OrchardCli/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..2e620e743 --- /dev/null +++ b/src/Tools/OrchardCli/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OrchardCLI")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Orchard")] +[assembly: AssemblyCopyright("Copyright © CodePlex Foundation 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5ee627dd-b767-441e-b8d0-ec7d26faac49")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.5.0")] +[assembly: AssemblyFileVersion("0.5.0")] diff --git a/src/Tools/OrchardCli/app.config b/src/Tools/OrchardCli/app.config new file mode 100644 index 000000000..21ac8f3ab --- /dev/null +++ b/src/Tools/OrchardCli/app.config @@ -0,0 +1,6 @@ + + + + + +