[0-9]+(?:\.[0-9]+)*) # release segment
(?P # pre-release
[-_\.]?
(?Palpha|a|beta|b|preview|pre|c|rc)
[-_\.]?
(?P[0-9]+)?
)?
(?P # post release
(?:-(?P[0-9]+))
|
(?:
[-_\.]?
(?Ppost|rev|r)
[-_\.]?
(?P[0-9]+)?
)
)?
(?P # dev release
[-_\.]?
(?Pdev)
[-_\.]?
(?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
================================================
FILE: gyp/pyproject.toml
================================================
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "gyp-next"
version = "0.21.1"
authors = [
{ name="Node.js contributors", email="ryzokuken@disroot.org" },
]
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>=24.0", "setuptools>=69.5.1"]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Natural Language :: English",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]
[project.optional-dependencies]
dev = ["pytest", "ruff"]
[project.scripts]
gyp = "gyp:script_main"
[project.urls]
"Homepage" = "https://github.com/nodejs/gyp-next"
[tool.ruff]
extend-exclude = ["pylib/packaging"]
line-length = 88
[tool.ruff.lint]
select = [
"C4", # flake8-comprehensions
"C90", # McCabe cyclomatic complexity
"DTZ", # flake8-datetimez
"E", # pycodestyle
"F", # Pyflakes
"G", # flake8-logging-format
"ICN", # flake8-import-conventions
"INT", # flake8-gettext
"PL", # Pylint
"PYI", # flake8-pyi
"RSE", # flake8-raise
"RUF", # Ruff-specific rules
"T10", # flake8-debugger
"TCH", # flake8-type-checking
"TID", # flake8-tidy-imports
"UP", # pyupgrade
"W", # pycodestyle
"YTT", # flake8-2020
# "A", # flake8-builtins
# "ANN", # flake8-annotations
# "ARG", # flake8-unused-arguments
# "B", # flake8-bugbear
# "BLE", # flake8-blind-except
# "COM", # flake8-commas
# "D", # pydocstyle
# "DJ", # flake8-django
# "EM", # flake8-errmsg
# "ERA", # eradicate
# "EXE", # flake8-executable
# "FBT", # flake8-boolean-trap
# "I", # isort
# "INP", # flake8-no-pep420
# "ISC", # flake8-implicit-str-concat
# "N", # pep8-naming
# "NPY", # NumPy-specific rules
# "PD", # pandas-vet
# "PGH", # pygrep-hooks
# "PIE", # flake8-pie
# "PT", # flake8-pytest-style
# "PTH", # flake8-use-pathlib
# "Q", # flake8-quotes
# "RET", # flake8-return
# "S", # flake8-bandit
# "SIM", # flake8-simplify
# "SLF", # flake8-self
# "T20", # flake8-print
# "TRY", # tryceratops
]
ignore = [
"PLR1714",
"PLW0603",
"PLW2901",
"RUF005",
"RUF012",
"UP031",
]
[tool.ruff.lint.mccabe]
max-complexity = 101
[tool.ruff.lint.pylint]
allow-magic-value-types = ["float", "int", "str"]
max-args = 11
max-branches = 108
max-returns = 10
max-statements = 286
[tool.setuptools]
package-dir = {"" = "pylib"}
packages = ["gyp", "gyp.generator"]
================================================
FILE: gyp/release-please-config.json
================================================
{
"last-release-sha": "78756421b0d7bb335992a9c7d26ba3cc8b619708",
"packages": {
".": {
"release-type": "python",
"package-name": "gyp-next",
"bump-minor-pre-major": true,
"include-component-in-tag": false
}
}
}
================================================
FILE: gyp/test_gyp.py
================================================
#!/usr/bin/env python3
# Copyright (c) 2012 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""gyptest.py -- test runner for GYP tests."""
import argparse
import os
import platform
import subprocess
import sys
import time
def is_test_name(f):
return f.startswith("gyptest") and f.endswith(".py")
def find_all_gyptest_files(directory):
result = []
for root, dirs, files in os.walk(directory):
result.extend([os.path.join(root, f) for f in files if is_test_name(f)])
result.sort()
return result
def main(argv=None):
if argv is None:
argv = sys.argv
parser = argparse.ArgumentParser()
parser.add_argument("-a", "--all", action="store_true", help="run all tests")
parser.add_argument("-C", "--chdir", action="store", help="change to directory")
parser.add_argument(
"-f",
"--format",
action="store",
default="",
help="run tests with the specified formats",
)
parser.add_argument(
"-G",
"--gyp_option",
action="append",
default=[],
help="Add -G options to the gyp command line",
)
parser.add_argument(
"-l", "--list", action="store_true", help="list available tests and exit"
)
parser.add_argument(
"-n",
"--no-exec",
action="store_true",
help="no execute, just print the command line",
)
parser.add_argument(
"--path", action="append", default=[], help="additional $PATH directory"
)
parser.add_argument(
"-q",
"--quiet",
action="store_true",
help="quiet, don't print anything unless there are failures",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="print configuration info and test results.",
)
parser.add_argument("tests", nargs="*")
args = parser.parse_args(argv[1:])
if args.chdir:
os.chdir(args.chdir)
if args.path:
extra_path = [os.path.abspath(p) for p in args.path]
extra_path = os.pathsep.join(extra_path)
os.environ["PATH"] = extra_path + os.pathsep + os.environ["PATH"]
if not args.tests:
if not args.all:
sys.stderr.write("Specify -a to get all tests.\n")
return 1
args.tests = ["test"]
tests = []
for arg in args.tests:
if os.path.isdir(arg):
tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
else:
if not is_test_name(os.path.basename(arg)):
print(arg, "is not a valid gyp test name.", file=sys.stderr)
sys.exit(1)
tests.append(arg)
if args.list:
for test in tests:
print(test)
sys.exit(0)
os.environ["PYTHONPATH"] = os.path.abspath("test/lib")
if args.verbose:
print_configuration_info()
if args.gyp_option and not args.quiet:
print("Extra Gyp options: %s\n" % args.gyp_option)
if args.format:
format_list = args.format.split(",")
else:
format_list = {
"aix5": ["make"],
"os400": ["make"],
"freebsd7": ["make"],
"freebsd8": ["make"],
"openbsd5": ["make"],
"cygwin": ["msvs"],
"win32": ["msvs", "ninja"],
"linux": ["make", "ninja"],
"linux2": ["make", "ninja"],
"linux3": ["make", "ninja"],
# TODO: Re-enable xcode-ninja.
# https://bugs.chromium.org/p/gyp/issues/detail?id=530
# 'darwin': ['make', 'ninja', 'xcode', 'xcode-ninja'],
"darwin": ["make", "ninja", "xcode"],
}[sys.platform]
gyp_options = []
for option in args.gyp_option:
gyp_options += ["-G", option]
runner = Runner(format_list, tests, gyp_options, args.verbose)
runner.run()
if not args.quiet:
runner.print_results()
return 1 if runner.failures else 0
def print_configuration_info():
print("Test configuration:")
if sys.platform == "darwin":
sys.path.append(os.path.abspath("test/lib"))
import TestMac # noqa: PLC0415
print(f" Mac {platform.mac_ver()[0]} {platform.mac_ver()[2]}")
print(f" Xcode {TestMac.Xcode.Version()}")
elif sys.platform == "win32":
sys.path.append(os.path.abspath("pylib"))
import gyp.MSVSVersion # noqa: PLC0415
print(" Win %s %s\n" % platform.win32_ver()[0:2])
print(" MSVS %s" % gyp.MSVSVersion.SelectVisualStudioVersion().Description())
elif sys.platform in ("linux", "linux2"):
print(" Linux %s" % " ".join(platform.linux_distribution()))
print(f" Python {platform.python_version()}")
print(f" PYTHONPATH={os.environ['PYTHONPATH']}")
print()
class Runner:
def __init__(self, formats, tests, gyp_options, verbose):
self.formats = formats
self.tests = tests
self.verbose = verbose
self.gyp_options = gyp_options
self.failures = []
self.num_tests = len(formats) * len(tests)
num_digits = len(str(self.num_tests))
self.fmt_str = "[%%%dd/%%%dd] (%%s) %%s" % (num_digits, num_digits)
self.isatty = sys.stdout.isatty() and not self.verbose
self.env = os.environ.copy()
self.hpos = 0
def run(self):
run_start = time.time()
i = 1
for fmt in self.formats:
for test in self.tests:
self.run_test(test, fmt, i)
i += 1
if self.isatty:
self.erase_current_line()
self.took = time.time() - run_start
def run_test(self, test, fmt, i):
if self.isatty:
self.erase_current_line()
msg = self.fmt_str % (i, self.num_tests, fmt, test)
self.print_(msg)
start = time.time()
cmd = [sys.executable, test] + self.gyp_options
self.env["TESTGYP_FORMAT"] = fmt
proc = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=self.env
)
proc.wait()
took = time.time() - start
stdout = proc.stdout.read().decode("utf8")
if proc.returncode == 2:
res = "skipped"
elif proc.returncode:
res = "failed"
self.failures.append(f"({test}) {fmt}")
else:
res = "passed"
res_msg = f" {res} {took:.3f}s"
self.print_(res_msg)
if stdout and not stdout.endswith(("PASSED\n", "NO RESULT\n")):
print()
print("\n".join(f" {line}" for line in stdout.splitlines()))
elif not self.isatty:
print()
def print_(self, msg):
print(msg, end="")
index = msg.rfind("\n")
if index == -1:
self.hpos += len(msg)
else:
self.hpos = len(msg) - index
sys.stdout.flush()
def erase_current_line(self):
print("\b" * self.hpos + " " * self.hpos + "\b" * self.hpos, end="")
sys.stdout.flush()
self.hpos = 0
def print_results(self):
num_failures = len(self.failures)
if num_failures:
print()
if num_failures == 1:
print("Failed the following test:")
else:
print("Failed the following %d tests:" % num_failures)
print("\t" + "\n\t".join(sorted(self.failures)))
print()
print(
"Ran %d tests in %.3fs, %d failed."
% (self.num_tests, self.took, num_failures)
)
print()
if __name__ == "__main__":
sys.exit(main())
================================================
FILE: gyp/tools/README
================================================
pretty_vcproj:
Usage: pretty_vcproj.py "c:\path\to\vcproj.vcproj" [key1=value1] [key2=value2]
They key/value pair are used to resolve vsprops name.
For example, if I want to diff the base.vcproj project:
pretty_vcproj.py z:\dev\src-chrome\src\base\build\base.vcproj "$(SolutionDir)=z:\dev\src-chrome\src\chrome\\" "$(CHROMIUM_BUILD)=" "$(CHROME_BUILD_TYPE)=" > original.txt
pretty_vcproj.py z:\dev\src-chrome\src\base\base_gyp.vcproj "$(SolutionDir)=z:\dev\src-chrome\src\chrome\\" "$(CHROMIUM_BUILD)=" "$(CHROME_BUILD_TYPE)=" > gyp.txt
And you can use your favorite diff tool to see the changes.
Note: In the case of base.vcproj, the original vcproj is one level up the generated one.
I suggest you do a search and replace for '"..\' and replace it with '"' in original.txt
before you perform the diff.
================================================
FILE: gyp/tools/Xcode/README
================================================
Specifications contains syntax formatters for Xcode 3. These do not appear to be supported yet on Xcode 4. To use these with Xcode 3 please install both the gyp.pbfilespec and gyp.xclangspec files in
~/Library/Application Support/Developer/Shared/Xcode/Specifications/
and restart Xcode.
================================================
FILE: gyp/tools/Xcode/Specifications/gyp.pbfilespec
================================================
/*
gyp.pbfilespec
GYP source file spec for Xcode 3
There is not much documentation available regarding the format
of .pbfilespec files. As a starting point, see for instance the
outdated documentation at:
http://maxao.free.fr/xcode-plugin-interface/specifications.html
and the files in:
/Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources/
Place this file in directory:
~/Library/Application Support/Developer/Shared/Xcode/Specifications/
*/
(
{
Identifier = sourcecode.gyp;
BasedOn = sourcecode;
Name = "GYP Files";
Extensions = ("gyp", "gypi");
MIMETypes = ("text/gyp");
Language = "xcode.lang.gyp";
IsTextFile = YES;
IsSourceFile = YES;
}
)
================================================
FILE: gyp/tools/Xcode/Specifications/gyp.xclangspec
================================================
/*
Copyright (c) 2011 Google Inc. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
gyp.xclangspec
GYP language specification for Xcode 3
There is not much documentation available regarding the format
of .xclangspec files. As a starting point, see for instance the
outdated documentation at:
http://maxao.free.fr/xcode-plugin-interface/specifications.html
and the files in:
/Developer/Library/PrivateFrameworks/XcodeEdit.framework/Versions/A/Resources/
Place this file in directory:
~/Library/Application Support/Developer/Shared/Xcode/Specifications/
*/
(
{
Identifier = "xcode.lang.gyp.keyword";
Syntax = {
Words = (
"and",
"or",
" (caar gyp-parse-history) target-point)
(setq gyp-parse-history (cdr gyp-parse-history))))
(defun gyp-parse-point ()
"The point of the last parse state added by gyp-parse-to."
(caar gyp-parse-history))
(defun gyp-parse-sections ()
"A list of section symbols holding at the last parse state point."
(cdar gyp-parse-history))
(defun gyp-inside-dictionary-p ()
"Predicate returning true if the parser is inside a dictionary."
(not (eq (cadar gyp-parse-history) 'list)))
(defun gyp-add-parse-history (point sections)
"Add parse state SECTIONS to the parse history at POINT so that parsing can be
resumed instantly."
(while (>= (caar gyp-parse-history) point)
(setq gyp-parse-history (cdr gyp-parse-history)))
(setq gyp-parse-history (cons (cons point sections) gyp-parse-history)))
(defun gyp-parse-to (target-point)
"Parses from (point) to TARGET-POINT adding the parse state information to
gyp-parse-state-history. Parsing stops if TARGET-POINT is reached or if a
string literal has been parsed. Returns nil if no further parsing can be
done, otherwise returns the position of the start of a parsed string, leaving
the point at the end of the string."
(let ((parsing t)
string-start)
(while parsing
(setq string-start nil)
;; Parse up to a character that starts a sexp, or if the nesting
;; level decreases.
(let ((state (parse-partial-sexp (gyp-parse-point)
target-point
-1
t))
(sections (gyp-parse-sections)))
(if (= (nth 0 state) -1)
(setq sections (cdr sections)) ; pop out a level
(cond ((looking-at-p "['\"]") ; a string
(setq string-start (point))
(goto-char (scan-sexps (point) 1))
(if (gyp-inside-dictionary-p)
;; Look for sections inside a dictionary
(let ((section (gyp-section-name
(buffer-substring-no-properties
(+ 1 string-start)
(- (point) 1)))))
(setq sections (cons section (cdr sections)))))
;; Stop after the string so it can be fontified.
(setq target-point (point)))
((looking-at-p "{")
;; Inside a dictionary. Increase nesting.
(forward-char 1)
(setq sections (cons 'unknown sections)))
((looking-at-p "\\[")
;; Inside a list. Increase nesting
(forward-char 1)
(setq sections (cons 'list sections)))
((not (eobp))
;; other
(forward-char 1))))
(gyp-add-parse-history (point) sections)
(setq parsing (< (point) target-point))))
string-start))
(defun gyp-section-at-point ()
"Transform the last parse state, which is a list of nested sections and return
the section symbol that should be used to determine font-lock information for
the string. Can return nil indicating the string should not have any attached
section."
(let ((sections (gyp-parse-sections)))
(cond
((eq (car sections) 'conditions)
;; conditions can occur in a variables section, but we still want to
;; highlight it as a keyword.
nil)
((and (eq (car sections) 'list)
(eq (cadr sections) 'list))
;; conditions and sources can have items in [[ ]]
(caddr sections))
(t (cadr sections)))))
(defun gyp-section-match (limit)
"Parse from (point) to LIMIT returning by means of match data what was
matched. The group of the match indicates what style font-lock should apply.
See also `gyp-add-font-lock-keywords'."
(gyp-invalidate-parse-states-after (point))
(let ((group nil)
(string-start t))
(while (and (< (point) limit)
(not group)
string-start)
(setq string-start (gyp-parse-to limit))
(if string-start
(setq group (cl-case (gyp-section-at-point)
('dependencies 1)
('variables 2)
('conditions 2)
('sources 3)
('defines 4)
(nil nil)))))
(if group
(progn
;; Set the match data to indicate to the font-lock mechanism the
;; highlighting to be performed.
(set-match-data (append (list string-start (point))
(make-list (* (1- group) 2) nil)
(list (1+ string-start) (1- (point)))))
t))))
;;; Please see http://code.google.com/p/gyp/wiki/GypLanguageSpecification for
;;; canonical list of keywords.
(defun gyp-add-font-lock-keywords ()
"Add gyp-mode keywords to font-lock mechanism."
;; TODO(jknotten): Move all the keyword highlighting into gyp-section-match
;; so that we can do the font-locking in a single font-lock pass.
(font-lock-add-keywords
nil
(list
;; Top-level keywords
(list (concat "['\"]\\("
(regexp-opt (list "action" "action_name" "actions" "cflags"
"cflags_cc" "conditions" "configurations"
"copies" "defines" "dependencies" "destination"
"direct_dependent_settings"
"export_dependent_settings" "extension" "files"
"include_dirs" "includes" "inputs" "ldflags" "libraries"
"link_settings" "mac_bundle" "message"
"msvs_external_rule" "outputs" "product_name"
"process_outputs_as_sources" "rules" "rule_name"
"sources" "suppress_wildcard"
"target_conditions" "target_defaults"
"target_defines" "target_name" "toolsets"
"targets" "type" "variables" "xcode_settings"))
"[!/+=]?\\)") 1 'font-lock-keyword-face t)
;; Type of target
(list (concat "['\"]\\("
(regexp-opt (list "loadable_module" "static_library"
"shared_library" "executable" "none"))
"\\)") 1 'font-lock-type-face t)
(list "\\(?:target\\|action\\)_name['\"]\\s-*:\\s-*['\"]\\([^ '\"]*\\)" 1
'font-lock-function-name-face t)
(list 'gyp-section-match
(list 1 'font-lock-function-name-face t t) ; dependencies
(list 2 'font-lock-variable-name-face t t) ; variables, conditions
(list 3 'font-lock-constant-face t t) ; sources
(list 4 'font-lock-preprocessor-face t t)) ; preprocessor
;; Variable expansion
(list "<@?(\\([^\n )]+\\))" 1 'font-lock-variable-name-face t)
;; Command expansion
(list " "{dst}"')
print("}")
def main():
if len(sys.argv) < 2:
print(__doc__, file=sys.stderr)
print(file=sys.stderr)
print("usage: %s target1 target2..." % (sys.argv[0]), file=sys.stderr)
return 1
edges = LoadEdges("dump.json", sys.argv[1:])
WriteGraph(edges)
return 0
if __name__ == "__main__":
sys.exit(main())
================================================
FILE: gyp/tools/pretty_gyp.py
================================================
#!/usr/bin/env python3
# Copyright (c) 2012 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Pretty-prints the contents of a GYP file."""
import re
import sys
# Regex to remove comments when we're counting braces.
COMMENT_RE = re.compile(r"\s*#.*")
# Regex to remove quoted strings when we're counting braces.
# It takes into account quoted quotes, and makes sure that the quotes match.
# NOTE: It does not handle quotes that span more than one line, or
# cases where an escaped quote is preceded by an escaped backslash.
QUOTE_RE_STR = r'(?P[\'"])(.*?)(? 0:
after = True
# This catches the special case of a closing brace having something
# other than just whitespace ahead of it -- we don't want to
# unindent that until after this line is printed so it stays with
# the previous indentation level.
if cnt < 0 and closing_prefix_re.match(stripline):
after = True
return (cnt, after)
def prettyprint_input(lines):
"""Does the main work of indenting the input based on the brace counts."""
indent = 0
basic_offset = 2
for line in lines:
if COMMENT_RE.match(line):
print(line)
else:
line = line.strip("\r\n\t ") # Otherwise doesn't strip \r on Unix.
if len(line) > 0:
(brace_diff, after) = count_braces(line)
if brace_diff != 0:
if after:
print(" " * (basic_offset * indent) + line)
indent += brace_diff
else:
indent += brace_diff
print(" " * (basic_offset * indent) + line)
else:
print(" " * (basic_offset * indent) + line)
else:
print()
def main():
if len(sys.argv) > 1:
data = open(sys.argv[1]).read().splitlines()
else:
data = sys.stdin.read().splitlines()
# Split up the double braces.
lines = split_double_braces(data)
# Indent and print the output.
prettyprint_input(lines)
return 0
if __name__ == "__main__":
sys.exit(main())
================================================
FILE: gyp/tools/pretty_sln.py
================================================
#!/usr/bin/env python3
# Copyright (c) 2012 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Prints the information in a sln file in a diffable way.
It first outputs each projects in alphabetical order with their
dependencies.
Then it outputs a possible build order.
"""
import os
import re
import sys
import pretty_vcproj
__author__ = "nsylvain (Nicolas Sylvain)"
def BuildProject(project, built, projects, deps):
# if all dependencies are done, we can build it, otherwise we try to build the
# dependency.
# This is not infinite-recursion proof.
for dep in deps[project]:
if dep not in built:
BuildProject(dep, built, projects, deps)
print(project)
built.append(project)
def ParseSolution(solution_file):
# All projects, their clsid and paths.
projects = {}
# A list of dependencies associated with a project.
dependencies = {}
# Regular expressions that matches the SLN format.
# The first line of a project definition.
begin_project = re.compile(
r'^Project\("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
r'}"\) = "(.*)", "(.*)", "(.*)"$'
)
# The last line of a project definition.
end_project = re.compile("^EndProject$")
# The first line of a dependency list.
begin_dep = re.compile(r"ProjectSection\(ProjectDependencies\) = postProject$")
# The last line of a dependency list.
end_dep = re.compile("EndProjectSection$")
# A line describing a dependency.
dep_line = re.compile(" *({.*}) = ({.*})$")
in_deps = False
solution = open(solution_file)
for line in solution:
results = begin_project.search(line)
if results:
# Hack to remove icu because the diff is too different.
if results.group(1).find("icu") != -1:
continue
# We remove "_gyp" from the names because it helps to diff them.
current_project = results.group(1).replace("_gyp", "")
projects[current_project] = [
results.group(2).replace("_gyp", ""),
results.group(3),
results.group(2),
]
dependencies[current_project] = []
continue
results = end_project.search(line)
if results:
current_project = None
continue
results = begin_dep.search(line)
if results:
in_deps = True
continue
results = end_dep.search(line)
if results:
in_deps = False
continue
results = dep_line.search(line)
if results and in_deps and current_project:
dependencies[current_project].append(results.group(1))
continue
# Change all dependencies clsid to name instead.
for project, deps in dependencies.items():
# For each dependencies in this project
new_dep_array = []
for dep in deps:
# Look for the project name matching this cldis
for project_info in projects:
if projects[project_info][1] == dep:
new_dep_array.append(project_info)
dependencies[project] = sorted(new_dep_array)
return (projects, dependencies)
def PrintDependencies(projects, deps):
print("---------------------------------------")
print("Dependencies for all projects")
print("---------------------------------------")
print("-- --")
for project, dep_list in sorted(deps.items()):
print("Project : %s" % project)
print("Path : %s" % projects[project][0])
if dep_list:
for dep in dep_list:
print(" - %s" % dep)
print()
print("-- --")
def PrintBuildOrder(projects, deps):
print("---------------------------------------")
print("Build order ")
print("---------------------------------------")
print("-- --")
built = []
for project, _ in sorted(deps.items()):
if project not in built:
BuildProject(project, built, projects, deps)
print("-- --")
def PrintVCProj(projects):
for project in projects:
print("-------------------------------------")
print("-------------------------------------")
print(project)
print(project)
print(project)
print("-------------------------------------")
print("-------------------------------------")
project_path = os.path.abspath(
os.path.join(os.path.dirname(sys.argv[1]), projects[project][2])
)
pretty = pretty_vcproj
argv = [
"",
project_path,
"$(SolutionDir)=%s\\" % os.path.dirname(sys.argv[1]),
]
argv.extend(sys.argv[3:])
pretty.main(argv)
def main():
# check if we have exactly 1 parameter.
if len(sys.argv) < 2:
print('Usage: %s "c:\\path\\to\\project.sln"' % sys.argv[0])
return 1
(projects, deps) = ParseSolution(sys.argv[1])
PrintDependencies(projects, deps)
PrintBuildOrder(projects, deps)
if "--recursive" in sys.argv:
PrintVCProj(projects)
return 0
if __name__ == "__main__":
sys.exit(main())
================================================
FILE: gyp/tools/pretty_vcproj.py
================================================
#!/usr/bin/env python3
# Copyright (c) 2012 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Make the format of a vcproj really pretty.
This script normalize and sort an xml. It also fetches all the properties
inside linked vsprops and include them explicitly in the vcproj.
It outputs the resulting xml to stdout.
"""
import os
import sys
from xml.dom.minidom import Node, parse
__author__ = "nsylvain (Nicolas Sylvain)"
ARGUMENTS = None
REPLACEMENTS = {}
def cmp(x, y):
return (x > y) - (x < y)
class CmpTuple:
"""Compare function between 2 tuple."""
def __call__(self, x, y):
return cmp(x[0], y[0])
class CmpNode:
"""Compare function between 2 xml nodes."""
def __call__(self, x, y):
def get_string(node):
node_string = "node"
node_string += node.nodeName
if node.nodeValue:
node_string += node.nodeValue
if node.attributes:
# We first sort by name, if present.
node_string += node.getAttribute("Name")
all_nodes = []
for name, value in node.attributes.items():
all_nodes.append((name, value))
all_nodes.sort(CmpTuple())
for name, value in all_nodes:
node_string += name
node_string += value
return node_string
return cmp(get_string(x), get_string(y))
def PrettyPrintNode(node, indent=0):
if node.nodeType == Node.TEXT_NODE:
if node.data.strip():
print("{}{}".format(" " * indent, node.data.strip()))
return
if node.childNodes:
node.normalize()
# Get the number of attributes
attr_count = 0
if node.attributes:
attr_count = node.attributes.length
# Print the main tag
if attr_count == 0:
print("{}<{}>".format(" " * indent, node.nodeName))
else:
print("{}<{}".format(" " * indent, node.nodeName))
all_attributes = []
for name, value in node.attributes.items():
all_attributes.append((name, value))
all_attributes.sort(CmpTuple())
for name, value in all_attributes:
print('{} {}="{}"'.format(" " * indent, name, value))
print("%s>" % (" " * indent))
if node.nodeValue:
print("{} {}".format(" " * indent, node.nodeValue))
for sub_node in node.childNodes:
PrettyPrintNode(sub_node, indent=indent + 2)
print("{}{}>".format(" " * indent, node.nodeName))
def FlattenFilter(node):
"""Returns a list of all the node and sub nodes."""
node_list = []
if node.attributes and node.getAttribute("Name") == "_excluded_files":
# We don't add the "_excluded_files" filter.
return []
for current in node.childNodes:
if current.nodeName == "Filter":
node_list.extend(FlattenFilter(current))
else:
node_list.append(current)
return node_list
def FixFilenames(filenames, current_directory):
new_list = []
for filename in filenames:
if filename:
for key, value in REPLACEMENTS.items():
filename = filename.replace(key, value)
os.chdir(current_directory)
filename = filename.strip("\"' ")
if filename.startswith("$"):
new_list.append(filename)
else:
new_list.append(os.path.abspath(filename))
return new_list
def AbsoluteNode(node):
"""Makes all the properties we know about in this node absolute."""
if node.attributes:
for name, value in node.attributes.items():
if name in [
"InheritedPropertySheets",
"RelativePath",
"AdditionalIncludeDirectories",
"IntermediateDirectory",
"OutputDirectory",
"AdditionalLibraryDirectories",
]:
# We want to fix up these paths
path_list = value.split(";")
new_list = FixFilenames(path_list, os.path.dirname(ARGUMENTS[1]))
node.setAttribute(name, ";".join(new_list))
if not value:
node.removeAttribute(name)
def CleanupVcproj(node):
"""For each sub node, we call recursively this function."""
for sub_node in node.childNodes:
AbsoluteNode(sub_node)
CleanupVcproj(sub_node)
# Normalize the node, and remove all extraneous whitespaces.
for sub_node in node.childNodes:
if sub_node.nodeType == Node.TEXT_NODE:
sub_node.data = sub_node.data.replace("\r", "")
sub_node.data = sub_node.data.replace("\n", "")
sub_node.data = sub_node.data.rstrip()
# Fix all the semicolon separated attributes to be sorted, and we also
# remove the dups.
if node.attributes:
for name, value in node.attributes.items():
sorted_list = sorted(value.split(";"))
unique_list = []
for i in sorted_list:
if not unique_list.count(i):
unique_list.append(i)
node.setAttribute(name, ";".join(unique_list))
if not value:
node.removeAttribute(name)
if node.childNodes:
node.normalize()
# For each node, take a copy, and remove it from the list.
node_array = []
while node.childNodes and node.childNodes[0]:
# Take a copy of the node and remove it from the list.
current = node.childNodes[0]
node.removeChild(current)
# If the child is a filter, we want to append all its children
# to this same list.
if current.nodeName == "Filter":
node_array.extend(FlattenFilter(current))
else:
node_array.append(current)
# Sort the list.
node_array.sort(CmpNode())
# Insert the nodes in the correct order.
for new_node in node_array:
# But don't append empty tool node.
if new_node.nodeName == "Tool":
if new_node.attributes and new_node.attributes.length == 1:
# This one was empty.
continue
if new_node.nodeName == "UserMacro":
continue
node.appendChild(new_node)
def GetConfigurationNodes(vcproj):
# TODO(nsylvain): Find a better way to navigate the xml.
nodes = []
for node in vcproj.childNodes:
if node.nodeName == "Configurations":
for sub_node in node.childNodes:
if sub_node.nodeName == "Configuration":
nodes.append(sub_node)
return nodes
def GetChildrenVsprops(filename):
dom = parse(filename)
if dom.documentElement.attributes:
vsprops = dom.documentElement.getAttribute("InheritedPropertySheets")
return FixFilenames(vsprops.split(";"), os.path.dirname(filename))
return []
def SeekToNode(node1, child2):
# A text node does not have properties.
if child2.nodeType == Node.TEXT_NODE:
return None
# Get the name of the current node.
current_name = child2.getAttribute("Name")
if not current_name:
# There is no name. We don't know how to merge.
return None
# Look through all the nodes to find a match.
for sub_node in node1.childNodes:
if sub_node.nodeName == child2.nodeName:
name = sub_node.getAttribute("Name")
if name == current_name:
return sub_node
# No match. We give up.
return None
def MergeAttributes(node1, node2):
# No attributes to merge?
if not node2.attributes:
return
for name, value2 in node2.attributes.items():
# Don't merge the 'Name' attribute.
if name == "Name":
continue
value1 = node1.getAttribute(name)
if value1:
# The attribute exist in the main node. If it's equal, we leave it
# untouched, otherwise we concatenate it.
if value1 != value2:
node1.setAttribute(name, ";".join([value1, value2]))
else:
# The attribute does not exist in the main node. We append this one.
node1.setAttribute(name, value2)
# If the attribute was a property sheet attributes, we remove it, since
# they are useless.
if name == "InheritedPropertySheets":
node1.removeAttribute(name)
def MergeProperties(node1, node2):
MergeAttributes(node1, node2)
for child2 in node2.childNodes:
child1 = SeekToNode(node1, child2)
if child1:
MergeProperties(child1, child2)
else:
node1.appendChild(child2.cloneNode(True))
def main(argv):
"""Main function of this vcproj prettifier."""
global ARGUMENTS
ARGUMENTS = argv
# check if we have exactly 1 parameter.
if len(argv) < 2:
print(
'Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] '
"[key2=value2]" % argv[0]
)
return 1
# Parse the keys
for i in range(2, len(argv)):
(key, value) = argv[i].split("=")
REPLACEMENTS[key] = value
# Open the vcproj and parse the xml.
dom = parse(argv[1])
# First thing we need to do is find the Configuration Node and merge them
# with the vsprops they include.
for configuration_node in GetConfigurationNodes(dom.documentElement):
# Get the property sheets associated with this configuration.
vsprops = configuration_node.getAttribute("InheritedPropertySheets")
# Fix the filenames to be absolute.
vsprops_list = FixFilenames(
vsprops.strip().split(";"), os.path.dirname(argv[1])
)
# Extend the list of vsprops with all vsprops contained in the current
# vsprops.
for current_vsprops in vsprops_list:
vsprops_list.extend(GetChildrenVsprops(current_vsprops))
# Now that we have all the vsprops, we need to merge them.
for current_vsprops in vsprops_list:
MergeProperties(configuration_node, parse(current_vsprops).documentElement)
# Now that everything is merged, we need to cleanup the xml.
CleanupVcproj(dom.documentElement)
# Finally, we use the prett xml function to print the vcproj back to the
# user.
# print dom.toprettyxml(newl="\n")
PrettyPrintNode(dom.documentElement)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
================================================
FILE: lib/Find-VisualStudio.cs
================================================
// Copyright 2017 - Refael Ackermann
// Distributed under MIT style license
// See accompanying file LICENSE at https://github.com/node4good/windows-autoconf
// Usage:
// powershell -ExecutionPolicy Unrestricted -Command "Add-Type -Path Find-VisualStudio.cs; [VisualStudioConfiguration.Main]::PrintJson()"
// This script needs to be compatible with PowerShell v2 to run on Windows 2008R2 and Windows 7.
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace VisualStudioConfiguration
{
[Flags]
public enum InstanceState : uint
{
None = 0,
Local = 1,
Registered = 2,
NoRebootRequired = 4,
NoErrors = 8,
Complete = 4294967295,
}
[Guid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface IEnumSetupInstances
{
void Next([MarshalAs(UnmanagedType.U4), In] int celt,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface), Out] ISetupInstance[] rgelt,
[MarshalAs(UnmanagedType.U4)] out int pceltFetched);
void Skip([MarshalAs(UnmanagedType.U4), In] int celt);
void Reset();
[return: MarshalAs(UnmanagedType.Interface)]
IEnumSetupInstances Clone();
}
[Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface ISetupConfiguration
{
}
[Guid("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface ISetupConfiguration2 : ISetupConfiguration
{
[return: MarshalAs(UnmanagedType.Interface)]
IEnumSetupInstances EnumInstances();
[return: MarshalAs(UnmanagedType.Interface)]
ISetupInstance GetInstanceForCurrentProcess();
[return: MarshalAs(UnmanagedType.Interface)]
ISetupInstance GetInstanceForPath([MarshalAs(UnmanagedType.LPWStr), In] string path);
[return: MarshalAs(UnmanagedType.Interface)]
IEnumSetupInstances EnumAllInstances();
}
[Guid("B41463C3-8866-43B5-BC33-2B0676F7F42E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface ISetupInstance
{
}
[Guid("89143C9A-05AF-49B0-B717-72E218A2185C")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface ISetupInstance2 : ISetupInstance
{
[return: MarshalAs(UnmanagedType.BStr)]
string GetInstanceId();
[return: MarshalAs(UnmanagedType.Struct)]
System.Runtime.InteropServices.ComTypes.FILETIME GetInstallDate();
[return: MarshalAs(UnmanagedType.BStr)]
string GetInstallationName();
[return: MarshalAs(UnmanagedType.BStr)]
string GetInstallationPath();
[return: MarshalAs(UnmanagedType.BStr)]
string GetInstallationVersion();
[return: MarshalAs(UnmanagedType.BStr)]
string GetDisplayName([MarshalAs(UnmanagedType.U4), In] int lcid);
[return: MarshalAs(UnmanagedType.BStr)]
string GetDescription([MarshalAs(UnmanagedType.U4), In] int lcid);
[return: MarshalAs(UnmanagedType.BStr)]
string ResolvePath([MarshalAs(UnmanagedType.LPWStr), In] string pwszRelativePath);
[return: MarshalAs(UnmanagedType.U4)]
InstanceState GetState();
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)]
ISetupPackageReference[] GetPackages();
ISetupPackageReference GetProduct();
[return: MarshalAs(UnmanagedType.BStr)]
string GetProductPath();
[return: MarshalAs(UnmanagedType.VariantBool)]
bool IsLaunchable();
[return: MarshalAs(UnmanagedType.VariantBool)]
bool IsComplete();
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)]
ISetupPropertyStore GetProperties();
[return: MarshalAs(UnmanagedType.BStr)]
string GetEnginePath();
}
[Guid("DA8D8A16-B2B6-4487-A2F1-594CCCCD6BF5")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface ISetupPackageReference
{
[return: MarshalAs(UnmanagedType.BStr)]
string GetId();
[return: MarshalAs(UnmanagedType.BStr)]
string GetVersion();
[return: MarshalAs(UnmanagedType.BStr)]
string GetChip();
[return: MarshalAs(UnmanagedType.BStr)]
string GetLanguage();
[return: MarshalAs(UnmanagedType.BStr)]
string GetBranch();
[return: MarshalAs(UnmanagedType.BStr)]
string GetType();
[return: MarshalAs(UnmanagedType.BStr)]
string GetUniqueId();
[return: MarshalAs(UnmanagedType.VariantBool)]
bool GetIsExtension();
}
[Guid("c601c175-a3be-44bc-91f6-4568d230fc83")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface ISetupPropertyStore
{
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
string[] GetNames();
object GetValue([MarshalAs(UnmanagedType.LPWStr), In] string pwszName);
}
[Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")]
[CoClass(typeof(SetupConfigurationClass))]
[ComImport]
public interface SetupConfiguration : ISetupConfiguration2, ISetupConfiguration
{
}
[Guid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")]
[ClassInterface(ClassInterfaceType.None)]
[ComImport]
public class SetupConfigurationClass
{
}
public static class Main
{
public static void PrintJson()
{
ISetupConfiguration query = new SetupConfiguration();
ISetupConfiguration2 query2 = (ISetupConfiguration2)query;
IEnumSetupInstances e = query2.EnumAllInstances();
int pceltFetched;
ISetupInstance2[] rgelt = new ISetupInstance2[1];
List instances = new List();
while (true)
{
e.Next(1, rgelt, out pceltFetched);
if (pceltFetched <= 0)
{
Console.WriteLine(String.Format("[{0}]", string.Join(",", instances.ToArray())));
return;
}
try
{
instances.Add(InstanceJson(rgelt[0]));
}
catch (COMException)
{
// Ignore instances that can't be queried.
}
}
}
private static string JsonString(string s)
{
return "\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
}
private static string InstanceJson(ISetupInstance2 setupInstance2)
{
// Visual Studio component directory:
// https://docs.microsoft.com/en-us/visualstudio/install/workload-and-component-ids
StringBuilder json = new StringBuilder();
json.Append("{");
string path = JsonString(setupInstance2.GetInstallationPath());
json.Append(String.Format("\"path\":{0},", path));
string version = JsonString(setupInstance2.GetInstallationVersion());
json.Append(String.Format("\"version\":{0},", version));
List packages = new List();
foreach (ISetupPackageReference package in setupInstance2.GetPackages())
{
string id = JsonString(package.GetId());
packages.Add(id);
}
json.Append(String.Format("\"packages\":[{0}]", string.Join(",", packages.ToArray())));
json.Append("}");
return json.ToString();
}
}
}
================================================
FILE: lib/build.js
================================================
'use strict'
const gracefulFs = require('graceful-fs')
const fs = gracefulFs.promises
const path = require('path')
const { glob } = require('tinyglobby')
const log = require('./log')
const which = require('which')
const win = process.platform === 'win32'
async function build (gyp, argv) {
let platformMake = 'make'
if (process.platform === 'aix') {
platformMake = 'gmake'
} else if (process.platform === 'os400') {
platformMake = 'gmake'
} else if (process.platform.indexOf('bsd') !== -1) {
platformMake = 'gmake'
} else if (win && argv.length > 0) {
argv = argv.map(function (target) {
return '/t:' + target
})
}
const makeCommand = gyp.opts.make || process.env.MAKE || platformMake
let command = win ? 'msbuild' : makeCommand
const jobs = gyp.opts.jobs || process.env.JOBS
let buildType
let config
let arch
let nodeDir
let guessedSolution
let python
let buildBinsDir
await loadConfigGypi()
/**
* Load the "config.gypi" file that was generated during "configure".
*/
async function loadConfigGypi () {
let data
try {
const configPath = path.resolve('build', 'config.gypi')
data = await fs.readFile(configPath, 'utf8')
} catch (err) {
if (err.code === 'ENOENT') {
throw new Error('You must run `node-gyp configure` first!')
} else {
throw err
}
}
config = JSON.parse(data.replace(/#.+\n/, ''))
// get the 'arch', 'buildType', and 'nodeDir' vars from the config
buildType = config.target_defaults.default_configuration
arch = config.variables.target_arch
nodeDir = config.variables.nodedir
python = config.variables.python
if ('debug' in gyp.opts) {
buildType = gyp.opts.debug ? 'Debug' : 'Release'
}
if (!buildType) {
buildType = 'Release'
}
log.verbose('build type', buildType)
log.verbose('architecture', arch)
log.verbose('node dev dir', nodeDir)
log.verbose('python', python)
if (win) {
await findSolutionFile()
} else {
await doWhich()
}
}
/**
* On Windows, find the first build/*.sln file.
*/
async function findSolutionFile () {
const files = await glob('build/*.sln', { expandDirectories: false })
if (files.length === 0) {
if (gracefulFs.existsSync('build/Makefile') ||
(await glob('build/*.mk', { expandDirectories: false })).length !== 0) {
command = makeCommand
await doWhich(false)
return
} else {
throw new Error('Could not find *.sln file or Makefile. Did you run "configure"?')
}
}
guessedSolution = files[0]
log.verbose('found first Solution file', guessedSolution)
await doWhich(true)
}
/**
* Uses node-which to locate the msbuild / make executable.
*/
async function doWhich (msvs) {
// On Windows use msbuild provided by node-gyp configure
if (msvs) {
if (!config.variables.msbuild_path) {
throw new Error('MSBuild is not set, please run `node-gyp configure`.')
}
command = config.variables.msbuild_path
log.verbose('using MSBuild:', command)
await doBuild(msvs)
return
}
// First make sure we have the build command in the PATH
const execPath = await which(command)
log.verbose('`which` succeeded for `' + command + '`', execPath)
await doBuild(msvs)
}
/**
* Actually spawn the process and compile the module.
*/
async function doBuild (msvs) {
// Enable Verbose build
const verbose = log.logger.isVisible('verbose')
let j
if (!msvs && verbose) {
argv.push('V=1')
}
if (msvs && !verbose) {
argv.push('/clp:Verbosity=minimal')
}
if (msvs) {
// Turn off the Microsoft logo on Windows
argv.push('/nologo')
// No lingering msbuild processes and open file handles
argv.push('/nodeReuse:false')
}
// Specify the build type, Release by default
if (msvs) {
// Convert .gypi config target_arch to MSBuild /Platform
// Since there are many ways to state '32-bit Intel', default to it.
// N.B. msbuild's Condition string equality tests are case-insensitive.
const archLower = arch.toLowerCase()
const p = archLower === 'x64'
? 'x64'
: (archLower === 'arm'
? 'ARM'
: (archLower === 'arm64' ? 'ARM64' : 'Win32'))
argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
if (jobs) {
j = parseInt(jobs, 10)
if (!isNaN(j) && j > 0) {
argv.push('/m:' + j)
} else if (jobs.toUpperCase() === 'MAX') {
argv.push('/m:' + require('os').availableParallelism())
}
}
} else {
argv.push('BUILDTYPE=' + buildType)
// Invoke the Makefile in the 'build' dir.
argv.push('-C')
argv.push('build')
if (jobs) {
j = parseInt(jobs, 10)
if (!isNaN(j) && j > 0) {
argv.push('--jobs')
argv.push(j)
} else if (jobs.toUpperCase() === 'MAX') {
argv.push('--jobs')
argv.push(require('os').availableParallelism())
}
}
}
if (msvs) {
// did the user specify their own .sln file?
const hasSln = argv.some(function (arg) {
return path.extname(arg) === '.sln'
})
if (!hasSln) {
argv.unshift(gyp.opts.solution || guessedSolution)
}
}
if (!win) {
// Add build-time dependency symlinks (such as Python) to PATH
buildBinsDir = path.resolve('build', 'node_gyp_bins')
process.env.PATH = `${buildBinsDir}:${process.env.PATH}`
await fs.mkdir(buildBinsDir, { recursive: true })
const symlinkDestination = path.join(buildBinsDir, 'python3')
try {
await fs.unlink(symlinkDestination)
} catch (err) {
if (err.code !== 'ENOENT') throw err
}
await fs.symlink(python, symlinkDestination)
log.verbose('bin symlinks', `created symlink to "${python}" in "${buildBinsDir}" and added to PATH`)
}
const proc = gyp.spawn(command, argv)
await new Promise((resolve, reject) => proc.on('exit', async (code, signal) => {
if (buildBinsDir) {
// Clean up the build-time dependency symlinks:
await fs.rm(buildBinsDir, { recursive: true, maxRetries: 3 })
}
if (code !== 0) {
return reject(new Error('`' + command + '` failed with exit code: ' + code))
}
if (signal) {
return reject(new Error('`' + command + '` got signal: ' + signal))
}
resolve()
}))
}
}
module.exports = build
module.exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
================================================
FILE: lib/clean.js
================================================
'use strict'
const fs = require('graceful-fs').promises
const log = require('./log')
async function clean (gyp, argv) {
// Remove the 'build' dir
const buildDir = 'build'
log.verbose('clean', 'removing "%s" directory', buildDir)
await fs.rm(buildDir, { recursive: true, force: true, maxRetries: 3 })
}
module.exports = clean
module.exports.usage = 'Removes any generated build files and the "out" dir'
================================================
FILE: lib/configure.js
================================================
'use strict'
const { promises: fs, readFileSync } = require('graceful-fs')
const path = require('path')
const log = require('./log')
const os = require('os')
const processRelease = require('./process-release')
const win = process.platform === 'win32'
const findNodeDirectory = require('./find-node-directory')
const { createConfigGypi } = require('./create-config-gypi')
const { format: msgFormat } = require('util')
const { findAccessibleSync } = require('./util')
const { findPython } = require('./find-python')
const { findVisualStudio } = win ? require('./find-visualstudio') : {}
const majorRe = /^#define NODE_MAJOR_VERSION (\d+)/m
const minorRe = /^#define NODE_MINOR_VERSION (\d+)/m
const patchRe = /^#define NODE_PATCH_VERSION (\d+)/m
async function configure (gyp, argv) {
const buildDir = path.resolve('build')
const configNames = ['config.gypi', 'common.gypi']
const configs = []
let nodeDir
const release = processRelease(argv, gyp, process.version, process.release)
const python = await findPython(gyp.opts.python)
return getNodeDir()
async function getNodeDir () {
// 'python' should be set by now
process.env.PYTHON = python
if (!gyp.opts.nodedir &&
process.config.variables.use_prefix_to_find_headers) {
// check if the headers can be found using the prefix specified
// at build time. Use them if they match the version expected
const prefix = process.config.variables.node_prefix
let availVersion
try {
const nodeVersionH = readFileSync(path.join(prefix,
'include', 'node', 'node_version.h'), { encoding: 'utf8' })
const major = nodeVersionH.match(majorRe)[1]
const minor = nodeVersionH.match(minorRe)[1]
const patch = nodeVersionH.match(patchRe)[1]
availVersion = major + '.' + minor + '.' + patch
} catch {}
if (availVersion === release.version) {
// ok version matches, use the headers
gyp.opts.nodedir = prefix
log.verbose('using local node headers based on prefix',
'setting nodedir to ' + gyp.opts.nodedir)
}
}
if (gyp.opts.nodedir) {
// --nodedir was specified. use that for the dev files
nodeDir = gyp.opts.nodedir.replace(/^~/, os.homedir())
log.verbose('get node dir', 'compiling against specified --nodedir dev files: %s', nodeDir)
} else {
// if no --nodedir specified, ensure node dependencies are installed
if ('v' + release.version !== process.version) {
// if --target was given, then determine a target version to compile for
log.verbose('get node dir', 'compiling against --target node version: %s', release.version)
} else {
// if no --target was specified then use the current host node version
log.verbose('get node dir', 'no --target version specified, falling back to host node version: %s', release.version)
}
if (!release.semver) {
// could not parse the version string with semver
throw new Error('Invalid version number: ' + release.version)
}
// If the tarball option is set, always remove and reinstall the headers
// into devdir. Otherwise only install if they're not already there.
gyp.opts.ensure = !gyp.opts.tarball
await gyp.commands.install([release.version])
log.verbose('get node dir', 'target node version installed:', release.versionDir)
nodeDir = path.resolve(gyp.devDir, release.versionDir)
}
return createBuildDir()
}
async function createBuildDir () {
log.verbose('build dir', 'attempting to create "build" dir: %s', buildDir)
const isNew = await fs.mkdir(buildDir, { recursive: true })
log.verbose(
'build dir', '"build" dir needed to be created?', isNew ? 'Yes' : 'No'
)
if (win) {
let usingMakeGenerator = false
for (let i = argv.length - 1; i >= 0; --i) {
const arg = argv[i]
if (arg === '-f' || arg === '--format') {
const format = argv[i + 1]
if (typeof format === 'string' && format.startsWith('make')) {
usingMakeGenerator = true
break
}
} else if (arg.startsWith('--format=make')) {
usingMakeGenerator = true
break
}
}
let vsInfo = {}
if (!usingMakeGenerator) {
vsInfo = await findVisualStudio(release.semver, gyp.opts['msvs-version'])
}
return createConfigFile(vsInfo)
}
return createConfigFile(null)
}
async function createConfigFile (vsInfo) {
if (win) {
process.env.GYP_MSVS_VERSION = Math.min(vsInfo.versionYear, 2015)
process.env.GYP_MSVS_OVERRIDE_PATH = vsInfo.path
}
const configPath = await createConfigGypi({ gyp, buildDir, nodeDir, vsInfo, python })
configs.push(configPath)
return findConfigs()
}
async function findConfigs () {
const name = configNames.shift()
if (!name) {
return runGyp()
}
const fullPath = path.resolve(name)
log.verbose(name, 'checking for gypi file: %s', fullPath)
try {
await fs.stat(fullPath)
log.verbose(name, 'found gypi file')
configs.push(fullPath)
} catch (err) {
// ENOENT will check next gypi filename
if (err.code !== 'ENOENT') {
throw err
}
}
return findConfigs()
}
async function runGyp () {
if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
if (win) {
log.verbose('gyp', 'gyp format was not specified; forcing "msvs"')
// force the 'make' target for non-Windows
argv.push('-f', 'msvs')
} else {
log.verbose('gyp', 'gyp format was not specified; forcing "make"')
// force the 'make' target for non-Windows
argv.push('-f', 'make')
}
}
// include all the ".gypi" files that were found
configs.forEach(function (config) {
argv.push('-I', config)
})
// For AIX and z/OS we need to set up the path to the exports file
// which contains the symbols needed for linking.
let nodeExpFile
let nodeRootDir
let candidates
let logprefix = 'find exports file'
if (process.platform === 'aix' || process.platform === 'os390' || process.platform === 'os400') {
const ext = process.platform === 'os390' ? 'x' : 'exp'
nodeRootDir = findNodeDirectory()
if (process.platform === 'aix' || process.platform === 'os400') {
candidates = [
'include/node/node',
'out/Release/node',
'out/Debug/node',
'node'
].map(function (file) {
return file + '.' + ext
})
} else {
candidates = [
'out/Release/lib.target/libnode',
'out/Debug/lib.target/libnode',
'out/Release/obj.target/libnode',
'out/Debug/obj.target/libnode',
'lib/libnode'
].map(function (file) {
return file + '.' + ext
})
}
nodeExpFile = findAccessibleSync(logprefix, nodeRootDir, candidates)
if (nodeExpFile !== undefined) {
log.verbose(logprefix, 'Found exports file: %s', nodeExpFile)
} else {
const msg = msgFormat('Could not find node.%s file in %s', ext, nodeRootDir)
log.error(logprefix, 'Could not find exports file')
throw new Error(msg)
}
}
// For z/OS we need to set up the path to zoslib include directory,
// which contains headers included in v8config.h.
let zoslibIncDir
if (process.platform === 'os390') {
logprefix = "find zoslib's zos-base.h:"
let msg
let zoslibIncPath = process.env.ZOSLIB_INCLUDES
if (zoslibIncPath) {
zoslibIncPath = findAccessibleSync(logprefix, zoslibIncPath, ['zos-base.h'])
if (zoslibIncPath === undefined) {
msg = msgFormat('Could not find zos-base.h file in the directory set ' +
'in ZOSLIB_INCLUDES environment variable: %s; set it ' +
'to the correct path, or unset it to search %s', process.env.ZOSLIB_INCLUDES, nodeRootDir)
}
} else {
candidates = [
'include/node/zoslib/zos-base.h',
'include/zoslib/zos-base.h',
'zoslib/include/zos-base.h',
'install/include/node/zoslib/zos-base.h'
]
zoslibIncPath = findAccessibleSync(logprefix, nodeRootDir, candidates)
if (zoslibIncPath === undefined) {
msg = msgFormat('Could not find any of %s in directory %s; set ' +
'environmant variable ZOSLIB_INCLUDES to the path ' +
'that contains zos-base.h', candidates.toString(), nodeRootDir)
}
}
if (zoslibIncPath !== undefined) {
zoslibIncDir = path.dirname(zoslibIncPath)
log.verbose(logprefix, "Found zoslib's zos-base.h in: %s", zoslibIncDir)
} else if (release.version.split('.')[0] >= 16) {
// zoslib is only shipped in Node v16 and above.
log.error(logprefix, msg)
throw new Error(msg)
}
}
// this logic ported from the old `gyp_addon` python file
const gypScript = path.resolve(__dirname, '..', 'gyp', 'gyp_main.py')
const addonGypi = path.resolve(__dirname, '..', 'addon.gypi')
let commonGypi = path.resolve(nodeDir, 'include/node/common.gypi')
try {
await fs.stat(commonGypi)
} catch (err) {
commonGypi = path.resolve(nodeDir, 'common.gypi')
}
let outputDir = 'build'
if (win) {
// Windows expects an absolute path
outputDir = buildDir
}
const nodeGypDir = path.resolve(__dirname, '..')
let nodeLibFile = path.join(nodeDir,
!gyp.opts.nodedir ? '<(target_arch)' : '$(Configuration)',
release.name + '.lib')
argv.push('-I', addonGypi)
argv.push('-I', commonGypi)
argv.push('-Dlibrary=shared_library')
argv.push('-Dvisibility=default')
argv.push('-Dnode_root_dir=' + nodeDir)
if (process.platform === 'aix' || process.platform === 'os390' || process.platform === 'os400') {
argv.push('-Dnode_exp_file=' + nodeExpFile)
if (process.platform === 'os390' && zoslibIncDir) {
argv.push('-Dzoslib_include_dir=' + zoslibIncDir)
}
}
argv.push('-Dnode_gyp_dir=' + nodeGypDir)
// Do this to keep Cygwin environments happy, else the unescaped '\' gets eaten up,
// resulting in bad paths, Ex c:parentFolderfolderanotherFolder instead of c:\parentFolder\folder\anotherFolder
if (win) {
nodeLibFile = nodeLibFile.replace(/\\/g, '\\\\')
}
argv.push('-Dnode_lib_file=' + nodeLibFile)
argv.push('-Dmodule_root_dir=' + process.cwd())
argv.push('-Dnode_engine=' +
(gyp.opts.node_engine || process.jsEngine || 'v8'))
argv.push('--depth=.')
argv.push('--no-parallel')
// tell gyp to write the Makefile/Solution files into output_dir
argv.push('--generator-output', outputDir)
// tell make to write its output into the same dir
argv.push('-Goutput_dir=.')
// enforce use of the "binding.gyp" file
argv.unshift('binding.gyp')
// execute `gyp` from the current target nodedir
argv.unshift(gypScript)
// make sure python uses files that came with this particular node package
const pypath = [path.join(__dirname, '..', 'gyp', 'pylib')]
if (process.env.PYTHONPATH) {
pypath.push(process.env.PYTHONPATH)
}
process.env.PYTHONPATH = pypath.join(win ? ';' : ':')
await new Promise((resolve, reject) => {
const cp = gyp.spawn(python, argv)
cp.on('exit', (code) => {
if (code !== 0) {
reject(new Error('`gyp` failed with exit code: ' + code))
} else {
// we're done
resolve()
}
})
})
}
}
module.exports = configure
module.exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'
================================================
FILE: lib/create-config-gypi.js
================================================
'use strict'
const fs = require('graceful-fs').promises
const log = require('./log')
const path = require('path')
function parseConfigGypi (config) {
// translated from tools/js2c.py of Node.js
// 1. string comments
config = config.replace(/#.*/g, '')
// 2. join multiline strings
config = config.replace(/'$\s+'/mg, '')
// 3. normalize string literals from ' into "
config = config.replace(/'/g, '"')
return JSON.parse(config)
}
async function getBaseConfigGypi ({ gyp, nodeDir }) {
// try reading $nodeDir/include/node/config.gypi first when:
// 1. --dist-url or --nodedir is specified
// 2. and --force-process-config is not specified
const useCustomHeaders = gyp.opts.nodedir || gyp.opts.disturl || gyp.opts['dist-url']
const shouldReadConfigGypi = useCustomHeaders && !gyp.opts['force-process-config']
if (shouldReadConfigGypi && nodeDir) {
try {
const baseConfigGypiPath = path.resolve(nodeDir, 'include/node/config.gypi')
const baseConfigGypi = await fs.readFile(baseConfigGypiPath)
return parseConfigGypi(baseConfigGypi.toString())
} catch (err) {
log.warn('read config.gypi', err.message)
}
}
// fallback to process.config if it is invalid
return JSON.parse(JSON.stringify(process.config))
}
async function getCurrentConfigGypi ({ gyp, nodeDir, vsInfo, python }) {
const config = await getBaseConfigGypi({ gyp, nodeDir })
if (!config.target_defaults) {
config.target_defaults = {}
}
if (!config.variables) {
config.variables = {}
}
const defaults = config.target_defaults
const variables = config.variables
// don't inherit the "defaults" from the base config.gypi.
// doing so could cause problems in cases where the `node` executable was
// compiled on a different machine (with different lib/include paths) than
// the machine where the addon is being built to
defaults.cflags = []
defaults.defines = []
defaults.include_dirs = []
defaults.libraries = []
// set the default_configuration prop
if ('debug' in gyp.opts) {
defaults.default_configuration = gyp.opts.debug ? 'Debug' : 'Release'
}
if (!defaults.default_configuration) {
defaults.default_configuration = 'Release'
}
// set the target_arch variable
variables.target_arch = gyp.opts.arch || process.arch || 'ia32'
if (variables.target_arch === 'arm64') {
defaults.msvs_configuration_platform = 'ARM64'
defaults.xcode_configuration_platform = 'arm64'
}
// set the node development directory
variables.nodedir = nodeDir
// set the configured Python path
variables.python = python
// disable -T "thin" static archives by default
variables.standalone_static_library = gyp.opts.thin ? 0 : 1
if (process.platform === 'win32') {
defaults.msbuild_toolset = vsInfo.toolset
if (vsInfo.sdk) {
defaults.msvs_windows_target_platform_version = vsInfo.sdk
}
if (variables.target_arch === 'arm64') {
if (vsInfo.versionMajor > 15 ||
(vsInfo.versionMajor === 15 && vsInfo.versionMajor >= 9)) {
defaults.msvs_enable_marmasm = 1
} else {
log.warn('Compiling ARM64 assembly is only available in\n' +
'Visual Studio 2017 version 15.9 and above')
}
}
variables.msbuild_path = vsInfo.msBuild
if (config.variables.clang === 1) {
config.variables.clang = 0
}
}
// loop through the rest of the opts and add the unknown ones as variables.
// this allows for module-specific configure flags like:
//
// $ node-gyp configure --shared-libxml2
Object.keys(gyp.opts).forEach(function (opt) {
if (opt === 'argv') {
return
}
if (opt in gyp.configDefs) {
return
}
variables[opt.replace(/-/g, '_')] = gyp.opts[opt]
})
return config
}
async function createConfigGypi ({ gyp, buildDir, nodeDir, vsInfo, python }) {
const configFilename = 'config.gypi'
const configPath = path.resolve(buildDir, configFilename)
log.verbose('build/' + configFilename, 'creating config file')
const config = await getCurrentConfigGypi({ gyp, nodeDir, vsInfo, python })
// ensures that any boolean values in config.gypi get stringified
function boolsToString (k, v) {
if (typeof v === 'boolean') {
return String(v)
}
return v
}
log.silly('build/' + configFilename, config)
// now write out the config.gypi file to the build/ dir
const prefix = '# Do not edit. File was generated by node-gyp\'s "configure" step'
const json = JSON.stringify(config, boolsToString, 2)
log.verbose('build/' + configFilename, 'writing out config file: %s', configPath)
await fs.writeFile(configPath, [prefix, json, ''].join('\n'))
return configPath
}
module.exports = {
createConfigGypi,
parseConfigGypi,
getCurrentConfigGypi
}
================================================
FILE: lib/download.js
================================================
const fetch = require('make-fetch-happen')
const { promises: fs } = require('graceful-fs')
const log = require('./log')
async function download (gyp, url) {
log.http('GET', url)
const requestOpts = {
headers: {
'User-Agent': `node-gyp v${gyp.version} (node ${process.version})`,
Connection: 'keep-alive'
},
proxy: gyp.opts.proxy,
noProxy: gyp.opts.noproxy
}
const cafile = gyp.opts.cafile
if (cafile) {
requestOpts.ca = await readCAFile(cafile)
}
const res = await fetch(url, requestOpts)
log.http(res.status, res.url)
return res
}
async function readCAFile (filename) {
// The CA file can contain multiple certificates so split on certificate
// boundaries. [\S\s]*? is used to match everything including newlines.
const ca = await fs.readFile(filename, 'utf8')
const re = /(-----BEGIN CERTIFICATE-----[\S\s]*?-----END CERTIFICATE-----)/g
return ca.match(re)
}
module.exports = {
download,
readCAFile
}
================================================
FILE: lib/find-node-directory.js
================================================
'use strict'
const path = require('path')
const log = require('./log')
function findNodeDirectory (scriptLocation, processObj) {
// set dirname and process if not passed in
// this facilitates regression tests
if (scriptLocation === undefined) {
scriptLocation = __dirname
}
if (processObj === undefined) {
processObj = process
}
// Have a look to see what is above us, to try and work out where we are
const npmParentDirectory = path.join(scriptLocation, '../../../..')
log.verbose('node-gyp root', 'npm_parent_directory is ' +
path.basename(npmParentDirectory))
let nodeRootDir = ''
log.verbose('node-gyp root', 'Finding node root directory')
if (path.basename(npmParentDirectory) === 'deps') {
// We are in a build directory where this script lives in
// deps/npm/node_modules/node-gyp/lib
nodeRootDir = path.join(npmParentDirectory, '..')
log.verbose('node-gyp root', 'in build directory, root = ' +
nodeRootDir)
} else if (path.basename(npmParentDirectory) === 'node_modules') {
// We are in a node install directory where this script lives in
// lib/node_modules/npm/node_modules/node-gyp/lib or
// node_modules/npm/node_modules/node-gyp/lib depending on the
// platform
if (processObj.platform === 'win32') {
nodeRootDir = path.join(npmParentDirectory, '..')
} else {
nodeRootDir = path.join(npmParentDirectory, '../..')
}
log.verbose('node-gyp root', 'in install directory, root = ' +
nodeRootDir)
} else {
// We don't know where we are, try working it out from the location
// of the node binary
const nodeDir = path.dirname(processObj.execPath)
const directoryUp = path.basename(nodeDir)
if (directoryUp === 'bin') {
nodeRootDir = path.join(nodeDir, '..')
} else if (directoryUp === 'Release' || directoryUp === 'Debug') {
// If we are a recently built node, and the directory structure
// is that of a repository. If we are on Windows then we only need
// to go one level up, everything else, two
if (processObj.platform === 'win32') {
nodeRootDir = path.join(nodeDir, '..')
} else {
nodeRootDir = path.join(nodeDir, '../..')
}
}
// Else return the default blank, "".
}
return nodeRootDir
}
module.exports = findNodeDirectory
================================================
FILE: lib/find-python.js
================================================
'use strict'
const log = require('./log')
const semver = require('semver')
const { execFile } = require('./util')
const win = process.platform === 'win32'
function getOsUserInfo () {
try {
return require('os').userInfo().username
} catch {}
}
const systemDrive = process.env.SystemDrive || 'C:'
const username = process.env.USERNAME || process.env.USER || getOsUserInfo()
const localAppData = process.env.LOCALAPPDATA || `${systemDrive}\\${username}\\AppData\\Local`
const foundLocalAppData = process.env.LOCALAPPDATA || username
const programFiles = process.env.ProgramW6432 || process.env.ProgramFiles || `${systemDrive}\\Program Files`
const programFilesX86 = process.env['ProgramFiles(x86)'] || `${programFiles} (x86)`
const winDefaultLocationsArray = []
for (const majorMinor of ['311', '310', '39', '38']) {
if (foundLocalAppData) {
winDefaultLocationsArray.push(
`${localAppData}\\Programs\\Python\\Python${majorMinor}\\python.exe`,
`${programFiles}\\Python${majorMinor}\\python.exe`,
`${localAppData}\\Programs\\Python\\Python${majorMinor}-32\\python.exe`,
`${programFiles}\\Python${majorMinor}-32\\python.exe`,
`${programFilesX86}\\Python${majorMinor}-32\\python.exe`
)
} else {
winDefaultLocationsArray.push(
`${programFiles}\\Python${majorMinor}\\python.exe`,
`${programFiles}\\Python${majorMinor}-32\\python.exe`,
`${programFilesX86}\\Python${majorMinor}-32\\python.exe`
)
}
}
class PythonFinder {
static findPython = (...args) => new PythonFinder(...args).findPython()
log = log.withPrefix('find Python')
argsExecutable = ['-c', 'import sys; sys.stdout.buffer.write(sys.executable.encode(\'utf-8\'));']
argsVersion = ['-c', 'import sys; print("%s.%s.%s" % sys.version_info[:3]);']
semverRange = '>=3.6.0'
// These can be overridden for testing:
execFile = execFile
env = process.env
win = win
pyLauncher = 'py.exe'
winDefaultLocations = winDefaultLocationsArray
constructor (configPython) {
this.configPython = configPython
this.errorLog = []
}
// Logs a message at verbose level, but also saves it to be displayed later
// at error level if an error occurs. This should help diagnose the problem.
addLog (message) {
this.log.verbose(message)
this.errorLog.push(message)
}
// Find Python by trying a sequence of possibilities.
// Ignore errors, keep trying until Python is found.
async findPython () {
const SKIP = 0
const FAIL = 1
const toCheck = (() => {
if (this.env.NODE_GYP_FORCE_PYTHON) {
return [{
before: () => {
this.addLog(
'checking Python explicitly set from NODE_GYP_FORCE_PYTHON')
this.addLog('- process.env.NODE_GYP_FORCE_PYTHON is ' +
`"${this.env.NODE_GYP_FORCE_PYTHON}"`)
},
check: () => this.checkCommand(this.env.NODE_GYP_FORCE_PYTHON)
}]
}
const checks = [
{
before: () => {
if (!this.configPython) {
this.addLog('--python was not set on the command line')
return SKIP
}
this.addLog(`--python=${this.configPython} was set on the command line`)
},
check: () => this.checkCommand(this.configPython)
},
{
before: () => {
if (!this.env.PYTHON) {
this.addLog('Python is not set from environment variable ' +
'PYTHON')
return SKIP
}
this.addLog('checking Python explicitly set from environment ' +
'variable PYTHON')
this.addLog(`- process.env.PYTHON is "${this.env.PYTHON}"`)
},
check: () => this.checkCommand(this.env.PYTHON)
}
]
if (this.win) {
checks.push({
before: () => {
this.addLog(
'checking if the py launcher can be used to find Python 3')
},
check: () => this.checkPyLauncher()
})
}
checks.push(...[
{
before: () => { this.addLog('checking if "python3" can be used') },
check: () => this.checkCommand('python3')
},
{
before: () => { this.addLog('checking if "python" can be used') },
check: () => this.checkCommand('python')
}
])
if (this.win) {
for (let i = 0; i < this.winDefaultLocations.length; ++i) {
const location = this.winDefaultLocations[i]
checks.push({
before: () => this.addLog(`checking if Python is ${location}`),
check: () => this.checkExecPath(location)
})
}
}
return checks
})()
for (const check of toCheck) {
const before = check.before()
if (before === SKIP) {
continue
}
if (before === FAIL) {
return this.fail()
}
try {
return await check.check()
} catch (err) {
this.log.silly('runChecks: err = %j', (err && err.stack) || err)
}
}
return this.fail()
}
// Check if command is a valid Python to use.
// Will exit the Python finder on success.
// If on Windows, run in a CMD shell to support BAT/CMD launchers.
async checkCommand (command) {
let exec = command
let args = this.argsExecutable
let shell = false
if (this.win) {
// Arguments have to be manually quoted
exec = `"${exec}"`
args = args.map(a => `"${a}"`)
shell = true
}
this.log.verbose(`- executing "${command}" to get executable path`)
// Possible outcomes:
// - Error: not in PATH, not executable or execution fails
// - Gibberish: the next command to check version will fail
// - Absolute path to executable
try {
const execPath = await this.run(exec, args, shell)
this.addLog(`- executable path is "${execPath}"`)
return this.checkExecPath(execPath)
} catch (err) {
this.addLog(`- "${command}" is not in PATH or produced an error`)
throw err
}
}
// Check if the py launcher can find a valid Python to use.
// Will exit the Python finder on success.
// Distributions of Python on Windows by default install with the "py.exe"
// Python launcher which is more likely to exist than the Python executable
// being in the $PATH.
// Because the Python launcher supports Python 2 and Python 3, we should
// explicitly request a Python 3 version. This is done by supplying "-3" as
// the first command line argument. Since "py.exe -3" would be an invalid
// executable for "execFile", we have to use the launcher to figure out
// where the actual "python.exe" executable is located.
async checkPyLauncher () {
this.log.verbose(`- executing "${this.pyLauncher}" to get Python 3 executable path`)
// Possible outcomes: same as checkCommand
try {
const execPath = await this.run(this.pyLauncher, ['-3', ...this.argsExecutable], false)
this.addLog(`- executable path is "${execPath}"`)
return this.checkExecPath(execPath)
} catch (err) {
this.addLog(`- "${this.pyLauncher}" is not in PATH or produced an error`)
throw err
}
}
// Check if a Python executable is the correct version to use.
// Will exit the Python finder on success.
async checkExecPath (execPath) {
this.log.verbose(`- executing "${execPath}" to get version`)
// Possible outcomes:
// - Error: executable can not be run (likely meaning the command wasn't
// a Python executable and the previous command produced gibberish)
// - Gibberish: somehow the last command produced an executable path,
// this will fail when verifying the version
// - Version of the Python executable
try {
const version = await this.run(execPath, this.argsVersion, false)
this.addLog(`- version is "${version}"`)
const range = new semver.Range(this.semverRange)
let valid = false
try {
valid = range.test(version)
} catch (err) {
this.log.silly('range.test() threw:\n%s', err.stack)
this.addLog(`- "${execPath}" does not have a valid version`)
this.addLog('- is it a Python executable?')
throw err
}
if (!valid) {
this.addLog(`- version is ${version} - should be ${this.semverRange}`)
this.addLog('- THIS VERSION OF PYTHON IS NOT SUPPORTED')
throw new Error(`Found unsupported Python version ${version}`)
}
return this.succeed(execPath, version)
} catch (err) {
this.addLog(`- "${execPath}" could not be run`)
throw err
}
}
// Run an executable or shell command, trimming the output.
async run (exec, args, shell) {
const env = Object.assign({}, this.env)
env.TERM = 'dumb'
const opts = { env, shell }
this.log.silly('execFile: exec = %j', exec)
this.log.silly('execFile: args = %j', args)
this.log.silly('execFile: opts = %j', opts)
try {
const [err, stdout, stderr] = await this.execFile(exec, args, opts)
this.log.silly('execFile result: err = %j', (err && err.stack) || err)
this.log.silly('execFile result: stdout = %j', stdout)
this.log.silly('execFile result: stderr = %j', stderr)
return stdout.trim()
} catch (err) {
this.log.silly('execFile: threw:\n%s', err.stack)
throw err
}
}
succeed (execPath, version) {
this.log.info(`using Python version ${version} found at "${execPath}"`)
return execPath
}
fail () {
const errorLog = this.errorLog.join('\n')
const pathExample = this.win
? 'C:\\Path\\To\\python.exe'
: '/path/to/pythonexecutable'
// For Windows 80 col console, use up to the column before the one marked
// with X (total 79 chars including logger prefix, 58 chars usable here):
// X
const info = [
'**********************************************************',
'You need to install the latest version of Python.',
'Node-gyp should be able to find and use Python. If not,',
'you can try one of the following options:',
`- Use the switch --python="${pathExample}"`,
' (accepted by both node-gyp and npm)',
'- Set the environment variable PYTHON',
'For more information consult the documentation at:',
'https://github.com/nodejs/node-gyp#installation',
'**********************************************************'
].join('\n')
this.log.error(`\n${errorLog}\n\n${info}\n`)
throw new Error('Could not find any Python installation to use')
}
}
module.exports = PythonFinder
================================================
FILE: lib/find-visualstudio.js
================================================
'use strict'
const log = require('./log')
const { existsSync } = require('fs')
const { win32: path } = require('path')
const { regSearchKeys, execFile } = require('./util')
class VisualStudioFinder {
static findVisualStudio = (...args) => new VisualStudioFinder(...args).findVisualStudio()
log = log.withPrefix('find VS')
regSearchKeys = regSearchKeys
constructor (nodeSemver, configMsvsVersion) {
this.nodeSemver = nodeSemver
this.configMsvsVersion = configMsvsVersion
this.errorLog = []
this.validVersions = []
}
// Logs a message at verbose level, but also saves it to be displayed later
// at error level if an error occurs. This should help diagnose the problem.
addLog (message) {
this.log.verbose(message)
this.errorLog.push(message)
}
async findVisualStudio () {
this.configVersionYear = null
this.configPath = null
if (this.configMsvsVersion) {
this.addLog(`--msvs_version=${this.configMsvsVersion} was set on the command line`)
if (this.configMsvsVersion.match(/^\d{4}$/)) {
this.configVersionYear = parseInt(this.configMsvsVersion, 10)
this.addLog(
`- looking for Visual Studio version ${this.configVersionYear}`)
} else {
this.configPath = path.resolve(this.configMsvsVersion)
this.addLog(
`- looking for Visual Studio installed in "${this.configPath}"`)
}
} else {
this.addLog('--msvs_version was not set on the command line')
}
if (process.env.VCINSTALLDIR) {
this.envVcInstallDir =
path.resolve(process.env.VCINSTALLDIR, '..')
this.addLog('running in VS Command Prompt, installation path is:\n' +
`"${this.envVcInstallDir}"\n- will only use this version`)
} else {
this.addLog('VCINSTALLDIR not set, not running in VS Command Prompt')
}
const checks = [
() => this.findVisualStudio2019OrNewerFromSpecifiedLocation(),
() => this.findVisualStudio2019OrNewerUsingSetupModule(),
() => this.findVisualStudio2019OrNewer(),
() => this.findVisualStudio2017FromSpecifiedLocation(),
() => this.findVisualStudio2017UsingSetupModule(),
() => this.findVisualStudio2017(),
() => this.findVisualStudio2015(),
() => this.findVisualStudio2013()
]
for (const check of checks) {
const info = await check()
if (info) {
return this.succeed(info)
}
}
return this.fail()
}
succeed (info) {
this.log.info(`using VS${info.versionYear} (${info.version}) found at:` +
`\n"${info.path}"` +
'\nrun with --verbose for detailed information')
return info
}
fail () {
if (this.configMsvsVersion && this.envVcInstallDir) {
this.errorLog.push(
'msvs_version does not match this VS Command Prompt or the',
'installation cannot be used.')
} else if (this.configMsvsVersion) {
// If msvs_version was specified but finding VS failed, print what would
// have been accepted
this.errorLog.push('')
if (this.validVersions) {
this.errorLog.push('valid versions for msvs_version:')
this.validVersions.forEach((version) => {
this.errorLog.push(`- "${version}"`)
})
} else {
this.errorLog.push('no valid versions for msvs_version were found')
}
}
const errorLog = this.errorLog.join('\n')
// For Windows 80 col console, use up to the column before the one marked
// with X (total 79 chars including logger prefix, 62 chars usable here):
// X
const infoLog = [
'**************************************************************',
'You need to install the latest version of Visual Studio',
'including the "Desktop development with C++" workload.',
'For more information consult the documentation at:',
'https://github.com/nodejs/node-gyp#on-windows',
'**************************************************************'
].join('\n')
this.log.error(`\n${errorLog}\n\n${infoLog}\n`)
throw new Error('Could not find any Visual Studio installation to use')
}
async findVisualStudio2019OrNewerFromSpecifiedLocation () {
return this.findVSFromSpecifiedLocation([2019, 2022, 2026])
}
async findVisualStudio2017FromSpecifiedLocation () {
if (this.nodeSemver.major >= 22) {
this.addLog(
'not looking for VS2017 as it is only supported up to Node.js 21')
return null
}
return this.findVSFromSpecifiedLocation([2017])
}
async findVSFromSpecifiedLocation (supportedYears) {
if (!this.envVcInstallDir) {
return null
}
const info = {
path: path.resolve(this.envVcInstallDir),
// Assume the version specified by the user is correct.
// Since Visual Studio 2015, the Developer Command Prompt sets the
// VSCMD_VER environment variable which contains the version information
// for Visual Studio.
// https://learn.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell?view=vs-2022
version: process.env.VSCMD_VER,
packages: [
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
'Microsoft.VisualStudio.Component.VC.Tools.ARM64',
// Assume MSBuild exists. It will be checked in processing.
'Microsoft.VisualStudio.VC.MSBuild.Base'
]
}
// Is there a better way to get SDK information?
const envWindowsSDKVersion = process.env.WindowsSDKVersion
const sdkVersionMatched = envWindowsSDKVersion?.match(/^(\d+)\.(\d+)\.(\d+)\..*/)
if (sdkVersionMatched) {
info.packages.push(`Microsoft.VisualStudio.Component.Windows10SDK.${sdkVersionMatched[3]}.Desktop`)
}
// pass for further processing
return this.processData([info], supportedYears)
}
async findVisualStudio2019OrNewerUsingSetupModule () {
return this.findNewVSUsingSetupModule([2019, 2022, 2026])
}
async findVisualStudio2017UsingSetupModule () {
if (this.nodeSemver.major >= 22) {
this.addLog(
'not looking for VS2017 as it is only supported up to Node.js 21')
return null
}
return this.findNewVSUsingSetupModule([2017])
}
async findNewVSUsingSetupModule (supportedYears) {
const ps = path.join(process.env.SystemRoot, 'System32',
'WindowsPowerShell', 'v1.0', 'powershell.exe')
const vcInstallDir = this.envVcInstallDir
const checkModuleArgs = [
'-NoProfile',
'-Command',
'&{@(Get-Module -ListAvailable -Name VSSetup).Version.ToString()}'
]
this.log.silly('Running', ps, checkModuleArgs)
const [cErr] = await this.execFile(ps, checkModuleArgs)
if (cErr) {
this.addLog('VSSetup module doesn\'t seem to exist. You can install it via: "Install-Module VSSetup -Scope CurrentUser"')
this.log.silly('VSSetup error = %j', cErr && (cErr.stack || cErr))
return null
}
const filterArg = vcInstallDir !== undefined ? `| where {$_.InstallationPath -eq '${vcInstallDir}' }` : ''
const psArgs = [
'-NoProfile',
'-Command',
`&{Get-VSSetupInstance ${filterArg} | ConvertTo-Json -Depth 3}`
]
this.log.silly('Running', ps, psArgs)
const [err, stdout, stderr] = await this.execFile(ps, psArgs)
let parsedData = this.parseData(err, stdout, stderr)
if (parsedData === null) {
return null
}
this.log.silly('Parsed data', parsedData)
if (!Array.isArray(parsedData)) {
// if there are only 1 result, then Powershell will output non-array
parsedData = [parsedData]
}
// normalize output
parsedData = parsedData.map((info) => {
info.path = info.InstallationPath
info.version = `${info.InstallationVersion.Major}.${info.InstallationVersion.Minor}.${info.InstallationVersion.Build}.${info.InstallationVersion.Revision}`
info.packages = info.Packages.map((p) => p.Id)
return info
})
// pass for further processing
return this.processData(parsedData, supportedYears)
}
// Invoke the PowerShell script to get information about Visual Studio 2019
// or newer installations
async findVisualStudio2019OrNewer () {
return this.findNewVS([2019, 2022, 2026])
}
// Invoke the PowerShell script to get information about Visual Studio 2017
async findVisualStudio2017 () {
if (this.nodeSemver.major >= 22) {
this.addLog(
'not looking for VS2017 as it is only supported up to Node.js 21')
return null
}
return this.findNewVS([2017])
}
// Invoke the PowerShell script to get information about Visual Studio 2017
// or newer installations
async findNewVS (supportedYears) {
const ps = path.join(process.env.SystemRoot, 'System32',
'WindowsPowerShell', 'v1.0', 'powershell.exe')
const csFile = path.join(__dirname, 'Find-VisualStudio.cs')
const psArgs = [
'-ExecutionPolicy',
'Unrestricted',
'-NoProfile',
'-Command',
'&{Add-Type -IgnoreWarnings -Path \'' + csFile + '\';' + '[VisualStudioConfiguration.Main]::PrintJson()}'
]
this.log.silly('Running', ps, psArgs)
const [err, stdout, stderr] = await this.execFile(ps, psArgs)
const parsedData = this.parseData(err, stdout, stderr, { checkIsArray: true })
if (parsedData === null) {
return null
}
return this.processData(parsedData, supportedYears)
}
// Parse the output of the PowerShell script, make sanity checks
parseData (err, stdout, stderr, sanityCheckOptions) {
const defaultOptions = {
checkIsArray: false
}
// Merging provided options with the default options
const sanityOptions = { ...defaultOptions, ...sanityCheckOptions }
this.log.silly('PS stderr = %j', stderr)
const failPowershell = (failureDetails) => {
this.addLog(
`could not use PowerShell to find Visual Studio 2017 or newer, try re-running with '--loglevel silly' for more details. \n
Failure details: ${failureDetails}`)
return null
}
if (err) {
this.log.silly('PS err = %j', err && (err.stack || err))
return failPowershell(`${err}`.substring(0, 40))
}
let vsInfo
try {
vsInfo = JSON.parse(stdout)
} catch (e) {
this.log.silly('PS stdout = %j', stdout)
this.log.silly(e)
return failPowershell()
}
if (sanityOptions.checkIsArray && !Array.isArray(vsInfo)) {
this.log.silly('PS stdout = %j', stdout)
return failPowershell('Expected array as output of the PS script')
}
return vsInfo
}
// Process parsed data containing information about VS installations
// Look for the required parts, extract and output them back
processData (vsInfo, supportedYears) {
vsInfo = vsInfo.map((info) => {
this.log.silly(`processing installation: "${info.path}"`)
info.path = path.resolve(info.path)
const ret = this.getVersionInfo(info)
ret.path = info.path
ret.msBuild = this.getMSBuild(info, ret.versionYear)
ret.toolset = this.getToolset(info, ret.versionYear)
ret.sdk = this.getSDK(info)
return ret
})
this.log.silly('vsInfo:', vsInfo)
// Remove future versions or errors parsing version number
// Also remove any unsupported versions
vsInfo = vsInfo.filter((info) => {
if (info.versionYear && supportedYears.indexOf(info.versionYear) !== -1) {
return true
}
this.addLog(`${info.versionYear ? 'unsupported' : 'unknown'} version "${info.version}" found at "${info.path}"`)
return false
})
// Sort to place newer versions first
vsInfo.sort((a, b) => b.versionYear - a.versionYear)
for (let i = 0; i < vsInfo.length; ++i) {
const info = vsInfo[i]
this.addLog(`checking VS${info.versionYear} (${info.version}) found ` +
`at:\n"${info.path}"`)
if (info.msBuild) {
this.addLog('- found "Visual Studio C++ core features"')
} else {
this.addLog('- "Visual Studio C++ core features" missing')
continue
}
if (info.toolset) {
this.addLog(`- found VC++ toolset: ${info.toolset}`)
} else {
this.addLog('- missing any VC++ toolset')
continue
}
if (info.sdk) {
this.addLog(`- found Windows SDK: ${info.sdk}`)
} else {
this.addLog('- missing any Windows SDK')
continue
}
if (!this.checkConfigVersion(info.versionYear, info.path)) {
continue
}
return info
}
this.addLog(
'could not find a version of Visual Studio 2017 or newer to use')
return null
}
// Helper - process version information
getVersionInfo (info) {
const match = /^(\d+)\.(\d+)(?:\..*)?/.exec(info.version)
if (!match) {
this.log.silly('- failed to parse version:', info.version)
return {}
}
this.log.silly('- version match = %j', match)
const ret = {
version: info.version,
versionMajor: parseInt(match[1], 10),
versionMinor: parseInt(match[2], 10)
}
if (ret.versionMajor === 15) {
ret.versionYear = 2017
return ret
}
if (ret.versionMajor === 16) {
ret.versionYear = 2019
return ret
}
if (ret.versionMajor === 17) {
ret.versionYear = 2022
return ret
}
if (ret.versionMajor === 18) {
ret.versionYear = 2026
return ret
}
this.log.silly('- unsupported version:', ret.versionMajor)
return {}
}
msBuildPathExists (path) {
return existsSync(path)
}
// Helper - process MSBuild information
getMSBuild (info, versionYear) {
const pkg = 'Microsoft.VisualStudio.VC.MSBuild.Base'
const msbuildPath = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'MSBuild.exe')
const msbuildPathArm64 = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'arm64', 'MSBuild.exe')
if (info.packages.indexOf(pkg) !== -1) {
this.log.silly('- found VC.MSBuild.Base')
if (versionYear === 2017) {
return path.join(info.path, 'MSBuild', '15.0', 'Bin', 'MSBuild.exe')
}
if (versionYear === 2019) {
if (process.arch === 'arm64' && this.msBuildPathExists(msbuildPathArm64)) {
return msbuildPathArm64
} else {
return msbuildPath
}
}
}
/**
* Visual Studio 2022 doesn't have the MSBuild package.
* Support for compiling _on_ ARM64 was added in MSVC 14.32.31326,
* so let's leverage it if the user has an ARM64 device.
*/
if (process.arch === 'arm64' && this.msBuildPathExists(msbuildPathArm64)) {
return msbuildPathArm64
} else if (this.msBuildPathExists(msbuildPath)) {
return msbuildPath
}
return null
}
// Helper - process toolset information
getToolset (info, versionYear) {
const vcToolsArm64 = 'VC.Tools.ARM64'
const pkgArm64 = `Microsoft.VisualStudio.Component.${vcToolsArm64}`
const vcToolsX64 = 'VC.Tools.x86.x64'
const pkgX64 = `Microsoft.VisualStudio.Component.${vcToolsX64}`
const express = 'Microsoft.VisualStudio.WDExpress'
if (process.arch === 'arm64' && info.packages.includes(pkgArm64)) {
this.log.silly(`- found ${vcToolsArm64}`)
} else if (info.packages.includes(pkgX64)) {
if (process.arch === 'arm64') {
this.addLog(`- found ${vcToolsX64} on ARM64 platform. Expect less performance and/or link failure with ARM64 binary.`)
} else {
this.log.silly(`- found ${vcToolsX64}`)
}
} else if (info.packages.includes(express)) {
this.log.silly('- found Visual Studio Express (looking for toolset)')
} else {
return null
}
if (versionYear === 2017) {
return 'v141'
} else if (versionYear === 2019) {
return 'v142'
} else if (versionYear === 2022) {
return 'v143'
} else if (versionYear === 2026) {
return 'v145'
}
this.log.silly('- invalid versionYear:', versionYear)
return null
}
// Helper - process Windows SDK information
getSDK (info) {
const win8SDK = 'Microsoft.VisualStudio.Component.Windows81SDK'
const win10SDKPrefix = 'Microsoft.VisualStudio.Component.Windows10SDK.'
const win11SDKPrefix = 'Microsoft.VisualStudio.Component.Windows11SDK.'
let Win10or11SDKVer = 0
info.packages.forEach((pkg) => {
if (!pkg.startsWith(win10SDKPrefix) && !pkg.startsWith(win11SDKPrefix)) {
return
}
const parts = pkg.split('.')
if (parts.length > 5 && parts[5] !== 'Desktop') {
this.log.silly('- ignoring non-Desktop Win10/11SDK:', pkg)
return
}
const foundSdkVer = parseInt(parts[4], 10)
if (isNaN(foundSdkVer)) {
// Microsoft.VisualStudio.Component.Windows10SDK.IpOverUsb
this.log.silly('- failed to parse Win10/11SDK number:', pkg)
return
}
this.log.silly('- found Win10/11SDK:', foundSdkVer)
Win10or11SDKVer = Math.max(Win10or11SDKVer, foundSdkVer)
})
if (Win10or11SDKVer !== 0) {
return `10.0.${Win10or11SDKVer}.0`
} else if (info.packages.indexOf(win8SDK) !== -1) {
this.log.silly('- found Win8SDK')
return '8.1'
}
return null
}
// Find an installation of Visual Studio 2015 to use
async findVisualStudio2015 () {
if (this.nodeSemver.major >= 19) {
this.addLog(
'not looking for VS2015 as it is only supported up to Node.js 18')
return null
}
return this.findOldVS({
version: '14.0',
versionMajor: 14,
versionMinor: 0,
versionYear: 2015,
toolset: 'v140'
})
}
// Find an installation of Visual Studio 2013 to use
async findVisualStudio2013 () {
if (this.nodeSemver.major >= 9) {
this.addLog(
'not looking for VS2013 as it is only supported up to Node.js 8')
return null
}
return this.findOldVS({
version: '12.0',
versionMajor: 12,
versionMinor: 0,
versionYear: 2013,
toolset: 'v120'
})
}
// Helper - common code for VS2013 and VS2015
async findOldVS (info) {
const regVC7 = ['HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7',
'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7']
const regMSBuild = 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions'
this.addLog(`looking for Visual Studio ${info.versionYear}`)
try {
let res = await this.regSearchKeys(regVC7, info.version, [])
const vsPath = path.resolve(res, '..')
this.addLog(`- found in "${vsPath}"`)
const msBuildRegOpts = process.arch === 'ia32' ? [] : ['/reg:32']
try {
res = await this.regSearchKeys([`${regMSBuild}\\${info.version}`], 'MSBuildToolsPath', msBuildRegOpts)
} catch (err) {
this.addLog('- could not find MSBuild in registry for this version')
return null
}
const msBuild = path.join(res, 'MSBuild.exe')
this.addLog(`- MSBuild in "${msBuild}"`)
if (!this.checkConfigVersion(info.versionYear, vsPath)) {
return null
}
info.path = vsPath
info.msBuild = msBuild
info.sdk = null
return info
} catch (err) {
this.addLog('- not found')
return null
}
}
// After finding a usable version of Visual Studio:
// - add it to validVersions to be displayed at the end if a specific
// version was requested and not found;
// - check if this is the version that was requested.
// - check if this matches the Visual Studio Command Prompt
checkConfigVersion (versionYear, vsPath) {
this.validVersions.push(versionYear)
this.validVersions.push(vsPath)
if (this.configVersionYear && this.configVersionYear !== versionYear) {
this.addLog('- msvs_version does not match this version')
return false
}
if (this.configPath &&
path.relative(this.configPath, vsPath) !== '') {
this.addLog('- msvs_version does not point to this installation')
return false
}
if (this.envVcInstallDir &&
path.relative(this.envVcInstallDir, vsPath) !== '') {
this.addLog('- does not match this Visual Studio Command Prompt')
return false
}
return true
}
async execFile (exec, args) {
return await execFile(exec, args, { encoding: 'utf8' })
}
}
module.exports = VisualStudioFinder
================================================
FILE: lib/install.js
================================================
'use strict'
const { createWriteStream, promises: fs } = require('graceful-fs')
const os = require('os')
const { backOff } = require('exponential-backoff')
const tar = require('tar')
const path = require('path')
const { Transform, promises: { pipeline } } = require('stream')
const crypto = require('crypto')
const log = require('./log')
const semver = require('semver')
const { download } = require('./download')
const processRelease = require('./process-release')
const win = process.platform === 'win32'
async function install (gyp, argv) {
log.stdout()
const release = processRelease(argv, gyp, process.version, process.release)
// Detecting target_arch based on logic from create-cnfig-gyp.js. Used on Windows only.
const arch = win ? (gyp.opts.target_arch || gyp.opts.arch || process.arch || 'ia32') : ''
// Used to prevent downloading tarball if only new node.lib is required on Windows.
let shouldDownloadTarball = true
// Determine which node dev files version we are installing
log.verbose('install', 'input version string %j', release.version)
if (!release.semver) {
// could not parse the version string with semver
throw new Error('Invalid version number: ' + release.version)
}
if (semver.lt(release.version, '0.8.0')) {
throw new Error('Minimum target version is `0.8.0` or greater. Got: ' + release.version)
}
// 0.x.y-pre versions are not published yet and cannot be installed. Bail.
if (release.semver.prerelease[0] === 'pre') {
log.verbose('detected "pre" node version', release.version)
if (!gyp.opts.nodedir) {
throw new Error('"pre" versions of node cannot be installed, use the --nodedir flag instead')
}
log.verbose('--nodedir flag was passed; skipping install', gyp.opts.nodedir)
return
}
// flatten version into String
log.verbose('install', 'installing version: %s', release.versionDir)
// the directory where the dev files will be installed
const devDir = path.resolve(gyp.devDir, release.versionDir)
// If '--ensure' was passed, then don't *always* install the version;
// check if it is already installed, and only install when needed
if (gyp.opts.ensure) {
log.verbose('install', '--ensure was passed, so won\'t reinstall if already installed')
try {
await fs.stat(devDir)
} catch (err) {
if (err.code === 'ENOENT') {
log.verbose('install', 'version not already installed, continuing with install', release.version)
try {
return await go()
} catch (err) {
return rollback(err)
}
} else if (err.code === 'EACCES') {
return eaccesFallback(err)
}
throw err
}
log.verbose('install', 'version is already installed, need to check "installVersion"')
const installVersionFile = path.resolve(devDir, 'installVersion')
let installVersion = 0
try {
const ver = await fs.readFile(installVersionFile, 'ascii')
installVersion = parseInt(ver, 10) || 0
} catch (err) {
if (err.code !== 'ENOENT') {
throw err
}
}
log.verbose('got "installVersion"', installVersion)
log.verbose('needs "installVersion"', gyp.package.installVersion)
if (installVersion < gyp.package.installVersion) {
log.verbose('install', 'version is no good; reinstalling')
try {
return await go()
} catch (err) {
return rollback(err)
}
}
log.verbose('install', 'version is good')
if (win) {
log.verbose('on Windows; need to check node.lib')
const nodeLibPath = path.resolve(devDir, arch, 'node.lib')
try {
await fs.stat(nodeLibPath)
} catch (err) {
if (err.code === 'ENOENT') {
log.verbose('install', `version not already installed for ${arch}, continuing with install`, release.version)
try {
shouldDownloadTarball = false
return await go()
} catch (err) {
return rollback(err)
}
} else if (err.code === 'EACCES') {
return eaccesFallback(err)
}
throw err
}
}
} else {
try {
return await go()
} catch (err) {
return rollback(err)
}
}
async function copyDirectory (src, dest) {
try {
await fs.stat(src)
} catch {
throw new Error(`Missing source directory for copy: ${src}`)
}
await fs.mkdir(dest, { recursive: true })
const entries = await fs.readdir(src, { withFileTypes: true })
for (const entry of entries) {
if (entry.isDirectory()) {
await copyDirectory(path.join(src, entry.name), path.join(dest, entry.name))
} else if (entry.isFile()) {
// with parallel installs, copying files may cause file errors on
// Windows so use an exponential backoff to resolve collisions
await backOff(async () => {
try {
await fs.copyFile(path.join(src, entry.name), path.join(dest, entry.name))
} catch (err) {
// if ensure, check if file already exists and that's good enough
if (gyp.opts.ensure && err.code === 'EBUSY') {
try {
await fs.stat(path.join(dest, entry.name))
return
} catch {}
}
throw err
}
})
} else {
throw new Error('Unexpected file directory entry type')
}
}
}
async function go () {
log.verbose('ensuring devDir is created', devDir)
// first create the dir for the node dev files
try {
const created = await fs.mkdir(devDir, { recursive: true })
if (created) {
log.verbose('created devDir', created)
}
} catch (err) {
if (err.code === 'EACCES') {
return eaccesFallback(err)
}
throw err
}
// now download the node tarball
const tarPath = gyp.opts.tarball
let extractErrors = false
let extractCount = 0
const contentShasums = {}
const expectShasums = {}
// checks if a file to be extracted from the tarball is valid.
// only .h header files and the gyp files get extracted
function isValid (path) {
const isValid = valid(path)
if (isValid) {
log.verbose('extracted file from tarball', path)
extractCount++
} else {
// invalid
log.silly('ignoring from tarball', path)
}
return isValid
}
function onwarn (code, message) {
extractErrors = true
log.error('error while extracting tarball', code, message)
}
// download the tarball and extract!
// Omitted on Windows if only new node.lib is required
// there can be file errors from tar if parallel installs
// are happening (not uncommon with multiple native modules) so
// extract the tarball to a temp directory first and then copy over
const tarExtractDir = await fs.mkdtemp(path.join(os.tmpdir(), 'node-gyp-tmp-'))
try {
if (shouldDownloadTarball) {
if (tarPath) {
await tar.extract({
file: tarPath,
strip: 1,
filter: isValid,
onwarn,
cwd: tarExtractDir
})
} else {
try {
const res = await download(gyp, release.tarballUrl)
if (res.status !== 200) {
throw new Error(`${res.status} response downloading ${release.tarballUrl}`)
}
await pipeline(
res.body,
// content checksum
new ShaSum((_, checksum) => {
const filename = path.basename(release.tarballUrl).trim()
contentShasums[filename] = checksum
log.verbose('content checksum', filename, checksum)
}),
tar.extract({
strip: 1,
cwd: tarExtractDir,
filter: isValid,
onwarn
})
)
} catch (err) {
// something went wrong downloading the tarball?
if (err.code === 'ENOTFOUND') {
throw new Error('This is most likely not a problem with node-gyp or the package itself and\n' +
'is related to network connectivity. In most cases you are behind a proxy or have bad \n' +
'network settings.')
}
throw err
}
}
// invoked after the tarball has finished being extracted
if (extractErrors || extractCount === 0) {
throw new Error('There was a fatal problem while downloading/extracting the tarball')
}
log.verbose('tarball', 'done parsing tarball')
}
const installVersionPath = path.resolve(tarExtractDir, 'installVersion')
await Promise.all([
// need to download node.lib
...(win ? [downloadNodeLib()] : []),
// write the "installVersion" file
fs.writeFile(installVersionPath, gyp.package.installVersion + '\n'),
// Only download SHASUMS.txt if we downloaded something in need of SHA verification
...(!tarPath || win ? [downloadShasums()] : [])
])
log.verbose('download contents checksum', JSON.stringify(contentShasums))
// check content shasums
for (const k in contentShasums) {
log.verbose('validating download checksum for ' + k, '(%s == %s)', contentShasums[k], expectShasums[k])
if (contentShasums[k] !== expectShasums[k]) {
throw new Error(k + ' local checksum ' + contentShasums[k] + ' not match remote ' + expectShasums[k])
}
}
// copy over the files from the temp tarball extract directory to devDir
await copyDirectory(tarExtractDir, devDir)
} finally {
try {
// try to cleanup temp dir
await fs.rm(tarExtractDir, { recursive: true, maxRetries: 3 })
} catch {
log.warn('failed to clean up temp tarball extract directory')
}
}
async function downloadShasums () {
log.verbose('check download content checksum, need to download `SHASUMS256.txt`...')
log.verbose('checksum url', release.shasumsUrl)
const res = await download(gyp, release.shasumsUrl)
if (res.status !== 200) {
throw new Error(`${res.status} status code downloading checksum`)
}
for (const line of (await res.text()).trim().split('\n')) {
const items = line.trim().split(/\s+/)
if (items.length !== 2) {
return
}
// 0035d18e2dcf9aad669b1c7c07319e17abfe3762 ./node-v0.11.4.tar.gz
const name = items[1].replace(/^\.\//, '')
expectShasums[name] = items[0]
}
log.verbose('checksum data', JSON.stringify(expectShasums))
}
async function downloadNodeLib () {
log.verbose('on Windows; need to download `' + release.name + '.lib`...')
const dir = path.resolve(tarExtractDir, arch)
const targetLibPath = path.resolve(dir, release.name + '.lib')
const { libUrl, libPath } = release[arch]
const name = `${arch} ${release.name}.lib`
log.verbose(name, 'dir', dir)
log.verbose(name, 'url', libUrl)
await fs.mkdir(dir, { recursive: true })
log.verbose('streaming', name, 'to:', targetLibPath)
const res = await download(gyp, libUrl)
// Since only required node.lib is downloaded throw error if it is not fetched
if (res.status !== 200) {
throw new Error(`${res.status} status code downloading ${name}`)
}
return pipeline(
res.body,
new ShaSum((_, checksum) => {
contentShasums[libPath] = checksum
log.verbose('content checksum', libPath, checksum)
}),
createWriteStream(targetLibPath)
)
} // downloadNodeLib()
} // go()
/**
* Checks if a given filename is "valid" for this installation.
*/
function valid (file) {
// header files
const extname = path.extname(file)
return extname === '.h' || extname === '.gypi'
}
async function rollback (err) {
log.warn('install', 'got an error, rolling back install')
// roll-back the install if anything went wrong
await gyp.commands.remove([release.versionDir])
throw err
}
/**
* The EACCES fallback is a workaround for npm's `sudo` behavior, where
* it drops the permissions before invoking any child processes (like
* node-gyp). So what happens is the "nobody" user doesn't have
* permission to create the dev dir. As a fallback, make the tmpdir() be
* the dev dir for this installation. This is not ideal, but at least
* the compilation will succeed...
*/
async function eaccesFallback (err) {
const noretry = '--node_gyp_internal_noretry'
if (argv.indexOf(noretry) !== -1) {
throw err
}
const tmpdir = os.tmpdir()
gyp.devDir = path.resolve(tmpdir, '.node-gyp')
let userString = ''
try {
// os.userInfo can fail on some systems, it's not critical here
userString = ` ("${os.userInfo().username}")`
} catch (e) {}
log.warn('EACCES', 'current user%s does not have permission to access the dev dir "%s"', userString, devDir)
log.warn('EACCES', 'attempting to reinstall using temporary dev dir "%s"', gyp.devDir)
if (process.cwd() === tmpdir) {
log.verbose('tmpdir == cwd', 'automatically will remove dev files after to save disk space')
gyp.todo.push({ name: 'remove', args: argv })
}
return gyp.commands.install([noretry].concat(argv))
}
}
class ShaSum extends Transform {
constructor (callback) {
super()
this._callback = callback
this._digester = crypto.createHash('sha256')
}
_transform (chunk, _, callback) {
this._digester.update(chunk)
callback(null, chunk)
}
_flush (callback) {
this._callback(null, this._digester.digest('hex'))
callback()
}
}
module.exports = install
module.exports.usage = 'Install node development files for the specified node version.'
================================================
FILE: lib/list.js
================================================
'use strict'
const fs = require('graceful-fs').promises
const log = require('./log')
async function list (gyp, args) {
const devDir = gyp.devDir
log.verbose('list', 'using node-gyp dir:', devDir)
let versions = []
try {
const dir = await fs.readdir(devDir)
if (Array.isArray(dir)) {
versions = dir.filter((v) => v !== 'current')
}
} catch (err) {
if (err && err.code !== 'ENOENT') {
throw err
}
}
return versions
}
module.exports = list
module.exports.usage = 'Prints a listing of the currently installed node development files'
================================================
FILE: lib/log.js
================================================
'use strict'
const { log } = require('proc-log')
const { format } = require('util')
// helper to emit log messages with a predefined prefix
const withPrefix = (prefix) => log.LEVELS.reduce((acc, level) => {
acc[level] = (...args) => log[level](prefix, ...args)
return acc
}, {})
// very basic ansi color generator
const COLORS = {
wrap: (str, colors) => {
const codes = colors.filter(c => typeof c === 'number')
return `\x1b[${codes.join(';')}m${str}\x1b[0m`
},
inverse: 7,
fg: {
black: 30,
red: 31,
green: 32,
yellow: 33,
blue: 34,
magenta: 35,
cyan: 36,
white: 37
},
bg: {
black: 40,
red: 41,
green: 42,
yellow: 43,
blue: 44,
magenta: 45,
cyan: 46,
white: 47
}
}
class Logger {
#buffer = []
#paused = null
#level = null
#stream = null
// ordered from loudest to quietest
#levels = [{
id: 'silly',
display: 'sill',
style: { inverse: true }
}, {
id: 'verbose',
display: 'verb',
style: { fg: 'cyan', bg: 'black' }
}, {
id: 'info',
style: { fg: 'green' }
}, {
id: 'http',
style: { fg: 'green', bg: 'black' }
}, {
id: 'notice',
style: { fg: 'cyan', bg: 'black' }
}, {
id: 'warn',
display: 'WARN',
style: { fg: 'black', bg: 'yellow' }
}, {
id: 'error',
display: 'ERR!',
style: { fg: 'red', bg: 'black' }
}]
constructor (stream) {
process.on('log', (...args) => this.#onLog(...args))
this.#levels = new Map(this.#levels.map((level, index) => [level.id, { ...level, index }]))
this.level = 'info'
this.stream = stream
log.pause()
}
get stream () {
return this.#stream
}
set stream (stream) {
this.#stream = stream
}
get level () {
return this.#levels.get(this.#level) ?? null
}
set level (level) {
this.#level = this.#levels.get(level)?.id ?? null
}
isVisible (level) {
return this.level?.index <= this.#levels.get(level)?.index ?? -1
}
#onLog (...args) {
const [level] = args
if (level === 'pause') {
this.#paused = true
return
}
if (level === 'resume') {
this.#paused = false
this.#buffer.forEach((b) => this.#log(...b))
this.#buffer.length = 0
return
}
if (this.#paused) {
this.#buffer.push(args)
return
}
this.#log(...args)
}
#color (str, { fg, bg, inverse }) {
if (!this.#stream?.isTTY) {
return str
}
return COLORS.wrap(str, [
COLORS.fg[fg],
COLORS.bg[bg],
inverse && COLORS.inverse
])
}
#log (levelId, msgPrefix, ...args) {
if (!this.isVisible(levelId) || typeof this.#stream?.write !== 'function') {
return
}
const level = this.#levels.get(levelId)
const prefixParts = [
this.#color('gyp', { fg: 'white', bg: 'black' }),
this.#color(level.display ?? level.id, level.style)
]
if (msgPrefix) {
prefixParts.push(this.#color(msgPrefix, { fg: 'magenta' }))
}
const prefix = prefixParts.join(' ').trim() + ' '
const lines = format(...args).split(/\r?\n/).map(l => prefix + l.trim())
this.#stream.write(lines.join('\n') + '\n')
}
}
// used to suppress logs in tests
const NULL_LOGGER = !!process.env.NODE_GYP_NULL_LOGGER
module.exports = {
logger: new Logger(NULL_LOGGER ? null : process.stderr),
stdout: NULL_LOGGER ? () => {} : (...args) => console.log(...args),
withPrefix,
...log
}
================================================
FILE: lib/node-gyp.js
================================================
'use strict'
const path = require('path')
const nopt = require('nopt')
const log = require('./log')
const childProcess = require('child_process')
const { EventEmitter } = require('events')
const commands = [
// Module build commands
'build',
'clean',
'configure',
'rebuild',
// Development Header File management commands
'install',
'list',
'remove'
]
class Gyp extends EventEmitter {
/**
* Export the contents of the package.json.
*/
package = require('../package.json')
/**
* nopt configuration definitions
*/
configDefs = {
help: Boolean, // everywhere
arch: String, // 'configure'
cafile: String, // 'install'
debug: Boolean, // 'build'
directory: String, // bin
make: String, // 'build'
'msvs-version': String, // 'configure'
ensure: Boolean, // 'install'
solution: String, // 'build' (windows only)
proxy: String, // 'install'
noproxy: String, // 'install'
devdir: String, // everywhere
nodedir: String, // 'configure'
loglevel: String, // everywhere
python: String, // 'configure'
'dist-url': String, // 'install'
tarball: String, // 'install'
jobs: String, // 'build'
thin: String, // 'configure'
'force-process-config': Boolean // 'configure'
}
/**
* nopt shorthands
*/
shorthands = {
release: '--no-debug',
C: '--directory',
debug: '--debug',
j: '--jobs',
silly: '--loglevel=silly',
verbose: '--loglevel=verbose',
silent: '--loglevel=silent'
}
/**
* expose the command aliases for the bin file to use.
*/
aliases = {
ls: 'list',
rm: 'remove'
}
constructor (...args) {
super(...args)
this.devDir = ''
this.commands = commands.reduce((acc, command) => {
acc[command] = (argv) => require('./' + command)(this, argv)
return acc
}, {})
Object.defineProperty(this, 'version', {
enumerable: true,
get: function () { return this.package.version }
})
}
/**
* Parses the given argv array and sets the 'opts',
* 'argv' and 'command' properties.
*/
parseArgv (argv) {
this.opts = nopt(this.configDefs, this.shorthands, argv)
this.argv = this.opts.argv.remain.slice()
const commands = this.todo = []
// create a copy of the argv array with aliases mapped
argv = this.argv.map((arg) => {
// is this an alias?
if (arg in this.aliases) {
arg = this.aliases[arg]
}
return arg
})
// process the mapped args into "command" objects ("name" and "args" props)
argv.slice().forEach((arg) => {
if (arg in this.commands) {
const args = argv.splice(0, argv.indexOf(arg))
argv.shift()
if (commands.length > 0) {
commands[commands.length - 1].args = args
}
commands.push({ name: arg, args: [] })
}
})
if (commands.length > 0) {
commands[commands.length - 1].args = argv.splice(0)
}
// support for inheriting config env variables from npm
// npm will set environment variables in the following forms:
// - `npm_config_` for values from npm's own config. Setting arbitrary
// options on npm's config was deprecated in npm v11 but node-gyp still
// supports it for backwards compatibility.
// See https://github.com/nodejs/node-gyp/issues/3156
// - `npm_package_config_node_gyp_` for values from the `config` object
// in package.json. This is the preferred way to set options for node-gyp
// since npm v11. The `node_gyp_` prefix is used to avoid conflicts with
// other tools.
// The `npm_package_config_node_gyp_` prefix will take precedence over
// `npm_config_` keys.
const npmConfigPrefix = /^npm_config_/i
const npmPackageConfigPrefix = /^npm_package_config_node_gyp_/i
const configEnvKeys = Object.keys(process.env)
.filter((k) => npmConfigPrefix.test(k) || npmPackageConfigPrefix.test(k))
// sort so that npm_package_config_node_gyp_ keys come last and will override
.sort((a) => npmConfigPrefix.test(a) ? -1 : 1)
for (const key of configEnvKeys) {
// add the user-defined options to the config
const name = npmConfigPrefix.test(key)
? key.replace(npmConfigPrefix, '')
: key.replace(npmPackageConfigPrefix, '')
// gyp@741b7f1 enters an infinite loop when it encounters
// zero-length options so ensure those don't get through.
if (name) {
// convert names like force_process_config to force-process-config
// and convert to lowercase
this.opts[name.replaceAll('_', '-').toLowerCase()] = process.env[key]
}
}
if (this.opts.loglevel) {
log.logger.level = this.opts.loglevel
delete this.opts.loglevel
}
log.resume()
}
/**
* Spawns a child process and emits a 'spawn' event.
*/
spawn (command, args, opts) {
if (!opts) {
opts = {}
}
if (!opts.silent && !opts.stdio) {
opts.stdio = [0, 1, 2]
}
const cp = childProcess.spawn(command, args, opts)
log.info('spawn', command)
log.info('spawn args', args)
return cp
}
/**
* Returns the usage instructions for node-gyp.
*/
usage () {
return [
'',
' Usage: node-gyp [options]',
'',
' where is one of:',
commands.map((c) => ' - ' + c + ' - ' + require('./' + c).usage).join('\n'),
'',
'node-gyp@' + this.version + ' ' + path.resolve(__dirname, '..'),
'node@' + process.versions.node
].join('\n')
}
}
module.exports = () => new Gyp()
module.exports.Gyp = Gyp
================================================
FILE: lib/process-release.js
================================================
'use strict'
const semver = require('semver')
const path = require('path')
const log = require('./log')
// versions where -headers.tar.gz started shipping
const headersTarballRange = '>= 3.0.0 || ~0.12.10 || ~0.10.42'
const bitsre = /\/win-(x86|x64|arm64)\//
const bitsreV3 = /\/win-(x86|ia32|x64)\// // io.js v3.x.x shipped with "ia32" but should
// have been "x86"
// Captures all the logic required to determine download URLs, local directory and
// file names. Inputs come from command-line switches (--target, --dist-url),
// `process.version` and `process.release` where it exists.
function processRelease (argv, gyp, defaultVersion, defaultRelease) {
let version = (semver.valid(argv[0]) && argv[0]) || gyp.opts.target || defaultVersion
const versionSemver = semver.parse(version)
let overrideDistUrl = gyp.opts['dist-url'] || gyp.opts.disturl
let isNamedForLegacyIojs
let name
let distBaseUrl
let baseUrl
let libUrl32
let libUrl64
let libUrlArm64
let tarballUrl
let canGetHeaders
if (!versionSemver) {
// not a valid semver string, nothing we can do
return { version }
}
// flatten version into String
version = versionSemver.version
// defaultVersion should come from process.version so ought to be valid semver
const isDefaultVersion = version === semver.parse(defaultVersion).version
// can't use process.release if we're using --target=x.y.z
if (!isDefaultVersion) {
defaultRelease = null
}
if (defaultRelease) {
// v3 onward, has process.release
name = defaultRelease.name.replace(/io\.js/, 'iojs') // remove the '.' for directory naming purposes
} else {
// old node or alternative --target=
// semver.satisfies() doesn't like prerelease tags so test major directly
isNamedForLegacyIojs = versionSemver.major >= 1 && versionSemver.major < 4
// isNamedForLegacyIojs is required to support Electron < 4 (in particular Electron 3)
// as previously this logic was used to ensure "iojs" was used to download iojs releases
// and "node" for node releases. Unfortunately the logic was broad enough that electron@3
// published release assets as "iojs" so that the node-gyp logic worked. Once Electron@3 has
// been EOL for a while (late 2019) we should remove this hack.
name = isNamedForLegacyIojs ? 'iojs' : 'node'
}
// check for the nvm.sh standard mirror env variables
if (!overrideDistUrl && process.env.NODEJS_ORG_MIRROR) {
overrideDistUrl = process.env.NODEJS_ORG_MIRROR
}
if (overrideDistUrl) {
log.verbose('download', 'using dist-url', overrideDistUrl)
}
if (overrideDistUrl) {
distBaseUrl = overrideDistUrl.replace(/\/+$/, '')
} else {
distBaseUrl = 'https://nodejs.org/dist'
}
distBaseUrl = new URL(distBaseUrl + '/v' + version + '/')
// new style, based on process.release so we have a lot of the data we need
if (defaultRelease && defaultRelease.headersUrl && !overrideDistUrl) {
baseUrl = new URL('./', defaultRelease.headersUrl)
libUrl32 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'x86', versionSemver.major)
libUrl64 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'x64', versionSemver.major)
libUrlArm64 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'arm64', versionSemver.major)
tarballUrl = defaultRelease.headersUrl
} else {
// older versions without process.release are captured here and we have to make
// a lot of assumptions, additionally if you --target=x.y.z then we can't use the
// current process.release
baseUrl = distBaseUrl
libUrl32 = resolveLibUrl(name, baseUrl, 'x86', versionSemver.major)
libUrl64 = resolveLibUrl(name, baseUrl, 'x64', versionSemver.major)
libUrlArm64 = resolveLibUrl(name, baseUrl, 'arm64', versionSemver.major)
// making the bold assumption that anything with a version number >3.0.0 will
// have a *-headers.tar.gz file in its dist location, even some frankenstein
// custom version
canGetHeaders = semver.satisfies(versionSemver, headersTarballRange)
tarballUrl = new URL(name + '-v' + version + (canGetHeaders ? '-headers' : '') + '.tar.gz', baseUrl).href
}
return {
version,
semver: versionSemver,
name,
baseUrl: baseUrl.href,
tarballUrl,
shasumsUrl: new URL('SHASUMS256.txt', baseUrl).href,
versionDir: (name !== 'node' ? name + '-' : '') + version,
ia32: {
libUrl: libUrl32.href,
libPath: normalizePath(path.relative(baseUrl.pathname, libUrl32.pathname))
},
x64: {
libUrl: libUrl64.href,
libPath: normalizePath(path.relative(baseUrl.pathname, libUrl64.pathname))
},
arm64: {
libUrl: libUrlArm64.href,
libPath: normalizePath(path.relative(baseUrl.pathname, libUrlArm64.pathname))
}
}
}
function normalizePath (p) {
return path.normalize(p).replace(/\\/g, '/')
}
function resolveLibUrl (name, defaultUrl, arch, versionMajor) {
if (!defaultUrl.pathname) defaultUrl = new URL(defaultUrl)
const base = new URL('./', defaultUrl)
const hasLibUrl = bitsre.test(defaultUrl.pathname) || (versionMajor === 3 && bitsreV3.test(defaultUrl.pathname))
if (!hasLibUrl) {
// let's assume it's a baseUrl then
if (versionMajor >= 1) {
return new URL('win-' + arch + '/' + name + '.lib', base)
}
// prior to io.js@1.0.0 32-bit node.lib lives in /, 64-bit lives in /x64/
return new URL((arch === 'x86' ? '' : arch + '/') + name + '.lib', base)
}
// else we have a proper url to a .lib, just make sure it's the right arch
return new URL(defaultUrl.pathname.replace(versionMajor === 3 ? bitsreV3 : bitsre, '/win-' + arch + '/'), defaultUrl)
}
module.exports = processRelease
================================================
FILE: lib/rebuild.js
================================================
'use strict'
async function rebuild (gyp, argv) {
gyp.todo.push(
{ name: 'clean', args: [] }
, { name: 'configure', args: argv }
, { name: 'build', args: [] }
)
}
module.exports = rebuild
module.exports.usage = 'Runs "clean", "configure" and "build" all at once'
================================================
FILE: lib/remove.js
================================================
'use strict'
const fs = require('graceful-fs').promises
const path = require('path')
const log = require('./log')
const semver = require('semver')
async function remove (gyp, argv) {
const devDir = gyp.devDir
log.verbose('remove', 'using node-gyp dir:', devDir)
// get the user-specified version to remove
let version = argv[0] || gyp.opts.target
log.verbose('remove', 'removing target version:', version)
if (!version) {
throw new Error('You must specify a version number to remove. Ex: "' + process.version + '"')
}
const versionSemver = semver.parse(version)
if (versionSemver) {
// flatten the version Array into a String
version = versionSemver.version
}
const versionPath = path.resolve(gyp.devDir, version)
log.verbose('remove', 'removing development files for version:', version)
// first check if its even installed
try {
await fs.stat(versionPath)
} catch (err) {
if (err.code === 'ENOENT') {
return 'version was already uninstalled: ' + version
}
throw err
}
await fs.rm(versionPath, { recursive: true, force: true, maxRetries: 3 })
}
module.exports = remove
module.exports.usage = 'Removes the node development files for the specified version'
================================================
FILE: lib/util.js
================================================
'use strict'
const cp = require('child_process')
const path = require('path')
const { openSync, closeSync } = require('graceful-fs')
const log = require('./log')
const execFile = async (...args) => new Promise((resolve) => {
const child = cp.execFile(...args, (...a) => resolve(a))
child.stdin.end()
})
async function regGetValue (key, value, addOpts) {
const outReValue = value.replace(/\W/g, '.')
const outRe = new RegExp(`^\\s+${outReValue}\\s+REG_\\w+\\s+(\\S.*)$`, 'im')
const reg = path.join(process.env.SystemRoot, 'System32', 'reg.exe')
const regArgs = ['query', key, '/v', value].concat(addOpts)
log.silly('reg', 'running', reg, regArgs)
const [err, stdout, stderr] = await execFile(reg, regArgs, { encoding: 'utf8' })
log.silly('reg', 'reg.exe stdout = %j', stdout)
if (err || stderr.trim() !== '') {
log.silly('reg', 'reg.exe err = %j', err && (err.stack || err))
log.silly('reg', 'reg.exe stderr = %j', stderr)
if (err) {
throw err
}
throw new Error(stderr)
}
const result = outRe.exec(stdout)
if (!result) {
log.silly('reg', 'error parsing stdout')
throw new Error('Could not parse output of reg.exe')
}
log.silly('reg', 'found: %j', result[1])
return result[1]
}
async function regSearchKeys (keys, value, addOpts) {
for (const key of keys) {
try {
return await regGetValue(key, value, addOpts)
} catch {
continue
}
}
}
/**
* Returns the first file or directory from an array of candidates that is
* readable by the current user, or undefined if none of the candidates are
* readable.
*/
function findAccessibleSync (logprefix, dir, candidates) {
for (let next = 0; next < candidates.length; next++) {
const candidate = path.resolve(dir, candidates[next])
let fd
try {
fd = openSync(candidate, 'r')
} catch (e) {
// this candidate was not found or not readable, do nothing
log.silly(logprefix, 'Could not open %s: %s', candidate, e.message)
continue
}
closeSync(fd)
log.silly(logprefix, 'Found readable %s', candidate)
return candidate
}
return undefined
}
module.exports = {
execFile,
regGetValue,
regSearchKeys,
findAccessibleSync
}
================================================
FILE: macOS_Catalina_acid_test.sh
================================================
#!/bin/bash
pkgs=(
"com.apple.pkg.DeveloperToolsCLILeo" # standalone
"com.apple.pkg.DeveloperToolsCLI" # from XCode
"com.apple.pkg.CLTools_Executables" # Mavericks
)
for pkg in "${pkgs[@]}"; do
output=$(/usr/sbin/pkgutil --pkg-info "$pkg" 2>/dev/null)
if [ "$output" ]; then
version=$(echo "$output" | grep 'version' | cut -d' ' -f2)
break
fi
done
if [ "$version" ]; then
echo "Command Line Tools version: $version"
else
echo >&2 'Command Line Tools not found'
fi
================================================
FILE: package.json
================================================
{
"name": "node-gyp",
"description": "Node.js native addon build tool",
"license": "MIT",
"keywords": [
"native",
"addon",
"module",
"c",
"c++",
"bindings",
"gyp"
],
"version": "12.2.0",
"installVersion": 11,
"author": "Nathan Rajlich (http://tootallnate.net)",
"repository": {
"type": "git",
"url": "git://github.com/nodejs/node-gyp.git"
},
"preferGlobal": true,
"bin": "./bin/node-gyp.js",
"main": "./lib/node-gyp.js",
"dependencies": {
"env-paths": "^2.2.0",
"exponential-backoff": "^3.1.1",
"graceful-fs": "^4.2.6",
"make-fetch-happen": "^15.0.0",
"nopt": "^9.0.0",
"proc-log": "^6.0.0",
"semver": "^7.3.5",
"tar": "^7.5.4",
"tinyglobby": "^0.2.12",
"which": "^6.0.0"
},
"engines": {
"node": "^20.17.0 || >=22.9.0"
},
"devDependencies": {
"bindings": "^1.5.0",
"cross-env": "^10.1.0",
"eslint": "^9.39.1",
"mocha": "^11.7.5",
"nan": "^2.23.1",
"neostandard": "^0.12.2",
"require-inject": "^1.4.4"
},
"scripts": {
"lint": "eslint \"*/*.js\" \"test/**/*.js\" \".github/**/*.js\"",
"test": "cross-env NODE_GYP_NULL_LOGGER=true mocha --timeout 30000 test/test-download.js test/test-*"
}
}
================================================
FILE: release-please-config.json
================================================
{
"packages": {
".": {
"include-component-in-tag": false,
"release-type": "node",
"changelog-sections": [
{ "type": "feat", "section": "Features", "hidden": false },
{ "type": "fix", "section": "Bug Fixes", "hidden": false },
{ "type": "bin", "section": "Core", "hidden": false },
{ "type": "gyp", "section": "Core", "hidden": false },
{ "type": "lib", "section": "Core", "hidden": false },
{ "type": "src", "section": "Core", "hidden": false },
{ "type": "test", "section": "Tests", "hidden": false },
{ "type": "build", "section": "Core", "hidden": false },
{ "type": "clean", "section": "Core", "hidden": false },
{ "type": "configure", "section": "Core", "hidden": false },
{ "type": "install", "section": "Core", "hidden": false },
{ "type": "list", "section": "Core", "hidden": false },
{ "type": "rebuild", "section": "Core", "hidden": false },
{ "type": "remove", "section": "Core", "hidden": false },
{ "type": "deps", "section": "Core", "hidden": false },
{ "type": "python", "section": "Core", "hidden": false },
{ "type": "lin", "section": "Core", "hidden": false },
{ "type": "linux", "section": "Core", "hidden": false },
{ "type": "mac", "section": "Core", "hidden": false },
{ "type": "macos", "section": "Core", "hidden": false },
{ "type": "win", "section": "Core", "hidden": false },
{ "type": "windows", "section": "Core", "hidden": false },
{ "type": "zos", "section": "Core", "hidden": false },
{ "type": "doc", "section": "Doc", "hidden": false },
{ "type": "docs", "section": "Doc", "hidden": false },
{ "type": "readme", "section": "Doc", "hidden": false },
{ "type": "chore", "section": "Miscellaneous", "hidden": false },
{ "type": "refactor", "section": "Miscellaneous", "hidden": false },
{ "type": "ci", "section": "Miscellaneous", "hidden": false },
{ "type": "meta", "section": "Miscellaneous", "hidden": false }
]
}
}
}
================================================
FILE: src/win_delay_load_hook.cc
================================================
/*
* When this file is linked to a DLL, it sets up a delay-load hook that
* intervenes when the DLL is trying to load the host executable
* dynamically. Instead of trying to locate the .exe file it'll just
* return a handle to the process image.
*
* This allows compiled addons to work when the host executable is renamed.
*/
#ifdef _MSC_VER
#pragma managed(push, off)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include
#include
#include
static FARPROC WINAPI load_exe_hook(unsigned int event, DelayLoadInfo* info) {
HMODULE m;
if (event != dliNotePreLoadLibrary)
return NULL;
if (_stricmp(info->szDll, HOST_BINARY) != 0)
return NULL;
// try for libnode.dll to compat node.js that using 'vcbuild.bat dll'
m = GetModuleHandle(TEXT("libnode.dll"));
if (m == NULL) m = GetModuleHandle(NULL);
return (FARPROC) m;
}
decltype(__pfnDliNotifyHook2) __pfnDliNotifyHook2 = load_exe_hook;
#pragma managed(pop)
#endif
================================================
FILE: test/common.js
================================================
const envPaths = require('env-paths')
const semver = require('semver')
module.exports.devDir = envPaths('node-gyp', { suffix: '' }).cache
module.exports.poison = (object, property) => {
function fail () {
console.error(Error(`Property ${property} should not have been accessed.`))
process.abort()
}
const descriptor = {
configurable: false,
enumerable: false,
get: fail,
set: fail
}
Object.defineProperty(object, property, descriptor)
}
// Only run full test suite when instructed and on a non-prerelease version of node
module.exports.FULL_TEST =
process.env.FULL_TEST === '1' &&
process.release.name === 'node' &&
semver.prerelease(process.version) === null
module.exports.platformTimeout = (def, obj) => {
for (const [key, value] of Object.entries(obj)) {
if (process.platform === key) {
return value * 60 * 1000
}
}
return def * 60 * 1000
}
================================================
FILE: test/fixtures/VSSetup_VS_2019_Professional_workload.txt
================================================
[
{
"InstanceId": "2619cf21",
"InstallationName": "VisualStudio/16.11.33+34407.143",
"InstallationPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional",
"InstallationVersion": {
"Major": 16,
"Minor": 11,
"Build": 34407,
"Revision": 143,
"MajorRevision": 0,
"MinorRevision": 143
},
"InstallDate": "\/Date(1706804943503)\/",
"State": 4294967295,
"DisplayName": "Visual Studio Professional 2019",
"Description": "Professional IDE best suited to small teams",
"ProductPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\Common7\\IDE\\devenv.exe",
"Product": {
"Id": "Microsoft.VisualStudio.Product.Professional",
"Version": {
"Major": 16,
"Minor": 11,
"Build": 34407,
"Revision": 143,
"MajorRevision": 0,
"MinorRevision": 143
},
"Chip": null,
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Professional,version=16.11.34407.143"
},
"Packages": [
{
"Id": "Microsoft.VisualStudio.Product.Professional",
"Version": "16.11.34407.143",
"Chip": null,
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Professional,version=16.11.34407.143"
},
{
"Id": "Microsoft.VisualStudio.Component.VC.14.29.16.10.ATL",
"Version": "16.11.31314.313",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.VC.14.29.16.10.ATL,version=16.11.31314.313"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.X64.v142",
"Version": "16.11.31503.54",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.X64.v142,version=16.11.31503.54"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.X64",
"Version": "16.11.31503.54",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.X64,version=16.11.31503.54"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.x86.v142",
"Version": "16.11.31503.54",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.x86.v142,version=16.11.31503.54"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.X86",
"Version": "16.11.31503.54",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.X86,version=16.11.31503.54"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.Base",
"Version": "16.11.31829.152",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.Base,version=16.11.31829.152"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.Base.Resources",
"Version": "16.11.31829.152",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.Base.Resources,version=16.11.31829.152,language=en-US"
},
{
"Id": "Microsoft.VisualStudio.Branding.Professional",
"Version": "16.11.31605.320",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Branding.Professional,version=16.11.31605.320,language=en-US"
},
{
"Id": "Microsoft.VisualStudio.Component.Windows10SDK.19041",
"Version": "16.10.31205.252",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.Windows10SDK.19041,version=16.10.31205.252"
},
{
"Id": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Version": "16.11.32406.258",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64,version=16.11.32406.258"
}
],
"Properties": [
{
"Key": "CampaignId",
"Value": "09"
},
{
"Key": "SetupEngineFilePath",
"Value": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\setup.exe"
},
{
"Key": "Nickname",
"Value": ""
},
{
"Key": "ChannelManifestId",
"Value": "VisualStudio.16.Release/16.11.33+34407.143"
}
],
"Errors": null,
"EnginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
"IsComplete": true,
"IsLaunchable": true,
"CatalogInfo": [
{
"Key": "Id",
"Value": "VisualStudio/16.11.33+34407.143"
},
{
"Key": "BuildBranch",
"Value": "d16.11"
},
{
"Key": "BuildVersion",
"Value": "16.11.34407.143"
},
{
"Key": "LocalBuild",
"Value": "build-lab"
},
{
"Key": "ManifestName",
"Value": "VisualStudio"
},
{
"Key": "ManifestType",
"Value": "installer"
},
{
"Key": "ProductDisplayVersion",
"Value": "16.11.33"
},
{
"Key": "ProductLine",
"Value": "Dev16"
},
{
"Key": "ProductLineVersion",
"Value": "2019"
},
{
"Key": "ProductMilestone",
"Value": "RTW"
},
{
"Key": "ProductMilestoneIsPreRelease",
"Value": "False"
},
{
"Key": "ProductName",
"Value": "Visual Studio"
},
{
"Key": "ProductPatchVersion",
"Value": "33"
},
{
"Key": "ProductPreReleaseMilestoneSuffix",
"Value": "1.0"
},
{
"Key": "ProductSemanticVersion",
"Value": "16.11.33+34407.143"
},
{
"Key": "RequiredEngineVersion",
"Value": "2.11.72.18200"
}
],
"IsPrerelease": false,
"PSPath": "Microsoft.PowerShell.Core\\FileSystem::C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"UpdateDate": "2024-01-09T19:19:11.0115234Z",
"ResolvedInstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"ChannelId": "VisualStudio.17.Release",
"InstalledChannelId": "VisualStudio.17.Release",
"ChannelUri": "https://aka.ms/vs/17/release/channel",
"InstalledChannelUri": "https://aka.ms/vs/17/release/channel",
"ReleaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.8#17.8.4",
"ThirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=661288"
}
]
================================================
FILE: test/fixtures/VSSetup_VS_2022_VS2019_workload.txt
================================================
[
{
"InstanceId": "621862c0",
"InstallationName": "VisualStudio/17.8.3+34330.188",
"InstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"InstallationVersion": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"InstallDate": "\/Date(1703254955000)\/",
"State": 4294967295,
"DisplayName": "Visual Studio Enterprise 2022",
"Description": "Scalable, end-to-end solution for teams of any size",
"ProductPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\IDE\\devenv.exe",
"Product": {
"Id": "Microsoft.VisualStudio.Product.Enterprise",
"Version": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"Chip": "x64",
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Enterprise,version=17.8.34330.188,chip=x64"
},
"Packages": [
{
"Id": "Microsoft.VisualStudio.Product.Enterprise",
"Version": "17.8.34330.188",
"Chip": "x64",
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Enterprise,version=17.8.34330.188,chip=x64"
},
{
"Id": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64,version=17.8.34129.139"
},
{
"Id": "Microsoft.VisualStudio.Component.Windows11SDK.22000",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.Windows11SDK.22000,version=17.8.34129.139"
},
{
"Id": "Win11SDK_10.0.22000",
"Version": "10.0.22000.4",
"Chip": null,
"Branch": null,
"Type": "Exe",
"IsExtension": false,
"UniqueId": "Win11SDK_10.0.22000,version=10.0.22000.4"
},
{
"Id": "Microsoft.VisualStudio.Component.Windows10SDK.20348",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.Windows10SDK.20348,version=17.8.34129.139"
},
{
"Id": "Win10SDK_10.0.20348",
"Version": "10.0.20348.3",
"Chip": null,
"Branch": null,
"Type": "Exe",
"IsExtension": false,
"UniqueId": "Win10SDK_10.0.20348,version=10.0.20348.3"
}
],
"Properties": [
{
"Key": "CampaignId",
"Value": ""
},
{
"Key": "SetupEngineFilePath",
"Value": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\setup.exe"
},
{
"Key": "Nickname",
"Value": ""
},
{
"Key": "ChannelManifestId",
"Value": "VisualStudio.17.Release/17.8.3+34330.188"
}
],
"Errors": null,
"EnginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
"IsComplete": true,
"IsLaunchable": true,
"CatalogInfo": [
{
"Key": "Id",
"Value": "VisualStudio/17.8.3+34330.188"
},
{
"Key": "BuildBranch",
"Value": "d17.8"
},
{
"Key": "BuildVersion",
"Value": "17.8.34330.188"
}
],
"IsPrerelease": false,
"PSPath": "Microsoft.PowerShell.Core\\FileSystem::C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"UpdateDate": "2023-12-22T14:22:35.1818213Z",
"ResolvedInstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"ChannelId": "VisualStudio.17.Release",
"InstalledChannelId": "VisualStudio.17.Release",
"ChannelUri": "https://aka.ms/vs/17/release/channel",
"InstalledChannelUri": "https://aka.ms/vs/17/release/channel",
"ReleaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.8#17.8.3",
"ThirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=661288"
},
{
"InstanceId": "2619cf21",
"InstallationName": "VisualStudio/16.11.33+34407.143",
"InstallationPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional",
"InstallationVersion": {
"Major": 16,
"Minor": 11,
"Build": 34407,
"Revision": 143,
"MajorRevision": 0,
"MinorRevision": 143
},
"InstallDate": "\/Date(1706804943503)\/",
"State": 4294967295,
"DisplayName": "Visual Studio Professional 2019",
"Description": "Professional IDE best suited to small teams",
"ProductPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Professional\\Common7\\IDE\\devenv.exe",
"Product": {
"Id": "Microsoft.VisualStudio.Product.Professional",
"Version": {
"Major": 16,
"Minor": 11,
"Build": 34407,
"Revision": 143,
"MajorRevision": 0,
"MinorRevision": 143
},
"Chip": null,
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Professional,version=16.11.34407.143"
},
"Packages": [
{
"Id": "Microsoft.VisualStudio.Product.Professional",
"Version": "16.11.34407.143",
"Chip": null,
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Professional,version=16.11.34407.143"
},
{
"Id": "Microsoft.VisualStudio.Component.VC.14.29.16.10.ATL",
"Version": "16.11.31314.313",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.VC.14.29.16.10.ATL,version=16.11.31314.313"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.X64.v142",
"Version": "16.11.31503.54",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.X64.v142,version=16.11.31503.54"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.X64",
"Version": "16.11.31503.54",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.X64,version=16.11.31503.54"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.x86.v142",
"Version": "16.11.31503.54",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.x86.v142,version=16.11.31503.54"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.X86",
"Version": "16.11.31503.54",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.X86,version=16.11.31503.54"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.Base",
"Version": "16.11.31829.152",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.Base,version=16.11.31829.152"
},
{
"Id": "Microsoft.VisualStudio.VC.MSBuild.Base.Resources",
"Version": "16.11.31829.152",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.MSBuild.Base.Resources,version=16.11.31829.152,language=en-US"
},
{
"Id": "Microsoft.VisualStudio.Branding.Professional",
"Version": "16.11.31605.320",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Branding.Professional,version=16.11.31605.320,language=en-US"
},
{
"Id": "Microsoft.VisualStudio.Component.Windows10SDK.19041",
"Version": "16.10.31205.252",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.Windows10SDK.19041,version=16.10.31205.252"
},
{
"Id": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Version": "16.11.32406.258",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64,version=16.11.32406.258"
}
],
"Properties": [
{
"Key": "CampaignId",
"Value": "09"
},
{
"Key": "SetupEngineFilePath",
"Value": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\setup.exe"
},
{
"Key": "Nickname",
"Value": ""
},
{
"Key": "ChannelManifestId",
"Value": "VisualStudio.16.Release/16.11.33+34407.143"
}
],
"Errors": null,
"EnginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
"IsComplete": true,
"IsLaunchable": true,
"CatalogInfo": [
{
"Key": "Id",
"Value": "VisualStudio/16.11.33+34407.143"
},
{
"Key": "BuildBranch",
"Value": "d16.11"
},
{
"Key": "BuildVersion",
"Value": "16.11.34407.143"
},
{
"Key": "LocalBuild",
"Value": "build-lab"
},
{
"Key": "ManifestName",
"Value": "VisualStudio"
},
{
"Key": "ManifestType",
"Value": "installer"
},
{
"Key": "ProductDisplayVersion",
"Value": "16.11.33"
},
{
"Key": "ProductLine",
"Value": "Dev16"
},
{
"Key": "ProductLineVersion",
"Value": "2019"
},
{
"Key": "ProductMilestone",
"Value": "RTW"
},
{
"Key": "ProductMilestoneIsPreRelease",
"Value": "False"
},
{
"Key": "ProductName",
"Value": "Visual Studio"
},
{
"Key": "ProductPatchVersion",
"Value": "33"
},
{
"Key": "ProductPreReleaseMilestoneSuffix",
"Value": "1.0"
},
{
"Key": "ProductSemanticVersion",
"Value": "16.11.33+34407.143"
},
{
"Key": "RequiredEngineVersion",
"Value": "2.11.72.18200"
}
],
"IsPrerelease": false,
"PSPath": "Microsoft.PowerShell.Core\\FileSystem::C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"UpdateDate": "2024-01-09T19:19:11.0115234Z",
"ResolvedInstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"ChannelId": "VisualStudio.17.Release",
"InstalledChannelId": "VisualStudio.17.Release",
"ChannelUri": "https://aka.ms/vs/17/release/channel",
"InstalledChannelUri": "https://aka.ms/vs/17/release/channel",
"ReleaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.8#17.8.4",
"ThirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=661288"
}
]
================================================
FILE: test/fixtures/VSSetup_VS_2022_multiple_install.txt
================================================
[
{
"InstanceId": "621862c0",
"InstallationName": "VisualStudio/17.8.3+34330.188",
"InstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"InstallationVersion": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"InstallDate": "\/Date(1703254955000)\/",
"State": 4294967295,
"DisplayName": "Visual Studio Enterprise 2022",
"Description": "Scalable, end-to-end solution for teams of any size",
"ProductPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\IDE\\devenv.exe",
"Product": {
"Id": "Microsoft.VisualStudio.Product.Enterprise",
"Version": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"Chip": "x64",
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Enterprise,version=17.8.34330.188,chip=x64"
},
"Packages": [
{
"Id": "Microsoft.VisualStudio.Product.Enterprise",
"Version": "17.8.34330.188",
"Chip": "x64",
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Enterprise,version=17.8.34330.188,chip=x64"
},
{
"Id": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64,version=17.8.34129.139"
},
{
"Id": "Microsoft.VisualStudio.Component.Windows11SDK.22000",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.Windows11SDK.22000,version=17.8.34129.139"
},
{
"Id": "Win11SDK_10.0.22000",
"Version": "10.0.22000.4",
"Chip": null,
"Branch": null,
"Type": "Exe",
"IsExtension": false,
"UniqueId": "Win11SDK_10.0.22000,version=10.0.22000.4"
},
{
"Id": "Microsoft.VisualStudio.Component.Windows10SDK.20348",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.Windows10SDK.20348,version=17.8.34129.139"
},
{
"Id": "Win10SDK_10.0.20348",
"Version": "10.0.20348.3",
"Chip": null,
"Branch": null,
"Type": "Exe",
"IsExtension": false,
"UniqueId": "Win10SDK_10.0.20348,version=10.0.20348.3"
}
],
"Properties": [
{
"Key": "CampaignId",
"Value": ""
},
{
"Key": "SetupEngineFilePath",
"Value": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\setup.exe"
},
{
"Key": "Nickname",
"Value": ""
},
{
"Key": "ChannelManifestId",
"Value": "VisualStudio.17.Release/17.8.3+34330.188"
}
],
"Errors": null,
"EnginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
"IsComplete": true,
"IsLaunchable": true,
"CatalogInfo": [
{
"Key": "Id",
"Value": "VisualStudio/17.8.3+34330.188"
},
{
"Key": "BuildBranch",
"Value": "d17.8"
},
{
"Key": "BuildVersion",
"Value": "17.8.34330.188"
},
{
"Key": "LocalBuild",
"Value": "build-lab"
},
{
"Key": "ManifestName",
"Value": "VisualStudio"
},
{
"Key": "ManifestType",
"Value": "installer"
},
{
"Key": "ProductDisplayVersion",
"Value": "17.8.3"
},
{
"Key": "ProductLine",
"Value": "Dev17"
},
{
"Key": "ProductLineVersion",
"Value": "2022"
},
{
"Key": "ProductMilestone",
"Value": "RTW"
},
{
"Key": "ProductMilestoneIsPreRelease",
"Value": "False"
},
{
"Key": "ProductName",
"Value": "Visual Studio"
},
{
"Key": "ProductPatchVersion",
"Value": "3"
},
{
"Key": "ProductPreReleaseMilestoneSuffix",
"Value": "1.0"
},
{
"Key": "ProductSemanticVersion",
"Value": "17.8.3+34330.188"
},
{
"Key": "RequiredEngineVersion",
"Value": "3.8.2112.61926"
}
],
"IsPrerelease": false,
"PSPath": "Microsoft.PowerShell.Core\\FileSystem::C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"UpdateDate": "2023-12-22T14:22:35.1818213Z",
"ResolvedInstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"ChannelId": "VisualStudio.17.Release",
"InstalledChannelId": "VisualStudio.17.Release",
"ChannelUri": "https://aka.ms/vs/17/release/channel",
"InstalledChannelUri": "https://aka.ms/vs/17/release/channel",
"ReleaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.8#17.8.3",
"ThirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=661288"
},
{
"InstanceId": "dd50c6cc",
"InstallationName": "VisualStudio/17.8.3+34330.188",
"InstallationPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools",
"InstallationVersion": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"InstallDate": "\/Date(1703262914503)\/",
"State": 4294967295,
"DisplayName": "Visual Studio Build Tools 2022",
"Description": "The Visual Studio Build Tools allows you to build native and managed MSBuild-based applications without requiring the Visual Studio IDE. There are options to install the Visual C++ compilers and libraries, MFC, ATL, and C++/CLI support.",
"ProductPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\Common7\\Tools\\LaunchDevCmd.bat",
"Product": {
"Id": "Microsoft.VisualStudio.Product.BuildTools",
"Version": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"Chip": null,
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.BuildTools,version=17.8.34330.188"
},
"Packages": [
{
"Id": "Microsoft.VisualStudio.Product.BuildTools",
"Version": "17.8.34330.188",
"Chip": null,
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.BuildTools,version=17.8.34330.188"
},
{
"Id": "Microsoft.VisualStudio.Workload.MSBuildTools",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Workload",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Workload.MSBuildTools,version=17.8.34129.139"
},
{
"Id": "Microsoft.VisualStudio.NuGet.BuildTools",
"Version": "17.0.60800.131",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.NuGet.BuildTools,version=17.0.60800.131"
},
{
"Id": "Microsoft.Build.UnGAC",
"Version": "17.8.3.2351904",
"Chip": "neutral",
"Branch": null,
"Type": "Exe",
"IsExtension": false,
"UniqueId": "Microsoft.Build.UnGAC,version=17.8.3.2351904,chip=neutral,language=neutral"
},
{
"Id": "Microsoft.VisualStudio.VC.Icons",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Vsix",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.VC.Icons,version=17.8.34129.139"
}
],
"Properties": [
{
"Key": "CampaignId",
"Value": "09"
},
{
"Key": "SetupEngineFilePath",
"Value": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\setup.exe"
},
{
"Key": "Nickname",
"Value": "2"
},
{
"Key": "ChannelManifestId",
"Value": "VisualStudio.17.Release/17.8.3+34330.188"
}
],
"Errors": null,
"EnginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
"IsComplete": true,
"IsLaunchable": true,
"CatalogInfo": [
{
"Key": "Id",
"Value": "VisualStudio/17.8.3+34330.188"
},
{
"Key": "BuildBranch",
"Value": "d17.8"
},
{
"Key": "BuildVersion",
"Value": "17.8.34330.188"
},
{
"Key": "LocalBuild",
"Value": "build-lab"
},
{
"Key": "ManifestName",
"Value": "VisualStudio"
},
{
"Key": "ManifestType",
"Value": "installer"
},
{
"Key": "ProductDisplayVersion",
"Value": "17.8.3"
},
{
"Key": "ProductLine",
"Value": "Dev17"
},
{
"Key": "ProductLineVersion",
"Value": "2022"
},
{
"Key": "ProductMilestone",
"Value": "RTW"
},
{
"Key": "ProductMilestoneIsPreRelease",
"Value": "False"
},
{
"Key": "ProductName",
"Value": "Visual Studio"
},
{
"Key": "ProductPatchVersion",
"Value": "3"
},
{
"Key": "ProductPreReleaseMilestoneSuffix",
"Value": "1.0"
},
{
"Key": "ProductSemanticVersion",
"Value": "17.8.3+34330.188"
},
{
"Key": "RequiredEngineVersion",
"Value": "3.8.2112.61926"
}
],
"IsPrerelease": false,
"PSPath": "Microsoft.PowerShell.Core\\FileSystem::C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"UpdateDate": "2023-12-22T14:22:35.1818213Z",
"ResolvedInstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"ChannelId": "VisualStudio.17.Release",
"InstalledChannelId": "VisualStudio.17.Release",
"ChannelUri": "https://aka.ms/vs/17/release/channel",
"InstalledChannelUri": "https://aka.ms/vs/17/release/channel",
"ReleaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.8#17.8.3",
"ThirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=661288"
}
]
================================================
FILE: test/fixtures/VSSetup_VS_2022_workload.txt
================================================
{
"InstanceId": "621862c0",
"InstallationName": "VisualStudio/17.8.3+34330.188",
"InstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"InstallationVersion": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"InstallDate": "\/Date(1703254955000)\/",
"State": 4294967295,
"DisplayName": "Visual Studio Enterprise 2022",
"Description": "Scalable, end-to-end solution for teams of any size",
"ProductPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\IDE\\devenv.exe",
"Product": {
"Id": "Microsoft.VisualStudio.Product.Enterprise",
"Version": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"Chip": "x64",
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Enterprise,version=17.8.34330.188,chip=x64"
},
"Packages": [
{
"Id": "Microsoft.VisualStudio.Product.Enterprise",
"Version": "17.8.34330.188",
"Chip": "x64",
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Enterprise,version=17.8.34330.188,chip=x64"
},
{
"Id": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64,version=17.8.34129.139"
},
{
"Id": "Microsoft.VisualStudio.Component.Windows11SDK.22000",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.Windows11SDK.22000,version=17.8.34129.139"
},
{
"Id": "Win11SDK_10.0.22000",
"Version": "10.0.22000.4",
"Chip": null,
"Branch": null,
"Type": "Exe",
"IsExtension": false,
"UniqueId": "Win11SDK_10.0.22000,version=10.0.22000.4"
},
{
"Id": "Microsoft.VisualStudio.Component.Windows10SDK.20348",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.Windows10SDK.20348,version=17.8.34129.139"
},
{
"Id": "Win10SDK_10.0.20348",
"Version": "10.0.20348.3",
"Chip": null,
"Branch": null,
"Type": "Exe",
"IsExtension": false,
"UniqueId": "Win10SDK_10.0.20348,version=10.0.20348.3"
}
],
"Properties": [
{
"Key": "CampaignId",
"Value": ""
},
{
"Key": "SetupEngineFilePath",
"Value": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\setup.exe"
},
{
"Key": "Nickname",
"Value": ""
},
{
"Key": "ChannelManifestId",
"Value": "VisualStudio.17.Release/17.8.3+34330.188"
}
],
"Errors": null,
"EnginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
"IsComplete": true,
"IsLaunchable": true,
"CatalogInfo": [
{
"Key": "Id",
"Value": "VisualStudio/17.8.3+34330.188"
},
{
"Key": "BuildBranch",
"Value": "d17.8"
},
{
"Key": "BuildVersion",
"Value": "17.8.34330.188"
}
],
"IsPrerelease": false,
"PSPath": "Microsoft.PowerShell.Core\\FileSystem::C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"UpdateDate": "2023-12-22T14:22:35.1818213Z",
"ResolvedInstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"ChannelId": "VisualStudio.17.Release",
"InstalledChannelId": "VisualStudio.17.Release",
"ChannelUri": "https://aka.ms/vs/17/release/channel",
"InstalledChannelUri": "https://aka.ms/vs/17/release/channel",
"ReleaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.8#17.8.3",
"ThirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=661288"
}
================================================
FILE: test/fixtures/VSSetup_VS_2022_workload_missing_sdk.txt
================================================
{
"InstanceId": "621862c0",
"InstallationName": "VisualStudio/17.8.3+34330.188",
"InstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"InstallationVersion": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"InstallDate": "\/Date(1703254955000)\/",
"State": 4294967295,
"DisplayName": "Visual Studio Enterprise 2022",
"Description": "Scalable, end-to-end solution for teams of any size",
"ProductPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Common7\\IDE\\devenv.exe",
"Product": {
"Id": "Microsoft.VisualStudio.Product.Enterprise",
"Version": {
"Major": 17,
"Minor": 8,
"Build": 34330,
"Revision": 188,
"MajorRevision": 0,
"MinorRevision": 188
},
"Chip": "x64",
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Enterprise,version=17.8.34330.188,chip=x64"
},
"Packages": [
{
"Id": "Microsoft.VisualStudio.Product.Enterprise",
"Version": "17.8.34330.188",
"Chip": "x64",
"Branch": null,
"Type": "Product",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Product.Enterprise,version=17.8.34330.188,chip=x64"
},
{
"Id": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Version": "17.8.34129.139",
"Chip": null,
"Branch": null,
"Type": "Component",
"IsExtension": false,
"UniqueId": "Microsoft.VisualStudio.Component.VC.Tools.x86.x64,version=17.8.34129.139"
},
],
"Properties": [
{
"Key": "CampaignId",
"Value": ""
},
{
"Key": "SetupEngineFilePath",
"Value": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\setup.exe"
},
{
"Key": "Nickname",
"Value": ""
},
{
"Key": "ChannelManifestId",
"Value": "VisualStudio.17.Release/17.8.3+34330.188"
}
],
"Errors": null,
"EnginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
"IsComplete": true,
"IsLaunchable": true,
"CatalogInfo": [
{
"Key": "Id",
"Value": "VisualStudio/17.8.3+34330.188"
},
{
"Key": "BuildBranch",
"Value": "d17.8"
},
{
"Key": "BuildVersion",
"Value": "17.8.34330.188"
},
{
"Key": "LocalBuild",
"Value": "build-lab"
},
{
"Key": "ManifestName",
"Value": "VisualStudio"
},
{
"Key": "ManifestType",
"Value": "installer"
},
{
"Key": "ProductDisplayVersion",
"Value": "17.8.3"
},
{
"Key": "ProductLine",
"Value": "Dev17"
},
{
"Key": "ProductLineVersion",
"Value": "2022"
},
{
"Key": "ProductMilestone",
"Value": "RTW"
},
{
"Key": "ProductMilestoneIsPreRelease",
"Value": "False"
},
{
"Key": "ProductName",
"Value": "Visual Studio"
},
{
"Key": "ProductPatchVersion",
"Value": "3"
},
{
"Key": "ProductPreReleaseMilestoneSuffix",
"Value": "1.0"
},
{
"Key": "ProductSemanticVersion",
"Value": "17.8.3+34330.188"
},
{
"Key": "RequiredEngineVersion",
"Value": "3.8.2112.61926"
}
],
"IsPrerelease": false,
"PSPath": "Microsoft.PowerShell.Core\\FileSystem::C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"UpdateDate": "2023-12-22T14:22:35.1818213Z",
"ResolvedInstallationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise",
"ChannelId": "VisualStudio.17.Release",
"InstalledChannelId": "VisualStudio.17.Release",
"ChannelUri": "https://aka.ms/vs/17/release/channel",
"InstalledChannelUri": "https://aka.ms/vs/17/release/channel",
"ReleaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.8#17.8.3",
"ThirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=661288"
}
================================================
FILE: test/fixtures/VS_2017_BuildTools_minimal.txt
================================================
[{"path":"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools","version":"15.9.28307.665","packages":["Microsoft.VisualStudio.Product.BuildTools","Microsoft.VisualStudio.Component.VC.CoreIde","Microsoft.VisualStudio.VC.Ide.Pro","Microsoft.VisualStudio.VC.Ide.Pro.Resources","Microsoft.VisualStudio.VC.Templates.Pro","Microsoft.VisualStudio.VC.Templates.Pro.Resources","Microsoft.VisualStudio.VC.Items.Pro","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced","Microsoft.VisualStudio.VC.Ide.MDD","Microsoft.VisualStudio.VC.Ide.x64","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express","Microsoft.VisualStudio.PackageGroup.Debugger.Script","Microsoft.VisualStudio.JavaScript.LanguageService","Microsoft.VisualStudio.JavaScript.LanguageService.Resources","Microsoft.VisualStudio.Debugger.Script.Msi","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.VC.Ide.WinXPlus","Microsoft.VisualStudio.VC.Ide.Dskx","Microsoft.VisualStudio.VC.Ide.Dskx.Resources","Microsoft.VisualStudio.VC.Ide.Core","Microsoft.VisualStudio.VC.Ide.Core.Resources","Microsoft.VisualStudio.VC.Ide.Base","Microsoft.VisualStudio.VC.Ide.LanguageService","Microsoft.VisualStudio.VC.Ide.ResourceEditor","Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources","Microsoft.VisualStudio.VC.Ide.ProjectSystem","Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources","Microsoft.VisualStudio.VC.Ide.LanguageService.Resources","Microsoft.VisualStudio.VC.Ide.Base.Resources","Microsoft.VisualStudio.PackageGroup.Core","Microsoft.VisualStudio.TestTools.TeamFoundationClient","Microsoft.VisualStudio.PackageGroup.Debugger.Core","Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost","Microsoft.VisualStudio.VC.Ide.Debugger","Microsoft.VisualStudio.VC.Ide.Debugger.Resources","Microsoft.VisualStudio.VC.Ide.Common","Microsoft.VisualStudio.VC.Ide.Common.Resources","Microsoft.VisualStudio.Debugger.Parallel","Microsoft.VisualStudio.Debugger.Parallel.Resources","Microsoft.VisualStudio.Debugger.CollectionAgents","Microsoft.VisualStudio.Debugger.Managed","Microsoft.CodeAnalysis.VisualStudio.Setup.Resources","Microsoft.CodeAnalysis.VisualStudio.Setup","Microsoft.CodeAnalysis.ExpressionEvaluator.Resources","Microsoft.CodeAnalysis.ExpressionEvaluator","Microsoft.VisualStudio.Debugger.Managed.Resources","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger","Microsoft.VisualStudio.VC.MSVCDis","Microsoft.VisualStudio.ScriptedHost","Microsoft.VisualStudio.ScriptedHost.Targeted","Microsoft.VisualStudio.ScriptedHost.Resources","Microsoft.IntelliTrace.DiagnosticsHub","Microsoft.VisualStudio.Debugger.Resources","Microsoft.PackageGroup.ClientDiagnostics","Microsoft.VisualStudio.AppResponsiveness","Microsoft.VisualStudio.AppResponsiveness.Targeted","Microsoft.VisualStudio.AppResponsiveness.Resources","Microsoft.VisualStudio.ClientDiagnostics","Microsoft.VisualStudio.ClientDiagnostics.Targeted","Microsoft.VisualStudio.ClientDiagnostics.Resources","Microsoft.VisualStudio.PackageGroup.CommunityCore","Microsoft.VisualStudio.ProjectSystem.Full","Microsoft.VisualStudio.ProjectSystem","Microsoft.VisualStudio.Community.x86","Microsoft.VisualStudio.Community.x64","Microsoft.VisualStudio.Community","Microsoft.IntelliTrace.CollectorCab","Microsoft.VisualStudio.Community.Resources","Microsoft.VisualStudio.WebSiteProject.DTE","Microsoft.MSHtml","Microsoft.VisualStudio.Community.Msi.Resources","Microsoft.VisualStudio.Community.Msi","Microsoft.VisualStudio.MinShell.Interop.Msi","Microsoft.VisualStudio.PackageGroup.CoreEditor","PortableFacades","Microsoft.VisualStudio.VirtualTree","Microsoft.VisualStudio.PackageGroup.Progression","Microsoft.VisualStudio.PerformanceProvider","Microsoft.VisualStudio.GraphModel","Microsoft.VisualStudio.GraphProvider","Microsoft.DiaSymReader","Microsoft.VisualStudio.TextMateGrammars","Microsoft.VisualStudio.PackageGroup.TeamExplorer","Microsoft.TeamFoundation.OfficeIntegration","Microsoft.TeamFoundation.OfficeIntegration.Resources","Microsoft.VisualStudio.TeamExplorer","Microsoft.ServiceHub","Microsoft.VisualStudio.ProjectServices","Microsoft.VisualStudio.SLNX.VSIX","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.PackageGroup.MinShell","Microsoft.VisualStudio.MinShell.Msi","Microsoft.VisualStudio.MinShell.Msi.Resources","Microsoft.VisualStudio.MinShell.Interop","Microsoft.VisualStudio.Log","Microsoft.VisualStudio.Log.Targeted","Microsoft.VisualStudio.Log.Resources","Microsoft.VisualStudio.Finalizer","Microsoft.VisualStudio.CoreEditor","Microsoft.VisualStudio.Connected","Microsoft.VisualStudio.Connected.Resources","Microsoft.VisualStudio.MinShell","Microsoft.VisualStudio.MinShell.Platform","Microsoft.VisualStudio.MinShell.Platform.Resources","Microsoft.VisualStudio.MefHosting","Microsoft.VisualStudio.MefHosting.Resources","Microsoft.VisualStudio.Initializer","Microsoft.VisualStudio.ExtensionManager","Microsoft.VisualStudio.Editors","Microsoft.Net.4.TargetingPack","Microsoft.VisualStudio.Component.Windows10SDK.17134","Win10SDK_10.0.17134","Microsoft.VisualStudio.Component.VC.Tools.x86.x64","Microsoft.VisualCpp.CodeAnalysis.Extensions","Microsoft.VisualCpp.CodeAnalysis.Extensions.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86.Resources","Microsoft.VisualCpp.CodeAnalysis.Extensions.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64.Resources","Microsoft.VisualStudio.Component.Static.Analysis.Tools","Microsoft.VisualStudio.StaticAnalysis","Microsoft.VisualStudio.StaticAnalysis.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX86","Microsoft.VisualCpp.VCTip.HostX64.TargetX86","Microsoft.VisualCpp.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX64","Microsoft.VisualCpp.VCTip.HostX64.TargetX64","Microsoft.VisualCpp.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64","Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.PGO.X86","Microsoft.VisualCpp.PGO.X64","Microsoft.VisualCpp.PGO.Headers","Microsoft.VisualCpp.CRT.x86.Store","Microsoft.VisualCpp.CRT.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.x64.Store","Microsoft.VisualCpp.CRT.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.ClickOnce.Msi","Microsoft.VisualStudio.PackageGroup.VC.Tools.x86","Microsoft.VisualCpp.Tools.HostX86.TargetX64","Microsoft.VisualCpp.VCTip.hostX86.targetX64","Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Tools.HostX86.TargetX86","Microsoft.VisualCpp.VCTip.hostX86.targetX86","Microsoft.VisualCpp.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Tools.Core.Resources","Microsoft.VisualCpp.Tools.Core.x86","Microsoft.VisualCpp.Tools.Common.Utils","Microsoft.VisualCpp.Tools.Common.Utils.Resources","Microsoft.VisualCpp.DIA.SDK","Microsoft.VisualCpp.CRT.x86.Desktop","Microsoft.VisualCpp.CRT.x64.Desktop","Microsoft.VisualCpp.CRT.Source","Microsoft.VisualCpp.CRT.Redist.X86","Microsoft.VisualCpp.CRT.Redist.X64","Microsoft.VisualCpp.CRT.Redist.Resources","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.CRT.Headers","Microsoft.VisualStudio.VC.MSBuild.X86","Microsoft.VisualStudio.VC.MSBuild.X64","Microsoft.VS.VC.MSBuild.X64.Resources","Microsoft.VisualStudio.VC.MSBuild.Base","Microsoft.VisualStudio.VC.MSBuild.Base.Resources","Microsoft.VisualStudio.VC.MSBuild.ARM","Microsoft.VisualStudio.Workload.MSBuildTools","Microsoft.VisualStudio.Component.CoreBuildTools","Microsoft.VisualStudio.Setup.Configuration","Microsoft.VisualStudio.PackageGroup.VsDevCmd","Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk","Microsoft.VisualStudio.VsDevCmd.Core.WinSdk","Microsoft.VisualStudio.VsDevCmd.Core.DotNet","Microsoft.VisualStudio.VC.DevCmd","Microsoft.VisualStudio.VC.DevCmd.Resources","Microsoft.VisualStudio.BuildTools.Resources","Microsoft.VisualStudio.Net.Eula.Resources","Microsoft.Build.Dependencies","Microsoft.Build.FileTracker.Msi","Microsoft.Component.MSBuild","Microsoft.PythonTools.BuildCore.Vsix","Microsoft.NuGet.Build.Tasks","Microsoft.VisualStudio.Component.Roslyn.Compiler","Microsoft.CodeAnalysis.Compilers.Resources","Microsoft.CodeAnalysis.Compilers","Microsoft.Net.PackageGroup.4.6.1.Redist","Microsoft.VisualStudio.NativeImageSupport","Microsoft.Build"]}]
================================================
FILE: test/fixtures/VS_2017_Community_workload.txt
================================================
[{"path":"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community","version":"15.9.28307.665","packages":["Microsoft.VisualStudio.Component.Windows10SDK.IpOverUsb","Win10SDK_IpOverUsb","Microsoft.VisualStudio.Component.VC.ATL.ARM64","Microsoft.VisualCpp.ATL.ARM64","Microsoft.VisualStudio.Component.VC.ATL.ARM","Microsoft.VisualCpp.ATL.ARM","Microsoft.VisualStudio.Component.VC.Tools.ARM","Microsoft.VisualCpp.Tools.HostX64.TargetX86.Resources","Microsoft.VisualStudio.Graphics.Analyzer.Resources","Microsoft.Icecap.Analysis","Microsoft.VisualCpp.CRT.Redist.arm.OneCore.Desktop","Microsoft.VisualCpp.CRT.arm.Store","Microsoft.VisualCpp.CRT.arm.Desktop","Microsoft.VisualStudio.PackageGroup.VC.Tools.x64.ARM","Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetarm","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetARM.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM.Resources","Microsoft.VisualCpp.Premium.Tools.ARM.Base","Microsoft.VisualCpp.Premium.Tools.ARM.Base.Resources","Microsoft.VisualCpp.PGO.ARM","Microsoft.VisualCpp.Tools.HostX64.TargetX64","Microsoft.VisualStudio.Product.Community","Microsoft.VisualCpp.Tools.Hostx86.Targetarm","Microsoft.VisualStudio.Component.VC.Tools.ARM64","Microsoft.VisualStudio.VC.MSBuild.Arm64","Microsoft.VisualCpp.CRT.Redist.ARM64.OneCore.Desktop","Microsoft.VisualCpp.VCTip.HostX64.TargetX64","Microsoft.VisualCpp.CRT.ARM64.OneCore.Desktop","Microsoft.VisualCpp.CRT.ARM64.Store","Microsoft.VisualCpp.CRT.ARM64.Desktop","Microsoft.VisualCpp.Tools.HostX64.TargetX64.Resources","Microsoft.Icecap.Analysis.Resources","Microsoft.VisualCpp.VCTip.hostX86.targetARM","Microsoft.VisualStudio.PackageGroup.VC.Tools.x64.ARM64","Microsoft.VisualCpp.Tools.Core","Microsoft.VisualCpp.PGO.ARM64","Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetarm64","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetARM64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM64","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM64.Resources","Microsoft.VisualCpp.Premium.Tools.ARM64.Base","Microsoft.VisualCpp.Tools.HostX86.TargetX64","Microsoft.VisualCpp.Tools.HostX86.TargetARM.Resources","Microsoft.VisualCpp.CRT.Redist.ARM64","Microsoft.VisualCpp.CRT.arm.OneCore.Desktop","Microsoft.VisualCpp.CodeAnalysis.Extensions.X86","Microsoft.VisualCpp.CodeAnalysis.Extensions.X64","Microsoft.VisualCpp.VCTip.HostX64.TargetX86","Component.WixToolset.VisualStudioExtension.Dev15","WixToolset.VisualStudioExtension.Dev15","Microsoft.VisualCpp.MFC.X64","Microsoft.VisualCpp.ATL.Headers","Microsoft.VisualStudio.Component.VC.CMake.Project","Microsoft.VisualStudio.VC.CMake","Microsoft.VisualStudio.VC.CMake.Project","Microsoft.VisualStudio.Component.Windows10SDK.17763","Microsoft.VisualStudio.VC.MSBuild.Base.Resources","MLGen","Microsoft.VisualStudio.Graphics.Analyzer","Microsoft.VisualStudio.Component.TestTools.Core","Microsoft.VisualCpp.Tools.Core.x86","Microsoft.VisualCpp.CRT.x86.OneCore.Desktop","Microsoft.VisualCpp.DIA.SDK","Microsoft.VisualCpp.CRT.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.ClickOnce.Msi","Microsoft.VisualStudio.NuGet.Licenses","SQLCommon","Microsoft.VisualStudio.VC.MSBuild.X86","Microsoft.VisualCpp.Tools.HostX64.TargetARM","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64.Resources","Microsoft.VisualCpp.HTMLHelpWorkshop.Msi","Microsoft.Icecap.Collection.Msi.Resources","Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.VCTip.hostX64.targetARM","Microsoft.VisualStudio.VC.Ide.Dskx.Resources","Microsoft.VisualStudio.VC.Templates.UnitTest","Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP","Microsoft.VisualStudio.VC.Ide.Core","Microsoft.VisualStudio.Graphics.Appid","Microsoft.VisualCpp.ATL.Source","Microsoft.VisualStudio.VC.Ide.Core.Resources","Microsoft.VisualStudio.Debugger.ImmersiveActivateHelper.Msi","Microsoft.VisualStudio.Debugger.JustInTime","Microsoft.DiagnosticsHub.CpuSampling","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Common","Microsoft.VisualStudio.TestTools.TP.Legacy.Common.Res","Microsoft.VisualStudio.ProTools.Resources","Microsoft.VisualStudio.Community.Msi","Microsoft.VisualCpp.Tools.HostX64.TargetARM.Resources","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Agent","Microsoft.Component.MSBuild","Microsoft.VisualStudio.Graphics.Msi","Microsoft.VisualStudio.WebToolsExtensions","Microsoft.VisualCpp.Tools.Hostx86.Targetarm64","Microsoft.VisualStudio.TextTemplating.MSBuild","Microsoft.VisualCpp.VCTip.hostX86.targetARM64","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine","Microsoft.VisualCpp.Tools.HostX86.TargetARM64.Resources","Microsoft.VisualStudio.RazorExtension","Microsoft.VisualCpp.CRT.x86.Store","Microsoft.VisualCpp.Tools.Core.Resources","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualCpp.MFC.Source","Microsoft.VisualCpp.CRT.x86.Desktop","Microsoft.VisualStudio.VC.MSBuild.X64","Microsoft.VisualStudio.VC.Items.Pro","Microsoft.VisualStudio.Graphics.Viewers","Microsoft.VisualCpp.CRT.x64.Desktop","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86.Resources","Microsoft.VisualCpp.MFC.Redist.X86","Microsoft.VisualStudio.WebToolsExtensions.Chip","Microsoft.DiagnosticsHub.Runtime.Resources","Microsoft.DiagnosticsHub.CpuSampling.Targeted","Microsoft.VisualStudio.VC.Ide.LanguageService.Resources","Microsoft.VisualStudio.Component.VC.DiagnosticTools","Microsoft.VisualCpp.MFC.Redist.X64","Microsoft.VisualStudio.PackageGroup.TestTools.Native","Microsoft.VisualStudio.Graphics.Viewers.Resources","Microsoft.VisualCpp.MFC.MBCS","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Component.TextTemplating","Win10SDK_10.0.17763","Microsoft.VisualStudio.VC.Ide.Base.Resources","Microsoft.VisualCpp.MFC.MBCS.X64","Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage","Microsoft.VisualStudio.Graphics.EnableTools","Microsoft.VisualStudio.Graphics.Appid.Resources","Microsoft.VisualStudio.VC.MSBuild.Base","Microsoft.VisualStudio.VC.MSBuild.ARM","Microsoft.VisualCpp.MFC.Headers","Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop","Microsoft.VisualCpp.Tools.HostX86.TargetX86","Microsoft.VisualStudio.VC.Ide.Base","Microsoft.VisualStudio.Graphics.Analyzer.Targeted","Microsoft.VisualCpp.CRT.Headers","Microsoft.DiagnosticsHub.Runtime.Targeted","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86","Microsoft.VisualCpp.Tools.HostX64.TargetARM64","Microsoft.VisualCpp.VCTip.hostX64.targetARM64","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86.Resources","Microsoft.Icecap.Collection.Msi","Microsoft.VisualCpp.ATL.X86","Microsoft.VisualCpp.Tools.HostX64.TargetARM64.Resources","Microsoft.VisualStudio.Component.VC.ATLMFC","Microsoft.VisualCpp.VCTip.hostX86.targetX86","Microsoft.Icecap.Collection.Msi.Resources.Targeted","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86","Microsoft.VisualStudio.Component.Graphics.Tools","Microsoft.VisualStudio.WebTools.Resources","Microsoft.VisualCpp.ATL.X64","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86.Resources","Microsoft.VisualStudio.Component.Graphics.Win81","Microsoft.VisualStudio.VC.Ide.MDD","Microsoft.VisualStudio.VC.Ide.ResourceEditor","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64","Microsoft.Icecap.Analysis.Resources.Targeted","Microsoft.VisualStudio.Debugger.Script.Msi","Microsoft.VisualStudio.Component.VC.CoreIde","Microsoft.VisualStudio.VC.Ide.MFC.Resources","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.PackageGroup.VC.Tools.x86","Microsoft.VisualStudio.TextTemplating.Core","Microsoft.VisualStudio.JavaScript.LanguageService","Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources","Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources","Microsoft.VisualStudio.Component.VC.TestAdapterForBoostTest","Microsoft.VisualStudio.VC.Ide.ProjectSystem","Microsoft.VisualStudio.VC.Ide.Dskx","Microsoft.VisualCpp.Tools.HostX86.TargetX86.Resources","Microsoft.CredentialProvider","Microsoft.VisualStudio.VC.Templates.Desktop","Microsoft.VisualStudio.VC.Ide.Pro.Resources","Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core","Microsoft.VisualStudio.TextTemplating.Integration","Microsoft.VisualStudio.Component.NuGet","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced","Microsoft.VisualCpp.PGO.Headers","Microsoft.DiagnosticsHub.Collection","Microsoft.Icecap.Collection.Msi.Targeted","Microsoft.VisualStudio.VC.Ide.LanguageService","Microsoft.VisualStudio.WebTools.WSP.FSA","Microsoft.VisualStudio.Graphics.Msi","Microsoft.VisualCpp.CRT.Redist.X86","Microsoft.VisualStudio.Branding.Community","Microsoft.VisualStudio.VC.Ide.x64","Microsoft.VisualStudio.WebToolsExtensions.Common","Microsoft.VisualStudio.WebTools.MSBuild","Microsoft.VisualStudio.NuGet.Core","Microsoft.DiagnosticsHub.Collection.Service","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources","Microsoft.CodeAnalysis.ExpressionEvaluator","Microsoft.VisualCpp.CRT.Redist.X64","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VS.VC.MSBuild.X64.Resources","Microsoft.VisualCpp.CRT.Source","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips.Resources","Microsoft.VisualStudio.VC.Ide.WinXPlus","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.Redist.14.Latest","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64","Microsoft.VisualCpp.CRT.Redist.Resources","Microsoft.VisualCpp.Redist.14.Latest","Microsoft.Net.4.TargetingPack","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualCpp.CRT.x64.Store","Microsoft.VisualStudio.VC.Ide.Debugger.Resources","Microsoft.DiaSymReader.Native","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.Redist.14","Microsoft.VisualStudio.StaticAnalysis","Microsoft.VisualStudio.TestTools.TeamFoundationClient","Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI","Microsoft.VisualStudio.VC.Ide.Common","Microsoft.VisualStudio.Community.Extra.Resources","Microsoft.VisualStudio.Component.Roslyn.LanguageServices","Microsoft.DiagnosticsHub.Collection.StopService.Install","Microsoft.VisualStudio.InteractiveWindow","Microsoft.PackageGroup.DiagnosticsHub.Platform","Microsoft.VisualStudio.StaticAnalysis.Resources","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.VC.Ide.Common.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX86","Microsoft.VisualStudio.VC.DevCmd","Microsoft.VisualStudio.Community.Extra","Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Msi","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.TestTools","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Resources","Microsoft.VisualStudio.PackageGroup.TestTools.Core","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V1.CLI","Microsoft.VisualStudio.Component.VC.Tools.x86.x64","Microsoft.VisualStudio.TestTools.Pex.Common","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.Legacy","Microsoft.VisualStudio.PackageGroup.MinShell.Interop","Microsoft.CodeAnalysis.ExpressionEvaluator.Resources","Microsoft.VisualCpp.CodeAnalysis.Extensions","Microsoft.VisualStudio.PackageGroup.CoreEditor","Microsoft.VisualStudio.Component.Roslyn.Compiler","Microsoft.VisualStudio.ScriptedHost.Targeted","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Professional","Microsoft.VisualStudio.Debugger.Resources","Microsoft.VisualStudio.Debugger.Parallel","Microsoft.VisualStudio.Debugger.Parallel.Resources","Microsoft.VisualCpp.PGO.X64","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE","Microsoft.VisualStudio.GraphModel","Microsoft.VisualStudio.PackageGroup.TestTools.DataCollectors","sqlsysclrtypes","Microsoft.VisualStudio.ProTools","Component.Microsoft.VisualStudio.RazorExtension","Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI","Microsoft.Build.Dependencies","Microsoft.VisualStudio.WebTools.WSP.FSA.Resources","Microsoft.VisualStudio.Component.Static.Analysis.Tools","Microsoft.VisualStudio.VC.Ide.ATL.Resources","Microsoft.VisualStudio.VC.Templates.UnitTest.Resources","Microsoft.VisualStudio.Debugger.Managed","Microsoft.VisualStudio.Workload.NativeDesktop","Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest","Microsoft.VisualStudio.Debugger.JustInTime.Msi","Microsoft.Net.PackageGroup.4.6.1.Redist","Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost","sqlsysclrtypes","Microsoft.VisualStudio.Debugger.Managed.Resources","Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Common","Microsoft.VisualStudio.VC.Ide.Debugger","Microsoft.VisualStudio.AppResponsiveness","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.TestTools.TestWIExtension","Microsoft.VisualStudio.VC.Ide.Pro","Microsoft.VisualStudio.PackageGroup.Debugger.Core","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express","Microsoft.VisualStudio.WebTools","Microsoft.VisualStudio.Component.VC.Redist.14.Latest","Microsoft.VisualStudio.VsDevCmd.Core.WinSdk","Microsoft.VisualStudio.TestTools.TestPlatform.IDE","Microsoft.VisualStudio.TextTemplating.Integration.Resources","Microsoft.VisualStudio.Debugger.CollectionAgents","Microsoft.VisualStudio.Debugger","Microsoft.VisualStudio.PackageGroup.Debugger.Script","Microsoft.VisualStudio.VC.MSVCDis","Microsoft.VisualStudio.ScriptedHost","Microsoft.VisualStudio.ClientDiagnostics.Targeted","Microsoft.VisualStudio.ScriptedHost.Resources","Microsoft.TeamFoundation.OfficeIntegration.Resources","Microsoft.IntelliTrace.DiagnosticsHub","Microsoft.VisualStudio.JavaScript.LanguageService.Resources","Microsoft.VisualStudio.VC.Ide.TestAdapterForGoogleTest","Microsoft.VisualStudio.PackageGroup.Community","Microsoft.VisualStudio.ClientDiagnostics","Microsoft.VisualStudio.Component.Windows10SDK.17134","Microsoft.VisualStudio.PackageGroup.Core","PortableFacades","Microsoft.DiaSymReader","Microsoft.DiagnosticsHub.Runtime","Microsoft.VisualStudio.Component.CoreEditor","Microsoft.VisualStudio.AppResponsiveness.Targeted","Microsoft.VisualStudio.AppResponsiveness.Resources","Microsoft.VisualStudio.Community","Microsoft.TeamFoundation.OfficeIntegration","Microsoft.VisualStudio.WebSiteProject.DTE","Microsoft.VisualStudio.ClientDiagnostics.Resources","Microsoft.VisualStudio.ProjectSystem.Full","Microsoft.VisualStudio.ProjectSystem","Microsoft.VisualCpp.Tools.Common.UtilsPrereq","Microsoft.IntelliTrace.CollectorCab","Microsoft.VisualStudio.Community.Resources","Microsoft.VisualCpp.Tools.Common.Utils","Microsoft.ServiceHub","Microsoft.VisualStudio.Editors","Microsoft.VisualStudio.TeamExplorer","Microsoft.CodeAnalysis.VisualStudio.InteractiveComponents.Resources","Microsoft.VisualStudio.MinShell.Interop.Msi","Microsoft.VisualStudio.GraphProvider","Microsoft.CodeAnalysis.VisualStudio.InteractiveComponents","Microsoft.CodeAnalysis.VisualStudio.Setup.Interactive.Resources","Microsoft.CodeAnalysis.VisualStudio.Setup.Resources","Microsoft.VisualStudio.Community.x86","Microsoft.VisualStudio.Community.x64","Microsoft.CodeAnalysis.VisualStudio.Setup","Microsoft.NuGet.Build.Tasks","Microsoft.PackageGroup.ClientDiagnostics","Microsoft.CodeAnalysis.Compilers.Resources","Microsoft.CodeAnalysis.Compilers","Microsoft.VisualCpp.Tools.Common.Utils.Resources","Microsoft.VisualStudio.Net.Eula.Resources","Microsoft.VisualStudio.PackageGroup.CommunityCore","Microsoft.Build","Microsoft.VisualStudio.VC.Ide.TestAdapterForBoostTest","Microsoft.VisualStudio.VC.Ide.ATL","Microsoft.VisualStudio.TextMateGrammars","Microsoft.VisualStudio.Workload.CoreEditor","Microsoft.VisualStudio.MinShell.Interop","Microsoft.Build.FileTracker.Msi","Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core","Microsoft.MSHtml","Microsoft.VisualStudio.Community.Msi.Resources","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips","Microsoft.VisualStudio.Devenv.Msi","Microsoft.VisualStudio.Component.VC.ATL","Microsoft.VisualStudio.VC.Templates.Pro","Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop","Microsoft.VisualStudio.SLNX.VSIX","Microsoft.VisualStudio.CoreEditor","Win10SDK_10.0.17134","Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk","Microsoft.VisualStudio.Component.Debugger.JustInTime","Microsoft.VisualStudio.VC.Ide.MFC","Microsoft.VisualStudio.VsDevCmd.Core.DotNet","Microsoft.VisualStudio.PackageGroup.VsDevCmd","Microsoft.VisualStudio.Finalizer","Microsoft.VisualStudio.VirtualTree","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.ProjectServices","Microsoft.VisualStudio.VC.DevCmd.Resources","Microsoft.VisualStudio.MinShell","Microsoft.VisualStudio.PackageGroup.Progression","Microsoft.VisualStudio.PerformanceProvider","Microsoft.VisualStudio.Connected.Resources","Microsoft.VisualStudio.Log","Microsoft.VisualStudio.PackageGroup.TeamExplorer","Microsoft.VisualStudio.Log.Targeted","Microsoft.VisualStudio.MinShell.Platform","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.VC.Templates.Pro.Resources","Microsoft.VisualStudio.Devenv","Microsoft.VisualCpp.VCTip.hostX86.targetX64","Microsoft.VisualStudio.Devenv.Resources","Microsoft.VisualStudio.MinShell.Platform.Resources","Microsoft.VisualStudio.Connected","Microsoft.VisualStudio.MefHosting","Microsoft.DiagnosticsHub.Collection.StopService.Uninstall","Microsoft.VisualStudio.PackageGroup.MinShell","Microsoft.VisualStudio.MefHosting.Resources","Microsoft.VisualCpp.MFC.X86","Microsoft.VisualStudio.Log.Resources","Microsoft.Icecap.Analysis.Targeted","Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.PGO.X86","Microsoft.VisualStudio.ExtensionManager","Microsoft.VisualStudio.MinShell.x86","Microsoft.VisualStudio.MinShell.Msi","Microsoft.VisualStudio.Setup.Configuration","Microsoft.VisualStudio.LanguageServer","Microsoft.VisualStudio.NativeImageSupport","Microsoft.VisualStudio.MinShell.Msi.Resources","Microsoft.VisualStudio.Devenv.Config","Microsoft.VisualStudio.MinShell.Resources","Microsoft.VisualStudio.Initializer","Microsoft.Net.PackageGroup.4.6.Redist"]}]
================================================
FILE: test/fixtures/VS_2017_Express.txt
================================================
[{"path":"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\WDExpress","version":"15.9.28307.858","packages":["Microsoft.VisualStudio.Product.WDExpress","Microsoft.VisualStudio.Workload.WDExpress","Microsoft.VisualStudio.Component.Windows10SDK.17763","MLGen","Win10SDK_10.0.17763","Microsoft.VisualStudio.Component.Windows10SDK.14393","Win10SDK_10.0.14393.795","Microsoft.VisualStudio.VC.Items.Pro","Microsoft.VisualStudio.VC.Ide.Pro","Microsoft.VisualStudio.VC.Ide.Pro.Resources","Microsoft.VisualStudio.Component.VC.Tools.ARM64","Microsoft.VisualStudio.VC.MSBuild.Arm64","Microsoft.VisualCpp.CRT.Redist.ARM64.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.ARM64","Microsoft.VisualCpp.CRT.ARM64.OneCore.Desktop","Microsoft.VisualCpp.CRT.ARM64.Store","Microsoft.VisualCpp.CRT.ARM64.Desktop","Microsoft.VisualCpp.Tools.Hostx86.Targetarm64","Microsoft.VisualCpp.VCTip.hostX86.targetARM64","Microsoft.VisualCpp.Tools.HostX86.TargetARM64.Resources","Microsoft.VisualStudio.Component.VC.Tools.ARM","Microsoft.VisualCpp.Tools.Hostx86.Targetarm","Microsoft.VisualCpp.VCTip.hostX86.targetARM","Microsoft.VisualCpp.Tools.HostX86.TargetARM.Resources","Microsoft.VisualCpp.CRT.x86.Store","Microsoft.VisualCpp.CRT.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.x64.Store","Microsoft.VisualCpp.CRT.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.arm.OneCore.Desktop","Microsoft.VisualCpp.CRT.arm.OneCore.Desktop","Microsoft.VisualCpp.CRT.arm.Store","Microsoft.VisualCpp.CRT.arm.Desktop","Microsoft.VisualStudio.VC.Templates.UnitTest","Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP","Microsoft.VisualStudio.VC.Templates.UnitTest.Resources","Microsoft.VisualStudio.VC.Templates.Desktop","Microsoft.VisualStudio.VC.Templates.Pro","Microsoft.VisualStudio.VC.Templates.Pro.Resources","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express","Microsoft.VisualStudio.PackageGroup.Debugger.Script","Microsoft.VisualStudio.JavaScript.LanguageService","Microsoft.VisualStudio.JavaScript.LanguageService.Resources","Microsoft.VisualStudio.Debugger.Script.Msi","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.VC.MSBuild.X64","Microsoft.VS.VC.MSBuild.X64.Resources","Microsoft.VisualStudio.VC.MSBuild.ARM","Microsoft.VisualStudio.VC.MSBuild.X86","Microsoft.VisualStudio.VC.MSBuild.Base","Microsoft.VisualStudio.VC.MSBuild.Base.Resources","Microsoft.VisualStudio.VC.Ide.WinXPlus","Microsoft.VisualStudio.VC.Ide.Dskx","Microsoft.VisualStudio.VC.Ide.Dskx.Resources","Microsoft.VisualStudio.VC.Ide.Core","Microsoft.VisualStudio.VC.Ide.Core.Resources","Microsoft.VisualStudio.VC.Ide.Base","Microsoft.VisualStudio.VC.Ide.Base.Resources","Microsoft.VisualStudio.Component.VC.CLI.Support","Microsoft.VisualCpp.CLI.X86","Microsoft.VisualCpp.CLI.X64","Microsoft.VisualCpp.CLI.Source","Microsoft.VisualCpp.CLI.ARM64","Microsoft.VisualCpp.CLI.ARM","Microsoft.VisualStudio.VC.Templates.CLR","Microsoft.VisualStudio.VC.Ide.LanguageService","Microsoft.VisualStudio.VC.Ide.ResourceEditor","Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources","Microsoft.VisualStudio.VC.Ide.ProjectSystem","Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources","Microsoft.VisualStudio.VC.Ide.LanguageService.Resources","Microsoft.VisualStudio.VC.Templates.CLR.Resources","Microsoft.Component.VC.Runtime.OSSupport","Microsoft.Windows.UniversalCRT.Tools.Msi","Microsoft.Windows.UniversalCRT.Tools.Msi","Microsoft.Windows.UniversalCRT.ExtensionSDK.Msi","Microsoft.Windows.UniversalCRT.HeadersLibsSources.Msi","Microsoft.VisualStudio.PackageGroup.VC.Tools.x86","Microsoft.VisualCpp.Tools.HostX86.TargetX64","Microsoft.VisualCpp.VCTip.hostX86.targetX64","Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Tools.HostX86.TargetX86","Microsoft.VisualCpp.VCTip.hostX86.targetX86","Microsoft.VisualCpp.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Tools.Core.Resources","Microsoft.VisualCpp.Tools.Core.x86","Microsoft.VisualCpp.Tools.Common.Utils","Microsoft.VisualCpp.Tools.Common.Utils.Resources","Microsoft.VisualCpp.DIA.SDK","Microsoft.VisualCpp.CRT.x86.Desktop","Microsoft.VisualCpp.CRT.x64.Desktop","Microsoft.VisualCpp.CRT.Source","Microsoft.VisualCpp.CRT.Redist.X86","Microsoft.VisualCpp.CRT.Redist.X64","Microsoft.VisualCpp.CRT.Redist.Resources","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.CRT.Headers","Microsoft.Component.HelpViewer","Microsoft.HelpViewer","Microsoft.VisualStudio.Help.Configuration.Msi","Microsoft.VisualStudio.Component.SQL.DataSources","Microsoft.VisualStudio.Component.SQL.SSDT","Microsoft.VisualStudio.Component.SQL.CMDUtils","sqlcmdlnutils","Microsoft.VisualStudio.Component.Common.Azure.Tools","Microsoft.VisualStudio.Azure.CommonAzureTools","SSDT","Microsoft.VisualStudio.Component.SQL.ADAL","sql_adalsql","Microsoft.VisualStudio.Component.NuGet","Microsoft.CredentialProvider","Microsoft.VisualStudio.NuGet.Licenses","Microsoft.VisualStudio.Component.SQL.LocalDB.Runtime","Microsoft.VisualStudio.Component.SQL.NCLI","sqllocaldb","sqlncli","Microsoft.VisualStudio.Component.EntityFramework","Microsoft.VisualStudio.PackageGroup.DslRuntime","Microsoft.VisualStudio.Dsl.Core","Microsoft.VisualStudio.Dsl.GraphObject","Microsoft.VisualStudio.Dsl.Core.Resources","Microsoft.VisualStudio.EntityFrameworkTools","Microsoft.VisualStudio.EntityFrameworkTools.Msi","Microsoft.VisualStudio.Component.Roslyn.LanguageServices","Microsoft.VisualStudio.InteractiveWindow","Microsoft.DiaSymReader.Native","Microsoft.VisualStudio.Component.Static.Analysis.Tools","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.Redist.14","Microsoft.VisualStudio.StaticAnalysis","Microsoft.VisualStudio.StaticAnalysis.Resources","Microsoft.CodeAnalysis.VisualStudio.InteractiveComponents.Resources","Microsoft.CodeAnalysis.VisualStudio.InteractiveComponents","Microsoft.CodeAnalysis.VisualStudio.Setup.Interactive.Resources","Microsoft.Net.ComponentGroup.TargetingPacks.Common","Microsoft.Net.Component.4.6.TargetingPack","Microsoft.Net.4.6.TargetingPack","Microsoft.Net.Component.4.5.2.TargetingPack","Microsoft.Net.4.5.2.TargetingPack","Microsoft.Net.Component.4.5.1.TargetingPack","Microsoft.Net.4.5.1.TargetingPack","Microsoft.Net.Component.4.5.TargetingPack","Microsoft.Net.4.5.TargetingPack","Microsoft.Net.Component.4.TargetingPack","Microsoft.Net.4.TargetingPack","Microsoft.Net.ComponentGroup.DevelopmentPrerequisites","Microsoft.Net.Component.4.6.1.TargetingPack","Microsoft.Net.4.6.1.TargetingPack","Microsoft.Net.Cumulative.TargetingPack.Resources","Microsoft.Net.Component.4.6.1.SDK","Microsoft.Net.4.6.1.SDK","Microsoft.VisualStudio.Component.TextTemplating","Microsoft.VisualStudio.TextTemplating.MSBuild","Microsoft.VisualStudio.TextTemplating.Integration","Microsoft.VisualStudio.TextTemplating.Core","Microsoft.VisualStudio.TextTemplating.Integration.Resources","Microsoft.VisualStudio.Component.VisualStudioData","Microsoft.VisualStudio.Component.SQL.CLR","Microsoft.VisualStudio.ProTools","sqlsysclrtypes","sqlsysclrtypes","SQLCommon","Microsoft.VisualStudio.ProTools.Resources","Microsoft.VisualStudio.XamlDiagnostics","Microsoft.VisualStudio.XamlDiagnostics.Resources","Microsoft.VisualStudio.XamlDesigner","Microsoft.VisualStudio.XamlDesigner.Resources","Microsoft.VisualStudio.XamlDesigner.Executables","Microsoft.VisualStudio.XamlShared","Microsoft.VisualStudio.XamlShared.Resources","Microsoft.VisualStudio.PackageGroup.TestTools.Managed","Microsoft.VisualStudio.PackageGroup.IntelliTrace.Core","Microsoft.IntelliTrace.Core","Microsoft.IntelliTrace.Core.Targeted","Microsoft.IntelliTrace.ProfilerProxy.Msi.x64","Microsoft.IntelliTrace.ProfilerProxy.Msi","Microsoft.VisualStudio.NuGet.Core","Microsoft.VisualStudio.TestWindow.SourceBasedTestDiscovery","Microsoft.VisualStudio.TestWindow.Dotnet","Microsoft.VisualStudio.TestTools.TestGeneration","Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage","Microsoft.VisualStudio.PackageGroup.TestTools.Enterprise","Microsoft.VisualStudio.PackageGroup.TestTools.MSTestV2.Managed","Microsoft.VisualStudio.TestTools.MSTestV2.WizardExtension.UnitTest","Microsoft.VisualStudio.PackageGroup.TestTools.Core","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI","Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V1.CLI","Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI","Microsoft.VisualStudio.TestTools.Pex.Common","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.Legacy","Microsoft.VisualStudio.PackageGroup.MinShell.Interop","Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Msi","Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Common","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips.Resources","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.TestTools","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Professional","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Common","Microsoft.VisualStudio.TestTools.TP.Legacy.Common.Res","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Resources","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Agent","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE","Microsoft.VisualStudio.TestTools.TestWIExtension","Microsoft.VisualStudio.TestTools.TestPlatform.IDE","Microsoft.VisualStudio.PackageGroup.TestTools.DataCollectors","Microsoft.Component.ClickOnce","Microsoft.VisualStudio.PackageGroup.ClickOnce.MSBuild","Microsoft.VisualCpp.CRT.ClickOnce.Msi","Microsoft.ClickOnce.SignTool.Msi","Microsoft.SQL.ClickOnceBootstrapper.Msi","Microsoft.Net.ClickOnceBootstrapper","Microsoft.ClickOnce.BootStrapper.Msi.Resources","Microsoft.ClickOnce.BootStrapper.Msi","Microsoft.VisualStudio.WebTools.WSP.FSA","Microsoft.VisualStudio.WebTools.WSP.FSA.Resources","Microsoft.VisualStudio.PackageGroup.Community","Microsoft.VisualStudio.Community.Extra.Resources","Microsoft.VisualStudio.Community.Extra","Microsoft.VisualStudio.PackageGroup.Core","Microsoft.VisualStudio.TestTools.TeamFoundationClient","Microsoft.VisualStudio.PackageGroup.Debugger.Core","Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost","Microsoft.VisualStudio.VC.Ide.Debugger","Microsoft.VisualStudio.VC.Ide.Debugger.Resources","Microsoft.VisualStudio.VC.Ide.Common","Microsoft.VisualStudio.VC.Ide.Common.Resources","Microsoft.VisualStudio.Debugger.Parallel","Microsoft.VisualStudio.Debugger.Parallel.Resources","Microsoft.VisualStudio.Debugger.CollectionAgents","Microsoft.VisualStudio.Debugger.Managed","Microsoft.CodeAnalysis.VisualStudio.Setup.Resources","Microsoft.CodeAnalysis.VisualStudio.Setup","Microsoft.CodeAnalysis.ExpressionEvaluator.Resources","Microsoft.CodeAnalysis.ExpressionEvaluator","Microsoft.VisualStudio.Debugger.Managed.Resources","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger","Microsoft.VisualStudio.VC.MSVCDis","Microsoft.VisualStudio.ScriptedHost","Microsoft.VisualStudio.ScriptedHost.Targeted","Microsoft.VisualStudio.ScriptedHost.Resources","Microsoft.IntelliTrace.DiagnosticsHub","Microsoft.VisualStudio.Debugger.Resources","Microsoft.PackageGroup.ClientDiagnostics","Microsoft.VisualStudio.AppResponsiveness","Microsoft.VisualStudio.AppResponsiveness.Targeted","Microsoft.VisualStudio.AppResponsiveness.Resources","Microsoft.VisualStudio.ClientDiagnostics","Microsoft.VisualStudio.ClientDiagnostics.Targeted","Microsoft.VisualStudio.ClientDiagnostics.Resources","Microsoft.VisualStudio.PackageGroup.CommunityCore","Microsoft.VisualStudio.ProjectSystem.Full","Microsoft.VisualStudio.ProjectSystem","Microsoft.VisualStudio.Community.x86","Microsoft.VisualStudio.Community.x64","Microsoft.VisualStudio.Community","Microsoft.IntelliTrace.CollectorCab","Microsoft.VisualStudio.Community.Resources","Microsoft.VisualStudio.Net.Eula.Resources","Microsoft.VisualStudio.WebSiteProject.DTE","Microsoft.MSHtml","Microsoft.VisualStudio.Community.Msi.Resources","Microsoft.VisualStudio.Community.Msi","Microsoft.VisualStudio.MinShell.Interop.Msi","Microsoft.VisualStudio.Editors","Microsoft.VisualStudio.ClickOnce.Resources","Microsoft.VisualStudio.ClickOnce","Microsoft.Component.MSBuild","Microsoft.NuGet.Build.Tasks","Microsoft.VisualStudio.Component.Roslyn.Compiler","Microsoft.CodeAnalysis.Compilers.Resources","Microsoft.CodeAnalysis.Compilers","Microsoft.Net.PackageGroup.4.6.1.Redist","Microsoft.VisualStudio.TemplateEngine","Microsoft.VisualStudio.WebToolsExtensions.Common","Microsoft.NET.Sdk","Microsoft.VisualStudio.PackageGroup.TestTools.Templates.Managed","Microsoft.VisualStudio.TestTools.Templates.Managed","Microsoft.VisualStudio.TestTools.Templates.Managed.Resources","Microsoft.VisualStudio.Templates.VB.MSTestv2.Desktop.UnitTest","Microsoft.VisualStudio.Templates.CS.MSTestv2.Desktop.UnitTest","Microsoft.VisualStudio.Templates.VB.Wpf","Microsoft.VisualStudio.Templates.VB.Wpf.Resources","Microsoft.VisualStudio.Templates.VB.Winforms","Microsoft.VisualStudio.Templates.VB.ManagedCore","Microsoft.VisualStudio.Templates.VB.Shared","Microsoft.VisualStudio.Templates.VB.Shared.Resources","Microsoft.VisualStudio.Templates.VB.ManagedCore.Resources","Microsoft.VisualStudio.Templates.CS.GettingStarted.Desktop.Package","Microsoft.VisualStudio.Templates.GetStarted.Desktop.Setup","Microsoft.VisualStudio.Templates.CS.GettingStarted.Console.Package","Microsoft.VisualStudio.Templates.GetStarted.Resources","Microsoft.VisualStudio.Templates.GetStarted.Common.Setup","Microsoft.VisualStudio.Templates.GetStarted.Console.Setup","Microsoft.VisualStudio.Templates.CS.Wpf","Microsoft.VisualStudio.Templates.CS.Wpf.Resources","Microsoft.VisualStudio.Templates.CS.Winforms","Microsoft.VisualStudio.Templates.CS.ManagedCore","Microsoft.VisualStudio.Templates.CS.Shared","Microsoft.VisualStudio.Templates.Editorconfig.Wizard.Setup","Templates.Editorconfig.SolutionFile.Setup","Microsoft.VisualStudio.Templates.CS.Shared.Resources","Microsoft.VisualStudio.Templates.CS.ManagedCore.Resources","Microsoft.VisualStudio.Component.CoreEditor","Microsoft.VisualStudio.PackageGroup.CoreEditor","PortableFacades","Microsoft.VisualStudio.PackageGroup.VsDevCmd","Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk","Microsoft.VisualStudio.VsDevCmd.Core.WinSdk","Microsoft.VisualStudio.VsDevCmd.Core.DotNet","Microsoft.VisualStudio.VC.DevCmd","Microsoft.VisualStudio.VC.DevCmd.Resources","Microsoft.VisualStudio.VirtualTree","Microsoft.VisualStudio.PackageGroup.Progression","Microsoft.VisualStudio.PerformanceProvider","Microsoft.VisualStudio.GraphModel","Microsoft.VisualStudio.GraphProvider","Microsoft.DiaSymReader","Microsoft.Build.Dependencies","Microsoft.Build.FileTracker.Msi","Microsoft.Build","Microsoft.VisualStudio.TextMateGrammars","Microsoft.VisualStudio.PackageGroup.TeamExplorer","Microsoft.TeamFoundation.OfficeIntegration","Microsoft.TeamFoundation.OfficeIntegration.Resources","Microsoft.VisualStudio.TeamExplorer","Microsoft.ServiceHub","Microsoft.VisualStudio.ProjectServices","Microsoft.VisualStudio.SLNX.VSIX","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.PackageGroup.MinShell","Microsoft.VisualStudio.MinShell.Interop","Microsoft.VisualStudio.Log","Microsoft.VisualStudio.Log.Targeted","Microsoft.VisualStudio.Log.Resources","Microsoft.VisualStudio.Finalizer","Microsoft.VisualStudio.WDExpress","Microsoft.VisualStudio.WDExpress.Resources","Microsoft.VisualStudio.CoreEditor","Microsoft.VisualStudio.Connected","Microsoft.VisualStudio.Connected.Resources","Microsoft.VisualStudio.MinShell","Microsoft.VisualStudio.Setup.Configuration","Microsoft.VisualStudio.MinShell.Platform","Microsoft.VisualStudio.MinShell.Platform.Resources","Microsoft.VisualStudio.MefHosting","Microsoft.VisualStudio.MefHosting.Resources","Microsoft.VisualStudio.Initializer","Microsoft.VisualStudio.ExtensionManager","Microsoft.VisualStudio.MinShell.x86","Microsoft.VisualStudio.NativeImageSupport","Microsoft.VisualStudio.MinShell.Msi","Microsoft.VisualStudio.MinShell.Msi.Resources","Microsoft.VisualStudio.LanguageServer","Microsoft.VisualStudio.MinShell.Resources","Microsoft.Net.PackageGroup.4.6.Redist","Microsoft.VisualStudio.Branding.WDExpress"]}]
================================================
FILE: test/fixtures/VS_2017_Unusable.txt
================================================
[{"path":"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildToolsUnusable","version":"15.9.28307.665","packages":["Microsoft.VisualStudio.Product.BuildTools","Microsoft.VisualStudio.Component.Windows10SDK.17134","Win10SDK_10.0.17134","Microsoft.VisualStudio.Component.VC.Tools.x86.x64","Microsoft.VisualCpp.CodeAnalysis.Extensions","Microsoft.VisualCpp.CodeAnalysis.Extensions.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86.Resources","Microsoft.VisualCpp.CodeAnalysis.Extensions.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64.Resources","Microsoft.VisualStudio.Component.Static.Analysis.Tools","Microsoft.VisualStudio.StaticAnalysis","Microsoft.VisualStudio.StaticAnalysis.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX86","Microsoft.VisualCpp.VCTip.HostX64.TargetX86","Microsoft.VisualCpp.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX64","Microsoft.VisualCpp.VCTip.HostX64.TargetX64","Microsoft.VisualCpp.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64","Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.PGO.X86","Microsoft.VisualCpp.PGO.X64","Microsoft.VisualCpp.PGO.Headers","Microsoft.VisualCpp.CRT.x86.Store","Microsoft.VisualCpp.CRT.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.x64.Store","Microsoft.VisualCpp.CRT.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.ClickOnce.Msi","Microsoft.VisualStudio.PackageGroup.VC.Tools.x86","Microsoft.VisualCpp.Tools.HostX86.TargetX64","Microsoft.VisualCpp.VCTip.hostX86.targetX64","Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Tools.HostX86.TargetX86","Microsoft.VisualCpp.VCTip.hostX86.targetX86","Microsoft.VisualCpp.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Tools.Core.Resources","Microsoft.VisualCpp.Tools.Core.x86","Microsoft.VisualCpp.Tools.Common.Utils","Microsoft.VisualCpp.Tools.Common.Utils.Resources","Microsoft.VisualCpp.DIA.SDK","Microsoft.VisualCpp.CRT.x86.Desktop","Microsoft.VisualCpp.CRT.x64.Desktop","Microsoft.VisualCpp.CRT.Source","Microsoft.VisualCpp.CRT.Redist.X86","Microsoft.VisualCpp.CRT.Redist.X64","Microsoft.VisualCpp.CRT.Redist.Resources","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.CRT.Headers","Microsoft.VisualStudio.Workload.MSBuildTools","Microsoft.VisualStudio.Component.CoreBuildTools","Microsoft.VisualStudio.Setup.Configuration","Microsoft.VisualStudio.PackageGroup.VsDevCmd","Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk","Microsoft.VisualStudio.VsDevCmd.Core.WinSdk","Microsoft.VisualStudio.VsDevCmd.Core.DotNet","Microsoft.VisualStudio.VC.DevCmd","Microsoft.VisualStudio.VC.DevCmd.Resources","Microsoft.VisualStudio.BuildTools.Resources","Microsoft.VisualStudio.Net.Eula.Resources","Microsoft.Build.Dependencies","Microsoft.Build.FileTracker.Msi","Microsoft.Component.MSBuild","Microsoft.PythonTools.BuildCore.Vsix","Microsoft.NuGet.Build.Tasks","Microsoft.VisualStudio.Component.Roslyn.Compiler","Microsoft.CodeAnalysis.Compilers.Resources","Microsoft.CodeAnalysis.Compilers","Microsoft.Net.PackageGroup.4.6.1.Redist","Microsoft.Net.4.6.1.FullRedist.NonThreshold","Microsoft.Windows.UniversalCRT.Msu.81","Microsoft.VisualStudio.NativeImageSupport","Microsoft.Build"]}]
================================================
FILE: test/fixtures/VS_2019_BuildTools_minimal.txt
================================================
[{"path":"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools","version":"16.1.28922.388","packages":["Microsoft.VisualStudio.Product.BuildTools","Microsoft.VisualStudio.Component.VC.CoreIde","Microsoft.VisualStudio.VC.Ide.Pro","Microsoft.VisualStudio.VC.Ide.Pro.Resources","Microsoft.VisualStudio.VC.Templates.Pro","Microsoft.VisualStudio.VC.Templates.Pro.Resources","Microsoft.VisualStudio.VC.Items.Pro","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced","Microsoft.VisualStudio.VC.Ide.MDD","Microsoft.VisualStudio.PackageGroup.Core","Microsoft.VisualStudio.CodeSense.Community","Microsoft.VisualStudio.TestTools.TeamFoundationClient","Microsoft.PackageGroup.ClientDiagnostics","Microsoft.VisualStudio.AppResponsiveness","Microsoft.VisualStudio.AppResponsiveness.Targeted","Microsoft.VisualStudio.AppResponsiveness.Resources","Microsoft.VisualStudio.ClientDiagnostics","Microsoft.VisualStudio.ClientDiagnostics.Targeted","Microsoft.VisualStudio.ClientDiagnostics.Resources","Microsoft.VisualStudio.PackageGroup.CommunityCore","Microsoft.VisualStudio.ProjectSystem.Full","Microsoft.VisualStudio.ProjectSystem","Microsoft.VisualStudio.Community.x86","Microsoft.VisualStudio.Community.x64","Microsoft.VisualStudio.Community","Microsoft.IntelliTrace.CollectorCab","Microsoft.VisualStudio.Community.Resources","Microsoft.VisualStudio.WebSiteProject.DTE","Microsoft.MSHtml","Microsoft.VisualStudio.Platform.CallHierarchy","Microsoft.VisualStudio.Community.Msi.Resources","Microsoft.VisualStudio.Community.Msi","Microsoft.VisualStudio.MinShell.Interop.Msi","Microsoft.VisualStudio.PackageGroup.CoreEditor","Microsoft.VisualStudio.VirtualTree","Microsoft.VisualStudio.PackageGroup.Progression","Microsoft.VisualStudio.PerformanceProvider","Microsoft.VisualStudio.GraphModel","Microsoft.VisualStudio.GraphProvider","Microsoft.VisualStudio.TextMateGrammars","Microsoft.VisualStudio.PackageGroup.TeamExplorer.Common","Microsoft.VisualStudio.TeamExplorer","Microsoft.ServiceHub","Microsoft.VisualStudio.ProjectServices","Microsoft.VisualStudio.OpenFolder.VSIX","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.PackageGroup.MinShell","Microsoft.VisualStudio.MinShell.Msi","Microsoft.VisualStudio.MinShell.Msi.Resources","Microsoft.VisualStudio.MinShell.Interop","Microsoft.VisualStudio.Log","Microsoft.VisualStudio.Log.Targeted","Microsoft.VisualStudio.Log.Resources","Microsoft.VisualStudio.Finalizer","Microsoft.VisualStudio.CoreEditor","Microsoft.VisualStudio.Platform.NavigateTo","Microsoft.VisualStudio.Connected","Microsoft.VisualStudio.Connected.Resources","Microsoft.VisualStudio.VC.Ide.x64","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express","Microsoft.VisualStudio.PackageGroup.Debugger.Script","Microsoft.VisualStudio.Debugger.Script.Msi","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.VC.Ide.WinXPlus","Microsoft.VisualStudio.VC.Ide.Dskx","Microsoft.VisualStudio.VC.Ide.Dskx.Resources","Microsoft.VisualStudio.VC.Ide.Base","Microsoft.VisualStudio.VC.Ide.LanguageService","Microsoft.VisualStudio.VC.Ide.Core","Microsoft.VisualStudio.VisualC.Logging","Microsoft.VisualStudio.VC.Ide.Core.Resources","Microsoft.VisualStudio.VC.Ide.VCPkgDatabase","Microsoft.VisualStudio.VC.Ide.ResourceEditor","Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources","Microsoft.VisualStudio.VC.Ide.ProjectSystem","Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources","Microsoft.VisualStudio.VC.Ide.LanguageService.Resources","Microsoft.VisualStudio.VC.Ide.Base.Resources","Microsoft.Net.4.TargetingPack","Microsoft.VisualStudio.PackageGroup.Debugger.Core","Microsoft.VisualStudio.PackageGroup.Debugger.TimeTravel.Record","Microsoft.VisualStudio.Debugger.TimeTravel.Runtime","Microsoft.VisualStudio.Debugger.TimeTravel.Runtime","Microsoft.VisualStudio.Debugger.TimeTravel.Agent","Microsoft.VisualStudio.Debugger.TimeTravel.Record","Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost","Microsoft.VisualStudio.VC.Ide.Debugger","Microsoft.VisualStudio.VC.Ide.Debugger.Concord","Microsoft.VisualStudio.VC.Ide.Debugger.Concord.Resources","Microsoft.VisualStudio.VC.Ide.Debugger.Resources","Microsoft.VisualStudio.VC.Ide.Common","Microsoft.VisualStudio.VC.Ide.Common.Resources","Microsoft.VisualStudio.Debugger.Parallel","Microsoft.VisualStudio.Debugger.Parallel.Resources","Microsoft.VisualStudio.Debugger.CollectionAgents","Microsoft.VisualStudio.Debugger.Managed","Microsoft.DiaSymReader","Microsoft.CodeAnalysis.ExpressionEvaluator","Microsoft.VisualStudio.Debugger.Concord.Managed","Microsoft.VisualStudio.Debugger.Concord.Managed.Resources","Microsoft.VisualStudio.Debugger.Managed.Resources","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger","Microsoft.VisualStudio.PerfLib","Microsoft.VisualStudio.Debugger.Package.DiagHub.Client.VSx86","Microsoft.VisualStudio.Debugger.Remote.DiagHub.Client","Microsoft.VisualStudio.Debugger.Remote.DiagHub.Client","Microsoft.VisualStudio.VC.MSVCDis","Microsoft.VisualStudio.ScriptedHost","Microsoft.VisualStudio.ScriptedHost.Targeted","Microsoft.VisualStudio.ScriptedHost.Resources","Microsoft.VisualStudio.Editors","Microsoft.IntelliTrace.DiagnosticsHub","Microsoft.VisualStudio.MinShell","Microsoft.VisualStudio.MinShell.Platform","Microsoft.VisualStudio.MinShell.Platform.Resources","Microsoft.VisualStudio.MefHosting","Microsoft.VisualStudio.MefHosting.Resources","Microsoft.VisualStudio.Initializer","Microsoft.VisualStudio.ExtensionManager","Microsoft.VisualStudio.Platform.Editor","Microsoft.VisualStudio.Debugger.Concord","Microsoft.VisualStudio.Debugger.Concord.Resources","Microsoft.VisualStudio.Debugger.Resources","Microsoft.CodeAnalysis.VisualStudio.Setup","Microsoft.VisualStudio.Component.Windows10SDK.17134","Win10SDK_10.0.17134","Microsoft.VisualStudio.Component.VC.Tools.x86.x64","Microsoft.VisualCpp.CodeAnalysis.Extensions","Microsoft.VisualCpp.CodeAnalysis.Extensions.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86.Resources","Microsoft.VisualCpp.CodeAnalysis.Extensions.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64.Resources","Microsoft.VisualStudio.StaticAnalysis","Microsoft.VisualStudio.StaticAnalysis.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX86","Microsoft.VisualCpp.VCTip.HostX64.TargetX86","Microsoft.VisualCpp.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX64","Microsoft.VisualCpp.VCTip.HostX64.TargetX64","Microsoft.VisualCpp.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64","Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.PGO.X86","Microsoft.VisualCpp.PGO.X64","Microsoft.VisualCpp.PGO.Headers","Microsoft.VisualCpp.CRT.x86.Store","Microsoft.VisualCpp.CRT.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.x64.Store","Microsoft.VisualCpp.CRT.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.ClickOnce.Msi","Microsoft.VisualStudio.PackageGroup.VC.Tools.x86","Microsoft.VisualCpp.Tools.HostX86.TargetX64","Microsoft.VisualCpp.VCTip.hostX86.targetX64","Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Tools.HostX86.TargetX86","Microsoft.VisualCpp.VCTip.hostX86.targetX86","Microsoft.VisualCpp.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Tools.Core.Resources","Microsoft.VisualCpp.Tools.Core.x86","Microsoft.VisualCpp.Tools.Common.Utils","Microsoft.VisualCpp.Tools.Common.Utils.Resources","Microsoft.VisualCpp.DIA.SDK","Microsoft.VisualCpp.CRT.x86.Desktop","Microsoft.VisualCpp.CRT.x64.Desktop","Microsoft.VisualCpp.CRT.Source","Microsoft.VisualCpp.CRT.Redist.X86","Microsoft.VisualCpp.CRT.Redist.X64","Microsoft.VisualCpp.CRT.Redist.Resources","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.Redist.14.Latest","Microsoft.VisualCpp.Redist.14.Latest","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.CRT.Headers","Microsoft.VisualStudio.VC.MSBuild.x86.v142","Microsoft.VisualStudio.VC.MSBuild.X86","Microsoft.VisualStudio.VC.MSBuild.X64.v142","Microsoft.VisualStudio.VC.MSBuild.X64","Microsoft.VS.VC.MSBuild.X64.Resources","Microsoft.VisualStudio.VC.MSBuild.ARM.v142","Microsoft.VisualStudio.VC.MSBuild.ARM","Microsoft.VisualStudio.VC.MSBuild.Base","Microsoft.VisualStudio.VC.MSBuild.Base.Resources","Microsoft.VisualStudio.Workload.MSBuildTools","Microsoft.VisualStudio.Component.CoreBuildTools","Microsoft.VisualStudio.Setup.Configuration","Microsoft.VisualStudio.PackageGroup.VsDevCmd","Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk","Microsoft.VisualStudio.VsDevCmd.Core.WinSdk","Microsoft.VisualStudio.VsDevCmd.Core.DotNet","Microsoft.VisualStudio.VC.DevCmd","Microsoft.VisualStudio.VC.DevCmd.Resources","Microsoft.VisualStudio.BuildTools.Resources","Microsoft.VisualStudio.Net.Eula.Resources","Microsoft.Build.Dependencies","Microsoft.Build.FileTracker.Msi","Microsoft.Component.MSBuild","Microsoft.PythonTools.BuildCore.Vsix","Microsoft.NuGet.Build.Tasks","Microsoft.VisualStudio.Component.Roslyn.Compiler","Microsoft.CodeAnalysis.Compilers","Microsoft.Net.PackageGroup.4.7.2.Redist","Microsoft.VisualStudio.NativeImageSupport","Microsoft.Build","Microsoft.VisualStudio.PackageGroup.NuGet","Microsoft.VisualStudio.NuGet.BuildTools"]}]
================================================
FILE: test/fixtures/VS_2019_Community_workload.txt
================================================
[{"path":"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community","version":"16.1.28922.388","packages":["Microsoft.VisualStudio.Workload.NativeDesktop","Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest","Microsoft.VisualStudio.VC.Ide.TestAdapterForGoogleTest","Microsoft.VisualStudio.Component.VC.TestAdapterForBoostTest","Microsoft.VisualStudio.VC.Ide.TestAdapterForBoostTest","Microsoft.VisualStudio.Component.VC.ATL","Microsoft.VisualStudio.VC.Ide.ATL","Microsoft.VisualStudio.VC.Ide.ATL.Resources","Microsoft.VisualCpp.ATL.X86","Microsoft.VisualCpp.ATL.X64","Microsoft.VisualCpp.ATL.Source","Microsoft.VisualCpp.ATL.Headers","Microsoft.VisualStudio.Component.VC.CMake.Project","Microsoft.VisualStudio.VC.CMake","Microsoft.VisualStudio.VC.CMake.Project","Microsoft.VisualStudio.VC.ExternalBuildFramework","Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core","Microsoft.VisualStudio.PackageGroup.TestTools.Native","Microsoft.VisualStudio.Component.VC.Redist.14.Latest","Microsoft.VisualStudio.VC.Templates.UnitTest","Microsoft.VisualStudio.VC.UnitTest.Desktop.Build.Core","Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP","Microsoft.VisualStudio.VC.Templates.UnitTest.Resources","Microsoft.VisualStudio.VC.Templates.Desktop","Microsoft.VisualStudio.Component.Debugger.JustInTime","Microsoft.VisualStudio.Debugger.ImmersiveActivateHelper.Msi","Microsoft.VisualStudio.Debugger.JustInTime","Microsoft.VisualStudio.Debugger.JustInTime.Msi","Microsoft.VisualStudio.Component.Windows10SDK.17763","Win10SDK_10.0.17763","Microsoft.VisualStudio.Component.VC.DiagnosticTools","Microsoft.VisualStudio.Component.Graphics.Tools","Microsoft.VisualStudio.Component.VC.Tools.x86.x64","Microsoft.VisualCpp.CodeAnalysis.Extensions","Microsoft.VisualCpp.CodeAnalysis.Extensions.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86.Resources","Microsoft.VisualCpp.CodeAnalysis.Extensions.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX86","Microsoft.VisualCpp.VCTip.HostX64.TargetX86","Microsoft.VisualCpp.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX64","Microsoft.VisualCpp.VCTip.HostX64.TargetX64","Microsoft.VisualCpp.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64","Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.PGO.X86","Microsoft.VisualCpp.PGO.X64","Microsoft.VisualCpp.PGO.Headers","Microsoft.VisualCpp.CRT.x86.Store","Microsoft.VisualCpp.CRT.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.x64.Store","Microsoft.VisualCpp.CRT.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop","Microsoft.VisualStudio.PackageGroup.VC.Tools.x86","Microsoft.VisualCpp.Tools.HostX86.TargetX64","Microsoft.VisualCpp.VCTip.hostX86.targetX64","Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Tools.HostX86.TargetX86","Microsoft.VisualCpp.VCTip.hostX86.targetX86","Microsoft.VisualCpp.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Tools.Core.Resources","Microsoft.VisualCpp.Tools.Core.x86","Microsoft.VisualCpp.DIA.SDK","Microsoft.VisualCpp.CRT.x86.Desktop","Microsoft.VisualCpp.CRT.x64.Desktop","Microsoft.VisualCpp.CRT.Source","Microsoft.VisualCpp.CRT.Redist.X86","Microsoft.VisualCpp.CRT.Redist.X64","Microsoft.VisualCpp.CRT.Redist.Resources","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.Redist.14.Latest","Microsoft.VisualCpp.Redist.14.Latest","Microsoft.VisualCpp.CRT.Headers","Microsoft.VisualStudio.Graphics.Viewers","Microsoft.VisualStudio.Graphics.Viewers.Resources","Microsoft.VisualStudio.Graphics.Msi","Microsoft.VisualStudio.Graphics.Msi","Microsoft.VisualStudio.Graphics.Analyzer","Microsoft.VisualStudio.Graphics.Analyzer.Targeted","Microsoft.VisualStudio.Graphics.Analyzer.Resources","Microsoft.VisualStudio.Graphics.Appid","Microsoft.VisualStudio.Graphics.Appid.Resources","Microsoft.VisualStudio.Component.VC.CoreIde","Microsoft.VisualStudio.VC.Ide.Pro","Microsoft.VisualStudio.VC.Ide.Pro.Resources","Microsoft.VisualStudio.VC.Templates.Pro","Microsoft.VisualStudio.VC.Templates.Pro.Resources","Microsoft.VisualStudio.VC.Items.Pro","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced","Microsoft.VisualStudio.VC.Ide.x64","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express","Microsoft.VisualStudio.VC.MSBuild.X64.v142","Microsoft.VisualStudio.VC.MSBuild.X64","Microsoft.VS.VC.MSBuild.X64.Resources","Microsoft.VisualStudio.VC.MSBuild.ARM.v142","Microsoft.VisualStudio.VC.MSBuild.ARM","Microsoft.VisualStudio.VC.MSBuild.x86.v142","Microsoft.VisualStudio.VC.MSBuild.X86","Microsoft.VisualStudio.VC.MSBuild.Base","Microsoft.VisualStudio.VC.MSBuild.Base.Resources","Microsoft.VisualStudio.VC.Ide.WinXPlus","Microsoft.VisualStudio.VC.Ide.Dskx","Microsoft.VisualStudio.VC.Ide.Dskx.Resources","Microsoft.VisualStudio.VC.Ide.Base","Microsoft.VisualStudio.VC.Ide.LanguageService","Microsoft.VisualStudio.VC.Ide.Core","Microsoft.VisualStudio.VC.Ide.Core.Resources","Microsoft.VisualStudio.VC.Ide.VCPkgDatabase","Microsoft.VisualStudio.VC.Ide.ProjectSystem","Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources","Microsoft.VisualStudio.VC.Ide.LanguageService.Resources","Microsoft.VisualStudio.VC.Ide.Base.Resources","Component.Microsoft.VisualStudio.LiveShare","Microsoft.VisualStudio.LiveShare","Microsoft.Icecap.Analysis","Microsoft.Icecap.Analysis.Targeted","Microsoft.Icecap.Analysis.Resources","Microsoft.Icecap.Analysis.Resources.Targeted","Microsoft.Icecap.Collection.Msi","Microsoft.Icecap.Collection.Msi.Targeted","Microsoft.Icecap.Collection.Msi.Resources","Microsoft.Icecap.Collection.Msi.Resources.Targeted","Microsoft.DiagnosticsHub.Instrumentation","Microsoft.DiagnosticsHub.CpuSampling.ExternalDependencies","Microsoft.DiagnosticsHub.CpuSampling","Microsoft.DiagnosticsHub.CpuSampling.Targeted","Microsoft.PackageGroup.DiagnosticsHub.Platform","Microsoft.DiagnosticsHub.Runtime.ExternalDependencies","Microsoft.DiagnosticsHub.Runtime.ExternalDependencies.Targeted","Microsoft.DiagnosticsHub.Collection.ExternalDependencies.x64","Microsoft.DiagnosticsHub.Collection.StopService.Uninstall","Microsoft.DiagnosticsHub.Runtime","Microsoft.DiagnosticsHub.Runtime.Targeted","Microsoft.DiagnosticsHub.Collection","Microsoft.DiagnosticsHub.Collection.Service","Microsoft.DiagnosticsHub.Collection.StopService.Install","Microsoft.VisualStudio.Component.IntelliCode","Microsoft.VisualStudio.IntelliCode","Microsoft.Net.4.TargetingPack","Microsoft.VisualStudio.VC.Ide.ResourceEditor","Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources","Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage","Microsoft.VisualStudio.PackageGroup.TestTools.Core","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI","Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V1.CLI","Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI","Microsoft.VisualStudio.TestTools.Pex.Common","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.Legacy","Microsoft.VisualStudio.PackageGroup.MinShell.Interop","Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Msi","Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Common","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips.Resources","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.TestTools","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Professional","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Common","Microsoft.VisualStudio.TestTools.TP.Legacy.Common.Res","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Resources","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Agent","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE","Microsoft.VisualStudio.TestTools.TestWIExtension","Microsoft.VisualStudio.TestTools.TestPlatform.IDE","Microsoft.VisualStudio.PackageGroup.TestTools.DataCollectors","Microsoft.VisualStudio.LiveShareApi","Microsoft.VisualStudio.Component.TextTemplating","Microsoft.VisualStudio.TextTemplating.MSBuild","Microsoft.VisualStudio.TextTemplating.Integration","Microsoft.VisualStudio.TextTemplating.Core","Microsoft.VisualStudio.TextTemplating.Integration.Resources","Microsoft.VisualCpp.CRT.ClickOnce.Msi","Microsoft.Component.MSBuild","Microsoft.NuGet.Build.Tasks","Microsoft.DiagnosticsHub.KB2882822.Win7","Microsoft.VisualStudio.PackageGroup.Debugger.Script","Microsoft.VisualStudio.Debugger.Script.Msi","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions","Microsoft.VisualStudio.ProTools","sqlsysclrtypes","sqlsysclrtypes","SQLCommon","Microsoft.VisualStudio.ProTools.Resources","Microsoft.VisualStudio.WebToolsExtensions","Microsoft.VisualStudio.WebTools","Microsoft.VisualStudio.WebTools.Resources","Microsoft.VisualStudio.WebTools.MSBuild","Microsoft.VisualStudio.WebTools.WSP.FSA","Microsoft.VisualStudio.WebTools.WSP.FSA.Resources","Microsoft.VisualStudio.VC.Ide.MDD","Microsoft.VisualStudio.VisualC.Logging","Microsoft.WebTools.Shared","Microsoft.WebTools.DotNet.Core.ItemTemplates","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.Redist.14","Microsoft.Windows.UniversalCRT.Msu.7","Microsoft.VisualStudio.StaticAnalysis","Microsoft.VisualStudio.StaticAnalysis.Resources","Microsoft.VisualStudio.Component.Roslyn.Compiler","Microsoft.CodeAnalysis.Compilers","Microsoft.VisualStudio.Component.NuGet","Microsoft.CredentialProvider","Microsoft.VisualStudio.NuGet.PowershellBindingRedirect","Microsoft.VisualStudio.NuGet.Licenses","Microsoft.VisualStudio.PackageGroup.Community","Microsoft.VisualStudio.Community.Extra.Resources","Microsoft.VisualStudio.Community.Extra","Microsoft.VisualStudio.PackageGroup.Core","Microsoft.VisualStudio.CodeSense.Community","Microsoft.VisualStudio.TestTools.TeamFoundationClient","Microsoft.VisualStudio.PackageGroup.Debugger.Core","Microsoft.VisualStudio.PackageGroup.Debugger.TimeTravel.Record","Microsoft.VisualStudio.Debugger.TimeTravel.Runtime","Microsoft.VisualStudio.Debugger.TimeTravel.Runtime","Microsoft.VisualStudio.Debugger.TimeTravel.Agent","Microsoft.VisualStudio.Debugger.TimeTravel.Record","Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost","Microsoft.VisualStudio.VC.Ide.Debugger","Microsoft.VisualStudio.VC.Ide.Debugger.Concord","Microsoft.VisualStudio.VC.Ide.Debugger.Concord.Resources","Microsoft.VisualStudio.VC.Ide.Debugger.Resources","Microsoft.VisualStudio.VC.Ide.Common","Microsoft.VisualStudio.VC.Ide.Common.Resources","Microsoft.VisualStudio.Debugger.Parallel","Microsoft.VisualStudio.Debugger.Parallel.Resources","Microsoft.VisualStudio.Debugger.CollectionAgents","Microsoft.VisualStudio.Debugger.Managed","Microsoft.CodeAnalysis.VisualStudio.Setup","Microsoft.CodeAnalysis.ExpressionEvaluator","Microsoft.VisualStudio.Debugger.Concord.Managed","Microsoft.VisualStudio.Debugger.Concord.Managed.Resources","Microsoft.VisualStudio.Debugger.Managed.Resources","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Remote.DbgHelp.Win8","Microsoft.VisualStudio.Debugger.Concord.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Remote.DbgHelp.Win8","Microsoft.VisualStudio.Debugger.Concord.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger","Microsoft.VisualStudio.Debugger.Package.DiagHub.Client.VSx86","Microsoft.VisualStudio.Debugger.Remote.DiagHub.Client","Microsoft.VisualStudio.Debugger.Remote.DiagHub.Client","Microsoft.VisualStudio.Debugger.DbgHelp.Win8","Microsoft.VisualStudio.VC.MSVCDis","Microsoft.VisualStudio.ScriptedHost","Microsoft.VisualStudio.ScriptedHost.Targeted","Microsoft.VisualStudio.ScriptedHost.Resources","Microsoft.IntelliTrace.DiagnosticsHub","Microsoft.VisualStudio.Debugger.Concord","Microsoft.VisualStudio.Debugger.Concord.Resources","Microsoft.VisualStudio.Debugger.Resources","Microsoft.PackageGroup.ClientDiagnostics","Microsoft.VisualStudio.AppResponsiveness","Microsoft.VisualStudio.AppResponsiveness.Targeted","Microsoft.VisualStudio.AppResponsiveness.Resources","Microsoft.VisualStudio.ClientDiagnostics","Microsoft.VisualStudio.ClientDiagnostics.Targeted","Microsoft.VisualStudio.ClientDiagnostics.Resources","Microsoft.VisualStudio.PackageGroup.CommunityCore","Microsoft.VisualStudio.ProjectSystem.Full","Microsoft.VisualStudio.ProjectSystem","Microsoft.VisualStudio.Community.x86","Microsoft.VisualStudio.Community.x64","Microsoft.VisualStudio.Community","Microsoft.IntelliTrace.CollectorCab","Microsoft.VisualStudio.Community.Resources","Microsoft.VisualStudio.Net.Eula.Resources","Microsoft.VisualStudio.WebSiteProject.DTE","Microsoft.MSHtml","Microsoft.VisualStudio.Platform.CallHierarchy","Microsoft.VisualStudio.Community.Msi.Resources","Microsoft.VisualStudio.Community.Msi","Microsoft.VisualStudio.Devenv.Msi","Microsoft.VisualStudio.MinShell.Interop.Msi","Microsoft.VisualStudio.Editors","Microsoft.VisualStudio.Product.Community","Microsoft.VisualStudio.Workload.CoreEditor","Microsoft.VisualStudio.Component.CoreEditor","Microsoft.VisualStudio.PackageGroup.CoreEditor","Microsoft.VisualCpp.Tools.Common.UtilsPrereq","Microsoft.VisualCpp.Tools.Common.Utils","Microsoft.VisualCpp.Tools.Common.Utils.Resources","Microsoft.VisualStudio.PackageGroup.VsDevCmd","Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk","Microsoft.VisualStudio.VsDevCmd.Core.WinSdk","Microsoft.VisualStudio.VsDevCmd.Core.DotNet","Microsoft.VisualStudio.VC.DevCmd","Microsoft.VisualStudio.VC.DevCmd.Resources","Microsoft.VisualStudio.VirtualTree","Microsoft.VisualStudio.PackageGroup.Progression","Microsoft.VisualStudio.PerformanceProvider","Microsoft.VisualStudio.GraphModel","Microsoft.VisualStudio.GraphProvider","Microsoft.DiaSymReader","Microsoft.Build.Dependencies","Microsoft.Build.FileTracker.Msi","Microsoft.Build","Microsoft.VisualStudio.PackageGroup.NuGet","Microsoft.VisualStudio.NuGet.Core","Microsoft.VisualStudio.TextMateGrammars","Microsoft.VisualStudio.PackageGroup.TeamExplorer.Common","Microsoft.VisualStudio.TeamExplorer","Microsoft.ServiceHub","Microsoft.VisualStudio.ProjectServices","Microsoft.VisualStudio.OpenFolder.VSIX","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.PackageGroup.MinShell","Microsoft.VisualStudio.MinShell.Interop","Microsoft.VisualStudio.Log","Microsoft.VisualStudio.Log.Targeted","Microsoft.VisualStudio.Log.Resources","Microsoft.VisualStudio.Finalizer","Microsoft.VisualStudio.Devenv","Microsoft.VisualStudio.Devenv.Resources","Microsoft.VisualStudio.CoreEditor","Microsoft.VisualStudio.Platform.NavigateTo","Microsoft.VisualStudio.Connected","Microsoft.VisualStudio.PerfLib","Microsoft.VisualStudio.Connected.Resources","Microsoft.VisualStudio.MinShell","Microsoft.VisualStudio.Setup.Configuration","Microsoft.VisualStudio.MinShell.Platform","Microsoft.VisualStudio.MinShell.Platform.Resources","Microsoft.VisualStudio.MefHosting","Microsoft.VisualStudio.MefHosting.Resources","Microsoft.VisualStudio.Initializer","Microsoft.VisualStudio.ExtensionManager","Microsoft.VisualStudio.Platform.Editor","Microsoft.VisualStudio.MinShell.x86","Microsoft.VisualStudio.NativeImageSupport","Microsoft.VisualStudio.MinShell.Msi","Microsoft.VisualStudio.MinShell.Msi.Resources","Microsoft.VisualStudio.LanguageServer","Microsoft.VisualStudio.Devenv.Config","Microsoft.VisualStudio.MinShell.Resources","Microsoft.Net.PackageGroup.4.7.2.Redist","Microsoft.Net.4.7.2.FullRedist","Microsoft.VisualStudio.Branding.Community"]}]
================================================
FILE: test/fixtures/VS_2019_Preview.txt
================================================
[{"path":"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Preview","version":"16.0.28608.199","packages":["Microsoft.VisualStudio.Product.Enterprise","Microsoft.VisualStudio.Workload.NativeDesktop","Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest","Microsoft.VisualStudio.VC.Ide.TestAdapterForGoogleTest","Microsoft.VisualStudio.Component.VC.TestAdapterForBoostTest","Microsoft.VisualStudio.VC.Ide.TestAdapterForBoostTest","Microsoft.VisualStudio.Component.VC.ATL","Microsoft.VisualStudio.VC.Ide.ATL","Microsoft.VisualStudio.VC.Ide.ATL.Resources","Microsoft.VisualCpp.ATL.X86","Microsoft.VisualCpp.ATL.X64","Microsoft.VisualCpp.ATL.Source","Microsoft.VisualCpp.ATL.Headers","Microsoft.VisualStudio.Component.VC.CMake.Project","Microsoft.VisualStudio.VC.CMake","Microsoft.VisualStudio.VC.CMake.Project","Microsoft.VisualStudio.VC.ExternalBuildFramework","Microsoft.VisualStudio.Component.VC.DiagnosticTools","Microsoft.VisualStudio.Component.Graphics.Tools","Microsoft.VisualStudio.Graphics.Viewers","Microsoft.VisualStudio.Graphics.Viewers.Resources","Microsoft.VisualStudio.Graphics.EnableTools","Microsoft.VisualStudio.Graphics.Msi","Microsoft.VisualStudio.Graphics.Msi","Microsoft.VisualStudio.Graphics.Analyzer","Microsoft.VisualStudio.Graphics.Analyzer.Targeted","Microsoft.VisualStudio.Graphics.Analyzer.Resources","Microsoft.VisualStudio.Graphics.Appid","Microsoft.VisualStudio.Graphics.Appid.Resources","Microsoft.VisualStudio.Component.Windows10SDK.17763","Win10SDK_10.0.17763","Microsoft.VisualStudio.Component.VC.Tools.x86.x64","Microsoft.VisualCpp.CodeAnalysis.Extensions","Microsoft.VisualCpp.CodeAnalysis.Extensions.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X86.Resources","Microsoft.VisualCpp.CodeAnalysis.Extensions.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64","Microsoft.VisualCpp.CodeAnalysis.ConcurrencyCheck.X64.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX86","Microsoft.VisualCpp.VCTip.HostX64.TargetX86","Microsoft.VisualCpp.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Tools.HostX64.TargetX64","Microsoft.VisualCpp.VCTip.HostX64.TargetX64","Microsoft.VisualCpp.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64","Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86.Resources","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64","Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64.Resources","Microsoft.VisualCpp.PGO.X86","Microsoft.VisualCpp.PGO.X64","Microsoft.VisualCpp.PGO.Headers","Microsoft.VisualCpp.CRT.x86.Store","Microsoft.VisualCpp.CRT.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.x64.Store","Microsoft.VisualCpp.CRT.x64.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop","Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop","Microsoft.VisualStudio.PackageGroup.VC.Tools.x86","Microsoft.VisualCpp.Tools.HostX86.TargetX64","Microsoft.VisualCpp.VCTip.hostX86.targetX64","Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Resources","Microsoft.VisualCpp.Tools.HostX86.TargetX86","Microsoft.VisualCpp.VCTip.hostX86.targetX86","Microsoft.VisualCpp.Tools.HostX86.TargetX86.Resources","Microsoft.VisualCpp.Tools.Core.Resources","Microsoft.VisualCpp.Tools.Core.x86","Microsoft.VisualCpp.DIA.SDK","Microsoft.VisualCpp.CRT.x86.Desktop","Microsoft.VisualCpp.CRT.x64.Desktop","Microsoft.VisualCpp.CRT.Source","Microsoft.VisualCpp.CRT.Redist.X86","Microsoft.VisualCpp.CRT.Redist.X64","Microsoft.VisualCpp.CRT.Redist.Resources","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.RuntimeDebug.14","Microsoft.VisualCpp.CRT.Headers","Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core","Microsoft.VisualStudio.PackageGroup.TestTools.Native","Microsoft.VisualStudio.ComponentGroup.ArchitectureTools.Native","Microsoft.VisualStudio.Component.ClassDesigner","Microsoft.VisualStudio.ClassDesigner","Microsoft.VisualStudio.ClassDesigner.Resources","Microsoft.VisualStudio.Component.VC.Redist.14.Latest","Microsoft.VisualCpp.Redist.14.Latest","Microsoft.VisualCpp.Redist.14.Latest","Microsoft.VisualStudio.VC.Templates.UnitTest","Microsoft.VisualStudio.VC.UnitTest.Desktop.Build.Core","Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP","Microsoft.VisualStudio.VC.Templates.UnitTest.Resources","Microsoft.VisualStudio.VC.Templates.Desktop","Microsoft.VisualStudio.Component.VC.CoreIde","Microsoft.VisualStudio.VC.Ide.Pro","Microsoft.VisualStudio.VC.Ide.Pro.Resources","Microsoft.VisualStudio.VC.Templates.Pro","Microsoft.VisualStudio.VC.Templates.Pro.Resources","Microsoft.VisualStudio.VC.Items.Pro","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced","Microsoft.VisualStudio.VC.Ide.x64","Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express","Microsoft.VisualStudio.VC.MSBuild.X64.v142","Microsoft.VisualStudio.VC.MSBuild.X64","Microsoft.VS.VC.MSBuild.X64.Resources","Microsoft.VisualStudio.VC.MSBuild.ARM.v142","Microsoft.VisualStudio.VC.MSBuild.ARM","Microsoft.VisualStudio.VC.MSBuild.x86.v142","Microsoft.VisualStudio.VC.MSBuild.X86","Microsoft.VisualStudio.VC.MSBuild.Base","Microsoft.VisualStudio.VC.MSBuild.Base.Resources","Microsoft.VisualStudio.VC.Ide.WinXPlus","Microsoft.VisualStudio.VC.Ide.Dskx","Microsoft.VisualStudio.VC.Ide.Dskx.Resources","Microsoft.VisualStudio.VC.Ide.Base","Microsoft.VisualStudio.VC.Ide.LanguageService","Microsoft.VisualStudio.VC.Ide.Core","Microsoft.VisualStudio.VC.Ide.Core.Resources","Microsoft.VisualStudio.VC.Ide.VCPkgDatabase","Microsoft.VisualStudio.VC.Ide.Progression.Enterprise","Microsoft.VisualStudio.VC.Ide.ProjectSystem","Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine","Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources","Microsoft.VisualStudio.VC.Ide.LanguageService.Resources","Microsoft.VisualStudio.VC.Ide.Base.Resources","Microsoft.VisualStudio.Component.CodeMap","Microsoft.VisualStudio.Component.GraphDocument","Microsoft.VisualStudio.Vmp","Microsoft.VisualStudio.GraphDocument","Microsoft.VisualStudio.GraphDocument.Resources","Microsoft.VisualStudio.CodeMap","Microsoft.VisualStudio.Component.SQL.LocalDB.Runtime","Microsoft.VisualStudio.Component.SQL.NCLI","sqllocaldb","sqlncli","Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions","Microsoft.VisualStudio.WebToolsExtensions","Microsoft.VisualStudio.WebTools","Microsoft.VisualStudio.WebTools.Resources","Microsoft.VisualStudio.WebTools.MSBuild","Microsoft.VisualStudio.PackageGroup.Debugger.Script","Microsoft.VisualStudio.Debugger.Script.Msi","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.Debugger.Script.Resources","Microsoft.VisualStudio.VC.Ide.MDD","Microsoft.VisualStudio.Component.NuGet","Microsoft.CredentialProvider","Component.Microsoft.VisualStudio.LiveShare","Microsoft.VisualStudio.LiveShare","Microsoft.VisualStudio.Component.Debugger.JustInTime","Microsoft.VisualStudio.Debugger.ImmersiveActivateHelper.Msi","Microsoft.VisualStudio.Debugger.JustInTime","Microsoft.VisualStudio.Debugger.JustInTime.Msi","Microsoft.VisualStudio.Component.IntelliTrace.FrontEnd","Microsoft.IntelliTrace.DiagnosticsHubAgent.Targeted","Microsoft.IntelliTrace.Debugger","Microsoft.IntelliTrace.Debugger.Targeted","Microsoft.IntelliTrace.FrontEnd","Microsoft.DiagnosticsHub.Instrumentation","Microsoft.DiagnosticsHub.CpuSampling","Microsoft.DiagnosticsHub.CpuSampling.Targeted","Microsoft.PackageGroup.DiagnosticsHub.Platform","Microsoft.DiagnosticsHub.Collection.StopService.Uninstall","Microsoft.DiagnosticsHub.Runtime","Microsoft.DiagnosticsHub.Runtime.Targeted","Microsoft.DiagnosticsHub.Runtime.Resources","Microsoft.DiagnosticsHub.Collection","Microsoft.DiagnosticsHub.Collection.Service","Microsoft.DiagnosticsHub.Collection.StopService.Install","Microsoft.VisualStudio.Dsl.GraphObject","Microsoft.Net.4.TargetingPack","Microsoft.VisualStudio.VC.Ide.ResourceEditor","Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources","Microsoft.VisualStudio.NuGet.Licenses","Microsoft.WebTools.Shared","Microsoft.VisualStudio.WebToolsExtensions.DotNet.Core.ItemTemplates","Microsoft.VisualStudio.Component.TextTemplating","Microsoft.VisualStudio.TextTemplating.MSBuild","Microsoft.VisualStudio.TextTemplating.Integration","Microsoft.VisualStudio.TextTemplating.Core","Microsoft.VisualStudio.TextTemplating.Integration.Resources","Microsoft.VisualStudio.ProTools","sqlsysclrtypes","sqlsysclrtypes","SQLCommon","Microsoft.VisualStudio.ProTools.Resources","Microsoft.VisualStudio.NuGet.Core","Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage","Microsoft.VisualStudio.PackageGroup.IntelliTrace.Core","Microsoft.IntelliTrace.Core","Microsoft.IntelliTrace.Core.Concord","Microsoft.IntelliTrace.Core.Targeted","Microsoft.IntelliTrace.ProfilerProxy.Msi.x64","Microsoft.IntelliTrace.ProfilerProxy.Msi","Microsoft.VisualStudio.TestTools.DynamicCodeCoverage","Microsoft.VisualStudio.TestTools.CodeCoverage.Msi","Microsoft.VisualStudio.TestTools.CodeCoverage","Microsoft.Icecap.Analysis","Microsoft.Icecap.Analysis.Targeted","Microsoft.Icecap.Analysis.Resources","Microsoft.Icecap.Analysis.Resources.Targeted","Microsoft.Icecap.Collection.Msi","Microsoft.Icecap.Collection.Msi.Targeted","Microsoft.Icecap.Collection.Msi.Resources","Microsoft.Icecap.Collection.Msi.Resources.Targeted","Microsoft.VisualStudio.PackageGroup.TestTools.Core","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI","Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V1.CLI","Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI","Microsoft.VisualStudio.TestTools.Pex.Common","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.Legacy","Microsoft.VisualStudio.PackageGroup.MinShell.Interop","Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Msi","Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Common","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips.Resources","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.TestTools","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Remote","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Professional","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Premium","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Common","Microsoft.VisualStudio.TestTools.TP.Legacy.Common.Res","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Resources","Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Agent","Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE","Microsoft.VisualStudio.TestTools.TestWIExtension","Microsoft.VisualStudio.TestTools.TestPlatform.IDE","Microsoft.VisualStudio.PackageGroup.TestTools.DataCollectors","Microsoft.VisualStudio.TestTools.NE.Msi.Targeted","Microsoft.VisualStudio.TestTools.NetworkEmulation","Microsoft.VisualStudio.TestTools.DataCollectors","Microsoft.VisualCpp.CRT.ClickOnce.Msi","Microsoft.VisualStudio.WebTools.WSP.FSA","Microsoft.VisualStudio.WebTools.WSP.FSA.Resources","Microsoft.VisualStudio.Component.Static.Analysis.Tools","Microsoft.VisualCpp.Redist.14","Microsoft.VisualCpp.Redist.14","Microsoft.VisualStudio.StaticAnalysis","Microsoft.VisualStudio.StaticAnalysis.Resources","Microsoft.VisualStudio.PackageGroup.Community","Microsoft.VisualStudio.Community.Extra.Resources","Microsoft.VisualStudio.Community.Extra","Microsoft.VisualStudio.PackageGroup.Core","Microsoft.VisualStudio.CodeSense","Microsoft.VisualStudio.CodeSense.Community","Microsoft.VisualStudio.TestTools.TeamFoundationClient","Microsoft.VisualStudio.PackageGroup.Debugger.Core","Microsoft.VisualStudio.PackageGroup.Debugger.TimeTravel.Record","Microsoft.VisualStudio.Debugger.TimeTravel.Runtime","Microsoft.VisualStudio.Debugger.TimeTravel.Runtime","Microsoft.VisualStudio.Debugger.TimeTravel.Agent","Microsoft.VisualStudio.Debugger.TimeTravel.Record","Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost","Microsoft.VisualStudio.VC.Ide.Debugger","Microsoft.VisualStudio.VC.Ide.Debugger.Concord","Microsoft.VisualStudio.VC.Ide.Debugger.Concord.Resources","Microsoft.VisualStudio.VC.Ide.Debugger.Resources","Microsoft.VisualStudio.VC.Ide.Common","Microsoft.VisualStudio.VC.Ide.Common.Resources","Microsoft.VisualStudio.Debugger.Parallel","Microsoft.VisualStudio.Debugger.Parallel.Resources","Microsoft.VisualStudio.Debugger.CollectionAgents","Microsoft.VisualStudio.Debugger.Managed","Microsoft.VisualStudio.Debugger.Concord.Managed","Microsoft.VisualStudio.Debugger.Concord.Managed.Resources","Microsoft.VisualStudio.Debugger.Managed.Resources","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote","Microsoft.VisualStudio.Debugger.Concord.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger.Remote.Resources","Microsoft.VisualStudio.Debugger","Microsoft.VisualStudio.Debugger.Package.DiagHub.Client.VSx86","Microsoft.VisualStudio.Debugger.Remote.DiagHub.Client","Microsoft.VisualStudio.Debugger.Remote.DiagHub.Client","Microsoft.VisualStudio.VC.MSVCDis","Microsoft.VisualStudio.ScriptedHost","Microsoft.VisualStudio.ScriptedHost.Targeted","Microsoft.VisualStudio.ScriptedHost.Resources","Microsoft.IntelliTrace.DiagnosticsHub","Microsoft.VisualStudio.Debugger.Concord","Microsoft.VisualStudio.Debugger.Concord.Resources","Microsoft.VisualStudio.Debugger.Resources","Microsoft.PackageGroup.ClientDiagnostics","Microsoft.VisualStudio.AppResponsiveness","Microsoft.VisualStudio.AppResponsiveness.Targeted","Microsoft.VisualStudio.AppResponsiveness.Resources","Microsoft.VisualStudio.ClientDiagnostics","Microsoft.VisualStudio.ClientDiagnostics.Targeted","Microsoft.VisualStudio.ClientDiagnostics.Resources","Microsoft.VisualStudio.PackageGroup.ProfessionalCore","Microsoft.VisualStudio.Professional","Microsoft.VisualStudio.Professional.Msi","Microsoft.VisualStudio.PackageGroup.EnterpriseCore","Microsoft.VisualStudio.Enterprise.Msi","Microsoft.VisualStudio.Enterprise","Microsoft.ShDocVw","Microsoft.VisualStudio.PackageGroup.CommunityCore","Microsoft.VisualStudio.ProjectSystem.Full","Microsoft.VisualStudio.ProjectSystem","Microsoft.VisualStudio.Community.x86","Microsoft.VisualStudio.Community.x64","Microsoft.VisualStudio.Community","Microsoft.IntelliTrace.CollectorCab","Microsoft.VisualStudio.Community.Resources","Microsoft.VisualStudio.WebSiteProject.DTE","Microsoft.MSHtml","Microsoft.VisualStudio.Platform.CallHierarchy","Microsoft.VisualStudio.Community.Msi.Resources","Microsoft.VisualStudio.Community.Msi","Microsoft.VisualStudio.Devenv.Msi","Microsoft.VisualStudio.MinShell.Interop.Msi","Microsoft.VisualStudio.Editors","Microsoft.VisualStudio.Net.Eula.Resources","Microsoft.CodeAnalysis.ExpressionEvaluator","Microsoft.CodeAnalysis.VisualStudio.Setup","Microsoft.Component.MSBuild","Microsoft.NuGet.Build.Tasks","Microsoft.VisualStudio.Component.Roslyn.Compiler","Microsoft.CodeAnalysis.Compilers","Microsoft.VisualStudio.Workload.CoreEditor","Microsoft.VisualStudio.Component.CoreEditor","Microsoft.VisualStudio.PackageGroup.CoreEditor","Microsoft.VisualCpp.Tools.Common.UtilsPrereq","Microsoft.VisualCpp.Tools.Common.Utils","Microsoft.VisualCpp.Tools.Common.Utils.Resources","Microsoft.VisualStudio.PackageGroup.VsDevCmd","Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk","Microsoft.VisualStudio.VsDevCmd.Core.WinSdk","Microsoft.VisualStudio.VsDevCmd.Core.DotNet","Microsoft.VisualStudio.VC.DevCmd","Microsoft.VisualStudio.VC.DevCmd.Resources","Microsoft.VisualStudio.VirtualTree","Microsoft.VisualStudio.PackageGroup.Progression","Microsoft.VisualStudio.PerformanceProvider","Microsoft.VisualStudio.GraphModel","Microsoft.VisualStudio.GraphProvider","Microsoft.DiaSymReader","Microsoft.Build.Dependencies","Microsoft.Build.FileTracker.Msi","Microsoft.Build","Microsoft.VisualStudio.TextMateGrammars","Microsoft.VisualStudio.PackageGroup.TeamExplorer.Common","Microsoft.VisualStudio.TeamExplorer","Microsoft.ServiceHub","Microsoft.VisualStudio.ProjectServices","Microsoft.VisualStudio.SLNX.VSIX","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.FileHandler.Msi","Microsoft.VisualStudio.PackageGroup.MinShell","Microsoft.VisualStudio.MinShell.Interop","Microsoft.VisualStudio.Log","Microsoft.VisualStudio.Log.Targeted","Microsoft.VisualStudio.Log.Resources","Microsoft.VisualStudio.Finalizer","Microsoft.VisualStudio.Devenv","Microsoft.VisualStudio.Devenv.Resources","Microsoft.VisualStudio.CoreEditor","Microsoft.VisualStudio.Platform.NavigateTo","Microsoft.VisualStudio.Connected","Microsoft.VisualStudio.Connected.Resources","Microsoft.VisualStudio.MinShell","Microsoft.VisualStudio.Setup.Configuration","Microsoft.VisualStudio.Platform.Search","Microsoft.VisualStudio.MinShell.Platform","Microsoft.VisualStudio.MinShell.Platform.Resources","Microsoft.VisualStudio.MefHosting","Microsoft.VisualStudio.MefHosting.Resources","Microsoft.VisualStudio.Initializer","Microsoft.VisualStudio.ExtensionManager","Microsoft.VisualStudio.Platform.Editor","Microsoft.VisualStudio.MinShell.x86","Microsoft.VisualStudio.NativeImageSupport","Microsoft.VisualStudio.MinShell.Msi","Microsoft.VisualStudio.MinShell.Msi.Resources","Microsoft.VisualStudio.LanguageServer","Microsoft.VisualStudio.Devenv.Config","Microsoft.VisualStudio.MinShell.Resources","Microsoft.Net.PackageGroup.4.7.2.Redist","Microsoft.VisualStudio.Branding.Enterprise"]}]
================================================
FILE: test/fixtures/VS_2022_BuildTools_arm64_only.txt
================================================
[
{
"path": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools",
"version": "17.11.35222.181",
"packages": [
"Microsoft.VisualStudio.Component.VC.Tools.ARM64",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM64.v143",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM64",
"Microsoft.VS.VC.vcvars.arm64.Shortcuts",
"Microsoft.VisualCpp.CA.Ext.Hostx64.TargetARM64",
"Microsoft.VC.14.41.17.11.CA.Ext.Hostx64.TargetARM64.base",
"Microsoft.VC.14.41.17.11.CA.Ext.Hostx64.TargetARM64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.TargetARM64",
"Microsoft.VC.14.41.17.11.CA.Ext.Hostx86.TargetARM64.base",
"Microsoft.VC.14.41.17.11.CA.Ext.Hostx86.TargetARM64.Res.base",
"Microsoft.VisualCpp.CA.Ext.HostARM64.TargetARM64",
"Microsoft.VC.14.41.17.11.CA.Ext.HostARM64.TargetARM64.base",
"Microsoft.VC.14.41.17.11.CA.Ext.HostARM64.TargetARM64.Res.base",
"Microsoft.VisualCpp.Tools.Hostx86.Targetarm64",
"Microsoft.VC.14.41.17.11.Tools.Hostx86.Targetarm64.base",
"Microsoft.VC.14.41.17.11.Tools.HostX86.TargetARM64.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetARM64",
"Microsoft.VC.14.41.17.11.Tools.HostARM64.TargetARM64.base",
"Microsoft.VC.14.41.17.11.Tools.HostARM64.TargetARM64.Res.base",
"Microsoft.VisualCpp.CRT.Redist.ARM64.OneCore.Desktop",
"Microsoft.VC.14.40.17.10.CRT.Redist.ARM64.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.ARM64",
"Microsoft.VC.14.40.17.10.CRT.Redist.ARM64.base",
"Microsoft.VisualCpp.CRT.ARM64.OneCore.Desktop",
"Microsoft.VC.14.41.17.11.CRT.ARM64.OneCore.Desktop.base",
"Microsoft.VC.14.41.17.11.CRT.ARM64.OneCore.Desktop.debug.base",
"Microsoft.VisualCpp.CRT.ARM64.Store",
"Microsoft.VC.14.41.17.11.CRT.ARM64.Store.base",
"Microsoft.VisualCpp.CRT.ARM64.Desktop",
"Microsoft.VC.14.41.17.11.CRT.ARM64.Desktop.base",
"Microsoft.VC.14.41.17.11.CRT.ARM64.Desktop.debug.base",
"Microsoft.VisualStudio.PackageGroup.VC.Tools.x64.ARM64",
"Microsoft.VisualCpp.Tools.Core",
"Microsoft.VisualCpp.PGO.ARM64",
"Microsoft.VC.14.41.17.11.PGO.ARM64.base",
"Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetarm64",
"Microsoft.VC.14.41.17.11.Premium.Tools.Hostx86.Targetarm64.base",
"Microsoft.VC.14.41.17.11.Prem.HostX86.TargetARM64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM64",
"Microsoft.VC.14.41.17.11.Premium.Tools.HostX64.TargetARM64.base",
"Microsoft.VC.14.41.17.11.Prem.HostX64.TargetARM64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.ARM64.Base",
"Microsoft.VC.14.41.17.11.Premium.Tools.ARM64.Base.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetARM64",
"Microsoft.VC.14.41.17.11.Tools.HostX64.TargetARM64.base",
"Microsoft.VC.14.41.17.11.Tools.HostX64.TargetARM64.Res.base",
"Microsoft.VC.14.41.17.11.Props.ARM64",
"Microsoft.VisualStudio.TestTools.TestWIExtension",
"Microsoft.VisualStudio.TestTools.TestPlatform.IDE",
"Microsoft.VisualStudio.VC.Ide.Pro",
"Microsoft.VisualStudio.VC.Ide.Pro.Resources",
"Microsoft.VisualStudio.VC.Templates.General",
"Microsoft.VisualStudio.VC.Templates.General.Resources",
"Microsoft.VisualStudio.VC.Items.Pro",
"Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced",
"Microsoft.VisualStudio.VC.Ide.MDD",
"Microsoft.VisualStudio.PackageGroup.Core",
"Microsoft.VisualStudio.CodeSense.Community",
"Microsoft.VisualStudio.TestTools.TeamFoundationClient",
"Microsoft.PackageGroup.ClientDiagnostics",
"Microsoft.VisualStudio.AppResponsiveness",
"Microsoft.VisualStudio.AppResponsiveness.Targeted",
"Microsoft.VisualStudio.AppResponsiveness.Resources",
"Microsoft.VisualStudio.ClientDiagnostics",
"Microsoft.VisualStudio.ClientDiagnostics.Targeted",
"Microsoft.VisualStudio.Component.VC.Llvm.Clang",
"Microsoft.VisualStudio.VC.Llvm.Clang",
"Microsoft.VisualStudio.ClientDiagnostics.Resources",
"Microsoft.VisualStudio.PackageGroup.CommunityCore",
"Microsoft.VisualStudio.ProjectSystem.Full",
"Microsoft.VisualStudio.Product.BuildTools",
"Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager",
"Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager.Resources",
"Microsoft.VisualStudio.PackageGroup.TestTools.Core",
"Microsoft.VC.14.41.17.11.Props.x86",
"Microsoft.VC.14.41.17.11.Props",
"Microsoft.VisualCpp.RuntimeDebug.14",
"Microsoft.VisualCpp.RuntimeDebug.14.ARM64",
"Microsoft.VC.14.41.17.11.Tools.HostX86.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.Core.Resources",
"Microsoft.VisualCpp.Tools.Core.x86",
"Microsoft.VC.14.41.17.11.Tools.Core.Props",
"Microsoft.VisualCpp.Tools.Common.Utils",
"Microsoft.VisualCpp.Tools.Common.Utils.Resources",
"Microsoft.VisualCpp.DIA.SDK",
"Microsoft.VisualCpp.Servicing.DIASDK",
"Microsoft.VisualCpp.CRT.x86.Desktop",
"Microsoft.VisualStudio.Workload.VCTools",
"Microsoft.VC.14.41.17.11.CRT.x64.Desktop.base",
"Microsoft.VisualCpp.CRT.Source",
"Microsoft.VC.14.41.17.11.CRT.Source.base",
"Microsoft.VisualCpp.CRT.Headers",
"Microsoft.VC.14.41.17.11.CRT.Headers.Resources",
"Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset",
"Microsoft.VisualCpp.CRT.Redist.Resources",
"Microsoft.VC.14.41.17.11.CRT.Headers.Resources.base",
"Microsoft.VisualStudio.VC.MSBuild.Llvm",
"Microsoft.VisualStudio.VC.MSBuild.Llvm.Resources",
"Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
"Microsoft.VisualStudio.PackageGroup.TestTools.Native",
"Microsoft.VisualStudio.VC.Templates.UnitTest",
"Microsoft.VisualStudio.VC.Templates.UnitTest.Resources",
"Microsoft.VisualCpp.ATL.ARM64",
"Microsoft.VC.14.41.17.11.ATL.ARM64.base",
"Microsoft.VisualStudio.Community.VB.Targeted",
"Microsoft.VisualStudio.Community.VB.Neutral",
"Microsoft.VisualStudio.Community.CSharp.Targeted",
"Microsoft.VisualStudio.Community.CSharp.Neutral",
"Microsoft.VisualStudio.Community.ProductArch.TargetedExtra",
"Microsoft.VisualStudio.VC.MSBuild.Base",
"Microsoft.VisualStudio.VC.MSBuild.Base.Resources",
"Microsoft.VisualStudio.VC.Templates.Desktop",
"Microsoft.VisualStudio.Component.VC.CoreIde",
"Microsoft.VisualCpp.ATL.ARM64.Spectre",
"Microsoft.VisualStudio.Component.VC.ATL.ARM64",
"Microsoft.VisualCpp.CRT.x86.Store",
"Microsoft.VC.14.41.17.11.ATL.ARM64.Spectre.base",
"Microsoft.VC.14.41.17.11.CRT.x86.Store.base",
"Microsoft.VC.14.41.17.11.Props.ARM64.Spectre",
"Microsoft.VisualStudio.Component.VC.ATL.ARM64.Spectre",
"Microsoft.VisualStudio.Community.x64",
"Microsoft.VisualStudio.Community.ProductArch.Targeted",
"Microsoft.VisualStudio.Community.ProductArch.NeutralExtra",
"Microsoft.IntelliTrace.CollectorCab",
"Microsoft.VisualStudio.Community.VB.Resources.Targeted",
"Microsoft.VisualStudio.Community.VB.Resources.Neutral",
"Microsoft.VisualStudio.Community.CSharp.Resources.Targeted",
"Microsoft.VisualStudio.Community.CSharp.Resources.Neutral",
"Microsoft.VisualStudio.Community.ProductArch.Resources.Targeted",
"Microsoft.VisualStudio.Community.ProductArch.Resources.NeutralExtra",
"Microsoft.VisualStudio.Community.ProductArch.Resources.Neutral",
"Microsoft.VisualStudio.WebSiteProject.DTE",
"Microsoft.VisualStudio.Diagnostics.AspNetHelper",
"Microsoft.MSHtml",
"Microsoft.VisualStudio.Platform.CallHierarchy",
"Microsoft.VisualStudio.Community.ProductArch.Neutral",
"Microsoft.VisualStudio.Community.Msi.Resources",
"Microsoft.VisualStudio.Community.Msi",
"Microsoft.VisualStudio.Community.Shared.Msi",
"Microsoft.VisualStudio.MinShell.Interop.Msi",
"Microsoft.VisualStudio.MinShell.Interop.Shared.Msi",
"Microsoft.VisualStudio.PackageGroup.CoreEditor",
"Microsoft.VisualStudio.ScriptedHost",
"Microsoft.VisualStudio.ScriptedHost.Targeted",
"Microsoft.VisualStudio.VirtualTree",
"Microsoft.VisualStudio.PackageGroup.Progression",
"Microsoft.VisualStudio.PerformanceProvider",
"Microsoft.VisualStudio.GraphModel",
"Microsoft.VisualStudio.GraphProvider",
"Microsoft.VisualStudio.TextMateGrammars",
"Microsoft.VisualStudio.Platform.Markdown",
"Microsoft.VisualStudio.PackageGroup.TeamExplorer.Common",
"Microsoft.VisualStudio.PackageGroup.ServiceHub",
"Microsoft.ServiceHub.Node",
"Microsoft.ServiceHub.Managed",
"Microsoft.VisualStudio.OpenFolder.VSIX",
"Microsoft.VisualStudio.FileHandler.Msi",
"Microsoft.VisualStudio.FileHandler.Msi",
"Microsoft.VisualStudio.PackageGroup.MinShell",
"Microsoft.VisualStudio.MinShell.Msi",
"Microsoft.VisualStudio.MinShell.Shared.Msi",
"Microsoft.VisualStudio.MinShell.Msi.Resources",
"Microsoft.VisualStudio.MinShell.Interop",
"Microsoft.VisualStudio.Log",
"Microsoft.VisualStudio.Log.Targeted",
"Microsoft.VisualStudio.Log.Resources",
"Microsoft.VisualStudio.Finalizer",
"Microsoft.VisualStudio.CoreEditor",
"Microsoft.VisualStudio.Platform.NavigateTo",
"Microsoft.VisualStudio.Connected",
"Microsoft.VisualStudio.Identity",
"Microsoft.Developer.IdentityServiceGS",
"SQLitePCLRaw",
"SQLitePCLRaw.Targeted",
"Microsoft.VisualStudio.Connected.Auto",
"Microsoft.VisualStudio.Connected.Auto.Resources",
"Microsoft.VisualStudio.Connected.Resources",
"Microsoft.VisualStudio.VC.Ide.x64",
"Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express",
"Microsoft.VisualStudio.PackageGroup.Debugger.Script",
"Microsoft.VisualStudio.Debugger.Script",
"Microsoft.VisualStudio.Debugger.Script.Resources",
"Microsoft.VisualStudio.Debugger.Script.Remote",
"Microsoft.WebView2",
"Microsoft.VisualStudio.Debugger.Script.Remote",
"Microsoft.VisualStudio.Debugger.Script.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Script.Remote.Resources",
"Microsoft.VisualStudio.VC.Ide.WinXPlus",
"Microsoft.VisualStudio.VC.Ide.Dskx",
"Microsoft.VisualStudio.VC.Ide.Dskx.Resources",
"Microsoft.VisualStudio.VC.Ide.Base",
"Microsoft.VisualStudio.VC.Ide.LanguageService",
"Microsoft.VisualStudio.VC.Copilot.Setup",
"Microsoft.VisualStudio.VC.Ide.VCPkgDatabase",
"Microsoft.VisualStudio.VC.Ide.ResourceEditor",
"Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources",
"Microsoft.VisualStudio.VC.Ide.Core",
"Microsoft.VisualStudio.VisualC.Utilities",
"Microsoft.VisualStudio.VisualC.Utilities.Resources",
"Microsoft.VisualStudio.VC.Ide.ProjectSystem",
"Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources",
"Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine",
"Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources",
"Microsoft.VisualStudio.VC.Ide.LanguageService.Resources",
"Microsoft.VisualStudio.VC.Llvm.Base",
"CoreEditorFonts",
"Microsoft.VisualStudio.VC.Ide.Base.Resources",
"Microsoft.VisualStudio.Component.TextTemplating",
"Microsoft.VisualStudio.PackageGroup.Debugger.Core",
"Microsoft.VisualStudio.Debugger.BrokeredServices",
"Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost",
"Microsoft.VisualStudio.Debugger.AzureAttach",
"Microsoft.VisualStudio.Web.Azure.Common",
"Microsoft.WebTools.Shared",
"Microsoft.WebTools.DotNet.Core.ItemTemplates",
"Microsoft.VisualStudio.PackageGroup.Debugger.TimeTravel.Replay",
"Microsoft.VisualStudio.VC.Ide.Debugger",
"Microsoft.VisualStudio.VC.Ide.Debugger.Concord",
"Microsoft.VisualStudio.VC.Ide.Debugger.Concord.Resources",
"Microsoft.VisualStudio.VC.Ide.Debugger.Resources",
"Microsoft.VisualStudio.VC.Ide.Common",
"Microsoft.VisualStudio.VC.Ide.Common.Resources",
"Microsoft.VisualStudio.Debugger.CollectionAgents",
"Microsoft.VisualStudio.Debugger.Parallel",
"Microsoft.VisualStudio.Debugger.Parallel.Resources",
"Microsoft.VisualStudio.Debugger.Managed",
"Microsoft.DiaSymReader",
"Microsoft.CodeAnalysis.ExpressionEvaluator",
"Microsoft.VisualStudio.Debugger.Concord.Managed",
"Microsoft.VisualStudio.Debugger.Concord.Managed.Resources",
"Microsoft.VisualStudio.Debugger.Managed.Resources",
"Microsoft.VisualStudio.Debugger.TargetComposition",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote.arm64",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote",
"Microsoft.VisualStudio.Debugger.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources",
"Microsoft.VisualStudio.VC.Ide.LanguageService.Dependencies",
"Microsoft.VisualStudio.Debugger.Remote",
"Microsoft.VisualStudio.Debugger.Remote.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM64",
"Microsoft.VisualStudio.Debugger.Remote.ARM",
"Microsoft.VisualStudio.Debugger.Concord.Remote.ARM",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM",
"Microsoft.VisualStudio.Debugger.Remote.Resources.ARM",
"Microsoft.VisualStudio.Debugger.Remote.Resources.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote.Resources",
"Microsoft.VisualStudio.Debugger",
"Microsoft.VisualStudio.AzureSDK",
"Microsoft.VisualStudio.Editors",
"Microsoft.VisualStudio.VC.MSVCDis",
"Microsoft.IntelliTrace.DiagnosticsHub",
"Microsoft.VisualStudio.MinShell",
"Microsoft.VisualStudio.Copilot.Contracts",
"Microsoft.VisualStudio.Licensing",
"Microsoft.VisualStudio.IdentityDependencies",
"Microsoft.VisualStudio.GitHubProtocolHandler.Msi",
"Microsoft.VisualStudio.VsWebProtocolSelector.Msi",
"Microsoft.VisualStudio.Extensibility.Container",
"Microsoft.VisualStudio.LanguageServer",
"Microsoft.VisualStudio.MefHosting",
"Microsoft.VisualStudio.Initializer",
"Microsoft.VisualStudio.ExtensionManager",
"Microsoft.VisualStudio.ExtensionManager.Auto",
"Microsoft.VisualStudio.Platform.Editor",
"Microsoft.VisualStudio.MinShell.Targeted",
"Microsoft.VisualStudio.Devenv.Config",
"Microsoft.VisualStudio.MinShell.Resources",
"Microsoft.VisualStudio.UIInternal.Guide",
"Microsoft.VisualStudio.UIInternal",
"Microsoft.VisualStudio.UIInternal.Resources",
"Microsoft.VisualStudio.CoreDotNet",
"Microsoft.VisualStudio.MinShell.Auto",
"Microsoft.VisualStudio.MinShell.Auto.Resources",
"Microsoft.VisualStudio.Debugger.Concord",
"Microsoft.VisualStudio.Debugger.Concord.Resources",
"Microsoft.VisualStudio.Debugger.Resources",
"Microsoft.DiaSymReader.PortablePdb",
"Microsoft.VisualStudio.PerfLib",
"Microsoft.VisualStudio.Debugger.Package.DiagHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.VisualStudio.TextTemplating.MSBuild",
"Microsoft.VisualStudio.TextTemplating.Integration",
"Microsoft.VisualStudio.TextTemplating.Core",
"Microsoft.VisualStudio.PackageGroup.Roslyn.LanguageServices",
"Microsoft.CodeAnalysis.VisualStudio.Setup",
"Microsoft.VisualStudio.TextTemplating.Integration.Resources",
"Microsoft.VC.14.41.17.11.Props.IFC",
"Microsoft.VisualStudio.Component.VC.ASAN",
"Microsoft.VisualCpp.ASAN.X86",
"Microsoft.VC.14.41.17.11.ASAN.X86.base",
"Microsoft.VC.14.41.17.11.ASAN.X64.base",
"Microsoft.VC.14.41.17.11.ASAN.Headers.base",
"Microsoft.VC.14.41.17.11.Props.ATLMFC",
"Microsoft.VisualCpp.ATL.Source",
"Microsoft.VC.14.41.17.11.ATL.Source.base",
"Microsoft.VisualCpp.ATL.Headers",
"Microsoft.VC.14.41.17.11.ATL.Headers.base",
"Microsoft.VC.14.41.17.11.Servicing.ATL",
"Microsoft.VisualStudio.Component.TestTools.BuildTools",
"Microsoft.VisualStudio.PackageGroup.TestTools.BuildTools",
"Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage",
"Microsoft.VisualStudio.TestTools.DynamicCodeCoverage",
"Microsoft.CodeCoverage.Console.Targeted",
"Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI",
"Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI",
"Microsoft.VisualStudio.Component.Windows11SDK.22621",
"Microsoft.VisualStudio.VC.UnitTest.Desktop.Build.Core",
"Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP",
"Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
"Microsoft.VC.14.41.17.11.CA.Rulesets.base",
"Microsoft.VC.14.41.17.11.Servicing.CARulesets",
"Microsoft.VC.14.41.17.11.Servicing.CAExtensions",
"Microsoft.VC.14.41.17.11.Tools.HostX64.TargetX86.base",
"Microsoft.VC.14.41.17.11.Tools.HostX64.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetX64",
"Microsoft.VC.14.41.17.11.Tools.HostX64.TargetX64.base",
"Microsoft.VC.14.41.17.11.Tools.HostX64.TargetX64.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetX86",
"Microsoft.VC.14.41.17.11.Tools.HostARM64.TargetX86.base",
"Microsoft.VC.14.41.17.11.Tools.HostARM64.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86",
"Microsoft.VC.14.41.17.11.Premium.Tools.HostX86.TargetX86.base",
"Microsoft.VisualStudio.Component.VC.Modules.ARM64",
"Microsoft.VC.14.41.17.11.Prem.HostX86.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64",
"Microsoft.VC.14.41.17.11.Premium.Tools.HostX64.TargetX64.base",
"Microsoft.VC.14.41.17.11.Prem.HostX64.TargetX64.Res.base",
"Microsoft.Build.Arm64",
"Microsoft.Build.UnGAC",
"Microsoft.VisualStudio.VC.Icons",
"Microsoft.VisualCpp.CRT.x86.OneCore.Desktop",
"Microsoft.VC.14.41.17.11.CRT.x86.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.x64.Store",
"Microsoft.VC.14.41.17.11.CRT.x64.Store.base",
"Microsoft.VisualStudio.InstrumentationEngine.ARM64",
"Microsoft.VisualStudio.InstrumentationEngine",
"Microsoft.VisualCpp.CRT.x64.OneCore.Desktop",
"Microsoft.VC.14.41.17.11.CRT.x64.OneCore.Desktop.base",
"Microsoft.VC.14.41.17.11.Tools.HostX86.TargetX64.base",
"Microsoft.VC.14.41.17.11.Props.x64",
"Microsoft.VC.14.41.17.11.Tools.Hostx86.Targetx64.Res.base",
"Win11SDK_10.0.22621",
"Microsoft.VisualCpp.Tools.HostX86.TargetX86",
"Microsoft.VC.14.41.17.11.Tools.HostX86.TargetX86.base",
"Microsoft.VC.14.41.17.11.Servicing.Compilers",
"Microsoft.VisualCpp.Redist.14.Latest",
"Microsoft.VisualCpp.Redist.14.Latest",
"Microsoft.VisualStudio.LiveShareApi",
"Microsoft.VisualStudio.ProjectSystem.Query",
"Microsoft.VisualStudio.Component.VC.Tools.ARM64EC",
"Microsoft.VisualCpp.CRT.ARM64EC.Store",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM64EC.v143",
"Microsoft.VC.14.41.17.11.CRT.ARM64EC.Store.base",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM64EC",
"Microsoft.VC.14.41.17.11.CRT.x86.Desktop.base",
"Microsoft.VisualCpp.CRT.x64.Desktop",
"Microsoft.VisualStudio.ProjectSystem",
"Microsoft.VisualStudio.Community.x86",
"Microsoft.VisualCpp.IFC.arm64",
"Microsoft.VisualCpp.Redist.14",
"Microsoft.VisualCpp.Redist.14",
"Microsoft.VisualCpp.Servicing.Redist",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE",
"Microsoft.VC.14.41.17.11.CRT.Headers.base",
"Microsoft.VC.14.41.17.11.Servicing.CrtHeaders",
"Microsoft.VC.14.41.17.11.Servicing",
"Microsoft.VisualStudio.Component.VC.CoreBuildTools",
"Microsoft.VisualStudio.VC.vcvars",
"Microsoft.VS.VC.vcvars.x86.Shortcuts",
"Microsoft.Windows.UniversalCRT.Redistributable.Msi",
"Microsoft.VS.VC.vcvars.x64.Shortcuts",
"Microsoft.VS.VC.vcvars.arm64_x64.Shortcuts",
"Microsoft.VisualStudio.Component.Windows10SDK",
"Microsoft.VisualStudio.VC.MSBuild.v170.x86.v143",
"Microsoft.VisualStudio.VC.MSBuild.v170.X86",
"Microsoft.VisualStudio.VC.MSBuild.v170.X64.v143",
"Microsoft.VisualStudio.VC.MSBuild.v170.X64",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM.v143",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM",
"Microsoft.VisualStudio.VC.MSBuild.v170.Base",
"Microsoft.VisualStudio.VC.MSBuild.v170.Base.Resources",
"Microsoft.VisualStudio.Workload.MSBuildTools",
"Microsoft.VisualStudio.Component.CoreBuildTools",
"Microsoft.VisualStudio.Setup.Configuration",
"Microsoft.VisualStudio.PackageGroup.Setup.Common",
"Microsoft.VisualStudio.Setup.WMIProvider",
"Microsoft.VisualStudio.Setup.Configuration.Interop",
"Microsoft.VisualStudio.PackageGroup.VsDevCmd",
"Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk",
"Microsoft.VisualStudio.VsDevCmd.Core.WinSdk",
"Microsoft.VisualStudio.VsDevCmd.Core.DotNet",
"Microsoft.VisualStudio.VC.DevCmd",
"Microsoft.VisualStudio.VC.DevCmd.Resources",
"Microsoft.VisualStudio.BuildTools.Resources",
"Microsoft.VisualStudio.Net.Eula.Resources",
"Microsoft.Build.Dependencies",
"Microsoft.NuGet.Build.Tasks.Setup",
"Microsoft.Build.FileTracker.Msi",
"Microsoft.Component.MSBuild",
"Microsoft.PythonTools.BuildCore.Vsix",
"Microsoft.VisualStudio.Component.Roslyn.Compiler",
"Microsoft.CodeAnalysis.Compilers",
"Microsoft.VisualStudio.NativeImageSupport",
"Microsoft.Build",
"Microsoft.VisualStudio.PackageGroup.NuGet",
"Microsoft.VisualStudio.NuGet.BuildTools"
]
}
]
================================================
FILE: test/fixtures/VS_2022_Community_workload.txt
================================================
[
{
"path": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community",
"version": "17.4.33213.308",
"packages": [
"Microsoft.VisualStudio.Product.Community",
"Microsoft.VisualStudio.PackageGroup.LiveShare.VSCore",
"Microsoft.VisualStudio.LiveShare.VSCore",
"Microsoft.VisualStudio.Workload.NativeDesktop",
"Microsoft.VisualStudio.Component.VC.ASAN",
"Microsoft.VisualCpp.ASAN.X86",
"Microsoft.VC.14.34.17.4.ASAN.X86.base",
"Microsoft.VC.14.34.17.4.ASAN.X64.base",
"Microsoft.VC.14.34.17.4.ASAN.Headers.base",
"Microsoft.VisualStudio.VC.IDE.Project.Factories",
"Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest",
"Microsoft.VisualStudio.VC.Ide.TestAdapterForGoogleTest",
"Microsoft.VisualStudio.Component.VC.TestAdapterForBoostTest",
"Microsoft.VisualStudio.VC.Ide.TestAdapterForBoostTest",
"Microsoft.VisualStudio.Component.VC.CMake.Project",
"Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.CMake",
"Microsoft.VisualStudio.VC.CMake",
"Microsoft.VisualStudio.VC.CMake.Project",
"Microsoft.VisualStudio.VC.CMake.Client",
"Microsoft.VisualStudio.VC.ExternalBuildFramework",
"Microsoft.VisualStudio.Component.VC.DiagnosticTools",
"Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
"Microsoft.VisualStudio.PackageGroup.TestTools.Native",
"Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
"Microsoft.VisualStudio.VC.Templates.UnitTest",
"Microsoft.VisualStudio.VC.UnitTest.Desktop.Build.Core",
"Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP",
"Microsoft.VisualStudio.VC.Templates.UnitTest.Resources",
"Microsoft.VisualStudio.VC.Templates.Desktop",
"Microsoft.VisualStudio.Component.Graphics",
"Microsoft.VisualStudio.Graphics.Viewers",
"Microsoft.VisualStudio.Graphics.Viewers.Resources",
"Microsoft.VisualStudio.Component.VC.ATL.ARM64",
"Microsoft.VisualCpp.ATL.ARM64",
"Microsoft.VC.14.34.17.4.ATL.ARM64.base",
"Microsoft.VisualStudio.Component.VC.ATL",
"Microsoft.VisualStudio.VC.Ide.ATL",
"Microsoft.VisualStudio.VC.Ide.ATL.Resources",
"Microsoft.VisualCpp.ATL.X86",
"Microsoft.VC.14.34.17.4.ATL.X86.base",
"Microsoft.VisualCpp.ATL.X64",
"Microsoft.VC.14.34.17.4.ATL.X64.base",
"Microsoft.VC.14.34.17.4.Props.ATLMFC",
"Microsoft.VisualCpp.ATL.Source",
"Microsoft.VC.14.34.17.4.ATL.Source.base",
"Microsoft.VisualCpp.ATL.Headers",
"Microsoft.VC.14.34.17.4.ATL.Headers.base",
"Microsoft.VC.14.34.17.4.Servicing.ATL",
"Microsoft.VisualStudio.Component.VC.Tools.ARM64",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM64.v143",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM64",
"Microsoft.VS.VC.vcvars.arm64.Shortcuts",
"Microsoft.VisualCpp.CA.Ext.Hostx64.TargetARM64",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.TargetARM64.base",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.TargetARM64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.TargetARM64",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.TargetARM64.base",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.TargetARM64.Res.base",
"Microsoft.VisualCpp.CA.Ext.HostARM64.TargetARM64",
"Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.TargetARM64.base",
"Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.TargetARM64.Res.base",
"Microsoft.VisualCpp.Tools.Hostx86.Targetarm64",
"Microsoft.VC.14.34.17.4.Tools.Hostx86.Targetarm64.base",
"Microsoft.VC.14.34.17.4.Tools.HostX86.TargetARM64.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetARM64",
"Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetARM64.base",
"Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetARM64.Res.base",
"Microsoft.VisualCpp.CRT.Redist.ARM64.OneCore.Desktop",
"Microsoft.VC.14.34.17.4.CRT.Redist.ARM64.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.ARM64",
"Microsoft.VC.14.34.17.4.CRT.Redist.ARM64.base",
"Microsoft.VisualCpp.CRT.ARM64.OneCore.Desktop",
"Microsoft.VC.14.34.17.4.CRT.ARM64.OneCore.Desktop.base",
"Microsoft.VC.14.34.17.4.CRT.ARM64.OneCore.Desktop.debug.base",
"Microsoft.VisualCpp.CRT.ARM64.Store",
"Microsoft.VC.14.34.17.4.CRT.ARM64.Store.base",
"Microsoft.VisualCpp.CRT.ARM64.Desktop",
"Microsoft.VC.14.34.17.4.CRT.ARM64.Desktop.base",
"Microsoft.VC.14.34.17.4.CRT.ARM64.Desktop.debug.base",
"Microsoft.VisualStudio.PackageGroup.VC.Tools.x64.ARM64",
"Microsoft.VisualCpp.Tools.Core",
"Microsoft.VisualCpp.PGO.ARM64",
"Microsoft.VC.14.34.17.4.PGO.ARM64.base",
"Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetarm64",
"Microsoft.VC.14.34.17.4.Premium.Tools.Hostx86.Targetarm64.base",
"Microsoft.VC.14.34.17.4.Prem.HostX86.TargetARM64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM64",
"Microsoft.VC.14.34.17.4.Premium.Tools.HostX64.TargetARM64.base",
"Microsoft.VC.14.34.17.4.Prem.HostX64.TargetARM64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.ARM64.Base",
"Microsoft.VC.14.34.17.4.Premium.Tools.ARM64.Base.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetARM64",
"Microsoft.VC.14.34.17.4.Tools.HostX64.TargetARM64.base",
"Microsoft.VC.14.34.17.4.Props.ARM64",
"Microsoft.VC.14.34.17.4.Tools.HostX64.TargetARM64.Res.base",
"Microsoft.VisualStudio.Component.VC.Tools.ARM64EC",
"Microsoft.VisualStudio.Component.Windows11SDK.22621",
"Win11SDK_10.0.22621",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM64EC.v143",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM64EC",
"Microsoft.VisualCpp.CRT.ARM64EC.Store",
"Microsoft.VC.14.34.17.4.CRT.ARM64EC.Store.base",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Microsoft.VisualCpp.CodeAnalysis.Extensions",
"Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx64",
"Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx64.base",
"Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx64.Res.base",
"Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx86",
"Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx86.base",
"Microsoft.VC.14.34.17.4.CA.Ext.HostARM64.Targetx86.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx64",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx64.base",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx86",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx86.base",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx86.Targetx86.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx64",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx64.base",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx86",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx86.base",
"Microsoft.VC.14.34.17.4.Servicing.CAExtensions",
"Microsoft.VC.14.34.17.4.CA.Ext.Hostx64.Targetx86.Res.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetX86",
"Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX86.base",
"Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetX64",
"Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX64.base",
"Microsoft.VC.14.34.17.4.Tools.HostX64.TargetX64.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetX86",
"Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetX86.base",
"Microsoft.VisualCpp.RuntimeDebug.14",
"Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetX64",
"Microsoft.VC.14.34.17.4.Tools.HostARM64.TargetX64.base",
"Microsoft.VisualCpp.RuntimeDebug.14.ARM64",
"Microsoft.VisualCpp.Redist.14.Latest",
"Microsoft.VisualCpp.Redist.14.Latest",
"Microsoft.VC.14.34.17.4.Tools.HostARM64.Targetx64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64",
"Microsoft.VC.14.34.17.4.Premium.Tools.HostX86.TargetX64.base",
"Microsoft.VC.14.34.17.4.Prem.Hostx86.Targetx64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86",
"Microsoft.VC.14.34.17.4.Premium.Tools.HostX86.TargetX86.base",
"Microsoft.VC.14.34.17.4.Prem.HostX86.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX86",
"Microsoft.VC.14.34.17.4.Premium.Tools.HostARM64.TargetX86.base",
"Microsoft.VC.14.34.17.4.Prem.HostARM64.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX64",
"Microsoft.VC.14.34.17.4.Premium.Tools.HostARM64.TargetX64.base",
"Microsoft.VC.14.34.17.4.Prem.HostARM64.Targetx64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86",
"Microsoft.VC.14.34.17.4.Premium.Tools.HostX64.TargetX86.base",
"Microsoft.VC.14.34.17.4.Prem.HostX64.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64",
"Microsoft.VC.14.34.17.4.Premium.Tools.HostX64.TargetX64.base",
"Microsoft.VC.14.34.17.4.Prem.HostX64.TargetX64.Res.base",
"Microsoft.VisualCpp.PGO.X86",
"Microsoft.VC.14.34.17.4.PGO.X86.base",
"Microsoft.VisualCpp.PGO.X64",
"Microsoft.VC.14.34.17.4.PGO.X64.base",
"Microsoft.VisualCpp.PGO.Headers",
"Microsoft.VC.14.34.17.4.PGO.Headers.base",
"Microsoft.VisualCpp.CRT.x86.Store",
"Microsoft.VC.14.34.17.4.CRT.x86.Store.base",
"Microsoft.VisualCpp.CRT.x86.OneCore.Desktop",
"Microsoft.VC.14.34.17.4.CRT.x86.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.x64.Store",
"Microsoft.VC.14.34.17.4.CRT.x64.Store.base",
"Microsoft.VisualCpp.CRT.x64.OneCore.Desktop",
"Microsoft.VC.14.34.17.4.CRT.x64.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop",
"Microsoft.VC.14.34.17.4.CRT.Redist.x86.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop",
"Microsoft.VC.14.34.17.4.CRT.Redist.x64.OneCore.Desktop.base",
"Microsoft.VisualStudio.PackageGroup.VC.Tools.x86",
"Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Res",
"Microsoft.VisualCpp.Tools.HostX86.TargetX64",
"Microsoft.VC.14.34.17.4.Tools.HostX86.TargetX64.base",
"Microsoft.VC.14.34.17.4.Props.x64",
"Microsoft.VC.14.34.17.4.Tools.Hostx86.Targetx64.Res.base",
"Microsoft.VisualCpp.Tools.HostX86.TargetX86.Res",
"Microsoft.VisualCpp.Tools.HostX86.TargetX86",
"Microsoft.VC.14.34.17.4.Tools.HostX86.TargetX86.base",
"Microsoft.VC.14.34.17.4.Servicing.Compilers",
"Microsoft.VC.14.34.17.4.Props.x86",
"Microsoft.VC.14.34.17.4.Props",
"Microsoft.VC.14.34.17.4.Tools.HostX86.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.Core.Resources",
"Microsoft.VisualCpp.Tools.Core.x86",
"Microsoft.VC.14.34.17.4.Tools.Core.Props",
"Microsoft.VisualCpp.DIA.SDK",
"Microsoft.VisualCpp.Servicing.DIASDK",
"Microsoft.VisualCpp.CRT.x86.Desktop",
"Microsoft.VC.14.34.17.4.CRT.x86.Desktop.base",
"Microsoft.VisualCpp.CRT.x64.Desktop",
"Microsoft.VC.14.34.17.4.CRT.x64.Desktop.base",
"Microsoft.VisualCpp.CRT.Source",
"Microsoft.VC.14.34.17.4.CRT.Source.base",
"Microsoft.VisualCpp.CRT.Redist.X86",
"Microsoft.VC.14.34.17.4.CRT.Redist.X86.base",
"Microsoft.VisualCpp.CRT.Redist.X64",
"Microsoft.VisualCpp.CRT.Redist.Resources",
"Microsoft.VC.14.34.17.4.CRT.Redist.X64.base",
"Microsoft.VisualCpp.CRT.Headers",
"Microsoft.VC.14.34.17.4.CRT.Headers.base",
"Microsoft.VC.14.34.17.4.Servicing.CrtHeaders",
"Microsoft.VC.14.34.17.4.Servicing",
"Microsoft.VisualStudio.Component.VC.CoreIde",
"Microsoft.VisualStudio.VC.Ide.Pro",
"Microsoft.VisualStudio.VC.Ide.Pro.Resources",
"Microsoft.VisualStudio.VC.Templates.General",
"Microsoft.VisualStudio.VC.Templates.General.Resources",
"Microsoft.VisualStudio.VC.Items.Pro",
"Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced",
"Microsoft.VisualStudio.VC.Ide.x64",
"Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express",
"Microsoft.VisualStudio.VC.vcvars",
"Microsoft.VS.VC.vcvars.x86.Shortcuts",
"Microsoft.VS.VC.vcvars.x64.Shortcuts",
"Microsoft.VS.VC.vcvars.arm64_x64.Shortcuts",
"Microsoft.VisualStudio.VC.MSBuild.v170.X64.v143",
"Microsoft.VisualStudio.VC.MSBuild.v170.X64",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM.v143",
"Microsoft.VisualStudio.VC.MSBuild.v170.ARM",
"Microsoft.VisualStudio.VC.MSBuild.v170.x86.v143",
"Microsoft.VisualStudio.VC.MSBuild.v170.X86",
"Microsoft.VisualStudio.VC.MSBuild.v170.Base",
"Microsoft.VisualStudio.VC.MSBuild.v170.Base.Resources",
"Microsoft.VisualStudio.VC.Ide.WinXPlus",
"Microsoft.VisualStudio.VC.Ide.Dskx",
"Microsoft.VisualStudio.VC.Ide.Dskx.Resources",
"Microsoft.VisualStudio.VC.Ide.Base",
"Microsoft.VisualStudio.VC.Ide.LanguageService",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.Scripts",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.PythonDistro",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.10",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.9",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.8",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.7",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.6",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.5",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.4",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.3",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.2",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.1",
"Microsoft.VisualStudio.VC.Ide.VCPkgDatabase",
"Microsoft.VisualStudio.VC.Ide.Core",
"Microsoft.VisualStudio.VC.Ide.ProjectSystem",
"Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources",
"Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine",
"Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources",
"Microsoft.VisualStudio.VC.Ide.LanguageService.Resources",
"Microsoft.VisualStudio.VC.Llvm.Base",
"Microsoft.VisualStudio.VC.Ide.Base.Resources",
"Microsoft.Net.PackageGroup.4.8.1.Redist",
"Microsoft.VisualStudio.Component.IntelliCode",
"Microsoft.VisualStudio.IntelliCode.CSharp",
"Microsoft.VisualStudio.IntelliCode",
"Component.Microsoft.VisualStudio.LiveShare.2022",
"Microsoft.VisualStudio.Component.Debugger.JustInTime",
"Microsoft.VisualStudio.Debugger.ImmersiveActivateHelper.Msi",
"Microsoft.VisualStudio.Debugger.JustInTime",
"Microsoft.VisualStudio.Debugger.JustInTime.Msi",
"Microsoft.VisualStudio.LiveShare.2022",
"Microsoft.Icecap.Analysis",
"Microsoft.Icecap.Analysis.Resources",
"Microsoft.Icecap.Analysis.Resources.Targeted",
"Microsoft.Icecap.Collection.Msi",
"Microsoft.Icecap.Collection.Msi.Targeted",
"Microsoft.Icecap.Collection.Msi.Resources",
"Microsoft.Icecap.Collection.Msi.Resources.Targeted",
"Microsoft.DiagnosticsHub.Instrumentation",
"Microsoft.DiagnosticsHub.Instrumentation.Targeted",
"Microsoft.DiagnosticsHub.CpuSampling",
"Microsoft.DiagnosticsHub.CpuSampling.Targeted",
"Microsoft.PackageGroup.DiagnosticsHub.Platform",
"Microsoft.VisualStudio.InstrumentationEngine.ARM64",
"Microsoft.VisualStudio.InstrumentationEngine",
"Microsoft.DiagnosticsHub.Runtime.ExternalDependencies",
"SQLiteCore",
"SQLiteCore.Targeted",
"Microsoft.DiagnosticsHub.Runtime.ExternalDependencies.Targeted",
"Microsoft.DiagnosticsHub.Runtime",
"Microsoft.DiagnosticsHub.Runtime.Targeted",
"Microsoft.DiagnosticsHub.Collection.ExternalDependencies.arm64",
"Microsoft.DiagnosticsHub.Collection",
"Microsoft.DiagnosticsHub.Collection.Service",
"Microsoft.VisualStudio.VC.Ide.MDD",
"Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager",
"Microsoft.VisualStudio.VisualC.Utilities",
"Microsoft.VisualStudio.VisualC.Utilities.Resources",
"Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager.Resources",
"Microsoft.VisualStudio.VC.Ide.ResourceEditor",
"Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources",
"Microsoft.VisualStudio.PackageGroup.TestTools.Core",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI",
"Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI",
"Microsoft.VisualStudio.TestTools.Pex.Common",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V1.CLI",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.Legacy",
"Microsoft.VisualStudio.PackageGroup.MinShell.Interop",
"Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Msi",
"Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Common",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips.Resources",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.TestSettings",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Professional",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Common",
"Microsoft.VisualStudio.TestTools.TP.Legacy.Common.Res",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Resources",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Agent",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE",
"Microsoft.VisualStudio.Cache.Service",
"Microsoft.VisualStudio.TestTools.TestWIExtension",
"Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI",
"Microsoft.VisualStudio.TestTools.TestPlatform.IDE",
"Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage",
"Microsoft.VisualStudio.PackageGroup.TestTools.DataCollectors",
"Microsoft.VisualStudio.Component.NuGet",
"Microsoft.CredentialProvider",
"Microsoft.VisualStudio.NuGet.Licenses",
"Microsoft.VisualStudio.Component.TextTemplating",
"Microsoft.VisualStudio.TextTemplating.MSBuild",
"Microsoft.VisualStudio.TextTemplating.Integration",
"Microsoft.VisualStudio.TextTemplating.Core",
"Microsoft.VisualStudio.TextTemplating.Integration.Resources",
"Microsoft.VisualCpp.CRT.ClickOnce.Msi",
"Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
"Microsoft.VisualStudio.InteractiveWindow",
"Microsoft.DiaSymReader.Native",
"Microsoft.VisualCpp.Redist.14",
"Microsoft.VisualCpp.Redist.14",
"Microsoft.VisualCpp.Servicing.Redist",
"Microsoft.VisualStudio.PackageGroup.StaticAnalysis",
"Microsoft.VisualStudio.StaticAnalysis.IDE",
"Microsoft.VisualStudio.StaticAnalysis.IDE.Resources",
"Microsoft.VisualStudio.StaticAnalysis.FxCop.Resources",
"Microsoft.VisualStudio.StaticAnalysis.auxil",
"Microsoft.VisualStudio.StaticAnalysis.auxil.Resources",
"Roslyn.VisualStudio.Setup.ServiceHub",
"Microsoft.Component.MSBuild",
"Microsoft.NuGet.Build.Tasks.Setup",
"Microsoft.VisualStudio.Component.Roslyn.Compiler",
"Microsoft.CodeAnalysis.Compilers",
"Microsoft.VisualStudio.Component.JavaScript.TypeScript",
"Microsoft.VisualStudio.JavaScript.ProjectSystem",
"Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions",
"Microsoft.VisualStudio.ProTools",
"sqlsysclrtypes",
"SQLCommon",
"Microsoft.VisualStudio.ProTools.Resources",
"Microsoft.VisualStudio.Web.Scaffolding",
"Microsoft.VisualStudio.WebToolsExtensions",
"Microsoft.VisualStudio.ConnectedServices.Core",
"Microsoft.VisualStudio.WebTools",
"Microsoft.VisualStudio.WebToolsExtensions.MSBuild",
"Microsoft.VisualStudio.WebTools.Resources",
"Microsoft.VisualStudio.WebTools.WSP.FSA",
"Microsoft.VisualStudio.WebTools.WSP.FSA.Resources",
"Microsoft.VisualStudio.PackageGroup.Debugger.Script",
"Microsoft.VisualStudio.Component.TypeScript.TSServer",
"Microsoft.VisualStudio.Package.TypeScript.TSServer",
"Microsoft.VisualStudio.PackageGroup.JavaScript.Language",
"Microsoft.VisualStudio.Package.NodeJs",
"TypeScript.Build",
"TypeScript.LanguageService",
"TypeScript.Tools",
"Microsoft.VisualStudio.PackageGroup.Community",
"Microsoft.VisualStudio.Community.VB.x86",
"Microsoft.VisualStudio.Community.VB.x64",
"Microsoft.VisualStudio.PackageGroup.Core",
"Microsoft.VisualStudio.CodeSense.Community",
"Microsoft.VisualStudio.TestTools.TeamFoundationClient",
"Microsoft.VisualStudio.PackageGroup.Debugger.Core",
"Microsoft.VisualStudio.Debugger.BrokeredServices",
"Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost",
"Microsoft.VisualStudio.Debugger.AzureAttach",
"Microsoft.VisualStudio.Web.Azure.Common",
"Microsoft.WebTools.Shared",
"Microsoft.WebTools.DotNet.Core.ItemTemplates",
"Microsoft.VisualStudio.PackageGroup.Debugger.TimeTravel.Replay",
"Microsoft.VisualStudio.VC.Ide.Debugger",
"Microsoft.VisualStudio.VC.Ide.Debugger.Concord",
"Microsoft.VisualStudio.VC.Ide.Debugger.Concord.Resources",
"Microsoft.VisualStudio.VC.Ide.Debugger.Resources",
"Microsoft.VisualStudio.VC.Ide.Common",
"Microsoft.VisualStudio.VC.Ide.Common.Resources",
"Microsoft.VisualStudio.Debugger.CollectionAgents",
"Microsoft.VisualStudio.Debugger.Parallel",
"Microsoft.VisualStudio.Debugger.Parallel.Resources",
"Microsoft.VisualStudio.Debugger.Managed",
"Microsoft.CodeAnalysis.ExpressionEvaluator",
"Microsoft.CodeAnalysis.VisualStudio.Setup",
"Microsoft.VisualStudio.Debugger.Concord.Managed",
"Microsoft.VisualStudio.Debugger.Concord.Managed.Resources",
"Microsoft.VisualStudio.Debugger.Managed.Resources",
"Microsoft.VisualStudio.Debugger.TargetComposition",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote.arm64",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote",
"Microsoft.VisualStudio.Debugger.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote",
"Microsoft.VisualStudio.Debugger.Remote.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM64",
"Microsoft.VisualStudio.Debugger.Remote.ARM",
"Microsoft.VisualStudio.Debugger.Concord.Remote.ARM",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM",
"Microsoft.VisualStudio.Debugger.Remote.Resources.ARM",
"Microsoft.VisualStudio.Debugger.Remote.Resources.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote.Resources",
"Microsoft.VisualStudio.Debugger",
"Microsoft.VisualStudio.VC.MSVCDis",
"Microsoft.IntelliTrace.DiagnosticsHub",
"Microsoft.VisualStudio.Debugger.Concord",
"Microsoft.VisualStudio.Debugger.Concord.Resources",
"Microsoft.VisualStudio.Debugger.Resources",
"Microsoft.VisualStudio.Debugger.Package.DiagHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.PackageGroup.ClientDiagnostics",
"Microsoft.VisualStudio.AppResponsiveness",
"Microsoft.VisualStudio.AppResponsiveness.Targeted",
"Microsoft.VisualStudio.AppResponsiveness.Resources",
"Microsoft.VisualStudio.ClientDiagnostics",
"Microsoft.VisualStudio.ClientDiagnostics.Targeted",
"Microsoft.VisualStudio.ClientDiagnostics.Resources",
"Microsoft.VisualStudio.PackageGroup.CommunityCore",
"Microsoft.VisualStudio.ProjectSystem.Full",
"Microsoft.VisualStudio.LiveShareApi",
"Microsoft.VisualStudio.ProjectSystem.Query",
"Microsoft.VisualStudio.ProjectSystem",
"Microsoft.VisualStudio.Community.x86",
"Microsoft.VisualStudio.Community.x64",
"Microsoft.VisualStudio.Community.Msi.Resources",
"Microsoft.VisualStudio.Community.Msi",
"Microsoft.VisualStudio.Community.Shared.Msi",
"Microsoft.VisualStudio.Devenv.Msi",
"Microsoft.VisualStudio.Devenv.Shared.Msi",
"Microsoft.VisualStudio.MinShell.Interop.Msi",
"Microsoft.VisualStudio.MinShell.Interop.Shared.Msi",
"Microsoft.VisualStudio.Editors",
"Microsoft.VisualStudio.Workload.CoreEditor",
"Microsoft.VisualStudio.Component.CoreEditor",
"Microsoft.VisualStudio.PackageGroup.CoreEditor",
"Microsoft.WebView2",
"Microsoft.VisualStudio.ScriptedHost",
"Microsoft.VisualStudio.ScriptedHost.Targeted",
"Microsoft.VisualCpp.Tools.Common.UtilsPrereq",
"Microsoft.VisualCpp.Tools.Common.Utils",
"Microsoft.VisualCpp.Tools.Common.Utils.Resources",
"Microsoft.VisualStudio.PackageGroup.VsDevCmd",
"Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk",
"Microsoft.VisualStudio.VsDevCmd.Core.WinSdk",
"Microsoft.VisualStudio.VsDevCmd.Core.DotNet",
"Microsoft.VisualStudio.VC.DevCmd",
"Microsoft.VisualStudio.VC.DevCmd.Resources",
"Microsoft.VisualStudio.VirtualTree",
"Microsoft.DiaSymReader",
"Microsoft.Build.Dependencies",
"Microsoft.Build.FileTracker.Msi",
"Microsoft.Build",
"Microsoft.VisualStudio.PackageGroup.NuGet",
"Microsoft.DataAI.NuGetRecommender",
"Microsoft.VisualStudio.NuGet.Core",
"Microsoft.Build.Arm64",
"Microsoft.Build.UnGAC",
"Microsoft.VisualStudio.TextMateGrammars",
"Microsoft.VisualStudio.Platform.Markdown",
"Microsoft.VisualStudio.Platform.CrossRepositorySearch",
"Microsoft.VisualStudio.PackageGroup.TeamExplorer.Common",
"Microsoft.VisualStudio.TeamExplorer",
"Microsoft.VisualStudio.PackageGroup.ServiceHub",
"Microsoft.ServiceHub.Node",
"Microsoft.ServiceHub.Managed",
"Microsoft.ServiceHub.arm64",
"Microsoft.VisualStudio.ProjectServices",
"Microsoft.VisualStudio.OpenFolder.VSIX",
"Microsoft.VisualStudio.FileHandler.Msi",
"Microsoft.VisualStudio.FileHandler.Msi",
"Microsoft.VisualStudio.PackageGroup.MinShell",
"Microsoft.VisualStudio.MinShell.Msi",
"Microsoft.VisualStudio.MinShell.Shared.Msi",
"Microsoft.VisualStudio.MinShell.Msi.Resources",
"Microsoft.VisualStudio.MinShell.Interop",
"CoreEditorFonts",
"Microsoft.VisualStudio.Log",
"Microsoft.VisualStudio.Log.Targeted",
"Microsoft.VisualStudio.Log.Resources",
"Microsoft.VisualStudio.Finalizer",
"Microsoft.VisualStudio.Devenv",
"Microsoft.VisualStudio.Devenv.Resources",
"Microsoft.VisualStudio.CoreEditor",
"Microsoft.VisualStudio.Navigation.RichCodeNav",
"Microsoft.VisualStudio.Platform.NavigateTo",
"Microsoft.VisualStudio.Connected",
"SQLitePCLRaw",
"SQLitePCLRaw.Targeted",
"Microsoft.VisualStudio.Connected.Auto",
"Microsoft.VisualStudio.Connected.Auto.Resources",
"Microsoft.VisualStudio.AzureSDK",
"Microsoft.VisualStudio.PerfLib",
"Microsoft.VisualStudio.Connected.Resources",
"Microsoft.Net.PackageGroup.4.8.Redist",
"Microsoft.VisualStudio.PackageGroup.Progression",
"Microsoft.VisualStudio.PerformanceProvider",
"Microsoft.VisualStudio.GraphModel",
"Microsoft.VisualStudio.GraphProvider",
"Microsoft.VisualStudio.Community.VB.Targeted",
"Microsoft.VisualStudio.Community.VB.Neutral",
"Microsoft.VisualStudio.Community.CSharp.Targeted",
"Microsoft.VisualStudio.Community.CSharp.Neutral",
"Microsoft.VisualStudio.Community.ProductArch.TargetedExtra",
"Microsoft.VisualStudio.Community.ProductArch.Targeted",
"Microsoft.VisualStudio.Community.ProductArch.NeutralExtra",
"Microsoft.DiaSymReader.PortablePdb",
"Microsoft.IntelliTrace.CollectorCab",
"Microsoft.VisualStudio.Community.VB.Resources.Targeted",
"Microsoft.VisualStudio.Community.VB.Resources.Neutral",
"Microsoft.VisualStudio.Community.CSharp.Resources.Targeted",
"Microsoft.VisualStudio.Community.CSharp.Resources.Neutral",
"Microsoft.VisualStudio.Community.ProductArch.Resources.Targeted",
"Microsoft.VisualStudio.Community.ProductArch.Resources.NeutralExtra",
"Microsoft.VisualStudio.Net.Eula.Resources",
"Microsoft.VisualStudio.Community.ProductArch.Resources.Neutral",
"Microsoft.VisualStudio.WebSiteProject.DTE",
"Microsoft.VisualStudio.Diagnostics.AspNetHelper",
"Microsoft.VisualStudio.Diagnostics.AspNetHelper.Standard",
"Microsoft.MSHtml",
"Microsoft.VisualStudio.Platform.CallHierarchy",
"Microsoft.VisualStudio.Community.ProductArch.Neutral",
"Microsoft.VisualStudio.MinShell",
"Microsoft.VisualStudio.VsWebProtocolSelector.Msi",
"Microsoft.Net.6.WindowsDesktop.Runtime",
"Microsoft.Net.6.Runtime",
"Microsoft.VisualStudio.PackageGroup.Setup.Common",
"Microsoft.VisualStudio.Setup.WMIProvider",
"Microsoft.VisualStudio.Setup.Configuration.Interop",
"Microsoft.VisualStudio.Setup.Configuration",
"Microsoft.VisualStudio.Extensibility.Container",
"Microsoft.VisualStudio.LanguageServer",
"Microsoft.VisualStudio.Platform.Terminal",
"Microsoft.VisualStudio.MefHosting",
"Microsoft.VisualStudio.Initializer",
"Microsoft.VisualStudio.ExtensionManager",
"Microsoft.VisualStudio.Platform.Editor",
"Microsoft.VisualStudio.MinShell.Targeted",
"Microsoft.VisualStudio.NativeImageSupport",
"Microsoft.VisualStudio.Devenv.Config",
"Microsoft.VisualStudio.MinShell.Resources.arm64",
"Microsoft.VisualStudio.MinShell.Auto",
"Microsoft.VisualStudio.MinShell.Auto.Resources",
"Microsoft.VisualStudio.Branding.Community"
]
}
]
================================================
FILE: test/fixtures/VS_2026_Community_workload.txt
================================================
[
{
"path": "C:\\Program Files\\Microsoft Visual Studio\\2026\\Community",
"version": "18.0.1000.100",
"packages": [
"Microsoft.VisualStudio.Product.Community",
"Microsoft.VisualStudio.PackageGroup.LiveShare.VSCore",
"Microsoft.VisualStudio.LiveShare.VSCore",
"Microsoft.VisualStudio.Workload.NativeDesktop",
"Microsoft.VisualStudio.Component.VC.ASAN",
"Microsoft.VisualCpp.ASAN.X86",
"Microsoft.VC.14.50.18.0.ASAN.X86.base",
"Microsoft.VC.14.50.18.0.ASAN.X64.base",
"Microsoft.VC.14.50.18.0.ASAN.Headers.base",
"Microsoft.VisualStudio.VC.IDE.Project.Factories",
"Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest",
"Microsoft.VisualStudio.VC.Ide.TestAdapterForGoogleTest",
"Microsoft.VisualStudio.Component.VC.TestAdapterForBoostTest",
"Microsoft.VisualStudio.VC.Ide.TestAdapterForBoostTest",
"Microsoft.VisualStudio.Component.VC.CMake.Project",
"Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.CMake",
"Microsoft.VisualStudio.VC.CMake",
"Microsoft.VisualStudio.VC.CMake.Project",
"Microsoft.VisualStudio.VC.CMake.Client",
"Microsoft.VisualStudio.VC.ExternalBuildFramework",
"Microsoft.VisualStudio.Component.VC.DiagnosticTools",
"Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
"Microsoft.VisualStudio.PackageGroup.TestTools.Native",
"Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
"Microsoft.VisualStudio.VC.Templates.UnitTest",
"Microsoft.VisualStudio.VC.UnitTest.Desktop.Build.Core",
"Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP",
"Microsoft.VisualStudio.VC.Templates.UnitTest.Resources",
"Microsoft.VisualStudio.VC.Templates.Desktop",
"Microsoft.VisualStudio.Component.Graphics",
"Microsoft.VisualStudio.Graphics.Viewers",
"Microsoft.VisualStudio.Graphics.Viewers.Resources",
"Microsoft.VisualStudio.Component.VC.ATL.ARM64",
"Microsoft.VisualCpp.ATL.ARM64",
"Microsoft.VC.14.50.18.0.ATL.ARM64.base",
"Microsoft.VisualStudio.Component.VC.ATL",
"Microsoft.VisualStudio.VC.Ide.ATL",
"Microsoft.VisualStudio.VC.Ide.ATL.Resources",
"Microsoft.VisualCpp.ATL.X86",
"Microsoft.VC.14.50.18.0.ATL.X86.base",
"Microsoft.VisualCpp.ATL.X64",
"Microsoft.VC.14.50.18.0.ATL.X64.base",
"Microsoft.VC.14.50.18.0.Props.ATLMFC",
"Microsoft.VisualCpp.ATL.Source",
"Microsoft.VC.14.50.18.0.ATL.Source.base",
"Microsoft.VisualCpp.ATL.Headers",
"Microsoft.VC.14.50.18.0.ATL.Headers.base",
"Microsoft.VC.14.50.18.0.Servicing.ATL",
"Microsoft.VisualStudio.Component.VC.Tools.ARM64",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM64.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM64",
"Microsoft.VS.VC.vcvars.arm64.Shortcuts",
"Microsoft.VisualCpp.CA.Ext.Hostx64.TargetARM64",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.TargetARM64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.TargetARM64",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.TargetARM64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.TargetARM64.Res.base",
"Microsoft.VisualCpp.CA.Ext.HostARM64.TargetARM64",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.TargetARM64.Res.base",
"Microsoft.VisualCpp.Tools.Hostx86.Targetarm64",
"Microsoft.VC.14.50.18.0.Tools.Hostx86.Targetarm64.base",
"Microsoft.VC.14.50.18.0.Tools.HostX86.TargetARM64.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetARM64",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetARM64.Res.base",
"Microsoft.VisualCpp.CRT.Redist.ARM64.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.Redist.ARM64.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.ARM64",
"Microsoft.VC.14.50.18.0.CRT.Redist.ARM64.base",
"Microsoft.VisualCpp.CRT.ARM64.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.ARM64.OneCore.Desktop.base",
"Microsoft.VC.14.50.18.0.CRT.ARM64.OneCore.Desktop.debug.base",
"Microsoft.VisualCpp.CRT.ARM64.Store",
"Microsoft.VC.14.50.18.0.CRT.ARM64.Store.base",
"Microsoft.VisualCpp.CRT.ARM64.Desktop",
"Microsoft.VC.14.50.18.0.CRT.ARM64.Desktop.base",
"Microsoft.VC.14.50.18.0.CRT.ARM64.Desktop.debug.base",
"Microsoft.VisualStudio.PackageGroup.VC.Tools.x64.ARM64",
"Microsoft.VisualCpp.Tools.Core",
"Microsoft.VisualCpp.PGO.ARM64",
"Microsoft.VC.14.50.18.0.PGO.ARM64.base",
"Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetarm64",
"Microsoft.VC.14.50.18.0.Premium.Tools.Hostx86.Targetarm64.base",
"Microsoft.VC.14.50.18.0.Prem.HostX86.TargetARM64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM64",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.Prem.HostX64.TargetARM64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.ARM64.Base",
"Microsoft.VC.14.50.18.0.Premium.Tools.ARM64.Base.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetARM64",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.Props.ARM64",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetARM64.Res.base",
"Microsoft.VisualStudio.Component.VC.Tools.ARM64EC",
"Microsoft.VisualStudio.Component.Windows11SDK.26100",
"Win11SDK_10.0.26100",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM64EC.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM64EC",
"Microsoft.VisualCpp.CRT.ARM64EC.Store",
"Microsoft.VC.14.50.18.0.CRT.ARM64EC.Store.base",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Microsoft.VisualCpp.CodeAnalysis.Extensions",
"Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx64",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.Targetx64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.Targetx64.Res.base",
"Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx86",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.Targetx86.base",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.Targetx86.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx64",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.Targetx64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.Targetx64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx86",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.Targetx86.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.Targetx86.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx64",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.Targetx64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.Targetx64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx86",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.Targetx86.base",
"Microsoft.VC.14.50.18.0.Servicing.CAExtensions",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.Targetx86.Res.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetX86",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetX86.base",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetX64",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetX64.base",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetX64.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetX86",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetX86.base",
"Microsoft.VisualCpp.RuntimeDebug.14",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetX64",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetX64.base",
"Microsoft.VisualCpp.RuntimeDebug.14.ARM64",
"Microsoft.VisualCpp.Redist.14.Latest",
"Microsoft.VisualCpp.Redist.14.Latest",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.Targetx64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX86.TargetX64.base",
"Microsoft.VC.14.50.18.0.Prem.Hostx86.Targetx64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX86.TargetX86.base",
"Microsoft.VC.14.50.18.0.Prem.HostX86.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX86",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostARM64.TargetX86.base",
"Microsoft.VC.14.50.18.0.Prem.HostARM64.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX64",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostARM64.TargetX64.base",
"Microsoft.VC.14.50.18.0.Prem.HostARM64.Targetx64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX64.TargetX86.base",
"Microsoft.VC.14.50.18.0.Prem.HostX64.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX64.TargetX64.base",
"Microsoft.VC.14.50.18.0.Prem.HostX64.TargetX64.Res.base",
"Microsoft.VisualCpp.PGO.X86",
"Microsoft.VC.14.50.18.0.PGO.X86.base",
"Microsoft.VisualCpp.PGO.X64",
"Microsoft.VC.14.50.18.0.PGO.X64.base",
"Microsoft.VisualCpp.PGO.Headers",
"Microsoft.VC.14.50.18.0.PGO.Headers.base",
"Microsoft.VisualCpp.CRT.x86.Store",
"Microsoft.VC.14.50.18.0.CRT.x86.Store.base",
"Microsoft.VisualCpp.CRT.x86.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.x86.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.x64.Store",
"Microsoft.VC.14.50.18.0.CRT.x64.Store.base",
"Microsoft.VisualCpp.CRT.x64.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.x64.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.Redist.x86.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.Redist.x64.OneCore.Desktop.base",
"Microsoft.VisualStudio.PackageGroup.VC.Tools.x86",
"Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Res",
"Microsoft.VisualCpp.Tools.HostX86.TargetX64",
"Microsoft.VC.14.50.18.0.Tools.HostX86.TargetX64.base",
"Microsoft.VC.14.50.18.0.Props.x64",
"Microsoft.VC.14.50.18.0.Tools.Hostx86.Targetx64.Res.base",
"Microsoft.VisualCpp.Tools.HostX86.TargetX86.Res",
"Microsoft.VisualCpp.Tools.HostX86.TargetX86",
"Microsoft.VC.14.50.18.0.Tools.HostX86.TargetX86.base",
"Microsoft.VC.14.50.18.0.Servicing.Compilers",
"Microsoft.VC.14.50.18.0.Props.x86",
"Microsoft.VC.14.50.18.0.Props",
"Microsoft.VC.14.50.18.0.Tools.HostX86.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.Core.Resources",
"Microsoft.VisualCpp.Tools.Core.x86",
"Microsoft.VC.14.50.18.0.Tools.Core.Props",
"Microsoft.VisualCpp.DIA.SDK",
"Microsoft.VisualCpp.Servicing.DIASDK",
"Microsoft.VisualCpp.CRT.x86.Desktop",
"Microsoft.VC.14.50.18.0.CRT.x86.Desktop.base",
"Microsoft.VisualCpp.CRT.x64.Desktop",
"Microsoft.VC.14.50.18.0.CRT.x64.Desktop.base",
"Microsoft.VisualCpp.CRT.Source",
"Microsoft.VC.14.50.18.0.CRT.Source.base",
"Microsoft.VisualCpp.CRT.Redist.X86",
"Microsoft.VC.14.50.18.0.CRT.Redist.X86.base",
"Microsoft.VisualCpp.CRT.Redist.X64",
"Microsoft.VisualCpp.CRT.Redist.Resources",
"Microsoft.VC.14.50.18.0.CRT.Redist.X64.base",
"Microsoft.VisualCpp.CRT.Headers",
"Microsoft.VC.14.50.18.0.CRT.Headers.base",
"Microsoft.VC.14.50.18.0.Servicing.CrtHeaders",
"Microsoft.VC.14.50.18.0.Servicing",
"Microsoft.VisualStudio.Component.VC.CoreIde",
"Microsoft.VisualStudio.VC.Ide.Pro",
"Microsoft.VisualStudio.VC.Ide.Pro.Resources",
"Microsoft.VisualStudio.VC.Templates.General",
"Microsoft.VisualStudio.VC.Templates.General.Resources",
"Microsoft.VisualStudio.VC.Items.Pro",
"Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced",
"Microsoft.VisualStudio.VC.Ide.x64",
"Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express",
"Microsoft.VisualStudio.VC.vcvars",
"Microsoft.VS.VC.vcvars.x86.Shortcuts",
"Microsoft.VS.VC.vcvars.x64.Shortcuts",
"Microsoft.VS.VC.vcvars.arm64_x64.Shortcuts",
"Microsoft.VisualStudio.VC.MSBuild.v180.X64.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.X64",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM",
"Microsoft.VisualStudio.VC.MSBuild.v180.x86.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.X86",
"Microsoft.VisualStudio.VC.MSBuild.v180.Base",
"Microsoft.VisualStudio.VC.MSBuild.v180.Base.Resources",
"Microsoft.VisualStudio.VC.Ide.WinXPlus",
"Microsoft.VisualStudio.VC.Ide.Dskx",
"Microsoft.VisualStudio.VC.Ide.Dskx.Resources",
"Microsoft.VisualStudio.VC.Ide.Base",
"Microsoft.VisualStudio.VC.Ide.LanguageService",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.Scripts",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.PythonDistro",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.10",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.9",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.8",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.7",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.6",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.5",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.4",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.3",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.2",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.1",
"Microsoft.VisualStudio.VC.Ide.VCPkgDatabase",
"Microsoft.VisualStudio.VC.Ide.Core",
"Microsoft.VisualStudio.VC.Ide.ProjectSystem",
"Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources",
"Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine",
"Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources",
"Microsoft.VisualStudio.VC.Ide.LanguageService.Resources",
"Microsoft.VisualStudio.VC.Llvm.Base",
"Microsoft.VisualStudio.VC.Ide.Base.Resources",
"Microsoft.Net.PackageGroup.4.8.1.Redist",
"Microsoft.VisualStudio.Component.IntelliCode",
"Microsoft.VisualStudio.IntelliCode.CSharp",
"Microsoft.VisualStudio.IntelliCode",
"Component.Microsoft.VisualStudio.LiveShare.2026",
"Microsoft.VisualStudio.Component.Debugger.JustInTime",
"Microsoft.VisualStudio.Debugger.ImmersiveActivateHelper.Msi",
"Microsoft.VisualStudio.Debugger.JustInTime",
"Microsoft.VisualStudio.Debugger.JustInTime.Msi",
"Microsoft.VisualStudio.LiveShare.2026",
"Microsoft.Icecap.Analysis",
"Microsoft.Icecap.Analysis.Resources",
"Microsoft.Icecap.Analysis.Resources.Targeted",
"Microsoft.Icecap.Collection.Msi",
"Microsoft.Icecap.Collection.Msi.Targeted",
"Microsoft.Icecap.Collection.Msi.Resources",
"Microsoft.Icecap.Collection.Msi.Resources.Targeted",
"Microsoft.DiagnosticsHub.Instrumentation",
"Microsoft.DiagnosticsHub.Instrumentation.Targeted",
"Microsoft.DiagnosticsHub.CpuSampling",
"Microsoft.DiagnosticsHub.CpuSampling.Targeted",
"Microsoft.PackageGroup.DiagnosticsHub.Platform",
"Microsoft.VisualStudio.InstrumentationEngine.ARM64",
"Microsoft.VisualStudio.InstrumentationEngine",
"Microsoft.DiagnosticsHub.Runtime.ExternalDependencies",
"SQLiteCore",
"SQLiteCore.Targeted",
"Microsoft.DiagnosticsHub.Runtime.ExternalDependencies.Targeted",
"Microsoft.DiagnosticsHub.Runtime",
"Microsoft.DiagnosticsHub.Runtime.Targeted",
"Microsoft.DiagnosticsHub.Collection.ExternalDependencies.arm64",
"Microsoft.DiagnosticsHub.Collection",
"Microsoft.DiagnosticsHub.Collection.Service",
"Microsoft.VisualStudio.VC.Ide.MDD",
"Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager",
"Microsoft.VisualStudio.VisualC.Utilities",
"Microsoft.VisualStudio.VisualC.Utilities.Resources",
"Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager.Resources",
"Microsoft.VisualStudio.VC.Ide.ResourceEditor",
"Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources",
"Microsoft.VisualStudio.PackageGroup.TestTools.Core",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI",
"Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI",
"Microsoft.VisualStudio.TestTools.Pex.Common",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V1.CLI",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.Legacy",
"Microsoft.VisualStudio.PackageGroup.MinShell.Interop",
"Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Msi",
"Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Common",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips.Resources",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.TestSettings",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Professional",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Common",
"Microsoft.VisualStudio.TestTools.TP.Legacy.Common.Res",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Resources",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Agent",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE",
"Microsoft.VisualStudio.Cache.Service",
"Microsoft.VisualStudio.TestTools.TestWIExtension",
"Microsoft.VisualStudio.TestTools.TestWIExtension.Res",
"Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI",
"Microsoft.VisualStudio.TestTools.TP.V1.CLI.Resources",
"Microsoft.VisualStudio.TestTools.TestPlatform.IDE",
"Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage",
"Microsoft.VisualStudio.PackageGroup.TestTools.DataCollectors",
"Microsoft.VisualStudio.Component.NuGet",
"Microsoft.CredentialProvider",
"Microsoft.VisualStudio.NuGet.Licenses",
"Microsoft.VisualStudio.Component.TextTemplating",
"Microsoft.VisualStudio.TextTemplating.MSBuild",
"Microsoft.VisualStudio.TextTemplating.Integration",
"Microsoft.VisualStudio.TextTemplating.Core",
"Microsoft.VisualStudio.TextTemplating.Integration.Resources",
"Microsoft.VisualCpp.CRT.ClickOnce.Msi",
"Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
"Microsoft.VisualStudio.InteractiveWindow",
"Microsoft.DiaSymReader.Native",
"Microsoft.VisualCpp.Redist.14",
"Microsoft.VisualCpp.Redist.14",
"Microsoft.VisualCpp.Servicing.Redist",
"Microsoft.VisualStudio.PackageGroup.StaticAnalysis",
"Microsoft.VisualStudio.StaticAnalysis.IDE",
"Microsoft.VisualStudio.StaticAnalysis.IDE.Resources",
"Microsoft.VisualStudio.StaticAnalysis.FxCop.Resources",
"Microsoft.VisualStudio.StaticAnalysis.auxil",
"Microsoft.VisualStudio.StaticAnalysis.auxil.Resources",
"Roslyn.VisualStudio.Setup.ServiceHub",
"Microsoft.Component.MSBuild",
"Microsoft.NuGet.Build.Tasks.Setup",
"Microsoft.VisualStudio.Component.Roslyn.Compiler",
"Microsoft.CodeAnalysis.Compilers",
"Microsoft.VisualStudio.Component.JavaScript.TypeScript",
"Microsoft.VisualStudio.JavaScript.ProjectSystem",
"Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions",
"Microsoft.VisualStudio.ProTools",
"sqlsysclrtypes",
"SQLCommon",
"Microsoft.VisualStudio.ProTools.Resources",
"Microsoft.VisualStudio.Web.Scaffolding",
"Microsoft.VisualStudio.WebToolsExtensions",
"Microsoft.VisualStudio.ConnectedServices.Core",
"Microsoft.VisualStudio.WebTools",
"Microsoft.VisualStudio.WebToolsExtensions.MSBuild",
"Microsoft.VisualStudio.WebTools.Resources",
"Microsoft.VisualStudio.WebTools.WSP.FSA",
"Microsoft.VisualStudio.WebTools.WSP.FSA.Resources",
"Microsoft.VisualStudio.PackageGroup.Debugger.Script",
"Microsoft.VisualStudio.Component.TypeScript.TSServer",
"Microsoft.VisualStudio.Package.TypeScript.TSServer",
"Microsoft.VisualStudio.PackageGroup.JavaScript.Language",
"Microsoft.VisualStudio.Package.NodeJs",
"TypeScript.Build",
"TypeScript.LanguageService",
"TypeScript.Tools",
"Microsoft.VisualStudio.PackageGroup.Community",
"Microsoft.VisualStudio.Community.VB.x86",
"Microsoft.VisualStudio.Community.VB.x64",
"Microsoft.VisualStudio.PackageGroup.Core",
"Microsoft.VisualStudio.CodeSense.Community",
"Microsoft.VisualStudio.TestTools.TeamFoundationClient",
"Microsoft.VisualStudio.PackageGroup.Debugger.Core",
"Microsoft.VisualStudio.Debugger.BrokeredServices",
"Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost",
"Microsoft.VisualStudio.Debugger.AzureAttach",
"Microsoft.VisualStudio.Web.Azure.Common",
"Microsoft.WebTools.Shared",
"Microsoft.WebTools.DotNet.Core.ItemTemplates",
"Microsoft.VisualStudio.PackageGroup.Debugger.TimeTravel.Replay",
"Microsoft.VisualStudio.VC.Ide.Debugger",
"Microsoft.VisualStudio.VC.Ide.Debugger.Concord",
"Microsoft.VisualStudio.VC.Ide.Debugger.Concord.Resources",
"Microsoft.VisualStudio.VC.Ide.Debugger.Resources",
"Microsoft.VisualStudio.VC.Ide.Common",
"Microsoft.VisualStudio.VC.Ide.Common.Resources",
"Microsoft.VisualStudio.Debugger.CollectionAgents",
"Microsoft.VisualStudio.Debugger.Parallel",
"Microsoft.VisualStudio.Debugger.Parallel.Resources",
"Microsoft.VisualStudio.Debugger.Managed",
"Microsoft.CodeAnalysis.ExpressionEvaluator",
"Microsoft.CodeAnalysis.VisualStudio.Setup",
"Microsoft.VisualStudio.Debugger.Concord.Managed",
"Microsoft.VisualStudio.Debugger.Concord.Managed.Resources",
"Microsoft.VisualStudio.Debugger.Managed.Resources",
"Microsoft.VisualStudio.Debugger.TargetComposition",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote.arm64",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote",
"Microsoft.VisualStudio.Debugger.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote",
"Microsoft.VisualStudio.Debugger.Remote.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM64",
"Microsoft.VisualStudio.Debugger.Remote.Resources.ARM",
"Microsoft.VisualStudio.Debugger.Remote.Resources.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote.Resources",
"Microsoft.VisualStudio.Debugger",
"Microsoft.VisualStudio.VC.MSVCDis",
"Microsoft.IntelliTrace.DiagnosticsHub",
"Microsoft.VisualStudio.Debugger.Concord",
"Microsoft.VisualStudio.Debugger.Concord.Resources",
"Microsoft.VisualStudio.Debugger.Resources",
"Microsoft.VisualStudio.Debugger.Package.DiagHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.PackageGroup.ClientDiagnostics",
"Microsoft.VisualStudio.AppResponsiveness",
"Microsoft.VisualStudio.AppResponsiveness.Targeted",
"Microsoft.VisualStudio.AppResponsiveness.Resources",
"Microsoft.VisualStudio.ClientDiagnostics",
"Microsoft.VisualStudio.ClientDiagnostics.Targeted",
"Microsoft.VisualStudio.ClientDiagnostics.Resources",
"Microsoft.VisualStudio.PackageGroup.CommunityCore",
"Microsoft.VisualStudio.ProjectSystem.Full",
"Microsoft.VisualStudio.LiveShareApi",
"Microsoft.VisualStudio.ProjectSystem.Query",
"Microsoft.VisualStudio.ProjectSystem",
"Microsoft.VisualStudio.Community.x86",
"Microsoft.VisualStudio.Community.x64",
"Microsoft.VisualStudio.Community.Msi.Resources",
"Microsoft.VisualStudio.Community.Msi",
"Microsoft.VisualStudio.Community.Shared.Msi",
"Microsoft.VisualStudio.Devenv.Msi",
"Microsoft.VisualStudio.Devenv.Shared.Msi",
"Microsoft.VisualStudio.MinShell.Interop.Msi",
"Microsoft.VisualStudio.MinShell.Interop.Shared.Msi",
"Microsoft.VisualStudio.Editors",
"Microsoft.VisualStudio.Workload.CoreEditor",
"Microsoft.VisualStudio.Component.CoreEditor",
"Microsoft.VisualStudio.PackageGroup.CoreEditor",
"Microsoft.WebView2",
"Microsoft.VisualStudio.ScriptedHost",
"Microsoft.VisualStudio.ScriptedHost.Targeted",
"Microsoft.VisualCpp.Tools.Common.UtilsPrereq",
"Microsoft.VisualCpp.Tools.Common.Utils",
"Microsoft.VisualCpp.Tools.Common.Utils.Resources",
"Microsoft.VisualStudio.PackageGroup.VsDevCmd",
"Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk",
"Microsoft.VisualStudio.VsDevCmd.Core.WinSdk",
"Microsoft.VisualStudio.VsDevCmd.Core.DotNet",
"Microsoft.VisualStudio.VC.DevCmd",
"Microsoft.VisualStudio.VC.DevCmd.Resources",
"Microsoft.VisualStudio.VirtualTree",
"Microsoft.DiaSymReader",
"Microsoft.Build.Dependencies",
"Microsoft.Build.FileTracker.Msi",
"Microsoft.Build",
"Microsoft.VisualStudio.PackageGroup.NuGet",
"Microsoft.DataAI.NuGetRecommender",
"Microsoft.VisualStudio.NuGet.Core",
"Microsoft.Build.Arm64",
"Microsoft.Build.UnGAC",
"Microsoft.VisualStudio.TextMateGrammars",
"Microsoft.VisualStudio.Platform.Markdown",
"Microsoft.VisualStudio.Platform.CrossRepositorySearch",
"Microsoft.VisualStudio.PackageGroup.TeamExplorer.Common",
"Microsoft.VisualStudio.TeamExplorer",
"Microsoft.VisualStudio.PackageGroup.ServiceHub",
"Microsoft.ServiceHub.Node",
"Microsoft.ServiceHub.Managed",
"Microsoft.ServiceHub.arm64",
"Microsoft.VisualStudio.ProjectServices",
"Microsoft.VisualStudio.OpenFolder.VSIX",
"Microsoft.VisualStudio.FileHandler.Msi",
"Microsoft.VisualStudio.FileHandler.Msi",
"Microsoft.VisualStudio.PackageGroup.MinShell",
"Microsoft.VisualStudio.MinShell.Msi",
"Microsoft.VisualStudio.MinShell.Shared.Msi",
"Microsoft.VisualStudio.MinShell.Msi.Resources",
"Microsoft.VisualStudio.MinShell.Interop",
"CoreEditorFonts",
"Microsoft.VisualStudio.Log",
"Microsoft.VisualStudio.Log.Targeted",
"Microsoft.VisualStudio.Log.Resources",
"Microsoft.VisualStudio.Finalizer",
"Microsoft.VisualStudio.Devenv",
"Microsoft.VisualStudio.Devenv.Resources",
"Microsoft.VisualStudio.CoreEditor",
"Microsoft.VisualStudio.Navigation.RichCodeNav",
"Microsoft.VisualStudio.Platform.NavigateTo",
"Microsoft.VisualStudio.Connected",
"SQLitePCLRaw",
"SQLitePCLRaw.Targeted",
"Microsoft.VisualStudio.Connected.Auto",
"Microsoft.VisualStudio.Connected.Auto.Resources",
"Microsoft.VisualStudio.AzureSDK",
"Microsoft.VisualStudio.PerfLib",
"Microsoft.VisualStudio.Connected.Resources",
"Microsoft.Net.PackageGroup.4.8.Redist",
"Microsoft.VisualStudio.PackageGroup.Progression",
"Microsoft.VisualStudio.PerformanceProvider",
"Microsoft.VisualStudio.GraphModel",
"Microsoft.VisualStudio.GraphProvider",
"Microsoft.VisualStudio.Community.VB.Targeted",
"Microsoft.VisualStudio.Community.VB.Neutral",
"Microsoft.VisualStudio.Community.CSharp.Targeted",
"Microsoft.VisualStudio.Community.CSharp.Neutral",
"Microsoft.VisualStudio.Community.ProductArch.TargetedExtra",
"Microsoft.VisualStudio.Community.ProductArch.Targeted",
"Microsoft.VisualStudio.Community.ProductArch.NeutralExtra",
"Microsoft.DiaSymReader.PortablePdb",
"Microsoft.IntelliTrace.CollectorCab",
"Microsoft.VisualStudio.Community.VB.Resources.Targeted",
"Microsoft.VisualStudio.Community.VB.Resources.Neutral",
"Microsoft.VisualStudio.Community.CSharp.Resources.Targeted",
"Microsoft.VisualStudio.Community.CSharp.Resources.Neutral",
"Microsoft.VisualStudio.Community.ProductArch.Resources.Targeted",
"Microsoft.VisualStudio.Community.ProductArch.Resources.NeutralExtra",
"Microsoft.VisualStudio.Net.Eula.Resources",
"Microsoft.VisualStudio.Community.ProductArch.Resources.Neutral",
"Microsoft.VisualStudio.WebSiteProject.DTE",
"Microsoft.VisualStudio.Diagnostics.AspNetHelper",
"Microsoft.VisualStudio.Diagnostics.AspNetHelper.Standard",
"Microsoft.MSHtml",
"Microsoft.VisualStudio.Platform.CallHierarchy",
"Microsoft.VisualStudio.Community.ProductArch.Neutral",
"Microsoft.VisualStudio.MinShell",
"Microsoft.VisualStudio.VsWebProtocolSelector.Msi",
"Microsoft.Net.8.0.WindowsDesktop.Runtime",
"Microsoft.Net.8.0.Runtime",
"Microsoft.VisualStudio.PackageGroup.Setup.Common",
"Microsoft.VisualStudio.Setup.WMIProvider",
"Microsoft.VisualStudio.Setup.Configuration.Interop",
"Microsoft.VisualStudio.Setup.Configuration",
"Microsoft.VisualStudio.Extensibility.Container",
"Microsoft.VisualStudio.LanguageServer",
"Microsoft.VisualStudio.Platform.Terminal",
"Microsoft.VisualStudio.MefHosting",
"Microsoft.VisualStudio.Initializer",
"Microsoft.VisualStudio.ExtensionManager",
"Microsoft.VisualStudio.Platform.Editor",
"Microsoft.VisualStudio.MinShell.Targeted",
"Microsoft.VisualStudio.NativeImageSupport",
"Microsoft.VisualStudio.Devenv.Config",
"Microsoft.VisualStudio.MinShell.Resources.arm64",
"Microsoft.VisualStudio.MinShell.Auto",
"Microsoft.VisualStudio.MinShell.Auto.Resources",
"Microsoft.VisualStudio.Branding.Community"
]
}
]
================================================
FILE: test/fixtures/VS_2026_Insiders_workload.txt
================================================
[
{
"path": "C:\\Program Files\\Microsoft Visual Studio\\18\\Insiders",
"version": "18.3.11206.111",
"packages": [
"Microsoft.VisualStudio.Product.Community",
"Microsoft.VisualStudio.PackageGroup.LiveShare.VSCore",
"Microsoft.VisualStudio.LiveShare.VSCore",
"Microsoft.VisualStudio.Workload.NativeDesktop",
"Microsoft.VisualStudio.Component.VC.ASAN",
"Microsoft.VisualCpp.ASAN.X86",
"Microsoft.VC.14.50.18.0.ASAN.X86.base",
"Microsoft.VC.14.50.18.0.ASAN.X64.base",
"Microsoft.VC.14.50.18.0.ASAN.Headers.base",
"Microsoft.VisualStudio.VC.IDE.Project.Factories",
"Microsoft.VisualStudio.Component.VC.TestAdapterForGoogleTest",
"Microsoft.VisualStudio.VC.Ide.TestAdapterForGoogleTest",
"Microsoft.VisualStudio.Component.VC.TestAdapterForBoostTest",
"Microsoft.VisualStudio.VC.Ide.TestAdapterForBoostTest",
"Microsoft.VisualStudio.Component.VC.CMake.Project",
"Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.CMake",
"Microsoft.VisualStudio.VC.CMake",
"Microsoft.VisualStudio.VC.CMake.Project",
"Microsoft.VisualStudio.VC.CMake.Client",
"Microsoft.VisualStudio.VC.ExternalBuildFramework",
"Microsoft.VisualStudio.Component.VC.DiagnosticTools",
"Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core",
"Microsoft.VisualStudio.PackageGroup.TestTools.Native",
"Microsoft.VisualStudio.Component.VC.Redist.14.Latest",
"Microsoft.VisualStudio.VC.Templates.UnitTest",
"Microsoft.VisualStudio.VC.UnitTest.Desktop.Build.Core",
"Microsoft.VisualStudio.TestTools.TestPlatform.V1.CPP",
"Microsoft.VisualStudio.VC.Templates.UnitTest.Resources",
"Microsoft.VisualStudio.VC.Templates.Desktop",
"Microsoft.VisualStudio.Component.Graphics",
"Microsoft.VisualStudio.Graphics.Viewers",
"Microsoft.VisualStudio.Graphics.Viewers.Resources",
"Microsoft.VisualStudio.Component.VC.ATL.ARM64",
"Microsoft.VisualCpp.ATL.ARM64",
"Microsoft.VC.14.50.18.0.ATL.ARM64.base",
"Microsoft.VisualStudio.Component.VC.ATL",
"Microsoft.VisualStudio.VC.Ide.ATL",
"Microsoft.VisualStudio.VC.Ide.ATL.Resources",
"Microsoft.VisualCpp.ATL.X86",
"Microsoft.VC.14.50.18.0.ATL.X86.base",
"Microsoft.VisualCpp.ATL.X64",
"Microsoft.VC.14.50.18.0.ATL.X64.base",
"Microsoft.VC.14.50.18.0.Props.ATLMFC",
"Microsoft.VisualCpp.ATL.Source",
"Microsoft.VC.14.50.18.0.ATL.Source.base",
"Microsoft.VisualCpp.ATL.Headers",
"Microsoft.VC.14.50.18.0.ATL.Headers.base",
"Microsoft.VC.14.50.18.0.Servicing.ATL",
"Microsoft.VisualStudio.Component.VC.Tools.ARM64",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM64.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM64",
"Microsoft.VS.VC.vcvars.arm64.Shortcuts",
"Microsoft.VisualCpp.CA.Ext.Hostx64.TargetARM64",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.TargetARM64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.TargetARM64",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.TargetARM64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.TargetARM64.Res.base",
"Microsoft.VisualCpp.CA.Ext.HostARM64.TargetARM64",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.TargetARM64.Res.base",
"Microsoft.VisualCpp.Tools.Hostx86.Targetarm64",
"Microsoft.VC.14.50.18.0.Tools.Hostx86.Targetarm64.base",
"Microsoft.VC.14.50.18.0.Tools.HostX86.TargetARM64.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetARM64",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetARM64.Res.base",
"Microsoft.VisualCpp.CRT.Redist.ARM64.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.Redist.ARM64.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.ARM64",
"Microsoft.VC.14.50.18.0.CRT.Redist.ARM64.base",
"Microsoft.VisualCpp.CRT.ARM64.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.ARM64.OneCore.Desktop.base",
"Microsoft.VC.14.50.18.0.CRT.ARM64.OneCore.Desktop.debug.base",
"Microsoft.VisualCpp.CRT.ARM64.Store",
"Microsoft.VC.14.50.18.0.CRT.ARM64.Store.base",
"Microsoft.VisualCpp.CRT.ARM64.Desktop",
"Microsoft.VC.14.50.18.0.CRT.ARM64.Desktop.base",
"Microsoft.VC.14.50.18.0.CRT.ARM64.Desktop.debug.base",
"Microsoft.VisualStudio.PackageGroup.VC.Tools.x64.ARM64",
"Microsoft.VisualCpp.Tools.Core",
"Microsoft.VisualCpp.PGO.ARM64",
"Microsoft.VC.14.50.18.0.PGO.ARM64.base",
"Microsoft.VisualCpp.Premium.Tools.Hostx86.Targetarm64",
"Microsoft.VC.14.50.18.0.Premium.Tools.Hostx86.Targetarm64.base",
"Microsoft.VC.14.50.18.0.Prem.HostX86.TargetARM64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetARM64",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.Prem.HostX64.TargetARM64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.ARM64.Base",
"Microsoft.VC.14.50.18.0.Premium.Tools.ARM64.Base.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetARM64",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetARM64.base",
"Microsoft.VC.14.50.18.0.Props.ARM64",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetARM64.Res.base",
"Microsoft.VisualStudio.Component.VC.Tools.ARM64EC",
"Microsoft.VisualStudio.Component.Windows11SDK.26100",
"Win11SDK_10.0.26100",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM64EC.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM64EC",
"Microsoft.VisualCpp.CRT.ARM64EC.Store",
"Microsoft.VC.14.50.18.0.CRT.ARM64EC.Store.base",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"Microsoft.VisualCpp.CodeAnalysis.Extensions",
"Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx64",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.Targetx64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.Targetx64.Res.base",
"Microsoft.VisualCpp.CA.Ext.HostARM64.Targetx86",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.Targetx86.base",
"Microsoft.VC.14.50.18.0.CA.Ext.HostARM64.Targetx86.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx64",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.Targetx64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.Targetx64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx86.Targetx86",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.Targetx86.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx86.Targetx86.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx64",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.Targetx64.base",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.Targetx64.Res.base",
"Microsoft.VisualCpp.CA.Ext.Hostx64.Targetx86",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.Targetx86.base",
"Microsoft.VC.14.50.18.0.Servicing.CAExtensions",
"Microsoft.VC.14.50.18.0.CA.Ext.Hostx64.Targetx86.Res.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetX86",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetX86.base",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.HostX64.TargetX64",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetX64.base",
"Microsoft.VC.14.50.18.0.Tools.HostX64.TargetX64.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetX86",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetX86.base",
"Microsoft.VisualCpp.RuntimeDebug.14",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.HostARM64.TargetX64",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.TargetX64.base",
"Microsoft.VisualCpp.RuntimeDebug.14.ARM64",
"Microsoft.VisualCpp.Redist.14.Latest",
"Microsoft.VisualCpp.Redist.14.Latest",
"Microsoft.VC.14.50.18.0.Tools.HostARM64.Targetx64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX64",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX86.TargetX64.base",
"Microsoft.VC.14.50.18.0.Prem.Hostx86.Targetx64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX86.TargetX86",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX86.TargetX86.base",
"Microsoft.VC.14.50.18.0.Prem.HostX86.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX86",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostARM64.TargetX86.base",
"Microsoft.VC.14.50.18.0.Prem.HostARM64.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostARM64.TargetX64",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostARM64.TargetX64.base",
"Microsoft.VC.14.50.18.0.Prem.HostARM64.Targetx64.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX86",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX64.TargetX86.base",
"Microsoft.VC.14.50.18.0.Prem.HostX64.TargetX86.Res.base",
"Microsoft.VisualCpp.Premium.Tools.HostX64.TargetX64",
"Microsoft.VC.14.50.18.0.Premium.Tools.HostX64.TargetX64.base",
"Microsoft.VC.14.50.18.0.Prem.HostX64.TargetX64.Res.base",
"Microsoft.VisualCpp.PGO.X86",
"Microsoft.VC.14.50.18.0.PGO.X86.base",
"Microsoft.VisualCpp.PGO.X64",
"Microsoft.VC.14.50.18.0.PGO.X64.base",
"Microsoft.VisualCpp.PGO.Headers",
"Microsoft.VC.14.50.18.0.PGO.Headers.base",
"Microsoft.VisualCpp.CRT.x86.Store",
"Microsoft.VC.14.50.18.0.CRT.x86.Store.base",
"Microsoft.VisualCpp.CRT.x86.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.x86.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.x64.Store",
"Microsoft.VC.14.50.18.0.CRT.x64.Store.base",
"Microsoft.VisualCpp.CRT.x64.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.x64.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.x86.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.Redist.x86.OneCore.Desktop.base",
"Microsoft.VisualCpp.CRT.Redist.x64.OneCore.Desktop",
"Microsoft.VC.14.50.18.0.CRT.Redist.x64.OneCore.Desktop.base",
"Microsoft.VisualStudio.PackageGroup.VC.Tools.x86",
"Microsoft.VisualCpp.Tools.Hostx86.Targetx64.Res",
"Microsoft.VisualCpp.Tools.HostX86.TargetX64",
"Microsoft.VC.14.50.18.0.Tools.HostX86.TargetX64.base",
"Microsoft.VC.14.50.18.0.Props.x64",
"Microsoft.VC.14.50.18.0.Tools.Hostx86.Targetx64.Res.base",
"Microsoft.VisualCpp.Tools.HostX86.TargetX86.Res",
"Microsoft.VisualCpp.Tools.HostX86.TargetX86",
"Microsoft.VC.14.50.18.0.Tools.HostX86.TargetX86.base",
"Microsoft.VC.14.50.18.0.Servicing.Compilers",
"Microsoft.VC.14.50.18.0.Props.x86",
"Microsoft.VC.14.50.18.0.Props",
"Microsoft.VC.14.50.18.0.Tools.HostX86.TargetX86.Res.base",
"Microsoft.VisualCpp.Tools.Core.Resources",
"Microsoft.VisualCpp.Tools.Core.x86",
"Microsoft.VC.14.50.18.0.Tools.Core.Props",
"Microsoft.VisualCpp.DIA.SDK",
"Microsoft.VisualCpp.Servicing.DIASDK",
"Microsoft.VisualCpp.CRT.x86.Desktop",
"Microsoft.VC.14.50.18.0.CRT.x86.Desktop.base",
"Microsoft.VisualCpp.CRT.x64.Desktop",
"Microsoft.VC.14.50.18.0.CRT.x64.Desktop.base",
"Microsoft.VisualCpp.CRT.Source",
"Microsoft.VC.14.50.18.0.CRT.Source.base",
"Microsoft.VisualCpp.CRT.Redist.X86",
"Microsoft.VC.14.50.18.0.CRT.Redist.X86.base",
"Microsoft.VisualCpp.CRT.Redist.X64",
"Microsoft.VisualCpp.CRT.Redist.Resources",
"Microsoft.VC.14.50.18.0.CRT.Redist.X64.base",
"Microsoft.VisualCpp.CRT.Headers",
"Microsoft.VC.14.50.18.0.CRT.Headers.base",
"Microsoft.VC.14.50.18.0.Servicing.CrtHeaders",
"Microsoft.VC.14.50.18.0.Servicing",
"Microsoft.VisualStudio.Component.VC.CoreIde",
"Microsoft.VisualStudio.VC.Ide.Pro",
"Microsoft.VisualStudio.VC.Ide.Pro.Resources",
"Microsoft.VisualStudio.VC.Templates.General",
"Microsoft.VisualStudio.VC.Templates.General.Resources",
"Microsoft.VisualStudio.VC.Items.Pro",
"Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Reduced",
"Microsoft.VisualStudio.VC.Ide.x64",
"Microsoft.VisualStudio.PackageGroup.VC.CoreIDE.Express",
"Microsoft.VisualStudio.VC.vcvars",
"Microsoft.VS.VC.vcvars.x86.Shortcuts",
"Microsoft.VS.VC.vcvars.x64.Shortcuts",
"Microsoft.VS.VC.vcvars.arm64_x64.Shortcuts",
"Microsoft.VisualStudio.VC.MSBuild.v180.X64.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.X64",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.ARM",
"Microsoft.VisualStudio.VC.MSBuild.v180.x86.v145",
"Microsoft.VisualStudio.VC.MSBuild.v180.X86",
"Microsoft.VisualStudio.VC.MSBuild.v180.Base",
"Microsoft.VisualStudio.VC.MSBuild.v180.Base.Resources",
"Microsoft.VisualStudio.VC.Ide.WinXPlus",
"Microsoft.VisualStudio.VC.Ide.Dskx",
"Microsoft.VisualStudio.VC.Ide.Dskx.Resources",
"Microsoft.VisualStudio.VC.Ide.Base",
"Microsoft.VisualStudio.VC.Ide.LanguageService",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.Scripts",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.PythonDistro",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.10",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.9",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.8",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.7",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.6",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.5",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.4",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.3",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.2",
"Microsoft.VisualStudio.VC.Ide.SecurityIssueAnalysis.3rdPartyLibs.1",
"Microsoft.VisualStudio.VC.Ide.VCPkgDatabase",
"Microsoft.VisualStudio.VC.Ide.Core",
"Microsoft.VisualStudio.VC.Ide.ProjectSystem",
"Microsoft.VisualStudio.VC.Ide.ProjectSystem.Resources",
"Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine",
"Microsoft.VisualStudio.VC.Ide.Core.VCProjectEngine.Resources",
"Microsoft.VisualStudio.VC.Ide.LanguageService.Resources",
"Microsoft.VisualStudio.VC.Llvm.Base",
"Microsoft.VisualStudio.VC.Ide.Base.Resources",
"Microsoft.Net.PackageGroup.4.8.1.Redist",
"Microsoft.VisualStudio.Component.IntelliCode",
"Microsoft.VisualStudio.IntelliCode.CSharp",
"Microsoft.VisualStudio.IntelliCode",
"Component.Microsoft.VisualStudio.LiveShare.2026",
"Microsoft.VisualStudio.Component.Debugger.JustInTime",
"Microsoft.VisualStudio.Debugger.ImmersiveActivateHelper.Msi",
"Microsoft.VisualStudio.Debugger.JustInTime",
"Microsoft.VisualStudio.Debugger.JustInTime.Msi",
"Microsoft.VisualStudio.LiveShare.2026",
"Microsoft.Icecap.Analysis",
"Microsoft.Icecap.Analysis.Resources",
"Microsoft.Icecap.Analysis.Resources.Targeted",
"Microsoft.Icecap.Collection.Msi",
"Microsoft.Icecap.Collection.Msi.Targeted",
"Microsoft.Icecap.Collection.Msi.Resources",
"Microsoft.Icecap.Collection.Msi.Resources.Targeted",
"Microsoft.DiagnosticsHub.Instrumentation",
"Microsoft.DiagnosticsHub.Instrumentation.Targeted",
"Microsoft.DiagnosticsHub.CpuSampling",
"Microsoft.DiagnosticsHub.CpuSampling.Targeted",
"Microsoft.PackageGroup.DiagnosticsHub.Platform",
"Microsoft.VisualStudio.InstrumentationEngine.ARM64",
"Microsoft.VisualStudio.InstrumentationEngine",
"Microsoft.DiagnosticsHub.Runtime.ExternalDependencies",
"SQLiteCore",
"SQLiteCore.Targeted",
"Microsoft.DiagnosticsHub.Runtime.ExternalDependencies.Targeted",
"Microsoft.DiagnosticsHub.Runtime",
"Microsoft.DiagnosticsHub.Runtime.Targeted",
"Microsoft.DiagnosticsHub.Collection.ExternalDependencies.arm64",
"Microsoft.DiagnosticsHub.Collection",
"Microsoft.DiagnosticsHub.Collection.Service",
"Microsoft.VisualStudio.VC.Ide.MDD",
"Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager",
"Microsoft.VisualStudio.VisualC.Utilities",
"Microsoft.VisualStudio.VisualC.Utilities.Resources",
"Microsoft.VisualStudio.VC.Ide.Linux.ConnectionManager.Resources",
"Microsoft.VisualStudio.VC.Ide.ResourceEditor",
"Microsoft.VisualStudio.VC.Ide.ResourceEditor.Resources",
"Microsoft.VisualStudio.PackageGroup.TestTools.Core",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V2.CLI",
"Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI",
"Microsoft.VisualStudio.TestTools.Pex.Common",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.V1.CLI",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.Legacy",
"Microsoft.VisualStudio.PackageGroup.MinShell.Interop",
"Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Msi",
"Microsoft.VisualStudio.TestTools.TP.Legacy.Tips.Common",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Tips.Resources",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.TestSettings",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Professional",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Common",
"Microsoft.VisualStudio.TestTools.TP.Legacy.Common.Res",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Core.Resources",
"Microsoft.VisualStudio.TestTools.TestPlatform.Legacy.Agent",
"Microsoft.VisualStudio.PackageGroup.TestTools.TestPlatform.IDE",
"Microsoft.VisualStudio.Cache.Service",
"Microsoft.VisualStudio.TestTools.TestWIExtension",
"Microsoft.VisualStudio.TestTools.TestWIExtension.Res",
"Microsoft.VisualStudio.TestTools.TestPlatform.V1.CLI",
"Microsoft.VisualStudio.TestTools.TP.V1.CLI.Resources",
"Microsoft.VisualStudio.TestTools.TestPlatform.IDE",
"Microsoft.VisualStudio.PackageGroup.TestTools.CodeCoverage",
"Microsoft.VisualStudio.PackageGroup.TestTools.DataCollectors",
"Microsoft.VisualStudio.Component.NuGet",
"Microsoft.CredentialProvider",
"Microsoft.VisualStudio.NuGet.Licenses",
"Microsoft.VisualStudio.Component.TextTemplating",
"Microsoft.VisualStudio.TextTemplating.MSBuild",
"Microsoft.VisualStudio.TextTemplating.Integration",
"Microsoft.VisualStudio.TextTemplating.Core",
"Microsoft.VisualStudio.TextTemplating.Integration.Resources",
"Microsoft.VisualCpp.CRT.ClickOnce.Msi",
"Microsoft.VisualStudio.Component.Roslyn.LanguageServices",
"Microsoft.VisualStudio.InteractiveWindow",
"Microsoft.DiaSymReader.Native",
"Microsoft.VisualCpp.Redist.14",
"Microsoft.VisualCpp.Redist.14",
"Microsoft.VisualCpp.Servicing.Redist",
"Microsoft.VisualStudio.PackageGroup.StaticAnalysis",
"Microsoft.VisualStudio.StaticAnalysis.IDE",
"Microsoft.VisualStudio.StaticAnalysis.IDE.Resources",
"Microsoft.VisualStudio.StaticAnalysis.FxCop.Resources",
"Microsoft.VisualStudio.StaticAnalysis.auxil",
"Microsoft.VisualStudio.StaticAnalysis.auxil.Resources",
"Roslyn.VisualStudio.Setup.ServiceHub",
"Microsoft.Component.MSBuild",
"Microsoft.NuGet.Build.Tasks.Setup",
"Microsoft.VisualStudio.Component.Roslyn.Compiler",
"Microsoft.CodeAnalysis.Compilers",
"Microsoft.VisualStudio.Component.JavaScript.TypeScript",
"Microsoft.VisualStudio.JavaScript.ProjectSystem",
"Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions",
"Microsoft.VisualStudio.ProTools",
"sqlsysclrtypes",
"SQLCommon",
"Microsoft.VisualStudio.ProTools.Resources",
"Microsoft.VisualStudio.Web.Scaffolding",
"Microsoft.VisualStudio.WebToolsExtensions",
"Microsoft.VisualStudio.ConnectedServices.Core",
"Microsoft.VisualStudio.WebTools",
"Microsoft.VisualStudio.WebToolsExtensions.MSBuild",
"Microsoft.VisualStudio.WebTools.Resources",
"Microsoft.VisualStudio.WebTools.WSP.FSA",
"Microsoft.VisualStudio.WebTools.WSP.FSA.Resources",
"Microsoft.VisualStudio.PackageGroup.Debugger.Script",
"Microsoft.VisualStudio.Component.TypeScript.TSServer",
"Microsoft.VisualStudio.Package.TypeScript.TSServer",
"Microsoft.VisualStudio.PackageGroup.JavaScript.Language",
"Microsoft.VisualStudio.Package.NodeJs",
"TypeScript.Build",
"TypeScript.LanguageService",
"TypeScript.Tools",
"Microsoft.VisualStudio.PackageGroup.Community",
"Microsoft.VisualStudio.Community.VB.x86",
"Microsoft.VisualStudio.Community.VB.x64",
"Microsoft.VisualStudio.PackageGroup.Core",
"Microsoft.VisualStudio.CodeSense.Community",
"Microsoft.VisualStudio.TestTools.TeamFoundationClient",
"Microsoft.VisualStudio.PackageGroup.Debugger.Core",
"Microsoft.VisualStudio.Debugger.BrokeredServices",
"Microsoft.VisualStudio.Debugger.VSCodeDebuggerHost",
"Microsoft.VisualStudio.Debugger.AzureAttach",
"Microsoft.VisualStudio.Web.Azure.Common",
"Microsoft.WebTools.Shared",
"Microsoft.WebTools.DotNet.Core.ItemTemplates",
"Microsoft.VisualStudio.PackageGroup.Debugger.TimeTravel.Replay",
"Microsoft.VisualStudio.VC.Ide.Debugger",
"Microsoft.VisualStudio.VC.Ide.Debugger.Concord",
"Microsoft.VisualStudio.VC.Ide.Debugger.Concord.Resources",
"Microsoft.VisualStudio.VC.Ide.Debugger.Resources",
"Microsoft.VisualStudio.VC.Ide.Common",
"Microsoft.VisualStudio.VC.Ide.Common.Resources",
"Microsoft.VisualStudio.Debugger.CollectionAgents",
"Microsoft.VisualStudio.Debugger.Parallel",
"Microsoft.VisualStudio.Debugger.Parallel.Resources",
"Microsoft.VisualStudio.Debugger.Managed",
"Microsoft.CodeAnalysis.ExpressionEvaluator",
"Microsoft.CodeAnalysis.VisualStudio.Setup",
"Microsoft.VisualStudio.Debugger.Concord.Managed",
"Microsoft.VisualStudio.Debugger.Concord.Managed.Resources",
"Microsoft.VisualStudio.Debugger.Managed.Resources",
"Microsoft.VisualStudio.Debugger.TargetComposition",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote.arm64",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote",
"Microsoft.VisualStudio.Debugger.TargetComposition.Remote",
"Microsoft.VisualStudio.Debugger.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote",
"Microsoft.VisualStudio.Debugger.Remote.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources.ARM64",
"Microsoft.VisualStudio.Debugger.Remote.Resources.ARM",
"Microsoft.VisualStudio.Debugger.Remote.Resources.ARM64",
"Microsoft.VisualStudio.Debugger.Concord.Remote",
"Microsoft.VisualStudio.Debugger.Concord.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote.Resources",
"Microsoft.VisualStudio.Debugger.Remote.Resources",
"Microsoft.VisualStudio.Debugger",
"Microsoft.VisualStudio.VC.MSVCDis",
"Microsoft.IntelliTrace.DiagnosticsHub",
"Microsoft.VisualStudio.Debugger.Concord",
"Microsoft.VisualStudio.Debugger.Concord.Resources",
"Microsoft.VisualStudio.Debugger.Resources",
"Microsoft.VisualStudio.Debugger.Package.DiagHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.VisualStudio.Debugger.Remote.DiagnosticsHub.Client",
"Microsoft.PackageGroup.ClientDiagnostics",
"Microsoft.VisualStudio.AppResponsiveness",
"Microsoft.VisualStudio.AppResponsiveness.Targeted",
"Microsoft.VisualStudio.AppResponsiveness.Resources",
"Microsoft.VisualStudio.ClientDiagnostics",
"Microsoft.VisualStudio.ClientDiagnostics.Targeted",
"Microsoft.VisualStudio.ClientDiagnostics.Resources",
"Microsoft.VisualStudio.PackageGroup.CommunityCore",
"Microsoft.VisualStudio.ProjectSystem.Full",
"Microsoft.VisualStudio.LiveShareApi",
"Microsoft.VisualStudio.ProjectSystem.Query",
"Microsoft.VisualStudio.ProjectSystem",
"Microsoft.VisualStudio.Community.x86",
"Microsoft.VisualStudio.Community.x64",
"Microsoft.VisualStudio.Community.Msi.Resources",
"Microsoft.VisualStudio.Community.Msi",
"Microsoft.VisualStudio.Community.Shared.Msi",
"Microsoft.VisualStudio.Devenv.Msi",
"Microsoft.VisualStudio.Devenv.Shared.Msi",
"Microsoft.VisualStudio.MinShell.Interop.Msi",
"Microsoft.VisualStudio.MinShell.Interop.Shared.Msi",
"Microsoft.VisualStudio.Editors",
"Microsoft.VisualStudio.Workload.CoreEditor",
"Microsoft.VisualStudio.Component.CoreEditor",
"Microsoft.VisualStudio.PackageGroup.CoreEditor",
"Microsoft.WebView2",
"Microsoft.VisualStudio.ScriptedHost",
"Microsoft.VisualStudio.ScriptedHost.Targeted",
"Microsoft.VisualCpp.Tools.Common.UtilsPrereq",
"Microsoft.VisualCpp.Tools.Common.Utils",
"Microsoft.VisualCpp.Tools.Common.Utils.Resources",
"Microsoft.VisualStudio.PackageGroup.VsDevCmd",
"Microsoft.VisualStudio.VsDevCmd.Ext.NetFxSdk",
"Microsoft.VisualStudio.VsDevCmd.Core.WinSdk",
"Microsoft.VisualStudio.VsDevCmd.Core.DotNet",
"Microsoft.VisualStudio.VC.DevCmd",
"Microsoft.VisualStudio.VC.DevCmd.Resources",
"Microsoft.VisualStudio.VirtualTree",
"Microsoft.DiaSymReader",
"Microsoft.Build.Dependencies",
"Microsoft.Build.FileTracker.Msi",
"Microsoft.Build",
"Microsoft.VisualStudio.PackageGroup.NuGet",
"Microsoft.DataAI.NuGetRecommender",
"Microsoft.VisualStudio.NuGet.Core",
"Microsoft.Build.Arm64",
"Microsoft.Build.UnGAC",
"Microsoft.VisualStudio.TextMateGrammars",
"Microsoft.VisualStudio.Platform.Markdown",
"Microsoft.VisualStudio.Platform.CrossRepositorySearch",
"Microsoft.VisualStudio.PackageGroup.TeamExplorer.Common",
"Microsoft.VisualStudio.TeamExplorer",
"Microsoft.VisualStudio.PackageGroup.ServiceHub",
"Microsoft.ServiceHub.Node",
"Microsoft.ServiceHub.Managed",
"Microsoft.ServiceHub.arm64",
"Microsoft.VisualStudio.ProjectServices",
"Microsoft.VisualStudio.OpenFolder.VSIX",
"Microsoft.VisualStudio.FileHandler.Msi",
"Microsoft.VisualStudio.FileHandler.Msi",
"Microsoft.VisualStudio.PackageGroup.MinShell",
"Microsoft.VisualStudio.MinShell.Msi",
"Microsoft.VisualStudio.MinShell.Shared.Msi",
"Microsoft.VisualStudio.MinShell.Msi.Resources",
"Microsoft.VisualStudio.MinShell.Interop",
"CoreEditorFonts",
"Microsoft.VisualStudio.Log",
"Microsoft.VisualStudio.Log.Targeted",
"Microsoft.VisualStudio.Log.Resources",
"Microsoft.VisualStudio.Finalizer",
"Microsoft.VisualStudio.Devenv",
"Microsoft.VisualStudio.Devenv.Resources",
"Microsoft.VisualStudio.CoreEditor",
"Microsoft.VisualStudio.Navigation.RichCodeNav",
"Microsoft.VisualStudio.Platform.NavigateTo",
"Microsoft.VisualStudio.Connected",
"SQLitePCLRaw",
"SQLitePCLRaw.Targeted",
"Microsoft.VisualStudio.Connected.Auto",
"Microsoft.VisualStudio.Connected.Auto.Resources",
"Microsoft.VisualStudio.AzureSDK",
"Microsoft.VisualStudio.PerfLib",
"Microsoft.VisualStudio.Connected.Resources",
"Microsoft.Net.PackageGroup.4.8.Redist",
"Microsoft.VisualStudio.PackageGroup.Progression",
"Microsoft.VisualStudio.PerformanceProvider",
"Microsoft.VisualStudio.GraphModel",
"Microsoft.VisualStudio.GraphProvider",
"Microsoft.VisualStudio.Community.VB.Targeted",
"Microsoft.VisualStudio.Community.VB.Neutral",
"Microsoft.VisualStudio.Community.CSharp.Targeted",
"Microsoft.VisualStudio.Community.CSharp.Neutral",
"Microsoft.VisualStudio.Community.ProductArch.TargetedExtra",
"Microsoft.VisualStudio.Community.ProductArch.Targeted",
"Microsoft.VisualStudio.Community.ProductArch.NeutralExtra",
"Microsoft.DiaSymReader.PortablePdb",
"Microsoft.IntelliTrace.CollectorCab",
"Microsoft.VisualStudio.Community.VB.Resources.Targeted",
"Microsoft.VisualStudio.Community.VB.Resources.Neutral",
"Microsoft.VisualStudio.Community.CSharp.Resources.Targeted",
"Microsoft.VisualStudio.Community.CSharp.Resources.Neutral",
"Microsoft.VisualStudio.Community.ProductArch.Resources.Targeted",
"Microsoft.VisualStudio.Community.ProductArch.Resources.NeutralExtra",
"Microsoft.VisualStudio.Net.Eula.Resources",
"Microsoft.VisualStudio.Community.ProductArch.Resources.Neutral",
"Microsoft.VisualStudio.WebSiteProject.DTE",
"Microsoft.VisualStudio.Diagnostics.AspNetHelper",
"Microsoft.VisualStudio.Diagnostics.AspNetHelper.Standard",
"Microsoft.MSHtml",
"Microsoft.VisualStudio.Platform.CallHierarchy",
"Microsoft.VisualStudio.Community.ProductArch.Neutral",
"Microsoft.VisualStudio.MinShell",
"Microsoft.VisualStudio.VsWebProtocolSelector.Msi",
"Microsoft.Net.8.0.WindowsDesktop.Runtime",
"Microsoft.Net.8.0.Runtime",
"Microsoft.VisualStudio.PackageGroup.Setup.Common",
"Microsoft.VisualStudio.Setup.WMIProvider",
"Microsoft.VisualStudio.Setup.Configuration.Interop",
"Microsoft.VisualStudio.Setup.Configuration",
"Microsoft.VisualStudio.Extensibility.Container",
"Microsoft.VisualStudio.LanguageServer",
"Microsoft.VisualStudio.Platform.Terminal",
"Microsoft.VisualStudio.MefHosting",
"Microsoft.VisualStudio.Initializer",
"Microsoft.VisualStudio.ExtensionManager",
"Microsoft.VisualStudio.Platform.Editor",
"Microsoft.VisualStudio.MinShell.Targeted",
"Microsoft.VisualStudio.NativeImageSupport",
"Microsoft.VisualStudio.Devenv.Config",
"Microsoft.VisualStudio.MinShell.Resources.arm64",
"Microsoft.VisualStudio.MinShell.Auto",
"Microsoft.VisualStudio.MinShell.Auto.Resources",
"Microsoft.VisualStudio.Branding.Community"
]
}
]
================================================
FILE: test/fixtures/certs.js
================================================
module.exports['ca.key'] = `
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAtTbG0k2UFUyCdZuip0TTEtXRHh57qosegrpHPBreSNTxt7OT
KfOUZp2rToTHeN9w0ZbV2eKRI5AuFx8Cmlm73/KIHKzSNTBATGMeeHnGaxvL/W/s
KJdTDRNf7/qCXHQ+gsuEWWCFzOZuHmmAQa2IBX2HAQTqXJI8+2iJ9gytFfJLxjqy
6O4u9ugZVHSyQJWs49tGRcWMlNm7EMStADFvJn3S11xe/kwIA2mSI/eddDnzL0Mx
AkR9dQBL66xOABLL5v3QQdhipfHluX6HLbDd/1YsFTuOpgvLRlr72rTAFrQZCokV
hXPiqstn5zJFW5arHakvMR0+OPaICF5feh/4qQIDAQABAoIBAHWg6exnWUF+GY0Y
CrwDS/QFASpI5UNt7M809bqJQlMKjyEMmvF3YJQ/soxUWlsWx1f1TjmR/V6VX6W4
hmsE5pRXDY13jTfja0lqacQQYAD02TRY63XpzIpHUlYnSWmUN2OVkgKmShQYW9C3
8P4xE4Nk2TaLJ0oRzy3uzOb/kXcVaJfknBRUnOhuaTSs+w4l4pPXueYA7xuHgVsL
Qq0S4kK+PmdwCMB7gzlAAQhCM3vQ1U4cjC9JIIKSmPy7BcvD0kBfVPIFQ2byGpA1
VkWBLSyeig0YxA5oIshK5cLiDIfBIiCSEzm4AMhVhGf0tbGEwiPljxKjbarYUUIi
ATMk83UCgYEA7kKeOveuPbMqxmT42swfa9OU5jLUjH+VExU0Kv3BbEjv/OGt0fac
/cs1Ze3vnrtCHudVajocFjydb8B4c62DbA4/T+LcUw/HaMaORbOoICQidi/zZ1Lj
gjg8Ip2WKXEhSAwqUpaFd6w16NZOxiTh+NDaRKywwbe8j57eDH4uR6MCgYEAwrTS
q5ra6+WDGUFMs0y3GMbL8j14PGhxBQBYSTM//NysI+EM6eeKn1cV3BbphEw//jgE
0pVokkjvLAQWWEG2dZyRxRE3YAMgOAIPx5zbJCim3iBVuoqY9ckLg2jF8Fqqubsb
3Rf2/Xzn/rFqsXdhsjGcJpdN66T9aEjwEkAnc0MCgYA5cOYk4UGormFJo147oaqR
nFjxhp+nn7qY9yu0kajoKk1xchct337J0Qv2nv5+DjdKrArzqT7MPaDXKFfhy5s7
mdO5tr/XZp50rCnws/d8iDmmtLjB2EHxSw10avmg1B1p+UTa1F8pEuOMVt529r1j
9zYoCFo02c8j8PEnoeQWcQKBgQCVBCuQZu5SSM/zTkTTnU0sy0lf1qflI9IMD92B
+JVqg8HDnAR0KF+x38a9MVP7ixgXCuy19t+XxfY269HmLjTlArWV671D4GCSPRGy
plwZ6nr72ieCo3y57+q94jxL3jh3+bozlpnUG/q6tTKBLGs7JDjsWDSsuxOu8tO6
RBttXQKBgB6LQFOTjDMfsFHKsnQXFUZId3GG/iLg3WCWxEo88T5Rq3JIR0zDpW8H
cKhl/sPY+JVHsxizNCMPtp7Hn7GrB6D/v9LbO0jpG2U0BFiJ6zhiDopbP9B0EAW4
5JJ+JGKRKoCxs3DmSVyns0gU4j4rVte97UWyVy5TZ8Acr/qrgOA1
-----END RSA PRIVATE KEY-----
`
module.exports['ca.crt'] = `
-----BEGIN CERTIFICATE-----
MIIDmzCCAoOgAwIBAgIUDA0GrvcnG41XT6LYFeNwvq8YV1UwDQYJKoZIhvcNAQEL
BQAwXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRAwDgYDVQQKDAdOb2RlLmpz
MREwDwYDVQQLDAhub2RlLWd5cDEcMBoGA1UEAwwTbm9kZS1neXAubm9kZWpzLm9y
ZzAeFw0yMjA1MTEwNDIyMjRaFw00OTA5MjUwNDIyMjRaMF0xCzAJBgNVBAYTAlVT
MQswCQYDVQQIDAJDQTEQMA4GA1UECgwHTm9kZS5qczERMA8GA1UECwwIbm9kZS1n
eXAxHDAaBgNVBAMME25vZGUtZ3lwLm5vZGVqcy5vcmcwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQC1NsbSTZQVTIJ1m6KnRNMS1dEeHnuqix6Cukc8Gt5I
1PG3s5Mp85RmnatOhMd433DRltXZ4pEjkC4XHwKaWbvf8ogcrNI1MEBMYx54ecZr
G8v9b+wol1MNE1/v+oJcdD6Cy4RZYIXM5m4eaYBBrYgFfYcBBOpckjz7aIn2DK0V
8kvGOrLo7i726BlUdLJAlazj20ZFxYyU2bsQxK0AMW8mfdLXXF7+TAgDaZIj9510
OfMvQzECRH11AEvrrE4AEsvm/dBB2GKl8eW5foctsN3/ViwVO46mC8tGWvvatMAW
tBkKiRWFc+Kqy2fnMkVblqsdqS8xHT449ogIXl96H/ipAgMBAAGjUzBRMB0GA1Ud
DgQWBBT6LcYYABEOAMv4hI/5bC82rGlD/DAfBgNVHSMEGDAWgBT6LcYYABEOAMv4
hI/5bC82rGlD/DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA9
D+qoKw0njub+NaFRS2DFbSiKb5JKTxVjU5aNusFONFLSXBuRpnYyjjkXpJy8JMWz
g8GFDEPP6kiSb8xaPNrFcUzb4PFzJabNTuaLJpBpd2gNBj5AeYwwpRa2DPv/b4yw
y2mfULuCWS09ZAguI2OcaARlAsFxYN0IuQ6pN1AvGFGee67ve9l2VF/hhwEi4lCk
MM0CWlP6COJ8TX7X0MTtexVOgo9m3hBuTSYEZClYFIdSOk10xkPl8Y3Iz/x6mzfK
Uu2l2ZtYvSdAX1CQMds3ZWt0ChNNEjOKPv4g2QSDhGkiqrmi4wUS81g68wKqOpqn
GbN8uKxIfyMjqZKaujPR
-----END CERTIFICATE-----
`
module.exports['server.key'] = `
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDpxqKqzq8PuOuo
M09X1gdh6V1nMmJ6Oqk/d8ZSAHhGBTjB5BBILtrxJPAdsNCRc8gPCtSuAzu9r0ct
D2znJjto8HO3a0s/4mlqMQ8iSvfH0c8nGLPxRXg0C9tR0VOyqJrqAPn9X6utxVQj
H2jLjZngZllhqlxIUxYuXO7MZfC2MQ4DRsp6GaJTftcOxTxevMdT6lK0yl3mDn0W
DyV9aWR5oCVXKIRK7jmF9bi9ETHwJHffFrduaaKYLQ/UOEtNek/pJsz0DNO0ePkm
DAt0GQkX3hmKd0VRgGEtaO+MAGbrDucPuDylMkC1GJm1lq6+6rkyQRNoAd8/yOJD
GihBJmLPAgMBAAECggEBAL3+WM/3IGHnyWavJMnfQaq6rdWkJlLugAT8BCs7BITr
04AJKY5wvjID8j4/KJM+BRbsl4NBT3lPDcq6YajO8rPL0E/+nG60RTYv3vvg79Xv
V6uPsRbifdnW1Q1+0cY+r4CFAKeC7JVS7ZmJ+nKMh8XPiM8OVOfW1w0hLFbkdqiq
UetA5H0oiJr0rFWh9Gfzc0avpmawXmZJqK8lKWB1rt2teu3bQWqn20dGr2IyCipz
KlGh3QImYogjqWEqPyowPGxnq8KWQ40Pjx61dy6cqYrw77yxLHGR8Az+TlRQZf/K
BeT3UkXCU5BTyC3PKZJpcYB/GMB8GBKRdNK+8H3OXskCgYEA963tUnLoiCwJjxvv
gIiMY5mIUAMnTDsCxSYekfkDvt4qdttn/+Y8/5/lXMSlCt+WZcXH0V8gmVOMqfHB
QRXWpi0uJnl9sUllb80Mw5PnS317UlJIbkro3crVUhIbrn9tKVFP1GO9xszNda8E
MkHV8FGmSaihXGnA8KEkTKg1CisCgYEA8aEjATIpDXyxQM4M9B1S0jI/nHOrg2lr
dMKQWJVruuvwrrZl6CFNIm2/PBXyHjCXqROXs7aXkE3vfRSypYNKBZl7BX08c0nE
koMVXwhGbSbUXjFx5bcUKaG/2eOK+ZV4ivNQokq1iIK+WKINAfP69ewzD7EAgbBg
KY7owSxka+0CgYB4Urh+W3B35tzl9y5NBQkewdGk/UM0F17rI++p/o1BRnDeuQw3
F0T+8lDc1nNPavuHiaPfJRWTJzGoxdeapN9Yb46CBnd3jy6GN9lBkjLFS7qDbZHe
cunaBdXIPx/Pj/waHHRpu+LQF2KhD1s8hxtF2oSsOA3b9UxUGhSmYPkTbQKBgEP8
muTTQEnTM+yQDYUCWzNZgBx9T10CZIHN3N+P62gEywvdtn7CH/n39z7ozd9AvOuN
37lpPuwTgbcoA7weXM2Gid7ZhhDKSM0QpQrAQVClBEwcjXedM8cjA+BC7e+b5vbx
z1ZavwlSAEzgC9jo1Uws0ZEwtHvJLMWEuGjiHL9hAoGAWEbj2cxhpCKTK3C8Qf+C
BscBwAZKmUasdWQBUzRFpR1UAO3fFBatjMPwrFYnt+ZgiCXTGFcoEa7mjoP/r5Mh
j1nRCoPQVcbmB1B9AtiaEa1AA+BqYF1r2aErbcsGrCV5OHU7TYFk1dep1SAQP/0W
9MQ+1Af5ttYSFYlJLnWJo4M=
-----END PRIVATE KEY-----
`
module.exports['server.crt'] = `
-----BEGIN CERTIFICATE-----
MIIDPjCCAiagAwIBAgIJALrth9K8D7HIMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTEQMA4GA1UECgwHTm9kZS5qczERMA8GA1UECwwI
bm9kZS1neXAxHDAaBgNVBAMME25vZGUtZ3lwLm5vZGVqcy5vcmcwHhcNMjMwOTI4
MDUxODM2WhcNMzMwOTI1MDUxODM2WjBgMQswCQYDVQQGEwJVUzETMBEGA1UECAwK
Q2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEQMA4GA1UECgwHTm9k
ZS5qczESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA6caiqs6vD7jrqDNPV9YHYeldZzJiejqpP3fGUgB4RgU4weQQSC7a
8STwHbDQkXPIDwrUrgM7va9HLQ9s5yY7aPBzt2tLP+JpajEPIkr3x9HPJxiz8UV4
NAvbUdFTsqia6gD5/V+rrcVUIx9oy42Z4GZZYapcSFMWLlzuzGXwtjEOA0bKehmi
U37XDsU8XrzHU+pStMpd5g59Fg8lfWlkeaAlVyiESu45hfW4vREx8CR33xa3bmmi
mC0P1DhLTXpP6SbM9AzTtHj5JgwLdBkJF94ZindFUYBhLWjvjABm6w7nD7g8pTJA
tRiZtZauvuq5MkETaAHfP8jiQxooQSZizwIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
AQBwgEyrqJOV8SC7PVTtEOqfSyrM7lJjVcmwXEIFPVCPxXnDtLS9+OaQe9ybjOR/
Bi/AvZK4gwsV9G5Bvbl0/sphYEKYLEpP76jhdETcBwhaEgK3itumoREeriut4bZI
OM6b1O45CoD67Lm87CUwLOdcNzPu4k7mat+xog5aFwaQuRjLBmmZcjl41QjVr9ti
La4PCMh7NwVMtHRqbYvgq785PsKAh+j4FSX1sj9NRzRPoJJ2qsre1Qn5tL/i6ovj
6s+3GxOQ5I1UzJX22PZFu003a582ha1CEFM0VaeDzzwbGNcV5SP+g2nw55zx9YRR
Rg8nGmjRuRtbs+/XAre2eQ5p
-----END CERTIFICATE-----
`
module.exports['ca-bundle.crt'] = `
-----BEGIN CERTIFICATE-----
MIIDJjCCAg4CAhnOMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD
VQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZMBcGA1UECgwQU3Ryb25n
TG9vcCwgSW5jLjESMBAGA1UECwwJU3Ryb25nT3BzMRowGAYDVQQDDBFjYS5zdHJv
bmdsb29wLmNvbTAeFw0xNTEyMDgyMzM1MzNaFw00MzA0MjQyMzM1MzNaMBkxFzAV
BgNVBAMMDnN0cm9uZ2xvb3AuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAwOYI7OZ2FX/YjRgLZoDQlbPc5UZXU/j0e1wwiJNPtPEax9Y5Uoza0Pnt
Ikzkc2SfvQ+IJrhXo385tI0W5juuqbHnE7UrjUuPjUX6NHevkxcs/flmjan5wnZM
cPsGhH71WDuUEEflvZihf2Se2x+xgZtMhc5XGmVmRuZFYKvkgUhA2/w8/QrK+jPT
n9QRJxZjWNh2RBdC1B7u4jffSmOSUljYFH1I2eTeY+Rdi6YUIYSU9gEoZxsv3Tia
SomfMF5jt2Mouo6MzA+IhLvvFjcrcph1Qxgi9RkfdCMMd+Ipm9YWELkyG1bDRpQy
0iyHD4gvVsAqz1Y2KdRSdc3Kt+nTqwIDAQABoxkwFzAVBgNVHREEDjAMhwQAAAAA
hwR/AAABMA0GCSqGSIb3DQEBBQUAA4IBAQAhy4J0hML3NgmDRHdL5/iTucBe22Mf
jJjg2aifD1S187dHm+Il4qZNO2plWwAhN0h704f+8wpsaALxUvBIu6nvlvcMP5PH
jGN5JLe2Km3UaPvYOQU2SgacLilu+uBcIo2JSHLV6O7ziqUj5Gior6YxDLCtEZie
Ea8aX5/YjuACtEMJ1JjRqjgkM66XAoUe0E8onOK3FgTIO3tGoTJwRp0zS50pFuP0
PsZtT04ck6mmXEXXknNoAyBCvPypfms9OHqcUIW9fiQnrGbS/Ri4QSQYj0DtFk/1
na4fY1gf3zTHxH8259b/TOOaPfTnCEsOQtjUrWNR4xhmVZ+HJy4yytUW
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDbzCCAlcCAmm6MA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAlVTMQswCQYD
VQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZMBcGA1UECgwQU3Ryb25n
TG9vcCwgSW5jLjESMBAGA1UECwwJU3Ryb25nT3BzMRowGAYDVQQDDBFjYS5zdHJv
bmdsb29wLmNvbTAeFw0xNTEyMDgyMzM1MzNaFw00MzA0MjQyMzM1MzNaMH0xCzAJ
BgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEZ
MBcGA1UECgwQU3Ryb25nTG9vcCwgSW5jLjESMBAGA1UECwwJU3Ryb25nT3BzMRow
GAYDVQQDDBFjYS5zdHJvbmdsb29wLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBANfj86jkvvYDjHBgiqWhk9Cj+bqiMq3MqnV0CBO4iuK33Fo6XssE
H+yVdXlIBFbFe6t655MdBVOR2Sfj7WqNh96vhu6PyDHiwcQlTaiLU6nhIed1J4Wv
lvnJHFmp8Wbtx5AgLT4UYu03ftvXEl2DLi3vhSL2tRM1ebXHB/KPbRWkb25DPX0P
foOHot3f2dgNe2x6kponf7E/QDmAu3s7Nlkfh+ryDhgGU7wocXEhXbprNqRqOGNo
xbXgUI+/9XDxYT/7Gn5LF/fPjtN+aB0SKMnTsDhprVlZie83mlqJ46fOOrR+vrsQ
mi/1m/TadrARtZoIExC/cQRdVM05EK4tUa8CAwEAATANBgkqhkiG9w0BAQsFAAOC
AQEAQ7k5WhyhDTIGYCNzRnrMHWSzGqa1y4tJMW06wafJNRqTm1cthq1ibc6Hfq5a
K10K0qMcgauRTfQ1MWrVCTW/KnJ1vkhiTOH+RvxapGn84gSaRmV6KZen0+gMsgae
KEGe/3Hn+PmDVV+PTamHgPACfpTww38WHIe/7Ce9gHfG7MZ8cKHNZhDy0IAYPln+
YRwMLd7JNQffHAbWb2CE1mcea4H/12U8JZW5tHCF6y9V+7IuDzqwIrLKcW3lG17n
VUG6ODF/Ryqn3V5X+TL91YyXi6c34y34IpC7MQDV/67U7+5Bp5CfeDPWW2wVSrW+
uGZtfEvhbNm6m2i4UNmpCXxUZQ==
-----END CERTIFICATE-----
`
================================================
FILE: test/fixtures/nodedir/include/node/config.gypi
================================================
# Test configuration
{
'variables': {
'build_with_electron': true
}
}
================================================
FILE: test/fixtures/test-charmap.py
================================================
import sys
import locale
try:
reload(sys)
except NameError: # Python 3
pass
def main():
encoding = locale.getdefaultlocale()[1]
if not encoding:
return False
try:
sys.setdefaultencoding(encoding)
except AttributeError: # Python 3
pass
textmap = {
"cp936": "\u4e2d\u6587",
"cp1252": "Lat\u012bna",
"cp932": "\u306b\u307b\u3093\u3054",
}
if encoding in textmap:
print(textmap[encoding])
return True
if __name__ == "__main__":
print(main())
================================================
FILE: test/simple-proxy.js
================================================
'use strict'
const http = require('http')
const https = require('https')
const server = http.createServer(handler)
const port = +process.argv[2]
const prefix = process.argv[3]
const upstream = process.argv[4]
let calls = 0
server.listen(port)
function handler (req, res) {
if (req.url.indexOf(prefix) !== 0) {
throw new Error('request url [' + req.url + '] does not start with [' + prefix + ']')
}
const upstreamUrl = upstream + req.url.substring(prefix.length)
https.get(upstreamUrl, function (ures) {
ures.on('end', function () {
if (++calls === 2) {
server.close()
}
})
ures.pipe(res)
})
}
================================================
FILE: test/test-addon.js
================================================
'use strict'
const { describe, it } = require('mocha')
const assert = require('assert')
const path = require('path')
const fs = require('graceful-fs')
const os = require('os')
const cp = require('child_process')
const util = require('../lib/util')
const { platformTimeout } = require('./common')
const addonPath = path.resolve(__dirname, 'node_modules', 'hello_world')
const nodeGyp = path.resolve(__dirname, '..', 'bin', 'node-gyp.js')
const execFileSync = (...args) => cp.execFileSync(...args).toString().trim()
const execFile = async (cmd) => {
const [err,, stderr] = await util.execFile(process.execPath, cmd, {
env: { ...process.env, NODE_GYP_NULL_LOGGER: undefined },
encoding: 'utf-8'
})
return [err, stderr.toString().trim().split(/\r?\n/)]
}
function runHello (hostProcess = process.execPath) {
const testCode = "console.log(require('hello_world').hello())"
return execFileSync(hostProcess, ['-e', testCode], { cwd: __dirname })
}
function getEncoding () {
const code = 'import locale;print(locale.getdefaultlocale()[1])'
return execFileSync('python', ['-c', code])
}
function checkCharmapValid () {
try {
const data = execFileSync('python', ['fixtures/test-charmap.py'], { cwd: __dirname })
return data.split('\n').pop() === 'True'
} catch {
return false
}
}
describe('addon', function () {
it('build simple addon', async function () {
this.timeout(platformTimeout(1, { win32: 5 }))
// Set the loglevel otherwise the output disappears when run via 'npm test'
const cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose']
const [err, logLines] = await execFile(cmd)
const lastLine = logLines[logLines.length - 1]
assert.strictEqual(err, null)
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
assert.strictEqual(runHello(), 'world')
})
it('build simple addon in path with non-ascii characters', async function () {
if (!checkCharmapValid()) {
return this.skip('python console app can\'t encode non-ascii character.')
}
// Select non-ascii characters by current encoding
const testDirName = {
cp936: '文件夹',
cp1252: 'Latīna',
cp932: 'フォルダ'
}[getEncoding()]
// If encoding is UTF-8 or other then no need to test
if (!testDirName) {
return this.skip('no need to test')
}
this.timeout(platformTimeout(1, { win32: 5 }))
let data
const configPath = path.join(addonPath, 'build', 'config.gypi')
try {
data = fs.readFileSync(configPath, 'utf8')
} catch (err) {
return assert.fail(err)
}
const config = JSON.parse(data.replace(/#.+\n/, ''))
const nodeDir = config.variables.nodedir
const testNodeDir = path.join(addonPath, testDirName)
// Create symbol link to path with non-ascii characters
try {
fs.symlinkSync(nodeDir, testNodeDir, 'dir')
} catch (err) {
switch (err.code) {
case 'EEXIST': break
case 'EPERM':
return assert.fail(err, null, 'Please try to running console as an administrator')
default:
return assert.fail(err)
}
}
const cmd = [
nodeGyp,
'rebuild',
'-C',
addonPath,
'--loglevel=verbose',
'-nodedir=' + testNodeDir
]
const [err, logLines] = await execFile(cmd)
try {
fs.unlink(testNodeDir)
} catch (err) {
assert.fail(err)
}
const lastLine = logLines[logLines.length - 1]
assert.strictEqual(err, null)
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
assert.strictEqual(runHello(), 'world')
})
it('addon works with renamed host executable', async function () {
this.timeout(platformTimeout(1, { win32: 5 }))
const notNodePath = path.join(os.tmpdir(), 'notnode' + path.extname(process.execPath))
fs.copyFileSync(process.execPath, notNodePath)
const cmd = [nodeGyp, 'rebuild', '-C', addonPath, '--loglevel=verbose']
const [err, logLines] = await execFile(cmd)
const lastLine = logLines[logLines.length - 1]
assert.strictEqual(err, null)
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
assert.strictEqual(runHello(notNodePath), 'world')
fs.unlinkSync(notNodePath)
})
})
================================================
FILE: test/test-configure-nodedir.js
================================================
'use strict'
const { describe, it } = require('mocha')
const assert = require('assert')
const path = require('path')
const os = require('os')
const gyp = require('../lib/node-gyp')
const requireInject = require('require-inject')
const semver = require('semver')
const versionSemver = semver.parse(process.version)
const configure = requireInject('../lib/configure', {
'graceful-fs': {
openSync: () => 0,
closeSync: () => {},
existsSync: () => true,
readFileSync: () => '#define NODE_MAJOR_VERSION ' + versionSemver.major + '\n' +
'#define NODE_MINOR_VERSION ' + versionSemver.minor + '\n' +
'#define NODE_PATCH_VERSION ' + versionSemver.patch + '\n',
promises: {
stat: async () => ({}),
mkdir: async () => {},
writeFile: async () => {}
}
}
})
const configure2 = requireInject('../lib/configure', {
'graceful-fs': {
openSync: () => 0,
closeSync: () => {},
existsSync: () => true,
readFileSync: () => '#define NODE_MAJOR_VERSION 8\n' +
'#define NODE_MINOR_VERSION 0\n' +
'#define NODE_PATCH_VERSION 0\n',
promises: {
stat: async () => ({}),
mkdir: async () => {},
writeFile: async () => {}
}
}
})
const SPAWN_RESULT = cb => ({ on: function () { cb() } })
const driveLetter = os.platform() === 'win32' ? `${process.cwd().split(path.sep)[0]}` : ''
function checkTargetPath (target, value) {
let targetPath = path.join(path.sep, target, 'include',
'node', 'common.gypi')
if (process.platform === 'win32') {
targetPath = driveLetter + targetPath
}
return targetPath.localeCompare(value) === 0
}
describe('configure-nodedir', function () {
it('configure nodedir with node-gyp command line', function (done) {
const prog = gyp()
prog.parseArgv(['dummy_prog', 'dummy_script', '--nodedir=' + path.sep + 'usr'])
prog.spawn = function (program, args) {
for (let i = 0; i < args.length; i++) {
if (checkTargetPath('usr', args[i])) {
return SPAWN_RESULT(done)
}
};
assert.fail()
}
configure(prog, [], assert.fail)
})
if (process.config.variables.use_prefix_to_find_headers) {
it('use-prefix-to-find-headers build time option - match', function (done) {
const prog = gyp()
prog.parseArgv(['dummy_prog', 'dummy_script'])
prog.spawn = function (program, args) {
for (let i = 0; i < args.length; i++) {
const nodedir = process.config.variables.node_prefix
if (checkTargetPath(nodedir, args[i])) {
return SPAWN_RESULT(done)
}
};
assert.fail()
}
configure(prog, [], assert.fail)
})
it('use-prefix-to-find-headers build time option - no match', function (done) {
const prog = gyp()
prog.parseArgv(['dummy_prog', 'dummy_script'])
prog.spawn = function (program, args) {
for (let i = 0; i < args.length; i++) {
const nodedir = process.config.variables.node_prefix
if (checkTargetPath(nodedir, args[i])) {
assert.fail()
}
};
return SPAWN_RESULT(done)
}
configure2(prog, [], assert.fail)
})
it('use-prefix-to-find-headers build time option, target specified', function (done) {
const prog = gyp()
prog.parseArgv(['dummy_prog', 'dummy_script', '--target=8.0.0'])
prog.spawn = function (program, args) {
for (let i = 0; i < args.length; i++) {
const nodedir = process.config.variables.node_prefix
if (checkTargetPath(nodedir, args[i])) {
assert.fail()
}
};
return SPAWN_RESULT(done)
}
configure(prog, [], assert.fail)
})
}
})
================================================
FILE: test/test-configure-python.js
================================================
'use strict'
const { describe, it } = require('mocha')
const assert = require('assert')
const path = require('path')
const { devDir } = require('./common')
const gyp = require('../lib/node-gyp')
const requireInject = require('require-inject')
const configure = requireInject('../lib/configure', {
'graceful-fs': {
openSync: () => 0,
closeSync: () => {},
existsSync: () => {},
promises: {
stat: async () => ({}),
mkdir: async () => {},
writeFile: async () => {}
}
}
})
const EXPECTED_PYPATH = path.join(__dirname, '..', 'gyp', 'pylib')
const SEPARATOR = process.platform === 'win32' ? ';' : ':'
const SPAWN_RESULT = cb => ({ on: function () { cb() } })
describe('configure-python', function () {
it('configure PYTHONPATH with no existing env', function (done) {
delete process.env.PYTHONPATH
const prog = gyp()
prog.parseArgv([])
prog.spawn = function () {
assert.strictEqual(process.env.PYTHONPATH, EXPECTED_PYPATH)
return SPAWN_RESULT(done)
}
prog.devDir = devDir
configure(prog, [], assert.fail)
})
it('configure PYTHONPATH with existing env of one dir', function (done) {
const existingPath = path.join('a', 'b')
process.env.PYTHONPATH = existingPath
const prog = gyp()
prog.parseArgv([])
prog.spawn = function () {
assert.strictEqual(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR))
const dirs = process.env.PYTHONPATH.split(SEPARATOR)
assert.deepStrictEqual(dirs, [EXPECTED_PYPATH, existingPath])
return SPAWN_RESULT(done)
}
prog.devDir = devDir
configure(prog, [], assert.fail)
})
it('configure PYTHONPATH with existing env of multiple dirs', function (done) {
const pythonDir1 = path.join('a', 'b')
const pythonDir2 = path.join('b', 'c')
const existingPath = [pythonDir1, pythonDir2].join(SEPARATOR)
process.env.PYTHONPATH = existingPath
const prog = gyp()
prog.parseArgv([])
prog.spawn = function () {
assert.strictEqual(process.env.PYTHONPATH, [EXPECTED_PYPATH, existingPath].join(SEPARATOR))
const dirs = process.env.PYTHONPATH.split(SEPARATOR)
assert.deepStrictEqual(dirs, [EXPECTED_PYPATH, pythonDir1, pythonDir2])
return SPAWN_RESULT(done)
}
prog.devDir = devDir
configure(prog, [], assert.fail)
})
})
================================================
FILE: test/test-create-config-gypi.js
================================================
'use strict'
const path = require('path')
const { describe, it } = require('mocha')
const assert = require('assert')
const gyp = require('../lib/node-gyp')
const { parseConfigGypi, getCurrentConfigGypi } = require('../lib/create-config-gypi')
describe('create-config-gypi', function () {
it('config.gypi with no options', async function () {
const prog = gyp()
prog.parseArgv([])
const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} })
assert.strictEqual(config.target_defaults.default_configuration, 'Release')
assert.strictEqual(config.variables.target_arch, process.arch)
})
it('config.gypi with --debug', async function () {
const prog = gyp()
prog.parseArgv(['_', '_', '--debug'])
const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} })
assert.strictEqual(config.target_defaults.default_configuration, 'Debug')
})
it('config.gypi with custom options', async function () {
const prog = gyp()
prog.parseArgv(['_', '_', '--shared-libxml2'])
const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} })
assert.strictEqual(config.variables.shared_libxml2, true)
})
it('config.gypi with nodedir', async function () {
const nodeDir = path.join(__dirname, 'fixtures', 'nodedir')
const prog = gyp()
prog.parseArgv(['_', '_', `--nodedir=${nodeDir}`])
const config = await getCurrentConfigGypi({ gyp: prog, nodeDir, vsInfo: {} })
assert.strictEqual(config.variables.build_with_electron, true)
})
it('config.gypi with --force-process-config', async function () {
const nodeDir = path.join(__dirname, 'fixtures', 'nodedir')
const prog = gyp()
prog.parseArgv(['_', '_', '--force-process-config', `--nodedir=${nodeDir}`])
const config = await getCurrentConfigGypi({ gyp: prog, nodeDir, vsInfo: {} })
assert.strictEqual(config.variables.build_with_electron, undefined)
})
it('config.gypi parsing', function () {
const str = "# Some comments\n{'variables': {'multiline': 'A'\n'B'}}"
const config = parseConfigGypi(str)
assert.deepStrictEqual(config, { variables: { multiline: 'AB' } })
})
})
================================================
FILE: test/test-download.js
================================================
'use strict'
const { describe, it, after } = require('mocha')
const assert = require('assert')
const fs = require('fs/promises')
const path = require('path')
const http = require('http')
const https = require('https')
const install = require('../lib/install')
const { download, readCAFile } = require('../lib/download')
const { FULL_TEST, devDir, platformTimeout } = require('./common')
const gyp = require('../lib/node-gyp')
const certs = require('./fixtures/certs')
describe('download', function () {
it('download over http', async function () {
const server = http.createServer((req, res) => {
assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
res.end('ok')
})
after(() => new Promise((resolve) => server.close(resolve)))
const host = 'localhost'
await new Promise((resolve) => server.listen(0, host, resolve))
const { port } = server.address()
const gyp = {
opts: {},
version: '42'
}
const url = `http://${host}:${port}`
const res = await download(gyp, url)
assert.strictEqual(await res.text(), 'ok')
})
it('download over https with custom ca', async function () {
const cafile = path.join(__dirname, 'fixtures/ca.crt')
const cacontents = certs['ca.crt']
const cert = certs['server.crt']
const key = certs['server.key']
await fs.writeFile(cafile, cacontents, 'utf8')
const ca = await readCAFile(cafile)
assert.strictEqual(ca.length, 1)
const options = { ca, cert, key }
const server = https.createServer(options, (req, res) => {
assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
res.end('ok')
})
after(async () => {
await new Promise((resolve) => server.close(resolve))
await fs.unlink(cafile)
})
server.on('clientError', (err) => { throw err })
const host = 'localhost'
await new Promise((resolve) => server.listen(0, host, resolve))
const { port } = server.address()
const gyp = {
opts: { cafile },
version: '42'
}
const url = `https://${host}:${port}`
const res = await download(gyp, url)
assert.strictEqual(await res.text(), 'ok')
})
it('download over http with proxy', async function () {
const server = http.createServer((_, res) => {
res.end('ok')
})
const pserver = http.createServer((req, res) => {
assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
res.end('proxy ok')
})
after(() => Promise.all([
new Promise((resolve) => server.close(resolve)),
new Promise((resolve) => pserver.close(resolve))
]))
const host = 'localhost'
await new Promise((resolve) => server.listen(0, host, resolve))
const { port } = server.address()
await new Promise((resolve) => pserver.listen(port + 1, host, resolve))
const gyp = {
opts: {
proxy: `http://${host}:${port + 1}`,
noproxy: 'bad'
},
version: '42'
}
const url = `http://${host}:${port}`
const res = await download(gyp, url)
assert.strictEqual(await res.text(), 'proxy ok')
})
it('download over http with noproxy', async function () {
const server = http.createServer((req, res) => {
assert.strictEqual(req.headers['user-agent'], `node-gyp v42 (node ${process.version})`)
res.end('ok')
})
const pserver = http.createServer((_, res) => {
res.end('proxy ok')
})
after(() => Promise.all([
new Promise((resolve) => server.close(resolve)),
new Promise((resolve) => pserver.close(resolve))
]))
const host = 'localhost'
await new Promise((resolve) => server.listen(0, host, resolve))
const { port } = server.address()
await new Promise((resolve) => pserver.listen(port + 1, host, resolve))
const gyp = {
opts: {
proxy: `http://${host}:${port + 1}`,
noproxy: host
},
version: '42'
}
const url = `http://${host}:${port}`
const res = await download(gyp, url)
assert.strictEqual(await res.text(), 'ok')
})
it('download with missing cafile', async function () {
const gyp = {
opts: { cafile: 'no.such.file' }
}
try {
await download(gyp, {}, 'http://bad/')
} catch (e) {
assert.ok(/no.such.file/.test(e.message))
}
})
it('check certificate splitting', async function () {
const cafile = path.join(__dirname, 'fixtures/ca-bundle.crt')
const cacontents = certs['ca-bundle.crt']
await fs.writeFile(cafile, cacontents, 'utf8')
after(async () => {
await fs.unlink(cafile)
})
const cas = await readCAFile(path.join(__dirname, 'fixtures/ca-bundle.crt'))
assert.strictEqual(cas.length, 2)
assert.notStrictEqual(cas[0], cas[1])
})
// only run this test if we are running a version of Node with predictable version path behavior
it('download headers (actual)', async function () {
if (!FULL_TEST) {
return this.skip('Skipping actual download of headers due to test environment configuration')
}
this.timeout(platformTimeout(1, { win32: 5 }))
const expectedDir = path.join(devDir, process.version.replace(/^v/, ''))
await fs.rm(expectedDir, { recursive: true, force: true, maxRetries: 3 })
const prog = gyp()
prog.parseArgv([])
prog.devDir = devDir
await install(prog, [])
const data = await fs.readFile(path.join(expectedDir, 'installVersion'), 'utf8')
assert.strictEqual(data, '11\n', 'correct installVersion')
const list = await fs.readdir(path.join(expectedDir, 'include/node'))
assert.ok(list.includes('common.gypi'))
assert.ok(list.includes('config.gypi'))
assert.ok(list.includes('node.h'))
assert.ok(list.includes('node_version.h'))
assert.ok(list.includes('openssl'))
assert.ok(list.includes('uv'))
assert.ok(list.includes('uv.h'))
assert.ok(list.includes('v8-platform.h'))
assert.ok(list.includes('v8.h'))
assert.ok(list.includes('zlib.h'))
const lines = (await fs.readFile(path.join(expectedDir, 'include/node/node_version.h'), 'utf8')).split('\n')
// extract the 3 version parts from the defines to build a valid version string and
// and check them against our current env version
const version = ['major', 'minor', 'patch'].reduce((version, type) => {
const re = new RegExp(`^#define\\sNODE_${type.toUpperCase()}_VERSION`)
const line = lines.find((l) => re.test(l))
const i = line ? parseInt(line.replace(/^[^0-9]+([0-9]+).*$/, '$1'), 10) : 'ERROR'
return `${version}${type !== 'major' ? '.' : 'v'}${i}`
}, '')
assert.strictEqual(version, process.version)
})
})
================================================
FILE: test/test-find-accessible-sync.js
================================================
'use strict'
const { describe, it } = require('mocha')
const assert = require('assert')
const path = require('path')
const requireInject = require('require-inject')
const { findAccessibleSync } = requireInject('../lib/util', {
'graceful-fs': {
closeSync: function () { return undefined },
openSync: function (path) {
if (readableFiles.some(function (f) { return f === path })) {
return 0
} else {
const error = new Error('ENOENT - not found')
throw error
}
}
}
})
const dir = path.sep + 'testdir'
const readableFile = 'readable_file'
const anotherReadableFile = 'another_readable_file'
const readableFileInDir = 'somedir' + path.sep + readableFile
const readableFiles = [
path.resolve(dir, readableFile),
path.resolve(dir, anotherReadableFile),
path.resolve(dir, readableFileInDir)
]
describe('find-accessible-sync', function () {
it('find accessible - empty array', function () {
const candidates = []
const found = findAccessibleSync('test', dir, candidates)
assert.strictEqual(found, undefined)
})
it('find accessible - single item array, readable', function () {
const candidates = [readableFile]
const found = findAccessibleSync('test', dir, candidates)
assert.strictEqual(found, path.resolve(dir, readableFile))
})
it('find accessible - single item array, readable in subdir', function () {
const candidates = [readableFileInDir]
const found = findAccessibleSync('test', dir, candidates)
assert.strictEqual(found, path.resolve(dir, readableFileInDir))
})
it('find accessible - single item array, unreadable', function () {
const candidates = ['unreadable_file']
const found = findAccessibleSync('test', dir, candidates)
assert.strictEqual(found, undefined)
})
it('find accessible - multi item array, no matches', function () {
const candidates = ['non_existent_file', 'unreadable_file']
const found = findAccessibleSync('test', dir, candidates)
assert.strictEqual(found, undefined)
})
it('find accessible - multi item array, single match', function () {
const candidates = ['non_existent_file', readableFile]
const found = findAccessibleSync('test', dir, candidates)
assert.strictEqual(found, path.resolve(dir, readableFile))
})
it('find accessible - multi item array, return first match', function () {
const candidates = ['non_existent_file', anotherReadableFile, readableFile]
const found = findAccessibleSync('test', dir, candidates)
assert.strictEqual(found, path.resolve(dir, anotherReadableFile))
})
})
================================================
FILE: test/test-find-node-directory.js
================================================
'use strict'
const { describe, it } = require('mocha')
const assert = require('assert')
const path = require('path')
const findNodeDirectory = require('../lib/find-node-directory')
const platforms = ['darwin', 'freebsd', 'linux', 'sunos', 'win32', 'aix', 'os400']
describe('find-node-directory', function () {
// we should find the directory based on the directory
// the script is running in and it should match the layout
// in a build tree where npm is installed in
// .... /deps/npm
it('test find-node-directory - node install', function () {
for (let next = 0; next < platforms.length; next++) {
const processObj = { execPath: '/x/y/bin/node', platform: platforms[next] }
assert.strictEqual(
findNodeDirectory('/x/deps/npm/node_modules/node-gyp/lib', processObj),
path.join('/x'))
}
})
// we should find the directory based on the directory
// the script is running in and it should match the layout
// in an installed tree where npm is installed in
// .... /lib/node_modules/npm or .../node_modules/npm
// depending on the patform
it('test find-node-directory - node build', function () {
for (let next = 0; next < platforms.length; next++) {
const processObj = { execPath: '/x/y/bin/node', platform: platforms[next] }
if (platforms[next] === 'win32') {
assert.strictEqual(
findNodeDirectory('/y/node_modules/npm/node_modules/node-gyp/lib',
processObj), path.join('/y'))
} else {
assert.strictEqual(
findNodeDirectory('/y/lib/node_modules/npm/node_modules/node-gyp/lib',
processObj), path.join('/y'))
}
}
})
// we should find the directory based on the execPath
// for node and match because it was in the bin directory
it('test find-node-directory - node in bin directory', function () {
for (let next = 0; next < platforms.length; next++) {
const processObj = { execPath: '/x/y/bin/node', platform: platforms[next] }
assert.strictEqual(
findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj),
path.join('/x/y'))
}
})
// we should find the directory based on the execPath
// for node and match because it was in the Release directory
it('test find-node-directory - node in build release dir', function () {
for (let next = 0; next < platforms.length; next++) {
let processObj
if (platforms[next] === 'win32') {
processObj = { execPath: '/x/y/Release/node', platform: platforms[next] }
} else {
processObj = {
execPath: '/x/y/out/Release/node',
platform: platforms[next]
}
}
assert.strictEqual(
findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj),
path.join('/x/y'))
}
})
// we should find the directory based on the execPath
// for node and match because it was in the Debug directory
it('test find-node-directory - node in Debug release dir', function () {
for (let next = 0; next < platforms.length; next++) {
let processObj
if (platforms[next] === 'win32') {
processObj = { execPath: '/a/b/Debug/node', platform: platforms[next] }
} else {
processObj = { execPath: '/a/b/out/Debug/node', platform: platforms[next] }
}
assert.strictEqual(
findNodeDirectory('/nothere/npm/node_modules/node-gyp/lib', processObj),
path.join('/a/b'))
}
})
// we should not find it as it will not match based on the execPath nor
// the directory from which the script is running
it('test find-node-directory - not found', function () {
for (let next = 0; next < platforms.length; next++) {
const processObj = { execPath: '/x/y/z/y', platform: next }
assert.strictEqual(findNodeDirectory('/a/b/c/d', processObj), '')
}
})
// we should find the directory based on the directory
// the script is running in and it should match the layout
// in a build tree where npm is installed in
// .... /deps/npm
// same test as above but make sure additional directory entries
// don't cause an issue
it('test find-node-directory - node install', function () {
for (let next = 0; next < platforms.length; next++) {
const processObj = { execPath: '/x/y/bin/node', platform: platforms[next] }
assert.strictEqual(
findNodeDirectory('/x/y/z/a/b/c/deps/npm/node_modules/node-gyp/lib',
processObj), path.join('/x/y/z/a/b/c'))
}
})
})
================================================
FILE: test/test-find-python.js
================================================
'use strict'
delete process.env.PYTHON
const { describe, it, after } = require('mocha')
const assert = require('assert')
const PythonFinder = require('../lib/find-python')
const { execFile } = require('../lib/util')
const { poison } = require('./common')
const fs = require('fs')
const path = require('path')
const os = require('os')
class TestPythonFinder extends PythonFinder {
constructor (...args) {
super(...args)
delete this.env.NODE_GYP_FORCE_PYTHON
}
async findPython () {
try {
return { err: null, python: await super.findPython() }
} catch (err) {
return { err, python: null }
}
}
}
describe('find-python', function () {
it('find python', async function () {
const found = await PythonFinder.findPython(null)
const [err, stdout, stderr] = await execFile(found, ['-V'], { encoding: 'utf-8' })
assert.strictEqual(err, null)
assert.ok(/Python 3/.test(stdout))
assert.strictEqual(stderr, '')
})
it('find python - encoding', async function () {
const found = await PythonFinder.findPython(null)
const testFolderPath = fs.mkdtempSync(path.join(os.tmpdir(), 'test-ü-'))
const testFilePath = path.join(testFolderPath, 'python.exe')
after(function () {
try {
fs.unlinkSync(testFilePath)
fs.rmdirSync(testFolderPath)
} catch {}
})
try {
fs.symlinkSync(found, testFilePath)
} catch (err) {
switch (err.code) {
case 'EPERM':
return assert.fail(err, null, 'Please try to run console as an administrator')
default:
return assert.fail(err)
}
}
const finder = new PythonFinder(testFilePath)
await assert.doesNotReject(finder.checkCommand(testFilePath))
})
it('find python - python', async function () {
const f = new TestPythonFinder('python')
f.execFile = async function (program, args, opts) {
f.execFile = async function (program, args, opts) {
poison(f, 'execFile')
assert.strictEqual(program, '/path/python')
assert.ok(/sys\.version_info/.test(args[1]))
return [null, '3.9.1']
}
assert.strictEqual(program, process.platform === 'win32' ? '"python"' : 'python')
assert.ok(/sys\.executable/.test(args[1]))
return [null, '/path/python']
}
const { err, python } = await f.findPython()
assert.strictEqual(err, null)
assert.strictEqual(python, '/path/python')
})
it('find python - python too old', async function () {
const f = new TestPythonFinder(null)
f.execFile = async function (program, args, opts) {
if (/sys\.executable/.test(args[args.length - 1])) {
return [null, '/path/python']
} else if (/sys\.version_info/.test(args[args.length - 1])) {
return [null, '2.3.4']
} else {
assert.fail()
}
}
const { err } = await f.findPython()
assert.ok(/Could not find any Python/.test(err))
assert.ok(/not supported/i.test(f.errorLog))
})
it('find python - no python', async function () {
const f = new TestPythonFinder(null)
f.execFile = async function (program, args, opts) {
if (/sys\.executable/.test(args[args.length - 1])) {
throw new Error('not found')
} else if (/sys\.version_info/.test(args[args.length - 1])) {
throw new Error('not a Python executable')
} else {
assert.fail()
}
}
const { err } = await f.findPython()
assert.ok(/Could not find any Python/.test(err))
assert.ok(/not in PATH/.test(f.errorLog))
})
it('find python - no python2, no python, unix', async function () {
const f = new TestPythonFinder(null)
f.checkPyLauncher = assert.fail
f.win = false
f.execFile = async function (program, args, opts) {
if (/sys\.executable/.test(args[args.length - 1])) {
throw new Error('not found')
} else {
assert.fail()
}
}
const { err } = await f.findPython()
assert.ok(/Could not find any Python/.test(err))
assert.ok(/not in PATH/.test(f.errorLog))
})
it('find python - no python, use python launcher', async function () {
const f = new TestPythonFinder(null)
f.win = true
f.execFile = async function (program, args, opts) {
if (program === 'py.exe') {
assert.notStrictEqual(args.indexOf('-3'), -1)
assert.notStrictEqual(args.indexOf('-c'), -1)
return [null, 'Z:\\snake.exe']
}
if (/sys\.executable/.test(args[args.length - 1])) {
throw new Error('not found')
} else if (f.winDefaultLocations.includes(program)) {
throw new Error('not found')
} else if (/sys\.version_info/.test(args[args.length - 1])) {
if (program === 'Z:\\snake.exe') {
return [null, '3.9.0']
} else {
assert.fail()
}
} else {
assert.fail()
}
}
const { err, python } = await f.findPython()
assert.strictEqual(err, null)
assert.strictEqual(python, 'Z:\\snake.exe')
})
it('find python - no python, no python launcher, good guess', async function () {
const f = new TestPythonFinder(null)
f.win = true
const expectedProgram = f.winDefaultLocations[0]
f.execFile = async function (program, args, opts) {
if (program === 'py.exe') {
throw new Error('not found')
}
if (/sys\.executable/.test(args[args.length - 1])) {
throw new Error('not found')
} else if (program === expectedProgram &&
/sys\.version_info/.test(args[args.length - 1])) {
return [null, '3.7.3']
} else {
assert.fail()
}
}
const { err, python } = await f.findPython()
assert.strictEqual(err, null)
assert.ok(python === expectedProgram)
})
it('find python - no python, no python launcher, bad guess', async function () {
const f = new TestPythonFinder(null)
f.win = true
f.execFile = async function (program, args, opts) {
if (/sys\.executable/.test(args[args.length - 1])) {
throw new Error('not found')
} else if (/sys\.version_info/.test(args[args.length - 1])) {
throw new Error('not a Python executable')
} else {
assert.fail()
}
}
const { err } = await f.findPython()
assert.ok(/Could not find any Python/.test(err))
assert.ok(/not in PATH/.test(f.errorLog))
})
})
================================================
FILE: test/test-find-visualstudio.js
================================================
'use strict'
const { describe, it } = require('mocha')
const assert = require('assert')
const fs = require('fs')
const path = require('path')
const VisualStudioFinder = require('../lib/find-visualstudio')
const { poison } = require('./common')
const semverV1 = { major: 1, minor: 0, patch: 0 }
delete process.env.VCINSTALLDIR
class TestVisualStudioFinder extends VisualStudioFinder {
async findVisualStudio () {
try {
return { err: null, info: await super.findVisualStudio() }
} catch (err) {
return { err, info: null }
}
}
}
describe('find-visualstudio', function () {
this.beforeAll(function () {
// Condition to skip the test suite
if (process.env.SystemRoot === undefined) {
process.env.SystemRoot = '/'
}
})
it('VS2013', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
finder.findNewVSUsingSetupModule = async () => null
finder.findNewVS = async () => null
finder.regSearchKeys = async (keys, value, addOpts) => {
for (let i = 0; i < keys.length; ++i) {
const fullName = `${keys[i]}\\${value}`
switch (fullName) {
case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0':
case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0':
continue
case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0':
assert.ok(true, `expected search for registry value ${fullName}`)
return 'C:\\VS2013\\VC\\'
case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath':
assert.ok(true, `expected search for registry value ${fullName}`)
return 'C:\\MSBuild12\\'
default:
assert.fail(`unexpected search for registry value ${fullName}`)
}
}
throw new Error()
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: 'C:\\MSBuild12\\MSBuild.exe',
path: 'C:\\VS2013',
sdk: null,
toolset: 'v120',
version: '12.0',
versionMajor: 12,
versionMinor: 0,
versionYear: 2013
})
})
it('VS2013 should not be found on new node versions', async function () {
const finder = new TestVisualStudioFinder({
major: 10,
minor: 0,
patch: 0
}, null)
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => {
const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
finder.regSearchKeys = async (keys, value, addOpts) => {
for (let i = 0; i < keys.length; ++i) {
const fullName = `${keys[i]}\\${value}`
switch (fullName) {
case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0':
case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0':
continue
default:
assert.fail(`unexpected search for registry value ${fullName}`)
}
}
throw new Error()
}
const { err, info } = await finder.findVisualStudio()
assert.ok(/find .* Visual Studio/i.test(err), 'expect error')
assert.ok(!info, 'no data')
})
it('VS2015', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
finder.findNewVSUsingSetupModule = async () => null
finder.findNewVS = async () => null
finder.regSearchKeys = async (keys, value, addOpts) => {
for (let i = 0; i < keys.length; ++i) {
const fullName = `${keys[i]}\\${value}`
switch (fullName) {
case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0':
assert.ok(true, `expected search for registry value ${fullName}`)
return 'C:\\VS2015\\VC\\'
case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath':
assert.ok(true, `expected search for registry value ${fullName}`)
return 'C:\\MSBuild14\\'
default:
assert.fail(`unexpected search for registry value ${fullName}`)
}
}
throw new Error()
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: 'C:\\MSBuild14\\MSBuild.exe',
path: 'C:\\VS2015',
sdk: null,
toolset: 'v140',
version: '14.0',
versionMajor: 14,
versionMinor: 0,
versionYear: 2015
})
})
it('error from PowerShell', async function () {
const finder = new TestVisualStudioFinder(semverV1, null, null)
const vsInfo = finder.parseData(new Error('Error msg'), '', '')
assert.ok(/use PowerShell/i.test(finder.errorLog[0]), `expect error, output: ${finder.errorLog[0]}`)
assert.ok(/error msg/i.test(finder.errorLog[0]), `expect error, output: ${finder.errorLog[0]}`)
assert.equal(vsInfo, null)
})
it('empty output from PowerShell', async function () {
const finder = new TestVisualStudioFinder(semverV1, null, null)
const vsInfo = finder.parseData(null, '', '', { checkIsArray: true })
assert.ok(/use PowerShell/i.test(finder.errorLog[0]), `expect error, output: ${finder.errorLog[0]}`)
assert.equal(vsInfo, null)
})
it('output from PowerShell not JSON', async function () {
const finder = new TestVisualStudioFinder(semverV1, null, null)
const vsInfo = finder.parseData(null, 'AAAABBBB', '', { checkIsArray: true })
assert.ok(/use PowerShell/i.test(finder.errorLog[0]), `expect error, output: ${finder.errorLog[0]}`)
assert.equal(vsInfo, null)
})
it('wrong JSON from PowerShell', async function () {
const finder = new TestVisualStudioFinder(semverV1, null, null)
const vsInfo = finder.parseData(null, '{}', '', { checkIsArray: true })
assert.ok(/use PowerShell/i.test(finder.errorLog[0]), `expect error, output: ${finder.errorLog[0]}`)
assert.ok(/expected array/i.test(finder.errorLog[0]), `expect error, output: ${finder.errorLog[0]}`)
assert.equal(vsInfo, null)
})
it('empty JSON from PowerShell', async function () {
const finder = new TestVisualStudioFinder(semverV1, null, null)
const vsInfo = finder.parseData(null, '[]', '', { checkIsArray: true })
assert.equal(finder.errorLog.length, 0)
assert.equal(vsInfo.length, 0)
})
it('future version', async function () {
const finder = new TestVisualStudioFinder(semverV1, null, null)
const vsInfo = finder.parseData(null, JSON.stringify([{
packages: [
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
'Microsoft.VisualStudio.Component.Windows10SDK.17763',
'Microsoft.VisualStudio.VC.MSBuild.Base'
],
path: 'C:\\VS',
version: '9999.9999.9999.9999'
}]), '', { checkIsArray: true })
assert.equal(finder.errorLog.length, 0)
assert.equal(vsInfo[0].packages.length, 3)
})
it('single unusable VS2017', async function () {
const finder = new TestVisualStudioFinder(semverV1, null, null)
const file = path.join(__dirname, 'fixtures', 'VS_2017_Unusable.txt')
const data = fs.readFileSync(file)
const vsInfo = finder.parseData(null, data, '', { checkIsArray: true })
assert.equal(finder.errorLog.length, 0)
assert.equal(vsInfo.length, 1)
assert.equal(vsInfo[0].InstallationPath, undefined)
assert.notEqual(vsInfo[0].path, undefined)
assert.ok(vsInfo[0].packages.length > 1)
})
it('minimal VS2017 Build Tools', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2017_BuildTools_minimal.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2017_BuildTools_minimal.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' +
'BuildTools\\MSBuild\\15.0\\Bin\\MSBuild.exe',
path:
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools',
sdk: '10.0.17134.0',
toolset: 'v141',
version: '15.9.28307.665',
versionMajor: 15,
versionMinor: 9,
versionYear: 2017
})
})
it('VS2017 Community with C++ workload', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2017_Community_workload.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2017_Community_workload.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' +
'Community\\MSBuild\\15.0\\Bin\\MSBuild.exe',
path:
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community',
sdk: '10.0.17763.0',
toolset: 'v141',
version: '15.9.28307.665',
versionMajor: 15,
versionMinor: 9,
versionYear: 2017
})
})
it('VS2017 Express', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures', 'VS_2017_Express.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => {
const file = path.join(__dirname, 'fixtures', 'VS_2017_Express.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\' +
'WDExpress\\MSBuild\\15.0\\Bin\\MSBuild.exe',
path:
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\WDExpress',
sdk: '10.0.17763.0',
toolset: 'v141',
version: '15.9.28307.858',
versionMajor: 15,
versionMinor: 9,
versionYear: 2017
})
})
it('VS2019 Preview with C++ workload', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2019_Preview.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2019_Preview.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' +
'Preview\\MSBuild\\Current\\Bin\\MSBuild.exe',
path:
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Preview',
sdk: '10.0.17763.0',
toolset: 'v142',
version: '16.0.28608.199',
versionMajor: 16,
versionMinor: 0,
versionYear: 2019
})
})
it('minimal VS2019 Build Tools', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2019_BuildTools_minimal.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2019_BuildTools_minimal.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' +
'BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe',
path:
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools',
sdk: '10.0.17134.0',
toolset: 'v142',
version: '16.1.28922.388',
versionMajor: 16,
versionMinor: 1,
versionYear: 2019
})
})
it('VS2019 Community with C++ workload', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2019_Community_workload.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2019_Community_workload.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' +
'Community\\MSBuild\\Current\\Bin\\MSBuild.exe',
path:
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community',
sdk: '10.0.17763.0',
toolset: 'v142',
version: '16.1.28922.388',
versionMajor: 16,
versionMinor: 1,
versionYear: 2019
})
})
it('VS2022 Preview with C++ workload', async function () {
const msBuildPath = process.arch === 'arm64'
? 'C:\\Program Files\\Microsoft Visual Studio\\2022\\' +
'Community\\MSBuild\\Current\\Bin\\arm64\\MSBuild.exe'
: 'C:\\Program Files\\Microsoft Visual Studio\\2022\\' +
'Community\\MSBuild\\Current\\Bin\\MSBuild.exe'
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
finder.msBuildPathExists = (path) => {
return true
}
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2022_Community_workload.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2022_Community_workload.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: msBuildPath,
path:
'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community',
sdk: '10.0.22621.0',
toolset: 'v143',
version: '17.4.33213.308',
versionMajor: 17,
versionMinor: 4,
versionYear: 2022
})
})
it('VS2026 Preview with C++ workload', async function () {
const msBuildPath = process.arch === 'arm64'
? 'C:\\Program Files\\Microsoft Visual Studio\\18\\' +
'Insiders\\MSBuild\\Current\\Bin\\arm64\\MSBuild.exe'
: 'C:\\Program Files\\Microsoft Visual Studio\\18\\' +
'Insiders\\MSBuild\\Current\\Bin\\MSBuild.exe'
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
finder.msBuildPathExists = (path) => {
return true
}
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2026_Insiders_workload.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2026_Insiders_workload.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: msBuildPath,
path:
'C:\\Program Files\\Microsoft Visual Studio\\18\\Insiders',
sdk: '10.0.26100.0',
toolset: 'v145',
version: '18.3.11206.111',
versionMajor: 18,
versionMinor: 3,
versionYear: 2026
})
})
it('VS2026 Release with C++ workload', async function () {
const msBuildPath = process.arch === 'arm64'
? 'C:\\Program Files\\Microsoft Visual Studio\\2026\\' +
'Community\\MSBuild\\Current\\Bin\\arm64\\MSBuild.exe'
: 'C:\\Program Files\\Microsoft Visual Studio\\2026\\' +
'Community\\MSBuild\\Current\\Bin\\MSBuild.exe'
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
finder.msBuildPathExists = (path) => {
return true
}
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
// Create mock data for release version with 2026 path
const releaseData = [{
path: 'C:\\Program Files\\Microsoft Visual Studio\\2026\\Community',
version: '18.0.1000.100',
packages: [
'Microsoft.VisualStudio.Product.Community',
'Microsoft.VisualStudio.Workload.NativeDesktop',
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
'Microsoft.VisualStudio.Component.Windows11SDK.26100'
]
}]
return finder.processData(releaseData, [2019, 2022, 2026])
}
finder.findVisualStudio2017 = async () => null
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: msBuildPath,
path:
'C:\\Program Files\\Microsoft Visual Studio\\2026\\Community',
sdk: '10.0.26100.0',
toolset: 'v145',
version: '18.0.1000.100',
versionMajor: 18,
versionMinor: 0,
versionYear: 2026
})
})
it('VS2022 Build Tools with ARM64 MSVC only', async function () {
if (process.arch !== 'arm64') {
return
}
const msBuildPath = 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\' +
'BuildTools\\MSBuild\\Current\\Bin\\arm64\\MSBuild.exe'
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
poison(finder, 'findVisualStudio2017')
finder.msBuildPathExists = (path) => {
return true
}
finder.findNewVSUsingSetupModule = async () => null
finder.findVisualStudio2019OrNewer = async () => {
const file = path.join(__dirname, 'fixtures',
'VS_2022_BuildTools_arm64_only.txt')
const data = fs.readFileSync(file)
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: msBuildPath,
path:
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools',
sdk: '10.0.22621.0',
toolset: 'v143',
version: '17.11.35222.181',
versionMajor: 17,
versionMinor: 11,
versionYear: 2022
})
})
it('VSSetup: VS2022 with C++ workload without SDK', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
finder.msBuildPathExists = (path) => {
return true
}
finder.findNewVS = async () => null
finder.findOldVS = async () => null
setupExecFixture(finder, 'VSSetup_VS_2022_workload_missing_sdk.txt')
const { err, info } = await finder.findVisualStudio()
assert.match(err.message, /could not find/i)
assert.strictEqual(info, null)
})
it('VSSetup: VS2019 with C++ workload', async function () {
await verifyVSSetupData('VSSetup_VS_2019_Professional_workload.txt', 'Professional', 2019,
'10.0.19041.0', 'v142', '16.11.34407.143', 'Program Files (x86)')
})
it('VSSetup: VS2022 with C++ workload', async function () {
await verifyVSSetupData('VSSetup_VS_2022_workload.txt', 'Enterprise', 2022,
'10.0.22000.0', 'v143', '17.8.34330.188', 'Program Files')
})
it('VSSetup: VS2022 and VS2019 with C++ workload', async function () {
await verifyVSSetupData('VSSetup_VS_2022_VS2019_workload.txt', 'Enterprise', 2022,
'10.0.22000.0', 'v143', '17.8.34330.188', 'Program Files')
})
it('VSSetup: VS2022 with multiple installations', async function () {
await verifyVSSetupData('VSSetup_VS_2022_multiple_install.txt', 'Enterprise', 2022,
'10.0.22000.0', 'v143', '17.8.34330.188', 'Program Files')
})
async function verifyVSSetupData (fixtureName, vsType, vsYear, sdkVersion, toolsetVersion, vsVersion, expectedProgramFilesPath) {
const msBuildPath = process.arch === 'arm64'
? `C:\\${expectedProgramFilesPath}\\Microsoft Visual Studio\\${vsYear}\\` +
`${vsType}\\MSBuild\\Current\\Bin\\arm64\\MSBuild.exe`
: `C:\\${expectedProgramFilesPath}\\Microsoft Visual Studio\\${vsYear}\\` +
`${vsType}\\MSBuild\\Current\\Bin\\MSBuild.exe`
const finder = new TestVisualStudioFinder(semverV1, null)
poison(finder, 'regSearchKeys')
const expectedVSPath = `C:\\${expectedProgramFilesPath}\\Microsoft Visual Studio\\${vsYear}\\${vsType}`
finder.msBuildPathExists = (path) => {
if (path.startsWith(expectedVSPath) && path.endsWith('MSBuild.exe')) {
return true
}
return false
}
finder.findVisualStudio2019OrNewer = async () => {
throw new Error("findVisualStudio2019OrNewer shouldn't be called")
}
finder.findVisualStudio2017 = async () => {
throw new Error("findVisualStudio2017 shouldn't be called")
}
setupExecFixture(finder, fixtureName)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
const vsVersionTokens = vsVersion.split('.')
assert.deepStrictEqual(info, {
msBuild: msBuildPath,
path:
`C:\\${expectedProgramFilesPath}\\Microsoft Visual Studio\\${vsYear}\\${vsType}`,
sdk: sdkVersion,
toolset: toolsetVersion,
version: vsVersion,
versionMajor: parseInt(vsVersionTokens[0]),
versionMinor: parseInt(vsVersionTokens[1]),
versionYear: vsYear
})
}
function setupExecFixture (finder, fixtureName) {
finder.execFile = async (exec, args) => {
if (args.length > 2 && args[2].includes('Get-Module')) {
return [null, '1.0.0', '']
} else if (args.length > 2 && args.at(-1).includes('Get-VSSetupInstance')) {
const file = path.join(__dirname, 'fixtures', fixtureName)
return [null, fs.readFileSync(file), '']
}
return [new Error(), '', '']
}
}
function allVsVersions (finder) {
finder.findVisualStudio2017OrNewerUsingSetupModule = async () => {
return null
}
finder.findVisualStudio2017 = async () => {
const data0 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures',
'VS_2017_Unusable.txt')))
const data1 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures',
'VS_2017_BuildTools_minimal.txt')))
const data2 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures',
'VS_2017_Community_workload.txt')))
const data3 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures',
'VS_2017_Express.txt')))
const data = JSON.stringify(data0.concat(data1, data2, data3))
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2017])
}
finder.findVisualStudio2019OrNewer = async () => {
const data0 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures',
'VS_2019_Preview.txt')))
const data1 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures',
'VS_2019_BuildTools_minimal.txt')))
const data2 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures',
'VS_2019_Community_workload.txt')))
const data3 = JSON.parse(fs.readFileSync(path.join(__dirname, 'fixtures',
'VS_2022_Community_workload.txt')))
const data = JSON.stringify(data0.concat(data1, data2, data3))
const parsedData = finder.parseData(null, data, '', { checkIsArray: true })
return finder.processData(parsedData, [2019, 2022, 2026])
}
finder.regSearchKeys = async (keys, value, addOpts) => {
for (let i = 0; i < keys.length; ++i) {
const fullName = `${keys[i]}\\${value}`
switch (fullName) {
case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0':
case 'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0':
continue
case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\12.0':
return 'C:\\VS2013\\VC\\'
case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\12.0\\MSBuildToolsPath':
return 'C:\\MSBuild12\\'
case 'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7\\14.0':
return 'C:\\VS2015\\VC\\'
case 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions\\14.0\\MSBuildToolsPath':
return 'C:\\MSBuild14\\'
default:
assert.fail(`unexpected search for registry value ${fullName}`)
}
}
throw new Error()
}
}
it('fail when looking for invalid path', async function () {
const finder = new TestVisualStudioFinder(semverV1, 'AABB')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.ok(/find .* Visual Studio/i.test(err), 'expect error')
assert.ok(!info, 'no data')
})
it('look for VS2013 by version number', async function () {
const finder = new TestVisualStudioFinder(semverV1, '2013')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.versionYear, 2013)
})
it('look for VS2013 by installation path', async function () {
const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2013')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.path, 'C:\\VS2013')
})
it('look for VS2015 by version number', async function () {
const finder = new TestVisualStudioFinder(semverV1, '2015')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.versionYear, 2015)
})
it('look for VS2015 by installation path', async function () {
const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.path, 'C:\\VS2015')
})
it('look for VS2017 by version number', async function () {
const finder = new TestVisualStudioFinder(semverV1, '2017')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.versionYear, 2017)
})
it('look for VS2017 by installation path', async function () {
const finder = new TestVisualStudioFinder(semverV1,
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.path,
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community')
})
it('look for VS2019 by version number', async function () {
const finder = new TestVisualStudioFinder(semverV1, '2019')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.versionYear, 2019)
})
it('look for VS2019 by installation path', async function () {
const finder = new TestVisualStudioFinder(semverV1,
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.path,
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools')
})
it('look for VS2022 by version number', async function () {
const finder = new TestVisualStudioFinder(semverV1, '2022')
finder.msBuildPathExists = (path) => {
return true
}
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.versionYear, 2022)
})
it('msvs_version match should be case insensitive', async function () {
const finder = new TestVisualStudioFinder(semverV1,
'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.path,
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools')
})
it('latest version should be found by default', async function () {
const finder = new TestVisualStudioFinder(semverV1, null)
finder.msBuildPathExists = (path) => {
return true
}
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.versionYear, 2022)
})
it('run on a usable VS Command Prompt', async function () {
process.env.VCINSTALLDIR = 'C:\\VS2015\\VC'
// VSINSTALLDIR is not defined on Visual C++ Build Tools 2015
delete process.env.VSINSTALLDIR
const finder = new TestVisualStudioFinder(semverV1, null)
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.path, 'C:\\VS2015')
})
it('VCINSTALLDIR match should be case insensitive', async function () {
process.env.VCINSTALLDIR =
'c:\\program files (x86)\\microsoft visual studio\\2019\\BUILDTOOLS\\VC'
const finder = new TestVisualStudioFinder(semverV1, null)
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.path,
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools')
})
it('run on a unusable VS Command Prompt', async function () {
process.env.VCINSTALLDIR =
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildToolsUnusable\\VC'
const finder = new TestVisualStudioFinder(semverV1, null)
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.ok(/find .* Visual Studio/i.test(err), 'expect error')
assert.ok(!info, 'no data')
})
it('run on a VS Command Prompt with matching msvs_version', async function () {
process.env.VCINSTALLDIR = 'C:\\VS2015\\VC'
const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info.path, 'C:\\VS2015')
})
it('run on a VS Command Prompt with mismatched msvs_version', async function () {
process.env.VCINSTALLDIR =
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC'
const finder = new TestVisualStudioFinder(semverV1, 'C:\\VS2015')
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.ok(/find .* Visual Studio/i.test(err), 'expect error')
assert.ok(!info, 'no data')
})
it('run on a portable VS Command Prompt with sufficient environs', async function () {
process.env.VCINSTALLDIR = 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC'
process.env.VSCMD_VER = '16.0'
process.env.WindowsSDKVersion = '10.0.17763.0'
const finder = new TestVisualStudioFinder(semverV1, null)
allVsVersions(finder)
const { err, info } = await finder.findVisualStudio()
assert.strictEqual(err, null)
assert.deepStrictEqual(info, {
msBuild: 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\' +
'Community\\MSBuild\\Current\\Bin\\MSBuild.exe',
path:
'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community',
sdk: '10.0.17763.0',
toolset: 'v142',
// Assume version in the environ is correct.
version: '16.0',
versionMajor: 16,
versionMinor: 0,
versionYear: 2019
})
})
})
================================================
FILE: test/test-install.js
================================================
'use strict'
const { describe, it, afterEach, beforeEach } = require('mocha')
const { rm, mkdtemp } = require('fs/promises')
const { createWriteStream } = require('fs')
const assert = require('assert')
const path = require('path')
const os = require('os')
const { pipeline: streamPipeline } = require('stream/promises')
const requireInject = require('require-inject')
const { FULL_TEST, platformTimeout } = require('./common')
const gyp = require('../lib/node-gyp')
const install = require('../lib/install')
const { download } = require('../lib/download')
describe('install', function () {
it('EACCES retry once', async () => {
let statCalled = 0
const mockInstall = requireInject('../lib/install', {
'graceful-fs': {
promises: {
stat (_) {
const err = new Error()
err.code = 'EACCES'
statCalled++
throw err
}
}
}
})
const Gyp = {
devDir: __dirname,
opts: {
ensure: true
},
commands: {
install: (...args) => mockInstall(Gyp, ...args),
remove: async () => {}
}
}
let err
try {
await Gyp.commands.install([])
} catch (e) {
err = e
}
assert.ok(err)
assert.equal(statCalled, 2)
if (/"pre" versions of node cannot be installed/.test(err.message)) {
assert.ok(true)
}
})
describe('parallel', function () {
let prog
beforeEach(async () => {
prog = gyp()
prog.parseArgv([])
prog.devDir = await mkdtemp(path.join(os.tmpdir(), 'node-gyp-test-'))
})
afterEach(async () => {
await rm(prog.devDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 1000 })
prog = null
})
const runIt = (name, fn) => {
// only run these tests if we are running a version of Node with predictable version path behavior
if (!FULL_TEST) {
return it.skip('Skipping parallel installs test due to test environment configuration')
}
return it(name, async function () {
this.timeout(platformTimeout(4, { win32: 20 }))
await fn.call(this)
const expectedDir = path.join(prog.devDir, process.version.replace(/^v/, ''))
await rm(expectedDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 1000 })
await Promise.all(new Array(5).fill(0).map(async (_, i) => {
const title = `${' '.repeat(8)}${name} ${(i + 1).toString().padEnd(2, ' ')}`
console.log(`${title} : Start`)
console.time(title)
await install(prog, [])
console.timeEnd(title)
}))
})
}
runIt('ensure=true', async function () {
prog.opts.ensure = true
})
runIt('ensure=false', async function () {
prog.opts.ensure = false
})
runIt('tarball', async function () {
prog.opts.tarball = path.join(prog.devDir, 'node-headers.tar.gz')
const dl = await download(prog, `https://nodejs.org/dist/${process.version}/node-${process.version}.tar.gz`)
await streamPipeline(dl.body, createWriteStream(prog.opts.tarball))
})
})
})
================================================
FILE: test/test-options.js
================================================
'use strict'
const { describe, it } = require('mocha')
const assert = require('assert')
const gyp = require('../lib/node-gyp')
const log = require('../lib/log')
describe('options', function () {
it('options in environment', () => {
// `npm test` dumps a ton of npm_config_* variables in the environment.
Object.keys(process.env)
.filter((key) => /^npm_config_/i.test(key) || /^npm_package_config_node_gyp_/i.test(key))
.forEach((key) => { delete process.env[key] })
// in some platforms, certain keys are stubborn and cannot be removed
const keys = Object.keys(process.env)
.filter((key) => /^npm_config_/i.test(key) || /^npm_package_config_node_gyp_/i.test(key))
.map((key) => key.substring('npm_config_'.length))
// Environment variables with the following prefixes should be added to opts.
// - `npm_config_` for npm versions before v11.
// - `npm_package_config_node_gyp_` for npm versions 11 and later.
// Zero-length keys should get filtered out.
process.env.npm_config_ = '42'
process.env.npm_package_config_node_gyp_ = '42'
// Other keys should get added.
process.env.npm_package_config_node_gyp_foo = '42'
process.env.npm_config_x = '42'
process.env.npm_config_y = '41'
// Package config should take precedence over npm_config_ keys.
process.env.npm_package_config_node_gyp_y = '42'
// All configs should be case-insensitive.
process.env.NPM_PACKAGE_CONFIG_NODE_GYP_XX = 'value'
process.env.NPM_CONFIG_YY = 'value'
// loglevel does not get added to opts but will change the logger's level.
process.env.npm_config_loglevel = 'silly'
const g = gyp()
assert.strictEqual(log.logger.level.id, 'info')
g.parseArgv(['rebuild']) // Also sets opts.argv.
assert.strictEqual(log.logger.level.id, 'silly')
assert.deepStrictEqual(Object.keys(g.opts).sort(), [...keys, 'argv', 'x', 'y', 'foo', 'xx', 'yy'].sort())
assert.strictEqual(g.opts['x'], '42')
assert.strictEqual(g.opts['y'], '42')
assert.strictEqual(g.opts['foo'], '42')
assert.strictEqual(g.opts['xx'], 'value')
assert.strictEqual(g.opts['yy'], 'value')
})
it('options with spaces in environment', () => {
process.env.npm_config_force_process_config = 'true'
const g = gyp()
g.parseArgv(['rebuild']) // Also sets opts.argv.
assert.strictEqual(g.opts['force-process-config'], 'true')
})
it('options with msvs_version', () => {
process.env.npm_config_msvs_version = '2017'
const g = gyp()
g.parseArgv(['rebuild']) // Also sets opts.argv.
assert.strictEqual(g.opts['msvs-version'], '2017')
})
})
================================================
FILE: test/test-process-release.js
================================================
'use strict'
const { describe, it } = require('mocha')
const assert = require('assert')
const processRelease = require('../lib/process-release')
describe('process-release', function () {
it('test process release - process.version = 0.8.20', function () {
const release = processRelease([], { opts: {} }, 'v0.8.20', null)
assert.strictEqual(release.semver.version, '0.8.20')
delete release.semver
assert.deepStrictEqual(release, {
version: '0.8.20',
name: 'node',
baseUrl: 'https://nodejs.org/dist/v0.8.20/',
tarballUrl: 'https://nodejs.org/dist/v0.8.20/node-v0.8.20.tar.gz',
shasumsUrl: 'https://nodejs.org/dist/v0.8.20/SHASUMS256.txt',
versionDir: '0.8.20',
ia32: { libUrl: 'https://nodejs.org/dist/v0.8.20/node.lib', libPath: 'node.lib' },
x64: { libUrl: 'https://nodejs.org/dist/v0.8.20/x64/node.lib', libPath: 'x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/dist/v0.8.20/arm64/node.lib', libPath: 'arm64/node.lib' }
})
})
it('test process release - process.version = 0.10.21', function () {
const release = processRelease([], { opts: {} }, 'v0.10.21', null)
assert.strictEqual(release.semver.version, '0.10.21')
delete release.semver
assert.deepStrictEqual(release, {
version: '0.10.21',
name: 'node',
baseUrl: 'https://nodejs.org/dist/v0.10.21/',
tarballUrl: 'https://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz',
shasumsUrl: 'https://nodejs.org/dist/v0.10.21/SHASUMS256.txt',
versionDir: '0.10.21',
ia32: { libUrl: 'https://nodejs.org/dist/v0.10.21/node.lib', libPath: 'node.lib' },
x64: { libUrl: 'https://nodejs.org/dist/v0.10.21/x64/node.lib', libPath: 'x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/dist/v0.10.21/arm64/node.lib', libPath: 'arm64/node.lib' }
})
})
// prior to -headers.tar.gz
it('test process release - process.version = 0.12.9', function () {
const release = processRelease([], { opts: {} }, 'v0.12.9', null)
assert.strictEqual(release.semver.version, '0.12.9')
delete release.semver
assert.deepStrictEqual(release, {
version: '0.12.9',
name: 'node',
baseUrl: 'https://nodejs.org/dist/v0.12.9/',
tarballUrl: 'https://nodejs.org/dist/v0.12.9/node-v0.12.9.tar.gz',
shasumsUrl: 'https://nodejs.org/dist/v0.12.9/SHASUMS256.txt',
versionDir: '0.12.9',
ia32: { libUrl: 'https://nodejs.org/dist/v0.12.9/node.lib', libPath: 'node.lib' },
x64: { libUrl: 'https://nodejs.org/dist/v0.12.9/x64/node.lib', libPath: 'x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/dist/v0.12.9/arm64/node.lib', libPath: 'arm64/node.lib' }
})
})
// prior to -headers.tar.gz
it('test process release - process.version = 0.10.41', function () {
const release = processRelease([], { opts: {} }, 'v0.10.41', null)
assert.strictEqual(release.semver.version, '0.10.41')
delete release.semver
assert.deepStrictEqual(release, {
version: '0.10.41',
name: 'node',
baseUrl: 'https://nodejs.org/dist/v0.10.41/',
tarballUrl: 'https://nodejs.org/dist/v0.10.41/node-v0.10.41.tar.gz',
shasumsUrl: 'https://nodejs.org/dist/v0.10.41/SHASUMS256.txt',
versionDir: '0.10.41',
ia32: { libUrl: 'https://nodejs.org/dist/v0.10.41/node.lib', libPath: 'node.lib' },
x64: { libUrl: 'https://nodejs.org/dist/v0.10.41/x64/node.lib', libPath: 'x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/dist/v0.10.41/arm64/node.lib', libPath: 'arm64/node.lib' }
})
})
// has -headers.tar.gz
it('test process release - process.release ~ node@0.10.42', function () {
const release = processRelease([], { opts: {} }, 'v0.10.42', null)
assert.strictEqual(release.semver.version, '0.10.42')
delete release.semver
assert.deepStrictEqual(release, {
version: '0.10.42',
name: 'node',
baseUrl: 'https://nodejs.org/dist/v0.10.42/',
tarballUrl: 'https://nodejs.org/dist/v0.10.42/node-v0.10.42-headers.tar.gz',
shasumsUrl: 'https://nodejs.org/dist/v0.10.42/SHASUMS256.txt',
versionDir: '0.10.42',
ia32: { libUrl: 'https://nodejs.org/dist/v0.10.42/node.lib', libPath: 'node.lib' },
x64: { libUrl: 'https://nodejs.org/dist/v0.10.42/x64/node.lib', libPath: 'x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/dist/v0.10.42/arm64/node.lib', libPath: 'arm64/node.lib' }
})
})
// has -headers.tar.gz
it('test process release - process.release ~ node@0.12.10', function () {
const release = processRelease([], { opts: {} }, 'v0.12.10', null)
assert.strictEqual(release.semver.version, '0.12.10')
delete release.semver
assert.deepStrictEqual(release, {
version: '0.12.10',
name: 'node',
baseUrl: 'https://nodejs.org/dist/v0.12.10/',
tarballUrl: 'https://nodejs.org/dist/v0.12.10/node-v0.12.10-headers.tar.gz',
shasumsUrl: 'https://nodejs.org/dist/v0.12.10/SHASUMS256.txt',
versionDir: '0.12.10',
ia32: { libUrl: 'https://nodejs.org/dist/v0.12.10/node.lib', libPath: 'node.lib' },
x64: { libUrl: 'https://nodejs.org/dist/v0.12.10/x64/node.lib', libPath: 'x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/dist/v0.12.10/arm64/node.lib', libPath: 'arm64/node.lib' }
})
})
it('test process release - process.release ~ node@4.1.23', function () {
const release = processRelease([], { opts: {} }, 'v4.1.23', {
name: 'node',
headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz'
})
assert.strictEqual(release.semver.version, '4.1.23')
delete release.semver
assert.deepStrictEqual(release, {
version: '4.1.23',
name: 'node',
baseUrl: 'https://nodejs.org/dist/v4.1.23/',
tarballUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz',
shasumsUrl: 'https://nodejs.org/dist/v4.1.23/SHASUMS256.txt',
versionDir: '4.1.23',
ia32: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' },
x64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/dist/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' }
})
})
it('test process release - process.release ~ node@4.1.23 / corp build', function () {
const release = processRelease([], { opts: {} }, 'v4.1.23', {
name: 'node',
headersUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz'
})
assert.strictEqual(release.semver.version, '4.1.23')
delete release.semver
assert.deepStrictEqual(release, {
version: '4.1.23',
name: 'node',
baseUrl: 'https://some.custom.location/',
tarballUrl: 'https://some.custom.location/node-v4.1.23-headers.tar.gz',
shasumsUrl: 'https://some.custom.location/SHASUMS256.txt',
versionDir: '4.1.23',
ia32: { libUrl: 'https://some.custom.location/win-x86/node.lib', libPath: 'win-x86/node.lib' },
x64: { libUrl: 'https://some.custom.location/win-x64/node.lib', libPath: 'win-x64/node.lib' },
arm64: { libUrl: 'https://some.custom.location/win-arm64/node.lib', libPath: 'win-arm64/node.lib' }
})
})
it('test process release - process.release ~ node@12.8.0 Windows', function () {
const release = processRelease([], { opts: {} }, 'v12.8.0', {
name: 'node',
sourceUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz',
headersUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz',
libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib'
})
assert.strictEqual(release.semver.version, '12.8.0')
delete release.semver
assert.deepStrictEqual(release, {
version: '12.8.0',
name: 'node',
baseUrl: 'https://nodejs.org/download/release/v12.8.0/',
tarballUrl: 'https://nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz',
shasumsUrl: 'https://nodejs.org/download/release/v12.8.0/SHASUMS256.txt',
versionDir: '12.8.0',
ia32: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' },
x64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' }
})
})
it('test process release - process.release ~ node@12.8.0 Windows ARM64', function () {
const release = processRelease([], { opts: {} }, 'v12.8.0', {
name: 'node',
sourceUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0.tar.gz',
headersUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz',
libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib'
})
assert.strictEqual(release.semver.version, '12.8.0')
delete release.semver
assert.deepStrictEqual(release, {
version: '12.8.0',
name: 'node',
baseUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/',
tarballUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/node-v12.8.0-headers.tar.gz',
shasumsUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/SHASUMS256.txt',
versionDir: '12.8.0',
ia32: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x86/node.lib', libPath: 'win-x86/node.lib' },
x64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-x64/node.lib', libPath: 'win-x64/node.lib' },
arm64: { libUrl: 'https://unofficial-builds.nodejs.org/download/release/v12.8.0/win-arm64/node.lib', libPath: 'win-arm64/node.lib' }
})
})
it('test process release - process.release ~ node@4.1.23 --target=0.10.40', function () {
const release = processRelease([], { opts: { target: '0.10.40' } }, 'v4.1.23', {
name: 'node',
headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz'
})
assert.strictEqual(release.semver.version, '0.10.40')
delete release.semver
assert.deepStrictEqual(release, {
version: '0.10.40',
name: 'node',
baseUrl: 'https://nodejs.org/dist/v0.10.40/',
tarballUrl: 'https://nodejs.org/dist/v0.10.40/node-v0.10.40.tar.gz',
shasumsUrl: 'https://nodejs.org/dist/v0.10.40/SHASUMS256.txt',
versionDir: '0.10.40',
ia32: { libUrl: 'https://nodejs.org/dist/v0.10.40/node.lib', libPath: 'node.lib' },
x64: { libUrl: 'https://nodejs.org/dist/v0.10.40/x64/node.lib', libPath: 'x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/dist/v0.10.40/arm64/node.lib', libPath: 'arm64/node.lib' }
})
})
it('test process release - process.release ~ node@4.1.23 --dist-url=https://foo.bar/baz', function () {
const release = processRelease([], { opts: { 'dist-url': 'https://foo.bar/baz' } }, 'v4.1.23', {
name: 'node',
headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz'
})
assert.strictEqual(release.semver.version, '4.1.23')
delete release.semver
assert.deepStrictEqual(release, {
version: '4.1.23',
name: 'node',
baseUrl: 'https://foo.bar/baz/v4.1.23/',
tarballUrl: 'https://foo.bar/baz/v4.1.23/node-v4.1.23-headers.tar.gz',
shasumsUrl: 'https://foo.bar/baz/v4.1.23/SHASUMS256.txt',
versionDir: '4.1.23',
ia32: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' },
x64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' },
arm64: { libUrl: 'https://foo.bar/baz/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' }
})
})
it('test process release - process.release ~ frankenstein@4.1.23', function () {
const release = processRelease([], { opts: {} }, 'v4.1.23', {
name: 'frankenstein',
headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz'
})
assert.strictEqual(release.semver.version, '4.1.23')
delete release.semver
assert.deepStrictEqual(release, {
version: '4.1.23',
name: 'frankenstein',
baseUrl: 'https://frankensteinjs.org/dist/v4.1.23/',
tarballUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23-headers.tar.gz',
shasumsUrl: 'https://frankensteinjs.org/dist/v4.1.23/SHASUMS256.txt',
versionDir: 'frankenstein-4.1.23',
ia32: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' },
x64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' },
arm64: { libUrl: 'https://frankensteinjs.org/dist/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' }
})
})
it('test process release - process.release ~ frankenstein@4.1.23 --dist-url=http://foo.bar/baz/', function () {
const release = processRelease([], { opts: { 'dist-url': 'http://foo.bar/baz/' } }, 'v4.1.23', {
name: 'frankenstein',
headersUrl: 'https://frankensteinjs.org/dist/v4.1.23/frankenstein-v4.1.23.tar.gz'
})
assert.strictEqual(release.semver.version, '4.1.23')
delete release.semver
assert.deepStrictEqual(release, {
version: '4.1.23',
name: 'frankenstein',
baseUrl: 'http://foo.bar/baz/v4.1.23/',
tarballUrl: 'http://foo.bar/baz/v4.1.23/frankenstein-v4.1.23-headers.tar.gz',
shasumsUrl: 'http://foo.bar/baz/v4.1.23/SHASUMS256.txt',
versionDir: 'frankenstein-4.1.23',
ia32: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x86/frankenstein.lib', libPath: 'win-x86/frankenstein.lib' },
x64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-x64/frankenstein.lib', libPath: 'win-x64/frankenstein.lib' },
arm64: { libUrl: 'http://foo.bar/baz/v4.1.23/win-arm64/frankenstein.lib', libPath: 'win-arm64/frankenstein.lib' }
})
})
it('test process release - process.release ~ node@4.0.0-rc.4', function () {
const release = processRelease([], { opts: {} }, 'v4.0.0-rc.4', {
name: 'node',
headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz'
})
assert.strictEqual(release.semver.version, '4.0.0-rc.4')
delete release.semver
assert.deepStrictEqual(release, {
version: '4.0.0-rc.4',
name: 'node',
baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/',
tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz',
shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt',
versionDir: '4.0.0-rc.4',
ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' },
x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' }
})
})
it('test process release - process.release ~ node@4.0.0-rc.4 passed as argv[0]', function () {
// note the missing 'v' on the arg, it should normalise when checking
// whether we're on the default or not
const release = processRelease(['4.0.0-rc.4'], { opts: {} }, 'v4.0.0-rc.4', {
name: 'node',
headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz'
})
assert.strictEqual(release.semver.version, '4.0.0-rc.4')
delete release.semver
assert.deepStrictEqual(release, {
version: '4.0.0-rc.4',
name: 'node',
baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/',
tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz',
shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt',
versionDir: '4.0.0-rc.4',
ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' },
x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' }
})
})
it('test process release - process.release ~ node@4.0.0-rc.4 - bogus string passed as argv[0]', function () {
// additional arguments can be passed in on the commandline that should be ignored if they
// are not specifying a valid version @ position 0
const release = processRelease(['this is no version!'], { opts: {} }, 'v4.0.0-rc.4', {
name: 'node',
headersUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz'
})
assert.strictEqual(release.semver.version, '4.0.0-rc.4')
delete release.semver
assert.deepStrictEqual(release, {
version: '4.0.0-rc.4',
name: 'node',
baseUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/',
tarballUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/node-v4.0.0-rc.4-headers.tar.gz',
shasumsUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/SHASUMS256.txt',
versionDir: '4.0.0-rc.4',
ia32: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x86/node.lib', libPath: 'win-x86/node.lib' },
x64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-x64/node.lib', libPath: 'win-x64/node.lib' },
arm64: { libUrl: 'https://nodejs.org/download/rc/v4.0.0-rc.4/win-arm64/node.lib', libPath: 'win-arm64/node.lib' }
})
})
it('test process release - NODEJS_ORG_MIRROR', function () {
process.env.NODEJS_ORG_MIRROR = 'http://foo.bar'
const release = processRelease([], { opts: {} }, 'v4.1.23', {
name: 'node',
headersUrl: 'https://nodejs.org/dist/v4.1.23/node-v4.1.23-headers.tar.gz'
})
assert.strictEqual(release.semver.version, '4.1.23')
delete release.semver
assert.deepStrictEqual(release, {
version: '4.1.23',
name: 'node',
baseUrl: 'http://foo.bar/v4.1.23/',
tarballUrl: 'http://foo.bar/v4.1.23/node-v4.1.23-headers.tar.gz',
shasumsUrl: 'http://foo.bar/v4.1.23/SHASUMS256.txt',
versionDir: '4.1.23',
ia32: { libUrl: 'http://foo.bar/v4.1.23/win-x86/node.lib', libPath: 'win-x86/node.lib' },
x64: { libUrl: 'http://foo.bar/v4.1.23/win-x64/node.lib', libPath: 'win-x64/node.lib' },
arm64: { libUrl: 'http://foo.bar/v4.1.23/win-arm64/node.lib', libPath: 'win-arm64/node.lib' }
})
delete process.env.NODEJS_ORG_MIRROR
})
})
================================================
FILE: test/test-windows-make.js
================================================
'use strict'
const { describe, it } = require('mocha')
const assert = require('assert')
const path = require('path')
const gracefulFs = require('graceful-fs')
const cp = require('child_process')
const util = require('../lib/util')
const { platformTimeout } = require('./common')
const addonPath = path.resolve(__dirname, 'node_modules', 'hello_napi')
const nodeGyp = path.resolve(__dirname, '..', 'bin', 'node-gyp.js')
const execFileSync = (...args) => cp.execFileSync(...args).toString().trim()
const execFile = async (cmd, env) => {
const [err,, stderr] = await util.execFile(process.execPath, cmd, {
env: {
...process.env,
NODE_GYP_NULL_LOGGER: undefined,
...env
},
encoding: 'utf-8'
})
return [err, stderr.toString().trim().split(/\r?\n/)]
}
function runHello (hostProcess = process.execPath) {
const testCode = "console.log(require('hello_napi').hello())"
return execFileSync(hostProcess, ['--experimental-wasi-unstable-preview1', '-e', testCode], { cwd: __dirname })
}
function executable (name) {
return name + (process.platform === 'win32' ? '.exe' : '')
}
function getEnv (target) {
const env = {
GYP_CROSSCOMPILE: '1',
AR_host: 'ar',
CC_host: 'clang',
CXX_host: 'clang++'
}
if (target === 'emscripten') {
env.AR_target = 'emar'
env.CC_target = 'emcc'
env.CXX_target = 'em++'
} else if (target === 'wasi') {
if (!process.env.WASI_SDK_PATH) return env
env.AR_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('ar'))
env.CC_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('clang'))
env.CXX_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('clang++'))
} else if (target === 'wasm') {
if (!process.env.WASI_SDK_PATH) return env
env.AR_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('ar'))
env.CC_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('clang'))
env.CXX_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('clang++'))
env.CFLAGS = '--target=wasm32'
} else if (target === 'win-clang') {
let vsdir = 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise'
if (!gracefulFs.existsSync(vsdir)) {
vsdir = 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community'
}
const llvmBin = 'VC\\Tools\\Llvm\\x64\\bin'
env.AR_target = path.join(vsdir, llvmBin, 'llvm-ar.exe')
env.CC_target = path.join(vsdir, llvmBin, 'clang.exe')
env.CXX_target = path.join(vsdir, llvmBin, 'clang++.exe')
env.CFLAGS = '--target=wasm32'
}
return env
}
function quote (path) {
if (path.includes(' ')) {
return `"${path}"`
}
return path
}
describe('windows-cross-compile', function () {
it('build simple node-api addon', async function () {
if (process.platform !== 'win32') {
return this.skip('This test is only for Windows')
}
const env = getEnv('wasm')
if (!gracefulFs.existsSync(env.CC_target)) {
return this.skip('CC_target does not exist')
}
// handle bash whitespace
env.AR_target = quote(env.AR_target)
env.CC_target = quote(env.CC_target)
env.CXX_target = quote(env.CXX_target)
this.timeout(platformTimeout(1, { win32: 5 }))
const cmd = [
nodeGyp,
'rebuild',
'-C', addonPath,
'--loglevel=verbose',
`--nodedir=${addonPath}`,
'--arch=wasm32',
'--', '-f', 'make'
]
const [err, logLines] = await execFile(cmd, env)
const lastLine = logLines[logLines.length - 1]
assert.strictEqual(err, null)
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
assert.strictEqual(runHello(), 'world')
})
})
================================================
FILE: update-gyp.py
================================================
#!/usr/bin/env python3
import argparse
import os
import shutil
import subprocess
import tarfile
import tempfile
import urllib.request
BASE_URL = "https://github.com/nodejs/gyp-next/archive/"
CHECKOUT_PATH = os.path.dirname(os.path.realpath(__file__))
CHECKOUT_GYP_PATH = os.path.join(CHECKOUT_PATH, "gyp")
parser = argparse.ArgumentParser()
parser.add_argument(
"--no-commit", action="store_true", dest="no_commit", help="do not run git-commit"
)
parser.add_argument("tag", help="gyp tag to update to")
args = parser.parse_args()
tar_url = BASE_URL + args.tag + ".tar.gz"
changed_files = subprocess.check_output(["git", "diff", "--name-only"]).strip()
if changed_files:
raise Exception("Can't update gyp while you have uncommitted changes in node-gyp")
with tempfile.TemporaryDirectory() as tmp_dir:
tar_file = os.path.join(tmp_dir, "gyp.tar.gz")
unzip_target = os.path.join(tmp_dir, "gyp")
with open(tar_file, "wb") as f:
print("Downloading gyp-next@" + args.tag + " into temporary directory...")
print("From: " + tar_url)
with urllib.request.urlopen(tar_url) as in_file:
f.write(in_file.read())
print("Unzipping...")
with tarfile.open(tar_file, "r:gz") as tar_ref:
def is_within_directory(directory, target):
abs_directory = os.path.abspath(directory)
abs_target = os.path.abspath(target)
prefix = os.path.commonprefix([abs_directory, abs_target])
return prefix == abs_directory
def safe_extract(tar, path=".", members=None, *, numeric_owner=False):
for member in tar.getmembers():
member_path = os.path.join(path, member.name)
if not is_within_directory(path, member_path):
raise Exception("Attempted Path Traversal in Tar File")
tar.extractall(path, members, numeric_owner=numeric_owner)
safe_extract(tar_ref, unzip_target)
print("Moving to current checkout (" + CHECKOUT_PATH + ")...")
if os.path.exists(CHECKOUT_GYP_PATH):
shutil.rmtree(CHECKOUT_GYP_PATH)
shutil.move(
os.path.join(unzip_target, os.listdir(unzip_target)[0]), CHECKOUT_GYP_PATH
)
if not args.no_commit:
subprocess.check_output(["git", "add", "gyp"], cwd=CHECKOUT_PATH)
subprocess.check_output(
["git", "commit", "-m", f"feat(gyp): update gyp to {args.tag}"]
)