18
#include "commit-graph.h"
19
#include "wildmatch.h"
20
#include "mem-pool.h"
21
+#include "pretty.h"
22
+#include "revision.h"
23
+#include "notes.h"
24
+#include "write-or-die.h"
25
26
/*
27
* One day. See the 'name a rev shortly after epoch' test in t6120 when
276
struct string_list exclude_filters;
277
};
278
279
+struct pretty_format {
280
+ struct pretty_print_context ctx;
281
+ struct userformat_want want;
282
+};
283
+
284
enum command_type {
285
NAME_REV = 1,
286
+ FORMAT_REV = 2,
287
+};
288
+
289
+enum stdin_mode {
290
+ TEXT = 1,
291
+ REVS = 2,
292
};
293
294
struct command {
295
enum command_type type;
296
union {
297
int name_only;
298
+ struct pretty_format *pretty_format;
299
} u;
300
};
301
306
cmd->u.name_only = name_only;
307
}
308
309
+static void init_format_rev_command(struct command *cmd,
310
+ struct pretty_format *pretty_format)
311
+{
312
+ cmd->type = FORMAT_REV;
313
+ cmd->u.pretty_format = pretty_format;
314
+}
315
+
316
static struct tip_table {
317
struct tip_table_entry {
318
struct object_id oid;
518
}
519
}
520
521
+static const char *get_format_rev(const struct commit *c,
522
+ struct pretty_format *format_ctx,
523
+ struct strbuf *buf)
524
+{
525
+ strbuf_reset(buf);
526
+
527
+ if (format_ctx->want.notes) {
528
+ struct strbuf notebuf = STRBUF_INIT;
529
+
530
+ format_display_notes(&c->object.oid, ¬ebuf,
531
+ get_log_output_encoding(),
532
+ format_ctx->ctx.fmt == CMIT_FMT_USERFORMAT);
533
+ format_ctx->ctx.notes_message = strbuf_detach(¬ebuf, NULL);
534
+ }
535
+
536
+ pretty_print_commit(&format_ctx->ctx, c, buf);
537
+ FREE_AND_NULL(format_ctx->ctx.notes_message);
538
+
539
+ return buf->buf;
540
+}
541
+
542
static void show_name(const struct object *obj,
543
const char *caller_name,
544
int always, int allow_undefined, int name_only)
608
else
609
printf("%.*s (%s)", p_len, p_start, name);
610
break;
611
+ case FORMAT_REV:
612
+ if (!oid_ret)
613
+ o = parse_object(the_repository, &oid);
614
+ if (o && o->type == OBJ_COMMIT)
615
+ name = get_format_rev((const struct commit *)o,
616
+ cmd->u.pretty_format,
617
+ &buf);
618
+ if (name)
619
+ printf("%.*s%s", p_len - hexsz, p_start, name);
620
+ else
621
+ printf("%.*s", p_len, p_start);
622
+ break;
623
default:
624
BUG("uncovered case: %d", cmd->type);
625
}
773
object_array_clear(&revs);
774
return 0;
775
}
776
+
777
+struct format_nul_data {
778
+ bool nul_input;
779
+ bool nul_output;
780
+};
781
+
782
+static int format_nul_cb(const struct option *option,
783
+ const char *arg,
784
+ int unset)
785
+{
786
+ struct format_nul_data *data = option->value;
787
+ data->nul_input = 1;
788
+ data->nul_output = 1;
789
+ BUG_ON_OPT_NEG(unset);
790
+ BUG_ON_OPT_ARG(arg);
791
+ return 0;
792
+}
793
+
794
+static enum stdin_mode parse_stdin_mode(const char *stdin_mode)
795
+{
796
+ if (!strcmp(stdin_mode, "text"))
797
+ return TEXT;
798
+ else if (!strcmp(stdin_mode, "revs") ||
799
+ !strcmp(stdin_mode, "rev"))
800
+ return REVS;
801
+ else
802
+ die(_("'%s' needs to be either text, revs, or rev"),
803
+ "--stdin-mode");
804
+}
805
+
806
+static char const *const format_rev_usage[] = {
807
+ N_("(EXPERIMENTAL!) git format-rev --stdin-mode=<mode> "
808
+ "--format=<pretty> [--[no-]notes=<ref>] "
809
+ "[-z] [--[no-]null-output] [--[no-]null-input]"),
810
+ NULL
811
+};
812
+
813
+int cmd_format_rev(int argc,
814
+ const char **argv,
815
+ const char *prefix,
816
+ struct repository *repo UNUSED)
817
+{
818
+ const char *format = NULL;
819
+ enum stdin_mode stdin_mode;
820
+ const char *stdin_mode_arg = NULL;
821
+ struct format_nul_data nul_data = { 0, 0 };
822
+ char output_terminator;
823
+ strbuf_getline_fn getline_fn;
824
+ struct display_notes_opt format_notes_opt;
825
+ struct rev_info format_rev = REV_INFO_INIT;
826
+ struct pretty_format format_pp = { 0 };
827
+ struct string_list notes = STRING_LIST_INIT_NODUP;
828
+ struct strbuf scratch_buf = STRBUF_INIT;
829
+ struct command cmd;
830
+ struct option opts[] = {
831
+ OPT_STRING(0, "format", &format, N_("format"),
832
+ N_("pretty format to use")),
833
+ OPT_STRING(0, "stdin-mode", &stdin_mode_arg, N_("stdin-mode"),
834
+ N_("how revs are processed")),
835
+ OPT_STRING_LIST(0, "notes", ¬es, N_("notes"),
836
+ N_("display notes for pretty format")),
837
+ OPT_CALLBACK_F('z', "null", &nul_data, N_("z"),
838
+ N_("Use NUL for input and output termination"),
839
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG, format_nul_cb),
840
+ OPT_BOOL(0, "null-input", &nul_data.nul_input,
841
+ N_("Use NUL for input termination")),
842
+ OPT_BOOL(0, "null-output", &nul_data.nul_output,
843
+ N_("Use NUL for output termination")),
844
+ OPT_END(),
845
+ };
846
+
847
+ argc = parse_options(argc, argv, prefix, opts, format_rev_usage, 0);
848
+
849
+ if (argc > 0) {
850
+ error(_("too many arguments"));
851
+ usage_with_options(format_rev_usage, opts);
852
+ }
853
+
854
+ if (!format)
855
+ die(_("'%s' is required"), "--format");
856
+ if (!stdin_mode_arg)
857
+ die(_("'%s' is required"), "--stdin-mode");
858
+
859
+ getline_fn = nul_data.nul_input ? strbuf_getline_nul : strbuf_getline_lf;
860
+ output_terminator = nul_data.nul_output ? '\0' : '\n';
861
+
862
+ init_display_notes(&format_notes_opt);
863
+ stdin_mode = parse_stdin_mode(stdin_mode_arg);
864
+
865
+ get_commit_format(format, &format_rev);
866
+ format_pp.ctx.rev = &format_rev;
867
+ format_pp.ctx.fmt = format_rev.commit_format;
868
+ format_pp.ctx.abbrev = format_rev.abbrev;
869
+ format_pp.ctx.date_mode_explicit = format_rev.date_mode_explicit;
870
+ format_pp.ctx.date_mode = format_rev.date_mode;
871
+ format_pp.ctx.color = GIT_COLOR_AUTO;
872
+
873
+ userformat_find_requirements(format,
874
+ &format_pp.want);
875
+ if (format_pp.want.notes) {
876
+ int ignore_show_notes = 0;
877
+ struct string_list_item *n;
878
+
879
+ for_each_string_list_item(n, ¬es)
880
+ enable_ref_display_notes(&format_notes_opt,
881
+ &ignore_show_notes,
882
+ n->string);
883
+ load_display_notes(&format_notes_opt);
884
+ }
885
+
886
+ init_format_rev_command(&cmd, &format_pp);
887
+
888
+ switch (stdin_mode) {
889
+ case TEXT:
890
+ while (getline_fn(&scratch_buf, stdin) != EOF) {
891
+ name_rev_line(scratch_buf.buf, &cmd);
892
+ /*
893
+ * We do not pass on the terminator to name_rev_line,
894
+ * unlike name-rev.
895
+ */
896
+ printf("%c", output_terminator);
897
+ maybe_flush_or_die(stdout, "stdout");
898
+ }
899
+ break;
900
+ case REVS:
901
+ while (getline_fn(&scratch_buf, stdin) != EOF) {
902
+ struct object_id oid;
903
+ struct object *object;
904
+ struct object *peeled;
905
+
906
+ if (repo_get_oid(the_repository, scratch_buf.buf, &oid)) {
907
+ fprintf(stderr, "Could not get object name for %s. Skipping.\n",
908
+ scratch_buf.buf);
909
+ continue;
910
+ }
911
+
912
+ object = parse_object(the_repository, &oid);
913
+ if (!object) {
914
+ fprintf(stderr, "Could not get object for %s. Skipping.\n",
915
+ scratch_buf.buf);
916
+ continue;
917
+ }
918
+
919
+ peeled = deref_tag(the_repository, object, scratch_buf.buf, 0);
920
+ if (!peeled || peeled->type != OBJ_COMMIT) {
921
+ fprintf(stderr,
922
+ "Could not get commit for %s. Skipping.\n",
923
+ scratch_buf.buf);
924
+ continue;
925
+ }
926
+
927
+ get_format_rev((struct commit *)peeled,
928
+ &format_pp, &scratch_buf);
929
+ printf("%s%c", scratch_buf.buf, output_terminator);
930
+ maybe_flush_or_die(stdout, "stdout");
931
+ strbuf_release(&scratch_buf);
932
+ }
933
+ break;
934
+ default:
935
+ BUG("uncovered case: %d", stdin_mode);
936
+ }
937
+
938
+ strbuf_release(&scratch_buf);
939
+ string_list_clear(¬es, 0);
940
+ release_display_notes(&format_notes_opt);
941
+ return 0;
942
+}