Skip to content

Commit

Permalink
Plugin configuration - get compiler exe to pass parameters and create…
Browse files Browse the repository at this point in the history
… plugins
  • Loading branch information
lukeapage committed Feb 17, 2012
1 parent 0131439 commit b92a68d
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 39 deletions.
7 changes: 1 addition & 6 deletions src/dotless.Compiler/CompilerConfiguration.cs
Expand Up @@ -5,13 +5,8 @@ namespace dotless.Compiler

internal class CompilerConfiguration : DotlessConfiguration
{
public CompilerConfiguration(DotlessConfiguration config)
public CompilerConfiguration(DotlessConfiguration config) : base(config)
{
LessSource = config.LessSource;
LogLevel = config.LogLevel;
MinifyOutput = config.MinifyOutput;
Optimization = config.Optimization;

CacheEnabled = false;
Web = false;
Watch = false;
Expand Down
85 changes: 77 additions & 8 deletions src/dotless.Compiler/Program.cs
Expand Up @@ -4,6 +4,7 @@ namespace dotless.Compiler
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Linq;
using Core;
using Core.configuration;
using Core.Parameters;
Expand Down Expand Up @@ -170,28 +171,36 @@ private static string GetAssemblyVersion()
return "v.Unknown";
}

private static IEnumerable<IPluginConfigurator> _pluginConfigurators = null;
private static IEnumerable<IPluginConfigurator> GetPluginConfigurators()
{
return PluginFinder.GetConfigurators(true, false);
if (_pluginConfigurators == null)
{
_pluginConfigurators = PluginFinder.GetConfigurators(true, false);
}
return _pluginConfigurators;
}

private static void WritePluginList()
{
Console.WriteLine("List of plugins:");
Console.WriteLine("List of plugins");
Console.WriteLine();
foreach (IPluginConfigurator pluginConfigurator in GetPluginConfigurators())
{
Console.WriteLine("Name: {0}", pluginConfigurator.Name);
Console.WriteLine("Description: {0}", pluginConfigurator.Description);
Console.Write("Params: ");
Console.WriteLine("{0}", pluginConfigurator.Name);
Console.WriteLine("\t{0}", pluginConfigurator.Description);
Console.WriteLine("\tParams: ");
foreach (IPluginParameter pluginParam in pluginConfigurator.GetParameters())
{
Console.Write("\t\t");

if (!pluginParam.IsMandatory)
Console.Write("[");

Console.Write("{0}:{1}", pluginParam.Name, pluginParam.TypeDescription);
Console.Write("{0}={1}", pluginParam.Name, pluginParam.TypeDescription);

if (!pluginParam.IsMandatory)
Console.Write("]");
Console.WriteLine("]");
}
Console.WriteLine();
}
Expand All @@ -207,11 +216,16 @@ private static void WriteHelp()
Console.WriteLine("\t\t-m --minify - Output CSS will be compressed");
Console.WriteLine("\t\t-w --watch - Watches .less file for changes");
Console.WriteLine("\t\t-h --help - Displays this dialog");
Console.WriteLine("\t\t-DKey=Value - prefixes variable to the less");
Console.WriteLine("\t\t-l --listplugins - Lists the plugins available and options");
Console.WriteLine("\t\t-p --plugin \"plugin name\" \"option:value[,option:value...]\"- adds the named plugin to dotless with the supplied options");
Console.WriteLine("\t\t-p: --plugin:pluginName[:option=value[,option=value...]] - adds the named plugin to dotless with the supplied options");
Console.WriteLine("\tinputfile: .less file dotless should compile to CSS");
Console.WriteLine("\toutputfile: (optional) desired filename for .css output");
Console.WriteLine("\t\t Defaults to inputfile.css");
Console.WriteLine("");
Console.WriteLine("Example:");
Console.WriteLine("\tdotless.Compiler.exe -m -w \"-p:Rtl:forceRtlTransform=true,onlyReversePrefixedRules=true\"");
Console.WriteLine("\t\tMinify, Watch and add the Rtl plugin");
}

private static CompilerConfiguration GetConfigurationFromArguments(List<string> arguments)
Expand Down Expand Up @@ -249,6 +263,61 @@ private static CompilerConfiguration GetConfigurationFromArguments(List<string>
var value = split[1];
ConsoleArgumentParameterSource.ConsoleArguments.Add(key, value);
}
else if (arg.StartsWith("-p:") || arg.StartsWith("-plugin:"))
{
var pluginName = arg.Substring(arg.IndexOf(':') + 1);
List<string> pluginArgs = null;
if (pluginName.IndexOf(':') > 0)
{
pluginArgs = pluginName.Substring(pluginName.IndexOf(':') + 1).Split(',').ToList();
pluginName = pluginName.Substring(0, pluginName.IndexOf(':'));
}

var pluginConfig = GetPluginConfigurators()
.Where(plugin => String.Compare(plugin.Name, pluginName, true) == 0)
.FirstOrDefault();

if (pluginConfig == null)
{
Console.WriteLine("Cannot find plugin {0}.", pluginName);
continue;
}

var pluginParams = pluginConfig.GetParameters();

foreach (var pluginParam in pluginParams)
{
var pluginArg = pluginArgs
.Where(argString => argString.StartsWith(pluginParam.Name + "="))
.FirstOrDefault();

if (pluginArg == null)
{
if (pluginParam.IsMandatory)
{
Console.WriteLine("Missing mandatory argument {0} in plugin {1}.", pluginParam.Name, pluginName);
}
continue;
}
else
{
pluginArgs.Remove(pluginArg);
}

pluginParam.SetValue(pluginArg.Substring(pluginParam.Name.Length + 1));
}

if (pluginArgs.Count > 0)
{
for (int i = 0; i < pluginArgs.Count; i++)
{
Console.WriteLine("Did not recognise argument '{0}'", pluginArgs[i]);
}
}

pluginConfig.SetParameterValues(pluginParams);
configuration.Plugins.Add(pluginConfig);
}
else
{
Console.WriteLine("Unknown command switch {0}.", arg);
Expand Down
5 changes: 5 additions & 0 deletions src/dotless.Core/ContainerFactory.cs
Expand Up @@ -11,6 +11,8 @@ namespace dotless.Core
using Parameters;
using Response;
using Stylizers;
using dotless.Core.Plugins;
using System.Collections.Generic;

public class ContainerFactory
{
Expand Down Expand Up @@ -83,6 +85,9 @@ private void RegisterCoreServices(FluentRegistration pandora, DotlessConfigurati
pandora.Service<ILessEngine>().Implementor<LessEngine>().Parameters("compress").Set("minify-output").Lifestyle.Transient();
pandora.Service<bool>("minify-output").Instance(configuration.MinifyOutput);

pandora.Service<ILessEngine>().Implementor<LessEngine>().Parameters("plugins").Set("default-plugins").Lifestyle.Transient();
pandora.Service<IEnumerable<IPluginConfigurator>>("default-plugins").Instance(configuration.Plugins);

pandora.Service<IFileReader>().Implementor(configuration.LessSource);
}
}
Expand Down
19 changes: 17 additions & 2 deletions src/dotless.Core/Engine/LessEngine.cs
Expand Up @@ -15,16 +15,23 @@ public class LessEngine : ILessEngine
public ILogger Logger { get; set; }
public bool Compress { get; set; }
public Env Env { get; set; }
public IEnumerable<IPluginConfigurator> Plugins { get; set; }

public LessEngine(Parser.Parser parser, ILogger logger, bool compress)
public LessEngine(Parser.Parser parser, ILogger logger, bool compress, IEnumerable<IPluginConfigurator> plugins)
{
Parser = parser;
Logger = logger;
Compress = compress;
Plugins = plugins;
}

public LessEngine(Parser.Parser parser, ILogger logger, bool compress)
: this(parser, logger, compress, null)
{
}

public LessEngine(Parser.Parser parser)
: this(parser, new ConsoleLogger(LogLevel.Error), false)
: this(parser, new ConsoleLogger(LogLevel.Error), false, null)
{
}

Expand All @@ -41,6 +48,14 @@ public string TransformToCss(string source, string fileName)

var env = Env ?? new Env { Compress = Compress };

if (Plugins != null)
{
foreach (IPluginConfigurator configurator in Plugins)
{
env.AddPlugin(configurator.CreatePlugin());
}
}

var css = tree.ToCSS(env);

return css;
Expand Down
8 changes: 5 additions & 3 deletions src/dotless.Core/Parser/Parser.cs
Expand Up @@ -6,7 +6,9 @@ namespace dotless.Core.Parser
using Importers;
using Infrastructure;
using Stylizers;
using Tree;
using Tree;
using dotless.Core.Plugins;
using System.Collections.Generic;

//
// less.js - parser
Expand Down Expand Up @@ -64,8 +66,8 @@ public IImporter Importer
_importer = value;
_importer.Parser = () => new Parser(Tokenizer.Optimization, Stylizer, _importer) {NodeProvider = this.NodeProvider};
}
}

}

private const int defaultOptimization = 1;

public Parser()
Expand Down
2 changes: 1 addition & 1 deletion src/dotless.Core/Plugins/ColorSpinPlugin.cs
Expand Up @@ -6,7 +6,7 @@
using Utils;
using System.ComponentModel;

[Description("Automatically spins all colors in a less file"), DisplayName("Color Spin Plugin")]
[Description("Automatically spins all colors in a less file"), DisplayName("ColorSpin")]
public class ColorSpinPlugin : VisitorPlugin
{
public double Spin { get; set; }
Expand Down
37 changes: 26 additions & 11 deletions src/dotless.Core/Plugins/GenericPluginConfigurator.cs
Expand Up @@ -33,25 +33,40 @@ public Type Configurates
}
}

public IPlugin CreatePlugin(IEnumerable<IPluginParameter> pluginParameters)
private Func<IPlugin> _pluginCreator = null;
public void SetParameterValues(IEnumerable<IPluginParameter> pluginParameters)
{
ConstructorInfo defaultConstructor;
ConstructorInfo parameterConstructor;
GetConstructorInfos(out parameterConstructor, out defaultConstructor);

if (pluginParameters.Count() == 0 || pluginParameters.Any(parameter => parameter.Value == null))
if (pluginParameters == null || pluginParameters.Count() == 0 || pluginParameters.Any(parameter => parameter.Value == null))
{
if (defaultConstructor == null)
{
throw new Exception();
throw new Exception("No parameters provided but no default constructor");
}
return (T)defaultConstructor.Invoke(new object[] { });
_pluginCreator = () => (T)defaultConstructor.Invoke(new object[] { });
}
else
{
var constructorArguments = parameterConstructor.GetParameters()
.OrderBy(parameter => parameter.Position)
.Select(parameter => pluginParameters.First(pluginParameter => pluginParameter.Name == parameter.Name).Value)
.ToArray();

_pluginCreator = () => (T)parameterConstructor.Invoke(constructorArguments);
}
}

public IPlugin CreatePlugin()
{
if (_pluginCreator == null)
{
SetParameterValues(null);
}

return (T)parameterConstructor.Invoke(parameterConstructor.GetParameters()
.OrderBy(parameter => parameter.Position)
.Select(parameter => pluginParameters.First(pluginParameter => pluginParameter.Name == parameter.Name).Value)
.ToArray());
return _pluginCreator();
}

private class ConstructorParameterSet
Expand All @@ -67,7 +82,7 @@ private void GetConstructorInfos(out ConstructorInfo parameterConstructor, out C

if (constructors.Count > 2 || constructors.Count == 0)
{
throw new Exception();
throw new Exception("Generic plugin configurator doesn't support less than 1 or more than 2 constructors. Add your own IPluginConfigurator to the assembly.");
} else if (constructors.Count == 2)
{
if (constructors[0].GetParameters().Length == 0)
Expand All @@ -80,7 +95,7 @@ private void GetConstructorInfos(out ConstructorInfo parameterConstructor, out C
parameterConstructor = constructors[0];
} else
{
throw new Exception();
throw new Exception("Generic plugin configurator only supports 1 parameterless constructor and 1 with parameters. Add your own IPluginConfigurator to the assembly.");
}
} else {
if (constructors[0].GetParameters().Length == 0)
Expand All @@ -107,7 +122,7 @@ public IEnumerable<IPluginParameter> GetParameters()
}

return parameterConstructor.GetParameters().Select(parameter => (IPluginParameter)new PluginParameter(
parameter.Name, parameter.ParameterType, defaultConstructor == null));
parameter.Name, parameter.ParameterType, defaultConstructor == null)).ToList();
}
}
}
4 changes: 3 additions & 1 deletion src/dotless.Core/Plugins/IPluginConfigurator.cs
Expand Up @@ -5,10 +5,12 @@

public interface IPluginConfigurator
{
IPlugin CreatePlugin(IEnumerable<IPluginParameter> parameters);
IPlugin CreatePlugin();

IEnumerable<IPluginParameter> GetParameters();

void SetParameterValues(IEnumerable<IPluginParameter> parameters);

string Name { get; }

string Description { get; }
Expand Down
18 changes: 17 additions & 1 deletion src/dotless.Core/Plugins/PluginParameter.cs
Expand Up @@ -42,7 +42,23 @@ public string TypeDescription

public void SetValue(string stringValue)
{
Value = Convert.ChangeType(stringValue, Type);
if (Type.Equals(typeof(Boolean)))
{
if (stringValue.Equals("true", StringComparison.InvariantCultureIgnoreCase) ||
stringValue.Equals("t", StringComparison.InvariantCultureIgnoreCase) ||
stringValue.Equals("1", StringComparison.InvariantCultureIgnoreCase))
{
Value = true;
}
else
{
Value = false;
}
}
else
{
Value = Convert.ChangeType(stringValue, Type);
}
}
}
}
18 changes: 16 additions & 2 deletions src/dotless.Core/Plugins/RtlPlugin.cs
Expand Up @@ -7,10 +7,18 @@
using dotless.Core.Parser.Infrastructure.Nodes;
using dotless.Core.Parser.Tree;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
using System.ComponentModel;

[DisplayName("Rtl"), Description("Reverses some css when in rtl mode")]
public class RtlPlugin : VisitorPlugin
{
public RtlPlugin(bool onlyReversePrefixedRules, bool forceRtlTransform) : this()
{
OnlyReversePrefixedRules = onlyReversePrefixedRules;
ForceRtlTransform = forceRtlTransform;
}

public RtlPlugin()
{
PropertiesToReverse = new List<string>()
Expand All @@ -32,6 +40,12 @@ public bool OnlyReversePrefixedRules
set;
}

public bool ForceRtlTransform
{
get;
set;
}

public IEnumerable<string> PropertiesToReverse
{
get;
Expand All @@ -47,7 +61,7 @@ public override void OnPreVisiting(Parser.Infrastructure.Env env)
{
base.OnPreVisiting(env);

bool isRtl = CultureInfo.CurrentCulture.TextInfo.IsRightToLeft;
bool isRtl = ForceRtlTransform || CultureInfo.CurrentCulture.TextInfo.IsRightToLeft;

PrefixesToProcess = new List<Prefix>();

Expand Down

0 comments on commit b92a68d

Please sign in to comment.