From 8afb80d594fe7075c9fba869e7063fe0914bc78c Mon Sep 17 00:00:00 2001 From: Raymond Zhao <7199958+rzhao271@users.noreply.github.com> Date: Wed, 4 Oct 2023 15:54:47 -0700 Subject: [PATCH 01/14] feat(gyp): update gyp to v0.15.1 --- gyp/.flake8 | 4 - gyp/.github/workflows/Python_tests.yml | 11 +-- gyp/.github/workflows/node-gyp.yml | 25 ++++-- gyp/AUTHORS | 1 + gyp/CHANGELOG.md | 28 ++++++ gyp/README.md | 23 +++++ gyp/pylib/gyp/MSVSNew.py | 26 +++--- gyp/pylib/gyp/MSVSProject.py | 2 +- gyp/pylib/gyp/MSVSSettings.py | 2 +- gyp/pylib/gyp/__init__.py | 6 +- gyp/pylib/gyp/common.py | 21 ++--- gyp/pylib/gyp/easy_xml.py | 6 +- gyp/pylib/gyp/easy_xml_test.py | 2 + gyp/pylib/gyp/generator/analyzer.py | 26 +++--- gyp/pylib/gyp/generator/android.py | 2 +- gyp/pylib/gyp/generator/cmake.py | 9 +- .../gyp/generator/compile_commands_json.py | 9 +- gyp/pylib/gyp/generator/eclipse.py | 5 +- gyp/pylib/gyp/generator/make.py | 13 ++- gyp/pylib/gyp/generator/msvs.py | 70 +++++++-------- gyp/pylib/gyp/generator/ninja.py | 7 +- gyp/pylib/gyp/generator/xcode.py | 7 +- gyp/pylib/gyp/input.py | 57 +++++------- gyp/pylib/gyp/msvs_emulation.py | 25 ++---- gyp/pylib/gyp/win_tool.py | 9 +- gyp/pylib/gyp/xcode_emulation.py | 12 +-- gyp/pylib/gyp/xcodeproj_file.py | 41 ++++----- gyp/pyproject.toml | 86 +++++++++++++++++-- gyp/tools/pretty_sln.py | 4 +- gyp/tools/pretty_vcproj.py | 2 +- 30 files changed, 313 insertions(+), 228 deletions(-) delete mode 100644 gyp/.flake8 diff --git a/gyp/.flake8 b/gyp/.flake8 deleted file mode 100644 index ea0c7680ef..0000000000 --- a/gyp/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -max-complexity = 101 -max-line-length = 88 -extend-ignore = E203 # whitespace before ':' to agree with psf/black diff --git a/gyp/.github/workflows/Python_tests.yml b/gyp/.github/workflows/Python_tests.yml index aad135027c..0f252b9ea6 100644 --- a/gyp/.github/workflows/Python_tests.yml +++ b/gyp/.github/workflows/Python_tests.yml @@ -13,24 +13,25 @@ jobs: runs-on: ${{ matrix.os }} strategy: fail-fast: false - max-parallel: 8 + max-parallel: 5 matrix: os: [macos-latest, ubuntu-latest] # , windows-latest] - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11-dev"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + allow-prereleases: true - name: Install dependencies run: | python -m pip install --upgrade pip setuptools pip install --editable ".[dev]" - run: ./gyp -V && ./gyp --version && gyp -V && gyp --version - - name: Lint with flake8 - run: flake8 . --ignore=E203,W503 --max-complexity=101 --max-line-length=88 --show-source --statistics - - name: Test with pytest + - name: Lint with ruff # See pyproject.toml for settings + run: ruff --format=github . + - name: Test with pytest # See pyproject.toml for settings run: pytest # - name: Run doctests with pytest # run: pytest --doctest-modules diff --git a/gyp/.github/workflows/node-gyp.yml b/gyp/.github/workflows/node-gyp.yml index 7cc1f9e075..edf6877347 100644 --- a/gyp/.github/workflows/node-gyp.yml +++ b/gyp/.github/workflows/node-gyp.yml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: os: [macos-latest, ubuntu-latest, windows-latest] - python: ["3.7", "3.10"] + python: ["3.8", "3.x", "3.12"] runs-on: ${{ matrix.os }} steps: @@ -26,11 +26,18 @@ jobs: path: node-gyp - uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: 18.x - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - - name: Install dependencies + allow-prereleases: true + - name: Install Python dependencies + run: | + cd gyp-next + python -m pip install --upgrade pip setuptools + pip install --editable . + pip uninstall -y gyp-next + - name: Install Node.js dependencies run: | cd node-gyp npm install --no-progress @@ -39,7 +46,15 @@ jobs: run: | rm -rf node-gyp/gyp cp -r gyp-next node-gyp/gyp - - name: Run tests + - name: Run tests (macOS or Linux) + if: runner.os != 'Windows' + shell: bash + run: | + cd node-gyp + npm test --python="${pythonLocation}/python" + - name: Run tests (Windows) + if: runner.os == 'Windows' + shell: pwsh run: | cd node-gyp - npm test + npm run test --python="${env:pythonLocation}\\python.exe" diff --git a/gyp/AUTHORS b/gyp/AUTHORS index f49a357b9e..c05d25b2cb 100644 --- a/gyp/AUTHORS +++ b/gyp/AUTHORS @@ -14,3 +14,4 @@ Tom Freudenberg
# pre-release + [-_\.]? + (?Palpha|a|beta|b|preview|pre|c|rc) + [-_\.]? + (?P [0-9]+)? + )? + (?P # post release + (?:-(?P [0-9]+)) + | + (?: + [-_\.]? + (?P post|rev|r) + [-_\.]? + (?P [0-9]+)? + ) + )? + (?P # dev release + [-_\.]? + (?P dev) + [-_\.]? + (?P [0-9]+)? + )? + ) + (?:\+(?P [a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version +""" + +VERSION_PATTERN = _VERSION_PATTERN +""" +A string containing the regular expression used to match a valid version. + +The pattern is not anchored at either end, and is intended for embedding in larger +expressions (for example, matching a version number as part of a file name). The +regular expression should be compiled with the ``re.VERBOSE`` and ``re.IGNORECASE`` +flags set. + +:meta hide-value: +""" + + +class Version(_BaseVersion): + """This class abstracts handling of a project's versions. + + A :class:`Version` instance is comparison aware and can be compared and + sorted using the standard Python interfaces. + + >>> v1 = Version("1.0a5") + >>> v2 = Version("1.0") + >>> v1 + + >>> v2 + + >>> v1 < v2 + True + >>> v1 == v2 + False + >>> v1 > v2 + False + >>> v1 >= v2 + False + >>> v1 <= v2 + True + """ + + _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE) + _key: CmpKey + + def __init__(self, version: str) -> None: + """Initialize a Version object. + + :param version: + The string representation of a version which will be parsed and normalized + before use. + :raises InvalidVersion: + If the ``version`` does not conform to PEP 440 in any way then this + exception will be raised. + """ + + # Validate the version and parse it into pieces + match = self._regex.search(version) + if not match: + raise InvalidVersion(f"Invalid version: '{version}'") + + # Store the parsed out pieces of the version + self._version = _Version( + epoch=int(match.group("epoch")) if match.group("epoch") else 0, + release=tuple(int(i) for i in match.group("release").split(".")), + pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")), + post=_parse_letter_version( + match.group("post_l"), match.group("post_n1") or match.group("post_n2") + ), + dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")), + local=_parse_local_version(match.group("local")), + ) + + # Generate a key which will be used for sorting + self._key = _cmpkey( + self._version.epoch, + self._version.release, + self._version.pre, + self._version.post, + self._version.dev, + self._version.local, + ) + + def __repr__(self) -> str: + """A representation of the Version that shows all internal state. + + >>> Version('1.0.0') + + """ + return f" " + + def __str__(self) -> str: + """A string representation of the version that can be rounded-tripped. + + >>> str(Version("1.0a5")) + '1.0a5' + """ + parts = [] + + # Epoch + if self.epoch != 0: + parts.append(f"{self.epoch}!") + + # Release segment + parts.append(".".join(str(x) for x in self.release)) + + # Pre-release + if self.pre is not None: + parts.append("".join(str(x) for x in self.pre)) + + # Post-release + if self.post is not None: + parts.append(f".post{self.post}") + + # Development release + if self.dev is not None: + parts.append(f".dev{self.dev}") + + # Local version segment + if self.local is not None: + parts.append(f"+{self.local}") + + return "".join(parts) + + @property + def epoch(self) -> int: + """The epoch of the version. + + >>> Version("2.0.0").epoch + 0 + >>> Version("1!2.0.0").epoch + 1 + """ + return self._version.epoch + + @property + def release(self) -> Tuple[int, ...]: + """The components of the "release" segment of the version. + + >>> Version("1.2.3").release + (1, 2, 3) + >>> Version("2.0.0").release + (2, 0, 0) + >>> Version("1!2.0.0.post0").release + (2, 0, 0) + + Includes trailing zeroes but not the epoch or any pre-release / development / + post-release suffixes. + """ + return self._version.release + + @property + def pre(self) -> Optional[Tuple[str, int]]: + """The pre-release segment of the version. + + >>> print(Version("1.2.3").pre) + None + >>> Version("1.2.3a1").pre + ('a', 1) + >>> Version("1.2.3b1").pre + ('b', 1) + >>> Version("1.2.3rc1").pre + ('rc', 1) + """ + return self._version.pre + + @property + def post(self) -> Optional[int]: + """The post-release number of the version. + + >>> print(Version("1.2.3").post) + None + >>> Version("1.2.3.post1").post + 1 + """ + return self._version.post[1] if self._version.post else None + + @property + def dev(self) -> Optional[int]: + """The development number of the version. + + >>> print(Version("1.2.3").dev) + None + >>> Version("1.2.3.dev1").dev + 1 + """ + return self._version.dev[1] if self._version.dev else None + + @property + def local(self) -> Optional[str]: + """The local version segment of the version. + + >>> print(Version("1.2.3").local) + None + >>> Version("1.2.3+abc").local + 'abc' + """ + if self._version.local: + return ".".join(str(x) for x in self._version.local) + else: + return None + + @property + def public(self) -> str: + """The public portion of the version. + + >>> Version("1.2.3").public + '1.2.3' + >>> Version("1.2.3+abc").public + '1.2.3' + >>> Version("1.2.3+abc.dev1").public + '1.2.3' + """ + return str(self).split("+", 1)[0] + + @property + def base_version(self) -> str: + """The "base version" of the version. + + >>> Version("1.2.3").base_version + '1.2.3' + >>> Version("1.2.3+abc").base_version + '1.2.3' + >>> Version("1!1.2.3+abc.dev1").base_version + '1!1.2.3' + + The "base version" is the public version of the project without any pre or post + release markers. + """ + parts = [] + + # Epoch + if self.epoch != 0: + parts.append(f"{self.epoch}!") + + # Release segment + parts.append(".".join(str(x) for x in self.release)) + + return "".join(parts) + + @property + def is_prerelease(self) -> bool: + """Whether this version is a pre-release. + + >>> Version("1.2.3").is_prerelease + False + >>> Version("1.2.3a1").is_prerelease + True + >>> Version("1.2.3b1").is_prerelease + True + >>> Version("1.2.3rc1").is_prerelease + True + >>> Version("1.2.3dev1").is_prerelease + True + """ + return self.dev is not None or self.pre is not None + + @property + def is_postrelease(self) -> bool: + """Whether this version is a post-release. + + >>> Version("1.2.3").is_postrelease + False + >>> Version("1.2.3.post1").is_postrelease + True + """ + return self.post is not None + + @property + def is_devrelease(self) -> bool: + """Whether this version is a development release. + + >>> Version("1.2.3").is_devrelease + False + >>> Version("1.2.3.dev1").is_devrelease + True + """ + return self.dev is not None + + @property + def major(self) -> int: + """The first item of :attr:`release` or ``0`` if unavailable. + + >>> Version("1.2.3").major + 1 + """ + return self.release[0] if len(self.release) >= 1 else 0 + + @property + def minor(self) -> int: + """The second item of :attr:`release` or ``0`` if unavailable. + + >>> Version("1.2.3").minor + 2 + >>> Version("1").minor + 0 + """ + return self.release[1] if len(self.release) >= 2 else 0 + + @property + def micro(self) -> int: + """The third item of :attr:`release` or ``0`` if unavailable. + + >>> Version("1.2.3").micro + 3 + >>> Version("1").micro + 0 + """ + return self.release[2] if len(self.release) >= 3 else 0 + + +def _parse_letter_version( + letter: Optional[str], number: Union[str, bytes, SupportsInt, None] +) -> Optional[Tuple[str, int]]: + + if letter: + # We consider there to be an implicit 0 in a pre-release if there is + # not a numeral associated with it. + if number is None: + number = 0 + + # We normalize any letters to their lower case form + letter = letter.lower() + + # We consider some words to be alternate spellings of other words and + # in those cases we want to normalize the spellings to our preferred + # spelling. + if letter == "alpha": + letter = "a" + elif letter == "beta": + letter = "b" + elif letter in ["c", "pre", "preview"]: + letter = "rc" + elif letter in ["rev", "r"]: + letter = "post" + + return letter, int(number) + if not letter and number: + # We assume if we are given a number, but we are not given a letter + # then this is using the implicit post release syntax (e.g. 1.0-1) + letter = "post" + + return letter, int(number) + + return None + + +_local_version_separators = re.compile(r"[\._-]") + + +def _parse_local_version(local: Optional[str]) -> Optional[LocalType]: + """ + Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve"). + """ + if local is not None: + return tuple( + part.lower() if not part.isdigit() else int(part) + for part in _local_version_separators.split(local) + ) + return None + + +def _cmpkey( + epoch: int, + release: Tuple[int, ...], + pre: Optional[Tuple[str, int]], + post: Optional[Tuple[str, int]], + dev: Optional[Tuple[str, int]], + local: Optional[LocalType], +) -> CmpKey: + + # When we compare a release version, we want to compare it with all of the + # trailing zeros removed. So we'll use a reverse the list, drop all the now + # leading zeros until we come to something non zero, then take the rest + # re-reverse it back into the correct order and make it a tuple and use + # that for our sorting key. + _release = tuple( + reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))) + ) + + # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0. + # We'll do this by abusing the pre segment, but we _only_ want to do this + # if there is not a pre or a post segment. If we have one of those then + # the normal sorting rules will handle this case correctly. + if pre is None and post is None and dev is not None: + _pre: CmpPrePostDevType = NegativeInfinity + # Versions without a pre-release (except as noted above) should sort after + # those with one. + elif pre is None: + _pre = Infinity + else: + _pre = pre + + # Versions without a post segment should sort before those with one. + if post is None: + _post: CmpPrePostDevType = NegativeInfinity + + else: + _post = post + + # Versions without a development segment should sort after those with one. + if dev is None: + _dev: CmpPrePostDevType = Infinity + + else: + _dev = dev + + if local is None: + # Versions without a local segment should sort before those with one. + _local: CmpLocalType = NegativeInfinity + else: + # Versions with a local segment need that segment parsed to implement + # the sorting rules in PEP440. + # - Alpha numeric segments sort before numeric segments + # - Alpha numeric segments sort lexicographically + # - Numeric segments sort numerically + # - Shorter versions sort before longer versions when the prefixes + # match exactly + _local = tuple( + (i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local + ) + + return epoch, _release, _pre, _post, _dev, _local diff --git a/gyp/pyproject.toml b/gyp/pyproject.toml index af540cd941..b5f722fa0e 100644 --- a/gyp/pyproject.toml +++ b/gyp/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "gyp-next" -version = "0.15.1" +version = "0.16.0" authors = [ { name="Node.js contributors", email="ryzokuken@disroot.org" }, ] @@ -12,7 +12,8 @@ description = "A fork of the GYP build system for use in the Node.js projects" readme = "README.md" license = { file="LICENSE" } requires-python = ">=3.8" -dependencies = ["packaging>=23.1"] +# The Python module "packaging" is vendored in the "pylib/packaging" directory to support Python >= 3.12. +# dependencies = ["packaging>=23.1"] # Uncomment this line if the vendored version is removed. classifiers = [ "Development Status :: 3 - Alpha", "Environment :: Console", @@ -100,6 +101,7 @@ ignore = [ "RUF012", "UP031", ] +extend-exclude = ["pylib/packaging"] line-length = 88 target-version = "py37" From 4f5bb36cc993f7b1603e671a8dee035786d036e5 Mon Sep 17 00:00:00 2001 From: DeeDeeG Date: Fri, 27 Oct 2023 16:44:46 -0400 Subject: [PATCH 11/14] feat(gyp): update gyp to v0.16.1 --- gyp/CHANGELOG.md | 7 +++++++ gyp/pylib/gyp/generator/msvs.py | 1 + gyp/pyproject.toml | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/gyp/CHANGELOG.md b/gyp/CHANGELOG.md index b9e7e73d09..483943e013 100644 --- a/gyp/CHANGELOG.md +++ b/gyp/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.16.1](https://github.com/nodejs/gyp-next/compare/v0.16.0...v0.16.1) (2023-10-25) + + +### Bug Fixes + +* add quotes for command in msvs generator ([#217](https://github.com/nodejs/gyp-next/issues/217)) ([d3b7bcd](https://github.com/nodejs/gyp-next/commit/d3b7bcdec90d6c1b1affc15ece706e63007b7264)) + ## [0.16.0](https://github.com/nodejs/gyp-next/compare/v0.15.1...v0.16.0) (2023-10-23) diff --git a/gyp/pylib/gyp/generator/msvs.py b/gyp/pylib/gyp/generator/msvs.py index 1f9e2497da..13b0794b4d 100644 --- a/gyp/pylib/gyp/generator/msvs.py +++ b/gyp/pylib/gyp/generator/msvs.py @@ -435,6 +435,7 @@ def _BuildCommandLineForRuleRaw( # Support a mode for using cmd directly. # Convert any paths to native form (first element is used directly). # TODO(quote): regularize quoting path names throughout the module + command[1] = '"%s"' % command[1] arguments = ['"%s"' % i for i in arguments] # Collapse into a single command. return input_dir_preamble + " ".join(command + arguments) diff --git a/gyp/pyproject.toml b/gyp/pyproject.toml index b5f722fa0e..0c25d0b3c1 100644 --- a/gyp/pyproject.toml +++ b/gyp/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "gyp-next" -version = "0.16.0" +version = "0.16.1" authors = [ { name="Node.js contributors", email="ryzokuken@disroot.org" }, ] From e085b69eacf2fc1492cbcea3c6cbba5134ba0028 Mon Sep 17 00:00:00 2001 From: DeeDeeG Date: Fri, 27 Oct 2023 16:43:13 -0400 Subject: [PATCH 12/14] CI: Don't install Python 'packaging' module (vendored in 'gyp-next' now) --- .github/workflows/tests.yml | 2 +- .github/workflows/visual-studio.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 20f5381759..6ced66f802 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,7 +44,7 @@ jobs: - name: Install Dependencies run: | npm install --no-progress - python -m pip install pytest packaging + python -m pip install pytest - name: Set Windows environment if: startsWith(matrix.os, 'windows') run: | diff --git a/.github/workflows/visual-studio.yml b/.github/workflows/visual-studio.yml index 7d93e0fa16..d427e957a9 100644 --- a/.github/workflows/visual-studio.yml +++ b/.github/workflows/visual-studio.yml @@ -28,7 +28,6 @@ jobs: - name: Install Dependencies run: | npm install --no-progress - python -m pip install packaging - name: Environment Information run: npx envinfo - name: Run Node tests From 814b421421d82871fb687eddd9dd91b36e86325b Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 28 Oct 2023 01:37:30 +0200 Subject: [PATCH 13/14] Apply suggestions from code review --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6ced66f802..310b4f06ea 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,7 +25,7 @@ jobs: max-parallel: 15 matrix: node: [16.x, 18.x, 20.x] - python: ["3.8", "3.11", "3.12"] + python: ["3.8", "3.10", "3.12"] os: [macos-latest, ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: @@ -44,7 +44,7 @@ jobs: - name: Install Dependencies run: | npm install --no-progress - python -m pip install pytest + pip install pytest - name: Set Windows environment if: startsWith(matrix.os, 'windows') run: | From 5749050f18ffdea15af62c69e8c160169c435a01 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 28 Oct 2023 01:39:42 +0200 Subject: [PATCH 14/14] Upgrade to actions/checkout@v4 --- .github/workflows/visual-studio.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/visual-studio.yml b/.github/workflows/visual-studio.yml index d427e957a9..8b796256da 100644 --- a/.github/workflows/visual-studio.yml +++ b/.github/workflows/visual-studio.yml @@ -24,7 +24,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Dependencies run: | npm install --no-progress