]>
Commit | Line | Data |
---|---|---|
9d83d368 | 1 | /* |
6cb831bd | 2 | * libgit2 "cat-file" example - shows how to print data from the ODB |
9d83d368 | 3 | * |
6cb831bd BS |
4 | * Written by the libgit2 contributors |
5 | * | |
6 | * To the extent possible under law, the author(s) have dedicated all copyright | |
7 | * and related and neighboring rights to this software to the public domain | |
8 | * worldwide. This software is distributed without any warranty. | |
9 | * | |
10 | * You should have received a copy of the CC0 Public Domain Dedication along | |
11 | * with this software. If not, see | |
12 | * <http://creativecommons.org/publicdomain/zero/1.0/>. | |
9d83d368 | 13 | */ |
58206c9a | 14 | |
9d83d368 | 15 | #include "common.h" |
58206c9a RB |
16 | |
17 | static void print_signature(const char *header, const git_signature *sig) | |
18 | { | |
19 | char sign; | |
20 | int offset, hours, minutes; | |
21 | ||
22 | if (!sig) | |
23 | return; | |
24 | ||
25 | offset = sig->when.offset; | |
26 | if (offset < 0) { | |
27 | sign = '-'; | |
28 | offset = -offset; | |
29 | } else { | |
30 | sign = '+'; | |
31 | } | |
32 | ||
33 | hours = offset / 60; | |
34 | minutes = offset % 60; | |
35 | ||
36 | printf("%s %s <%s> %ld %c%02d%02d\n", | |
37 | header, sig->name, sig->email, (long)sig->when.time, | |
38 | sign, hours, minutes); | |
39 | } | |
40 | ||
4f62d559 | 41 | /** Printing out a blob is simple, get the contents and print */ |
58206c9a RB |
42 | static void show_blob(const git_blob *blob) |
43 | { | |
44 | /* ? Does this need crlf filtering? */ | |
300f4412 | 45 | fwrite(git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob), 1, stdout); |
58206c9a RB |
46 | } |
47 | ||
c44820c6 | 48 | /** Show each entry with its type, id and attributes */ |
58206c9a RB |
49 | static void show_tree(const git_tree *tree) |
50 | { | |
51 | size_t i, max_i = (int)git_tree_entrycount(tree); | |
52 | char oidstr[GIT_OID_HEXSZ + 1]; | |
53 | const git_tree_entry *te; | |
54 | ||
55 | for (i = 0; i < max_i; ++i) { | |
56 | te = git_tree_entry_byindex(tree, i); | |
57 | ||
58 | git_oid_tostr(oidstr, sizeof(oidstr), git_tree_entry_id(te)); | |
59 | ||
60 | printf("%06o %s %s\t%s\n", | |
61 | git_tree_entry_filemode(te), | |
62 | git_object_type2string(git_tree_entry_type(te)), | |
63 | oidstr, git_tree_entry_name(te)); | |
64 | } | |
65 | } | |
66 | ||
c44820c6 CMN |
67 | /** |
68 | * Commits and tags have a few interesting fields in their header. | |
69 | */ | |
58206c9a RB |
70 | static void show_commit(const git_commit *commit) |
71 | { | |
72 | unsigned int i, max_i; | |
73 | char oidstr[GIT_OID_HEXSZ + 1]; | |
74 | ||
75 | git_oid_tostr(oidstr, sizeof(oidstr), git_commit_tree_id(commit)); | |
76 | printf("tree %s\n", oidstr); | |
77 | ||
78 | max_i = (unsigned int)git_commit_parentcount(commit); | |
79 | for (i = 0; i < max_i; ++i) { | |
80 | git_oid_tostr(oidstr, sizeof(oidstr), git_commit_parent_id(commit, i)); | |
81 | printf("parent %s\n", oidstr); | |
82 | } | |
83 | ||
84 | print_signature("author", git_commit_author(commit)); | |
85 | print_signature("committer", git_commit_committer(commit)); | |
86 | ||
87 | if (git_commit_message(commit)) | |
88 | printf("\n%s\n", git_commit_message(commit)); | |
89 | } | |
90 | ||
91 | static void show_tag(const git_tag *tag) | |
92 | { | |
93 | char oidstr[GIT_OID_HEXSZ + 1]; | |
94 | ||
95 | git_oid_tostr(oidstr, sizeof(oidstr), git_tag_target_id(tag));; | |
96 | printf("object %s\n", oidstr); | |
97 | printf("type %s\n", git_object_type2string(git_tag_target_type(tag))); | |
98 | printf("tag %s\n", git_tag_name(tag)); | |
99 | print_signature("tagger", git_tag_tagger(tag)); | |
100 | ||
101 | if (git_tag_message(tag)) | |
102 | printf("\n%s\n", git_tag_message(tag)); | |
103 | } | |
104 | ||
0c9c969a | 105 | typedef enum { |
58206c9a RB |
106 | SHOW_TYPE = 1, |
107 | SHOW_SIZE = 2, | |
108 | SHOW_NONE = 3, | |
109 | SHOW_PRETTY = 4 | |
0c9c969a | 110 | } catfile_mode; |
58206c9a | 111 | |
9d83d368 | 112 | /* Forward declarations for option-parsing helper */ |
0c9c969a | 113 | struct catfile_options { |
9d83d368 BS |
114 | const char *dir; |
115 | const char *rev; | |
0c9c969a | 116 | catfile_mode action; |
9d83d368 BS |
117 | int verbose; |
118 | }; | |
0c9c969a UG |
119 | |
120 | static void parse_opts(struct catfile_options *o, int argc, char *argv[]); | |
9d83d368 BS |
121 | |
122 | ||
c44820c6 | 123 | /** Entry point for this command */ |
0c9c969a | 124 | int lg2_cat_file(git_repository *repo, int argc, char *argv[]) |
58206c9a | 125 | { |
0c9c969a | 126 | struct catfile_options o = { ".", NULL, 0, 0 }; |
58206c9a RB |
127 | git_object *obj = NULL; |
128 | char oidstr[GIT_OID_HEXSZ + 1]; | |
129 | ||
9d83d368 | 130 | parse_opts(&o, argc, argv); |
58206c9a | 131 | |
9d83d368 BS |
132 | check_lg2(git_revparse_single(&obj, repo, o.rev), |
133 | "Could not resolve", o.rev); | |
58206c9a | 134 | |
9d83d368 | 135 | if (o.verbose) { |
58206c9a RB |
136 | char oidstr[GIT_OID_HEXSZ + 1]; |
137 | git_oid_tostr(oidstr, sizeof(oidstr), git_object_id(obj)); | |
138 | ||
139 | printf("%s %s\n--\n", | |
140 | git_object_type2string(git_object_type(obj)), oidstr); | |
141 | } | |
142 | ||
9d83d368 | 143 | switch (o.action) { |
58206c9a RB |
144 | case SHOW_TYPE: |
145 | printf("%s\n", git_object_type2string(git_object_type(obj))); | |
146 | break; | |
147 | case SHOW_SIZE: { | |
148 | git_odb *odb; | |
149 | git_odb_object *odbobj; | |
150 | ||
9d83d368 BS |
151 | check_lg2(git_repository_odb(&odb, repo), "Could not open ODB", NULL); |
152 | check_lg2(git_odb_read(&odbobj, odb, git_object_id(obj)), | |
153 | "Could not find obj", NULL); | |
58206c9a RB |
154 | |
155 | printf("%ld\n", (long)git_odb_object_size(odbobj)); | |
156 | ||
157 | git_odb_object_free(odbobj); | |
158 | git_odb_free(odb); | |
159 | } | |
160 | break; | |
161 | case SHOW_NONE: | |
162 | /* just want return result */ | |
163 | break; | |
164 | case SHOW_PRETTY: | |
165 | ||
166 | switch (git_object_type(obj)) { | |
ac3d33df | 167 | case GIT_OBJECT_BLOB: |
58206c9a RB |
168 | show_blob((const git_blob *)obj); |
169 | break; | |
ac3d33df | 170 | case GIT_OBJECT_COMMIT: |
58206c9a RB |
171 | show_commit((const git_commit *)obj); |
172 | break; | |
ac3d33df | 173 | case GIT_OBJECT_TREE: |
58206c9a RB |
174 | show_tree((const git_tree *)obj); |
175 | break; | |
ac3d33df | 176 | case GIT_OBJECT_TAG: |
58206c9a RB |
177 | show_tag((const git_tag *)obj); |
178 | break; | |
179 | default: | |
180 | printf("unknown %s\n", oidstr); | |
181 | break; | |
182 | } | |
183 | break; | |
184 | } | |
185 | ||
186 | git_object_free(obj); | |
58206c9a RB |
187 | |
188 | return 0; | |
189 | } | |
9d83d368 | 190 | |
c44820c6 | 191 | /** Print out usage information */ |
9d83d368 BS |
192 | static void usage(const char *message, const char *arg) |
193 | { | |
194 | if (message && arg) | |
195 | fprintf(stderr, "%s: %s\n", message, arg); | |
196 | else if (message) | |
197 | fprintf(stderr, "%s\n", message); | |
198 | fprintf(stderr, | |
199 | "usage: cat-file (-t | -s | -e | -p) [-v] [-q] " | |
200 | "[-h|--help] [--git-dir=<dir>] <object>\n"); | |
201 | exit(1); | |
202 | } | |
203 | ||
c44820c6 | 204 | /** Parse the command-line options taken from git */ |
0c9c969a | 205 | static void parse_opts(struct catfile_options *o, int argc, char *argv[]) |
9d83d368 BS |
206 | { |
207 | struct args_info args = ARGS_INFO_INIT; | |
208 | ||
209 | for (args.pos = 1; args.pos < argc; ++args.pos) { | |
210 | char *a = argv[args.pos]; | |
211 | ||
212 | if (a[0] != '-') { | |
213 | if (o->rev != NULL) | |
214 | usage("Only one rev should be provided", NULL); | |
215 | else | |
216 | o->rev = a; | |
217 | } | |
218 | else if (!strcmp(a, "-t")) | |
219 | o->action = SHOW_TYPE; | |
220 | else if (!strcmp(a, "-s")) | |
221 | o->action = SHOW_SIZE; | |
222 | else if (!strcmp(a, "-e")) | |
223 | o->action = SHOW_NONE; | |
224 | else if (!strcmp(a, "-p")) | |
225 | o->action = SHOW_PRETTY; | |
226 | else if (!strcmp(a, "-q")) | |
227 | o->verbose = 0; | |
228 | else if (!strcmp(a, "-v")) | |
229 | o->verbose = 1; | |
230 | else if (!strcmp(a, "--help") || !strcmp(a, "-h")) | |
231 | usage(NULL, NULL); | |
232 | else if (!match_str_arg(&o->dir, &args, "--git-dir")) | |
233 | usage("Unknown option", a); | |
234 | } | |
235 | ||
236 | if (!o->action || !o->rev) | |
237 | usage(NULL, NULL); | |
238 | ||
239 | } |