Skip to content
Merged
Prev Previous commit
Next Next commit
examples: ls-files: show current files in index
  • Loading branch information
Carson Howard authored and Carson Howard committed Mar 27, 2018
commit 991fc08805c83cffbe3a0902eb66140ece590f0a
129 changes: 109 additions & 20 deletions examples/ls-files.c
Original file line number Diff line number Diff line change
@@ -1,37 +1,126 @@
#include <common.h>
/*
* libgit2 "ls-files" example - shows how to view all files currently in the index
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/

typedef struct ls_files_state {
#include "common.h"

/**
* This example demonstrates the libgit2 index APIs to roughly
* simulate the output of `git ls-files`.
* `git ls-files` has many options and this currently does not show them.
*
* `git ls-files` base command shows all paths in the index at that time.
* This includes staged and committed files, but unstaged files will not display.
*/

#define MAX_FILES 64

typedef struct ls_options {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we usually avoid giving the struct itself a name if it's already typedef'd.

int error_unmatch;
char *files[MAX_FILES];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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" :)

int file_count;
} ls_options;

void parse_options(ls_options *opts, int argc, char *argv[]);

int main(int argc, char *argv[]) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We prefer to have a newline between function head and the opening brace.

ls_options opts;
git_repository *repo;
git_index *index;
char **files;
size_t num_entries;
} ls_files;

void create_ls_files(ls_files **ls);
const git_index_entry *entry;
size_t entry_count;
size_t i = 0;
int error;

int main(int argc, char[] *argv) {
ls_files *ls;
git_index_entry *entry;
size_t i;
parse_options(&opts, argc, argv);

/* we need to initialize libgit2 */
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this and the following comments don't really have much value, as they simply state the obvious.

git_libgit2_init();

ls = git__malloc(sizeof(ls_files));
/* we need to open the repo */
if ((error = git_repository_open_ext(&repo, ".", 0, NULL)) != 0)
goto cleanup;

// TODO err
git_repository_open_ext(&ls->repo, ".", 0, NULL);
/* we need to load the repo's index */
if ((error = git_repository_index(&index, repo)) != 0)
goto cleanup;

// TODO err
git_repository_index__weakptr(&ls->index, ls->repo);
if (opts.error_unmatch) {
for (i = 0; i < opts.file_count; i++) {
const char *path = opts.files[i];
printf("Checking first path '%s'\n", path);
entry = git_index_get_bypath(index, path, GIT_INDEX_STAGE_NORMAL);
if (!entry) {
printf("Could not find path '%s'\n", path);
return -1;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice :)

}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No need for braces here.

}
goto cleanup;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think you've got a slight misconception of error_unmatch. What you do here is print out different things based on whether error_unmatch is set or not. But in fact, in both cases we'd like to either list the complete index if we have no explicit file list, or in the other case just the files. So what is printed should only be decided based on whether the user explicitly passed files into the program or not. error_unmatch is then only used in the case where we have paths to check if the path actually exists.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.


/* we need to know how many entries exist in the index */
entry_count = git_index_entrycount(index);

git_vector_foreach(&ls->index->entries, i, entry) {
/* loop through the entries by index and display their pathes */
for (i = 0; i < entry_count; i++) {
entry = git_index_get_byindex(index, i);
printf("%s\n", entry->path);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.


git_repository_free(ls->repo);
git__free(ls);
cleanup:
/* free our allocated resources */
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think there's no need to state the obvious here ;) Same for the two previous comments.

git_index_free(index);
git_repository_free(repo);

/* we need to shutdown libgit2 */
git_libgit2_shutdown();

return 0;
return error;
}

void parse_options(ls_options *opts, int argc, char *argv[]) {
int parsing_files = 0;
int file_idx = 0;
struct args_info args = ARGS_INFO_INIT;

memset(opts, 0, sizeof(ls_options));
opts->error_unmatch = 0;
opts->file_count = 0;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No need to zero those two variables out if you've already used memset.


if (argc < 2)
return;

for (args.pos = 1; args.pos < argc; ++args.pos) {
char *a = argv[args.pos];

if (a[0] != '-' || !strcmp(a, "--")) {
if (parsing_files) {
printf("%s\n", a);
opts->files[opts->file_count++] = a;
} else {
parsing_files = 1;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

To me this looks like you're actually skipping the first file? Or am I misinterpreting that?

}
} else if (!strcmp(a, "--error-unmatch")) {
opts->error_unmatch = 1;
parsing_files = 1;
} else {
printf("Bad command\n");
}
}

printf("file count: %d\n", opts->file_count);
int i;
for (i = 0; i < opts->file_count; i++) {
printf("Path ids %d: %s\n", i, opts->files[i]);
}
}