core-lightning/common/deprecation.c
Rusty Russell 94a539ee3d Makefile: add CLN_NEXT_VERSION, functions encoding deprecation schedule.
Each feature has a name, and says when deprecation begins and ends.

There's an API coming to allow you to re-enable on a per-feature basis
even if it's ended (as long as it's not been removed from the code ofc!).

Default end is 6 months after deprecation, i.e. we complain about it
at that point, if we can detect its use.

e.g, a standard deprecation in v24.05:

v24.02: allowed
v24.02 with mods: allowed

master after v24.02: allowed unless deprecated APIs disabled.
v24.05: allowed unless deprecated APIs disabled.
v24.08: allowed unless deprecated APIs disabled.

v24.11: allowed unless deprecated APIs disabled, but logs at BROKEN level.

v25.02: allowed only if --i-promise-to-fix-broken-api-user=FEATURE.
v25.05: code is actually removed.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2024-01-26 10:30:22 +10:30

148 lines
3.2 KiB
C

#include "config.h"
#include <assert.h>
#include <ccan/str/str.h>
#include <ccan/tal/tal.h>
#include <common/deprecation.h>
#include <stdlib.h>
#define MONTH_VAL (10)
#define YEAR_VAL (12 * MONTH_VAL)
/* Returns 1 + patchnumber + 10*minor + 120*major. 0 on malformed */
u32 version_to_number(const char *version)
{
char *yend, *mend;
long year, month, patchlevel;
if (version[0] != 'v')
return 0;
year = strtol(version + 1, &yend, 10);
if (yend == version + 1 || *yend != '.')
return 0;
if (year > 99)
return 0;
month = strtol(yend + 1, &mend, 10);
if (mend == yend + 1)
return 0;
if (month < 1 || month > 12)
return 0;
if (*mend == '.') {
char *endp;
patchlevel = strtol(mend + 1, &endp, 10);
if (endp == mend + 1)
return 0;
if (patchlevel >= MONTH_VAL)
return 0;
} else
patchlevel = 0;
return 1 + year*YEAR_VAL + month*MONTH_VAL + patchlevel;
}
enum deprecation_level {
/* Will be deprecated in future */
DEPRECATED_SOON,
/* Deprecated, but still ok unless explicitly disabled */
DEPRECATED,
/* Deprecated, and we whine about it */
DEPRECATED_COMPLAIN,
/* Deprecated, and we only enable it if they begged */
DEPRECATED_BEG,
};
static enum deprecation_level deprecation(const char *start,
const char *end)
{
long cur;
long startnum;
long endnum;
/* Versions are hard. Consider these:
* v23.05
* -- A released version
* v23.05rc1
* -- A release candidate
* v23.05rc4-11-g1e96146
* -- Development off rc4, OR a user's local mods.
* v23.05-1-gf165dc0-modded
* -- Development off 23.05, OR a user's local mods.
*/
/* If master has moved since release, we want to increment
* deprecations. If a user has made local mods, we don't!
* Fortunately, the Makefile sets "CLN_NEXT_VERSION", and
* we can simply use this.
*/
cur = version_to_number(CLN_NEXT_VERSION);
assert(cur);
startnum = version_to_number(start);
assert(startnum);
if (end) {
endnum = version_to_number(end);
assert(endnum);
assert(endnum >= startnum);
} else /* 6 months later */
endnum = startnum + 6 * MONTH_VAL;
if (cur < startnum)
return DEPRECATED_SOON;
if (cur < endnum)
return DEPRECATED;
if (cur == endnum)
return DEPRECATED_COMPLAIN;
return DEPRECATED_BEG;
}
bool deprecated_ok_(bool deprecated_apis,
const char *feature,
const char *start,
const char *end,
const char **begs,
void (*complain)(const char *feature, bool allowing, void *cbarg),
void *cbarg)
{
enum deprecation_level level;
bool allow;
/* Not deprecated at all? */
if (!start)
return true;
level = deprecation(start, end);
switch (level) {
case DEPRECATED_SOON:
return false;
case DEPRECATED:
/* Complain if we're disallowing becuase it's deprecated */
allow = deprecated_apis;
if (!allow)
goto complain;
goto no_complain;
case DEPRECATED_COMPLAIN:
allow = deprecated_apis;
/* Always complain about these! */
goto complain;
case DEPRECATED_BEG:
allow = false;
for (size_t i = 0; i < tal_count(begs); i++) {
if (streq(feature, begs[i]))
allow = true;
}
/* Don't complain about begging: they've explicitly noted this! */
if (allow)
goto no_complain;
goto complain;
}
abort();
complain:
if (complain)
complain(feature, allow, cbarg);
no_complain:
return allow;
}