examples: ls-files: add ls-files to list paths in the index - #4380
Conversation
pks-t
left a comment
There was a problem hiding this comment.
Hi @cjhoward92! I always think it worthwhile to have more examples, as a lot of people prefer to learn by example instead by documentation, so I welcome this PR. Thanks a lot :)
There are a few things which could be improved. Most things are not actually game breaking but just small nits, but you've got the --error-unmatch thing wrong. Right now you decide whether to print the complete index or by path simply by inspecting opts.error_unmatch, which is wrong. Instead, we want to print the complete index when no files were in by the user, otherwise we want to list just what the user provided. error_unmatch is then used to decide, in the second case where we have a list of paths from the user`, whether we want to give an error when he has listed a non-existing path.
So if you correct that behaviour and the other nits I'd be happy to merge :)
| @@ -3,7 +3,7 @@ | |||
| CC = gcc | |||
There was a problem hiding this comment.
We have a makefile here? I'll create a PR and delete that.
|
|
||
| #define MAX_FILES 64 | ||
|
|
||
| typedef struct ls_options { |
There was a problem hiding this comment.
I think we usually avoid giving the struct itself a name if it's already typedef'd.
|
|
||
| typedef struct ls_options { | ||
| int error_unmatch; | ||
| char *files[MAX_FILES]; |
There was a problem hiding this comment.
You never check whether you overflow that array. Furthermore, I'd propose to just use an array, that should be much simpler. Just have a look at "array.h" :)
|
|
||
| static void usage(const char *message, const char *arg); | ||
| void parse_options(ls_options *opts, int argc, char *argv[]); | ||
| int print_error_unmatch(ls_options *opts, git_index *index); |
There was a problem hiding this comment.
static declarations are missing here. You could also consider to reorder functions to avoid these declarations, but I'm rather indifferent to that.
| void parse_options(ls_options *opts, int argc, char *argv[]); | ||
| int print_error_unmatch(ls_options *opts, git_index *index); | ||
|
|
||
| int main(int argc, char *argv[]) { |
There was a problem hiding this comment.
We prefer to have a newline between function head and the opening brace.
| } | ||
|
|
||
| /* Print a usage message for the program. */ | ||
| static void usage(const char *message, const char *arg) |
There was a problem hiding this comment.
This here is a strange signature, I'd have expected varargs. But as you've simply taken that from other examples, I guess it's fine. Probably it would also be a bit overkill as there is no need for that right now.
| opts->files[opts->file_count++] = a; | ||
| } else { | ||
| parsing_files = 1; | ||
| } |
| if (parsing_files) { | ||
| opts->files[opts->file_count++] = a; | ||
| } else { | ||
| parsing_files = 1; |
There was a problem hiding this comment.
To me this looks like you're actually skipping the first file? Or am I misinterpreting that?
| } | ||
| } | ||
|
|
||
| int print_error_unmatch(ls_options *opts, git_index *index) { |
There was a problem hiding this comment.
I'd rename that to e.g. print_paths. You could then have a second function print_index when no paths are given.
| if (!entry) { | ||
| printf("error: pathspec '%s' did not match any file(s) known to git.\n", path); | ||
| printf("Did you forget to 'git add'?\n"); | ||
| return -1; |
There was a problem hiding this comment.
This error should in fact only trigger if (!entry && opts->error_unmatch).
|
@pks-t Thanks a ton for reviewing this! I will be happy to make these changes, hopefully tonight, but maybe tomorrow. I really appreciate you taking the time to look over this and being patient with me! I am pretty new to C, but I would really like to become an active contributor to libgit2, so I will work hard to get you some quality PR's. Thanks again! |
f04a187 to
859ddde
Compare
|
@pks-t This should be mostly good to go. Not 100% sure how to use the |
|
All updated. I figured out how to use |
|
I was wondering if I should squash this? |
|
Any chance anyone will take a look at this? |
|
I'll find some time next week. |
pks-t
left a comment
There was a problem hiding this comment.
There's just one functional issue here, the rest is about style, so we're mostly there. Thanks for fixing up and working on this!
| tag | ||
| for-each-ref | ||
| describe | ||
| ls-files |
There was a problem hiding this comment.
I've deleted this file on libgit2's master now, as it should not be required anymore. You'll have to rebase your PR to fix that conflict. unfortunately.
| APPS = general showindex diff rev-list cat-file status log rev-parse init blame tag remote | ||
| APPS = general showindex diff rev-list cat-file status log rev-parse init blame tag remote ls-files | ||
| APPS += for-each-ref | ||
| APPS += describe |
There was a problem hiding this comment.
Same here, I've also deleted that file on master.
| * This includes staged and committed files, but unstaged files will not display. | ||
| * | ||
| * This currently supports: | ||
| * - The --error-unmatch paramter with the same output as the git cli |
There was a problem hiding this comment.
Small nit: there's one space too much here. I'd also put that whole supported/unsupported thing a little bit shorter: "This currently only supports default behaviour and the --error-unmatch option."
| static int parse_options(ls_options *opts, int argc, char *argv[]) | ||
| { | ||
| int parsing_files = 0; | ||
| struct args_info args = ARGS_INFO_INIT; |
There was a problem hiding this comment.
This is not really being used, is it? You could instead just loop over argc/argv[]:
int i;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
...
}
|
|
||
| file = git_array_alloc(opts->files); | ||
| GITERR_CHECK_ALLOC(file); | ||
| *file = a; |
|
|
||
| /* if it doesn't start with a '-' or is after the '--' then it is a file */ | ||
| if (a[0] != '-') { | ||
| parsing_files = 1; |
There was a problem hiding this comment.
You set this, but you don't use that value to distinguish files/non-files. It should probably be
if (a[0] != '-' || parsing_files) {
...
}
So as soon as we find the first non-argument, we treat all remaining arguments as files.
| *file = a; | ||
| } else if (!strcmp(a, "--")) { | ||
| parsing_files = 1; | ||
| } else if (!strcmp(a, "--error-unmatch") && !parsing_files) { |
There was a problem hiding this comment.
If you change the first condition as proposed, there's no need for the !parsing_files anymore.
| entry = git_index_get_bypath(index, path, GIT_INDEX_STAGE_NORMAL); | ||
| if (!entry && opts->error_unmatch) { | ||
| printf("error: pathspec '%s' did not match any file(s) known to git.\n", path); | ||
| printf("Did you forget to 'git add'?\n"); |
There was a problem hiding this comment.
These should probably be fprintf(stderr, ...) to print to stderr instead.
| if (git_array_size(opts.files) > 0) { | ||
| error = print_paths(&opts, index); | ||
| goto cleanup; | ||
| } |
There was a problem hiding this comment.
I would simply put the rest into an else branch. Like that, you don't need that goto cleanup anymore and it becomes a bit more obvious.
| } | ||
|
|
||
| cleanup: | ||
| /* free our allocated resources */ |
There was a problem hiding this comment.
I think there's no need to state the obvious here ;) Same for the two previous comments.
0b255eb to
d3f9aef
Compare
|
@pks-t This is all updated, but I am not too sure what is causing the windows builds to break. |
|
Regarding the Windows builds: However, I think that we're not linking the examples with the CRT debugging libraries. Ugh. Not sure how to fix this offhand. |
|
Ok, I will check it out when I get a moment. Thanks for the explanation! |
e97d063 to
8c61dea
Compare
|
Would updating the CMakeLists for the examples to statically link the CRT debugging libraries work? I'm not super familiar with how CMake works to really know. All I found was the flags to link when running the main build process. I don't really understand why this fails on AppVeyor but works on my machine either, unless I installed something that exposes the CRT libraries on my includes path. |
|
AppVeyor is explicitly turning on the CRT memory debugging functionality, with In any case, the ideal way to fix this would be to not use |
|
I see why you want to use I do think that we should make sure that we do not crash if a user enters 17 filenames though. :grin |
|
Thanks @ethomson! I'll verify |
|
Looks like there is only an error with some of the credentials stuff now, might be some network error. I think they should be good to go, though. |
|
bump |
pks-t
left a comment
There was a problem hiding this comment.
This should be the last round of comments now. The example looks very nice by now, but there's two issues with C99-comments and the missing error when the files array is too small. I only added the other comments because there's already some stuff that needs fixing up, so they'd be nice to have, too.
|
|
||
| // watch for overflows (just in case) | ||
| if (opts->file_count == 1024) { | ||
| break; |
There was a problem hiding this comment.
You probably shouldn't break here but print an error and return an error code.
| if (a[0] != '-' || parsing_files) { | ||
| parsing_files = 1; | ||
|
|
||
| // watch for overflows (just in case) |
There was a problem hiding this comment.
C++-style comments are not allowed
| int file_count; | ||
| } ls_options; | ||
|
|
||
| /* Print a usage message for the program. */ |
There was a problem hiding this comment.
This comment does not provide any useful information
| static int print_paths(ls_options *opts, git_index *index) | ||
| { | ||
| int i; | ||
| const git_index_entry *entry; |
There was a problem hiding this comment.
This could also be scoped to the loop
| entry = git_index_get_byindex(index, i); | ||
| printf("%s\n", entry->path); | ||
| } | ||
| } |
There was a problem hiding this comment.
Just a small style issue: I do find it a bit funny that some printing logic is in print_paths and some is not. Maybe put the complete priting logic into print_paths and destinguish cases by opts.file_count inside of that function, then? That would make the main function a bit nicer to read.
a42087c to
02e8598
Compare
|
@pks-t Hopefully this is updated in the way you recommended. Let me know what you think! Thanks for all of the feedback! |
pks-t
left a comment
There was a problem hiding this comment.
Your updates look perfect, thanks for it! I just tried it locally and found a bug in it such that all command line arguments are printed out, whether they are found or not. Everything else looks good to me.
| /* watch for overflows (just in case) */ | ||
| if (opts->file_count == 1024) { | ||
| fprintf(stderr, "ls-files can only support 1024 files at this time.\n"); | ||
| return -1; |
| return -1; | ||
| } | ||
|
|
||
| printf("%s\n", path); |
There was a problem hiding this comment.
I just tried the code locally as I wanted to merge it, but I found this bug here. You're inconditionally printing path whether it is found or not. But in fact, you only want to print it if entry != NULL. So something like the following:
if ((entry = git_index_get_bypath(...)) != NULL) {
printf("%s\n", path);
} else if (opts->error_unmatch) {
fprintf(stderr, ...);
return -1;
}
| if ((error = git_repository_index(&index, repo)) < 0) | ||
| goto cleanup; | ||
|
|
||
| error = print_paths(&opts, index); |
There was a problem hiding this comment.
Yup, this looks like a very clean main function now :)
02e8598 to
d7394c3
Compare
|
Wow, sorry this took so long to get done! I have been really busy lately. Thanks a ton for all of the review you have done! I hope I finally have it clean enough to get merged! |
|
Any more review on this? It looks like the test failures and build issues were an internet connectivity issue perhaps. I wonder if restarting the build on Travis would fix that. Thanks! |
pks-t
left a comment
There was a problem hiding this comment.
Looks good to me. There are some really minor nits, but I don't really care for them. Some quick testing showed no issues. Waiting for a few days if there's more feedback, otherwise I'm going to merge
|
|
||
| typedef struct { | ||
| int error_unmatch; | ||
| char * files[1024]; |
There was a problem hiding this comment.
* goes with the variable name, so this should rather be char *files[1024];.
| size_t i; | ||
| const git_index_entry *entry; | ||
|
|
||
| /* if there are not files explicitly listed by the user print all entries in the index */ |
|
|
||
| for (i = 0; i < entry_count; i++) { | ||
| entry = git_index_get_byindex(index, i); | ||
| printf("%s\n", entry->path); |
There was a problem hiding this comment.
puts(entry->path) would be preferred
| const char *path = opts->files[i]; | ||
|
|
||
| if ((entry = git_index_get_bypath(index, path, GIT_INDEX_STAGE_NORMAL)) != NULL) { | ||
| printf("%s\n", path); |
|
I was in here so I fixed those final issues you had anyway! Thanks again! |
|
Thanks a lot, @cjhoward92! |
Added an example to mimic
git ls-filesusing the libgit2 library. It also supports the--error-unmatchparameter to determine if the specified paths are in the index. This will hopefully be a useful example for new libgit2 users.