import json import os import shutil import subprocess import urllib.request from functools import partial from pathlib import Path from tarfile import TarFile NODE_MODULES = "node_modules" def replace(target_path, link_target): # Ensure the parent directory of target_path exists target_path.parent.mkdir(parents=True, exist_ok=True) if target_path.is_symlink(): if target_path.resolve() == link_target.resolve(): print(f"Symlink already correct: {target_path} -> {link_target}") else: print(f"Symlink points to the wrong target. Updating: {target_path}") target_path.unlink() os.symlink(link_target, target_path) elif target_path.exists(): print( f"Path exists but is not a symlink. Removing and replacing: {target_path}" ) if target_path.is_dir(): shutil.rmtree(target_path) else: target_path.unlink() os.symlink(link_target, target_path) else: print(f"Creating new symlink: {target_path} -> {link_target}") os.symlink(link_target, target_path) def replace_node_modules(vscode_path, native_path, name): replace(target_path=vscode_path / NODE_MODULES / name, link_target=native_path / NODE_MODULES / name) native_modules = [ "node-pty", "native-watchdog", "@vscode/spdlog", "@parcel/watcher", ] def replace_natives(vscode_path, native_path): replace = partial(replace_node_modules, vscode_path, native_path) for name in native_modules: replace(name) def mk_native_modules(vscode_path: Path, native_path: Path): """ For each native module: 1. Read VSCode's node_modules package/package.json to retrieve version info 2. Use npm to install specific versions of the native modules """ native_path.mkdir(parents=True, exist_ok=True) # Create package.json if it doesn't exist package_json_path = native_path / "package.json" if not package_json_path.exists(): with open(package_json_path, "w") as f: json.dump({ "name": "vscode-native-modules", "version": "1.0.0", "private": True, "dependencies": {} }, f, indent=2) # Read the existing package.json with open(package_json_path, "r") as f: package_json = json.load(f) # Ensure dependencies object exists if "dependencies" not in package_json: package_json["dependencies"] = {} # For each native module, get its version and add to dependencies modules_to_install = [] for module_name in native_modules: module_package_json = vscode_path / NODE_MODULES / module_name / "package.json" if module_package_json.exists(): with open(module_package_json, "r") as f: module_info = json.load(f) version = module_info.get("version", "latest") package_json["dependencies"][module_name] = version modules_to_install.append(f"{module_name}@{version}") # Write updated package.json with open(package_json_path, "w") as f: json.dump(package_json, f, indent=2) # Install the native modules if modules_to_install: print(f"Installing native modules: {', '.join(modules_to_install)}") subprocess.run(["npm", "install"], cwd=str(native_path), check=True) def replace_node(vscode_path, node_path): """ Replace the node binary in vscode_path with the one from node_path. """ vscode_node_path = vscode_path / "node" # Ensure the parent directory of vscode_node_path exists vscode_node_path.parent.mkdir(parents=True, exist_ok=True) replace( target_path=vscode_node_path, link_target=node_path, ) def main(): # Download vscode server url = "https://github.com/VSCodium/vscodium/releases/download/1.99.32562/vscodium-reh-web-linux-x64-1.99.32562.tar.gz" # Replace with the actual URL tar_path = "vscode-server.tar.gz" # Replace with your tar.gz file path with urllib.request.urlopen(url) as response: with open(tar_path, "wb") as file: file.write(response.read()) vscode_path = (Path(".") / "vscode-server-linux-x64-web").absolute() # Extract it (tar.gz) with TarFile.open(tar_path, "r:gz") as tar: tar.extractall(path=vscode_path) native_path = (Path(".") / "native_modules").absolute() mk_native_modules( vscode_path=vscode_path, native_path=native_path, ) replace_natives(vscode_path, native_path) replace_node(vscode_path, Path(shutil.which("node"))) if __name__ == "__main__": main()