config: add --expiry-date
Add --expiry-date as a data-type for config files when 'git config --get' is used. This will return any relative or fixed dates from config files as timestamps. This is useful for scripts (e.g. gc.reflogexpire) that work with timestamps so that '2.weeks' can be converted to a format acceptable by those scripts/functions. Following the convention of git_config_pathname(), move the helper function required for this feature from builtin/reflog.c to builtin/config.c where other similar functions exist (e.g. for --bool or --path), and match the order of parameters with other functions (i.e. output pointer as first parameter). Signed-off-by: Haaris Mehmood <hsed@unimetic.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Haaris Mehmood committed
Nov 18, 2017 at 02:27 UTC
5f9674243d0341519e5031681c941b0e1ad7a9e3
7 files changed
+69
-13
Documentation/git-config.txt
+5
@@ -180,6 +180,11 @@ See also <<FILES>>.
180
value (but you can use `git config section.variable ~/`
181
from the command line to let your shell do the expansion).
182
183
+--expiry-date::
184
+ `git config` will ensure that the output is converted from
185
+ a fixed or relative date-string to a timestamp. This option
186
+ has no effect when setting the value.
187
+
188
-z::
189
--null::
190
For all options that output values and/or keys, always
builtin/config.c
+9
-1
@@ -52,6 +52,7 @@ static int show_origin;
52
#define TYPE_INT (1<<1)
53
#define TYPE_BOOL_OR_INT (1<<2)
54
#define TYPE_PATH (1<<3)
55
+#define TYPE_EXPIRY_DATE (1<<4)
56
57
static struct option builtin_config_options[] = {
58
OPT_GROUP(N_("Config file location")),
@@ -80,6 +81,7 @@ static struct option builtin_config_options[] = {
81
OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT),
82
OPT_BIT(0, "bool-or-int", &types, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
83
OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
84
+ OPT_BIT(0, "expiry-date", &types, N_("value is an expiry date"), TYPE_EXPIRY_DATE),
85
OPT_GROUP(N_("Other")),
86
OPT_BOOL('z', "null", &end_null, N_("terminate values with NUL byte")),
87
OPT_BOOL(0, "name-only", &omit_values, N_("show variable names only")),
@@ -159,6 +161,11 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
161
return -1;
162
strbuf_addstr(buf, v);
163
free((char *)v);
164
+ } else if (types == TYPE_EXPIRY_DATE) {
165
+ timestamp_t t;
166
+ if (git_config_expiry_date(&t, key_, value_) < 0)
167
+ return -1;
168
+ strbuf_addf(buf, "%"PRItime, t);
169
} else if (value_) {
170
strbuf_addstr(buf, value_);
171
} else {
@@ -273,12 +280,13 @@ static char *normalize_value(const char *key, const char *value)
280
if (!value)
281
return NULL;
282
276
- if (types == 0 || types == TYPE_PATH)
283
+ if (types == 0 || types == TYPE_PATH || types == TYPE_EXPIRY_DATE)
284
/*
285
* We don't do normalization for TYPE_PATH here: If
286
* the path is like ~/foobar/, we prefer to store
287
* "~/foobar/" in the config file, and to expand the ~
288
* when retrieving the value.
289
+ * Also don't do normalization for expiry dates.
290
*/
291
return xstrdup(value);
292
if (types == TYPE_INT)
builtin/reflog.c
+2
-12
@@ -416,16 +416,6 @@ static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
416
return ent;
417
}
418
419
-static int parse_expire_cfg_value(const char *var, const char *value, timestamp_t *expire)
420
-{
421
- if (!value)
422
- return config_error_nonbool(var);
423
- if (parse_expiry_date(value, expire))
424
- return error(_("'%s' for '%s' is not a valid timestamp"),
425
- value, var);
426
- return 0;
427
-}
428
-
419
/* expiry timer slot */
420
#define EXPIRE_TOTAL 01
421
#define EXPIRE_UNREACH 02
@@ -443,11 +433,11 @@ static int reflog_expire_config(const char *var, const char *value, void *cb)
433
434
if (!strcmp(key, "reflogexpire")) {
435
slot = EXPIRE_TOTAL;
446
- if (parse_expire_cfg_value(var, value, &expire))
436
+ if (git_config_expiry_date(&expire, var, value))
437
return -1;
438
} else if (!strcmp(key, "reflogexpireunreachable")) {
439
slot = EXPIRE_UNREACH;
450
- if (parse_expire_cfg_value(var, value, &expire))
440
+ if (git_config_expiry_date(&expire, var, value))
441
return -1;
442
} else
443
return git_default_config(var, value, cb);
config.c
+10
@@ -990,6 +990,16 @@ int git_config_pathname(const char **dest, const char *var, const char *value)
990
return 0;
991
}
992
993
+int git_config_expiry_date(timestamp_t *timestamp, const char *var, const char *value)
994
+{
995
+ if (!value)
996
+ return config_error_nonbool(var);
997
+ if (parse_expiry_date(value, timestamp))
998
+ return error(_("'%s' for '%s' is not a valid timestamp"),
999
+ value, var);
1000
+ return 0;
1001
+}
1002
+
1003
static int git_default_core_config(const char *var, const char *value)
1004
{
1005
/* This needs a better name */
config.h
+1
@@ -58,6 +58,7 @@ extern int git_config_bool_or_int(const char *, const char *, int *);
58
extern int git_config_bool(const char *, const char *);
59
extern int git_config_string(const char **, const char *, const char *);
60
extern int git_config_pathname(const char **, const char *, const char *);
61
+extern int git_config_expiry_date(timestamp_t *, const char *, const char *);
62
extern int git_config_set_in_file_gently(const char *, const char *, const char *);
63
extern void git_config_set_in_file(const char *, const char *, const char *);
64
extern int git_config_set_gently(const char *, const char *);
t/helper/test-date.c
+12
@@ -5,6 +5,7 @@ static const char *usage_msg = "\n"
5
" test-date show:<format> [time_t]...\n"
6
" test-date parse [date]...\n"
7
" test-date approxidate [date]...\n"
8
+" test-date timestamp [date]...\n"
9
" test-date is64bit\n"
10
" test-date time_t-is64bit\n";
11
@@ -71,6 +72,15 @@ static void parse_approxidate(const char **argv, struct timeval *now)
72
}
73
}
74
75
+static void parse_approx_timestamp(const char **argv, struct timeval *now)
76
+{
77
+ for (; *argv; argv++) {
78
+ timestamp_t t;
79
+ t = approxidate_relative(*argv, now);
80
+ printf("%s -> %"PRItime"\n", *argv, t);
81
+ }
82
+}
83
+
84
int cmd_main(int argc, const char **argv)
85
{
86
struct timeval now;
@@ -95,6 +105,8 @@ int cmd_main(int argc, const char **argv)
105
parse_dates(argv+1, &now);
106
else if (!strcmp(*argv, "approxidate"))
107
parse_approxidate(argv+1, &now);
108
+ else if (!strcmp(*argv, "timestamp"))
109
+ parse_approx_timestamp(argv+1, &now);
110
else if (!strcmp(*argv, "is64bit"))
111
return sizeof(timestamp_t) == 8 ? 0 : 1;
112
else if (!strcmp(*argv, "time_t-is64bit"))
t/t1300-repo-config.sh
+30
@@ -901,6 +901,36 @@ test_expect_success 'get --path barfs on boolean variable' '
901
test_must_fail git config --get --path path.bool
902
'
903
904
+test_expect_success 'get --expiry-date' '
905
+ rel="3.weeks.5.days.00:00" &&
906
+ rel_out="$rel ->" &&
907
+ cat >.git/config <<-\EOF &&
908
+ [date]
909
+ valid1 = "3.weeks.5.days 00:00"
910
+ valid2 = "Fri Jun 4 15:46:55 2010"
911
+ valid3 = "2017/11/11 11:11:11PM"
912
+ valid4 = "2017/11/10 09:08:07 PM"
913
+ valid5 = "never"
914
+ invalid1 = "abc"
915
+ EOF
916
+ cat >expect <<-EOF &&
917
+ $(test-date timestamp $rel)
918
+ 1275666415
919
+ 1510441871
920
+ 1510348087
921
+ 0
922
+ EOF
923
+ {
924
+ echo "$rel_out $(git config --expiry-date date.valid1)"
925
+ git config --expiry-date date.valid2 &&
926
+ git config --expiry-date date.valid3 &&
927
+ git config --expiry-date date.valid4 &&
928
+ git config --expiry-date date.valid5
929
+ } >actual &&
930
+ test_cmp expect actual &&
931
+ test_must_fail git config --expiry-date date.invalid1
932
+'
933
+
934
cat > expect << EOF
935
[quote]
936
leading = " test"