From 032620a044b80de3221b65e91a069047608e79c4 Mon Sep 17 00:00:00 2001 From: Corey White Date: Sat, 27 Aug 2022 05:40:40 -0400 Subject: [PATCH 01/26] g.mapsets: fixed indenting and added json flag in preperation to add json output --- general/g.mapsets/get_maps.c | 10 ++-- general/g.mapsets/list.c | 16 +++--- general/g.mapsets/main.c | 106 +++++++++++++++++++---------------- 3 files changed, 72 insertions(+), 60 deletions(-) diff --git a/general/g.mapsets/get_maps.c b/general/g.mapsets/get_maps.c index c22af42c838..ada49b230bb 100644 --- a/general/g.mapsets/get_maps.c +++ b/general/g.mapsets/get_maps.c @@ -6,27 +6,27 @@ static int cmp(const void *, const void *); -char** get_available_mapsets(int *nmapsets) +char **get_available_mapsets(int *nmapsets) { char **ms, **mapset_name; int i, n; ms = G_get_available_mapsets(); - for (n = 0; ms[n]; n++); + for (n = 0; ms[n]; n++) ; mapset_name = (char **)G_malloc(n * sizeof(char *)); - for(i = 0; i < n; i++) + for (i = 0; i < n; i++) mapset_name[i] = G_store(ms[i]); /* sort mapsets */ qsort(mapset_name, n, sizeof(char *), cmp); *nmapsets = n; - + return mapset_name; } -int cmp(const void *a, const void *b) +int cmp(const void *a, const void *b) { return (strcmp(*(char **)a, *(char **)b)); } diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 21582ec43e3..f8dfabbdc5e 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -4,14 +4,16 @@ #include #include "local_proto.h" -void list_available_mapsets(const char **mapset_name, int nmapsets, const char* fs) +void list_available_mapsets(const char **mapset_name, int nmapsets, + const char *fs) { - int n; + int n; + G_message(_("Available mapsets:")); - + for (n = 0; n < nmapsets; n++) { fprintf(stdout, "%s", mapset_name[n]); - if (n < nmapsets-1) { + if (n < nmapsets - 1) { if (strcmp(fs, "newline") == 0) fprintf(stdout, "\n"); else if (strcmp(fs, "space") == 0) @@ -27,16 +29,16 @@ void list_available_mapsets(const char **mapset_name, int nmapsets, const char* fprintf(stdout, "\n"); } -void list_accessible_mapsets(const char* fs) +void list_accessible_mapsets(const char *fs) { int n; const char *name; - + G_message(_("Accessible mapsets:")); for (n = 0; (name = G_get_mapset_name(n)); n++) { /* match each mapset to its numeric equivalent */ fprintf(stdout, "%s", name); - if (G_get_mapset_name(n+1)) { + if (G_get_mapset_name(n + 1)) { if (strcmp(fs, "newline") == 0) fprintf(stdout, "\n"); else if (strcmp(fs, "space") == 0) diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index f833eb8814e..409b1d65ff0 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -47,14 +47,15 @@ int main(int argc, char *argv[]) char path_buf[GPATH_MAX]; char *path, *fs; int operation, nchoices; - + char **mapset_name; int nmapsets; - - struct GModule *module; - struct _opt { + + struct GModule *module; + struct _opt + { struct Option *mapset, *op, *fs; - struct Flag *print, *list, *dialog; + struct Flag *print, *list, *dialog, *json; } opt; G_gisinit(argv[0]); @@ -63,15 +64,18 @@ int main(int argc, char *argv[]) G_add_keyword(_("general")); G_add_keyword(_("settings")); G_add_keyword(_("search path")); - module->label = _("Modifies/prints the user's current mapset search path."); - module->description = _("Affects the user's access to data existing " - "under the other mapsets in the current location."); + module->label = + _("Modifies/prints the user's current mapset search path."); + module->description = + _("Affects the user's access to data existing " + "under the other mapsets in the current location."); opt.mapset = G_define_standard_option(G_OPT_M_MAPSET); opt.mapset->required = YES; opt.mapset->multiple = YES; - opt.mapset->description = _("Name(s) of existing mapset(s) to add/remove or set"); - + opt.mapset->description = + _("Name(s) of existing mapset(s) to add/remove or set"); + opt.op = G_define_option(); opt.op->key = "operation"; opt.op->type = TYPE_STRING; @@ -80,15 +84,16 @@ int main(int argc, char *argv[]) opt.op->options = "set,add,remove"; opt.op->description = _("Operation to be performed"); opt.op->answer = "add"; - + opt.fs = G_define_standard_option(G_OPT_F_SEP); opt.fs->label = _("Field separator for printing (-l and -p flags)"); opt.fs->answer = "space"; opt.fs->guisection = _("Print"); - + opt.list = G_define_flag(); opt.list->key = 'l'; - opt.list->description = _("List all available mapsets in alphabetical order"); + opt.list->description = + _("List all available mapsets in alphabetical order"); opt.list->guisection = _("Print"); opt.list->suppress_required = YES; @@ -102,7 +107,12 @@ int main(int argc, char *argv[]) opt.dialog->key = 's'; opt.dialog->description = _("Launch mapset selection GUI dialog"); opt.dialog->suppress_required = YES; - + + opt.json = G_define_flag(); + opt.json->key = 'j'; + opt.json->description = _("Print the stats in JSON"); + opt.json->guisection = _("Print"); + path = NULL; mapset_name = NULL; nmapsets = nchoices = 0; @@ -112,7 +122,7 @@ int main(int argc, char *argv[]) operation = OP_UKN; if (opt.mapset->answer && opt.op->answer) { - switch(opt.op->answer[0]) { + switch (opt.op->answer[0]) { case 's': operation = OP_SET; break; @@ -127,7 +137,7 @@ int main(int argc, char *argv[]) break; } } - + fs = G_option_to_separator(opt.fs); /* list available mapsets */ @@ -151,22 +161,23 @@ int main(int argc, char *argv[]) list_accessible_mapsets(fs); exit(EXIT_SUCCESS); } - + /* show GUI dialog */ if (opt.dialog->answer) { if (opt.mapset->answer) G_warning(_("Option <%s> ignored"), opt.mapset->key); - sprintf(path_buf, "%s/gui/wxpython/modules/mapsets_picker.py", G_gisbase()); + sprintf(path_buf, "%s/gui/wxpython/modules/mapsets_picker.py", + G_gisbase()); G_spawn(getenv("GRASS_PYTHON"), "mapsets_picker.py", path_buf, NULL); exit(EXIT_SUCCESS); } cur_mapset = G_mapset(); - + /* modify search path */ if (operation == OP_SET) { int cur_found; - + cur_found = FALSE; for (ptr = opt.mapset->answers; *ptr != NULL; ptr++) { mapset = substitute_mapset(*ptr); @@ -184,7 +195,7 @@ int main(int argc, char *argv[]) else if (operation == OP_ADD) { /* add to existing search path */ const char *oldname; - + if (path) { G_free(path); path = NULL; @@ -203,7 +214,7 @@ int main(int argc, char *argv[]) G_message(_("Mapset <%s> already in the path"), mapset); continue; } - + if (G_mapset_permissions(mapset) < 0) G_fatal_error(_("Mapset <%s> not found"), mapset); else @@ -218,35 +229,34 @@ int main(int argc, char *argv[]) /* remove from existing search path */ const char *oldname; int found; - + if (path) { G_free(path); path = NULL; } - + /* read existing mapsets from SEARCH_PATH */ for (n = 0; (oldname = G_get_mapset_name(n)); n++) { found = FALSE; - - for (ptr = opt.mapset->answers; *ptr && !found; ptr++) + for (ptr = opt.mapset->answers; *ptr && !found; ptr++) mapset = substitute_mapset(*ptr); - - if (strcmp(oldname, mapset) == 0) - found = TRUE; - - if (found) { - if (strcmp(oldname, cur_mapset) == 0) - G_warning(_("Current mapset (<%s>) must always included in the search path"), - cur_mapset); - else - G_verbose_message(_("Mapset <%s> removed from search path"), - oldname); - continue; - } - - nchoices++; - append_mapset(&path, oldname); + + if (strcmp(oldname, mapset) == 0) + found = TRUE; + + if (found) { + if (strcmp(oldname, cur_mapset) == 0) + G_warning(_("Current mapset (<%s>) must always included in the search path"), + cur_mapset); + else + G_verbose_message(_("Mapset <%s> removed from search path"), + oldname); + continue; + } + + nchoices++; + append_mapset(&path, oldname); } } /* stuffem sets nchoices */ @@ -255,16 +265,16 @@ int main(int argc, char *argv[]) G_important_message(_("Search path not modified")); if (path) G_free(path); - + if (nmapsets) { - for(nmapsets--; nmapsets >= 0; nmapsets--) + for (nmapsets--; nmapsets >= 0; nmapsets--) G_free(mapset_name[nmapsets]); G_free(mapset_name); } - + exit(EXIT_SUCCESS); } - + /* note I'm assuming that mapsets cannot have ' 's in them */ tokens = G_tokenize(path, " "); @@ -276,7 +286,7 @@ int main(int argc, char *argv[]) * make sure current mapset is specified in the list if not add it * to the head of the list */ - + skip = 0; for (n = 0; n < nchoices; n++) if (strcmp(cur_mapset, tokens[n]) == 0) { @@ -313,7 +323,7 @@ int main(int argc, char *argv[]) G_free(path); if (nmapsets) { - for(nmapsets--; nmapsets >= 0; nmapsets--) + for (nmapsets--; nmapsets >= 0; nmapsets--) G_free(mapset_name[nmapsets]); G_free(mapset_name); } From dfbf8cf3880c30eff17a1fec3409ea24707ccce7 Mon Sep 17 00:00:00 2001 From: Corey White Date: Sat, 27 Aug 2022 07:35:55 -0400 Subject: [PATCH 02/26] Added format options to list mapsets as plain, vertical, csv, or json --- general/g.mapsets/list.c | 17 ++++- general/g.mapsets/main.c | 140 ++++++++++++++++++++++++++++++++++----- 2 files changed, 139 insertions(+), 18 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index f8dfabbdc5e..6328effcd09 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -9,8 +9,6 @@ void list_available_mapsets(const char **mapset_name, int nmapsets, { int n; - G_message(_("Available mapsets:")); - for (n = 0; n < nmapsets; n++) { fprintf(stdout, "%s", mapset_name[n]); if (n < nmapsets - 1) { @@ -53,3 +51,18 @@ void list_accessible_mapsets(const char *fs) } fprintf(stdout, "\n"); } + +void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) +{ + int n; + + fprintf(stdout, "{\"mapsets\": ["); + for (n = 0; n < nmapsets; n++) { + fprintf(stdout, "\"%s\"", mapset_name[n]); + if (n < nmapsets - 1) { + fprintf(stdout, ","); + } + } + fprintf(stdout, "]}\n"); + +} diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 409b1d65ff0..3532ab92964 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -33,6 +33,33 @@ #define OP_ADD 2 #define OP_REM 3 +enum OutputFormat { + PLAIN, + JSON, + CSV, + VERTICAL +}; + +void fatal_error_option_value_excludes_flag(struct Option *option, + struct Flag *excluded, + const char *because) +{ + if (!excluded->answer) + return; + G_fatal_error(_("The flag -%c is not allowed with %s=%s. %s"), + excluded->key, option->key, option->answer, because); +} + +void fatal_error_option_value_excludes_option(struct Option *option, + struct Option *excluded, + const char *because) +{ + if (!excluded->answer) + return; + G_fatal_error(_("The option %s is not allowed with %s=%s. %s"), + excluded->key, option->key, option->answer, because); +} + static void append_mapset(char **, const char *); int main(int argc, char *argv[]) @@ -45,17 +72,18 @@ int main(int argc, char *argv[]) int no_tokens; FILE *fp; char path_buf[GPATH_MAX]; - char *path, *fs; + char *path, *fsep, *vsep; int operation, nchoices; - + enum OutputFormat format; + bool vsep_needs_newline; char **mapset_name; int nmapsets; struct GModule *module; struct _opt { - struct Option *mapset, *op, *fs; - struct Flag *print, *list, *dialog, *json; + struct Option *mapset, *op, *format, *fsep, *vsep, *nullval; + struct Flag *print, *list, *dialog, *colnames, *escape; } opt; G_gisinit(argv[0]); @@ -85,10 +113,42 @@ int main(int argc, char *argv[]) opt.op->description = _("Operation to be performed"); opt.op->answer = "add"; - opt.fs = G_define_standard_option(G_OPT_F_SEP); - opt.fs->label = _("Field separator for printing (-l and -p flags)"); - opt.fs->answer = "space"; - opt.fs->guisection = _("Print"); + opt.format = G_define_option(); + opt.format->key = "format"; + opt.format->type = TYPE_STRING; + opt.format->required = YES; + opt.format->label = _("Output format for printing (-l and -p flags)"); + opt.format->options = "plain,csv,json,vertical"; + opt.format->descriptions = + "plain;Configurable plain text output;" + "csv;CSV (Comma Separated Values);" + "json;JSON (JavaScript Object Notation);" + "vertical;Plain text vertical output (instead of horizontal)"; + opt.format->answer = "plain"; + opt.format->guisection = _("Format"); + + opt.fsep = G_define_standard_option(G_OPT_F_SEP); + opt.fsep->answer = NULL; + opt.fsep->guisection = _("Format"); + + opt.vsep = G_define_standard_option(G_OPT_F_SEP); + opt.vsep->key = "vertical_separator"; + opt.vsep->label = _("Output vertical record separator"); + opt.vsep->answer = NULL; + opt.vsep->guisection = _("Format"); + + opt.nullval = G_define_standard_option(G_OPT_M_NULL_VALUE); + opt.nullval->guisection = _("Format"); + + opt.colnames = G_define_flag(); + opt.colnames->key = 'c'; + opt.colnames->description = _("Do not include column names in output"); + opt.colnames->guisection = _("Format"); + + opt.escape = G_define_flag(); + opt.escape->key = 'e'; + opt.escape->description = _("Escape newline and backslash characters"); + opt.escape->guisection = _("Format"); opt.list = G_define_flag(); opt.list->key = 'l'; @@ -108,11 +168,6 @@ int main(int argc, char *argv[]) opt.dialog->description = _("Launch mapset selection GUI dialog"); opt.dialog->suppress_required = YES; - opt.json = G_define_flag(); - opt.json->key = 'j'; - opt.json->description = _("Print the stats in JSON"); - opt.json->guisection = _("Print"); - path = NULL; mapset_name = NULL; nmapsets = nchoices = 0; @@ -138,7 +193,54 @@ int main(int argc, char *argv[]) } } - fs = G_option_to_separator(opt.fs); + if (strcmp(opt.format->answer, "csv") == 0) + format = CSV; + else if (strcmp(opt.format->answer, "json") == 0) + format = JSON; + else if (strcmp(opt.format->answer, "vertical") == 0) + format = VERTICAL; + else + format = PLAIN; + if (format == JSON) { + fatal_error_option_value_excludes_flag(opt.format, opt.escape, + _("Escaping is based on the format")); + fatal_error_option_value_excludes_flag(opt.format, opt.colnames, + _("Column names are always included")); + fatal_error_option_value_excludes_option(opt.format, opt.fsep, + _("Separator is part of the format")); + fatal_error_option_value_excludes_option(opt.format, opt.nullval, + _("Null value is part of the format")); + } + if (format != VERTICAL) { + fatal_error_option_value_excludes_option(opt.format, opt.vsep, + _("Only vertical output can use vertical separator")); + } + + /* the field separator */ + if (opt.fsep->answer) { + fsep = G_option_to_separator(opt.fsep); + } + else { + /* A different separator is needed to for each format and output. */ + if (format == CSV) { + fsep = G_store(","); + } + else if (format == VERTICAL) { + fsep = G_store("newline"); + } + else if (format == PLAIN || format == VERTICAL) { + fsep = G_store("|"); + } + else + fsep = NULL; /* Something like a separator is part of the format. */ + } + if (opt.vsep->answer) + vsep = G_option_to_separator(opt.vsep); + else + vsep = NULL; + vsep_needs_newline = true; + if (vsep && !strcmp(vsep, "\n")) + vsep_needs_newline = false; /* list available mapsets */ if (opt.list->answer) { @@ -149,7 +251,13 @@ int main(int argc, char *argv[]) if (opt.mapset->answer) G_warning(_("Option <%s> ignored"), opt.mapset->key); mapset_name = get_available_mapsets(&nmapsets); - list_available_mapsets((const char **)mapset_name, nmapsets, fs); + if (format == JSON) { + list_avaliable_mapsets_json((const char **)mapset_name, nmapsets); + } + else { + list_available_mapsets((const char **)mapset_name, nmapsets, fsep); + } + exit(EXIT_SUCCESS); } @@ -158,7 +266,7 @@ int main(int argc, char *argv[]) G_warning(_("Flag -%c ignored"), opt.dialog->key); if (opt.mapset->answer) G_warning(_("Option <%s> ignored"), opt.mapset->key); - list_accessible_mapsets(fs); + list_accessible_mapsets(fsep); exit(EXIT_SUCCESS); } From 3cd14ccd4664db4321d196b06fc89b05607d7e15 Mon Sep 17 00:00:00 2001 From: Corey White Date: Sat, 27 Aug 2022 12:13:01 -0400 Subject: [PATCH 03/26] g.mapsets: Added start testing listing mapsets with different formats --- general/g.mapsets/list.c | 22 ++++++ general/g.mapsets/main.c | 25 +++---- general/g.mapsets/tests/conftest.py | 34 +++++++++ .../tests/test_g_mapsets_list_format.py | 71 +++++++++++++++++++ 4 files changed, 137 insertions(+), 15 deletions(-) create mode 100644 general/g.mapsets/tests/conftest.py create mode 100644 general/g.mapsets/tests/test_g_mapsets_list_format.py diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 6328effcd09..bbe948f31bf 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -66,3 +66,25 @@ void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) fprintf(stdout, "]}\n"); } + + +void list_avaliable_mapsets_vertical(const char **mapset_name, int nmapsets, + const char *vsep) +{ + int n; + + for (n = 0; n < nmapsets; n++) { + fprintf(stdout, "%s", mapset_name[n]); + if (n < nmapsets - 1) { + if (strcmp(vsep, "space") == 0) + fprintf(stdout, " \n"); + else if (strcmp(vsep, "comma") == 0) + fprintf(stdout, ",\n"); + else if (strcmp(vsep, "tab") == 0) + fprintf(stdout, "\t\n"); + else + fprintf(stdout, "%s\n", vsep); + } + } + fprintf(stdout, "\n"); +} \ No newline at end of file diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 3532ab92964..1d820334dc5 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -9,9 +9,10 @@ * Markus Neteler , * Moritz Lennert , * Martin Landa , - * Huidae Cho + * Huidae Cho , + * Corey White * PURPOSE: set current mapset path - * COPYRIGHT: (C) 1994-2009, 2012 by the GRASS Development Team + * COPYRIGHT: (C) 1994-2009, 2012-2022 by the GRASS Development Team * * This program is free software under the GNU General * Public License (>=v2). Read the file COPYING that @@ -83,7 +84,7 @@ int main(int argc, char *argv[]) struct _opt { struct Option *mapset, *op, *format, *fsep, *vsep, *nullval; - struct Flag *print, *list, *dialog, *colnames, *escape; + struct Flag *print, *list, *dialog, *escape; } opt; G_gisinit(argv[0]); @@ -140,11 +141,6 @@ int main(int argc, char *argv[]) opt.nullval = G_define_standard_option(G_OPT_M_NULL_VALUE); opt.nullval->guisection = _("Format"); - opt.colnames = G_define_flag(); - opt.colnames->key = 'c'; - opt.colnames->description = _("Do not include column names in output"); - opt.colnames->guisection = _("Format"); - opt.escape = G_define_flag(); opt.escape->key = 'e'; opt.escape->description = _("Escape newline and backslash characters"); @@ -204,8 +200,6 @@ int main(int argc, char *argv[]) if (format == JSON) { fatal_error_option_value_excludes_flag(opt.format, opt.escape, _("Escaping is based on the format")); - fatal_error_option_value_excludes_flag(opt.format, opt.colnames, - _("Column names are always included")); fatal_error_option_value_excludes_option(opt.format, opt.fsep, _("Separator is part of the format")); fatal_error_option_value_excludes_option(opt.format, opt.nullval, @@ -225,19 +219,17 @@ int main(int argc, char *argv[]) if (format == CSV) { fsep = G_store(","); } - else if (format == VERTICAL) { - fsep = G_store("newline"); - } - else if (format == PLAIN || format == VERTICAL) { + else if (format == PLAIN) { fsep = G_store("|"); } else fsep = NULL; /* Something like a separator is part of the format. */ } + if (opt.vsep->answer) vsep = G_option_to_separator(opt.vsep); else - vsep = NULL; + vsep = G_store("\n"); vsep_needs_newline = true; if (vsep && !strcmp(vsep, "\n")) vsep_needs_newline = false; @@ -254,6 +246,9 @@ int main(int argc, char *argv[]) if (format == JSON) { list_avaliable_mapsets_json((const char **)mapset_name, nmapsets); } + else if (format == VERTICAL) { + list_avaliable_mapsets_vertical((const char **)mapset_name, nmapsets, vsep); + } else { list_available_mapsets((const char **)mapset_name, nmapsets, fsep); } diff --git a/general/g.mapsets/tests/conftest.py b/general/g.mapsets/tests/conftest.py new file mode 100644 index 00000000000..0b105e63820 --- /dev/null +++ b/general/g.mapsets/tests/conftest.py @@ -0,0 +1,34 @@ +"""Fixtures for Jupyter tests + +Fixture for grass.jupyter.TimeSeries test + +Fixture for ReprojectionRenderer test with simple GRASS location, raster, vector. +""" + +from datetime import datetime +from types import SimpleNamespace + +import pytest + +import grass.script as gs + +TEST_MAPSETS = ["PERMANENT", "test1", "test2", "test3"] + +@pytest.fixture(scope="module") +def simple_dataset(tmp_path_factory): + """Start a session and create a test mapsets + Returns object with attributes about the dataset. + """ + tmp_path = tmp_path_factory.mktemp("simple_dataset") + location = "test" + gs.core._create_location_xy(tmp_path, location) # pylint: disable=protected-access + with gs.setup.init(tmp_path / location): + gs.run_command("g.proj", flags="c", epsg=26917) + gs.run_command("g.region", s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10) + # Create Mock Mapsets + for mapset in TEST_MAPSETS: + gs.run_command("g.mapset", location=location, mapset=mapset, flags="c") + + yield SimpleNamespace( + mapsets=TEST_MAPSETS + ) diff --git a/general/g.mapsets/tests/test_g_mapsets_list_format.py b/general/g.mapsets/tests/test_g_mapsets_list_format.py new file mode 100644 index 00000000000..c7530f810ab --- /dev/null +++ b/general/g.mapsets/tests/test_g_mapsets_list_format.py @@ -0,0 +1,71 @@ +############################################################################ +# +# MODULE: Test of g.mapsets +# AUTHOR(S): Corey White +# PURPOSE: Test parsing and structure of CSV and JSON outputs +# COPYRIGHT: (C) 2022 by Corey White the GRASS Development Team +# +# This program is free software under the GNU General Public +# License (>=v2). Read the file COPYING that comes with GRASS +# for details. +# +############################################################################# + +"""Test parsing and structure of CSV and JSON outputs from g.mapsets""" + +import json +import csv +import pytest + +import grass.script as gs + + + +def check_separators(format, mapsets): + SEPARATORS = ["newline", "space", "comma", "tab", "pipe", None] + + for sep in SEPARATORS: + text = gs.read_command("g.mapsets", format=format, separator=fsep, flags="l") + if sep == "newline": + assert text == "\n".join(mapsets) + "\n" + elif sep == "space": + assert text == " ".join(mapsets) + "\n" + elif sep == "comma": + assert text == ",".join(mapsets) + "\n" + elif sep == "tab": + assert text == "\t".join(mapsets) + "\n" + elif sep == "pipe": + assert text == "|".join(mapsets) + "\n" + else: + # Default vallue + assert text == "|".join(mapsets) + "\n" + +def test_plain_output(simple_dataset): + """Test that the separators are properly applied""" + check_separators("plain", simple_dataset.mapsets) + + +def test_json_ouput(simple_dataset): + """ JSON format """ + text = gs.read_command("g.mapsets", format="json", flags="l") + print(f"Text JSON: {text}") + data = json.loads(text) + assert list(data.keys()) == ["mapsets"] + assert isinstance(data["mapsets"], list) + assert len(data["mapsets"]) == 4 + for mapset in simple_dataset.mapsets: + assert mapset in data["mapsets"] + +def test_csv_output(simple_dataset): + """ CSV format """ + text = gs.read_command("g.mapsets", format="csv", flags="l") + assert text == ",".join(simple_dataset.mapsets) + "\n" + +# def test_vertical_output(simple_dataset): +# """ Vertical format """ +# text = gs.read_command("g.mapsets", format="vertical", flags="l") +# assert text == "\n".join(simple_dataset.mapsets) + "\n" + + +if __name__ == "__main__": + test() From 53e3905d1554aa3eea6c3ab962e3341942538e0c Mon Sep 17 00:00:00 2001 From: Corey White Date: Sat, 27 Aug 2022 12:18:32 -0400 Subject: [PATCH 04/26] g.mapsets: Reformated python with flake8 and black --- general/g.mapsets/tests/conftest.py | 8 +++---- .../tests/test_g_mapsets_list_format.py | 23 +++++-------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/general/g.mapsets/tests/conftest.py b/general/g.mapsets/tests/conftest.py index 0b105e63820..ba25c2137a4 100644 --- a/general/g.mapsets/tests/conftest.py +++ b/general/g.mapsets/tests/conftest.py @@ -5,7 +5,6 @@ Fixture for ReprojectionRenderer test with simple GRASS location, raster, vector. """ -from datetime import datetime from types import SimpleNamespace import pytest @@ -14,6 +13,7 @@ TEST_MAPSETS = ["PERMANENT", "test1", "test2", "test3"] + @pytest.fixture(scope="module") def simple_dataset(tmp_path_factory): """Start a session and create a test mapsets @@ -28,7 +28,5 @@ def simple_dataset(tmp_path_factory): # Create Mock Mapsets for mapset in TEST_MAPSETS: gs.run_command("g.mapset", location=location, mapset=mapset, flags="c") - - yield SimpleNamespace( - mapsets=TEST_MAPSETS - ) + + yield SimpleNamespace(mapsets=TEST_MAPSETS) diff --git a/general/g.mapsets/tests/test_g_mapsets_list_format.py b/general/g.mapsets/tests/test_g_mapsets_list_format.py index c7530f810ab..649bd7d6af6 100644 --- a/general/g.mapsets/tests/test_g_mapsets_list_format.py +++ b/general/g.mapsets/tests/test_g_mapsets_list_format.py @@ -14,18 +14,14 @@ """Test parsing and structure of CSV and JSON outputs from g.mapsets""" import json -import csv -import pytest - import grass.script as gs - def check_separators(format, mapsets): SEPARATORS = ["newline", "space", "comma", "tab", "pipe", None] for sep in SEPARATORS: - text = gs.read_command("g.mapsets", format=format, separator=fsep, flags="l") + text = gs.read_command("g.mapsets", format=format, separator=sep, flags="l") if sep == "newline": assert text == "\n".join(mapsets) + "\n" elif sep == "space": @@ -40,13 +36,14 @@ def check_separators(format, mapsets): # Default vallue assert text == "|".join(mapsets) + "\n" + def test_plain_output(simple_dataset): - """Test that the separators are properly applied""" + """Test that the separators are properly applied""" check_separators("plain", simple_dataset.mapsets) def test_json_ouput(simple_dataset): - """ JSON format """ + """JSON format""" text = gs.read_command("g.mapsets", format="json", flags="l") print(f"Text JSON: {text}") data = json.loads(text) @@ -56,16 +53,8 @@ def test_json_ouput(simple_dataset): for mapset in simple_dataset.mapsets: assert mapset in data["mapsets"] + def test_csv_output(simple_dataset): - """ CSV format """ + """CSV format""" text = gs.read_command("g.mapsets", format="csv", flags="l") assert text == ",".join(simple_dataset.mapsets) + "\n" - -# def test_vertical_output(simple_dataset): -# """ Vertical format """ -# text = gs.read_command("g.mapsets", format="vertical", flags="l") -# assert text == "\n".join(simple_dataset.mapsets) + "\n" - - -if __name__ == "__main__": - test() From 0f053020ab36b3aacdfb63561df6d475ad0653f1 Mon Sep 17 00:00:00 2001 From: Corey White Date: Sat, 27 Aug 2022 14:00:39 -0400 Subject: [PATCH 05/26] g.mapsets: Fixed indent conflict --- general/g.mapsets/list.c | 6 +++--- general/g.mapsets/main.c | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index bbe948f31bf..81e8b9fc4be 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -55,7 +55,7 @@ void list_accessible_mapsets(const char *fs) void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) { int n; - + fprintf(stdout, "{\"mapsets\": ["); for (n = 0; n < nmapsets; n++) { fprintf(stdout, "\"%s\"", mapset_name[n]); @@ -68,7 +68,7 @@ void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) } -void list_avaliable_mapsets_vertical(const char **mapset_name, int nmapsets, +void list_avaliable_mapsets_vertical(const char **mapset_name, int nmapsets, const char *vsep) { int n; @@ -87,4 +87,4 @@ void list_avaliable_mapsets_vertical(const char **mapset_name, int nmapsets, } } fprintf(stdout, "\n"); -} \ No newline at end of file +} diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 1d820334dc5..88de176d7f7 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -34,7 +34,8 @@ #define OP_ADD 2 #define OP_REM 3 -enum OutputFormat { +enum OutputFormat +{ PLAIN, JSON, CSV, @@ -83,7 +84,7 @@ int main(int argc, char *argv[]) struct GModule *module; struct _opt { - struct Option *mapset, *op, *format, *fsep, *vsep, *nullval; + struct Option *mapset, *op, *format, *fsep, *vsep, *nullval; struct Flag *print, *list, *dialog, *escape; } opt; @@ -220,16 +221,16 @@ int main(int argc, char *argv[]) fsep = G_store(","); } else if (format == PLAIN) { - fsep = G_store("|"); + fsep = G_store("|"); } else - fsep = NULL; /* Something like a separator is part of the format. */ + fsep = NULL; /* Something like a separator is part of the format. */ } if (opt.vsep->answer) vsep = G_option_to_separator(opt.vsep); else - vsep = G_store("\n"); + vsep = G_store("\n"); vsep_needs_newline = true; if (vsep && !strcmp(vsep, "\n")) vsep_needs_newline = false; @@ -247,12 +248,14 @@ int main(int argc, char *argv[]) list_avaliable_mapsets_json((const char **)mapset_name, nmapsets); } else if (format == VERTICAL) { - list_avaliable_mapsets_vertical((const char **)mapset_name, nmapsets, vsep); + list_avaliable_mapsets_vertical((const char **)mapset_name, + nmapsets, vsep); } else { - list_available_mapsets((const char **)mapset_name, nmapsets, fsep); + list_available_mapsets((const char **)mapset_name, nmapsets, + fsep); } - + exit(EXIT_SUCCESS); } From a904c05a7795b401c175b5f7ab3b3a4b120026bc Mon Sep 17 00:00:00 2001 From: Corey White Date: Sat, 27 Aug 2022 14:58:25 -0400 Subject: [PATCH 06/26] Fixed implicit declaration of function errors --- general/g.mapsets/list.c | 1 - general/g.mapsets/local_proto.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 81e8b9fc4be..d5161279181 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -32,7 +32,6 @@ void list_accessible_mapsets(const char *fs) int n; const char *name; - G_message(_("Accessible mapsets:")); for (n = 0; (name = G_get_mapset_name(n)); n++) { /* match each mapset to its numeric equivalent */ fprintf(stdout, "%s", name); diff --git a/general/g.mapsets/local_proto.h b/general/g.mapsets/local_proto.h index badbf2fabc2..72cedc03185 100644 --- a/general/g.mapsets/local_proto.h +++ b/general/g.mapsets/local_proto.h @@ -5,3 +5,5 @@ const char *substitute_mapset(const char *); /* list.c */ void list_available_mapsets(const char **, int, const char *); void list_accessible_mapsets(const char *); +void list_avaliable_mapsets_json(const char **, int); +void list_avaliable_mapsets_vertical(const char **, int, const char *); \ No newline at end of file From d3da3fde65c48f4e6d6a1a4d979d44b0b1777e78 Mon Sep 17 00:00:00 2001 From: Corey White Date: Sun, 28 Aug 2022 09:04:51 -0400 Subject: [PATCH 07/26] Fixed issues found in code review --- general/g.mapsets/list.c | 26 ++------ general/g.mapsets/local_proto.h | 1 - general/g.mapsets/main.c | 62 +++--------------- general/g.mapsets/tests/conftest.py | 4 +- .../tests/test_g_mapsets_list_format.py | 63 +++++++++++-------- 5 files changed, 50 insertions(+), 106 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index d5161279181..caa935c33c4 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -9,6 +9,8 @@ void list_available_mapsets(const char **mapset_name, int nmapsets, { int n; + G_message(_("Available mapsets:")); + for (n = 0; n < nmapsets; n++) { fprintf(stdout, "%s", mapset_name[n]); if (n < nmapsets - 1) { @@ -32,6 +34,8 @@ void list_accessible_mapsets(const char *fs) int n; const char *name; + G_message(_("Accessible mapsets:")); + for (n = 0; (name = G_get_mapset_name(n)); n++) { /* match each mapset to its numeric equivalent */ fprintf(stdout, "%s", name); @@ -65,25 +69,3 @@ void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) fprintf(stdout, "]}\n"); } - - -void list_avaliable_mapsets_vertical(const char **mapset_name, int nmapsets, - const char *vsep) -{ - int n; - - for (n = 0; n < nmapsets; n++) { - fprintf(stdout, "%s", mapset_name[n]); - if (n < nmapsets - 1) { - if (strcmp(vsep, "space") == 0) - fprintf(stdout, " \n"); - else if (strcmp(vsep, "comma") == 0) - fprintf(stdout, ",\n"); - else if (strcmp(vsep, "tab") == 0) - fprintf(stdout, "\t\n"); - else - fprintf(stdout, "%s\n", vsep); - } - } - fprintf(stdout, "\n"); -} diff --git a/general/g.mapsets/local_proto.h b/general/g.mapsets/local_proto.h index 72cedc03185..56c7a81fafe 100644 --- a/general/g.mapsets/local_proto.h +++ b/general/g.mapsets/local_proto.h @@ -6,4 +6,3 @@ const char *substitute_mapset(const char *); void list_available_mapsets(const char **, int, const char *); void list_accessible_mapsets(const char *); void list_avaliable_mapsets_json(const char **, int); -void list_avaliable_mapsets_vertical(const char **, int, const char *); \ No newline at end of file diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 88de176d7f7..8297e5a233c 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -37,9 +37,7 @@ enum OutputFormat { PLAIN, - JSON, - CSV, - VERTICAL + JSON }; void fatal_error_option_value_excludes_flag(struct Option *option, @@ -74,18 +72,17 @@ int main(int argc, char *argv[]) int no_tokens; FILE *fp; char path_buf[GPATH_MAX]; - char *path, *fsep, *vsep; + char *path, *fsep; int operation, nchoices; enum OutputFormat format; - bool vsep_needs_newline; char **mapset_name; int nmapsets; struct GModule *module; struct _opt { - struct Option *mapset, *op, *format, *fsep, *vsep, *nullval; - struct Flag *print, *list, *dialog, *escape; + struct Option *mapset, *op, *format, *fsep; + struct Flag *print, *list, *dialog; } opt; G_gisinit(argv[0]); @@ -120,12 +117,10 @@ int main(int argc, char *argv[]) opt.format->type = TYPE_STRING; opt.format->required = YES; opt.format->label = _("Output format for printing (-l and -p flags)"); - opt.format->options = "plain,csv,json,vertical"; + opt.format->options = "plain,json"; opt.format->descriptions = "plain;Configurable plain text output;" - "csv;CSV (Comma Separated Values);" - "json;JSON (JavaScript Object Notation);" - "vertical;Plain text vertical output (instead of horizontal)"; + "json;JSON (JavaScript Object Notation);"; opt.format->answer = "plain"; opt.format->guisection = _("Format"); @@ -133,20 +128,6 @@ int main(int argc, char *argv[]) opt.fsep->answer = NULL; opt.fsep->guisection = _("Format"); - opt.vsep = G_define_standard_option(G_OPT_F_SEP); - opt.vsep->key = "vertical_separator"; - opt.vsep->label = _("Output vertical record separator"); - opt.vsep->answer = NULL; - opt.vsep->guisection = _("Format"); - - opt.nullval = G_define_standard_option(G_OPT_M_NULL_VALUE); - opt.nullval->guisection = _("Format"); - - opt.escape = G_define_flag(); - opt.escape->key = 'e'; - opt.escape->description = _("Escape newline and backslash characters"); - opt.escape->guisection = _("Format"); - opt.list = G_define_flag(); opt.list->key = 'l'; opt.list->description = @@ -190,25 +171,13 @@ int main(int argc, char *argv[]) } } - if (strcmp(opt.format->answer, "csv") == 0) - format = CSV; - else if (strcmp(opt.format->answer, "json") == 0) + if (strcmp(opt.format->answer, "json") == 0) format = JSON; - else if (strcmp(opt.format->answer, "vertical") == 0) - format = VERTICAL; else format = PLAIN; if (format == JSON) { - fatal_error_option_value_excludes_flag(opt.format, opt.escape, - _("Escaping is based on the format")); fatal_error_option_value_excludes_option(opt.format, opt.fsep, _("Separator is part of the format")); - fatal_error_option_value_excludes_option(opt.format, opt.nullval, - _("Null value is part of the format")); - } - if (format != VERTICAL) { - fatal_error_option_value_excludes_option(opt.format, opt.vsep, - _("Only vertical output can use vertical separator")); } /* the field separator */ @@ -217,24 +186,13 @@ int main(int argc, char *argv[]) } else { /* A different separator is needed to for each format and output. */ - if (format == CSV) { - fsep = G_store(","); - } - else if (format == PLAIN) { + if (format == PLAIN) { fsep = G_store("|"); } else fsep = NULL; /* Something like a separator is part of the format. */ } - if (opt.vsep->answer) - vsep = G_option_to_separator(opt.vsep); - else - vsep = G_store("\n"); - vsep_needs_newline = true; - if (vsep && !strcmp(vsep, "\n")) - vsep_needs_newline = false; - /* list available mapsets */ if (opt.list->answer) { if (opt.print->answer) @@ -247,10 +205,6 @@ int main(int argc, char *argv[]) if (format == JSON) { list_avaliable_mapsets_json((const char **)mapset_name, nmapsets); } - else if (format == VERTICAL) { - list_avaliable_mapsets_vertical((const char **)mapset_name, - nmapsets, vsep); - } else { list_available_mapsets((const char **)mapset_name, nmapsets, fsep); diff --git a/general/g.mapsets/tests/conftest.py b/general/g.mapsets/tests/conftest.py index ba25c2137a4..cd8ed11c690 100644 --- a/general/g.mapsets/tests/conftest.py +++ b/general/g.mapsets/tests/conftest.py @@ -5,11 +5,11 @@ Fixture for ReprojectionRenderer test with simple GRASS location, raster, vector. """ -from types import SimpleNamespace -import pytest +from types import SimpleNamespace import grass.script as gs +import pytest TEST_MAPSETS = ["PERMANENT", "test1", "test2", "test3"] diff --git a/general/g.mapsets/tests/test_g_mapsets_list_format.py b/general/g.mapsets/tests/test_g_mapsets_list_format.py index 649bd7d6af6..cf5f900c28d 100644 --- a/general/g.mapsets/tests/test_g_mapsets_list_format.py +++ b/general/g.mapsets/tests/test_g_mapsets_list_format.py @@ -14,47 +14,56 @@ """Test parsing and structure of CSV and JSON outputs from g.mapsets""" import json +import pytest import grass.script as gs -def check_separators(format, mapsets): - SEPARATORS = ["newline", "space", "comma", "tab", "pipe", None] - - for sep in SEPARATORS: - text = gs.read_command("g.mapsets", format=format, separator=sep, flags="l") - if sep == "newline": - assert text == "\n".join(mapsets) + "\n" - elif sep == "space": - assert text == " ".join(mapsets) + "\n" - elif sep == "comma": - assert text == ",".join(mapsets) + "\n" - elif sep == "tab": - assert text == "\t".join(mapsets) + "\n" - elif sep == "pipe": - assert text == "|".join(mapsets) + "\n" +@pytest.mark.parametrize( + "separator", ["newline", "space", "comma", "tab", "pipe", ",", None] +) +def test_plain_output(simple_dataset, separator): + """Test that the separators are properly applied""" + mapsets = simple_dataset.mapsets + text = gs.read_command("g.mapsets", format="plain", separator=separator, flags="l") + + def _check_parsed_list(text, sep): + """Asserts to run on for each separator""" + parsed_list = text.splitlines() + + # Make sure new line conditions are handled correctly + if sep != "\n": + parsed_list = text.split(sep) + assert parsed_list[-1] == "test3\n" else: - # Default vallue - assert text == "|".join(mapsets) + "\n" + assert parsed_list[-1] == "test3" + assert len(parsed_list) == 4 + assert parsed_list[0] == "PERMANENT" + assert text == sep.join(mapsets) + "\n" -def test_plain_output(simple_dataset): - """Test that the separators are properly applied""" - check_separators("plain", simple_dataset.mapsets) + if separator == "newline": + _check_parsed_list(text, "\n") + elif separator == "space": + _check_parsed_list(text, " ") + elif separator == "comma": + _check_parsed_list(text, ",") + elif separator == "tab": + assert text == "\t".join(mapsets) + "\n" + elif separator == "pipe": + assert text == "|".join(mapsets) + "\n" + elif separator == ",": + assert text == ",".join(mapsets) + "\n" + else: + # Default vallue + assert text == "|".join(mapsets) + "\n" def test_json_ouput(simple_dataset): """JSON format""" text = gs.read_command("g.mapsets", format="json", flags="l") - print(f"Text JSON: {text}") data = json.loads(text) assert list(data.keys()) == ["mapsets"] assert isinstance(data["mapsets"], list) assert len(data["mapsets"]) == 4 for mapset in simple_dataset.mapsets: assert mapset in data["mapsets"] - - -def test_csv_output(simple_dataset): - """CSV format""" - text = gs.read_command("g.mapsets", format="csv", flags="l") - assert text == ",".join(simple_dataset.mapsets) + "\n" From 81739650d4d9a8dc7316a537151798b68ef6a680 Mon Sep 17 00:00:00 2001 From: Corey White Date: Sun, 28 Aug 2022 09:59:08 -0400 Subject: [PATCH 08/26] Added print flag to json output and added tests --- general/g.mapsets/list.c | 18 +++++++- general/g.mapsets/local_proto.h | 1 + general/g.mapsets/main.c | 8 +++- general/g.mapsets/tests/conftest.py | 5 ++- .../tests/test_g_mapsets_list_format.py | 41 ++++++++++++++++--- 5 files changed, 63 insertions(+), 10 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index caa935c33c4..491c0f1f362 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -35,7 +35,7 @@ void list_accessible_mapsets(const char *fs) const char *name; G_message(_("Accessible mapsets:")); - + for (n = 0; (name = G_get_mapset_name(n)); n++) { /* match each mapset to its numeric equivalent */ fprintf(stdout, "%s", name); @@ -55,6 +55,21 @@ void list_accessible_mapsets(const char *fs) fprintf(stdout, "\n"); } +void list_accessible_mapsets_json(const char *fs) +{ + int n; + const char *name; + + fprintf(stdout, "{\"mapsets\": ["); + for (n = 0; (name = G_get_mapset_name(n)); n++) { + fprintf(stdout, "\"%s\"", name); + if (G_get_mapset_name(n + 1)) { + fprintf(stdout, ","); + } + } + fprintf(stdout, "]}\n"); +} + void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) { int n; @@ -67,5 +82,4 @@ void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) } } fprintf(stdout, "]}\n"); - } diff --git a/general/g.mapsets/local_proto.h b/general/g.mapsets/local_proto.h index 56c7a81fafe..f5bd1e3577e 100644 --- a/general/g.mapsets/local_proto.h +++ b/general/g.mapsets/local_proto.h @@ -6,3 +6,4 @@ const char *substitute_mapset(const char *); void list_available_mapsets(const char **, int, const char *); void list_accessible_mapsets(const char *); void list_avaliable_mapsets_json(const char **, int); +void list_accessible_mapsets_json(const char *); diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 8297e5a233c..7c6ec92ce7a 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -218,7 +218,13 @@ int main(int argc, char *argv[]) G_warning(_("Flag -%c ignored"), opt.dialog->key); if (opt.mapset->answer) G_warning(_("Option <%s> ignored"), opt.mapset->key); - list_accessible_mapsets(fsep); + if (format == JSON) { + list_accessible_mapsets_json(fsep); + } + else { + list_accessible_mapsets(fsep); + } + exit(EXIT_SUCCESS); } diff --git a/general/g.mapsets/tests/conftest.py b/general/g.mapsets/tests/conftest.py index cd8ed11c690..ca58228607c 100644 --- a/general/g.mapsets/tests/conftest.py +++ b/general/g.mapsets/tests/conftest.py @@ -12,6 +12,7 @@ import pytest TEST_MAPSETS = ["PERMANENT", "test1", "test2", "test3"] +ACCESSIBLE_MAPSETS = ["test3", "PERMANENT"] @pytest.fixture(scope="module") @@ -29,4 +30,6 @@ def simple_dataset(tmp_path_factory): for mapset in TEST_MAPSETS: gs.run_command("g.mapset", location=location, mapset=mapset, flags="c") - yield SimpleNamespace(mapsets=TEST_MAPSETS) + yield SimpleNamespace( + mapsets=TEST_MAPSETS, accessible_mapsets=ACCESSIBLE_MAPSETS + ) diff --git a/general/g.mapsets/tests/test_g_mapsets_list_format.py b/general/g.mapsets/tests/test_g_mapsets_list_format.py index cf5f900c28d..e1c58fe1ac9 100644 --- a/general/g.mapsets/tests/test_g_mapsets_list_format.py +++ b/general/g.mapsets/tests/test_g_mapsets_list_format.py @@ -18,13 +18,19 @@ import grass.script as gs +@pytest.mark.parametrize("flag", ["p", "l", "lp"]) @pytest.mark.parametrize( "separator", ["newline", "space", "comma", "tab", "pipe", ",", None] ) -def test_plain_output(simple_dataset, separator): +def test_plain_output(simple_dataset, separator, flag): """Test that the separators are properly applied""" mapsets = simple_dataset.mapsets - text = gs.read_command("g.mapsets", format="plain", separator=separator, flags="l") + mapsets_len = len(mapsets) + if flag == "p": + mapsets = simple_dataset.accessible_mapsets + mapsets_len = len(mapsets) + + text = gs.read_command("g.mapsets", format="plain", separator=separator, flags=flag) def _check_parsed_list(text, sep): """Asserts to run on for each separator""" @@ -33,12 +39,24 @@ def _check_parsed_list(text, sep): # Make sure new line conditions are handled correctly if sep != "\n": parsed_list = text.split(sep) - assert parsed_list[-1] == "test3\n" + if flag == "l": + assert parsed_list[-1] == "test3\n" + if flag == "p": + assert parsed_list[-1] == "PERMANENT\n" else: - assert parsed_list[-1] == "test3" + if flag == "l": + assert parsed_list[-1] == "test3" + if flag == "p": + assert parsed_list[-1] == "PERMANENT" + + # Check the beginning of list is correct + if flag == "p": + assert parsed_list[0] == "test3" + + if flag == "l": + assert parsed_list[0] == "PERMANENT" - assert len(parsed_list) == 4 - assert parsed_list[0] == "PERMANENT" + assert len(parsed_list) == mapsets_len assert text == sep.join(mapsets) + "\n" if separator == "newline": @@ -67,3 +85,14 @@ def test_json_ouput(simple_dataset): assert len(data["mapsets"]) == 4 for mapset in simple_dataset.mapsets: assert mapset in data["mapsets"] + + +def test_accessible_mapsets_json_ouput(simple_dataset): + """JSON format""" + text = gs.read_command("g.mapsets", format="json", flags="p") + data = json.loads(text) + assert list(data.keys()) == ["mapsets"] + assert isinstance(data["mapsets"], list) + assert len(data["mapsets"]) == 2 + for mapset in simple_dataset.accessible_mapsets: + assert mapset in data["mapsets"] From 34dd4359e2c10a3193af59c17ee0cd6beaedf7ac Mon Sep 17 00:00:00 2001 From: Corey White Date: Tue, 30 Aug 2022 22:21:31 -0400 Subject: [PATCH 09/26] Simplified tests --- .../tests/test_g_mapsets_list_format.py | 73 ++++++------------- 1 file changed, 21 insertions(+), 52 deletions(-) diff --git a/general/g.mapsets/tests/test_g_mapsets_list_format.py b/general/g.mapsets/tests/test_g_mapsets_list_format.py index e1c58fe1ac9..07d6cd06b00 100644 --- a/general/g.mapsets/tests/test_g_mapsets_list_format.py +++ b/general/g.mapsets/tests/test_g_mapsets_list_format.py @@ -16,67 +16,36 @@ import json import pytest import grass.script as gs +from grass.script import utils as gutils +SEPARATORS = ["newline", "space", "comma", "tab", "pipe", ","] -@pytest.mark.parametrize("flag", ["p", "l", "lp"]) -@pytest.mark.parametrize( - "separator", ["newline", "space", "comma", "tab", "pipe", ",", None] -) -def test_plain_output(simple_dataset, separator, flag): - """Test that the separators are properly applied""" - mapsets = simple_dataset.mapsets - mapsets_len = len(mapsets) - if flag == "p": - mapsets = simple_dataset.accessible_mapsets - mapsets_len = len(mapsets) - - text = gs.read_command("g.mapsets", format="plain", separator=separator, flags=flag) - def _check_parsed_list(text, sep): - """Asserts to run on for each separator""" - parsed_list = text.splitlines() +def _check_parsed_list(mapsets, text, sep="|"): + """Asserts to run on for each separator""" + parsed_list = text.splitlines() if sep == "\n" else text.split(sep) + mapsets_len = len(mapsets) - # Make sure new line conditions are handled correctly - if sep != "\n": - parsed_list = text.split(sep) - if flag == "l": - assert parsed_list[-1] == "test3\n" - if flag == "p": - assert parsed_list[-1] == "PERMANENT\n" - else: - if flag == "l": - assert parsed_list[-1] == "test3" - if flag == "p": - assert parsed_list[-1] == "PERMANENT" + assert len(parsed_list) == mapsets_len + assert text == sep.join(mapsets) + "\n" - # Check the beginning of list is correct - if flag == "p": - assert parsed_list[0] == "test3" - if flag == "l": - assert parsed_list[0] == "PERMANENT" +@pytest.mark.parametrize("separator", SEPARATORS) +def test_plain_list_output(simple_dataset, separator): + """Test that the separators are properly applied with list flag""" + mapsets = simple_dataset.mapsets + text = gs.read_command("g.mapsets", format="plain", separator=separator, flags="l") + _check_parsed_list(mapsets, text, gutils.separator(separator)) - assert len(parsed_list) == mapsets_len - assert text == sep.join(mapsets) + "\n" - if separator == "newline": - _check_parsed_list(text, "\n") - elif separator == "space": - _check_parsed_list(text, " ") - elif separator == "comma": - _check_parsed_list(text, ",") - elif separator == "tab": - assert text == "\t".join(mapsets) + "\n" - elif separator == "pipe": - assert text == "|".join(mapsets) + "\n" - elif separator == ",": - assert text == ",".join(mapsets) + "\n" - else: - # Default vallue - assert text == "|".join(mapsets) + "\n" +def test_plain_print_output(simple_dataset, separator): + """Test that the separators are properly applied with print flag""" + mapsets = simple_dataset.accessible_mapsets + text = gs.read_command("g.mapsets", format="plain", separator=separator, flags="p") + _check_parsed_list(mapsets, text, gutils.separator(separator)) -def test_json_ouput(simple_dataset): +def test_json_list_ouput(simple_dataset): """JSON format""" text = gs.read_command("g.mapsets", format="json", flags="l") data = json.loads(text) @@ -87,7 +56,7 @@ def test_json_ouput(simple_dataset): assert mapset in data["mapsets"] -def test_accessible_mapsets_json_ouput(simple_dataset): +def test_json_print_ouput(simple_dataset): """JSON format""" text = gs.read_command("g.mapsets", format="json", flags="p") data = json.loads(text) From e5e834cc4d32e73c3367c566f68a202c757a0831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edouard=20Choini=C3=A8re?= <27212526+echoix@users.noreply.github.com> Date: Thu, 21 Mar 2024 18:29:23 -0400 Subject: [PATCH 10/26] Apply clang format suggestions Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- general/g.mapsets/main.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 2a0af37ecff..3437f980d44 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -34,11 +34,7 @@ #define OP_ADD 2 #define OP_REM 3 -enum OutputFormat -{ - PLAIN, - JSON -}; +enum OutputFormat { PLAIN, JSON }; void fatal_error_option_value_excludes_flag(struct Option *option, struct Flag *excluded, @@ -79,8 +75,7 @@ int main(int argc, char *argv[]) int nmapsets; struct GModule *module; - struct _opt - { + struct _opt { struct Option *mapset, *op, *format, *fsep; struct Flag *print, *list, *dialog; } opt; @@ -116,9 +111,8 @@ int main(int argc, char *argv[]) opt.format->required = YES; opt.format->label = _("Output format for printing (-l and -p flags)"); opt.format->options = "plain,json"; - opt.format->descriptions = - "plain;Configurable plain text output;" - "json;JSON (JavaScript Object Notation);"; + opt.format->descriptions = "plain;Configurable plain text output;" + "json;JSON (JavaScript Object Notation);"; opt.format->answer = "plain"; opt.format->guisection = _("Format"); @@ -174,8 +168,8 @@ int main(int argc, char *argv[]) else format = PLAIN; if (format == JSON) { - fatal_error_option_value_excludes_option(opt.format, opt.fsep, - _("Separator is part of the format")); + fatal_error_option_value_excludes_option( + opt.format, opt.fsep, _("Separator is part of the format")); } /* the field separator */ @@ -188,7 +182,7 @@ int main(int argc, char *argv[]) fsep = G_store("|"); } else - fsep = NULL; /* Something like a separator is part of the format. */ + fsep = NULL; /* Something like a separator is part of the format. */ } /* list available mapsets */ @@ -204,8 +198,7 @@ int main(int argc, char *argv[]) list_avaliable_mapsets_json((const char **)mapset_name, nmapsets); } else { - list_available_mapsets((const char **)mapset_name, nmapsets, - fsep); + list_available_mapsets((const char **)mapset_name, nmapsets, fsep); } exit(EXIT_SUCCESS); From fb21b77fbf936509cb6d8e2c98e96f7f06ef5cf0 Mon Sep 17 00:00:00 2001 From: Corey White Date: Thu, 4 Apr 2024 17:28:50 -0400 Subject: [PATCH 11/26] Updated code to use parson and fixed tests --- general/g.mapsets/Makefile | 2 +- general/g.mapsets/list.c | 84 ++++++++++++++++--- ...ormat.py => g_mapsets_list_format_test.py} | 1 + 3 files changed, 74 insertions(+), 13 deletions(-) rename general/g.mapsets/tests/{test_g_mapsets_list_format.py => g_mapsets_list_format_test.py} (98%) diff --git a/general/g.mapsets/Makefile b/general/g.mapsets/Makefile index 016bbd6cc05..6672dda2804 100644 --- a/general/g.mapsets/Makefile +++ b/general/g.mapsets/Makefile @@ -3,7 +3,7 @@ MODULE_TOPDIR = ../.. PGM = g.mapsets -LIBES = $(GISLIB) +LIBES = $(PARSONLIB) $(GISLIB) DEPENDENCIES = $(GISDEP) include $(MODULE_TOPDIR)/include/Make/Module.make diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 491c0f1f362..927d3b38d1e 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -3,6 +3,7 @@ #include #include #include "local_proto.h" +#include void list_available_mapsets(const char **mapset_name, int nmapsets, const char *fs) @@ -59,27 +60,86 @@ void list_accessible_mapsets_json(const char *fs) { int n; const char *name; + char *serialized_string = NULL; + JSON_Value *root_value = NULL; + JSON_Object *root_object; + JSON_Array *root_array, *mapsets; - fprintf(stdout, "{\"mapsets\": ["); + // Create root json object + root_value = json_value_init_object(); + root_object = json_value_get_object(root_value); + + // Create mapsets array + root_array = json_value_init_array(); + json_object_set_value(root_object, "mapsets", root_array); + mapsets = json_object_get_array(root_object, "mapsets"); + + // Check that memory was allocated to root json object + if (root_value == NULL) { + G_fatal_error(_("Failed to initialize JSON. Out of memory?")); + } + + // Check that memory was allocated to mapsets array + if (mapsets == NULL) { + G_fatal_error(_("Failed to initialize JSON array. Out of memory?")); + } + + // Add mapsets to mapsets array for (n = 0; (name = G_get_mapset_name(n)); n++) { - fprintf(stdout, "\"%s\"", name); - if (G_get_mapset_name(n + 1)) { - fprintf(stdout, ","); - } + // Append mapset name to mapsets array + json_array_append_string(mapsets, name); } - fprintf(stdout, "]}\n"); + + // Add mapsets array to root object + json_object_set_value(root_object, "mapsets", mapsets); + + // Serialize root object to string and print it to stdout + serialized_string = json_serialize_to_string_pretty(root_value); + puts(serialized_string); + + // Free memory + json_free_serialized_string(serialized_string); + json_value_free(root_value); } void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) { int n; + char *serialized_string = NULL; + JSON_Value *root_value = NULL; + JSON_Object *root_object; + JSON_Array *root_array, *mapsets; - fprintf(stdout, "{\"mapsets\": ["); + root_value = json_value_init_object(); + root_object = json_value_get_object(root_value); + + // Create mapsets array + root_array = json_value_init_array(); + json_object_set_value(root_object, "mapsets", root_array); + mapsets = json_object_get_array(root_object, "mapsets"); + + // Check that memory was allocated to root json object + if (root_value == NULL) { + G_fatal_error(_("Failed to initialize JSON. Out of memory?")); + } + + if (mapsets == NULL) { + G_fatal_error(_("Failed to initialize JSON array. Out of memory?")); + } + + // Append mapsets to mapsets array for (n = 0; n < nmapsets; n++) { - fprintf(stdout, "\"%s\"", mapset_name[n]); - if (n < nmapsets - 1) { - fprintf(stdout, ","); - } + json_array_append_string(mapsets, mapset_name[n]); } - fprintf(stdout, "]}\n"); + + // Add mapsets array to root object + json_object_set_value(root_object, "mapsets", mapsets); + + // Serialize root object to string and print it to stdout + serialized_string = json_serialize_to_string_pretty(root_value); + puts(serialized_string); + + // Free memory + json_free_serialized_string(serialized_string); + json_value_free(root_value); } diff --git a/general/g.mapsets/tests/test_g_mapsets_list_format.py b/general/g.mapsets/tests/g_mapsets_list_format_test.py similarity index 98% rename from general/g.mapsets/tests/test_g_mapsets_list_format.py rename to general/g.mapsets/tests/g_mapsets_list_format_test.py index 07d6cd06b00..79555085bb0 100644 --- a/general/g.mapsets/tests/test_g_mapsets_list_format.py +++ b/general/g.mapsets/tests/g_mapsets_list_format_test.py @@ -38,6 +38,7 @@ def test_plain_list_output(simple_dataset, separator): _check_parsed_list(mapsets, text, gutils.separator(separator)) +@pytest.mark.parametrize("separator", SEPARATORS) def test_plain_print_output(simple_dataset, separator): """Test that the separators are properly applied with print flag""" mapsets = simple_dataset.accessible_mapsets From 76dbf30c4c3a73be4f2c65b472c10f5e4048f8ef Mon Sep 17 00:00:00 2001 From: Corey White Date: Thu, 4 Apr 2024 17:40:50 -0400 Subject: [PATCH 12/26] Updated docs --- general/g.mapsets/g.mapsets.html | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/general/g.mapsets/g.mapsets.html b/general/g.mapsets/g.mapsets.html index d1e10adbe2d..cd04a944dae 100644 --- a/general/g.mapsets/g.mapsets.html +++ b/general/g.mapsets/g.mapsets.html @@ -118,6 +118,22 @@

Print available mapsets

PERMANENT user1 user2 +Mapsets can be also printed out as json by setting the format option to "json" (format="json"). + +
+
+    g.mapsets format="json" -l
+
+    {
+      "mapsets": [
+        "PERMANENT",
+        "user1",
+        "user2"
+      ]
+    }
+  
+
+

Add new mapset

Add mapset 'user2' to the current mapset search path From 4e6b53b1862c00496a923def56d52c30a2004cb7 Mon Sep 17 00:00:00 2001 From: Corey White Date: Thu, 4 Apr 2024 18:20:40 -0400 Subject: [PATCH 13/26] Fixed mapsets array initalization issue --- general/g.mapsets/list.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 927d3b38d1e..8a3b08c68f4 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -62,16 +62,14 @@ void list_accessible_mapsets_json(const char *fs) const char *name; char *serialized_string = NULL; JSON_Value *root_value = NULL; - JSON_Object *root_object; - JSON_Array *root_array, *mapsets; + JSON_Object *root_object = NULL; + JSON_Array *mapsets = NULL; - // Create root json object root_value = json_value_init_object(); root_object = json_value_get_object(root_value); // Create mapsets array - root_array = json_value_init_array(); - json_object_set_value(root_object, "mapsets", root_array); + json_object_set_value(root_object, "mapsets", json_value_init_array()); mapsets = json_object_get_array(root_object, "mapsets"); // Check that memory was allocated to root json object @@ -107,15 +105,14 @@ void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) int n; char *serialized_string = NULL; JSON_Value *root_value = NULL; - JSON_Object *root_object; - JSON_Array *root_array, *mapsets; + JSON_Object *root_object = NULL; + JSON_Array *mapsets = NULL; root_value = json_value_init_object(); root_object = json_value_get_object(root_value); // Create mapsets array - root_array = json_value_init_array(); - json_object_set_value(root_object, "mapsets", root_array); + json_object_set_value(root_object, "mapsets", json_value_init_array()); mapsets = json_object_get_array(root_object, "mapsets"); // Check that memory was allocated to root json object From 816358127141059c08524b01dd39bf52b739647d Mon Sep 17 00:00:00 2001 From: Corey White Date: Thu, 4 Apr 2024 18:41:07 -0400 Subject: [PATCH 14/26] Fixed bug setting JSON_ARRAY --- general/g.mapsets/list.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 8a3b08c68f4..003f201da93 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -68,7 +68,7 @@ void list_accessible_mapsets_json(const char *fs) root_value = json_value_init_object(); root_object = json_value_get_object(root_value); - // Create mapsets array + // Create and add mapsets array to root object json_object_set_value(root_object, "mapsets", json_value_init_array()); mapsets = json_object_get_array(root_object, "mapsets"); @@ -88,9 +88,6 @@ void list_accessible_mapsets_json(const char *fs) json_array_append_string(mapsets, name); } - // Add mapsets array to root object - json_object_set_value(root_object, "mapsets", mapsets); - // Serialize root object to string and print it to stdout serialized_string = json_serialize_to_string_pretty(root_value); puts(serialized_string); @@ -129,9 +126,6 @@ void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) json_array_append_string(mapsets, mapset_name[n]); } - // Add mapsets array to root object - json_object_set_value(root_object, "mapsets", mapsets); - // Serialize root object to string and print it to stdout serialized_string = json_serialize_to_string_pretty(root_value); puts(serialized_string); From bdceb3daf6bf2e1610a2fcbb0ea1e4484ba65bb3 Mon Sep 17 00:00:00 2001 From: Corey White Date: Thu, 4 Apr 2024 18:58:33 -0400 Subject: [PATCH 15/26] Removed unused parameter --- general/g.mapsets/list.c | 2 +- general/g.mapsets/local_proto.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 003f201da93..7e6f61ce680 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -56,7 +56,7 @@ void list_accessible_mapsets(const char *fs) fprintf(stdout, "\n"); } -void list_accessible_mapsets_json(const char *fs) +void list_accessible_mapsets_json() { int n; const char *name; diff --git a/general/g.mapsets/local_proto.h b/general/g.mapsets/local_proto.h index f5bd1e3577e..5a050b0aedb 100644 --- a/general/g.mapsets/local_proto.h +++ b/general/g.mapsets/local_proto.h @@ -6,4 +6,4 @@ const char *substitute_mapset(const char *); void list_available_mapsets(const char **, int, const char *); void list_accessible_mapsets(const char *); void list_avaliable_mapsets_json(const char **, int); -void list_accessible_mapsets_json(const char *); +void list_accessible_mapsets_json(); From db0252ea24c19054a5f4d05ad55525b0a382493d Mon Sep 17 00:00:00 2001 From: Corey White Date: Fri, 5 Apr 2024 12:39:37 -0400 Subject: [PATCH 16/26] Update general/g.mapsets/main.c Fixed typo. Co-authored-by: Anna Petrasova --- general/g.mapsets/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 3437f980d44..c4f2e8b61d7 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -169,7 +169,7 @@ int main(int argc, char *argv[]) format = PLAIN; if (format == JSON) { fatal_error_option_value_excludes_option( - opt.format, opt.fsep, _("Separator is part of the format")); + opt.format, opt.fsep, _("Separator is part of the format.")); } /* the field separator */ From 6c18a501b3c8af05b155478becf6bc0538dc6e84 Mon Sep 17 00:00:00 2001 From: Corey White Date: Fri, 5 Apr 2024 12:52:44 -0400 Subject: [PATCH 17/26] Updated default separator to space --- general/g.mapsets/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index c4f2e8b61d7..df134f693e3 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -12,7 +12,7 @@ * Huidae Cho , * Corey White * PURPOSE: set current mapset path - * COPYRIGHT: (C) 1994-2009, 2012-2022 by the GRASS Development Team + * COPYRIGHT: (C) 1994-2009, 2012-2024 by the GRASS Development Team * * This program is free software under the GNU General * Public License (>=v2). Read the file COPYING that @@ -179,7 +179,7 @@ int main(int argc, char *argv[]) else { /* A different separator is needed to for each format and output. */ if (format == PLAIN) { - fsep = G_store("|"); + fsep = G_store("space"); } else fsep = NULL; /* Something like a separator is part of the format. */ From 8e99fec1abc7820e882e6d142bcbd2dfa5186575 Mon Sep 17 00:00:00 2001 From: Corey White Date: Sun, 7 Apr 2024 14:57:55 -0400 Subject: [PATCH 18/26] Update general/g.mapsets/main.c Switch GUI section to Print Co-authored-by: Anna Petrasova --- general/g.mapsets/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index df134f693e3..039100702ef 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -114,11 +114,11 @@ int main(int argc, char *argv[]) opt.format->descriptions = "plain;Configurable plain text output;" "json;JSON (JavaScript Object Notation);"; opt.format->answer = "plain"; - opt.format->guisection = _("Format"); + opt.format->guisection = _("Print"); opt.fsep = G_define_standard_option(G_OPT_F_SEP); opt.fsep->answer = NULL; - opt.fsep->guisection = _("Format"); + opt.fsep->guisection = _("Print"); opt.list = G_define_flag(); opt.list->key = 'l'; From 8961692ca9eea0f40d3f26c4bd01b5e07baf85d2 Mon Sep 17 00:00:00 2001 From: Corey White Date: Sun, 7 Apr 2024 14:58:49 -0400 Subject: [PATCH 19/26] Update general/g.mapsets/main.c Co-authored-by: Anna Petrasova --- general/g.mapsets/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 039100702ef..9786904b86f 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -179,7 +179,7 @@ int main(int argc, char *argv[]) else { /* A different separator is needed to for each format and output. */ if (format == PLAIN) { - fsep = G_store("space"); + fsep = G_store(" "); } else fsep = NULL; /* Something like a separator is part of the format. */ From 06d04a6b328ae922336f93cdf46fca9a8206feba Mon Sep 17 00:00:00 2001 From: Corey White Date: Sun, 7 Apr 2024 14:59:47 -0400 Subject: [PATCH 20/26] Update general/g.mapsets/main.c Co-authored-by: Anna Petrasova --- general/g.mapsets/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/general/g.mapsets/main.c b/general/g.mapsets/main.c index 9786904b86f..55c8c81f646 100644 --- a/general/g.mapsets/main.c +++ b/general/g.mapsets/main.c @@ -210,7 +210,7 @@ int main(int argc, char *argv[]) if (opt.mapset->answer) G_warning(_("Option <%s> ignored"), opt.mapset->key); if (format == JSON) { - list_accessible_mapsets_json(fsep); + list_accessible_mapsets_json(); } else { list_accessible_mapsets(fsep); From ace2374dc925fbd0c183a1447eecbddafc4bebcd Mon Sep 17 00:00:00 2001 From: Corey White Date: Sun, 7 Apr 2024 15:08:19 -0400 Subject: [PATCH 21/26] Removed unneeded logic --- general/g.mapsets/list.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 7e6f61ce680..9d73ae5f086 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -15,16 +15,7 @@ void list_available_mapsets(const char **mapset_name, int nmapsets, for (n = 0; n < nmapsets; n++) { fprintf(stdout, "%s", mapset_name[n]); if (n < nmapsets - 1) { - if (strcmp(fs, "newline") == 0) - fprintf(stdout, "\n"); - else if (strcmp(fs, "space") == 0) - fprintf(stdout, " "); - else if (strcmp(fs, "comma") == 0) - fprintf(stdout, ","); - else if (strcmp(fs, "tab") == 0) - fprintf(stdout, "\t"); - else - fprintf(stdout, "%s", fs); + fprintf(stdout, "%s", fs); } } fprintf(stdout, "\n"); @@ -41,16 +32,7 @@ void list_accessible_mapsets(const char *fs) /* match each mapset to its numeric equivalent */ fprintf(stdout, "%s", name); if (G_get_mapset_name(n + 1)) { - if (strcmp(fs, "newline") == 0) - fprintf(stdout, "\n"); - else if (strcmp(fs, "space") == 0) - fprintf(stdout, " "); - else if (strcmp(fs, "comma") == 0) - fprintf(stdout, ","); - else if (strcmp(fs, "tab") == 0) - fprintf(stdout, "\t"); - else - fprintf(stdout, "%s", fs); + fprintf(stdout, "%s", fs); } } fprintf(stdout, "\n"); From 26f47c32abdba101cf7efe04ce99b6ce056fab60 Mon Sep 17 00:00:00 2001 From: Corey White Date: Mon, 8 Apr 2024 17:49:04 -0400 Subject: [PATCH 22/26] Update general/g.mapsets/list.c Co-authored-by: Nicklas Larsson --- general/g.mapsets/list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 9d73ae5f086..a66c1cc2461 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -55,7 +55,7 @@ void list_accessible_mapsets_json() mapsets = json_object_get_array(root_object, "mapsets"); // Check that memory was allocated to root json object - if (root_value == NULL) { + if (root_value == NULL || mapsets == NULL) { G_fatal_error(_("Failed to initialize JSON. Out of memory?")); } From e7f815afe13ecee3f2c7786e483e2effb72e43ef Mon Sep 17 00:00:00 2001 From: Corey White Date: Mon, 8 Apr 2024 17:52:55 -0400 Subject: [PATCH 23/26] Update general/g.mapsets/list.c Co-authored-by: Nicklas Larsson --- general/g.mapsets/list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index a66c1cc2461..5ab5ca3f2b2 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -65,7 +65,7 @@ void list_accessible_mapsets_json() } // Add mapsets to mapsets array - for (n = 0; (name = G_get_mapset_name(n)); n++) { + for (int n = 0; (name = G_get_mapset_name(n)); n++) { // Append mapset name to mapsets array json_array_append_string(mapsets, name); } From 4d0794c0526371f0dba6c861ffc84dfbcf6e95eb Mon Sep 17 00:00:00 2001 From: Corey White Date: Mon, 8 Apr 2024 18:01:44 -0400 Subject: [PATCH 24/26] Implmented suggestion from code review --- general/g.mapsets/list.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index 5ab5ca3f2b2..ba20b5867e1 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -8,11 +8,9 @@ void list_available_mapsets(const char **mapset_name, int nmapsets, const char *fs) { - int n; - G_message(_("Available mapsets:")); - for (n = 0; n < nmapsets; n++) { + for (int n = 0; n < nmapsets; n++) { fprintf(stdout, "%s", mapset_name[n]); if (n < nmapsets - 1) { fprintf(stdout, "%s", fs); @@ -23,12 +21,11 @@ void list_available_mapsets(const char **mapset_name, int nmapsets, void list_accessible_mapsets(const char *fs) { - int n; const char *name; G_message(_("Accessible mapsets:")); - for (n = 0; (name = G_get_mapset_name(n)); n++) { + for (int n = 0; (name = G_get_mapset_name(n)); n++) { /* match each mapset to its numeric equivalent */ fprintf(stdout, "%s", name); if (G_get_mapset_name(n + 1)) { @@ -40,7 +37,6 @@ void list_accessible_mapsets(const char *fs) void list_accessible_mapsets_json() { - int n; const char *name; char *serialized_string = NULL; JSON_Value *root_value = NULL; @@ -81,7 +77,6 @@ void list_accessible_mapsets_json() void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) { - int n; char *serialized_string = NULL; JSON_Value *root_value = NULL; JSON_Object *root_object = NULL; @@ -104,7 +99,7 @@ void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) } // Append mapsets to mapsets array - for (n = 0; n < nmapsets; n++) { + for (int n = 0; n < nmapsets; n++) { json_array_append_string(mapsets, mapset_name[n]); } From 6c8509a8628a93ab96d8f6500e5387343fd3f606 Mon Sep 17 00:00:00 2001 From: Corey White Date: Mon, 8 Apr 2024 18:04:03 -0400 Subject: [PATCH 25/26] Removed duplicate code --- general/g.mapsets/list.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index ba20b5867e1..ec278880702 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -50,16 +50,11 @@ void list_accessible_mapsets_json() json_object_set_value(root_object, "mapsets", json_value_init_array()); mapsets = json_object_get_array(root_object, "mapsets"); - // Check that memory was allocated to root json object + // Check that memory was allocated to root json object and array if (root_value == NULL || mapsets == NULL) { G_fatal_error(_("Failed to initialize JSON. Out of memory?")); } - // Check that memory was allocated to mapsets array - if (mapsets == NULL) { - G_fatal_error(_("Failed to initialize JSON array. Out of memory?")); - } - // Add mapsets to mapsets array for (int n = 0; (name = G_get_mapset_name(n)); n++) { // Append mapset name to mapsets array @@ -89,15 +84,11 @@ void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) json_object_set_value(root_object, "mapsets", json_value_init_array()); mapsets = json_object_get_array(root_object, "mapsets"); - // Check that memory was allocated to root json object - if (root_value == NULL) { + // Check that memory was allocated to root json object and array + if (root_value == NULL || mapsets == NULL) { G_fatal_error(_("Failed to initialize JSON. Out of memory?")); } - if (mapsets == NULL) { - G_fatal_error(_("Failed to initialize JSON array. Out of memory?")); - } - // Append mapsets to mapsets array for (int n = 0; n < nmapsets; n++) { json_array_append_string(mapsets, mapset_name[n]); From 4463bf1b52f7d918bc23e2702e14866e5a751bf8 Mon Sep 17 00:00:00 2001 From: Corey White Date: Wed, 10 Apr 2024 11:42:02 -0400 Subject: [PATCH 26/26] Refactored duplicate code and removed some comments --- general/g.mapsets/list.c | 97 +++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/general/g.mapsets/list.c b/general/g.mapsets/list.c index ec278880702..0bea28ddda8 100644 --- a/general/g.mapsets/list.c +++ b/general/g.mapsets/list.c @@ -5,6 +5,40 @@ #include "local_proto.h" #include +// Function to initialize a JSON object with a mapsets array +static JSON_Object *initialize_json_object() +{ + JSON_Value *root_value = json_value_init_object(); + if (!root_value) { + G_fatal_error(_("Failed to initialize JSON object. Out of memory?")); + } + + JSON_Object *root_object = json_value_get_object(root_value); + json_object_set_value(root_object, "mapsets", json_value_init_array()); + + JSON_Array *mapsets = json_object_get_array(root_object, "mapsets"); + if (!mapsets) { + json_value_free(root_value); + G_fatal_error(_("Failed to initialize mapsets array. Out of memory?")); + } + + return root_object; +} + +// Function to serialize and print JSON object +static void serialize_and_print_json_object(JSON_Value *root_value) +{ + char *serialized_string = json_serialize_to_string_pretty(root_value); + if (!serialized_string) { + json_value_free(root_value); + G_fatal_error(_("Failed to serialize JSON to pretty format.")); + } + + fprintf(stdout, "%s\n", serialized_string); + json_free_serialized_string(serialized_string); + json_value_free(root_value); +} + void list_available_mapsets(const char **mapset_name, int nmapsets, const char *fs) { @@ -35,70 +69,31 @@ void list_accessible_mapsets(const char *fs) fprintf(stdout, "\n"); } +// Lists all accessible mapsets in JSON format void list_accessible_mapsets_json() { const char *name; - char *serialized_string = NULL; - JSON_Value *root_value = NULL; - JSON_Object *root_object = NULL; - JSON_Array *mapsets = NULL; + JSON_Object *root_object = initialize_json_object(); + JSON_Array *mapsets = json_object_get_array(root_object, "mapsets"); - root_value = json_value_init_object(); - root_object = json_value_get_object(root_value); - - // Create and add mapsets array to root object - json_object_set_value(root_object, "mapsets", json_value_init_array()); - mapsets = json_object_get_array(root_object, "mapsets"); - - // Check that memory was allocated to root json object and array - if (root_value == NULL || mapsets == NULL) { - G_fatal_error(_("Failed to initialize JSON. Out of memory?")); - } - - // Add mapsets to mapsets array for (int n = 0; (name = G_get_mapset_name(n)); n++) { - // Append mapset name to mapsets array json_array_append_string(mapsets, name); } - // Serialize root object to string and print it to stdout - serialized_string = json_serialize_to_string_pretty(root_value); - puts(serialized_string); - - // Free memory - json_free_serialized_string(serialized_string); - json_value_free(root_value); + serialize_and_print_json_object( + json_object_get_wrapping_value(root_object)); } -void list_avaliable_mapsets_json(const char **mapset_name, int nmapsets) +// Lists available mapsets from a provided array in JSON format +void list_avaliable_mapsets_json(const char **mapset_names, int nmapsets) { - char *serialized_string = NULL; - JSON_Value *root_value = NULL; - JSON_Object *root_object = NULL; - JSON_Array *mapsets = NULL; + JSON_Object *root_object = initialize_json_object(); + JSON_Array *mapsets = json_object_get_array(root_object, "mapsets"); - root_value = json_value_init_object(); - root_object = json_value_get_object(root_value); - - // Create mapsets array - json_object_set_value(root_object, "mapsets", json_value_init_array()); - mapsets = json_object_get_array(root_object, "mapsets"); - - // Check that memory was allocated to root json object and array - if (root_value == NULL || mapsets == NULL) { - G_fatal_error(_("Failed to initialize JSON. Out of memory?")); - } - - // Append mapsets to mapsets array for (int n = 0; n < nmapsets; n++) { - json_array_append_string(mapsets, mapset_name[n]); + json_array_append_string(mapsets, mapset_names[n]); } - // Serialize root object to string and print it to stdout - serialized_string = json_serialize_to_string_pretty(root_value); - puts(serialized_string); - - // Free memory - json_free_serialized_string(serialized_string); - json_value_free(root_value); + serialize_and_print_json_object( + json_object_get_wrapping_value(root_object)); }