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 14 commits into
base: main
Choose a base branch
from

Conversation

NishantBansal2003
Copy link
Contributor

Fixes: #4217
Use parson to add json output format support to the v.info module for history flag.
The JSON output looks like as follows:

$ grass --exec v.info -h map=roadsmajor format=json
{
    "records": [
        {
            "command": "v.in.ogr dsn=\"majorroads.shp\" output=\"roads_major\" min_area=0.0001 snap=-1",
            "mapset_path": "\/bigdata\/grassdata05\/wakestpfeet\/PERMANENT",
            "user": "helena",
            "date": "Tue Nov  7 18:34:20 2006"
        },
        {
            "command": "v.proj input=\"wroads_major\" location=\"wakestpfeet\" output=\"roadsmajor_wake\"",
            "mapset_path": "\/bigdata\/grassdata05\/ncfromfile\/PERMANENT",
            "user": "helena",
            "date": "Wed Nov  8 00:18:50 2006"
        },
        {
            "command": "v.db.connect -o map=\"roadsmajor@PERMANENT\" driver=\"sqlite\" database=\"\/home\/neteler\/grassdata\/nc_spm_latest\/nc_spm_08\/PERMANENT\/sqlite\/sqlite.db\" table=\"roadsmajor\" key=\"cat\" layer=\"1\" separator=\"|\"",
            "mapset_path": "\/home\/neteler\/grassdata\/nc_spm_latest\/nc_spm_08\/PERMANENT",
            "user": "neteler",
            "date": "Mon Nov 26 16:55:38 2012"
        },
        {
            "command": "v.db.connect -o map=\"roadsmajor@PERMANENT\" driver=\"sqlite\" database=\"$GISDBASE\/$LOCATION_NAME\/$MAPSET\/sqlite\/sqlite.db\" table=\"roadsmajor\" key=\"cat\" layer=\"1\" separator=\"|\"",
            "mapset_path": "\/home\/neteler\/grassdata\/nc_spm_08_grass7\/PERMANENT",
            "user": "neteler",
            "date": "Fri Dec  7 23:25:12 2012"
        }
    ]
}

@github-actions github-actions bot added vector Related to vector data processing Python Related code is in Python C Related code is in C module tests Related to Test Suite labels Jan 25, 2025
Signed-off-by: Nishant Bansal <[email protected]>
vector/v.info/print.c Outdated Show resolved Hide resolved
vector/v.info/print.c Outdated Show resolved Hide resolved
@NishantBansal2003
Copy link
Contributor Author

NishantBansal2003 commented Jan 27, 2025

Failing gunittest tests on the macOS build: FAILED ./scripts/g.extension/testsuite/test_addons_download.py (1 test failed). I am unsure why this test is failing.

Previously in the macOS CI, test_github_official_module_man_page_src_code_links_exists was failing.
Now, test_github_install is failing inside ./scripts/g.extension/testsuite/test_addons_download.py.

@neteler
Copy link
Member

neteler commented Jan 27, 2025

macOS: I have restarted this test.

And the OSGeo4W CI error is a bit unexpected:

checking whether to use PostgreSQL... "yes"
checking for location of PostgreSQL includes... /c/OSGeo4W/include
checking for libpq-fe.h... yes
checking for location of PostgreSQL library... /c/OSGeo4W/lib
checking for PQsetdbLogin in -lpq... no
checking for PQsetdbLogin in -lpq... no
checking for PQsetdbLogin in -lpq... no
checking for PQsetdbLogin in -lpq... no
configure: error: *** Unable to locate PostgreSQL library.

@nilason
Copy link
Contributor

nilason commented Jan 27, 2025

And the OSGeo4W CI error is a bit unexpected:

See #4990

Copy link
Member

@wenzeslaus wenzeslaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good overall and the generated JSON seems good too. I have just comments about code structure.

I'm still for the mapset_path but I would be happy to discuss alternatives if anyone feels like.

I completely agree that a function is needed. With how the code is written, two separate functions seem to be more fitting. One for actual parsing and another one for JSON. Let's say we would want to write to a different format than JSON. However, my reason for wanting two functions is mostly from code reading perspective.

Comment on lines 106 to 120
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, MAX_STR_LEN, "%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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the second function which adds one record to JSON.

Comment on lines 113 to 114
json_object_set_string(info_object, "command", command);
snprintf(mapset_path, MAX_STR_LEN, "%s/%s/%s", gisdbase, location,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

command and gisdbase are here inputs while there were outputs the previous calls of the function.

G_fatal_error(
_("Failed to initialize JSON object. Out of memory?"));
}
JSON_Object *info_object = json_object(info_value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes the order in the source file and in the functions calls. Perhaps safe assumption, but confusing in the context.

Comment on lines 91 to 93
void parse_history_json(char *buf, char *command, char *gisdbase,
char *location, char *mapset, char *user, char *date,
char *mapset_path, JSON_Array *record_array)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function ended up here just because of its name. The parsing here is parsing command line input. I don't

In the tool itself, the function is more linked to the print anyway, so just keep it there for simplicity. Actually, in the current form, it is also very much linked to that print code.

In any case, please document split the function into two and document them with a sentence or two. It took me some time to orient myself in this code although it is actually straightforward and nicely written otherwise.

@NishantBansal2003
Copy link
Contributor Author

Hey @wenzeslaus, thanks for the detailed review. I've tried to improve the code structure based on your feedback and will keep it in mind for next time. Could you please take a look and check if everything is covered? Thanks.

Copy link
Contributor

@nilason nilason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a quick reading, I have some minor suggestions.

vector/v.info/print.c Outdated Show resolved Hide resolved
vector/v.info/print.c Outdated Show resolved Hide resolved
vector/v.info/local_proto.h Outdated Show resolved Hide resolved
vector/v.info/local_proto.h Outdated Show resolved Hide resolved
Signed-off-by: Nishant Bansal <[email protected]>
Signed-off-by: Nishant Bansal <[email protected]>
vector/v.info/print.c Outdated Show resolved Hide resolved
Co-authored-by: Nicklas Larsson <[email protected]>
Signed-off-by: Nishant Bansal <[email protected]>
@nilason nilason self-requested a review February 5, 2025 15:01
Copy link
Contributor

@cwhite911 cwhite911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nilason
Copy link
Contributor

nilason commented Feb 5, 2025

I wonder, with the traditional output the history is ordered, this is not evident with current json output?!

Update: e.g. add a "history_no", or "event_no" or similarly named int to json output.

@NishantBansal2003
Copy link
Contributor Author

I wonder, with the traditional output the history is ordered, this is not evident with current json output?!

The order of elements within a JSON object created by Parson may vary (i.e., they are not necessarily in the order in which we inserted them). However, the order of elements in a JSON list/array created by Parson remains the same (i.e., exactly in the order we inserted them) unless you remove elements. See: kgabis/parson#218

@nilason
Copy link
Contributor

nilason commented Feb 6, 2025

I wonder, with the traditional output the history is ordered, this is not evident with current json output?!

The order of elements within a JSON object created by Parson may vary (i.e., they are not necessarily in the order in which we inserted them). However, the order of elements in a JSON list/array created by Parson remains the same (i.e., exactly in the order we inserted them) unless you remove elements. See: kgabis/parson#218

That is what I mean. The order of history is important, but this information is lost working with a json file with an array of "records" (no predictable way to know the order there, is there). It is like a database table without a pkey.

Something like:

{
    "records": [
        {
            "history_no_or_whatever_name": "1",
            "command": "v.in.ogr dsn=\"majorroads.shp\" output=\"roads_major\" min_area=0.0001 snap=-1",
            "mapset_path": "\/bigdata\/grassdata05\/wakestpfeet\/PERMANENT",
            "user": "helena",
            "date": "Tue Nov  7 18:34:20 2006"
        },
...

This is, I imagine, easy to implement with a counter in the read line loop.

Copy link
Member

@wenzeslaus wenzeslaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the strings are used to signal the state, I think it is better to clear them in the caller code instead of the function. It will be more clear what is happening.

@nilason
Copy link
Contributor

nilason commented Feb 6, 2025

Given the strings are used to signal the state, I think it is better to clear them in the caller code instead of the function. It will be more clear what is happening.

I'm not sure what you mean.

nilason
nilason previously approved these changes Feb 6, 2025
Copy link
Contributor

@nilason nilason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.
@NishantBansal2003 Thanks!

Signed-off-by: Nishant Bansal <[email protected]>
@NishantBansal2003
Copy link
Contributor Author

Given the strings are used to signal the state, I think it is better to clear them in the caller code instead of the function. It will be more clear what is happening.

Sorry, I'm not entirely clear on your suggestion. Could you please explain in more detail where you think the strings should be cleared?

nilason
nilason previously approved these changes Feb 6, 2025
@petrasovaa
Copy link
Contributor

Given the strings are used to signal the state, I think it is better to clear them in the caller code instead of the function. It will be more clear what is happening.

I'm not sure what you mean.

I think he refers to parse_history_line

@nilason
Copy link
Contributor

nilason commented Feb 7, 2025

Given the strings are used to signal the state, I think it is better to clear them in the caller code instead of the function. It will be more clear what is happening.

I'm not sure what you mean.

I think he refers to parse_history_line

That would be my guess too, but that’s where it is known when to clear.

@nilason
Copy link
Contributor

nilason commented Feb 7, 2025

That would be my guess too, but that’s where it is known when to clear.

Or possibly after call to add_record_to_json(), would work as well.

@wenzeslaus
Copy link
Member

That would be my guess too, but that’s where it is known when to clear.

Or possibly after call to add_record_to_json(), would work as well.

Yes, that's what I meant. Keeping the state out of the function. Sorry for not being clear.

@echoix
Copy link
Member

echoix commented Feb 7, 2025

So is this PR ok, or your requested changes still apply?

vector/v.info/print.c Outdated Show resolved Hide resolved
Signed-off-by: Nishant Bansal <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C Related code is in C module Python Related code is in Python tests Related to Test Suite vector Related to vector data processing
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

[Feat] Add JSON output for history in v.info
7 participants