fsmonitor: layer on another hack in bser.c for os.stat() compat (
issue5811)
It's unclear to me how these `bserobj_tuple` objects are used, other
than as stat objects. This should fix fsmonitor in the wake of
ffa3026d4196 and similar changes. I regret the hack here, but the code
already has plenty of hg-specific hacks. :(
It feels like we should be able to use int(result.st_mtime) globally,
but that doesn't work. See
issue4836 for a bug that was hard to track
down relating to rounding behavior causing very subtle dirstate
problems.
Differential Revision: https://phab.mercurial-scm.org/D2939
--- a/hgext/fsmonitor/pywatchman/bser.c Wed Apr 11 17:24:38 2018 -0400
+++ b/hgext/fsmonitor/pywatchman/bser.c Sat Mar 24 14:28:24 2018 -0400
@@ -128,27 +128,38 @@
Py_ssize_t i, n;
PyObject* name_bytes = NULL;
PyObject* ret = NULL;
- const char* namestr;
+ const char* namestr = NULL;
if (PyIndex_Check(name)) {
i = PyNumber_AsSsize_t(name, PyExc_IndexError);
if (i == -1 && PyErr_Occurred()) {
goto bail;
}
- ret = PySequence_GetItem(obj->values, i);
- goto bail;
- }
- // We can be passed in Unicode objects here -- we don't support anything other
- // than UTF-8 for keys.
- if (PyUnicode_Check(name)) {
- name_bytes = PyUnicode_AsUTF8String(name);
- if (name_bytes == NULL) {
+ if (i == 8 && PySequence_Size(obj->values) < 9) {
+ // Hack alert: Python 3 removed support for os.stat().st_mtime
+ // being an integer.Instead, if you need an integer, you have to
+ // use os.stat()[stat.ST_MTIME] instead. stat.ST_MTIME is 8, and
+ // our stat tuples are shorter than that, so we can detect
+ // requests for index 8 on tuples shorter than that and return
+ // st_mtime instead.
+ namestr = "st_mtime";
+ } else {
+ ret = PySequence_GetItem(obj->values, i);
goto bail;
}
- namestr = PyBytes_AsString(name_bytes);
} else {
- namestr = PyBytes_AsString(name);
+ // We can be passed in Unicode objects here -- we don't support anything other
+ // than UTF-8 for keys.
+ if (PyUnicode_Check(name)) {
+ name_bytes = PyUnicode_AsUTF8String(name);
+ if (name_bytes == NULL) {
+ goto bail;
+ }
+ namestr = PyBytes_AsString(name_bytes);
+ } else {
+ namestr = PyBytes_AsString(name);
+ }
}
if (namestr == NULL) {