py2docfx 0.1.11.dev1994698__py3-none-any.whl → 0.1.11.dev1994975__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- py2docfx/convert_prepare/environment.py +13 -10
- py2docfx/convert_prepare/generate_document.py +2 -2
- py2docfx/convert_prepare/get_source.py +6 -6
- py2docfx/convert_prepare/git.py +9 -12
- py2docfx/convert_prepare/install_package.py +2 -2
- py2docfx/convert_prepare/pack.py +6 -9
- py2docfx/convert_prepare/pip_utils.py +12 -14
- py2docfx/convert_prepare/sphinx_caller.py +4 -4
- py2docfx/convert_prepare/tests/test_get_source.py +21 -14
- py2docfx/convert_prepare/tests/test_pack.py +4 -3
- py2docfx/convert_prepare/tests/test_sphinx_caller.py +4 -4
- py2docfx/docfx_yaml/logger.py +43 -38
- {py2docfx-0.1.11.dev1994698.dist-info → py2docfx-0.1.11.dev1994975.dist-info}/METADATA +1 -1
- {py2docfx-0.1.11.dev1994698.dist-info → py2docfx-0.1.11.dev1994975.dist-info}/RECORD +16 -16
- {py2docfx-0.1.11.dev1994698.dist-info → py2docfx-0.1.11.dev1994975.dist-info}/WHEEL +0 -0
- {py2docfx-0.1.11.dev1994698.dist-info → py2docfx-0.1.11.dev1994975.dist-info}/top_level.txt +0 -0
@@ -22,7 +22,7 @@ PIP_INSTALL_VENV_COMMON_OPTIONS = [
|
|
22
22
|
"--disable-pip-version-check",
|
23
23
|
]
|
24
24
|
|
25
|
-
def install_converter_requirements(executable: str):
|
25
|
+
async def install_converter_requirements(executable: str):
|
26
26
|
"""
|
27
27
|
Install setuptools/sphinx/pyyaml/jinja2
|
28
28
|
Replacing logic of
|
@@ -41,14 +41,14 @@ def install_converter_requirements(executable: str):
|
|
41
41
|
for module in REQUIREMENT_MODULES:
|
42
42
|
msg = f"<CI INFO>: Upgrading {module}..."
|
43
43
|
py2docfx_logger.info(msg)
|
44
|
-
|
45
|
-
|
46
|
-
)
|
44
|
+
full_cmd = pip_install_cmd + [module] + pip_install_common_options
|
45
|
+
await run_async_subprocess(executable, full_cmd, py2docfx_logger)
|
47
46
|
|
48
47
|
async def install_venv_requirements(venv_num: int):
|
49
48
|
venv_exe = get_venv_exe(venv_num)
|
50
49
|
pip_cmd = ["-m", "pip", "install", "--upgrade"]+ VENV_REQUIREMENT_MODULES
|
51
|
-
|
50
|
+
py2docfx_logger = get_logger(__name__)
|
51
|
+
await run_async_subprocess(venv_exe, pip_cmd, py2docfx_logger)
|
52
52
|
|
53
53
|
def get_venv_path(venv_num: int) -> str:
|
54
54
|
return os.path.join(PACKAGE_ROOT, VENV_DIR, "venv"+str(venv_num))
|
@@ -85,7 +85,8 @@ def get_base_venv_sphinx_build_path() -> str:
|
|
85
85
|
|
86
86
|
async def install_converter_requirement_async(executable: str):
|
87
87
|
pip_cmd = PIP_INSTALL_COMMAND + PIP_INSTALL_VENV_COMMON_OPTIONS + REQUIREMENT_MODULES
|
88
|
-
|
88
|
+
py2docfx_logger = get_logger(__name__)
|
89
|
+
await run_async_subprocess(executable, pip_cmd, py2docfx_logger)
|
89
90
|
|
90
91
|
async def install_required_packages(
|
91
92
|
executable: str, required_package_list: list[PackageInfo], github_token: str, ado_token: str):
|
@@ -95,7 +96,8 @@ async def install_required_packages(
|
|
95
96
|
# get_source(package, idx, vststoken=ado_token, githubtoken=github_token)
|
96
97
|
package_name, options = package.get_install_command()
|
97
98
|
pip_cmd = PIP_INSTALL_COMMAND + PIP_INSTALL_VENV_COMMON_OPTIONS + options + [package_name]
|
98
|
-
|
99
|
+
py2docfx_logger = get_logger(__name__)
|
100
|
+
await run_async_subprocess(executable, pip_cmd, py2docfx_logger)
|
99
101
|
|
100
102
|
async def create_environment(venv_path: int):
|
101
103
|
if os.name == 'nt':
|
@@ -125,7 +127,7 @@ async def prepare_venv(venv_num: int, package_info: PackageInfo, package_number:
|
|
125
127
|
py2docfx_logger = get_logger(__name__)
|
126
128
|
await create_environment(get_venv_path(venv_num))
|
127
129
|
await install_venv_requirements(venv_num)
|
128
|
-
get_source(get_venv_exe(venv_num), package_info, package_number, vststoken=ado_token, githubtoken=github_token)
|
130
|
+
await get_source(get_venv_exe(venv_num), package_info, package_number, vststoken=ado_token, githubtoken=github_token)
|
129
131
|
package_name, options = package_info.get_install_command()
|
130
132
|
await pip_utils.install_in_exe_async(get_venv_exe(venv_num), package_name, options)
|
131
133
|
msg = f"<CI INFO>: venv{venv_num} setup complete."
|
@@ -138,8 +140,9 @@ async def remove_environment(venv_num: int):
|
|
138
140
|
msg = f"<CI INFO>: Removing venv{venv_num}..."
|
139
141
|
py2docfx_logger.info(msg)
|
140
142
|
# Create a subprocess to run the shell command for removing the directory
|
143
|
+
cmd = f'rm -rf {venv_path}' if os.name != 'nt' else f'rmdir /S /Q {venv_path}'
|
141
144
|
process = await asyncio.create_subprocess_shell(
|
142
|
-
|
145
|
+
cmd,
|
143
146
|
stdout=asyncio.subprocess.PIPE,
|
144
147
|
stderr=asyncio.subprocess.PIPE
|
145
148
|
)
|
@@ -150,4 +153,4 @@ async def remove_environment(venv_num: int):
|
|
150
153
|
else:
|
151
154
|
msg = f"<CI ERROR>: Failed to remove venv{venv_num}. Error: {stderr.decode()}"
|
152
155
|
py2docfx_logger.error(msg)
|
153
|
-
raise
|
156
|
+
raise subprocess.CalledProcessError(process.returncode, cmd, stdout, stderr)
|
@@ -28,12 +28,12 @@ async def generate_document(pkg: PackageInfo, output_root: str | os.PathLike, sp
|
|
28
28
|
exclude_paths = pkg.get_exluded_command()
|
29
29
|
|
30
30
|
if pkg.install_type == pkg.InstallType.SOURCE_CODE and getattr(pkg, "branch", None):
|
31
|
-
checkout(package_paths.source_folder, pkg.branch)
|
31
|
+
await checkout(package_paths.source_folder, pkg.branch)
|
32
32
|
|
33
33
|
msg = f"<CI INFO>: Generating RST files for {pkg.name}."
|
34
34
|
py2docfx_logger.info(msg)
|
35
35
|
|
36
|
-
subpackages_rst_record = run_apidoc(pkg.name, package_paths.doc_folder, package_paths.source_folder,
|
36
|
+
subpackages_rst_record = await run_apidoc(pkg.name, package_paths.doc_folder, package_paths.source_folder,
|
37
37
|
exclude_paths, pkg)
|
38
38
|
|
39
39
|
msg = f"<CI INFO>: Listing RST files:"
|
@@ -72,7 +72,7 @@ def update_package_info(executable: str, pkg: PackageInfo, source_folder: str):
|
|
72
72
|
source_folder=source_folder, yaml_output_folder=yaml_output_folder, package_name=pkg.name
|
73
73
|
)
|
74
74
|
|
75
|
-
def get_source(executable: str, pkg: PackageInfo, cnt: int, vststoken=None, githubtoken=None):
|
75
|
+
async def get_source(executable: str, pkg: PackageInfo, cnt: int, vststoken=None, githubtoken=None):
|
76
76
|
py2docfx_logger = get_logger(__name__)
|
77
77
|
path_cnt = str(cnt)
|
78
78
|
dist_dir = path.join(DIST_TEMP, path_cnt)
|
@@ -81,7 +81,7 @@ def get_source(executable: str, pkg: PackageInfo, cnt: int, vststoken=None, gith
|
|
81
81
|
if pkg.url:
|
82
82
|
repo_folder = path.join(SOURCE_REPO, path_cnt)
|
83
83
|
token = githubtoken if "github.com" in pkg.url else vststoken
|
84
|
-
source_folder = git.clone(
|
84
|
+
source_folder = await git.clone(
|
85
85
|
repo_location=pkg.url,
|
86
86
|
branch=pkg.branch,
|
87
87
|
folder=repo_folder,
|
@@ -94,7 +94,7 @@ def get_source(executable: str, pkg: PackageInfo, cnt: int, vststoken=None, gith
|
|
94
94
|
sys.path.insert(0, source_folder)
|
95
95
|
elif pkg.install_type == PackageInfo.InstallType.PYPI:
|
96
96
|
full_name = pkg.get_combined_name_version()
|
97
|
-
pip_utils.download(
|
97
|
+
await pip_utils.download(
|
98
98
|
full_name,
|
99
99
|
dist_dir,
|
100
100
|
extra_index_url=pkg.extra_index_url,
|
@@ -102,17 +102,17 @@ def get_source(executable: str, pkg: PackageInfo, cnt: int, vststoken=None, gith
|
|
102
102
|
)
|
103
103
|
# unpack the downloaded wheel file.
|
104
104
|
downloaded_dist_file = path.join(dist_dir, os.listdir(dist_dir)[0])
|
105
|
-
pack.unpack_dist(pkg.name, downloaded_dist_file)
|
105
|
+
await pack.unpack_dist(pkg.name, downloaded_dist_file)
|
106
106
|
os.remove(downloaded_dist_file)
|
107
107
|
source_folder = path.join(
|
108
108
|
path.dirname(downloaded_dist_file),
|
109
109
|
os.listdir(dist_dir)[0]
|
110
110
|
)
|
111
111
|
elif pkg.install_type == PackageInfo.InstallType.DIST_FILE:
|
112
|
-
pip_utils.download(pkg.location, dist_dir, prefer_source_distribution=False)
|
112
|
+
await pip_utils.download(pkg.location, dist_dir, prefer_source_distribution=False)
|
113
113
|
# unpack the downloaded dist file.
|
114
114
|
downloaded_dist_file = path.join(dist_dir, os.listdir(dist_dir)[0])
|
115
|
-
pack.unpack_dist(pkg.name, downloaded_dist_file)
|
115
|
+
await pack.unpack_dist(pkg.name, downloaded_dist_file)
|
116
116
|
os.remove(downloaded_dist_file)
|
117
117
|
if downloaded_dist_file.endswith(".tar.gz"):
|
118
118
|
downloaded_dist_file = downloaded_dist_file.rsplit(".", maxsplit=1)[
|
py2docfx/convert_prepare/git.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
import re
|
2
2
|
import subprocess
|
3
3
|
|
4
|
-
from py2docfx.docfx_yaml.logger import get_logger,
|
4
|
+
from py2docfx.docfx_yaml.logger import get_logger, run_async_subprocess_without_executable
|
5
5
|
|
6
6
|
repoMap = {}
|
7
7
|
|
8
|
-
def clone(repo_location, branch, folder, extra_token=None):
|
8
|
+
async def clone(repo_location, branch, folder, extra_token=None):
|
9
9
|
"""
|
10
10
|
Clone a git repo to the folder
|
11
11
|
When extra_token isn't None, add it to the command
|
@@ -57,8 +57,7 @@ def clone(repo_location, branch, folder, extra_token=None):
|
|
57
57
|
extra_token
|
58
58
|
),
|
59
59
|
]
|
60
|
-
|
61
|
-
log_git_clone_subprocess_ouput(output, py2docfx_logger)
|
60
|
+
await run_async_subprocess_without_executable(clone_params, py2docfx_logger)
|
62
61
|
repoMap[pureURL] = folder
|
63
62
|
msg = "<CI INFO>: Repo {} successfully cloned in {}...".format(
|
64
63
|
repo_location, repoMap[pureURL]
|
@@ -123,7 +122,7 @@ def convertBranch(repo_url, branch, extraHeader):
|
|
123
122
|
return result
|
124
123
|
|
125
124
|
|
126
|
-
def checkout(folder, branch):
|
125
|
+
async def checkout(folder, branch):
|
127
126
|
"""
|
128
127
|
Checkout one folder to a given branch
|
129
128
|
|
@@ -145,8 +144,7 @@ def checkout(folder, branch):
|
|
145
144
|
if "* {}".format(branch) not in branches:
|
146
145
|
# branch is not exactly current branch
|
147
146
|
if branch not in branches:
|
148
|
-
|
149
|
-
[
|
147
|
+
fetch_cmd = [
|
150
148
|
"git",
|
151
149
|
"-C",
|
152
150
|
folder,
|
@@ -154,12 +152,11 @@ def checkout(folder, branch):
|
|
154
152
|
"--quiet",
|
155
153
|
remote,
|
156
154
|
"{}:{}".format(branch, branch),
|
157
|
-
]
|
158
|
-
)
|
159
|
-
log_subprocess_ouput(output, py2docfx_logger)
|
155
|
+
]
|
156
|
+
await run_async_subprocess_without_executable(fetch_cmd, py2docfx_logger)
|
160
157
|
|
161
|
-
|
162
|
-
|
158
|
+
checkout_cmd = ["git", "-C", folder, "checkout", "--quiet", branch]
|
159
|
+
await run_async_subprocess_without_executable(checkout_cmd, py2docfx_logger)
|
163
160
|
msg = "<CI INFO>: Switched to branch {}.".format(branch)
|
164
161
|
py2docfx_logger.info(msg)
|
165
162
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from py2docfx.convert_prepare.package_info import PackageInfo
|
2
2
|
import py2docfx.convert_prepare.pip_utils as pip_utils
|
3
3
|
|
4
|
-
def install_package(pkg: PackageInfo):
|
4
|
+
async def install_package(pkg: PackageInfo):
|
5
5
|
package_name, options = pkg.get_install_command()
|
6
|
-
pip_utils.install(package_name, options)
|
6
|
+
await pip_utils.install(package_name, options)
|
py2docfx/convert_prepare/pack.py
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
import shutil
|
2
2
|
from os import path
|
3
3
|
import os
|
4
|
-
import subprocess
|
5
4
|
import sys
|
6
5
|
|
7
|
-
from py2docfx.docfx_yaml.logger import get_package_logger,
|
6
|
+
from py2docfx.docfx_yaml.logger import get_package_logger, run_async_subprocess
|
8
7
|
|
9
|
-
def unpack_dist(package_name, dist_file):
|
8
|
+
async def unpack_dist(package_name, dist_file):
|
10
9
|
if dist_file.endswith(".whl"):
|
11
|
-
unpack_wheel(package_name, dist_file)
|
10
|
+
await unpack_wheel(package_name, dist_file)
|
12
11
|
else:
|
13
12
|
unpack_compressed(dist_file)
|
14
13
|
|
@@ -20,20 +19,18 @@ def unpack_compressed(file_path):
|
|
20
19
|
shutil.unpack_archive(file_path, path.dirname(file_path))
|
21
20
|
|
22
21
|
|
23
|
-
def unpack_wheel(package_name, file_path):
|
22
|
+
async def unpack_wheel(package_name, file_path):
|
24
23
|
"""
|
25
24
|
Transform a wheel file to a folder containing source code
|
26
25
|
"""
|
27
26
|
py2docfx_logger = get_package_logger(__name__, package_name)
|
28
|
-
command = [
|
29
|
-
'-m',
|
27
|
+
command = ['-m',
|
30
28
|
'wheel',
|
31
29
|
'unpack',
|
32
30
|
file_path,
|
33
31
|
'-d',
|
34
32
|
os.path.dirname(file_path)]
|
35
|
-
|
36
|
-
log_subprocess_ouput(output, py2docfx_logger)
|
33
|
+
await run_async_subprocess(sys.executable, command, py2docfx_logger)
|
37
34
|
extract_folder = [file for file in os.listdir(path.dirname(file_path)) if path.isdir(path.join(path.dirname(file_path), file))][0]
|
38
35
|
data_folder = path.join(path.dirname(file_path), extract_folder, extract_folder + ".data")
|
39
36
|
if path.exists(data_folder):
|
@@ -1,7 +1,7 @@
|
|
1
|
-
import
|
1
|
+
import sys
|
2
2
|
|
3
3
|
from py2docfx import PACKAGE_ROOT
|
4
|
-
from py2docfx.docfx_yaml.logger import get_logger,
|
4
|
+
from py2docfx.docfx_yaml.logger import get_logger, run_async_subprocess, run_async_subprocess_without_executable
|
5
5
|
|
6
6
|
PYPI = "pypi"
|
7
7
|
|
@@ -14,7 +14,7 @@ pip_install_common_options = [
|
|
14
14
|
"--verbose"
|
15
15
|
]
|
16
16
|
|
17
|
-
def download(package_name, path, extra_index_url=None, prefer_source_distribution=True):
|
17
|
+
async def download(package_name, path, extra_index_url=None, prefer_source_distribution=True):
|
18
18
|
# Downloads a package from PyPI to the specified path using pip.
|
19
19
|
download_param = ["pip", "download", "--dest", path, "--no-deps", package_name]
|
20
20
|
if extra_index_url:
|
@@ -24,29 +24,27 @@ def download(package_name, path, extra_index_url=None, prefer_source_distributio
|
|
24
24
|
download_param.append("--no-binary=:all:")
|
25
25
|
else:
|
26
26
|
download_param.append("--prefer-binary")
|
27
|
-
output = subprocess.run(download_param, check=True, cwd=PACKAGE_ROOT, capture_output=True, text=True)
|
28
|
-
py2docfx_logger = get_logger(__name__)
|
29
|
-
log_subprocess_ouput(output, py2docfx_logger)
|
30
27
|
|
28
|
+
py2docfx_logger = get_logger(__name__)
|
29
|
+
await run_async_subprocess_without_executable(download_param, py2docfx_logger, cwd=PACKAGE_ROOT)
|
31
30
|
|
32
|
-
def install(package_name, options):
|
31
|
+
async def install(package_name, options):
|
33
32
|
# Installs a package from PyPI using pip.
|
34
33
|
install_param = "pip install {} {}".format(
|
35
34
|
" ".join(pip_install_common_options + options), package_name
|
36
35
|
).split(" ")
|
37
|
-
output = subprocess.run(install_param, check=True, cwd=PACKAGE_ROOT, capture_output=True, text=True)
|
38
36
|
py2docfx_logger = get_logger(__name__)
|
39
|
-
|
37
|
+
await run_async_subprocess_without_executable(install_param, py2docfx_logger, cwd=PACKAGE_ROOT)
|
40
38
|
|
41
|
-
def install_in_exe(exe_path, package_name, options):
|
39
|
+
async def install_in_exe(exe_path, package_name, options):
|
42
40
|
# Installs a package from PyPI using pip.
|
43
41
|
install_param = [exe_path] + "-m pip install {} {}".format(
|
44
42
|
" ".join(pip_install_common_options + options), package_name
|
45
43
|
).split(" ")
|
46
|
-
output = subprocess.run(install_param, check=True, cwd=PACKAGE_ROOT, capture_output=True, text=True)
|
47
44
|
py2docfx_logger = get_logger(__name__)
|
48
|
-
|
49
|
-
|
45
|
+
await run_async_subprocess(exe_path, install_param, py2docfx_logger, cwd=PACKAGE_ROOT)
|
46
|
+
|
50
47
|
async def install_in_exe_async(exe_path, package_name, options):
|
51
48
|
pip_cmd = ["-m", "pip", "install"]+ pip_install_common_options + options + [package_name]
|
52
|
-
|
49
|
+
py2docfx_logger = get_logger(__name__)
|
50
|
+
await run_async_subprocess(exe_path, pip_cmd, py2docfx_logger)
|
@@ -4,7 +4,7 @@ import subprocess
|
|
4
4
|
import sys
|
5
5
|
|
6
6
|
from py2docfx import PACKAGE_ROOT
|
7
|
-
from py2docfx.docfx_yaml.logger import get_package_logger,
|
7
|
+
from py2docfx.docfx_yaml.logger import get_package_logger,run_async_subprocess
|
8
8
|
from py2docfx.convert_prepare.package_info import PackageInfo
|
9
9
|
from py2docfx.convert_prepare.paths import folder_is_hidden
|
10
10
|
from py2docfx.convert_prepare.subpackage import (get_subpackages,
|
@@ -12,7 +12,7 @@ from py2docfx.convert_prepare.subpackage import (get_subpackages,
|
|
12
12
|
|
13
13
|
DEBUG_SPHINX_FLAG = 'PY2DOCFX_DEBUG_SPHINX'
|
14
14
|
|
15
|
-
def run_apidoc(package_name, rst_path, source_code_path, exclude_paths, package_info: PackageInfo):
|
15
|
+
async def run_apidoc(package_name, rst_path, source_code_path, exclude_paths, package_info: PackageInfo):
|
16
16
|
"""
|
17
17
|
Run sphinx-apidoc to generate RST inside rst_path folder
|
18
18
|
|
@@ -41,8 +41,8 @@ def run_apidoc(package_name, rst_path, source_code_path, exclude_paths, package_
|
|
41
41
|
subfolderPath,
|
42
42
|
]
|
43
43
|
args.extend(exclude_paths)
|
44
|
-
|
45
|
-
|
44
|
+
full_args = ["-m", "sphinx.ext.apidoc"] + args
|
45
|
+
await run_async_subprocess(sys.executable, full_args, py2docfx_logger)
|
46
46
|
if package_info.build_in_subpackage and subfolder == "azure":
|
47
47
|
subpackages_rst_record = move_rst_files_to_subfolder(
|
48
48
|
package_paths.doc_folder, package_info.name,
|
@@ -62,7 +62,8 @@ def test_update_package_info(init_package_info):
|
|
62
62
|
assert package.name == "mock_package"
|
63
63
|
assert package.version == "1.2.0"
|
64
64
|
|
65
|
-
|
65
|
+
@pytest.mark.asyncio
|
66
|
+
async def test_get_source_git_clone(init_package_info):
|
66
67
|
"""
|
67
68
|
Test the git clone of get_source
|
68
69
|
"""
|
@@ -77,10 +78,11 @@ def test_get_source_git_clone(init_package_info):
|
|
77
78
|
package.branch = "main"
|
78
79
|
package.folder = None
|
79
80
|
package.url = "https://github.com/Azure/azure-iot-hub-python"
|
80
|
-
get_source.get_source(sys.executable, package, 0)
|
81
|
+
await get_source.get_source(sys.executable, package, 0)
|
81
82
|
assert git.status("source_repo/0") is True
|
82
83
|
|
83
|
-
|
84
|
+
@pytest.mark.asyncio
|
85
|
+
async def test_get_source_dist_file_zip(init_package_info):
|
84
86
|
"""
|
85
87
|
Test the zip dist file download of get_source
|
86
88
|
"""
|
@@ -93,12 +95,13 @@ def test_get_source_dist_file_zip(init_package_info):
|
|
93
95
|
package.extra_index_url = None
|
94
96
|
package.prefer_source_distribution = True
|
95
97
|
package.location = "https://files.pythonhosted.org/packages/3e/71/f6f71a276e2e69264a97ad39ef850dca0a04fce67b12570730cb38d0ccac/azure-common-1.1.28.zip"
|
96
|
-
get_source.get_source(sys.executable, package, 1)
|
98
|
+
await get_source.get_source(sys.executable, package, 1)
|
97
99
|
assert os.path.exists("dist_temp/1/azure-common-1.1.28")
|
98
100
|
assert package.path.source_folder == os.path.join("dist_temp", "1", "azure-common-1.1.28")
|
99
101
|
assert os.path.exists("dist_temp/1/azure-common-1.1.28.zip") is False
|
100
102
|
|
101
|
-
|
103
|
+
@pytest.mark.asyncio
|
104
|
+
async def test_get_source_dist_file_whl(init_package_info):
|
102
105
|
"""
|
103
106
|
Test the whl dist file download of get_source
|
104
107
|
"""
|
@@ -111,12 +114,13 @@ def test_get_source_dist_file_whl(init_package_info):
|
|
111
114
|
package.extra_index_url = None
|
112
115
|
package.prefer_source_distribution = True
|
113
116
|
package.location = "https://files.pythonhosted.org/packages/62/55/7f118b9c1b23ec15ca05d15a578d8207aa1706bc6f7c87218efffbbf875d/azure_common-1.1.28-py2.py3-none-any.whl"
|
114
|
-
get_source.get_source(sys.executable, package, 2)
|
117
|
+
await get_source.get_source(sys.executable, package, 2)
|
115
118
|
assert os.path.exists("dist_temp/2/azure_common-1.1.28")
|
116
119
|
assert package.path.source_folder == os.path.join("dist_temp", "2", "azure_common-1.1.28")
|
117
120
|
assert os.path.exists("dist_temp/2/azure_common-1.1.28-py2.py3-none-any.whl") is False
|
118
121
|
|
119
|
-
|
122
|
+
@pytest.mark.asyncio
|
123
|
+
async def test_get_source_dist_file_tar(init_package_info):
|
120
124
|
"""
|
121
125
|
Test the tar dist file download of get_source
|
122
126
|
"""
|
@@ -129,12 +133,13 @@ def test_get_source_dist_file_tar(init_package_info):
|
|
129
133
|
package.extra_index_url = None
|
130
134
|
package.prefer_source_distribution = True
|
131
135
|
package.location = "https://files.pythonhosted.org/packages/fa/19/43a9eb812b4d6071fdc2c55640318f7eb5a1be8dbd3b6f9d96a1996e1bb6/azure-core-1.29.4.tar.gz"
|
132
|
-
get_source.get_source(sys.executable, package, 3)
|
136
|
+
await get_source.get_source(sys.executable, package, 3)
|
133
137
|
assert os.path.exists("dist_temp/3/azure-core-1.29.4")
|
134
138
|
assert package.path.source_folder == os.path.join("dist_temp", "3", "azure-core-1.29.4")
|
135
139
|
assert os.path.exists("dist_temp/3/azure-core-1.29.4.tar.gz") is False
|
136
140
|
|
137
|
-
|
141
|
+
@pytest.mark.asyncio
|
142
|
+
async def test_get_source_pip_whl(init_package_info):
|
138
143
|
"""
|
139
144
|
Test the pip install of get_source with prefer_source_distribution = False
|
140
145
|
"""
|
@@ -146,12 +151,13 @@ def test_get_source_pip_whl(init_package_info):
|
|
146
151
|
package.build_in_subpackage = False
|
147
152
|
package.extra_index_url = None
|
148
153
|
package.prefer_source_distribution = False
|
149
|
-
get_source.get_source(sys.executable, package, 4)
|
154
|
+
await get_source.get_source(sys.executable, package, 4)
|
150
155
|
assert os.path.exists("dist_temp/4/azure_common-1.1.28")
|
151
156
|
assert package.path.source_folder == os.path.join("dist_temp", "4", "azure_common-1.1.28")
|
152
157
|
assert os.path.exists("dist_temp/4/azure_common-1.1.28-py2.py3-none-any.whl") is False
|
153
158
|
|
154
|
-
|
159
|
+
@pytest.mark.asyncio
|
160
|
+
async def test_get_source_pip_zip(init_package_info):
|
155
161
|
"""
|
156
162
|
Test the pip install of get_source with prefer_source_distribution = True
|
157
163
|
"""
|
@@ -163,12 +169,13 @@ def test_get_source_pip_zip(init_package_info):
|
|
163
169
|
package.build_in_subpackage = False
|
164
170
|
package.extra_index_url = None
|
165
171
|
package.prefer_source_distribution = True
|
166
|
-
get_source.get_source(sys.executable, package, 5)
|
172
|
+
await get_source.get_source(sys.executable, package, 5)
|
167
173
|
assert os.path.exists("dist_temp/5/azure-common-1.1.28")
|
168
174
|
assert package.path.source_folder == os.path.join("dist_temp", "5", "azure-common-1.1.28")
|
169
175
|
assert os.path.exists("dist_temp/5/azure-common-1.1.28.zip") is False
|
170
176
|
|
171
|
-
|
177
|
+
@pytest.mark.asyncio
|
178
|
+
async def test_get_source_zip_file_at_position_0(init_package_info):
|
172
179
|
"""
|
173
180
|
Test the pip install of packages with zip or tar file at position 0 in the dirctory list
|
174
181
|
"""
|
@@ -180,7 +187,7 @@ def test_get_source_zip_file_at_position_0(init_package_info):
|
|
180
187
|
package.build_in_subpackage = False
|
181
188
|
package.extra_index_url = None
|
182
189
|
package.prefer_source_distribution = True
|
183
|
-
get_source.get_source(sys.executable, package, 6)
|
190
|
+
await get_source.get_source(sys.executable, package, 6)
|
184
191
|
assert os.path.exists("dist_temp/6/azure_template-0.1.0b3942895")
|
185
192
|
assert package.path.source_folder == os.path.join("dist_temp", "6", "azure_template-0.1.0b3942895")
|
186
193
|
assert os.path.exists("dist_temp/6/azure_template-0.1.0b3942895.tar.gz") is False
|
@@ -5,6 +5,7 @@ import subprocess
|
|
5
5
|
import shutil
|
6
6
|
import glob
|
7
7
|
from os import path
|
8
|
+
import pytest
|
8
9
|
|
9
10
|
from py2docfx.convert_prepare.pack import unpack_compressed, unpack_wheel
|
10
11
|
|
@@ -82,8 +83,8 @@ def test_pack_unpack_compressed(tmp_path):
|
|
82
83
|
path.abspath("convert_prepare/tests/data/pack"), tmp_path / "gz", [], [str(gz_file_path)]
|
83
84
|
)
|
84
85
|
|
85
|
-
|
86
|
-
def test_pack_unpack_wheel(tmp_path):
|
86
|
+
@pytest.mark.asyncio
|
87
|
+
async def test_pack_unpack_wheel(tmp_path):
|
87
88
|
def _prepare_wheel(target_path):
|
88
89
|
subprocess.run(
|
89
90
|
["pip", "wheel", ".", "--wheel-dir", str(target_path / "wheel")],
|
@@ -109,7 +110,7 @@ def test_pack_unpack_wheel(tmp_path):
|
|
109
110
|
|
110
111
|
# unpack and assert the file list
|
111
112
|
package_name = wheel_name.split("-")[0]
|
112
|
-
unpack_wheel(package_name, wheel_path)
|
113
|
+
await unpack_wheel(package_name, wheel_path)
|
113
114
|
_assert_file_list_same(
|
114
115
|
path.abspath("convert_prepare/tests/data/pack"),
|
115
116
|
tmp_path / "wheel" / "foo-0.1",
|
@@ -24,11 +24,11 @@ def init_paths(tmp_path):
|
|
24
24
|
package_info.name = 'testcode'
|
25
25
|
return rst_path, destination
|
26
26
|
|
27
|
-
|
28
|
-
def test_run_apidoc(tmp_path):
|
27
|
+
@pytest.mark.asyncio
|
28
|
+
async def test_run_apidoc(tmp_path):
|
29
29
|
rst_path, source_code_path = init_paths(tmp_path)
|
30
30
|
package_name = "testcode"
|
31
|
-
run_apidoc(package_name, rst_path, source_code_path, package_info.get_exluded_command(), package_info)
|
31
|
+
await run_apidoc(package_name, rst_path, source_code_path, package_info.get_exluded_command(), package_info)
|
32
32
|
|
33
33
|
# List all files under rst_path
|
34
34
|
rst_list = os.listdir(rst_path)
|
@@ -39,7 +39,7 @@ def test_run_apidoc(tmp_path):
|
|
39
39
|
async def test_run_converter(tmp_path):
|
40
40
|
rst_path, source_code_path = init_paths(tmp_path)
|
41
41
|
package_name = "testcode"
|
42
|
-
run_apidoc(package_name, rst_path, source_code_path, package_info.get_exluded_command(), package_info)
|
42
|
+
await run_apidoc(package_name, rst_path, source_code_path, package_info.get_exluded_command(), package_info)
|
43
43
|
|
44
44
|
# prepare conf.py, index.rst and docfx_yaml
|
45
45
|
conf_path = os.path.abspath("convert_prepare/tests/data/sphinx_caller/conf.py")
|
py2docfx/docfx_yaml/logger.py
CHANGED
@@ -65,34 +65,6 @@ def get_package_logger(logger_name:str, package_name:str = None):
|
|
65
65
|
|
66
66
|
return file_logger
|
67
67
|
|
68
|
-
def log_subprocess_ouput(subprocess_out: subprocess.CompletedProcess, logger: logging.Logger):
|
69
|
-
if subprocess_out.stdout:
|
70
|
-
logger.info(subprocess_out.stdout)
|
71
|
-
if subprocess_out.stderr:
|
72
|
-
msgs = subprocess_out.stderr.split('\n')
|
73
|
-
for msg in msgs:
|
74
|
-
if msg is None or msg == "":
|
75
|
-
continue
|
76
|
-
logger.warning(msg)
|
77
|
-
if subprocess_out.returncode != 0:
|
78
|
-
msg = f"Subprocess failed with return code {subprocess_out.returncode}"
|
79
|
-
logger.error(msg)
|
80
|
-
raise RuntimeError(msg)
|
81
|
-
|
82
|
-
def log_git_clone_subprocess_ouput(subprocess_out: subprocess.CompletedProcess, logger: logging.Logger):
|
83
|
-
if subprocess_out.stdout:
|
84
|
-
logger.info(subprocess_out.stdout)
|
85
|
-
if subprocess_out.stderr:
|
86
|
-
msgs = subprocess_out.stderr.split('\n')
|
87
|
-
for msg in msgs:
|
88
|
-
if msg is None or msg == "":
|
89
|
-
continue
|
90
|
-
logger.info(msg)
|
91
|
-
if subprocess_out.returncode != 0:
|
92
|
-
msg = f"Subprocess failed with return code {subprocess_out.returncode}"
|
93
|
-
logger.error(msg)
|
94
|
-
raise RuntimeError(msg)
|
95
|
-
|
96
68
|
def counts_errors_warnings(log_file_path):
|
97
69
|
error_count = 0
|
98
70
|
warning_count = 0
|
@@ -156,20 +128,53 @@ def output_log_by_log_level():
|
|
156
128
|
log_file_path = os.path.join(package_logs_folder, log_file)
|
157
129
|
print_out_log_by_log_level(parse_log(log_file_path), log_level)
|
158
130
|
|
159
|
-
async def run_async_subprocess(exe_path, cmd):
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
131
|
+
async def run_async_subprocess(exe_path, cmd, logger, cwd=None):
|
132
|
+
if cwd is None:
|
133
|
+
process = await asyncio.create_subprocess_exec(
|
134
|
+
exe_path, *cmd,
|
135
|
+
stdout=asyncio.subprocess.PIPE,
|
136
|
+
stderr=asyncio.subprocess.PIPE
|
137
|
+
)
|
138
|
+
else:
|
139
|
+
process = await asyncio.create_subprocess_exec(
|
140
|
+
exe_path, *cmd,
|
141
|
+
cwd=cwd,
|
142
|
+
stdout=asyncio.subprocess.PIPE,
|
143
|
+
stderr=asyncio.subprocess.PIPE,
|
144
|
+
)
|
145
|
+
stdout, stderr = await process.communicate()
|
146
|
+
if process.returncode != 0:
|
147
|
+
msg = stderr.decode('utf-8')
|
148
|
+
if msg != None and msg != "":
|
149
|
+
logger.error(msg)
|
150
|
+
raise subprocess.CalledProcessError(process.returncode, cmd, stdout, stderr)
|
151
|
+
else:
|
152
|
+
msg = stdout.decode('utf-8')
|
153
|
+
if msg != None and msg != "":
|
154
|
+
logger.info(msg)
|
155
|
+
|
156
|
+
async def run_async_subprocess_without_executable(cmd, logger, cwd=None):
|
157
|
+
if cwd is None:
|
158
|
+
process = await asyncio.create_subprocess_exec(
|
159
|
+
*cmd,
|
160
|
+
stdout=asyncio.subprocess.PIPE,
|
161
|
+
stderr=asyncio.subprocess.PIPE
|
162
|
+
)
|
163
|
+
else:
|
164
|
+
process = await asyncio.create_subprocess_exec(
|
165
|
+
*cmd,
|
166
|
+
cwd=cwd,
|
167
|
+
stdout=asyncio.subprocess.PIPE,
|
168
|
+
stderr=asyncio.subprocess.PIPE,
|
169
|
+
)
|
170
|
+
|
165
171
|
stdout, stderr = await process.communicate()
|
166
|
-
py2docfx_logger = get_logger(__name__)
|
167
172
|
if process.returncode != 0:
|
168
173
|
msg = stderr.decode('utf-8')
|
169
174
|
if msg != None and msg != "":
|
170
|
-
|
171
|
-
raise
|
175
|
+
logger.error(msg)
|
176
|
+
raise subprocess.CalledProcessError(process.returncode, cmd, stdout, stderr)
|
172
177
|
else:
|
173
178
|
msg = stdout.decode('utf-8')
|
174
179
|
if msg != None and msg != "":
|
175
|
-
|
180
|
+
logger.info(msg)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: py2docfx
|
3
|
-
Version: 0.1.11.
|
3
|
+
Version: 0.1.11.dev1994975
|
4
4
|
Summary: A package built based on Sphinx which download source code package and generate yaml files supported by docfx.
|
5
5
|
Author: Microsoft Corporation
|
6
6
|
License: MIT License
|
@@ -3,21 +3,21 @@ py2docfx/__main__.py,sha256=TYVpOAmi2MeAg2-d88RxyhCMSxxT6FfCafP_qnzSDKo,5875
|
|
3
3
|
py2docfx/convert_prepare/__init__.py,sha256=XxtxrP0kmW3ZBHIAoxsPDEHzcgeC0WSnole8Lk6CjKs,11
|
4
4
|
py2docfx/convert_prepare/arg_parser.py,sha256=Wa1iK8a0Gb3QqaS4X7nUPGvh-7mWhuBS9IVbmnjC770,7606
|
5
5
|
py2docfx/convert_prepare/constants.py,sha256=RC5DqNkqWvx4hb91FrajZ1R9dBFLxcPyoEJ43jdm36E,102
|
6
|
-
py2docfx/convert_prepare/environment.py,sha256=
|
6
|
+
py2docfx/convert_prepare/environment.py,sha256=ClUnNHehYjxMwS50cqnCQO5vHCQaA289opSdfhkOARc,7293
|
7
7
|
py2docfx/convert_prepare/generate_conf.py,sha256=wqs6iyElzJarH-20_qEL9zvZvt5xfBMsGXSXPSZy6wg,2295
|
8
|
-
py2docfx/convert_prepare/generate_document.py,sha256=
|
9
|
-
py2docfx/convert_prepare/get_source.py,sha256=
|
10
|
-
py2docfx/convert_prepare/git.py,sha256=
|
11
|
-
py2docfx/convert_prepare/install_package.py,sha256=
|
12
|
-
py2docfx/convert_prepare/pack.py,sha256=
|
8
|
+
py2docfx/convert_prepare/generate_document.py,sha256=iTOCMBwkfvZEj5dlEGUq4qynUodaYxJuIrG9R5eGk38,2949
|
9
|
+
py2docfx/convert_prepare/get_source.py,sha256=Sw5QMWWbKLSznHgNu7JLSW0Wy_FEk0uR_IaKKSKUCl4,5280
|
10
|
+
py2docfx/convert_prepare/git.py,sha256=Qb6uexUo3KKwp2Hq9Q27gMU4Z2P8ZBk7JcSmxBfFCBY,6491
|
11
|
+
py2docfx/convert_prepare/install_package.py,sha256=aJxQBwLRPTIKpdtLVl-SaXPaF_OX_H1ZtWmcKD8Zzuk,274
|
12
|
+
py2docfx/convert_prepare/pack.py,sha256=Jjj9ps8ESoKUFmSk6VgNmxOwMhuwirnQ-rhqigH-4VY,1578
|
13
13
|
py2docfx/convert_prepare/package_info.py,sha256=-zrMNeAkHxxzLRjBl1kRehUJy_ugc16yns-xdcAHQIQ,7711
|
14
14
|
py2docfx/convert_prepare/package_info_extra_settings.py,sha256=u5B5e8hc0m9PA_-0kJzq1LtKn-xzZlucwXHTFy49mDg,1475
|
15
15
|
py2docfx/convert_prepare/params.py,sha256=PXMB8pLtb4XbfI322avA47q0AO-TyBE6kZf7FU8I6v4,1771
|
16
16
|
py2docfx/convert_prepare/paths.py,sha256=964RX81Qf__rzXgEATfqBNFCKTYVjLt9J7WCz2TnNdc,485
|
17
|
-
py2docfx/convert_prepare/pip_utils.py,sha256=
|
17
|
+
py2docfx/convert_prepare/pip_utils.py,sha256=Y_xmIE0Ld-gXgR8rkXSfj-AMh1bcUJvscMgSdNZyPQU,2138
|
18
18
|
py2docfx/convert_prepare/repo_info.py,sha256=6ASJlhBwf6vZTSENgrWCVlJjlJVhuBxzdQyWEdWAC4c,117
|
19
19
|
py2docfx/convert_prepare/source.py,sha256=6-A7oof3-WAQcQZZVpT9pKiFLH4CCIZeYqq0MN0O3gw,1710
|
20
|
-
py2docfx/convert_prepare/sphinx_caller.py,sha256=
|
20
|
+
py2docfx/convert_prepare/sphinx_caller.py,sha256=K7HZddkzENu_QkOrgoKeILsXkRmyQrpUXhRsow-51I4,4696
|
21
21
|
py2docfx/convert_prepare/subpackage.py,sha256=mXAi_07pXvnPkSLZfykDh_7VeFxfLy74pYlzhMO8N_Q,5183
|
22
22
|
py2docfx/convert_prepare/utils.py,sha256=TwfDjIqIx_nAoSeQ-LX30h_-d96WhPQcAu7P8N_tSjM,1618
|
23
23
|
py2docfx/convert_prepare/conf_templates/conf.py_t,sha256=8zxvY1WiG-z2aiSNDY0719C08QxZLXXEMwKfYSGN0ZE,3811
|
@@ -28,13 +28,13 @@ py2docfx/convert_prepare/subpackage_merge/merge_toc.py,sha256=nkVqe8R0m8D6cyTYV7
|
|
28
28
|
py2docfx/convert_prepare/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
29
29
|
py2docfx/convert_prepare/tests/test_environment.py,sha256=UfeTlfdZKLFcUrSNODw0mvkzZSdbQHBUoK56bdm1xz8,2065
|
30
30
|
py2docfx/convert_prepare/tests/test_generate_document.py,sha256=mY8DRT-WRGIBFdDRdFwa7ZSUQwR-fTQtyKwzrzFZLU8,2621
|
31
|
-
py2docfx/convert_prepare/tests/test_get_source.py,sha256=
|
32
|
-
py2docfx/convert_prepare/tests/test_pack.py,sha256=
|
31
|
+
py2docfx/convert_prepare/tests/test_get_source.py,sha256=IGBLAemm5SWUnNJJh6GJE5gBtAAdlC_cxS1xSeugzBI,7949
|
32
|
+
py2docfx/convert_prepare/tests/test_pack.py,sha256=Gw-LkIcbQuQHpoSbvkybYt4_fVw-LL12dceWw5AUKdE,4242
|
33
33
|
py2docfx/convert_prepare/tests/test_package_info.py,sha256=3B-IzmUjETVO-5s3g3Lmh2E6JgopwnRauv8mB-SDZEM,3361
|
34
34
|
py2docfx/convert_prepare/tests/test_params.py,sha256=itwmVdBMtU1qIXAGaIoaDfvTOYyAL2B_WLsaBV9KUZY,2232
|
35
35
|
py2docfx/convert_prepare/tests/test_post_process_merge_toc.py,sha256=YKOcn4_lf4syGsAvJ9BqpdUUc3SLfK4TiOX1lpXJT_Y,885
|
36
36
|
py2docfx/convert_prepare/tests/test_source.py,sha256=LNFZtvjz6QhVLOxatjWokYCCcoSm0bhTikMF9KoTPIE,2025
|
37
|
-
py2docfx/convert_prepare/tests/test_sphinx_caller.py,sha256=
|
37
|
+
py2docfx/convert_prepare/tests/test_sphinx_caller.py,sha256=btA6O9IjDSzIecvbjXWvB6r-zhs7rAtKI-eDVOHHOdI,2786
|
38
38
|
py2docfx/convert_prepare/tests/test_subpackage.py,sha256=famt8LqwS8hCujtzvRLE5Ih8pa7t45y0d1EBk3UdYns,4984
|
39
39
|
py2docfx/convert_prepare/tests/data/generate_document/azure-dummy-sourcecode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
40
|
py2docfx/convert_prepare/tests/data/generate_document/azure-dummy-sourcecode/azure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -65,7 +65,7 @@ py2docfx/docfx_yaml/convert_enum.py,sha256=HX6qdjDbdbBblx-TH41JXBLIJY3wzL3if-qnL
|
|
65
65
|
py2docfx/docfx_yaml/convert_module.py,sha256=GptO1MRwaQ2Qbu724F0kCDDQQTZe7mWOtrOp3Rzgl-I,2259
|
66
66
|
py2docfx/docfx_yaml/convert_package.py,sha256=Ep7PmvoLInDvY6OU5dveR6iVwyzGRkW3q6lX7yGJ0JE,2109
|
67
67
|
py2docfx/docfx_yaml/directives.py,sha256=zVVuNM_6AU9G6sbqL1UAyHHgPe7bkBWbthXI-PO5ez0,879
|
68
|
-
py2docfx/docfx_yaml/logger.py,sha256=
|
68
|
+
py2docfx/docfx_yaml/logger.py,sha256=gz416vqSqmsD91qLOCLAzomczlCfWqGXFJFRzLlVbJE,6503
|
69
69
|
py2docfx/docfx_yaml/miss_reference.py,sha256=Btoj9wAvA4u_wU7JHH0Cei3910N8a7MS34OUqJvXAd4,2443
|
70
70
|
py2docfx/docfx_yaml/nodes.py,sha256=tBDi35jLJArlobl07DKOkmH2qz7dudXLp_kTUfR_r2w,412
|
71
71
|
py2docfx/docfx_yaml/parameter_utils.py,sha256=zGSIQrUfbXf9PUK-W_1K83Uo5Zk797Zlze6aMurbHIA,8706
|
@@ -4193,7 +4193,7 @@ py2docfx/venv/venv1/Lib/site-packages/win32comext/taskscheduler/test/test_addtas
|
|
4193
4193
|
py2docfx/venv/venv1/Lib/site-packages/win32comext/taskscheduler/test/test_localsystem.py,sha256=08ojAS48W6RLsUbRD45j0SJhg_Y2NFHZT6qjT4Vrig0,75
|
4194
4194
|
py2docfx/venv/venv1/Scripts/pywin32_postinstall.py,sha256=u95n7QQUxpCjrZistYE-3gN451zXzopuJna8cXRQ4Jw,28115
|
4195
4195
|
py2docfx/venv/venv1/Scripts/pywin32_testall.py,sha256=-6yvZmd2lPQc4e8i6PgLsr_totF6mScvoq0Jqr0V2fM,3844
|
4196
|
-
py2docfx-0.1.11.
|
4197
|
-
py2docfx-0.1.11.
|
4198
|
-
py2docfx-0.1.11.
|
4199
|
-
py2docfx-0.1.11.
|
4196
|
+
py2docfx-0.1.11.dev1994975.dist-info/METADATA,sha256=1XFib52JkrdFsQzL7VUQAXxxpcRK7O33jJTA7WiPAOA,601
|
4197
|
+
py2docfx-0.1.11.dev1994975.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
4198
|
+
py2docfx-0.1.11.dev1994975.dist-info/top_level.txt,sha256=5dH2uP81dczt_qQJ38wiZ-gzoVWasfiJALWRSjdbnYU,9
|
4199
|
+
py2docfx-0.1.11.dev1994975.dist-info/RECORD,,
|
File without changes
|
File without changes
|