vscode-offline 0.1.3__py3-none-any.whl → 0.1.5__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.
vscode_offline/app.py CHANGED
@@ -1,11 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- import os
5
4
  from argparse import ArgumentParser, Namespace
6
5
  from pathlib import Path
7
6
 
8
7
  from vscode_offline.download import (
8
+ download_vscode_client,
9
9
  download_vscode_extensions,
10
10
  download_vscode_server,
11
11
  )
@@ -14,56 +14,51 @@ from vscode_offline.install import (
14
14
  install_vscode_extensions,
15
15
  install_vscode_server,
16
16
  )
17
- from vscode_offline.loggers import logger
18
17
  from vscode_offline.utils import (
18
+ get_default_code_version,
19
19
  get_host_platform,
20
- get_vscode_cli_bin,
21
- get_vscode_commit_from_code_version,
22
- get_vscode_commit_from_server_installer,
23
20
  get_vscode_extensions_config,
24
- get_vscode_server_home,
21
+ get_vscode_version_from_server_installer,
25
22
  )
26
23
 
27
24
 
28
25
  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."
26
+ if args.code_version is None:
27
+ args.code_version = get_default_code_version()
28
+ if args.code_version is None:
29
+ raise ValueError(
30
+ "Cannot determine version from `code --version`, please specify `--version` when downloading."
34
31
  )
35
- raise ValueError("Please specify --commit when installing.")
36
32
 
37
33
  download_vscode_server(
38
- args.commit,
39
- output=args.installer / f"server-{args.commit}",
40
- target_platform=args.target_platform,
34
+ args.code_version,
35
+ output=args.installer / f"server-{args.code_version.replace(':', '-')}",
36
+ platform=args.platform,
41
37
  )
42
38
  extensions_config = Path(args.extensions_config).expanduser()
43
39
  download_vscode_extensions(
44
- extensions_config, args.target_platform, args.installer / "extensions"
40
+ extensions_config,
41
+ target_platforms=[args.platform],
42
+ output=args.installer / "extensions",
45
43
  )
46
44
 
47
45
 
48
46
  def cmd_install_server(args: Namespace) -> None:
49
47
  host_platform = get_host_platform()
50
- if args.commit is None:
48
+ if args.code_version is None:
51
49
  try:
52
- args.commit = get_vscode_commit_from_server_installer(
50
+ args.code_version = get_vscode_version_from_server_installer(
53
51
  args.installer, host_platform
54
52
  )
55
53
  except Exception as e:
56
54
  raise ValueError(
57
- f"{e}, please specify `--commit` when installing."
55
+ f"{e}, please specify `--version` when installing."
58
56
  ) from None
59
57
 
60
- install_vscode_server(
61
- args.commit,
62
- cli_installer=args.installer / f"server-{args.commit}",
63
- vscode_cli_bin=get_vscode_cli_bin(args.commit),
58
+ vscode_server_home = install_vscode_server(
59
+ server_installer=args.installer / f"server-{args.code_version}",
64
60
  platform=host_platform,
65
61
  )
66
- vscode_server_home = get_vscode_server_home(args.commit)
67
62
  install_vscode_extensions(
68
63
  Path(vscode_server_home) / "bin/code-server",
69
64
  vsix_dir=args.installer / "extensions",
@@ -75,19 +70,68 @@ def cmd_install_server(args: Namespace) -> None:
75
70
  def cmd_download_extensions(args: Namespace) -> None:
76
71
  extensions_config = Path(args.extensions_config).expanduser()
77
72
  download_vscode_extensions(
78
- extensions_config, args.target_platform, args.installer / "extensions"
73
+ extensions_config,
74
+ target_platforms=[args.platform],
75
+ output=args.installer / "extensions",
79
76
  )
80
77
 
81
78
 
82
79
  def cmd_install_extensions(args: Namespace) -> None:
83
80
  host_platform = get_host_platform()
84
81
  install_vscode_extensions(
85
- os.fspath("code"),
82
+ args.code,
86
83
  vsix_dir=args.installer / "extensions",
87
84
  platform=host_platform,
88
85
  )
89
86
 
90
87
 
88
+ def cmd_download_client(args: Namespace) -> None:
89
+ if args.code_version is None:
90
+ args.code_version = get_default_code_version()
91
+ if args.code_version is None:
92
+ raise ValueError(
93
+ "Cannot determine version from `code --version`, please specify `--version` manually."
94
+ )
95
+
96
+ download_vscode_client(
97
+ args.code_version,
98
+ output=args.installer / f"client-{args.code_version.replace(':', '-')}",
99
+ platform=args.platform,
100
+ )
101
+ extensions_config = Path(args.extensions_config).expanduser()
102
+ download_vscode_extensions(
103
+ extensions_config,
104
+ target_platforms=[args.platform],
105
+ output=args.installer / "extensions",
106
+ )
107
+
108
+
109
+ def cmd_download_all(args: Namespace) -> None:
110
+ if args.code_version is None:
111
+ args.code_version = get_default_code_version()
112
+ if args.code_version is None:
113
+ raise ValueError(
114
+ "Cannot determine version from `code --version`, please specify `--version` manually."
115
+ )
116
+
117
+ download_vscode_server(
118
+ args.code_version,
119
+ output=args.installer / f"server-{args.code_version.replace(':', '-')}",
120
+ platform=args.server_platform,
121
+ )
122
+ download_vscode_client(
123
+ args.code_version,
124
+ output=args.installer / f"client-{args.code_version.replace(':', '-')}",
125
+ platform=args.client_platform,
126
+ )
127
+ extensions_config = Path(args.extensions_config).expanduser()
128
+ download_vscode_extensions(
129
+ extensions_config,
130
+ target_platforms=[args.server_platform, args.client_platform],
131
+ output=args.installer / "extensions",
132
+ )
133
+
134
+
91
135
  def make_argparser() -> ArgumentParser:
92
136
  parent_parser = ArgumentParser(add_help=False)
93
137
 
@@ -108,12 +152,12 @@ def make_argparser() -> ArgumentParser:
108
152
  )
109
153
  download_server_parser.set_defaults(func=cmd_download_server)
110
154
  download_server_parser.add_argument(
111
- "--commit",
155
+ "--code-version",
112
156
  type=str,
113
- help="The commit hash of the VS Code Server to download, must match the version of the VSCode client.",
157
+ help="The version of the VS Code Server to download, must match the version of the VS Code Client.",
114
158
  )
115
159
  download_server_parser.add_argument(
116
- "--target-platform",
160
+ "--platform",
117
161
  type=str,
118
162
  required=True,
119
163
  help="The target platform of the VS Code Server to download.",
@@ -132,9 +176,9 @@ def make_argparser() -> ArgumentParser:
132
176
  )
133
177
  install_server_parser.set_defaults(func=cmd_install_server)
134
178
  install_server_parser.add_argument(
135
- "--commit",
179
+ "--code-version",
136
180
  type=str,
137
- help="The commit hash of the VS Code Server to install.",
181
+ help="The version of the VS Code Server to install.",
138
182
  )
139
183
 
140
184
  download_extensions_parser = subparsers.add_parser(
@@ -144,10 +188,10 @@ def make_argparser() -> ArgumentParser:
144
188
  )
145
189
  download_extensions_parser.set_defaults(func=cmd_download_extensions)
146
190
  download_extensions_parser.add_argument(
147
- "--target-platform",
191
+ "--platform",
148
192
  type=str,
149
193
  required=True,
150
- help="The target platform of the VSCode extensions to download.",
194
+ help="The target platform of the VS Code extensions to download.",
151
195
  )
152
196
  download_extensions_parser.add_argument(
153
197
  "--extensions-config",
@@ -158,17 +202,71 @@ def make_argparser() -> ArgumentParser:
158
202
 
159
203
  install_extensions_parser = subparsers.add_parser(
160
204
  "install-extensions",
161
- help="Install VSCode extensions",
205
+ help="Install VS Code extensions",
162
206
  parents=[parent_parser],
163
207
  )
164
208
  install_extensions_parser.set_defaults(func=cmd_install_extensions)
165
- download_extensions_parser.add_argument(
209
+ install_extensions_parser.add_argument(
166
210
  "--code",
167
211
  type=str,
168
212
  default="code",
169
213
  help="Path to the `code` binary.",
170
214
  )
171
215
 
216
+ download_client_parser = subparsers.add_parser(
217
+ "download-client",
218
+ help="Download VS Code and extensions",
219
+ parents=[parent_parser],
220
+ )
221
+ download_client_parser.set_defaults(func=cmd_download_client)
222
+ download_client_parser.add_argument(
223
+ "--code-version",
224
+ type=str,
225
+ help="The version of the VS Code to download, must match the version of the VS Code Client.",
226
+ )
227
+ download_client_parser.add_argument(
228
+ "--platform",
229
+ type=str,
230
+ required=True,
231
+ help="The target platform of the VS Code to download.",
232
+ )
233
+ download_client_parser.add_argument(
234
+ "--extensions-config",
235
+ type=Path,
236
+ default=get_vscode_extensions_config(),
237
+ help="Path to the extensions configuration file. Will search for extensions to download.",
238
+ )
239
+
240
+ download_all_parser = subparsers.add_parser(
241
+ "download-all",
242
+ help="Download VS Code server, client and extensions, all in one command",
243
+ parents=[parent_parser],
244
+ )
245
+ download_all_parser.set_defaults(func=cmd_download_all)
246
+ download_all_parser.add_argument(
247
+ "--code-version",
248
+ type=str,
249
+ help="The version of the VS Code to download, defaults to `code --version` at current environment.",
250
+ )
251
+ download_all_parser.add_argument(
252
+ "--server-platform",
253
+ type=str,
254
+ default="linux-x64",
255
+ help="The target platform of the VS Code Server to download, defaults to linux-x64.",
256
+ )
257
+ download_all_parser.add_argument(
258
+ "--client-platform",
259
+ type=str,
260
+ default="win32-x64",
261
+ help="The target platform of the VS Code to download, defaults to win32-x64.",
262
+ )
263
+ download_all_parser.add_argument(
264
+ "--extensions-config",
265
+ type=Path,
266
+ default=get_vscode_extensions_config(),
267
+ help="Path to the extensions configuration file. Will search for extensions to download.",
268
+ )
269
+
172
270
  return parser
173
271
 
174
272
 
@@ -2,17 +2,22 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import os
5
+ from collections.abc import Sequence
5
6
  from gzip import GzipFile
7
+ from io import DEFAULT_BUFFER_SIZE
8
+ from pathlib import Path
6
9
  from urllib.error import HTTPError
7
10
  from urllib.request import urlopen
8
11
 
9
12
  from vscode_offline.loggers import logger
10
- from vscode_offline.utils import get_cli_os_arch
13
+ from vscode_offline.utils import get_cli_platform, get_filename_from_headers
11
14
 
12
- _CHUCK_SIZE = 4 * 1024 * 1024 # 4MiB
13
15
 
14
-
15
- def _download_file(url: str, filename: str) -> None:
16
+ def _download_file(
17
+ url: str,
18
+ directory: str | os.PathLike[str],
19
+ filename: str | None = None,
20
+ ) -> os.PathLike[str]:
16
21
  with urlopen(url) as resp:
17
22
  content_encoding = resp.headers.get("Content-Encoding")
18
23
  if content_encoding in {"gzip", "deflate"}:
@@ -23,39 +28,56 @@ def _download_file(url: str, filename: str) -> None:
23
28
  else:
24
29
  raise ValueError(f"Unsupported Content-Encoding: {content_encoding}")
25
30
 
26
- with reader, open(filename, "wb") as fp:
31
+ if filename:
32
+ file_path = Path(directory).joinpath(filename)
33
+ else:
34
+ filename = get_filename_from_headers(resp.headers)
35
+ if not filename:
36
+ raise ValueError(
37
+ "Cannot get filename from HTTP headers, please specify argument `filename`."
38
+ )
39
+ logger.info(f"Get filename `{filename}` from HTTP headers.")
40
+ file_path = Path(directory).joinpath(filename)
41
+ if file_path.exists():
42
+ logger.info(f"File {file_path} already exists, skipping download.")
43
+ return file_path
44
+
45
+ tmp_file_path = Path(directory).joinpath(f"{filename}.tmp")
46
+ with reader, tmp_file_path.open("wb") as fp:
27
47
  while True:
28
- chunk = reader.read(_CHUCK_SIZE)
48
+ chunk = reader.read(DEFAULT_BUFFER_SIZE)
29
49
  if not chunk:
30
50
  break
31
51
  fp.write(chunk)
32
52
 
53
+ if os.path.exists(file_path):
54
+ os.remove(file_path)
55
+ os.rename(tmp_file_path, file_path)
56
+
57
+ logger.info(f"Saved to {file_path} .")
58
+ return file_path
59
+
33
60
 
34
61
  def download_file(
35
62
  url: str,
36
- filename: str,
63
+ directory: str | os.PathLike[str],
64
+ filename: str | None = None,
37
65
  ) -> None:
38
- if os.path.exists(filename):
39
- logger.info(f"File {filename} already exists, skipping download.")
40
- return
41
-
42
- logger.info(f"Downloading {url}")
43
- tmp_filename = f"{filename}.tmp"
66
+ if filename:
67
+ file_path = Path(directory).joinpath(filename)
68
+ if file_path.exists():
69
+ logger.info(f"File {file_path} already exists, skipping download.")
70
+ return
44
71
 
72
+ logger.info(f"Downloading {url} ...")
45
73
  for i in range(3):
46
74
  try:
47
- _download_file(url, tmp_filename)
75
+ _download_file(url, directory, filename)
48
76
  break
49
77
  except Exception as e:
50
78
  if isinstance(e, HTTPError) and e.code == 404:
51
79
  raise
52
- logger.info(f"Attempt {i + 1} failed: {e}")
53
-
54
- if os.path.exists(filename):
55
- os.remove(filename)
56
- os.rename(tmp_filename, filename)
57
-
58
- logger.info(f"Saved to {filename}")
80
+ logger.info(f"Attempt {i + 1} times failed: {e}")
59
81
 
60
82
 
61
83
  def download_extension(
@@ -68,15 +90,14 @@ def download_extension(
68
90
  url = f"https://marketplace.visualstudio.com/_apis/public/gallery/publishers/{publisher}/vsextensions/{name}/{version}/vspackage"
69
91
  if platform:
70
92
  url = f"{url}?targetPlatform={platform}"
71
- filename = f"{publisher}.{name}-{version}"
72
- if platform:
73
- filename = f"{filename}@{platform}"
74
- filename = f"{filename}.vsix"
75
- download_file(url, f"{output}/{filename}")
93
+ filename = f"{publisher}.{name}-{version}{f'@{platform}' if platform else ''}.vsix"
94
+ download_file(url, output, filename)
76
95
 
77
96
 
78
97
  def download_vscode_extensions(
79
- extensions_config: os.PathLike[str], target_platform: str, output: str = "."
98
+ extensions_config: os.PathLike[str],
99
+ target_platforms: Sequence[str],
100
+ output: str = ".",
80
101
  ) -> None:
81
102
  logger.info(f"Reading extensions config from {extensions_config}")
82
103
  with open(extensions_config) as fp:
@@ -87,18 +108,42 @@ def download_vscode_extensions(
87
108
  identifier = extension["identifier"]
88
109
  publisher, name = identifier["id"].split(".")
89
110
  version = extension["version"]
90
- try:
91
- download_extension(publisher, name, version, target_platform, output=output)
92
- except HTTPError as e:
93
- if e.code != 404:
111
+
112
+ requires_fallback_download = False
113
+ for target_platform in target_platforms:
114
+ try:
115
+ download_extension(
116
+ publisher, name, version, target_platform, output=output
117
+ )
118
+ except HTTPError as e:
119
+ if e.code == 404:
120
+ requires_fallback_download = True
121
+ continue
94
122
  raise
123
+ if requires_fallback_download:
95
124
  download_extension(publisher, name, version, output=output)
96
125
 
97
126
 
127
+ def _download_vscode(
128
+ version: str,
129
+ output: str,
130
+ platform: str,
131
+ ) -> None:
132
+ """Download VS Code for the given version and target platform."""
133
+
134
+ # filename is like
135
+ # "VS CodeSetup-x64-1.104.3.exe" for windows VS Code,
136
+ # "vscode-server-linux-x64.tar.gz" for linux VS Code Server,
137
+ # "vscode_cli_alpine_x64_cli.tar.gz" for linux VS Code CLI.
138
+ download_file(
139
+ f"https://update.code.visualstudio.com/{version}/{platform}/stable", output
140
+ )
141
+
142
+
98
143
  def download_vscode_server(
99
- commit: str,
144
+ version: str,
100
145
  output: str,
101
- target_platform: str,
146
+ platform: str,
102
147
  ) -> None:
103
148
  """Download VS Code Server and CLI for the given commit and target platform.
104
149
 
@@ -107,13 +152,16 @@ def download_vscode_server(
107
152
  https://blog.csdn.net/qq_69668825/article/details/144224417
108
153
  """
109
154
  os.makedirs(output, exist_ok=True)
110
- download_file(
111
- f"https://update.code.visualstudio.com/commit:{commit}/server-{target_platform}/stable",
112
- f"{output}/vscode-server-{target_platform}.tar.gz",
113
- )
114
- target_os_arch = get_cli_os_arch(target_platform)
115
- target_os_arch_ = target_os_arch.replace("-", "_")
116
- download_file(
117
- f"https://update.code.visualstudio.com/commit:{commit}/cli-{target_os_arch}/stable",
118
- f"{output}/vscode_cli_{target_os_arch_}_cli.tar.gz",
119
- )
155
+ _download_vscode(version, output, f"server-{platform}")
156
+ cli_platform = get_cli_platform(platform)
157
+ _download_vscode(version, output, f"cli-{cli_platform}")
158
+
159
+
160
+ def download_vscode_client(
161
+ version: str,
162
+ output: str,
163
+ platform: str,
164
+ ) -> None:
165
+ """Download VS Code Client for the given version and target platform."""
166
+ os.makedirs(output, exist_ok=True)
167
+ _download_vscode(version, output, platform)
vscode_offline/install.py CHANGED
@@ -1,13 +1,18 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import os
4
+ import re
4
5
  import subprocess
5
6
  from collections.abc import Set as AbstractSet
6
7
  from pathlib import Path
7
8
  from tempfile import TemporaryDirectory
8
9
 
9
10
  from vscode_offline.loggers import logger
10
- from vscode_offline.utils import get_cli_os_arch, get_vscode_server_home
11
+ from vscode_offline.utils import (
12
+ get_cli_platform,
13
+ get_vscode_cli_bin,
14
+ get_vscode_server_home,
15
+ )
11
16
 
12
17
  # These extensions are excluded because they are not needed in a VS Code Server.
13
18
  SERVER_EXCLUDE_EXTENSIONS = frozenset(
@@ -64,26 +69,40 @@ def install_vscode_extensions(
64
69
  logger.info(f"Installed {vsix_file}")
65
70
 
66
71
 
72
+ _code_version_output_pattern = re.compile(rb"\(commit ([0-9a-f]{40,})\)")
73
+
74
+
75
+ def _extract_commit_from_code_version_output(code_version_output: bytes) -> str:
76
+ m = _code_version_output_pattern.search(code_version_output)
77
+ if not m:
78
+ raise ValueError("Cannot determine commit hash from code version")
79
+ return m.group(1).decode("utf-8")
80
+
81
+
67
82
  def install_vscode_server(
68
- commit: str,
69
- cli_installer: str,
70
- vscode_cli_bin: os.PathLike[str],
83
+ server_installer: str,
71
84
  platform: str,
72
- ) -> None:
73
- cli_os = get_cli_os_arch(platform)
74
- cli_os_ = cli_os.replace("-", "_")
85
+ ) -> os.PathLike[str]:
86
+ cli_platform = get_cli_platform(platform)
87
+ cli_platform_ = cli_platform.replace("-", "_")
75
88
 
76
- vscode_cli_tarball = Path(cli_installer) / f"vscode_cli_{cli_os_}_cli.tar.gz"
89
+ code_cli_tarball = Path(server_installer) / f"vscode_cli_{cli_platform_}_cli.tar.gz"
77
90
  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"
91
+ subprocess.check_call(["tar", "-xzf", code_cli_tarball, "-C", tmpdir])
92
+ tmp_code_cli = Path(tmpdir) / "code"
93
+ version_output = subprocess.check_output(
94
+ ["code", "--version"], executable=tmp_code_cli, cwd=tmpdir
95
+ )
96
+ commit = _extract_commit_from_code_version_output(version_output)
97
+ logger.info(f"Extracted commit from `code --version`: {commit}")
98
+ code_cli = get_vscode_cli_bin(commit)
99
+ if os.path.exists(code_cli):
100
+ os.remove(code_cli)
101
+ os.makedirs(os.path.dirname(code_cli), exist_ok=True)
102
+ os.rename(tmp_code_cli, code_cli)
103
+ logger.info(f"Extracted vscode_cli_{cli_platform_}_cli.tar.gz to {code_cli}")
104
+
105
+ vscode_server_tarball = Path(server_installer) / f"vscode-server-{platform}.tar.gz"
87
106
  vscode_server_home = get_vscode_server_home(commit)
88
107
  os.makedirs(vscode_server_home, exist_ok=True)
89
108
  subprocess.check_call(
@@ -97,3 +116,4 @@ def install_vscode_server(
97
116
  ]
98
117
  )
99
118
  logger.info(f"Extracted vscode-server-{platform}.tar.gz to {vscode_server_home}")
119
+ return vscode_server_home
vscode_offline/utils.py CHANGED
@@ -4,6 +4,8 @@ import os
4
4
  import shutil
5
5
  import subprocess
6
6
  import sys
7
+ from collections.abc import Mapping
8
+ from email.parser import HeaderParser
7
9
  from pathlib import Path
8
10
 
9
11
  from vscode_offline.loggers import logger
@@ -30,7 +32,7 @@ def get_vscode_extensions_config() -> os.PathLike[str]:
30
32
  return p # default to this path
31
33
 
32
34
 
33
- def get_vscode_commit_from_server_installer(
35
+ def get_vscode_version_from_server_installer(
34
36
  installer: os.PathLike[str], platform: str
35
37
  ) -> str:
36
38
  directories = list(
@@ -45,14 +47,16 @@ def get_vscode_commit_from_server_installer(
45
47
  f"No matching installer found in {installer} for platform {platform}"
46
48
  )
47
49
 
48
- commit = directories[0].parent.name[len("server-") :]
49
- logger.info(f"Getting commit from {platform} installer: {commit}")
50
- return commit
50
+ version = directories[0].parent.name[len("server-") :]
51
+ logger.info(f"Getting version from {platform} installer: {version}")
52
+ return version
51
53
 
52
54
 
53
- def get_vscode_commit_from_code_version() -> str | None:
54
- """Get the current VS Code commit hash by running `code --version`.
55
- Returns None if `code` is not found or the output is unexpected.
55
+ def get_default_code_version() -> str | None:
56
+ """Get the current VS Code version by running `code --version`.
57
+
58
+ Returns:
59
+ `None` if `code` is not found or the output is unexpected.
56
60
  """
57
61
  executable = shutil.which("code")
58
62
  if executable is None:
@@ -70,34 +74,30 @@ def get_vscode_commit_from_code_version() -> str | None:
70
74
 
71
75
  # The commit hash is usually on the second line
72
76
  commit = lines[1].strip().decode("utf-8")
73
- logger.info(f"Getting commit from `code --version`: {commit}")
74
-
75
- return lines[1].strip().decode("utf-8")
77
+ version = f"commit:{commit}"
78
+ logger.info(f"Getting version from `code --version`: {version}")
76
79
 
77
-
78
- def get_target_platform_from_installer(cli_installer: str) -> str | None:
79
- directories = list(Path(cli_installer).glob("vscode-server-*.tar.gz"))
80
- if len(directories) == 1:
81
- return directories[0].name[len("vscode-server-") : -len(".tar.gz")]
82
- return None
80
+ return version
83
81
 
84
82
 
85
83
  # Mapping from target platform to CLI OS and architecture used in download URLs
86
- _cli_os_arch_mapping = {
84
+ _cli_platform_mapping = {
87
85
  "linux-x64": "alpine-x64",
88
86
  "linux-arm64": "alpine-arm64",
87
+ "linux-armhf": "linux-arm64",
88
+ "win32-x64": "win32-x64",
89
89
  }
90
90
 
91
91
 
92
- def get_cli_os_arch(platform: str) -> str:
92
+ def get_cli_platform(platform: str) -> str:
93
93
  """Get the CLI OS and architecture for the given target platform."""
94
- if platform not in _cli_os_arch_mapping:
94
+ if platform not in _cli_platform_mapping:
95
95
  raise ValueError(f"Unsupported target platform: {platform}")
96
- return _cli_os_arch_mapping[platform]
96
+ return _cli_platform_mapping[platform]
97
97
 
98
98
 
99
99
  def get_host_platform() -> str:
100
- """Get the host platform in the format used by VS Code Server install."""
100
+ """Get the host platform in the format used by VS Code install."""
101
101
  if os.name == "nt":
102
102
  if "amd64" in sys.version.lower():
103
103
  return "win32-x64"
@@ -111,3 +111,21 @@ def get_host_platform() -> str:
111
111
  elif machine in ("aarch64", "arm64"):
112
112
  return "linux-arm64"
113
113
  raise ValueError(f"Unsupported host platform: {osname}-{machine}")
114
+
115
+
116
+ def get_filename_from_headers(headers: Mapping[str, str]) -> str | None:
117
+ """Get the filename from HTTP headers.
118
+
119
+ Args:
120
+ headers: The HTTP headers.
121
+ """
122
+ content_disposition = headers.get("Content-Disposition")
123
+ header_str = ""
124
+ if content_type := headers.get("Content-Type"):
125
+ header_str += f"Content-Type: {content_type}\n"
126
+ if content_disposition := headers.get("Content-Disposition"):
127
+ header_str += f"Content-Disposition: {content_disposition}\n"
128
+ if not header_str:
129
+ return None
130
+ header = HeaderParser().parsestr(header_str)
131
+ return header.get_filename()
@@ -1,25 +1,24 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vscode-offline
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: Download and install VS Code Server for offline environments
5
- Author: Chuck Fan
5
+ Project-URL: Homepage, https://github.com/fanck0605/vscode-offline
6
6
  Author-email: Chuck Fan <fanck0605@qq.com>
7
7
  License-Expression: MIT
8
8
  License-File: LICENSE
9
9
  Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: Microsoft :: Windows
13
+ Classifier: Operating System :: POSIX :: Linux
10
14
  Classifier: Programming Language :: Python :: 3 :: Only
11
15
  Classifier: Programming Language :: Python :: 3.9
12
16
  Classifier: Programming Language :: Python :: 3.10
13
17
  Classifier: Programming Language :: Python :: 3.11
14
18
  Classifier: Programming Language :: Python :: 3.12
15
19
  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
20
  Classifier: Topic :: Utilities
21
21
  Requires-Python: >=3.9
22
- Project-URL: Homepage, https://github.com/fanck0605/vscode-offline
23
22
  Description-Content-Type: text/markdown
24
23
 
25
24
  # vscode-offline
@@ -37,38 +36,40 @@ pip install -U vscode-offline
37
36
  1. 自动识别并下载所有 `.vsix` 文件(包括间接依赖)
38
37
  2. 一键安装 VS Code Server 以及所有插件
39
38
 
40
- ## VS Code Server 安装
39
+ ## VS Code 离线安装
41
40
 
42
- (1)在联网环境安装好 VSCode 和你需要的插件。
41
+ (1)在联网环境安装好 VS Code 和你需要的插件,如 [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh), [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) 等。
43
42
 
44
- (2)执行如下命令,将会自动下载 VS Code Server,和目前安装的所有的插件
43
+ (2)执行如下命令,下载 VS Code 安装包,和目前安装的所有的插件
45
44
 
46
- > `--commit` 可以指定对应 VSCode 的 Commit,默认自动获取当前环境 VSCode 的 Commit。
47
- >
48
- > 手动查看方式:*帮助* -> *关于* -> *Commit*,
45
+ ```shell
46
+ vscode-offline download-all --installer ./vscode-offline-installer
47
+ ```
48
+
49
+ (3)复制 `./vscode-offline-installer` 到内网 Windows 机器,安装 `client-<version>` 下的 VS Code,然后执行如下命令安装所有插件
49
50
 
50
51
  ```shell
51
- vscode-offline download-server --target-platform linux-x64 --installer ./vscode-offline-installer
52
+ vscode-offline install-extensions --installer ./vscode-offline-installer
52
53
  ```
53
54
 
54
- 3)复制 `./vscode-offline-installer` 到内网服务器
55
+ 4)复制 `./vscode-offline-installer` 到内网 Linux 服务器,执行如下命令安装 VS Code Server 和所有插件
55
56
 
56
57
  ```shell
57
58
  vscode-offline install-server --installer ./vscode-offline-installer
58
59
  ```
59
60
 
60
- ## VS Code 插件安装
61
+ ## 指定 VS Code 版本号
61
62
 
62
- (1)联网环境执行如下命令,将会自动下载 VSCode 目前安装的所有的插件
63
+ 如果你想下载或安装指定版本的 VS Code,可以先通过 `code --version` 获取当前版本,然后通过 --code-version 参数指定版本号,例如:
63
64
 
64
65
  ```shell
65
- vscode-offline download-extensions --target-platform win32-x64 --installer ./vscode-offline-installer
66
+ vscode-offline download-all --code-version 1.104.3
66
67
  ```
67
68
 
68
- (2)复制 `./vscode-offline-installer` 到内网机器
69
+ 也支持使用 commit hash 作为版本号,例如:
69
70
 
70
71
  ```shell
71
- vscode-offline install-extensions --installer ./vscode-offline-installer
72
+ vscode-offline download-all --code-version commit:385651c938df8a906869babee516bffd0ddb9829
72
73
  ```
73
74
 
74
75
  ## 贡献
@@ -0,0 +1,11 @@
1
+ vscode_offline/__init__.py,sha256=dr6Jtj0XT9eQEC4fzNigEYsAIEfCsaom3HDbUsS-2O4,57
2
+ vscode_offline/app.py,sha256=Rm-uSkJrRmJVmyjiubPpRQTofttQdTADsGyEeZDSeY0,9142
3
+ vscode_offline/download.py,sha256=blu2WjG8zhuBrHrrV-v-FUf2fXbIt7fVSX8DoUX_Ikk,5442
4
+ vscode_offline/install.py,sha256=SZ3UTg-fkzJrfwMGyvjyayyGHGKbymm6bkUs0ayZsKQ,4214
5
+ vscode_offline/loggers.py,sha256=vX91NMtNo1xfxq5y4BCtm_uhCTKtCODqBJHNvcT7JdQ,104
6
+ vscode_offline/utils.py,sha256=vpVSmE4JN0O-ezpzNJo9R9Y3YjzmzslhRVTG5H_-We0,4038
7
+ vscode_offline-0.1.5.dist-info/METADATA,sha256=-ssOm2fHDRr25iLf5hcm4G7BYbMhrwobwrouzwuOWMY,2803
8
+ vscode_offline-0.1.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
9
+ vscode_offline-0.1.5.dist-info/entry_points.txt,sha256=XyuZLe7bgm2RmZp9oh9qCxcrAwHypD8XrTnm4G0_CzM,55
10
+ vscode_offline-0.1.5.dist-info/licenses/LICENSE,sha256=pUIXFkLeTS986b7dopOVLyuw72fJsUxhl8H3rEMIycA,1053
11
+ vscode_offline-0.1.5.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -1,3 +1,2 @@
1
1
  [console_scripts]
2
2
  vscode-offline = vscode_offline:main
3
-
@@ -1,11 +0,0 @@
1
- vscode_offline/__init__.py,sha256=dr6Jtj0XT9eQEC4fzNigEYsAIEfCsaom3HDbUsS-2O4,57
2
- vscode_offline/app.py,sha256=MLYg_2q3pudTL0zBAWTRSjVM_8zDccLIZt0s00xvT7Q,5686
3
- vscode_offline/download.py,sha256=hImUW23npX0hgNMcJ2E3nRLbW8fvzeIFEovg0mWzm9U,3763
4
- vscode_offline/install.py,sha256=UNgLnMAAZEOtX4s8v6QlmuIHPf3aeuXrCWfC6_TEM-0,3488
5
- vscode_offline/loggers.py,sha256=vX91NMtNo1xfxq5y4BCtm_uhCTKtCODqBJHNvcT7JdQ,104
6
- vscode_offline/utils.py,sha256=XknMz1aBMyyTvWG-szE_0eMG3KOdpl9aAeX3E5BrDAI,3542
7
- vscode_offline-0.1.3.dist-info/licenses/LICENSE,sha256=pUIXFkLeTS986b7dopOVLyuw72fJsUxhl8H3rEMIycA,1053
8
- vscode_offline-0.1.3.dist-info/WHEEL,sha256=-neZj6nU9KAMg2CnCY6T3w8J53nx1kFGw_9HfoSzM60,79
9
- vscode_offline-0.1.3.dist-info/entry_points.txt,sha256=zIMeh_ENKKzlt9lDao8icofSI0TeCQxH8eCwxIRI2G8,56
10
- vscode_offline-0.1.3.dist-info/METADATA,sha256=hjeP62mRkggLHpIypE8RgSNXUceC9PYGYBWCrhvabak,2492
11
- vscode_offline-0.1.3.dist-info/RECORD,,
@@ -1,4 +0,0 @@
1
- Wheel-Version: 1.0
2
- Generator: uv 0.8.22
3
- Root-Is-Purelib: true
4
- Tag: py3-none-any