comparison plugins/mod_admin_shell.lua @ 13939:b1e7d3f571b1

prosodyctl shell: Output TSV when output is not a TTY This is meant to make it easier to use in scripts. CSV would have been nice but requires escaping of fields containing ",", but this implementation simply ignores this and assumes fields will not contain tabs.
author Kim Alvefur <zash@zash.se>
date Sun, 31 Aug 2025 00:47:25 +0200
parents 88f5ea4c28ce
children a2d4c71f5066
comparison
equal deleted inserted replaced
13938:88f5ea4c28ce 13939:b1e7d3f571b1
117 for column, spec in pairs(available_columns) do 117 for column, spec in pairs(available_columns) do
118 meta_columns[1].width = math.max(meta_columns[1].width or 0, #column); 118 meta_columns[1].width = math.max(meta_columns[1].width or 0, #column);
119 meta_columns[2].width = math.max(meta_columns[2].width or 0, #(spec.title or "")); 119 meta_columns[2].width = math.max(meta_columns[2].width or 0, #(spec.title or ""));
120 meta_columns[3].width = math.max(meta_columns[3].width or 0, #(spec.description or "")); 120 meta_columns[3].width = math.max(meta_columns[3].width or 0, #(spec.description or ""));
121 end 121 end
122 local row = format_table(meta_columns, self.session.width) 122 local row = format_table(meta_columns, self.session.width, self.session.column_separator)
123 print(row()); 123 print(row());
124 for column, spec in iterators.sorted_pairs(available_columns) do 124 for column, spec in iterators.sorted_pairs(available_columns) do
125 print(row({ column, spec.title, spec.description })); 125 print(row({ column, spec.title, spec.description }));
126 end 126 end
127 print [[]] 127 print [[]]
349 349
350 local line = event.stanza:get_text(); 350 local line = event.stanza:get_text();
351 local useglobalenv; 351 local useglobalenv;
352 352
353 session.repl = event.stanza.attr.repl ~= "0"; 353 session.repl = event.stanza.attr.repl ~= "0";
354 if session.repl then 354 if session.repl and session.width ~= -1 then
355 session.width = session.width - margin; 355 session.width = session.width - margin;
356 elseif session.width == -1 then
357 session.column_separator = "\t";
356 end 358 end
357 359
358 local result = st.stanza("repl-result"); 360 local result = st.stanza("repl-result");
359 361
360 if line:match("^>") then 362 if line:match("^>") then
488 end 490 end
489 491
490 print [[Commands are divided into multiple sections. For help on a particular section, ]] 492 print [[Commands are divided into multiple sections. For help on a particular section, ]]
491 print [[type: help SECTION (for example, 'help c2s'). Sections are: ]] 493 print [[type: help SECTION (for example, 'help c2s'). Sections are: ]]
492 print [[]] 494 print [[]]
493 local row = format_table({ { title = "Section", width = 7 }, { title = "Description", width = "100%" } }, session.width) 495 local row = format_table({ { title = "Section", width = 7 }, { title = "Description", width = "100%" } }, session.width, session.column_separator)
494 print(row()) 496 print(row())
495 for section_name, section in it.sorted_pairs(def_env) do 497 for section_name, section in it.sorted_pairs(def_env) do
496 local section_mt = getmetatable(section); 498 local section_mt = getmetatable(section);
497 local section_help = section_mt and section_mt.help; 499 local section_help = section_mt and section_mt.help;
498 print(row { section_name; section_help and section_help.desc or "" }); 500 print(row { section_name; section_help and section_help.desc or "" });
1307 1309
1308 describe_command [[c2s:show(jid, columns) - Show all client sessions with the specified JID (or all if no JID given)]] 1310 describe_command [[c2s:show(jid, columns) - Show all client sessions with the specified JID (or all if no JID given)]]
1309 function def_env.c2s:show(match_jid, colspec) 1311 function def_env.c2s:show(match_jid, colspec)
1310 local print = self.session.print; 1312 local print = self.session.print;
1311 local columns = get_colspec(colspec, { "id"; "jid"; "role"; "ipv"; "status"; "secure"; "smacks"; "csi" }); 1313 local columns = get_colspec(colspec, { "id"; "jid"; "role"; "ipv"; "status"; "secure"; "smacks"; "csi" });
1312 local row = format_table(columns, self.session.width); 1314 local row = format_table(columns, self.session.width, self.session.column_separator);
1313 1315
1314 local function match(session) 1316 local function match(session)
1315 local jid = get_jid(session) 1317 local jid = get_jid(session)
1316 return (not match_jid) or match_jid == "*" or jid_compare(jid, match_jid); 1318 return (not match_jid) or match_jid == "*" or jid_compare(jid, match_jid);
1317 end 1319 end
1412 1414
1413 describe_command [[s2s:show(domain, columns) - Show all s2s connections for the given domain (or all if no domain given)]] 1415 describe_command [[s2s:show(domain, columns) - Show all s2s connections for the given domain (or all if no domain given)]]
1414 function def_env.s2s:show(match_jid, colspec) 1416 function def_env.s2s:show(match_jid, colspec)
1415 local print = self.session.print; 1417 local print = self.session.print;
1416 local columns = get_colspec(colspec, { "id"; "host"; "dir"; "remote"; "ipv"; "secure"; "s2s_sasl"; "dialback" }); 1418 local columns = get_colspec(colspec, { "id"; "host"; "dir"; "remote"; "ipv"; "secure"; "s2s_sasl"; "dialback" });
1417 local row = format_table(columns, self.session.width); 1419 local row = format_table(columns, self.session.width, self.session.column_separator);
1418 1420
1419 local function match(session) 1421 local function match(session)
1420 return match_s2s_jid(session, match_jid); 1422 return match_s2s_jid(session, match_jid);
1421 end 1423 end
1422 1424
1769 local print = self.session.print; 1771 local print = self.session.print;
1770 local row = format_table({ 1772 local row = format_table({
1771 { title = "Role"; width = 12; key = "role" }; -- longest role name 1773 { title = "Role"; width = 12; key = "role" }; -- longest role name
1772 { title = "JID"; width = "75%"; key = "bare_jid" }; 1774 { title = "JID"; width = "75%"; key = "bare_jid" };
1773 { title = "Nickname"; width = "25%"; key = "nick"; mapper = jid_resource }; 1775 { title = "Nickname"; width = "25%"; key = "nick"; mapper = jid_resource };
1774 }, self.session.width); 1776 }, self.session.width, self.session.column_separator);
1775 local occupants = array.collect(iterators.select(2, room_obj:each_occupant())); 1777 local occupants = array.collect(iterators.select(2, room_obj:each_occupant()));
1776 local total = #occupants; 1778 local total = #occupants;
1777 if filter then 1779 if filter then
1778 occupants:filter(function(occupant) 1780 occupants:filter(function(occupant)
1779 return occupant.role == filter or jid_resource(occupant.nick):find(filter, 1, true); 1781 return occupant.role == filter or jid_resource(occupant.nick):find(filter, 1, true);
1814 local print = self.session.print; 1816 local print = self.session.print;
1815 local row = format_table({ 1817 local row = format_table({
1816 { title = "Affiliation"; width = 12 }; -- longest affiliation name 1818 { title = "Affiliation"; width = 12 }; -- longest affiliation name
1817 { title = "JID"; width = "75%" }; 1819 { title = "JID"; width = "75%" };
1818 { title = "Nickname"; width = "25%"; key = "reserved_nickname" }; 1820 { title = "Nickname"; width = "25%"; key = "reserved_nickname" };
1819 }, self.session.width); 1821 }, self.session.width, self.session.column_separator);
1820 local affiliated = array(); 1822 local affiliated = array();
1821 for affiliated_jid, affiliation, affiliation_data in room_obj:each_affiliation() do 1823 for affiliated_jid, affiliation, affiliation_data in room_obj:each_affiliation() do
1822 affiliated:push(setmetatable({ affiliation; affiliated_jid }, { __index = affiliation_data })); 1824 affiliated:push(setmetatable({ affiliation; affiliated_jid }, { __index = affiliation_data }));
1823 end 1825 end
1824 1826
2158 local print = self.session.print; 2160 local print = self.session.print;
2159 hosts = array.collect(set.new({ not hosts and "*" or nil }) + get_hosts_set(hosts)):sort(_sort_hosts); 2161 hosts = array.collect(set.new({ not hosts and "*" or nil }) + get_hosts_set(hosts)):sort(_sort_hosts);
2160 local output_simple = format_table({ 2162 local output_simple = format_table({
2161 { title = "Module"; width = "1p" }; 2163 { title = "Module"; width = "1p" };
2162 { title = "External URL"; width = "6p" }; 2164 { title = "External URL"; width = "6p" };
2163 }, self.session.width); 2165 }, self.session.width, self.session.column_separator);
2164 local output_split = format_table({ 2166 local output_split = format_table({
2165 { title = "Module"; width = "1p" }; 2167 { title = "Module"; width = "1p" };
2166 { title = "External URL"; width = "3p" }; 2168 { title = "External URL"; width = "3p" };
2167 { title = "Internal URL"; width = "3p" }; 2169 { title = "Internal URL"; width = "3p" };
2168 }, self.session.width); 2170 }, self.session.width, self.session.column_separator);
2169 2171
2170 for _, host in ipairs(hosts) do 2172 for _, host in ipairs(hosts) do
2171 local http_apps = modulemanager.get_items("http-provider", host); 2173 local http_apps = modulemanager.get_items("http-provider", host);
2172 if #http_apps > 0 then 2174 if #http_apps > 0 then
2173 local http_host = module:context(host):get_option_string("http_host"); 2175 local http_host = module:context(host):get_option_string("http_host");
2379 local row = format_table({ 2381 local row = format_table({
2380 { title = "ID"; width = 12 }; 2382 { title = "ID"; width = 12 };
2381 { title = "Function"; width = "10p" }; 2383 { title = "Function"; width = "10p" };
2382 { title = "Status"; width = "16" }; 2384 { title = "Status"; width = "16" };
2383 { title = "Location"; width = "10p" }; 2385 { title = "Location"; width = "10p" };
2384 }, self.session.width); 2386 }, self.session.width, self.session.column_separator);
2385 print(row()) 2387 print(row())
2386 2388
2387 local c = 0; 2389 local c = 0;
2388 for runner, since in pairs(async.waiting_runners) do 2390 for runner, since in pairs(async.waiting_runners) do
2389 c = c + 1; 2391 c = c + 1;
2444 2446
2445 local row = format_table({ 2447 local row = format_table({
2446 { title = "Domain", width = max_domain }; 2448 { title = "Domain", width = max_domain };
2447 { title = "Certificate", width = "100%" }; 2449 { title = "Certificate", width = "100%" };
2448 { title = "Service", width = 5 }; 2450 { title = "Service", width = 5 };
2449 }, self.session.width); 2451 }, self.session.width, self.session.column_separator);
2450 print(row()); 2452 print(row());
2451 print(("-"):rep(self.session.width or 80)); 2453 print(("-"):rep(self.session.width or 80));
2452 for domain, certs in it.sorted_pairs(index) do 2454 for domain, certs in it.sorted_pairs(index) do
2453 for cert_file, services in it.sorted_pairs(certs) do 2455 for cert_file, services in it.sorted_pairs(certs) do
2454 for service in it.sorted_pairs(services) do 2456 for service in it.sorted_pairs(services) do