private void C_Append(LineReader reader, string args) { string[] parts = Chop(args); if (parts[0] != "-r" && parts.Length >= 2) { string key = parts[0]; var sb = new StringBuilder(); string contents; if (TryGetMacro(key, out contents)) { sb.Append(contents); } for (int i = 1; i < parts.Length; i++) { string val = parts[i]; sb.AppendLine().Append(GetMacro(val)); } SetMacro(key, sb.ToString()); SendMessage("@append {0}", args); } else { var append = ReadHereString(reader, false); string key = args; bool ok = false; string contents; if (TryGetMacro(key, out contents)) { SetMacro(key, contents + Expand(append)); ok = true; } else { string[] paths = GetFiles(args); if (paths.Length != 0) { append = Expand(append); foreach (var p in paths) { SetFile(p); if (Write) File.AppendAllText(p, Generate(append)); ok = true; } } } if (ok) SendMessage("@append {0}", args); else SendMessage("@skip append {0}"); } }
private void C_Ask(LineReader reader, string args) { string[] nv = Chop(args, 2, '='); string key = nv[0]; string text; if (!TryGetMacro(key, out text)) text = ""; if (Interactive) { if (nv.Length > 1) { text = Input(nv[1], true, text); } else { string contents = ReadHereString(reader); string[] lines = contents.Split(new[] { "\r\n" }, StringSplitOptions.None); var sb = new StringBuilder(); int i; for (i = 0; i < lines.Length; i++) { string s = lines[i]; if (s == "-") break; sb.AppendLine(s); } i++; var parts = new string[lines.Length - i]; Array.Copy(lines, i, parts, 0, parts.Length); text = Input(sb.ToString(), true, text, parts); } //Cancel->null, OK without selection -> "" if (text == null) { SendMessage("@ask -> cancel"); _Run = false; } else { SetMacro(key, text); SendKeyValueMessage(key, text); } } else if (nv.Length == 1) ReadCData(reader, "#end"); }
private void C_Udp(LineReader reader, string args) { string[] parts = Chop(args); string contents = ReadHereString(reader); using (var u = new UdpClient(parts[0], Convert.ToInt32(parts[1]))) { if (Write) { byte[] bytes = Encoding.UTF8.GetBytes(contents); u.Send(bytes, bytes.Length); } SendMessage("@udp {0}:{1} {2}", parts[0], parts[1], Truncate(contents, 70)); } }
private void C_Post(LineReader reader, string args) { string[] parts = Chop(args, 2, '='); string contents = ReadHereString(reader); if (Write && contents.Length > 0) { var request = (HttpWebRequest)WebRequest.Create(parts[1]); byte[] buf = Encoding.UTF8.GetBytes(contents); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = buf.Length; request.Credentials = CredentialCache.DefaultCredentials; request.UserAgent = "RecipeTool"; using (Stream st = request.GetRequestStream()) { st.Write(buf, 0, buf.Length); } using (var response = request.GetResponse()) { using (Stream st = response.GetResponseStream()) { using (var sr = new StreamReader(st)) { _Macros[parts[0]] = sr.ReadToEnd(); } } } } }
private void C_Output(LineReader reader, string args, string cmd, string rawArgs) { // info mbox warn write string text = (rawArgs == string.Empty) ? ReadHereString(reader) : args; if (cmd == "write" || cmd == "print") SendMessage("~{0}", text); else SendMessage("@{0} {1}", cmd, text); }
private string C_Mkdir(LineReader reader, string args) { args = args.Trim(); bool force = args.StartsWith("-f"); string key = force ? args.Substring(3).TrimStart() : args; string contents = ReadHereString(reader); string[] parts = contents.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); if (Write) Directory.CreateDirectory(key); foreach (string part in parts) { bool copy = part.StartsWith("+"); string text = copy ? "copy" : "move"; var file = (copy ? part.Substring(1) : part).Trim(); string[] paths = GetFiles(file); foreach (string p in paths) { string dest = Path.Combine(key, Path.GetFileName(p)); if (force || !File.Exists(dest)) { if (Write) { if (File.Exists(dest)) { File.Delete(dest); text = "repl"; } if (copy) File.Copy(p, dest); else File.Move(p, dest); } SendMessage("@file{0} {1}", text, dest); } else { SendMessage("@skip file{0}, already exists: {1}", text, dest); } } } return args; }
private void C_Line(LineReader reader) { SendMessage(GetLine(reader)); }
private void C_For(LineReader reader, string args) { string[] parts = Chop(args); string fmt = parts[0]; int min = Convert.ToInt32(parts[1]); int step = Convert.ToInt32(parts[2]); int max = Convert.ToInt32(parts[3]); string contents = ReadCData(reader, "#next"); SendMessage("@for {0}, {1}..{3} step {2}", fmt, min, step, max); for (int i = min; i <= max; i += step) { SetMacro("_", i.ToString(fmt, CultureInfo.InvariantCulture)); string text = Expand(contents); using (var sr = new LineReader(text, args)) { if (Run(sr) == null && !_Run) break; } } }
private void C_CData(LineReader reader, string args) { string key = args; string contents = ReadCData(reader, "#end " + key); SetMacro(key, contents); SendKeyValueMessage(key, contents); }
private void C_Write(LineReader reader, string args) { if (Write) { string script = ReadCData(reader, null); string[] parts = args.Split(':'); string host = parts[0] == string.Empty ? "0.0.0.0" : parts[0]; int port = parts.Length < 2 || string.IsNullOrEmpty(parts[1]) ? DefaultPort : Convert.ToInt32(parts[1]); if (_Server != null) throw new Exception("Can run only one instance of a server at port " + port); _Server = new RecipeServer(host, port, this, script); new Thread(_Server.Listen).Start(); SendMessage("@server {0}", port); } }
private void C_CallExternal(LineReader reader, string args, string cmd) { if (cmd == "xcopy") { args = "{xcopy} " + args; cmd = "cmd"; } string fmt = "@{0} {1} -> {2}"; string key, script, text; string[] nv; if (cmd == "ps" && args.Contains("=")) { nv = Chop(args, 2, '='); key = nv[0]; script = nv[1] + " | Out-String"; int exitCode = RunPowerShell(script, out text); SetMacro("exitcode", exitCode.ToString()); if (key != string.Empty) SetMacro(key, text); SendMessage(fmt, "run here", script, exitCode); } else if ((cmd == "call" || cmd == "cmd" || cmd == "ps") && !args.Contains("{")) { script = ReadHereString(reader); int exitCode = cmd == "ps" ? RunPowerShell(script, out text) : RunShell(script, out text); SetMacro("exitcode", exitCode.ToString()); key = args; if (key != string.Empty) SetMacro(key, text); SendMessage(fmt, "run here", script, exitCode); } else if (cmd == "git") { if (args.Contains("=")) { nv = Chop(args, 2, '='); key = nv[0]; script = "git.exe " + nv[1]; //"C:\Program Files (x86)\Git\cmd\" } else { key = args; script = ReadHereString(reader); string[] parts = script.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).Select(s => "git.exe " + s).ToArray(); script = string.Join(Environment.NewLine, parts); } string macro = GetMacro("repo"); if (macro == "") { SendMessage("@git -> unknown repo, use #put repo=<drive>:<folder>"); SetMacro("exitcode", "test only"); throw new Exception("git repo name missing"); } script = "cd \"" + macro + "\"" + Environment.NewLine + script; if (macro.Length > 1 && macro[1] == ':') script = macro.Substring(0, 2) + Environment.NewLine + script; int exitCode = RunShell(script, out text); SetMacro("exitcode", exitCode.ToString()); text = Regex.Replace(text, @"(?<!\r)\n", "\r\n"); if (key != string.Empty) SetMacro(key, text); SendMessage(fmt, "run git: ", script, exitCode); } else { var match = Regex.Match(args, @"\{([^}]+)\}\s*(.*)$"); // #cmd/#run {program} arg1 arg2 arg3 ... string prog = match.Groups[1].Value; string progArgs = match.Groups[2].Value; Process p = Process.Start(prog, progArgs); if (cmd == "run") { SendMessage(fmt, cmd, args, "async"); } else if (p != null) { p.WaitForExit(); SetMacro("exitcode", p.ExitCode.ToString()); SendMessage(fmt, cmd, args, p.ExitCode); } } }
private void C_With(LineReader reader, string args) { if (!string.IsNullOrEmpty(args)) { string[] parts = Chop(args, 2, '='); string key = parts[0]; string script = parts.Length == 2 ? parts[1].TrimStart() : ReadHereString(reader); string text; string[] paths; if (TryGetMacro(key, out text)) { text = Apply(script, text); SetMacro(key, text); SendKeyValueMessage(key, script); } else { paths = GetFiles(args); foreach (string p in paths) { text = File.ReadAllText(p); text = Apply(script, text); if (Write) File.WriteAllText(p, text); SendMessage("@with {0}", p); } } } }
private void C_While_Until(LineReader reader, string args, string cmd) { string[] parts = Chop(args, 2, ' '); string macro = parts[0]; string rx = parts[1]; bool not = cmd == "until"; string contents = ReadCData(reader, "#loop"); SendMessage("@{0} {1} {2}", cmd, macro, rx); string text; while (not ^ (TryGetMacro(macro, out text) && Regex.IsMatch(text, rx))) { text = Expand(contents); using (var sr = new LineReader(text, name: args)) { if (Run(sr) == null && !_Run) break; } } }
private void C_Watch(LineReader reader, string args) { if (Write) { string script = ReadCData(reader, null); string[] parts = Chop(args, 2, ' '); _Watcher = new Watcher(this, script); new Thread(() => _Watcher.ExecutionLoop(parts[0], parts[1])).Start(); SendMessage("@watch {0}", args); } }
private void C_Expn(LineReader reader, string args) { /* compare #expn vs. #with template #put a one|two|three four|five|six #end #with a template insert $1 into $2 yield $3 #end #info `a` --- #cdata b insert `1` into `2` yield `3`... #end b #expn b one|two|three four|five|six #end #info `b` */ string key = args; string text; if (TryGetMacro(key, out text)) { string contents = ReadHereString(reader, true); var sb = new StringBuilder(); string[] parts = contents.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string s in new TemplateExpander(text, parts, Put, Expand).Instances()) { sb.Append(s); } SetMacro(key, sb.ToString()); } }
private void C_Csharp(LineReader reader, string args) { string script = ReadHereString(reader); var result = CSharp.Build(script); string text; if (result.Errors.HasErrors) { text = string.Join(Environment.NewLine, CSharp.Errors(result)); SendMessage("@csharp {0}", text); } else if (Write) { string[] parts = Chop(args); string key = parts[0]; parts = parts.Where((s, i) => i > 0).Select(s => GetMacro(s)).ToArray(); text = CSharp.Execute(result.CompiledAssembly, parts); if (key != string.Empty) SetMacro(key, text); } else SendMessage("@csharp skip (test mode)"); }
private void C_Extract(LineReader reader, string args, string cmd) { string rx, macro; string[] paths; if (GetRxLine(args, out rx, out paths, out macro)) { string text, contents; if (macro != null && TryGetMacro(macro, out text)) { contents = ReadHereString(reader); text = Replace(contents, text, rx); _Macros[macro] = text; SendKeyValueMessage(macro, text); } else { if (paths.Length == 0) { ReadHereString(reader, false); SendMessage("@skip {0} {1}", cmd, args); } else { contents = ReadHereString(reader, false); foreach (string p in paths) { SetFile(p); string inst = Expand(contents); text = File.ReadAllText(p); text = Replace(inst, text, rx); if (Write) { File.WriteAllText(p, text); } SendMessage("@{0} {1}", cmd, p); } } } } else { ReadHereString(reader, false); SendMessage("@nomatch {0}: {1}", cmd, args); } }
/// <summary> /// Converts dates found in the macro text or files, using the given spec. /// </summary> /// <param name="spec">4 lines: 1. input format (*=any), 2. input time zone (*=UTC), 3. output time zone. (*=same as input), 4. output format (*=same as input)</param> /// <param name="args">rxline: rx macro/paths</param> private void C_Date(LineReader reader, string args) { string spec = ReadHereString(reader); string srx, macro; string[] paths; if (GetRxLine(args, out srx, out paths, out macro)) { Regex rx = new Regex(srx, RegexOptions.CultureInvariant | RegexOptions.Compiled); if (macro != null) { string text; if (TryGetMacro(macro, out text)) { string text1 = ConvertDateTime(text, rx, spec); SetMacro(macro, text1); } } else { foreach (string p in paths) { string text = File.ReadAllText(p); string text1 = ConvertDateTime(text, rx, spec); File.WriteAllText(p, text1); } } } }
private bool C_If_Ifnot(LineReader reader, string args, string cmd, out string val) { string[] parts = Chop(args, 2, ' '); string macro = parts[0]; string rx = parts[1]; bool isElse; bool not = cmd == "ifnot"; string text, contents; if (not ^ (TryGetMacro(macro, out text) && Regex.IsMatch(text, rx))) { contents = Expand(ReadConditionalBlock(reader, out isElse)); using (var sr = new LineReader(contents, args + " (then)")) { SendMessage("@{0} ({1})->then", cmd, macro); val = Run(sr); if (val != null) return true; } if (isElse) ReadCData(reader, "#endif"); } else { ReadConditionalBlock(reader, out isElse); if (isElse) { contents = Expand(ReadCData(reader, "#endif")); using (var sr = new LineReader(contents, args + " (else)")) { SendMessage("@{0} ({1})->else", cmd, macro); val = Run(sr); if (val != null) return true; } } } val = null; return false; }
private void C_Def(LineReader reader, string args) { string[] parts = Chop(args); string key = parts[0]; if (key.Length < 1 || key[0] < 'A' || key[0] > 'Z') throw new ArgumentException("#def name must start with capital A..Z"); string text = ReadCData(reader, "#enddef"); string[] arr = new string[parts.Length - 1]; Array.Copy(parts, 1, arr, 0, parts.Length - 1); _CustomCommands[key] = new CustomCommand(key, text, arr); }
private void C_Iter(LineReader reader, string args) { string[] parts = Chop(args, 3, ' '); string key, text, contents; if (parts.Length >= 3) { // #iter list recipe i key = parts[2]; text = GetMacro(parts[1]); // recipe contents = GetMacro(parts[0]); SetMacro(key, contents); } else if (parts.Length == 2) { // #putv i=list // #iter i recipe key = parts[0]; text = GetMacro(parts[1]); // recipe contents = GetMacro(key); } else { // #iter list // ... `_` ... // #next key = "_"; text = ReadCData(reader, "#next"); // recipe contents = GetMacro(parts[0]); } string[] items = contents.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); string itemKey = key; int n = 0; foreach (string item in items) { n++; SendMessage("@iter {0} = {1}", key, item); using (var sr = new LineReader(text, string.Format("{0} #{1}", args, n))) { _Macros[itemKey] = item; if (Run(sr) == null && !_Run) break; } } _Macros.Remove(itemKey); }
private void C_Default(LineReader reader, string args, string cmd) { string key = args.Trim(); CustomCommand cc; if (_CustomCommands.TryGetValue(cmd, out cc)) { string text = ReadHereString(reader, true); string val = ExecuteCustomCommand(cc, text); if (key != "") SetMacro(key, val); } else if (cmd != "tags" && cmd != "auto") { throw new Exception("Unknown command: #" + cmd); } }
private void C_MakeXml(LineReader reader, string args) { if (string.IsNullOrEmpty(args)) throw new Exception("#makexml needs key and here-text"); var contents = ReadHereString(reader, true); string xml = LightXml.ToNormalXml(contents); SetMacro(args, xml); SendMessage("@makexml {0}", args); }
private void C_Email(LineReader reader, string args) { string[] ra = Chop(args, 2, ' '); if (ra.Length > 0) { string recip = ra[0]; string body = ReadHereString(reader); string[] att = ra.Length > 1 ? ra[1].Trim().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries) : new string[0]; string sender; if (!TryGetMacro("smtp-sender", out sender)) { SendMessage("@skip email: macro smtp-sender not defined"); } else { var mm = new MailMessage(sender, recip, _MarkerName, body); foreach (string file in att) { mm.Attachments.Add(new Attachment(file)); } SmtpClient client = GetSmtpClient(); if (client == null) { SendMessage("@skip email: macro smtp-host not defined"); } else { if (Write) { try { client.Send(mm); } catch { // email doesn't work, just write it out SendMessage("~{0}", body); } } SendMessage("@email " + recip); } } } }
private void C_New_Newer(LineReader reader, string args, string cmd) { string path; SetFile(path = args); string contents = ReadHereString(reader); string directory = Path.GetDirectoryName(path); if (string.IsNullOrEmpty(directory)) { SendMessage("@skip new {0} -> directory missing", path); } else { if (!Directory.Exists(directory)) { if (Write) Directory.CreateDirectory(directory); SendMessage("@new {0}", directory); } if (cmd == "newer" || !File.Exists(path)) { if (Write) File.WriteAllText(path, contents); SendMessage("@{0} {1}", cmd, path); } else { SendMessage("@skip new {0}", path); } } }
private void C_Esc(LineReader reader, string args) { string[] nv = Chop(args, 2, '='); string rx = Regex.Escape(nv.Length == 2 ? nv[1] : ReadHereString(reader)); SetMacro(nv[0], rx); SendMessage("@esc {0}", rx); }
private void C_Path(LineReader reader, string args) { string key = args; string contents = ReadHereString(reader); string[] parts = contents.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); string text = Path.Combine(parts); SetMacro(key, text); }
private void C_EscXml(LineReader reader, string args) { string[] nv = Chop(args, 2, '='); string xml = SecurityElement.Escape(nv.Length == 2 ? nv[1] : ReadHereString(reader)); SetMacro(nv[0], xml); SendMessage("@escxml {0}", nv[0]); }
private void InitializeRecipe() { try { ConfigUtils.RefreshAppSettings(); string recipePath = ConfigUtils.GetString("Path", @"~prog\Main.rcp"); recipePath = ExpandPath(recipePath); _LogLevel = ConfigUtils.GetValue("LogLevel", 1); var macros = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // add all environment variables to the dictionary IDictionary env = Environment.GetEnvironmentVariables(); foreach (string key in env.Keys) macros.Add(key, (string)env[key]); // parse config file arguments and add to dictionary string[] args = ConfigUtils.GetArray("Macros", ""); var sb = new StringBuilder(); if (args != null) { foreach (string t in args) { string[] nv = t.Split('='); if (nv.Length == 2) { string key = nv[0].Trim(); string value = ExpandPath(nv[1].Trim()); macros[key] = value; sb.Append(key).Append('=').Append(value).Append('|'); } else throw new Exception("Invalid argument: " + t); } } Log(0, "Macros from configuration: [{0}]", sb.ToString().TrimEnd('|')); _RecipeExec = new Recipe { Write = true }; _RecipeExec.ClearHandlers(); _RecipeExec.Message += HandleMessage; _RecipeExec.SetRootPath(recipePath); using (LineReader sr = new LineReader(File.OpenText(recipePath), name: recipePath)) { Log(0, "Running: [{0}] LogLevel: {1}", recipePath, _LogLevel); _RecipeExec.Run(sr, macros, string.Empty); } } catch (ApplicationException) { Log(0, "Recipe Exit {0}"); } catch (Exception ex) { Log(1, "{0}", ex); } }
private void C_Before_Subs_After(LineReader reader, string args, string cmd) { string rx, macro; string[] paths; if (GetRxLine(args, out rx, out paths, out macro)) { string text; string contents; if (macro != null && TryGetMacro(macro, out text)) { contents = ReadHereString(reader); string repl = cmd == "subs" ? contents : cmd == "before" ? contents + "$0" : "$0" + contents; text = Regex.Replace(text, rx, repl); _Macros[macro] = text; SendKeyValueMessage(macro, text); } else { if (paths.Length == 0) { ReadHereString(reader, false); SendMessage("@skip {0} {1}", cmd, args); } else { contents = ReadHereString(reader, false); foreach (string p in paths) { SetFile(p); string inst = Expand(Generate(contents)); string repl = cmd == "subs" ? inst : cmd == "before" ? inst + "$0" : "$0" + inst; text = File.ReadAllText(p); var text1 = Regex.Replace(text, rx, repl); if (Write && text != text1) { File.WriteAllText(p, text1); SendMessage("@{0} {1}", cmd, p); } } } } } else { ReadHereString(reader, false); SendMessage("@nomatch {0}: {1}", cmd, args); } }