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.
@@ -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 encoding is {content_encoding}, using GzipFile")
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
- logger.info(f"Downloading {filename}")
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, output: str, target_platform: str, cli_os: 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://vscode.download.prss.microsoft.com/dbazure/download/stable/{commit}/vscode-server-linux-x64.tar.gz",
98
- f"{output}/vscode-server-linux-x64.tar.gz",
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
- logger.info("============================================")
101
- cli_os_ = cli_os.replace("-", "_")
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://vscode.download.prss.microsoft.com/dbazure/download/stable/{commit}/vscode_{cli_os_}_cli.tar.gz",
104
- f"{output}/vscode_{cli_os_}_cli.tar.gz",
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}")
@@ -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)
@@ -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