ls-files.c 3.45 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * 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/>.
 */
14

15
#include "common.h"
16
#include "array.h"
17 18 19 20 21

/**
 * 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.
22
 *
23 24
 * `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.
25
 *
26
 * This currently supports the default behavior and the `--error-unmatch` option.
27 28
 */

29
typedef struct {
30
	int error_unmatch;
31
	char *files[1024];
32
	size_t file_count;
33 34
} ls_options;

35 36 37 38 39 40 41 42 43 44
static void usage(const char *message, const char *arg)
{
	if (message && arg)
		fprintf(stderr, "%s: %s\n", message, arg);
	else if (message)
		fprintf(stderr, "%s\n", message);
	fprintf(stderr, "usage: ls-files [--error-unmatch] [--] [<file>...]\n");
	exit(1);
}

45
static int parse_options(ls_options *opts, int argc, char *argv[])
46
{
47
	int parsing_files = 0;
48
	int i;
49

50 51 52
	memset(opts, 0, sizeof(ls_options));

	if (argc < 2)
53
		return 0;
54

55 56
	for (i = 1; i < argc; ++i) {
		char *a = argv[i];
57

58
		/* if it doesn't start with a '-' or is after the '--' then it is a file */
59
		if (a[0] != '-' || parsing_files) {
60
			parsing_files = 1;
61

62
			/* watch for overflows (just in case) */
63
			if (opts->file_count == 1024) {
64 65
				fprintf(stderr, "ls-files can only support 1024 files at this time.\n");
				return -1;
66 67 68
			}

			opts->files[opts->file_count++] = a;
69 70
		} else if (!strcmp(a, "--")) {
			parsing_files = 1;
71
		} else if (!strcmp(a, "--error-unmatch")) {
72
			opts->error_unmatch = 1;
73
		} else {
74
			usage("Unsupported argument", a);
75
			return -1;
76 77
		}
	}
78 79

	return 0;
80
}
81

82
static int print_paths(ls_options *opts, git_index *index)
83
{
84
	size_t i;
85
	const git_index_entry *entry;
86

87
	/* if there are no files explicitly listed by the user print all entries in the index */
88 89 90 91 92
	if (opts->file_count == 0) {
		size_t entry_count = git_index_entrycount(index);

		for (i = 0; i < entry_count; i++) {
			entry = git_index_get_byindex(index, i);
93
			puts(entry->path);
94 95 96
		}
		return 0;
	}
97 98

	/* loop through the files found in the args and print them if they exist */
99 100
	for (i = 0; i < opts->file_count; ++i) {
		const char *path = opts->files[i];
101

102
		if ((entry = git_index_get_bypath(index, path, GIT_INDEX_STAGE_NORMAL)) != NULL) {
103
			puts(path);
104
		} else if (opts->error_unmatch) {
105 106
			fprintf(stderr, "error: pathspec '%s' did not match any file(s) known to git.\n", path);
			fprintf(stderr, "Did you forget to 'git add'?\n");
107 108
			return -1;
		}
109
	}
110

111 112
	return 0;
}
113 114 115 116

int main(int argc, char *argv[])
{
	ls_options opts;
117 118
	git_repository *repo = NULL;
	git_index *index = NULL;
119 120
	int error;

121 122
	if ((error = parse_options(&opts, argc, argv)) < 0)
		return error;
123 124 125

	git_libgit2_init();

126
	if ((error = git_repository_open_ext(&repo, ".", 0, NULL)) < 0)
127 128
		goto cleanup;

129
	if ((error = git_repository_index(&index, repo)) < 0)
130 131
		goto cleanup;

132
	error = print_paths(&opts, index);
133 134 135 136 137 138 139 140

cleanup:
	git_index_free(index);
	git_repository_free(repo);
	git_libgit2_shutdown();

	return error;
}