-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathfind.py
151 lines (115 loc) · 4.87 KB
/
find.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import os
import platform
import shutil
import sys
from pathlib import Path
from typing import Iterator, Optional
from .runtime_spec import DotnetCoreRuntimeSpec
def find_dotnet_cli() -> Optional[Path]:
dotnet_path = shutil.which("dotnet")
if not dotnet_path:
return None
else:
return Path(dotnet_path)
def find_dotnet_root() -> Path:
"""Try to discover the .NET Core root directory
If the environment variable ``DOTNET_ROOT`` is defined, we will use that.
Otherwise, we probe the default installation paths on Windows and macOS.
If none of these lead to a result, we try to discover the ``dotnet`` CLI
tool and use its (real) parent directory.
Otherwise, this function raises an exception.
:return: Path to the .NET Core root
"""
dotnet_root = os.environ.get("DOTNET_ROOT", None)
if dotnet_root is not None:
return Path(dotnet_root)
if sys.platform == "win32":
# On Windows, the host library is stored separately from dotnet.exe for x86
prog_files = os.environ.get("ProgramFiles")
if not prog_files:
raise RuntimeError("Could not find ProgramFiles")
prog_files = Path(prog_files)
dotnet_root = prog_files / "dotnet"
elif sys.platform == "darwin":
if "ARM64" in os.uname().version and platform.machine() == "x86_64":
# Apple Silicon in Rosetta 2 mode
dotnet_root = Path("/usr/local/share/dotnet/x64")
else:
dotnet_root = Path("/usr/local/share/dotnet")
if dotnet_root is not None and dotnet_root.is_dir():
return dotnet_root
# Try to discover dotnet from PATH otherwise
dotnet_cli = find_dotnet_cli()
if not dotnet_cli:
raise RuntimeError("Can not determine dotnet root")
return dotnet_cli.resolve().parent
def find_runtimes_using_cli(dotnet_cli: Path) -> Iterator[DotnetCoreRuntimeSpec]:
import re
from subprocess import check_output
out = check_output([str(dotnet_cli), "--list-runtimes"], encoding="UTF8")
runtime_re = re.compile(r"(?P<name>\S+) (?P<version>\S+) \[(?P<path>[^\]]+)\]")
for line in out.splitlines():
m = re.match(runtime_re, line)
if m:
path = Path(m.group("path"))
version = m.group("version")
if path.is_dir():
yield DotnetCoreRuntimeSpec(m.group("name"), version, path / version)
def find_runtimes_in_root(dotnet_root: Path) -> Iterator[DotnetCoreRuntimeSpec]:
shared = dotnet_root / "shared"
for runtime in shared.iterdir():
if runtime.is_dir():
name = runtime.name
for version_path in runtime.iterdir():
if version_path.is_dir():
yield DotnetCoreRuntimeSpec(name, version_path.name, version_path)
def find_runtimes() -> Iterator[DotnetCoreRuntimeSpec]:
"""Find installed .NET Core runtimes
If the ``dotnet`` CLI can be found, we will call it as ``dotnet
--list-runtimes`` and parse the result.
If it is not available, we try to discover the dotnet root directory using
:py:func:`find_dotnet_root` and enumerate the runtimes installed in the
``shared`` subdirectory.
:return: Iterable of :py:class:`DotnetCoreRuntimeSpec` objects
"""
dotnet_cli = find_dotnet_cli()
if dotnet_cli is not None:
return find_runtimes_using_cli(dotnet_cli)
else:
dotnet_root = find_dotnet_root()
return find_runtimes_in_root(dotnet_root)
def find_libmono(*, assembly_dir: str = None, sgen: bool = True) -> Path:
"""Find a suitable libmono dynamic library
On Windows and macOS, we check the default installation directories.
:param sgen:
Whether to look for an SGen or Boehm GC instance. This parameter is
ignored on Windows, as only ``sgen`` is installed with the default
installer
:return:
Path to usable ``libmono``
"""
unix_name = f"mono{'sgen' if sgen else ''}-2.0"
if sys.platform == "win32":
if sys.maxsize > 2**32:
prog_files = os.environ.get("ProgramFiles")
else:
prog_files = os.environ.get("ProgramFiles(x86)")
if prog_files is None:
raise RuntimeError("Could not determine Program Files location")
# Ignore sgen on Windows, the main installation only contains this DLL
path = Path(prog_files) / "Mono/bin/mono-2.0-sgen.dll"
elif sys.platform == "darwin":
path = (
Path("/Library/Frameworks/Mono.framework/Versions/Current/lib")
/ f"lib{unix_name}.dylib"
)
else:
if assembly_dir is None:
from ctypes.util import find_library
path = find_library(unix_name)
else:
libname = "lib" + unix_name + ".so"
path = Path(assembly_dir) / "lib" / libname
if path is None:
raise RuntimeError("Could not find libmono")
return Path(path)