public BenchRenderers() { var parsers = new BenchParsers(); _scribanTemplate = parsers.TestScriban(); _dotLiquidTemplate = parsers.TestDotLiquid(); _stubbleTemplate = parsers.TestStubble(); _stubbleSettings = new Stubble.Core.Settings.RendererSettingsBuilder().BuildSettings(); _nustacheTemplate = parsers.TestNustache(); _handlebarsTemplate = parsers.TestHandlebars(); _cottleTemplate = parsers.TestCottle(); _fluidTemplate = parsers.TestFluid(); _razorTemplate = parsers.TestRazor(); const int ProductCount = 500; _products = new List <Product>(ProductCount); _scribanProducts = new List <ScriptObject>(); _dotLiquidProducts = new List <DotLiquid.Hash>(ProductCount); var cottleValues = new List <Cottle.Value>(); for (int i = 0; i < ProductCount; i++) { var product = new Product("Name" + i, i, Lorem); _products.Add(product); var hash = new Hash() { ["name"] = product.Name, ["price"] = product.Price, ["description"] = product.Description }; _dotLiquidProducts.Add(hash); var obj = new ScriptObject { ["name"] = product.Name, ["price"] = product.Price, ["description"] = product.Description }; _scribanProducts.Add(obj); cottleValues.Add(new Cottle.Values.ReflectionValue(product)); } _liquidTemplateContext = new LiquidTemplateContext(); // For Cottle, we match the behavior of Scriban that is accessing the Truncate function via an reflection invoke // In Scriban, we could also have a direct Truncate function, but it is much less practical in terms of declaration _cottleStringStore = new Dictionary <Cottle.Value, Cottle.Value>(); _cottleStringStore["truncate"] = new Cottle.Functions.NativeFunction((values, store, Output) => { if (values.Count != 2) { throw new InvalidOperationException("Unexpected number of arguments for truncate function"); } return(StringFunctions.Truncate(values[0].AsString, Convert.ToInt32(values[1].AsNumber))); }, 2); }
public BenchRenderers() { var parsers = new BenchParsers(); _scribanTemplate = parsers.TestScriban(); _dotLiquidTemplate = parsers.TestDotLiquid(); _stubbleTemplate = parsers.TestStubble(); _stubbleSettings = new Stubble.Core.Settings.RendererSettingsBuilder().BuildSettings(); _nustacheTemplate = parsers.TestNustache(); _handlebarsTemplate = parsers.TestHandlebars(); _cottleTemplate = parsers.TestCottle(); _fluidTemplate = parsers.TestFluid(); const int ProductCount = 500; _products = new List <Product>(ProductCount); _scribanProducts = new List <ScriptObject>(); _dotLiquidProducts = new List <DotLiquid.Hash>(ProductCount); var cottleProducts = new List <Cottle.Value>(); for (int i = 0; i < ProductCount; i++) { var product = new Product("Name" + i, i, Lorem); _products.Add(product); var hash = new Hash() { ["name"] = product.Name, ["price"] = product.Price, ["description"] = product.Description }; _dotLiquidProducts.Add(hash); var obj = new ScriptObject { ["name"] = product.Name, ["price"] = product.Price, ["description"] = product.Description }; _scribanProducts.Add(obj); var value = new Dictionary <Cottle.Value, Cottle.Value> { ["name"] = product.Name, ["price"] = product.Price, ["description"] = product.Description }; cottleProducts.Add(value); } _cottleProducts = cottleProducts; _templateContext = new TemplateContext(); _templateContext.BuiltinObject["truncate"] = ((ScriptObject)_templateContext.BuiltinObject["string"])["truncate"]; // For Cottle, we match the behavior of Scriban that is accessing the Truncate function via an reflection invoke // In Scriban, we could also have a direct Truncate function, but it is much less practical in terms of declaration _cottleStringStore = new Dictionary <Cottle.Value, Cottle.Value>(); _cottleStringStore["truncate"] = new Cottle.Functions.NativeFunction(values => StringFunctions.Truncate(values[0].AsString, Convert.ToInt32(values[1].AsNumber)), 2); }
public static Task Record(string ffmpegPath, string ffmpegArguments, RecordParam recordParam, CancellationToken cancellationToken, IProgress <string> logProgress) { return(Task.Run(() => { // TODO: check more? if (recordParam.OutputPath.IndexOf('"') >= 0) { throw new ArgumentException("OutputPath contains '\"'"); } var argumentTemplate = ffmpegArguments; var simpleDocument = new Cottle.Documents.SimpleDocument(argumentTemplate); var store = new Cottle.Stores.BuiltinStore(); recordParam.SetToCottleStore(store); var arguments = simpleDocument.Render(store); string startLine = string.Format("Start: {0} {1}", ffmpegPath, arguments); logProgress.Report(startLine); var psi = new System.Diagnostics.ProcessStartInfo() { FileName = ffmpegPath, Arguments = arguments, CreateNoWindow = true, UseShellExecute = false, RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, }; var proc = new System.Diagnostics.Process() { StartInfo = psi, }; proc.OutputDataReceived += (sender, e) => { logProgress.Report(e.Data); }; proc.ErrorDataReceived += (sender, e) => { logProgress.Report(e.Data); }; // TODO: wait process with modern non-blocking way var mre = new ManualResetEventSlim(); proc.EnableRaisingEvents = true; proc.Exited += (sender, e) => { mre.Set(); }; proc.Start(); proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); WaitHandle.WaitAny(new WaitHandle[] { mre.WaitHandle, cancellationToken.WaitHandle }); if (cancellationToken.IsCancellationRequested) { if (!proc.HasExited) { var io = proc.StandardInput; io.WriteLine("q"); } logProgress.Report("Cancellation requested. Pressed q and waiting..."); var waitResult = mre.Wait(10000); if (waitResult) { logProgress.Report("The process finished."); return; } else { logProgress.Report("The process is not finished. Killing it."); proc.Kill(); return; } } logProgress.Report(string.Format("Process finished: exit code: {0}", proc.ExitCode)); })); }