From de827b14628b130d4b5c8b3b8660da2964ef849d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Sun, 14 Apr 2024 19:35:08 +0200 Subject: [PATCH 1/3] feat: bump to libfaketime 0.9.10 - update to libfaketime 0.9.10 - the libfaketime submodules points to the upstream - apply a patch on build - run GHA on macos 12, 13 and 14 --- .github/workflows/tests.yaml | 21 ++++++++----- .gitmodules | 6 +--- MANIFEST.in | 5 --- README.md | 3 ++ libfaketime/__init__.py | 10 ++---- libfaketime/vendor/libfaketime | 2 +- libfaketime/vendor/libfaketime-pre_sierra | 1 - libfaketime/vendor/libfaketime.patch | 38 +++++++++++++++++++++++ setup.py | 14 +-------- 9 files changed, 60 insertions(+), 40 deletions(-) delete mode 160000 libfaketime/vendor/libfaketime-pre_sierra create mode 100644 libfaketime/vendor/libfaketime.patch diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 544b516..d114212 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -6,11 +6,16 @@ on: jobs: tests: - name: ${{ matrix.python }} - runs-on: ubuntu-latest + name: ${{ matrix.os }} - python${{ matrix.python }} - ${{ matrix.tz }} + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: + os: + - ubuntu-22.04 + - macos-14 + - macos-13 + - macos-12 python: - '3.12' - '3.11' @@ -21,15 +26,17 @@ jobs: - 'utc' - 'cest' steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - - uses: actions/cache@v1 + - uses: actions/cache@v4 with: path: ~/.cache/pip key: pip|${{ hashFiles('setup.py') }}|${{ hashFiles('setup.cfg') }} - run: pip install tox - - run: git submodule update --init - - run: make -C libfaketime/vendor/libfaketime + - run: git submodule update --init --force + - run: | + git apply --directory libfaketime/vendor/libfaketime libfaketime/vendor/libfaketime.patch + make -C libfaketime/vendor/libfaketime - run: tox -e ${{ matrix.python }}-${{ matrix.tz }} diff --git a/.gitmodules b/.gitmodules index 51214e3..f0ed0ea 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,8 +1,4 @@ [submodule "vendor/libfaketime"] path = libfaketime/vendor/libfaketime - url = https://github.com/simon-weber/libfaketime.git + url = https://github.com/wolfcw/libfaketime.git branch = python-libfaketime -[submodule "vendor/libfaketime-pre_sierra"] - path = libfaketime/vendor/libfaketime-pre_sierra - url = https://github.com/simon-weber/libfaketime.git - branch = python-libfaketime-pre_sierra diff --git a/MANIFEST.in b/MANIFEST.in index e8e8bb2..c7dbb74 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,8 +5,3 @@ include libfaketime/vendor/libfaketime/src/Makefile include libfaketime/vendor/libfaketime/src/Makefile.OSX include libfaketime/vendor/libfaketime/COPYING recursive-include libfaketime/vendor/libfaketime/src *.c *.h *.map -include libfaketime/vendor/libfaketime-pre_sierra/Makefile -include libfaketime/vendor/libfaketime-pre_sierra/src/Makefile -include libfaketime/vendor/libfaketime-pre_sierra/src/Makefile.OSX -include libfaketime/vendor/libfaketime-pre_sierra/COPYING -recursive-include libfaketime/vendor/libfaketime-pre_sierra/src *.c *.h *.map diff --git a/README.md b/README.md index 2bbc636..6b08c38 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,7 @@ In some cases - especially when your tests start other processes - re-execing ca $ python-libfaketime export LD_PRELOAD="/home/foo//vendor/libfaketime/src/libfaketime.so.1" export DONT_FAKE_MONOTONIC="1" +export FAKETIME_NO_CACHE="1" export FAKETIME_DID_REEXEC=true ``` @@ -163,6 +164,8 @@ Contributing and testing Contributions are welcome! You should compile libfaketime before running tests: ```bash +git submodule init --update +git apply --directory libfaketime/vendor/libfaketime libfaketime/vendor/libfaketime.patch make -C libfaketime/vendor/libfaketime ``` diff --git a/libfaketime/__init__.py b/libfaketime/__init__.py index b82bb72..182ecc0 100644 --- a/libfaketime/__init__.py +++ b/libfaketime/__init__.py @@ -6,7 +6,6 @@ import functools import inspect import os -import platform import sys import threading import time @@ -21,7 +20,6 @@ basestring = (str, bytes) -SIERRA_VERSION_TUPLE = (10, 12) # When using reexec_if_needed, remove_vars=True and a test loader that purges sys.modules # (like nose), it can be tough to run reexec_if_needed only once. @@ -33,12 +31,6 @@ def _get_lib_path(): vendor_dir = 'libfaketime' - if sys.platform == "darwin": - version_tuple = tuple(int(x) for x in platform.mac_ver()[0].split('.')) - pre_sierra = version_tuple < SIERRA_VERSION_TUPLE - if pre_sierra: - vendor_dir = 'libfaketime-pre_sierra' - return os.path.join( os.path.dirname(__file__), os.path.join('vendor', vendor_dir, 'src')) @@ -71,10 +63,12 @@ def _setup_ld_preload(soname): _other_additions = { 'linux': { 'DONT_FAKE_MONOTONIC': '1', + 'FAKETIME_NO_CACHE': '1', }, 'darwi': { 'DONT_FAKE_MONOTONIC': '1', 'DYLD_FORCE_FLAT_NAMESPACE': '1', + 'FAKETIME_NO_CACHE': '1', }, } diff --git a/libfaketime/vendor/libfaketime b/libfaketime/vendor/libfaketime index d9d2bd7..d475b92 160000 --- a/libfaketime/vendor/libfaketime +++ b/libfaketime/vendor/libfaketime @@ -1 +1 @@ -Subproject commit d9d2bd76f00f95e9409e4a53d0469aef0e988a0b +Subproject commit d475b925943ad404c6c728ac868dc73949e7281c diff --git a/libfaketime/vendor/libfaketime-pre_sierra b/libfaketime/vendor/libfaketime-pre_sierra deleted file mode 160000 index 83c997b..0000000 --- a/libfaketime/vendor/libfaketime-pre_sierra +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 83c997b9c11b437ec5791387045c0364626649df diff --git a/libfaketime/vendor/libfaketime.patch b/libfaketime/vendor/libfaketime.patch new file mode 100644 index 0000000..e5b44d7 --- /dev/null +++ b/libfaketime/vendor/libfaketime.patch @@ -0,0 +1,38 @@ +diff --git a/src/Makefile b/src/Makefile +index 62e924c..6f03e26 100644 +--- a/src/Makefile ++++ b/src/Makefile +@@ -110,7 +110,7 @@ PREFIX ?= /usr/local + LIBDIRNAME ?= /lib/faketime + PLATFORM ?=$(shell uname) + +-CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -DFAKE_PTHREAD -DFAKE_STAT -DFAKE_UTIME -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"' $(FAKETIME_COMPILE_CFLAGS) ++CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -DFAKE_PTHREAD -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"' $(FAKETIME_COMPILE_CFLAGS) + ifeq ($(PLATFORM),SunOS) + CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 + endif +diff --git a/src/libfaketime.c b/src/libfaketime.c +index e632395..09d9019 100644 +--- a/src/libfaketime.c ++++ b/src/libfaketime.c +@@ -2384,10 +2384,16 @@ static void parse_ft_string(const char *user_faked_time) + user_faked_time_tm.tm_isdst = -1; + nstime_str = strptime(user_faked_time, user_faked_time_fmt, &user_faked_time_tm); + ++ /* the actual format has a " %f" appended. Parse out the microseconds. */ ++ char nanosecond_str[7]; ++ memcpy(&nanosecond_str, user_faked_time + 20, 6); ++ nanosecond_str[6] = '\0'; ++ int nanoseconds = atoi(nanosecond_str) * 1000; ++ + if (NULL != nstime_str) + { + user_faked_time_timespec.tv_sec = mktime(&user_faked_time_tm); +- user_faked_time_timespec.tv_nsec = 0; ++ user_faked_time_timespec.tv_nsec = nanoseconds; + + if (nstime_str[0] == '.') + { +-- +2.45.0 + diff --git a/setup.py b/setup.py index 4f28d7a..b479ab8 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,6 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- import os -import platform import re from setuptools import setup, find_packages from setuptools.command.install import install @@ -10,10 +8,6 @@ import sys -# libfaketime broke compatibility with osx before sierra. -# We keep a separate submodule for each and choose between them dynamically. -SIERRA_VERSION_TUPLE = (10, 12) - # This hack is from http://stackoverflow.com/a/7071358/1231454; # the version is kept in a seperate file and gets parsed - this # way, setup.py doesn't have to import the package. @@ -35,13 +29,6 @@ elif sys.platform == "darwin": libname = 'libfaketime.1.dylib' - version_tuple = tuple(int(x) for x in platform.mac_ver()[0].split('.')) - pre_sierra = version_tuple < SIERRA_VERSION_TUPLE - if pre_sierra: - _vendor_path = 'libfaketime/vendor/libfaketime-pre_sierra' - - print("OSX version is %s-sierra: %r" % ('pre' if pre_sierra else 'post', version_tuple)) - else: raise RuntimeError("libfaketime does not support platform %s" % sys.platform) @@ -51,6 +38,7 @@ class CustomInstall(install): def run(self): self.my_outputs = [] + subprocess.check_call(['patch', '-p1', '<', '../libfaketime.patch'], cwd=_vendor_path, shell=True) subprocess.check_call(['make', '-C', _vendor_path]) dest = os.path.join(self.install_purelib, os.path.dirname(faketime_lib)) From 4ea08c5afed641f947e5f1bb5c4ed3022ba3a9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 30 Apr 2024 20:59:51 +0200 Subject: [PATCH 2/3] refactor: directly pass libfaketime CFLAGS instead of changing the Makefile C flags in the patch --- .github/workflows/tests.yaml | 10 ++++++---- README.md | 7 +++++-- .../vendor/{libfaketime.patch => nanosecond.patch} | 13 ------------- setup.py | 7 +++++-- 4 files changed, 16 insertions(+), 21 deletions(-) rename libfaketime/vendor/{libfaketime.patch => nanosecond.patch} (55%) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d114212..d861ea7 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -36,7 +36,9 @@ jobs: key: pip|${{ hashFiles('setup.py') }}|${{ hashFiles('setup.cfg') }} - run: pip install tox - run: git submodule update --init --force - - run: | - git apply --directory libfaketime/vendor/libfaketime libfaketime/vendor/libfaketime.patch - make -C libfaketime/vendor/libfaketime - - run: tox -e ${{ matrix.python }}-${{ matrix.tz }} + - run: git apply --directory libfaketime/vendor/libfaketime libfaketime/vendor/nanosecond.patch + - run: env FAKETIME_COMPILE_CFLAGS="-UFAKE_STAT -UFAKE_UTIME -UFAKE_SLEEP" make -C libfaketime/vendor/libfaketime + if: runner.os == 'Linux' + - run: make -C libfaketime/vendor/libfaketime + if: runner.os == 'macOS' + - run: tox -e ${{ matrix.python }}-${{ matrix.tz }} --recreate diff --git a/README.md b/README.md index 6b08c38..d906ebb 100644 --- a/README.md +++ b/README.md @@ -165,8 +165,11 @@ Contributions are welcome! You should compile libfaketime before running tests: ```bash git submodule init --update -git apply --directory libfaketime/vendor/libfaketime libfaketime/vendor/libfaketime.patch -make -C libfaketime/vendor/libfaketime +git apply --directory libfaketime/vendor/libfaketime libfaketime/vendor/nanosecond.patch +# For Linux: +env FAKETIME_COMPILE_CFLAGS="-UFAKE_STAT -UFAKE_UTIME -UFAKE_SLEEP" make -C libfaketime/vendor/libfaketime +# For macOS +env make -C libfaketime/vendor/libfaketime ``` Then you can install requirements with ``pip install -r requirements.txt`` and use ``pytest`` and ``tox`` to run the tests. diff --git a/libfaketime/vendor/libfaketime.patch b/libfaketime/vendor/nanosecond.patch similarity index 55% rename from libfaketime/vendor/libfaketime.patch rename to libfaketime/vendor/nanosecond.patch index e5b44d7..542bcf2 100644 --- a/libfaketime/vendor/libfaketime.patch +++ b/libfaketime/vendor/nanosecond.patch @@ -1,16 +1,3 @@ -diff --git a/src/Makefile b/src/Makefile -index 62e924c..6f03e26 100644 ---- a/src/Makefile -+++ b/src/Makefile -@@ -110,7 +110,7 @@ PREFIX ?= /usr/local - LIBDIRNAME ?= /lib/faketime - PLATFORM ?=$(shell uname) - --CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -DFAKE_PTHREAD -DFAKE_STAT -DFAKE_UTIME -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"' $(FAKETIME_COMPILE_CFLAGS) -+CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -DFAKE_PTHREAD -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"' $(FAKETIME_COMPILE_CFLAGS) - ifeq ($(PLATFORM),SunOS) - CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 - endif diff --git a/src/libfaketime.c b/src/libfaketime.c index e632395..09d9019 100644 --- a/src/libfaketime.c diff --git a/setup.py b/setup.py index b479ab8..69c85dc 100644 --- a/setup.py +++ b/setup.py @@ -38,8 +38,11 @@ class CustomInstall(install): def run(self): self.my_outputs = [] - subprocess.check_call(['patch', '-p1', '<', '../libfaketime.patch'], cwd=_vendor_path, shell=True) - subprocess.check_call(['make', '-C', _vendor_path]) + subprocess.check_call(['patch', '-p1', '<', '../nanosecond.patch'], cwd=_vendor_path, shell=True) + if sys.platform in ("linux", "linux2"): + subprocess.check_call(['env', 'FAKETIME_COMPILE_CFLAGS=-UFAKE_STAT -UFAKE_UTIME -UFAKE_SLEEP', 'make', '-C', _vendor_path]) + elif sys.platform == "darwin": + subprocess.check_call(['make', '-C', _vendor_path]) dest = os.path.join(self.install_purelib, os.path.dirname(faketime_lib)) try: From 74f41973c25831412b3dfa1a72db47078db2b820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Wed, 1 May 2024 18:02:44 +0200 Subject: [PATCH 3/3] feat: use FAKETIME_FMT environment var instead of patching libfaketime --- .github/workflows/tests.yaml | 1 - README.md | 1 - libfaketime/__init__.py | 14 +++++++++++--- libfaketime/vendor/nanosecond.patch | 25 ------------------------- setup.py | 1 - 5 files changed, 11 insertions(+), 31 deletions(-) delete mode 100644 libfaketime/vendor/nanosecond.patch diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d861ea7..cc06a01 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -36,7 +36,6 @@ jobs: key: pip|${{ hashFiles('setup.py') }}|${{ hashFiles('setup.cfg') }} - run: pip install tox - run: git submodule update --init --force - - run: git apply --directory libfaketime/vendor/libfaketime libfaketime/vendor/nanosecond.patch - run: env FAKETIME_COMPILE_CFLAGS="-UFAKE_STAT -UFAKE_UTIME -UFAKE_SLEEP" make -C libfaketime/vendor/libfaketime if: runner.os == 'Linux' - run: make -C libfaketime/vendor/libfaketime diff --git a/README.md b/README.md index d906ebb..53c87fc 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,6 @@ Contributions are welcome! You should compile libfaketime before running tests: ```bash git submodule init --update -git apply --directory libfaketime/vendor/libfaketime libfaketime/vendor/nanosecond.patch # For Linux: env FAKETIME_COMPILE_CFLAGS="-UFAKE_STAT -UFAKE_UTIME -UFAKE_SLEEP" make -C libfaketime/vendor/libfaketime # For macOS diff --git a/libfaketime/__init__.py b/libfaketime/__init__.py index 182ecc0..e59bdfb 100644 --- a/libfaketime/__init__.py +++ b/libfaketime/__init__.py @@ -26,7 +26,7 @@ # This env var is set by reexec to ensure we don't reload more than once. _DID_REEXEC_VAR = 'FAKETIME_DID_REEXEC' - +_FAKETIME_FMT = '%Y-%m-%d %T.%f' def _get_lib_path(): vendor_dir = 'libfaketime' @@ -162,7 +162,7 @@ def _should_patch_uuid(self): return None def _format_datetime(self, _datetime): - return _datetime.strftime('%Y-%m-%d %T %f') + return _datetime.strftime(_FAKETIME_FMT) def tick(self, delta=datetime.timedelta(seconds=1)): self.time_to_freeze += delta @@ -173,11 +173,13 @@ def __enter__(self): begin_callback(self) self._prev_spec = os.environ.get('FAKETIME') self._prev_tz = os.environ.get('TZ') + self._prev_fmt = os.environ.get('FAKETIME_FMT') os.environ['TZ'] = self.timezone_str time.tzset() os.environ['FAKETIME'] = self._format_datetime(self.time_to_freeze) + os.environ['FAKETIME_FMT'] = _FAKETIME_FMT func_name = self._should_patch_uuid() if func_name: @@ -202,7 +204,13 @@ def __exit__(self, *exc): os.environ['FAKETIME'] = self._prev_spec else: del os.environ['FAKETIME'] - end_callback(self) + + if self._prev_fmt is not None: + os.environ['FAKETIME_FMT'] = self._prev_spec + else: + del os.environ['FAKETIME_FMT'] + + end_callback(self) return False diff --git a/libfaketime/vendor/nanosecond.patch b/libfaketime/vendor/nanosecond.patch deleted file mode 100644 index 542bcf2..0000000 --- a/libfaketime/vendor/nanosecond.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/src/libfaketime.c b/src/libfaketime.c -index e632395..09d9019 100644 ---- a/src/libfaketime.c -+++ b/src/libfaketime.c -@@ -2384,10 +2384,16 @@ static void parse_ft_string(const char *user_faked_time) - user_faked_time_tm.tm_isdst = -1; - nstime_str = strptime(user_faked_time, user_faked_time_fmt, &user_faked_time_tm); - -+ /* the actual format has a " %f" appended. Parse out the microseconds. */ -+ char nanosecond_str[7]; -+ memcpy(&nanosecond_str, user_faked_time + 20, 6); -+ nanosecond_str[6] = '\0'; -+ int nanoseconds = atoi(nanosecond_str) * 1000; -+ - if (NULL != nstime_str) - { - user_faked_time_timespec.tv_sec = mktime(&user_faked_time_tm); -- user_faked_time_timespec.tv_nsec = 0; -+ user_faked_time_timespec.tv_nsec = nanoseconds; - - if (nstime_str[0] == '.') - { --- -2.45.0 - diff --git a/setup.py b/setup.py index 69c85dc..6add73e 100644 --- a/setup.py +++ b/setup.py @@ -38,7 +38,6 @@ class CustomInstall(install): def run(self): self.my_outputs = [] - subprocess.check_call(['patch', '-p1', '<', '../nanosecond.patch'], cwd=_vendor_path, shell=True) if sys.platform in ("linux", "linux2"): subprocess.check_call(['env', 'FAKETIME_COMPILE_CFLAGS=-UFAKE_STAT -UFAKE_UTIME -UFAKE_SLEEP', 'make', '-C', _vendor_path]) elif sys.platform == "darwin":