vscode-offline 0.1.0__tar.gz → 0.1.2__tar.gz
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.
- vscode_offline-0.1.2/LICENSE +7 -0
- vscode_offline-0.1.2/PKG-INFO +82 -0
- vscode_offline-0.1.2/README.md +58 -0
- vscode_offline-0.1.2/pyproject.toml +48 -0
- vscode_offline-0.1.2/src/vscode_offline/app.py +183 -0
- {vscode_offline-0.1.0 → vscode_offline-0.1.2}/src/vscode_offline/download.py +22 -11
- vscode_offline-0.1.2/src/vscode_offline/install.py +99 -0
- vscode_offline-0.1.2/src/vscode_offline/utils.py +92 -0
- vscode_offline-0.1.0/PKG-INFO +0 -50
- vscode_offline-0.1.0/README.md +0 -41
- vscode_offline-0.1.0/pyproject.toml +0 -28
- vscode_offline-0.1.0/src/vscode_offline/app.py +0 -104
- vscode_offline-0.1.0/src/vscode_offline/install.py +0 -74
- vscode_offline-0.1.0/src/vscode_offline/paths.py +0 -25
- {vscode_offline-0.1.0 → vscode_offline-0.1.2}/src/vscode_offline/__init__.py +0 -0
- {vscode_offline-0.1.0 → vscode_offline-0.1.2}/src/vscode_offline/loggers.py +0 -0
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2025 Chuck Fan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,82 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: vscode-offline
|
3
|
+
Version: 0.1.2
|
4
|
+
Summary: Download and install VS Code Server for offline environments
|
5
|
+
Author: Chuck Fan
|
6
|
+
Author-email: Chuck Fan <fanck0605@qq.com>
|
7
|
+
License-Expression: MIT
|
8
|
+
License-File: LICENSE
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
10
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
16
|
+
Classifier: Intended Audience :: Developers
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
19
|
+
Classifier: Operating System :: Microsoft :: Windows
|
20
|
+
Classifier: Topic :: Utilities
|
21
|
+
Requires-Python: >=3.9
|
22
|
+
Project-URL: Homepage, https://github.com/fanck0605/vscode-offline
|
23
|
+
Description-Content-Type: text/markdown
|
24
|
+
|
25
|
+
# vscode-offline
|
26
|
+
|
27
|
+
vscode-offline 主要用于在无网环境下安装 VS Code Server,方便使用 *Remote - SSH* 插件进行远程开发。
|
28
|
+
|
29
|
+
## 安装
|
30
|
+
|
31
|
+
```shell
|
32
|
+
pip install -U vscode-offline
|
33
|
+
```
|
34
|
+
|
35
|
+
## 优势
|
36
|
+
|
37
|
+
1. 自动识别并下载所有 `.vsix` 文件(包括间接依赖)
|
38
|
+
2. 一键安装 VS Code Server 以及所有插件
|
39
|
+
|
40
|
+
## VS Code Server 安装
|
41
|
+
|
42
|
+
(1)在联网环境安装好 VSCode 和你需要的插件。
|
43
|
+
|
44
|
+
(2)执行如下命令,将会自动下载 VS Code Server,和目前安装的所有的插件
|
45
|
+
|
46
|
+
> `--commit` 可以指定对应 VSCode 的 Commit,默认自动获取当前环境 VSCode 的 Commit。
|
47
|
+
>
|
48
|
+
> 手动查看方式:*帮助* -> *关于* -> *Commit*,
|
49
|
+
|
50
|
+
```shell
|
51
|
+
vscode-offline download-server --target-platform linux-x64 --installer ./vscode-offline-installer
|
52
|
+
```
|
53
|
+
|
54
|
+
(3)复制 `./vscode-offline-installer` 到内网服务器
|
55
|
+
|
56
|
+
```shell
|
57
|
+
vscode-offline install-server --installer ./vscode-offline-installer
|
58
|
+
```
|
59
|
+
|
60
|
+
## VS Code 插件安装
|
61
|
+
|
62
|
+
(1)联网环境执行如下命令,将会自动下载 VSCode 目前安装的所有的插件
|
63
|
+
|
64
|
+
```shell
|
65
|
+
vscode-offline download-extensions --target-platform win32-x64 --installer ./vscode-offline-installer
|
66
|
+
```
|
67
|
+
|
68
|
+
(2)复制 `./vscode-offline-installer` 到内网机器
|
69
|
+
|
70
|
+
```shell
|
71
|
+
vscode-offline install-extensions --installer ./vscode-offline-installer
|
72
|
+
```
|
73
|
+
|
74
|
+
## 贡献
|
75
|
+
|
76
|
+
欢迎提交 Issue 和 PR 改进本项目。
|
77
|
+
|
78
|
+
## License
|
79
|
+
|
80
|
+
Copyright (c) 2025 Chuck Fan.
|
81
|
+
|
82
|
+
Distributed under the terms of the [MIT License](https://github.com/fanck0605/vscode-offline/blob/master/LICENSE).
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# vscode-offline
|
2
|
+
|
3
|
+
vscode-offline 主要用于在无网环境下安装 VS Code Server,方便使用 *Remote - SSH* 插件进行远程开发。
|
4
|
+
|
5
|
+
## 安装
|
6
|
+
|
7
|
+
```shell
|
8
|
+
pip install -U vscode-offline
|
9
|
+
```
|
10
|
+
|
11
|
+
## 优势
|
12
|
+
|
13
|
+
1. 自动识别并下载所有 `.vsix` 文件(包括间接依赖)
|
14
|
+
2. 一键安装 VS Code Server 以及所有插件
|
15
|
+
|
16
|
+
## VS Code Server 安装
|
17
|
+
|
18
|
+
(1)在联网环境安装好 VSCode 和你需要的插件。
|
19
|
+
|
20
|
+
(2)执行如下命令,将会自动下载 VS Code Server,和目前安装的所有的插件
|
21
|
+
|
22
|
+
> `--commit` 可以指定对应 VSCode 的 Commit,默认自动获取当前环境 VSCode 的 Commit。
|
23
|
+
>
|
24
|
+
> 手动查看方式:*帮助* -> *关于* -> *Commit*,
|
25
|
+
|
26
|
+
```shell
|
27
|
+
vscode-offline download-server --target-platform linux-x64 --installer ./vscode-offline-installer
|
28
|
+
```
|
29
|
+
|
30
|
+
(3)复制 `./vscode-offline-installer` 到内网服务器
|
31
|
+
|
32
|
+
```shell
|
33
|
+
vscode-offline install-server --installer ./vscode-offline-installer
|
34
|
+
```
|
35
|
+
|
36
|
+
## VS Code 插件安装
|
37
|
+
|
38
|
+
(1)联网环境执行如下命令,将会自动下载 VSCode 目前安装的所有的插件
|
39
|
+
|
40
|
+
```shell
|
41
|
+
vscode-offline download-extensions --target-platform win32-x64 --installer ./vscode-offline-installer
|
42
|
+
```
|
43
|
+
|
44
|
+
(2)复制 `./vscode-offline-installer` 到内网机器
|
45
|
+
|
46
|
+
```shell
|
47
|
+
vscode-offline install-extensions --installer ./vscode-offline-installer
|
48
|
+
```
|
49
|
+
|
50
|
+
## 贡献
|
51
|
+
|
52
|
+
欢迎提交 Issue 和 PR 改进本项目。
|
53
|
+
|
54
|
+
## License
|
55
|
+
|
56
|
+
Copyright (c) 2025 Chuck Fan.
|
57
|
+
|
58
|
+
Distributed under the terms of the [MIT License](https://github.com/fanck0605/vscode-offline/blob/master/LICENSE).
|
@@ -0,0 +1,48 @@
|
|
1
|
+
[project]
|
2
|
+
name = "vscode-offline"
|
3
|
+
version = "0.1.2"
|
4
|
+
description = "Download and install VS Code Server for offline environments"
|
5
|
+
readme = "README.md"
|
6
|
+
authors = [
|
7
|
+
{ name = "Chuck Fan", email = "fanck0605@qq.com" }
|
8
|
+
]
|
9
|
+
requires-python = ">=3.9"
|
10
|
+
license = "MIT"
|
11
|
+
license-files = ["LICENSE"]
|
12
|
+
classifiers = [
|
13
|
+
"Development Status :: 4 - Beta",
|
14
|
+
"Programming Language :: Python :: 3 :: Only",
|
15
|
+
"Programming Language :: Python :: 3.9",
|
16
|
+
"Programming Language :: Python :: 3.10",
|
17
|
+
"Programming Language :: Python :: 3.11",
|
18
|
+
"Programming Language :: Python :: 3.12",
|
19
|
+
"Programming Language :: Python :: 3.13",
|
20
|
+
"Intended Audience :: Developers",
|
21
|
+
"License :: OSI Approved :: MIT License",
|
22
|
+
"Operating System :: POSIX :: Linux",
|
23
|
+
"Operating System :: Microsoft :: Windows",
|
24
|
+
"Topic :: Utilities",
|
25
|
+
]
|
26
|
+
dependencies = []
|
27
|
+
|
28
|
+
[project.urls]
|
29
|
+
Homepage = "https://github.com/fanck0605/vscode-offline"
|
30
|
+
|
31
|
+
[project.scripts]
|
32
|
+
vscode-offline = "vscode_offline:main"
|
33
|
+
|
34
|
+
[build-system]
|
35
|
+
requires = ["uv-build"]
|
36
|
+
build-backend = "uv_build"
|
37
|
+
|
38
|
+
[dependency-groups]
|
39
|
+
dev = [
|
40
|
+
"lefthook>=1.13.6",
|
41
|
+
"ruff>=0.13.3",
|
42
|
+
]
|
43
|
+
|
44
|
+
[tool.ruff.lint]
|
45
|
+
select = [
|
46
|
+
"I", # isort
|
47
|
+
"F", # Pyflakes
|
48
|
+
]
|
@@ -0,0 +1,183 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import logging
|
4
|
+
import os
|
5
|
+
from argparse import ArgumentParser, Namespace
|
6
|
+
from pathlib import Path
|
7
|
+
|
8
|
+
from vscode_offline.download import (
|
9
|
+
download_vscode_extensions,
|
10
|
+
download_vscode_server,
|
11
|
+
)
|
12
|
+
from vscode_offline.install import (
|
13
|
+
SERVER_EXCLUDE_EXTENSIONS,
|
14
|
+
install_vscode_extensions,
|
15
|
+
install_vscode_server,
|
16
|
+
)
|
17
|
+
from vscode_offline.loggers import logger
|
18
|
+
from vscode_offline.utils import (
|
19
|
+
get_host_platform,
|
20
|
+
get_vscode_cli_bin,
|
21
|
+
get_vscode_commit_from_code_version,
|
22
|
+
get_vscode_commit_from_installer,
|
23
|
+
get_vscode_extensions_config,
|
24
|
+
get_vscode_server_home,
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
def cmd_download_server(args: Namespace) -> None:
|
29
|
+
if args.commit is None:
|
30
|
+
args.commit = get_vscode_commit_from_code_version()
|
31
|
+
if args.commit is None:
|
32
|
+
logger.info(
|
33
|
+
"Cannot determine commit from `code --version`, please specify --commit manually."
|
34
|
+
)
|
35
|
+
raise ValueError("Please specify --commit when installing.")
|
36
|
+
|
37
|
+
download_vscode_server(
|
38
|
+
args.commit,
|
39
|
+
output=args.installer / f"cli-{args.commit}",
|
40
|
+
target_platform=args.target_platform,
|
41
|
+
)
|
42
|
+
extensions_config = Path(args.extensions_config).expanduser()
|
43
|
+
download_vscode_extensions(
|
44
|
+
extensions_config, args.target_platform, args.installer / "extensions"
|
45
|
+
)
|
46
|
+
|
47
|
+
|
48
|
+
def cmd_install_server(args: Namespace) -> None:
|
49
|
+
host_platform = get_host_platform()
|
50
|
+
if args.commit is None:
|
51
|
+
try:
|
52
|
+
args.commit = get_vscode_commit_from_installer(
|
53
|
+
args.installer, host_platform
|
54
|
+
)
|
55
|
+
except Exception as e:
|
56
|
+
raise ValueError(
|
57
|
+
f"{e}, please specify `--commit` when installing."
|
58
|
+
) from None
|
59
|
+
|
60
|
+
install_vscode_server(
|
61
|
+
args.commit,
|
62
|
+
cli_installer=args.installer / f"cli-{args.commit}",
|
63
|
+
vscode_cli_bin=get_vscode_cli_bin(args.commit),
|
64
|
+
platform=host_platform,
|
65
|
+
)
|
66
|
+
vscode_server_home = get_vscode_server_home(args.commit)
|
67
|
+
install_vscode_extensions(
|
68
|
+
Path(vscode_server_home) / "bin/code-server",
|
69
|
+
vsix_dir=args.installer / "extensions",
|
70
|
+
platform=host_platform,
|
71
|
+
exclude=SERVER_EXCLUDE_EXTENSIONS,
|
72
|
+
)
|
73
|
+
|
74
|
+
|
75
|
+
def cmd_download_extensions(args: Namespace) -> None:
|
76
|
+
extensions_config = Path(args.extensions_config).expanduser()
|
77
|
+
download_vscode_extensions(
|
78
|
+
extensions_config, args.target_platform, args.installer / "extensions"
|
79
|
+
)
|
80
|
+
|
81
|
+
|
82
|
+
def cmd_install_extensions(args: Namespace) -> None:
|
83
|
+
host_platform = get_host_platform()
|
84
|
+
install_vscode_extensions(
|
85
|
+
os.fspath("code"),
|
86
|
+
vsix_dir=args.installer / "extensions",
|
87
|
+
platform=host_platform,
|
88
|
+
)
|
89
|
+
|
90
|
+
|
91
|
+
def make_argparser() -> ArgumentParser:
|
92
|
+
parent_parser = ArgumentParser(add_help=False)
|
93
|
+
|
94
|
+
parent_parser.add_argument(
|
95
|
+
"--installer",
|
96
|
+
type=Path,
|
97
|
+
default="./vscode-offline-installer",
|
98
|
+
help="The output directory for downloaded files. Also used as the installer directory.",
|
99
|
+
)
|
100
|
+
|
101
|
+
parser = ArgumentParser()
|
102
|
+
subparsers = parser.add_subparsers(required=True)
|
103
|
+
|
104
|
+
download_server_parser = subparsers.add_parser(
|
105
|
+
"download-server",
|
106
|
+
help="Download VS Code Server and extensions",
|
107
|
+
parents=[parent_parser],
|
108
|
+
)
|
109
|
+
download_server_parser.set_defaults(func=cmd_download_server)
|
110
|
+
download_server_parser.add_argument(
|
111
|
+
"--commit",
|
112
|
+
type=str,
|
113
|
+
help="The commit hash of the VS Code Server to download, must match the version of the VSCode client.",
|
114
|
+
)
|
115
|
+
download_server_parser.add_argument(
|
116
|
+
"--target-platform",
|
117
|
+
type=str,
|
118
|
+
required=True,
|
119
|
+
help="The target platform of the VS Code Server to download.",
|
120
|
+
)
|
121
|
+
download_server_parser.add_argument(
|
122
|
+
"--extensions-config",
|
123
|
+
type=Path,
|
124
|
+
default=get_vscode_extensions_config(),
|
125
|
+
help="Path to the extensions configuration file. Will search for extensions to download.",
|
126
|
+
)
|
127
|
+
|
128
|
+
install_server_parser = subparsers.add_parser(
|
129
|
+
"install-server",
|
130
|
+
help="Install VS Code Server and extensions",
|
131
|
+
parents=[parent_parser],
|
132
|
+
)
|
133
|
+
install_server_parser.set_defaults(func=cmd_install_server)
|
134
|
+
install_server_parser.add_argument(
|
135
|
+
"--commit",
|
136
|
+
type=str,
|
137
|
+
help="The commit hash of the VS Code Server to install.",
|
138
|
+
)
|
139
|
+
|
140
|
+
download_extensions_parser = subparsers.add_parser(
|
141
|
+
"download-extensions",
|
142
|
+
help="Download VS Code Server and extensions",
|
143
|
+
parents=[parent_parser],
|
144
|
+
)
|
145
|
+
download_extensions_parser.set_defaults(func=cmd_download_extensions)
|
146
|
+
download_extensions_parser.add_argument(
|
147
|
+
"--target-platform",
|
148
|
+
type=str,
|
149
|
+
required=True,
|
150
|
+
help="The target platform of the VSCode extensions to download.",
|
151
|
+
)
|
152
|
+
download_extensions_parser.add_argument(
|
153
|
+
"--extensions-config",
|
154
|
+
type=Path,
|
155
|
+
default=get_vscode_extensions_config(),
|
156
|
+
help="Path to the extensions configuration file. Will search for extensions to download.",
|
157
|
+
)
|
158
|
+
|
159
|
+
install_extensions_parser = subparsers.add_parser(
|
160
|
+
"install-extensions",
|
161
|
+
help="Install VSCode extensions",
|
162
|
+
parents=[parent_parser],
|
163
|
+
)
|
164
|
+
install_extensions_parser.set_defaults(func=cmd_install_extensions)
|
165
|
+
download_extensions_parser.add_argument(
|
166
|
+
"--code",
|
167
|
+
type=str,
|
168
|
+
default="code",
|
169
|
+
help="Path to the `code` binary.",
|
170
|
+
)
|
171
|
+
|
172
|
+
return parser
|
173
|
+
|
174
|
+
|
175
|
+
def main() -> None:
|
176
|
+
logging.basicConfig(level=logging.INFO)
|
177
|
+
parser = make_argparser()
|
178
|
+
args = parser.parse_args()
|
179
|
+
args.func(args)
|
180
|
+
|
181
|
+
|
182
|
+
if __name__ == "__main__":
|
183
|
+
main()
|
@@ -7,13 +7,14 @@ from urllib.error import HTTPError
|
|
7
7
|
from urllib.request import urlopen
|
8
8
|
|
9
9
|
from vscode_offline.loggers import logger
|
10
|
+
from vscode_offline.utils import get_cli_os_arch
|
10
11
|
|
11
12
|
|
12
13
|
def _download_file(url: str, filename: str) -> None:
|
13
14
|
with urlopen(url) as resp:
|
14
15
|
content_encoding = resp.headers.get("Content-Encoding")
|
15
16
|
if content_encoding in {"gzip", "deflate"}:
|
16
|
-
logger.info(f"Content
|
17
|
+
logger.info(f"Content-Encoding is {content_encoding}, using GzipFile")
|
17
18
|
reader = GzipFile(fileobj=resp)
|
18
19
|
elif not content_encoding:
|
19
20
|
reader = resp
|
@@ -32,7 +33,11 @@ def download_file(
|
|
32
33
|
url: str,
|
33
34
|
filename: str,
|
34
35
|
) -> None:
|
35
|
-
|
36
|
+
if os.path.exists(filename):
|
37
|
+
logger.info(f"File {filename} already exists, skipping download.")
|
38
|
+
return
|
39
|
+
|
40
|
+
logger.info(f"Downloading {url}")
|
36
41
|
tmp_filename = f"{filename}.tmp"
|
37
42
|
|
38
43
|
for i in range(3):
|
@@ -86,21 +91,27 @@ def download_vscode_extensions(
|
|
86
91
|
if e.code != 404:
|
87
92
|
raise
|
88
93
|
download_extension(publisher, name, version, output=output)
|
89
|
-
logger.info("============================================")
|
90
94
|
|
91
95
|
|
92
96
|
def download_vscode_server(
|
93
|
-
commit: str,
|
97
|
+
commit: str,
|
98
|
+
output: str,
|
99
|
+
target_platform: str,
|
94
100
|
) -> None:
|
101
|
+
"""Download VS Code Server and CLI for the given commit and target platform.
|
102
|
+
|
103
|
+
See Also:
|
104
|
+
https://www.cnblogs.com/michaelcjl/p/18262833
|
105
|
+
https://blog.csdn.net/qq_69668825/article/details/144224417
|
106
|
+
"""
|
95
107
|
os.makedirs(output, exist_ok=True)
|
96
108
|
download_file(
|
97
|
-
f"https://
|
98
|
-
f"{output}/vscode-server-
|
109
|
+
f"https://update.code.visualstudio.com/commit:{commit}/server-{target_platform}/stable",
|
110
|
+
f"{output}/vscode-server-{target_platform}.tar.gz",
|
99
111
|
)
|
100
|
-
|
101
|
-
|
112
|
+
target_os_arch = get_cli_os_arch(target_platform)
|
113
|
+
target_os_arch_ = target_os_arch.replace("-", "_")
|
102
114
|
download_file(
|
103
|
-
f"https://
|
104
|
-
f"{output}/
|
115
|
+
f"https://update.code.visualstudio.com/commit:{commit}/cli-{target_os_arch}/stable",
|
116
|
+
f"{output}/vscode_cli_{target_os_arch_}_cli.tar.gz",
|
105
117
|
)
|
106
|
-
logger.info("============================================")
|
@@ -0,0 +1,99 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import os
|
4
|
+
import subprocess
|
5
|
+
from collections.abc import Set as AbstractSet
|
6
|
+
from pathlib import Path
|
7
|
+
from tempfile import TemporaryDirectory
|
8
|
+
|
9
|
+
from vscode_offline.loggers import logger
|
10
|
+
from vscode_offline.utils import get_cli_os_arch, get_vscode_server_home
|
11
|
+
|
12
|
+
# These extensions are excluded because they are not needed in a VS Code Server.
|
13
|
+
SERVER_EXCLUDE_EXTENSIONS = frozenset(
|
14
|
+
[
|
15
|
+
"ms-vscode-remote.remote-ssh",
|
16
|
+
"ms-vscode-remote.remote-ssh-edit",
|
17
|
+
"ms-vscode-remote.remote-wsl",
|
18
|
+
"ms-vscode-remote.remote-containers",
|
19
|
+
"ms-vscode.remote-explorer",
|
20
|
+
"ms-vscode-remote.vscode-remote-extensionpack",
|
21
|
+
"ms-vscode.remote-server",
|
22
|
+
]
|
23
|
+
)
|
24
|
+
|
25
|
+
|
26
|
+
def get_extension_identifier(filename: str) -> str:
|
27
|
+
filename = os.path.splitext(filename)[0]
|
28
|
+
identifier_version = filename.rsplit("@", maxsplit=1)[0]
|
29
|
+
extension_identifier = identifier_version.rsplit("-", maxsplit=1)[0]
|
30
|
+
return extension_identifier
|
31
|
+
|
32
|
+
|
33
|
+
def get_extension_target_platform(filename: str) -> str | None:
|
34
|
+
filename = os.path.splitext(filename)[0]
|
35
|
+
parts = filename.rsplit("@", maxsplit=1)
|
36
|
+
if len(parts) != 2:
|
37
|
+
return None
|
38
|
+
return parts[1]
|
39
|
+
|
40
|
+
|
41
|
+
def install_vscode_extensions(
|
42
|
+
vscode_bin: str | os.PathLike[str],
|
43
|
+
vsix_dir: str,
|
44
|
+
platform: str,
|
45
|
+
exclude: AbstractSet[str] = frozenset(),
|
46
|
+
) -> None:
|
47
|
+
for vsix_file in Path(vsix_dir).glob("*.vsix"):
|
48
|
+
extension_identifier = get_extension_identifier(vsix_file.name)
|
49
|
+
if extension_identifier in exclude:
|
50
|
+
logger.info(f"Skipping excluded extension {extension_identifier}")
|
51
|
+
continue
|
52
|
+
# Skip extensions that are not for the current platform
|
53
|
+
extension_target_platform = get_extension_target_platform(vsix_file.name)
|
54
|
+
if (
|
55
|
+
extension_target_platform is not None
|
56
|
+
and extension_target_platform != platform
|
57
|
+
):
|
58
|
+
logger.info(
|
59
|
+
f"Skipping extension {extension_identifier} for platform {extension_target_platform}"
|
60
|
+
)
|
61
|
+
continue
|
62
|
+
logger.info(f"Installing {vsix_file}")
|
63
|
+
subprocess.check_call([vscode_bin, "--install-extension", vsix_file, "--force"])
|
64
|
+
logger.info(f"Installed {vsix_file}")
|
65
|
+
|
66
|
+
|
67
|
+
def install_vscode_server(
|
68
|
+
commit: str,
|
69
|
+
cli_installer: str,
|
70
|
+
vscode_cli_bin: os.PathLike[str],
|
71
|
+
platform: str,
|
72
|
+
) -> None:
|
73
|
+
cli_os = get_cli_os_arch(platform)
|
74
|
+
cli_os_ = cli_os.replace("-", "_")
|
75
|
+
|
76
|
+
vscode_cli_tarball = Path(cli_installer) / f"vscode_cli_{cli_os_}_cli.tar.gz"
|
77
|
+
with TemporaryDirectory() as tmpdir:
|
78
|
+
subprocess.check_call(["tar", "-xzf", vscode_cli_tarball, "-C", tmpdir])
|
79
|
+
tmpfile = Path(tmpdir) / "code"
|
80
|
+
if os.path.exists(vscode_cli_bin):
|
81
|
+
os.remove(vscode_cli_bin)
|
82
|
+
os.makedirs(os.path.dirname(vscode_cli_bin), exist_ok=True)
|
83
|
+
os.rename(tmpfile, vscode_cli_bin)
|
84
|
+
logger.info(f"Extracted vscode_cli_{cli_os_}_cli.tar.gz to {vscode_cli_bin}")
|
85
|
+
|
86
|
+
vscode_server_tarball = Path(cli_installer) / f"vscode-server-{platform}.tar.gz"
|
87
|
+
vscode_server_home = get_vscode_server_home(commit)
|
88
|
+
os.makedirs(vscode_server_home, exist_ok=True)
|
89
|
+
subprocess.check_call(
|
90
|
+
[
|
91
|
+
"tar",
|
92
|
+
"-xzf",
|
93
|
+
vscode_server_tarball,
|
94
|
+
"-C",
|
95
|
+
vscode_server_home,
|
96
|
+
"--strip-components=1",
|
97
|
+
]
|
98
|
+
)
|
99
|
+
logger.info(f"Extracted vscode-server-{platform}.tar.gz to {vscode_server_home}")
|
@@ -0,0 +1,92 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import os
|
4
|
+
import subprocess
|
5
|
+
from pathlib import Path
|
6
|
+
|
7
|
+
from vscode_offline.loggers import logger
|
8
|
+
|
9
|
+
_vscode_data = Path("~/.vscode").expanduser()
|
10
|
+
_vscode_server_data = Path("~/.vscode-server").expanduser()
|
11
|
+
|
12
|
+
|
13
|
+
def get_vscode_cli_bin(commit: str) -> os.PathLike[str]:
|
14
|
+
return _vscode_server_data / f"code-{commit}"
|
15
|
+
|
16
|
+
|
17
|
+
def get_vscode_server_home(commit: str) -> os.PathLike[str]:
|
18
|
+
return _vscode_server_data / f"cli/servers/Stable-{commit}/server"
|
19
|
+
|
20
|
+
|
21
|
+
def get_vscode_extensions_config() -> os.PathLike[str]:
|
22
|
+
p = _vscode_data / "extensions/extensions.json"
|
23
|
+
if p.exists():
|
24
|
+
return p
|
25
|
+
s = _vscode_server_data / "extensions/extensions.json"
|
26
|
+
if s.exists():
|
27
|
+
return s
|
28
|
+
return p # default to this path
|
29
|
+
|
30
|
+
|
31
|
+
def get_vscode_commit_from_installer(installer: os.PathLike[str], platform: str) -> str:
|
32
|
+
directories = list(Path(installer).glob(f"cli-*/vscode-server-{platform}.tar.gz"))
|
33
|
+
if len(directories) > 1:
|
34
|
+
raise ValueError(
|
35
|
+
f"Multiple matching installers found in {installer} for platform {platform}"
|
36
|
+
)
|
37
|
+
elif len(directories) == 0:
|
38
|
+
raise ValueError(
|
39
|
+
f"No matching installer found in {installer} for platform {platform}"
|
40
|
+
)
|
41
|
+
|
42
|
+
commit = directories[0].parent.name[len("cli-") :]
|
43
|
+
logger.info(f"Getting commit from {platform} installer: {commit}")
|
44
|
+
return commit
|
45
|
+
|
46
|
+
|
47
|
+
def get_vscode_commit_from_code_version() -> str | None:
|
48
|
+
res = subprocess.run(["code", "--version"], stdout=subprocess.PIPE)
|
49
|
+
if res.returncode != 0:
|
50
|
+
return None
|
51
|
+
lines = res.stdout.splitlines()
|
52
|
+
if len(lines) < 2:
|
53
|
+
return None # Unexpected output
|
54
|
+
|
55
|
+
# The commit hash is usually on the second line
|
56
|
+
commit = lines[1].strip().decode("utf-8")
|
57
|
+
logger.info(f"Getting commit from `code --version`: {commit}")
|
58
|
+
|
59
|
+
return lines[1].strip().decode("utf-8")
|
60
|
+
|
61
|
+
|
62
|
+
def get_target_platform_from_installer(cli_installer: str) -> str | None:
|
63
|
+
directories = list(Path(cli_installer).glob("vscode-server-*.tar.gz"))
|
64
|
+
if len(directories) == 1:
|
65
|
+
return directories[0].name[len("vscode-server-") : -len(".tar.gz")]
|
66
|
+
return None
|
67
|
+
|
68
|
+
|
69
|
+
# Mapping from target platform to CLI OS and architecture used in download URLs
|
70
|
+
_cli_os_arch_mapping = {
|
71
|
+
"linux-x64": "alpine-x64",
|
72
|
+
"linux-arm64": "alpine-arm64",
|
73
|
+
}
|
74
|
+
|
75
|
+
|
76
|
+
def get_cli_os_arch(platform: str) -> str:
|
77
|
+
"""Get the CLI OS and architecture for the given target platform."""
|
78
|
+
if platform not in _cli_os_arch_mapping:
|
79
|
+
raise ValueError(f"Unsupported target platform: {platform}")
|
80
|
+
return _cli_os_arch_mapping[platform]
|
81
|
+
|
82
|
+
|
83
|
+
def get_host_platform() -> str:
|
84
|
+
"""Get the host platform in the format used by VS Code Server install."""
|
85
|
+
(osname, _, _, _, machine) = os.uname()
|
86
|
+
|
87
|
+
if osname.lower() == "linux":
|
88
|
+
if machine in ("x86_64", "amd64"):
|
89
|
+
return "linux-x64"
|
90
|
+
elif machine in ("aarch64", "arm64"):
|
91
|
+
return "linux-arm64"
|
92
|
+
raise ValueError(f"Unsupported host platform: {osname}-{machine}")
|
vscode_offline-0.1.0/PKG-INFO
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.3
|
2
|
-
Name: vscode-offline
|
3
|
-
Version: 0.1.0
|
4
|
-
Summary: Download and install vscode server for offline environments
|
5
|
-
Author: Chuck Fan
|
6
|
-
Author-email: Chuck Fan <fanck0605@qq.com>
|
7
|
-
Requires-Python: >=3.9
|
8
|
-
Description-Content-Type: text/markdown
|
9
|
-
|
10
|
-
# vscode-offline
|
11
|
-
|
12
|
-
vscode-offline 主要用于在无网环境下安装 VSCode Server,方便使用 *Remote - SSH* 插件进行远程开发。
|
13
|
-
|
14
|
-
## 安装
|
15
|
-
|
16
|
-
```shell
|
17
|
-
pip install -U vscode-offline
|
18
|
-
```
|
19
|
-
|
20
|
-
## 用法
|
21
|
-
|
22
|
-
(1)在联网环境安装好 VSCode 和你需要的插件。
|
23
|
-
|
24
|
-
(2)联网环境执行如下命令,将会自动下载当前 VSCode 所有的插件
|
25
|
-
|
26
|
-
> `--commit` 为对应 VSCode 的 Commit 号,*帮助* -> *关于* -> *Commit*
|
27
|
-
|
28
|
-
```shell
|
29
|
-
vscode-offline download \
|
30
|
-
--commit 385651c938df8a906869babee516bffd0ddb9829 \
|
31
|
-
--target-platform linux-x64 \
|
32
|
-
--installer ./vscode-offline-installer
|
33
|
-
```
|
34
|
-
|
35
|
-
(3)复制 `vscode-offline-installer` 到内网服务器
|
36
|
-
|
37
|
-
```shell
|
38
|
-
vscode-offline install \
|
39
|
-
--commit 385651c938df8a906869babee516bffd0ddb9829 \
|
40
|
-
--target-platform linux-x64 \
|
41
|
-
--installer ./vscode-offline-installer
|
42
|
-
```
|
43
|
-
|
44
|
-
## 贡献
|
45
|
-
|
46
|
-
欢迎提交 Issue 和 PR 改进本项目。
|
47
|
-
|
48
|
-
## 许可证
|
49
|
-
|
50
|
-
[MIT License](./LICENSE)
|
vscode_offline-0.1.0/README.md
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
# vscode-offline
|
2
|
-
|
3
|
-
vscode-offline 主要用于在无网环境下安装 VSCode Server,方便使用 *Remote - SSH* 插件进行远程开发。
|
4
|
-
|
5
|
-
## 安装
|
6
|
-
|
7
|
-
```shell
|
8
|
-
pip install -U vscode-offline
|
9
|
-
```
|
10
|
-
|
11
|
-
## 用法
|
12
|
-
|
13
|
-
(1)在联网环境安装好 VSCode 和你需要的插件。
|
14
|
-
|
15
|
-
(2)联网环境执行如下命令,将会自动下载当前 VSCode 所有的插件
|
16
|
-
|
17
|
-
> `--commit` 为对应 VSCode 的 Commit 号,*帮助* -> *关于* -> *Commit*
|
18
|
-
|
19
|
-
```shell
|
20
|
-
vscode-offline download \
|
21
|
-
--commit 385651c938df8a906869babee516bffd0ddb9829 \
|
22
|
-
--target-platform linux-x64 \
|
23
|
-
--installer ./vscode-offline-installer
|
24
|
-
```
|
25
|
-
|
26
|
-
(3)复制 `vscode-offline-installer` 到内网服务器
|
27
|
-
|
28
|
-
```shell
|
29
|
-
vscode-offline install \
|
30
|
-
--commit 385651c938df8a906869babee516bffd0ddb9829 \
|
31
|
-
--target-platform linux-x64 \
|
32
|
-
--installer ./vscode-offline-installer
|
33
|
-
```
|
34
|
-
|
35
|
-
## 贡献
|
36
|
-
|
37
|
-
欢迎提交 Issue 和 PR 改进本项目。
|
38
|
-
|
39
|
-
## 许可证
|
40
|
-
|
41
|
-
[MIT License](./LICENSE)
|
@@ -1,28 +0,0 @@
|
|
1
|
-
[project]
|
2
|
-
name = "vscode-offline"
|
3
|
-
version = "0.1.0"
|
4
|
-
description = "Download and install vscode server for offline environments"
|
5
|
-
readme = "README.md"
|
6
|
-
authors = [
|
7
|
-
{ name = "Chuck Fan", email = "fanck0605@qq.com" }
|
8
|
-
]
|
9
|
-
requires-python = ">=3.9"
|
10
|
-
dependencies = []
|
11
|
-
|
12
|
-
[project.scripts]
|
13
|
-
vscode-offline = "vscode_offline:main"
|
14
|
-
|
15
|
-
[build-system]
|
16
|
-
requires = ["uv-build"]
|
17
|
-
build-backend = "uv_build"
|
18
|
-
|
19
|
-
[dependency-groups]
|
20
|
-
dev = [
|
21
|
-
"ruff>=0.13.3",
|
22
|
-
]
|
23
|
-
|
24
|
-
[tool.ruff.lint]
|
25
|
-
select = [
|
26
|
-
"I", # isort
|
27
|
-
"F", # Pyflakes
|
28
|
-
]
|
@@ -1,104 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import logging
|
4
|
-
from argparse import ArgumentParser, Namespace
|
5
|
-
from pathlib import Path
|
6
|
-
|
7
|
-
from vscode_offline.download import download_vscode_extensions, download_vscode_server
|
8
|
-
from vscode_offline.install import install_vscode_extensions, install_vscode_server
|
9
|
-
from vscode_offline.paths import (
|
10
|
-
get_vscode_cli_bin,
|
11
|
-
get_vscode_extensions_config,
|
12
|
-
get_vscode_server_home,
|
13
|
-
)
|
14
|
-
|
15
|
-
cli_os_mapping = {
|
16
|
-
"linux-x64": "cli-alpine-x64",
|
17
|
-
}
|
18
|
-
|
19
|
-
|
20
|
-
def download(args: Namespace) -> None:
|
21
|
-
download_vscode_server(
|
22
|
-
args.commit,
|
23
|
-
output=args.installer / f"cli-{args.commit}",
|
24
|
-
target_platform=args.target_platform,
|
25
|
-
cli_os=cli_os_mapping[args.target_platform],
|
26
|
-
)
|
27
|
-
extensions_config = Path(args.extensions_config).expanduser()
|
28
|
-
download_vscode_extensions(
|
29
|
-
extensions_config, args.target_platform, args.installer / "extensions"
|
30
|
-
)
|
31
|
-
|
32
|
-
|
33
|
-
def install(args: Namespace) -> None:
|
34
|
-
install_vscode_server(
|
35
|
-
args.commit,
|
36
|
-
installer=args.installer / f"cli-{args.commit}",
|
37
|
-
vscode_cli_bin=get_vscode_cli_bin(args.commit),
|
38
|
-
target_platform=args.target_platform,
|
39
|
-
cli_os=cli_os_mapping[args.target_platform],
|
40
|
-
)
|
41
|
-
vscode_server_home = get_vscode_server_home(args.commit)
|
42
|
-
install_vscode_extensions(
|
43
|
-
Path(vscode_server_home) / "bin/code-server",
|
44
|
-
vsix_dir=args.installer / "extensions",
|
45
|
-
)
|
46
|
-
|
47
|
-
|
48
|
-
def make_argparser() -> ArgumentParser:
|
49
|
-
parent_parser = ArgumentParser(add_help=False)
|
50
|
-
|
51
|
-
parent_parser.add_argument(
|
52
|
-
"--commit",
|
53
|
-
type=str,
|
54
|
-
required=True,
|
55
|
-
help="The commit hash of the VSCode server to download, must match the version of the VSCode client.",
|
56
|
-
)
|
57
|
-
parent_parser.add_argument(
|
58
|
-
"--target-platform",
|
59
|
-
type=str,
|
60
|
-
default="linux-x64",
|
61
|
-
help="The target platform for the VSCode server.",
|
62
|
-
)
|
63
|
-
parent_parser.add_argument(
|
64
|
-
"--installer",
|
65
|
-
type=Path,
|
66
|
-
default="./vscode-offline-installer",
|
67
|
-
help="The output directory for downloaded files. Also used as the installer directory.",
|
68
|
-
)
|
69
|
-
|
70
|
-
parser = ArgumentParser()
|
71
|
-
subparsers = parser.add_subparsers(required=True)
|
72
|
-
|
73
|
-
download_parser = subparsers.add_parser(
|
74
|
-
"download",
|
75
|
-
help="Download VSCode server and extensions",
|
76
|
-
parents=[parent_parser],
|
77
|
-
)
|
78
|
-
download_parser.set_defaults(func=download)
|
79
|
-
download_parser.add_argument(
|
80
|
-
"--extensions-config",
|
81
|
-
type=Path,
|
82
|
-
default=get_vscode_extensions_config(),
|
83
|
-
help="Path to the extensions configuration file. Will search for extensions to download.",
|
84
|
-
)
|
85
|
-
|
86
|
-
install_parsers = subparsers.add_parser(
|
87
|
-
"install",
|
88
|
-
help="Install VSCode server and extensions",
|
89
|
-
parents=[parent_parser],
|
90
|
-
)
|
91
|
-
install_parsers.set_defaults(func=install)
|
92
|
-
|
93
|
-
return parser
|
94
|
-
|
95
|
-
|
96
|
-
def main() -> None:
|
97
|
-
logging.basicConfig(level=logging.INFO)
|
98
|
-
parser = make_argparser()
|
99
|
-
args = parser.parse_args()
|
100
|
-
args.func(args)
|
101
|
-
|
102
|
-
|
103
|
-
if __name__ == "__main__":
|
104
|
-
main()
|
@@ -1,74 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import os
|
4
|
-
import subprocess
|
5
|
-
from pathlib import Path
|
6
|
-
from tempfile import TemporaryDirectory
|
7
|
-
|
8
|
-
from vscode_offline.loggers import logger
|
9
|
-
from vscode_offline.paths import get_vscode_server_home
|
10
|
-
|
11
|
-
EXCLUDE_EXTENSIONS = {
|
12
|
-
"ms-vscode-remote.remote-ssh",
|
13
|
-
"ms-vscode-remote.remote-ssh-edit",
|
14
|
-
"ms-vscode-remote.remote-wsl",
|
15
|
-
"ms-vscode-remote.remote-containers",
|
16
|
-
"ms-vscode.remote-explorer",
|
17
|
-
"ms-vscode-remote.vscode-remote-extensionpack",
|
18
|
-
"ms-vscode.remote-server",
|
19
|
-
}
|
20
|
-
|
21
|
-
|
22
|
-
def get_extension_identifier(filename: str) -> str:
|
23
|
-
filename = os.path.splitext(filename)[0]
|
24
|
-
identifier_version = filename.rsplit("@", maxsplit=1)[0]
|
25
|
-
extension_identifier = identifier_version.rsplit("-", maxsplit=1)[0]
|
26
|
-
return extension_identifier
|
27
|
-
|
28
|
-
|
29
|
-
def install_vscode_extensions(vscode_bin: os.PathLike[str], vsix_dir: str) -> None:
|
30
|
-
for vsix_file in Path(vsix_dir).glob("*.vsix"):
|
31
|
-
extension_identifier = get_extension_identifier(vsix_file.name)
|
32
|
-
if extension_identifier in EXCLUDE_EXTENSIONS:
|
33
|
-
logger.info(f"Skipping excluded extension {extension_identifier}")
|
34
|
-
continue
|
35
|
-
logger.info(f"Installing {vsix_file}")
|
36
|
-
subprocess.check_call([vscode_bin, "--install-extension", vsix_file, "--force"])
|
37
|
-
logger.info(f"Installed {vsix_file}")
|
38
|
-
|
39
|
-
|
40
|
-
def install_vscode_server(
|
41
|
-
commit: str,
|
42
|
-
installer: str,
|
43
|
-
vscode_cli_bin: os.PathLike[str],
|
44
|
-
target_platform: str,
|
45
|
-
cli_os: str,
|
46
|
-
) -> None:
|
47
|
-
cli_os_ = cli_os.replace("-", "_")
|
48
|
-
|
49
|
-
vscode_cli_tarball = Path(installer) / f"vscode_{cli_os_}_cli.tar.gz"
|
50
|
-
with TemporaryDirectory() as tmpdir:
|
51
|
-
subprocess.check_call(["tar", "-xzf", vscode_cli_tarball, "-C", tmpdir])
|
52
|
-
tmpfile = Path(tmpdir) / "code"
|
53
|
-
if os.path.exists(vscode_cli_bin):
|
54
|
-
os.remove(vscode_cli_bin)
|
55
|
-
os.makedirs(os.path.dirname(vscode_cli_bin), exist_ok=True)
|
56
|
-
os.rename(tmpfile, vscode_cli_bin)
|
57
|
-
logger.info(f"Extracted vscode_{cli_os_}_cli.tar.gz to {vscode_cli_bin}")
|
58
|
-
|
59
|
-
vscode_server_tarball = Path(installer) / f"vscode-server-{target_platform}.tar.gz"
|
60
|
-
vscode_server_home = get_vscode_server_home(commit)
|
61
|
-
os.makedirs(vscode_server_home, exist_ok=True)
|
62
|
-
subprocess.check_call(
|
63
|
-
[
|
64
|
-
"tar",
|
65
|
-
"-xzf",
|
66
|
-
vscode_server_tarball,
|
67
|
-
"-C",
|
68
|
-
vscode_server_home,
|
69
|
-
"--strip-components=1",
|
70
|
-
]
|
71
|
-
)
|
72
|
-
logger.info(
|
73
|
-
f"Extracted vscode-server-{target_platform}.tar.gz to {vscode_server_home}"
|
74
|
-
)
|
@@ -1,25 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import os
|
4
|
-
from pathlib import Path
|
5
|
-
|
6
|
-
VSCODE_DATA = Path("~/.vscode").expanduser()
|
7
|
-
VSCODE_SERVER_DATA = Path("~/.vscode-server").expanduser()
|
8
|
-
|
9
|
-
|
10
|
-
def get_vscode_cli_bin(commit: str) -> os.PathLike[str]:
|
11
|
-
return VSCODE_SERVER_DATA / f"code-{commit}"
|
12
|
-
|
13
|
-
|
14
|
-
def get_vscode_server_home(commit: str) -> os.PathLike[str]:
|
15
|
-
return VSCODE_SERVER_DATA / f"cli/servers/Stable-{commit}/server"
|
16
|
-
|
17
|
-
|
18
|
-
def get_vscode_extensions_config() -> os.PathLike[str]:
|
19
|
-
p = VSCODE_DATA / "extensions/extensions.json"
|
20
|
-
if p.exists():
|
21
|
-
return p
|
22
|
-
s = VSCODE_SERVER_DATA / "extensions/extensions.json"
|
23
|
-
if s.exists():
|
24
|
-
return s
|
25
|
-
return p # default to this path
|
File without changes
|
File without changes
|