Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v.info: Add JSON output for history #4989

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions vector/v.info/local_proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#define SHELL_BASIC 0x02
#define SHELL_REGION 0x04
#define SHELL_TOPO 0x08
#define MAX_STR_LEN 1001

enum OutputFormat { PLAIN, SHELL, JSON };

Expand All @@ -24,3 +25,4 @@ void print_columns(struct Map_info *, const char *, const char *,
void print_info(struct Map_info *);
void print_shell(struct Map_info *, const char *, enum OutputFormat,
JSON_Object *);
void print_history(struct Map_info, enum OutputFormat);
7 changes: 1 addition & 6 deletions vector/v.info/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,7 @@ int main(int argc, char *argv[])

if (hist_flag || col_flag) {
if (hist_flag) {
char buf[1001];

Vect_hist_rewind(&Map);
while (Vect_hist_read(buf, 1000, &Map) != NULL) {
fprintf(stdout, "%s\n", buf);
}
print_history(Map, format);
}
else if (col_flag) {
print_columns(&Map, input_opt, field_opt, format);
Expand Down
81 changes: 81 additions & 0 deletions vector/v.info/print.c
Original file line number Diff line number Diff line change
Expand Up @@ -771,3 +771,84 @@ void print_info(struct Map_info *Map)
divider('+');
fprintf(stdout, "\n");
}

void print_history(struct Map_info Map, enum OutputFormat format)
{
char buf[MAX_STR_LEN];
char command[MAX_STR_LEN] = {0}, gisdbase[MAX_STR_LEN] = {0};
char location[MAX_STR_LEN] = {0}, mapset[MAX_STR_LEN] = {0};
char user[MAX_STR_LEN] = {0}, date[MAX_STR_LEN] = {0};
char mapset_path[3 * MAX_STR_LEN] = {0};

JSON_Value *root_value = NULL, *record_value = NULL;
JSON_Object *root_object = NULL;
JSON_Array *record_array = NULL;

if (format == JSON) {
root_value = json_value_init_object();
if (root_value == NULL) {
G_fatal_error(
_("Failed to initialize JSON object. Out of memory?"));
}
root_object = json_object(root_value);

record_value = json_value_init_array();
if (record_value == NULL) {
G_fatal_error(_("Failed to initialize JSON array. Out of memory?"));
}
record_array = json_array(record_value);
}

Vect_hist_rewind(&Map);
while (Vect_hist_read(buf, 1000, &Map) != NULL) {
NishantBansal2003 marked this conversation as resolved.
Show resolved Hide resolved
switch (format) {
case PLAIN:
case SHELL:
fprintf(stdout, "%s\n", buf);
break;
case JSON:
// Parse each line based on its prefix
if (strncmp(buf, "COMMAND:", 8) == 0) {
sscanf(buf, "COMMAND: %[^\n]", command);
}
else if (strncmp(buf, "GISDBASE:", 9) == 0) {
sscanf(buf, "GISDBASE: %[^\n]", gisdbase);
}
else if (strncmp(buf, "LOCATION:", 9) == 0) {
sscanf(buf, "LOCATION: %s MAPSET: %s USER: %s DATE: %[^\n]",
location, mapset, user, date);

JSON_Value *info_value = json_value_init_object();
if (info_value == NULL) {
G_fatal_error(
_("Failed to initialize JSON object. Out of memory?"));
}
JSON_Object *info_object = json_object(info_value);

json_object_set_string(info_object, "command", command);
snprintf(mapset_path, sizeof(mapset_path), "%s/%s/%s", gisdbase,
location, mapset);
json_object_set_string(info_object, "mapset_path", mapset_path);
json_object_set_string(info_object, "user", user);
json_object_set_string(info_object, "date", date);

json_array_append_value(record_array, info_value);
}
NishantBansal2003 marked this conversation as resolved.
Show resolved Hide resolved
break;
}
}

if (format == JSON) {
json_object_set_value(root_object, "records", record_value);

char *serialized_string = json_serialize_to_string_pretty(root_value);
if (!serialized_string) {
json_value_free(root_value);
G_fatal_error(_("Failed to initialize pretty JSON string."));
}
puts(serialized_string);

json_free_serialized_string(serialized_string);
json_value_free(root_value);
}
}
27 changes: 27 additions & 0 deletions vector/v.info/testsuite/test_vinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,33 @@ def test_json_column(self):

self.assertDictEqual(expected_json, result)

def test_json_histroy(self):
"""Test the v.info JSON output format with the history flag."""
module = SimpleModule(
"v.info", map=self.test_vinfo_with_db_3d, format="json", flags="h"
)
self.runModule(module)
result = json.loads(module.outputs.stdout)

expected_json = {
"records": [
{
"command": 'v.random -z output="test_vinfo_with_db_3d" npoints=5 layer="-1" zmin=0 zmax=100 column="elevation" column_type="double precision"'
}
]
}

# The following fields vary depending on the Grass sample data's path,
# date, and user. Therefore, only check for their presence in the JSON output
# and not for their exact values.
remove_fields = ["mapset_path", "date", "user"]
for record in result["records"]:
for field in remove_fields:
self.assertIn(field, record)
record.pop(field)

self.assertDictEqual(expected_json, result)

def test_database_table(self):
"""Test the database table column and type of the two vector maps with attribute data"""
self.assertModuleKeyValue(
Expand Down
Loading