2018-03-24 07:44:36 +00:00
|
|
|
#include "test-tool.h"
|
date API: create a date.h, split from cache.h
Move the declaration of the date.c functions from cache.h, and adjust
the relevant users to include the new date.h header.
The show_ident_date() function belonged in pretty.h (it's defined in
pretty.c), its two users outside of pretty.c didn't strictly need to
include pretty.h, as they get it indirectly, but let's add it to them
anyway.
Similarly, the change to "builtin/{fast-import,show-branch,tag}.c"
isn't needed as far as the compiler is concerned, but since they all
use the "DATE_MODE()" macro we now define in date.h, let's have them
include it.
We could simply include this new header in "cache.h", but as this
change shows these functions weren't common enough to warrant
including in it in the first place. By moving them out of cache.h
changes to this API will no longer cause a (mostly) full re-build of
the project when "make" is run.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-02-16 08:14:02 +00:00
|
|
|
#include "date.h"
|
2023-04-11 03:00:38 +00:00
|
|
|
#include "trace.h"
|
2005-04-30 20:19:56 +00:00
|
|
|
|
2009-08-31 02:26:46 +00:00
|
|
|
static const char *usage_msg = "\n"
|
2018-03-24 07:44:36 +00:00
|
|
|
" test-tool date relative [time_t]...\n"
|
2019-01-29 03:50:15 +00:00
|
|
|
" test-tool date human [time_t]...\n"
|
2018-03-24 07:44:36 +00:00
|
|
|
" test-tool date show:<format> [time_t]...\n"
|
|
|
|
" test-tool date parse [date]...\n"
|
|
|
|
" test-tool date approxidate [date]...\n"
|
|
|
|
" test-tool date timestamp [date]...\n"
|
test-date: add a subcommand to measure times in shell scripts
In the next commit, we want to teach Git's test suite to optionally
output test results in JUnit-style .xml files. These files contain
information about the time spent. So we need a way to measure time.
While we could use `date +%s` for that, this will give us only seconds,
i.e. very coarse-grained timings.
GNU `date` supports `date +%s.%N` (i.e. nanosecond-precision output),
but there is no equivalent in BSD `date` (read: on macOS, we would not
be able to obtain precise timings).
So let's introduce `test-tool date getnanos`, with an optional start
time, that outputs preciser values. Note that this might not actually
give us nanosecond precision on some platforms, but it will give us as
precise information as possible, without the portability issues of shell
commands.
Granted, it is a bit pointless to try measuring times accurately in
shell scripts, certainly to nanosecond precision. But it is better than
second-granularity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-01-27 23:26:54 +00:00
|
|
|
" test-tool date getnanos [start-nanos]\n"
|
2018-03-24 07:44:36 +00:00
|
|
|
" test-tool date is64bit\n"
|
|
|
|
" test-tool date time_t-is64bit\n";
|
2009-08-31 02:26:46 +00:00
|
|
|
|
2019-09-12 04:11:01 +00:00
|
|
|
static void show_relative_dates(const char **argv)
|
2005-04-30 20:19:56 +00:00
|
|
|
{
|
2012-04-23 12:30:23 +00:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2009-08-31 02:26:46 +00:00
|
|
|
|
|
|
|
for (; *argv; argv++) {
|
|
|
|
time_t t = atoi(*argv);
|
2019-09-12 04:11:01 +00:00
|
|
|
show_date_relative(t, &buf);
|
2012-04-23 12:30:23 +00:00
|
|
|
printf("%s -> %s\n", *argv, buf.buf);
|
2009-08-31 02:26:46 +00:00
|
|
|
}
|
2012-04-23 12:30:23 +00:00
|
|
|
strbuf_release(&buf);
|
2009-08-31 02:26:46 +00:00
|
|
|
}
|
2005-04-30 20:19:56 +00:00
|
|
|
|
2019-01-29 03:50:15 +00:00
|
|
|
static void show_human_dates(const char **argv)
|
|
|
|
{
|
|
|
|
for (; *argv; argv++) {
|
|
|
|
time_t t = atoi(*argv);
|
|
|
|
printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(HUMAN)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-19 20:22:19 +00:00
|
|
|
static void show_dates(const char **argv, const char *format)
|
2016-06-20 21:11:59 +00:00
|
|
|
{
|
2022-02-16 08:14:03 +00:00
|
|
|
struct date_mode mode = DATE_MODE_INIT;
|
2016-06-20 21:11:59 +00:00
|
|
|
|
|
|
|
parse_date_format(format, &mode);
|
|
|
|
for (; *argv; argv++) {
|
2016-07-19 20:22:19 +00:00
|
|
|
char *arg;
|
2017-04-26 19:29:31 +00:00
|
|
|
timestamp_t t;
|
2016-06-20 21:11:59 +00:00
|
|
|
int tz;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not use our normal timestamp parsing here, as the point
|
|
|
|
* is to test the formatting code in isolation.
|
|
|
|
*/
|
2017-04-21 10:45:44 +00:00
|
|
|
t = parse_timestamp(*argv, &arg, 10);
|
2016-06-20 21:11:59 +00:00
|
|
|
while (*arg == ' ')
|
|
|
|
arg++;
|
|
|
|
tz = atoi(arg);
|
|
|
|
|
|
|
|
printf("%s -> %s\n", *argv, show_date(t, tz, &mode));
|
|
|
|
}
|
2022-02-16 08:14:05 +00:00
|
|
|
|
|
|
|
date_mode_release(&mode);
|
2016-06-20 21:11:59 +00:00
|
|
|
}
|
|
|
|
|
2019-03-20 08:14:30 +00:00
|
|
|
static void parse_dates(const char **argv)
|
2009-08-31 02:26:46 +00:00
|
|
|
{
|
2014-08-27 07:57:08 +00:00
|
|
|
struct strbuf result = STRBUF_INIT;
|
|
|
|
|
2009-08-31 02:26:46 +00:00
|
|
|
for (; *argv; argv++) {
|
2017-04-26 19:29:31 +00:00
|
|
|
timestamp_t t;
|
2010-07-04 10:48:35 +00:00
|
|
|
int tz;
|
2005-04-30 20:19:56 +00:00
|
|
|
|
2014-08-27 07:57:08 +00:00
|
|
|
strbuf_reset(&result);
|
|
|
|
parse_date(*argv, &result);
|
2017-04-21 10:45:48 +00:00
|
|
|
if (sscanf(result.buf, "%"PRItime" %d", &t, &tz) == 2)
|
2010-07-04 10:48:35 +00:00
|
|
|
printf("%s -> %s\n",
|
convert "enum date_mode" into a struct
In preparation for adding date modes that may carry extra
information beyond the mode itself, this patch converts the
date_mode enum into a struct.
Most of the conversion is fairly straightforward; we pass
the struct as a pointer and dereference the type field where
necessary. Locations that declare a date_mode can use a "{}"
constructor. However, the tricky case is where we use the
enum labels as constants, like:
show_date(t, tz, DATE_NORMAL);
Ideally we could say:
show_date(t, tz, &{ DATE_NORMAL });
but of course C does not allow that. Likewise, we cannot
cast the constant to a struct, because we need to pass an
actual address. Our options are basically:
1. Manually add a "struct date_mode d = { DATE_NORMAL }"
definition to each caller, and pass "&d". This makes
the callers uglier, because they sometimes do not even
have their own scope (e.g., they are inside a switch
statement).
2. Provide a pre-made global "date_normal" struct that can
be passed by address. We'd also need "date_rfc2822",
"date_iso8601", and so forth. But at least the ugliness
is defined in one place.
3. Provide a wrapper that generates the correct struct on
the fly. The big downside is that we end up pointing to
a single global, which makes our wrapper non-reentrant.
But show_date is already not reentrant, so it does not
matter.
This patch implements 3, along with a minor macro to keep
the size of the callers sane.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-25 16:55:02 +00:00
|
|
|
*argv, show_date(t, tz, DATE_MODE(ISO8601)));
|
2010-07-04 10:48:35 +00:00
|
|
|
else
|
|
|
|
printf("%s -> bad\n", *argv);
|
2009-08-31 02:26:46 +00:00
|
|
|
}
|
2014-08-27 07:57:08 +00:00
|
|
|
strbuf_release(&result);
|
2009-08-31 02:26:46 +00:00
|
|
|
}
|
2005-11-15 08:07:04 +00:00
|
|
|
|
2019-09-12 04:11:01 +00:00
|
|
|
static void parse_approxidate(const char **argv)
|
2009-08-31 02:26:46 +00:00
|
|
|
{
|
|
|
|
for (; *argv; argv++) {
|
2017-04-26 19:29:31 +00:00
|
|
|
timestamp_t t;
|
2023-04-08 09:35:24 +00:00
|
|
|
t = approxidate(*argv);
|
convert "enum date_mode" into a struct
In preparation for adding date modes that may carry extra
information beyond the mode itself, this patch converts the
date_mode enum into a struct.
Most of the conversion is fairly straightforward; we pass
the struct as a pointer and dereference the type field where
necessary. Locations that declare a date_mode can use a "{}"
constructor. However, the tricky case is where we use the
enum labels as constants, like:
show_date(t, tz, DATE_NORMAL);
Ideally we could say:
show_date(t, tz, &{ DATE_NORMAL });
but of course C does not allow that. Likewise, we cannot
cast the constant to a struct, because we need to pass an
actual address. Our options are basically:
1. Manually add a "struct date_mode d = { DATE_NORMAL }"
definition to each caller, and pass "&d". This makes
the callers uglier, because they sometimes do not even
have their own scope (e.g., they are inside a switch
statement).
2. Provide a pre-made global "date_normal" struct that can
be passed by address. We'd also need "date_rfc2822",
"date_iso8601", and so forth. But at least the ugliness
is defined in one place.
3. Provide a wrapper that generates the correct struct on
the fly. The big downside is that we end up pointing to
a single global, which makes our wrapper non-reentrant.
But show_date is already not reentrant, so it does not
matter.
This patch implements 3, along with a minor macro to keep
the size of the callers sane.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-25 16:55:02 +00:00
|
|
|
printf("%s -> %s\n", *argv, show_date(t, 0, DATE_MODE(ISO8601)));
|
2009-08-31 02:26:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-12 04:11:01 +00:00
|
|
|
static void parse_approx_timestamp(const char **argv)
|
2017-11-18 02:27:27 +00:00
|
|
|
{
|
|
|
|
for (; *argv; argv++) {
|
|
|
|
timestamp_t t;
|
2023-04-08 09:35:24 +00:00
|
|
|
t = approxidate(*argv);
|
2017-11-18 02:27:27 +00:00
|
|
|
printf("%s -> %"PRItime"\n", *argv, t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 19:35:52 +00:00
|
|
|
static void getnanos(const char **argv)
|
test-date: add a subcommand to measure times in shell scripts
In the next commit, we want to teach Git's test suite to optionally
output test results in JUnit-style .xml files. These files contain
information about the time spent. So we need a way to measure time.
While we could use `date +%s` for that, this will give us only seconds,
i.e. very coarse-grained timings.
GNU `date` supports `date +%s.%N` (i.e. nanosecond-precision output),
but there is no equivalent in BSD `date` (read: on macOS, we would not
be able to obtain precise timings).
So let's introduce `test-tool date getnanos`, with an optional start
time, that outputs preciser values. Note that this might not actually
give us nanosecond precision on some platforms, but it will give us as
precise information as possible, without the portability issues of shell
commands.
Granted, it is a bit pointless to try measuring times accurately in
shell scripts, certainly to nanosecond precision. But it is better than
second-granularity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-01-27 23:26:54 +00:00
|
|
|
{
|
|
|
|
double seconds = getnanotime() / 1.0e9;
|
|
|
|
|
|
|
|
if (*argv)
|
|
|
|
seconds -= strtod(*argv, NULL);
|
|
|
|
printf("%lf\n", seconds);
|
|
|
|
}
|
|
|
|
|
2023-03-28 20:57:25 +00:00
|
|
|
int cmd__date(int argc UNUSED, const char **argv)
|
2009-08-31 02:26:46 +00:00
|
|
|
{
|
|
|
|
const char *x;
|
|
|
|
|
|
|
|
argv++;
|
|
|
|
if (!*argv)
|
|
|
|
usage(usage_msg);
|
2016-06-20 21:10:29 +00:00
|
|
|
if (!strcmp(*argv, "relative"))
|
2019-09-12 04:11:01 +00:00
|
|
|
show_relative_dates(argv+1);
|
2019-01-29 03:50:15 +00:00
|
|
|
else if (!strcmp(*argv, "human"))
|
|
|
|
show_human_dates(argv+1);
|
2016-06-20 21:11:59 +00:00
|
|
|
else if (skip_prefix(*argv, "show:", &x))
|
|
|
|
show_dates(argv+1, x);
|
2009-08-31 02:26:46 +00:00
|
|
|
else if (!strcmp(*argv, "parse"))
|
2019-03-20 08:14:30 +00:00
|
|
|
parse_dates(argv+1);
|
2009-08-31 02:26:46 +00:00
|
|
|
else if (!strcmp(*argv, "approxidate"))
|
2019-09-12 04:11:01 +00:00
|
|
|
parse_approxidate(argv+1);
|
2017-11-18 02:27:27 +00:00
|
|
|
else if (!strcmp(*argv, "timestamp"))
|
2019-09-12 04:11:01 +00:00
|
|
|
parse_approx_timestamp(argv+1);
|
test-date: add a subcommand to measure times in shell scripts
In the next commit, we want to teach Git's test suite to optionally
output test results in JUnit-style .xml files. These files contain
information about the time spent. So we need a way to measure time.
While we could use `date +%s` for that, this will give us only seconds,
i.e. very coarse-grained timings.
GNU `date` supports `date +%s.%N` (i.e. nanosecond-precision output),
but there is no equivalent in BSD `date` (read: on macOS, we would not
be able to obtain precise timings).
So let's introduce `test-tool date getnanos`, with an optional start
time, that outputs preciser values. Note that this might not actually
give us nanosecond precision on some platforms, but it will give us as
precise information as possible, without the portability issues of shell
commands.
Granted, it is a bit pointless to try measuring times accurately in
shell scripts, certainly to nanosecond precision. But it is better than
second-granularity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-01-27 23:26:54 +00:00
|
|
|
else if (!strcmp(*argv, "getnanos"))
|
2019-02-06 19:35:52 +00:00
|
|
|
getnanos(argv+1);
|
t0006 & t5000: prepare for 64-bit timestamps
Git's source code refers to timestamps as unsigned longs. On 32-bit
platforms, as well as on Windows, unsigned long is not large enough to
capture dates that are "absurdly far in the future".
It is perfectly valid by the C standard, of course, for the `long` data
type to refer to 32-bit integers. That is why the `time_t` data type
exists: so that it can be 64-bit even if `long` is 32-bit. Git's source
code simply uses an incorrect data type for timestamps, is all.
The earlier quick fix 6b9c38e14cd (t0006: skip "far in the future" test
when unsigned long is not long enough, 2016-07-11) papered over this
issue simply by skipping the respective test cases on platforms where
they would fail due to the data type in use.
This quick fix, however, tests for *long* to be 64-bit or not. What we
need, though, is a test that says whether *whatever data type we use for
timestamps* is 64-bit or not.
The same quick fix was used to handle the similar problem where Git's
source code uses `unsigned long` to represent size, instead of `size_t`,
conflating the two issues.
So let's just add another prerequisite to test specifically whether
timestamps are represented by a 64-bit data type or not. Later, after we
switch to a larger data type, we can flip that prerequisite to test
`time_t` instead of `long`.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-04-20 20:52:13 +00:00
|
|
|
else if (!strcmp(*argv, "is64bit"))
|
2017-04-26 19:29:31 +00:00
|
|
|
return sizeof(timestamp_t) == 8 ? 0 : 1;
|
2017-04-20 20:58:21 +00:00
|
|
|
else if (!strcmp(*argv, "time_t-is64bit"))
|
|
|
|
return sizeof(time_t) == 8 ? 0 : 1;
|
2009-08-31 02:26:46 +00:00
|
|
|
else
|
|
|
|
usage(usage_msg);
|
2005-04-30 20:19:56 +00:00
|
|
|
return 0;
|
|
|
|
}
|