54#include <wx/cmdline.h>
56#include <wx/fileconf.h>
59#include "base_platform.h"
60#include "catalog_handler.h"
61#include "comm_appmsg_bus.h"
62#include "comm_driver.h"
63#include "comm_navmsg_bus.h"
64#include "config_vars.h"
65#include "downloader.h"
66#include "observable_evtvar.h"
67#include "ocpn_utils.h"
68#include "plugin_handler.h"
69#include "plugin_loader.h"
79bool g_bportable =
false;
80wxString g_winPluginDir;
81void* g_pi_manager =
reinterpret_cast<void*
>(1L);
82wxString g_compatOS = PKG_TARGET;
83wxString g_compatOsVersion = PKG_TARGET_VERSION;
85wxString g_catalog_custom_url;
86wxString g_catalog_channel;
89bool g_bAIS_ACK_Timeout;
90bool g_bAIS_CPA_Alert_Suppress_Moored;
95double g_AckTimeout_Mins;
98double g_ShowMoored_Kts;
107bool g_bAllowShowScaled;
108bool g_bAISRolloverShowCOG;
109bool g_bAISRolloverShowCPA;
110bool g_bAISShowTracks;
111bool g_bAISRolloverShowClass;
112bool g_bAIS_CPA_Alert;
113double g_RemoveLost_Mins;
114double g_MarkLost_Mins;
115double g_AISShowTracks_Mins;
116float g_selection_radius_mm;
117float g_selection_radius_touch_mm;
118int g_nCOMPortCheck = 32;
119bool g_benableUDPNullHeader;
122std::vector<Track*> g_TrackList;
123wxString AISTargetNameFileName;
131int g_NMEAAPBPrecision;
134double g_n_arrival_circle_radius;
138wxString g_default_routepoint_icon;
139double g_TrackDeltaDistance;
140float g_fWaypointRangeRingsStep;
141float g_ChartScaleFactorExp;
142float g_MarkScaleFactorExp;
143wxString g_default_wp_icon;
145int g_iWaypointRangeRingsNumber;
146int g_iWaypointRangeRingsStepUnits;
147wxColour g_colourWaypointRangeRingsColour;
151bool g_bOverruleScaMin;
152int g_nTrackPrecision;
154RouteList *pRouteList;
156int g_route_line_width;
157int g_track_line_width;
160bool g_bAllowShipToActive;
167static void InitRouteman() {
169 auto RouteMgrDlgUpdateListCtrl = [&]() {};
170 g_pRouteMan =
new Routeman(ctx, RouteMgrDlgUpdateListCtrl);
174int g_iDistanceFormat = 0;
175int g_iSDMMFormat = 0;
176int g_iSpeedFormat = 0;
178namespace safe_mode {
bool get_mode() {
return false; } }
180static const char* USAGE = R
"""(
181Usage: opencpn-cli [options] <command>
189 Use non-default ABI. <abi-spec> is a string platform:version for
190 example 'ubuntu-gtk3-x86_64:20.04'.
193 load-plugin <plugin library file>:
194 Try to load a given library file, report possible errors.
196 install-plugin <plugin name>:
197 Download and install given plugin
199 uninstall-plugin <plugin name>:
200 Uninstall given plugin
203 List name and version for all installed plugins
206 List name and version for available plugins in catalog.
208 import-plugin <tarball file>
209 Import a given tarball file
212 print default ABI spec platform:version
215 Download latest master catalog.
219static const char *
const DOWNLOAD_REPO_PROTO =
220 "https://raw.githubusercontent.com/OpenCPN/plugins/@branch@/"
223wxDEFINE_EVENT(EVT_FOO, wxCommandEvent);
224wxDEFINE_EVENT(EVT_BAR, wxCommandEvent);
229 CliApp() : wxAppConsole() {
230 CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE,
"program");
231 SetAppName(
"opencpn");
234 void OnInitCmdLine(wxCmdLineParser& parser)
override {
235 parser.AddOption(
"a",
"abi",
"abi:version e. g., \"ubuntu-x86_64:20.04\"");
236 parser.AddSwitch(
"v",
"verbose",
"Verbose logging");
237 parser.AddSwitch(
"h",
"help",
"Print help");
238 parser.AddParam(
"<command>",
239 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
240 parser.AddParam(
"[arg]", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
242 wxLog::SetActiveTarget(
new wxLogStderr);
243 wxLog::SetTimestamp(
"");
244 wxLog::SetLogLevel(wxLOG_Warning);
247 auto config_file = g_BasePlatform->GetConfigFileName();
248 InitBaseConfig(
new wxFileConfig(
"",
"", config_file));
250 pRouteList =
new RouteList;
255 void list_plugins() {
257 wxImage::AddHandler(
new wxPNGHandler());
258 g_BasePlatform->GetSharedDataDir();
259 PluginLoader::getInstance()->LoadAllPlugIns(
false);
260 auto plugins = PluginHandler::getInstance()->
getInstalled();
261 for (
const auto& p : plugins) {
262 if (p.version ==
"0.0")
continue;
263 cout << left << setw(25) << p.name << p.version <<
"\n";
267 void list_available() {
269 auto handler = PluginHandler::getInstance();
270 auto plugins = handler->getAvailable();
271 for (
const auto& p : plugins) {
272 if (handler->isCompatible(p)) {
273 cout << left << setw(25) << p.name << p.version <<
"\n";
278 void uninstall_plugin(
const std::string& plugin) {
280 g_BasePlatform->GetSharedDataDir();
281 PluginLoader::getInstance()->LoadAllPlugIns(
false);
282 auto plugins = PluginHandler::getInstance()->
getInstalled();
283 vector<PluginMetadata> found;
284 copy_if(plugins.begin(), plugins.end(), back_inserter(found),
286 if (found.size() == 0) {
287 cerr <<
"No such plugin installed\n";
290 PluginHandler::getInstance()->
uninstall(found[0].name);
293 void import_plugin(
const std::string& tarball_path) {
298 void install_plugin(
const std::string& plugin) {
300 g_BasePlatform->GetSharedDataDir();
301 wxImage::AddHandler(
new wxPNGHandler());
302 auto handler = PluginHandler::getInstance();
303 auto plugins = handler->getAvailable();
304 vector<PluginMetadata> found;
305 copy_if(plugins.begin(), plugins.end(), back_inserter(found),
307 return m.name == plugin && handler->isCompatible(m); });
308 if (found.size() == 0) {
309 cerr <<
"No such plugin available\n";
314 bool ok = downloader.
download(path);
316 cerr <<
"Cannot download data from " << found[0].tarball_url <<
"\n";
320 remove(path.c_str());
324 bool load_plugin(
const std::string& plugin) {
325 auto loader = PluginLoader::getInstance();
326 wxImage::AddHandler(
new wxPNGHandler());
327 g_BasePlatform->GetSharedDataDir();
328 wxDEFINE_EVENT(EVT_FILE_NOTFOUND, wxCommandEvent);
330 file_notfound_listener.
Listen(loader->evt_unreadable_plugin,
331 this, EVT_FILE_NOTFOUND);
332 Bind(EVT_FILE_NOTFOUND, [&](wxCommandEvent ev) {
333 std::cerr <<
"Cannot open file: " << ev.GetString() <<
"\n";
336 wxDEFINE_EVENT(EVT_BAD_VERSION, wxCommandEvent);
338 bad_version_listener.
Listen(loader->evt_version_incompatible_plugin,
339 this, EVT_BAD_VERSION);
340 Bind(EVT_BAD_VERSION, [&](wxCommandEvent ev) {
341 std::cerr <<
"Incompatible plugin version " << ev.GetString() <<
"\n";
344 auto container = loader->LoadPlugIn(plugin.c_str());
345 ProcessPendingEvents();
346 std::cout << (container ?
"File loaded OK\n" :
"Load error\n");
347 return container ? true :
false;
350 void check_param_count(
const wxCmdLineParser& parser,
size_t count) {
351 if (parser.GetParamCount() < count) {
352 std::cerr << USAGE <<
"\n";
357 void update_catalog() {
358 std::string catalog(g_catalog_channel ==
"" ?
"master" : g_catalog_channel);
359 std::string url(g_catalog_custom_url);
360 if (catalog !=
"custom") {
361 url = std::string(DOWNLOAD_REPO_PROTO);
362 ocpn::replace(url,
"@branch@", catalog);
365 auto cat_handler = CatalogHandler::getInstance();
366 auto status = cat_handler->DownloadCatalog(path, url);
367 if (status != CatalogHandler::ServerStatus::OK) {
368 std::cout <<
"Cannot update catalog\n";
373 bool OnCmdLineParsed(wxCmdLineParser& parser) {
374 wxAppConsole::OnCmdLineParsed(parser);
376 std::cout <<
"OpenCPN CLI application. Use -h for help\n";
380 if (parser.Found(
"help")) {
381 std::cout << USAGE <<
"\n";
384 if (parser.Found(
"verbose")) wxLog::SetLogLevel(wxLOG_Debug);
385 if (parser.Found(
"abi", &option_val)) {
386 auto abi_vers = ocpn::split(option_val,
":");
387 g_compatOS = abi_vers[0];
388 if (abi_vers.size() > 1) g_compatOsVersion = abi_vers[1];
390 if (parser.GetParamCount() < 1) {
391 std::cerr << USAGE <<
"\n";
394 std::string command(parser.GetParam(0));
395 if (command ==
"load-plugin") {
396 check_param_count(parser, 2);
397 load_plugin(parser.GetParam(1).ToStdString());
399 else if (command ==
"uninstall-plugin") {
400 check_param_count(parser, 2);
401 uninstall_plugin(parser.GetParam(1).ToStdString());
403 else if (command ==
"import-plugin") {
404 check_param_count(parser, 2);
405 import_plugin(parser.GetParam(1).ToStdString());
407 else if (command ==
"install-plugin") {
408 check_param_count(parser, 2);
409 install_plugin(parser.GetParam(1).ToStdString());
411 else if (command ==
"list-plugins") {
412 check_param_count(parser, 1);
415 else if (command ==
"list-available") {
416 check_param_count(parser, 1);
419 else if (command ==
"print-abi") {
420 check_param_count(parser, 1);
421 std::cout << PKG_TARGET <<
":" << PKG_TARGET_VERSION
"\n";
423 else if (command ==
"update-catalog") {
424 check_param_count(parser, 1);
428 std::cerr << USAGE <<
"\n";
435wxIMPLEMENT_APP_CONSOLE(
CliApp);
Handle downloading of files from remote urls.
bool download(std::ostream *stream)
Download url into stream, return false on errors.
Keeps listening over it's lifespan, removes itself on destruction.
void Listen(const std::string &key, wxEvtHandler *listener, wxEventType evt)
Set object to send wxEventType ev to listener on changes in key.
const std::vector< PluginMetadata > getInstalled()
Return list of all installed plugins.
bool uninstall(const std::string plugin)
Uninstall an installed plugin.
bool installPlugin(PluginMetadata plugin)
Download and install a new, not installed plugin.
std::string getMetadataPath()
Return path to metadata XML file.