Skip to content

Instantly share code, notes, and snippets.

@b01
Last active April 22, 2024 14:22
Show Gist options
  • Save b01/0a16b6645ab7921b0910603dfb85e4fb to your computer and use it in GitHub Desktop.
Save b01/0a16b6645ab7921b0910603dfb85e4fb to your computer and use it in GitHub Desktop.
Linux script to download latest VS Code Server, good for Docker (tested in Alpine).
#!/bin/sh
# Copyright 2023 Khalifah K. Shabazz
#
# 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:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 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.
set -e
# Auto-Get the latest commit sha via command line.
get_latest_release() {
platform=${1}
arch=${2}
# Grab the first commit SHA since as this script assumes it will be the
# latest.
platform="win32"
arch="x64"
commit_id=$(curl --silent "https://update.code.visualstudio.com/api/commits/stable/${platform}-${arch}" | sed s'/^\["\([^"]*\).*$/\1/')
printf "%s" "${commit_id}"
}
PLATFORM="${1}"
ARCH="${2}"
if [ -z "${PLATFORM}" ]; then
echo "please enter a platform, acceptable values are win32, linux, darwin, or alpine"
exit 1
fi
if [ -z "${ARCH}" ]; then
U_NAME=$(uname -m)
if [ "${U_NAME}" = "aarch64" ]; then
ARCH="arm64"
elif [ "${U_NAME}" = "x86_64" ]; then
ARCH="x64"
elif [ "${U_NAME}" = "armv7l" ]; then
ARCH="armhf"
fi
fi
commit_sha=$(get_latest_release "${PLATFORM}" "${ARCH}")
if [ -n "${commit_sha}" ]; then
echo "will attempt to download VS Code Server version = '${commit_sha}'"
prefix="server-${PLATFORM}"
if [ "${PLATFORM}" = "alpine" ]; then
prefix="cli-${PLATFORM}"
fi
archive="vscode-${prefix}-${ARCH}.tar.gz"
# Download VS Code Server tarball to tmp directory.
curl -L "https://update.code.visualstudio.com/commit:${commit_sha}/${prefix}-${ARCH}/stable" -o "/tmp/${archive}"
# Make the parent directory where the server should live.
# NOTE: Ensure VS Code will have read/write access; namely the user running VScode or container user.
mkdir -vp ~/.vscode-server/bin/"${commit_sha}"
# Extract the tarball to the right location.
tar --no-same-owner -xzv --strip-components=1 -C ~/.vscode-server/bin/"${commit_sha}" -f "/tmp/${archive}"
# Add symlink
cd ~/.vscode-server/bin && ln -s "${commit_sha}" default_version
else
echo "could not pre install vscode server"
fi
@panwarab
Copy link

This worked!

@antmerlino
Copy link

Thanks for the script!

If you add the following to the top of the script, and replace x64 with "$ARCH", this works for aarch64 devices and possible others too.

ARCH=$(uname -m)
if [[ "$ARCH" == "aarch64" ]]; then
        ARCH="arm64"
elif [[ "$ARCH" == "x86_64" ]]; then
        ARCH="x64"
fi

@antmerlino
Copy link

Thanks for the script!

If you add the following to the top of the script, and replace x64 with "$ARCH", this works for aarch64 devices and possible others too.

ARCH=$(uname -m)
if [[ "$ARCH" == "aarch64" ]]; then
        ARCH="arm64"
elif [[ "$ARCH" == "x86_64" ]]; then
        ARCH="x64"
fi

Actually, this doesn't work if the script is executed by /bin/sh instead of /bin/bash, as specified by the shebang.

/bin/sh doesn't support [[ syntax.

The following works

if [ "$ARCH" = "aarch64" ]; then
        ARCH="arm64"
elif [ "$ARCH" = "x86_64" ]; then
        ARCH="x64"
fi

In that case, this line should also be changed from

if [[ "${sha_type}" != "commit" ]]; then

to

if [ "${sha_type}" != "commit" ]; then

@b01
Copy link
Author

b01 commented Jun 7, 2022

That's a good idea. I'll try and add this tonight.

@district10
Copy link

I added extra symlinking:

    # Extract the tarball to the right location.
    tar --no-same-owner -xzv --strip-components=1 -C ~/.vscode-server/bin/"${commit_sha}" -f "/tmp/${archive}"
+   (cd ~/.vscode-server/bin && ln -s "${commit_sha}" default_version)

So I can add code-server to $PATH:

ADD download-vs-code-server.sh /root
RUN cd /root && chmod a+x download-vs-code-server.sh && ./download-vs-code-server.sh
ENV PATH=/root/.vscode-server/bin/default_version/bin:$PATH
RUN code-server --install-extension ms-python.python

@cornshakes
Copy link

cornshakes commented Jan 31, 2023

Thanks a trillion, works great!
To make vscode-server download on raspberry pi, i added these lines:

if [ "${U_NAME}" = "armv7l" ]; then
    ARCH="armhf"
fi

@NathanEmb
Copy link

NathanEmb commented Mar 9, 2023

I added extra symlinking:

    # Extract the tarball to the right location.
    tar --no-same-owner -xzv --strip-components=1 -C ~/.vscode-server/bin/"${commit_sha}" -f "/tmp/${archive}"
+   (cd ~/.vscode-server/bin && ln -s "${commit_sha}" default_version)

So I can add code-server to $PATH:

ADD download-vs-code-server.sh /root
RUN cd /root && chmod a+x download-vs-code-server.sh && ./download-vs-code-server.sh
ENV PATH=/root/.vscode-server/bin/default_version/bin:$PATH
RUN code-server --install-extension ms-python.python

@district10 just tried following this, during my container build the extensions install properly, but they aren't recognized by vscode once I attach. Any ideas, or did this happen to you?

@district10
Copy link

@NathanEmb No. It works well for me.

Maybe check your vscode version (maybe your docker vesion mismatch your client vs code version?), check ~/.vscode-server dir (maybe you mount some dir, overriding this one?)

@WilyWildWilly
Copy link

WilyWildWilly commented Jul 17, 2023

I was going CRAZY with the issue of the eternal wget command sent by the VSC remote-SSh extension to a VM that can't execute it properly, so I downloaded the latest tar.gz and changed one line of your script, worked 3rd shot, you put and end to 6h of MS-fueled brain agony THANK YOU


Copyright (c) 2023 Guglielmo Chelazzi Grandinetti 

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:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

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.

#!/bin/sh

set -e

# Auto-Get the latest commit sha via command line.
get_latest_release() {
    tag=$(curl --silent "https://api.github.com/repos/${1}/releases/latest" | # Get latest release from GitHub API
          grep '"tag_name":'                                              | # Get tag line
          sed -E 's/.*"([^"]+)".*/\1/'                                    ) # Pluck JSON value

    tag_data=$(curl --silent "https://api.github.com/repos/${1}/git/ref/tags/${tag}")

    sha=$(echo "${tag_data}"           | # Get latest release from GitHub API
          grep '"sha":'                | # Get tag line
          sed -E 's/.*"([^"]+)".*/\1/' ) # Pluck JSON value

    sha_type=$(echo "${tag_data}"           | # Get latest release from GitHub API
          grep '"type":'                    | # Get tag line
          sed -E 's/.*"([^"]+)".*/\1/'      ) # Pluck JSON value

    if [ "${sha_type}" != "commit" ]; then
        combo_sha=$(curl -s "https://api.github.com/repos/${1}/git/tags/${sha}" | # Get latest release from GitHub API
              grep '"sha":'                                                     | # Get tag line
              sed -E 's/.*"([^"]+)".*/\1/'                                      ) # Pluck JSON value

        # Remove the tag sha, leaving only the commit sha;
        # this won't work if there are ever more than 2 sha,
        # and use xargs to remove whitespace/newline.
        sha=$(echo "${combo_sha}" | sed -E "s/${sha}//" | xargs)
    fi

    printf "${sha}"
}

ARCH="x64"
U_NAME=$(uname -m)

if [ "${U_NAME}" = "aarch64" ]; then
    ARCH="arm64"
fi

archive="vscode-server-linux-${ARCH}.tar.gz"
owner='microsoft'
repo='vscode'
commit_sha=$(get_latest_release "${owner}/${repo}")

if [ -n "${commit_sha}" ]; then
    echo "will attempt to download VS Code Server version = '${commit_sha}'"

    # Download VS Code Server tarball to tmp directory.
    # curl -L "https://update.code.visualstudio.com/commit:${commit_sha}/server-linux-${ARCH}/stable" -o "/tmp/${archive}"
    cp "/home/tfone/vscode-server-linux-x64.tar.gz" "/tmp/vscode-server-linux-x64.tar.gz" # <- really barbaric modification
    # Make the parent directory where the server should live.
    # NOTE: Ensure VS Code will have read/write access; namely the user running VScode or container user.
    mkdir -vp ~/.vscode-server/bin/"${commit_sha}"

    # Extract the tarball to the right location.
    tar --no-same-owner -xzv --strip-components=1 -C ~/.vscode-server/bin/"${commit_sha}" -f "/tmp/${archive}"
else
    echo "could not pre install vscode server"
fi

@b01
Copy link
Author

b01 commented Aug 27, 2023

I've finally gotten around to adding the addition suggestions.

@MarcoMagriDev
Copy link

@b01

Could you please add a license header for your code that allows using it (e.g. MIT) ?

@b01
Copy link
Author

b01 commented Nov 17, 2023

@MarcoMagriDev There you go.

@flier
Copy link

flier commented Nov 28, 2023

VSCode Insider use download url like https://update.code.visualstudio.com/commit:${commit_sha}/server-linux-${ARCH}/insider

@b01
Copy link
Author

b01 commented Nov 28, 2023

@flier I can change that to a parameter that gets passed in. Will that work?

@flier
Copy link

flier commented Nov 30, 2023

@flier I can change that to a parameter that gets passed in. Will that work?

Sure, it seems we need pass the commit_sha in, because the VSCode insider is not in the https://api.github.com/repos/${1}/releases/latest

@magicwenli
Copy link

Brilliant work!

@Ali-Flt
Copy link

Ali-Flt commented Feb 1, 2024

@b01 The way you are capturing the latest release commit id does not work at all times. For example right now the commit id of the latest release shown in github's release page is f5442d1f9fcdc7ce89a34c6e52a11ba44e47b423 but in fact the commit id of the latest stable version is 05047486b6df5eb8d44b2ecd70ea3bdf775fd937 which is the parent commit of f5442d1f9fcdc7ce89a34c6e52a11ba44e47b423.

VScode provides an API to find the last 200 release versions (see here)
I think this script works better:

#!/bin/sh

# Copyright 2023 Khalifah K. Shabazz
#
# 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:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# 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.

set -e


# Auto-Get the latest commit sha via command line.
get_latest_vscode_release() {
    commit_id=$(curl --silent "https://update.code.visualstudio.com/api/commits/stable/linux-${1}" | grep -o -P '(?<=\[")[^"]*')
    printf "${commit_id}"
}

ARCH="x64"
U_NAME=$(uname -m)

if [ "${U_NAME}" = "aarch64" ]; then
    ARCH="arm64"
elif [ "${U_NAME}" = "x86_64" ]; then
    ARCH="x64"
elif [ "${U_NAME}" = "armv7l" ]; then
    ARCH="armhf"
fi

archive="vscode-server-linux-${ARCH}.tar.gz"
commit_sha=$(get_latest_vscode_release "${ARCH}")

if [ -n "${commit_sha}" ]; then
    echo "will attempt to download VS Code Server version = '${commit_sha}'"

    # Download VS Code Server tarball to tmp directory.
    curl -L "https://update.code.visualstudio.com/commit:${commit_sha}/server-linux-${ARCH}/stable" -o "/tmp/${archive}"

    # Make the parent directory where the server should live.
    # NOTE: Ensure VS Code will have read/write access; namely the user running VScode or container user.
    mkdir -vp ~/.vscode-server/bin/"${commit_sha}"

    # Extract the tarball to the right location.
    tar --no-same-owner -xz --strip-components=1 -C ~/.vscode-server/bin/"${commit_sha}" -f "/tmp/${archive}"
    # Add symlink
    cd ~/.vscode-server/bin && ln -s "${commit_sha}" default_version
else
    echo "could not pre install vscode server"
fi

@andyneff
Copy link

andyneff commented Feb 9, 2024

FYI additional platform information:

  • On Amazon Linux, the url was https://update.code.visualstudio.com/commit:${commit_id}/cli-alpine-x64/stable
  • On Windows it was https://update.code.visualstudio.com/commit:${commit_id}/server-win32-x64/stable

@b01
Copy link
Author

b01 commented Feb 10, 2024

@Ali-Flt yes this will be exactly what was needed from the beginning.
https://update.code.visualstudio.com/api/commits/stable/linux-${1}

@b01
Copy link
Author

b01 commented Feb 10, 2024

@andyneff I also want to add that change as well. But you have likely noticed this script is built for a small sub-set of the platforms VSCode is available on. So I did a bit of digging starting from the link that @Ali-Flt referred to. Which turn up a great big find!

This issue mentioned a Swagger documentation for the update.code.visualstudio.com API: microsoft/vscode#122396 (comment)

The swagger reveals most of the platform options, I guess not all though (excludes Alpine, but we have that so its OK).

          {
            "name": "platform",
            "in": "path",
            "description": "Platform",
            "required": true,
            "type": "string",
            "enum": [
              "win32-x64",
              "win32",
              "win32-archive-x64",
              "win32-archive",
              "win32-x64-user",
              "win32-user",
              "linux-x64",
              "linux-ia32",
              "linux-deb-x64",
              "linux-deb-ia32",
              "linux-rpm-x64",
              "linux-rpm-ia32",
              "darwin"
            ]
          }

@b01
Copy link
Author

b01 commented Feb 10, 2024

OK. Tested the script locally to ensure it downloads the latest server has as reported by the API. It also worked to run a project in a container from VS code. Give the latest version a try if you are up to it!

@Ali-Flt
Copy link

Ali-Flt commented Feb 20, 2024

@b01 thanks.

I have a question unrelated to this script. When I download and extract the linux version of the vscode server and run it using

./vscode-server-linux-x64/bin/code-server --host 127.0.0.1 --without-connection-token --accept-server-license-terms

and then try to open 127.0.0.1:8000 in the browser, it shows "Not Found" instead of opening vscode. Any idea why?
Edit:
The Alpine version seem to work but the linux version doesn't.
Another issue I have is that when I run the Alpine version, it doesn't download the server until I open 127.0.0.1:8000 in browser.
Does anyone know a way to download the server before opening the link in browser?

@Ali-Flt
Copy link

Ali-Flt commented Feb 20, 2024

@b01
btw, I think --strip-components=1 breaks the code for alpine version.

@Ali-Flt
Copy link

Ali-Flt commented Feb 21, 2024

@b01 I think you hardcoded platform and arch in get_latest_release

@b01
Copy link
Author

b01 commented Feb 23, 2024

@Ali-Flt I've never tried to run the sever manually. This is part of the container image that VS code builds for development inside a container. So VS code handle starting the server. So I can't say.

I also tested this version with Alpine 3.19. though I'm not sure if there may be side effects due to --strip-components=1.

And yes, I did hardcode the platform to Linux. Which I can update to allow for Windows. I just wasn't sure how to test that.

@lcmen
Copy link

lcmen commented Apr 2, 2024

Thank you @b01 for the initial script and every one else for the improvements.

I'm not sure if things have changed recently but extracting vscode-server to mkdir -vp ~/.vscode-server/bin/"${commit_sha}" still causes an installation script to kick in when I ssh into a docker container for the first time. After some investigation, I've found out the correct installation path:

# Make the parent directory where the server should live.
# NOTE: Ensure VS Code will have read/write access; namely the user running VScode or container user.
mkdir -vp ~/.vscode-server/cli/servers/Stable-"${commit_sha}/server"

# Extract the tarball to the right location.
tar --no-same-owner -xz --strip-components=1 -C ~/.vscode-server/cli/servers/Stable-"${commit_sha}"/server -f "/tmp/${archive}"

@daixtrose
Copy link

@lcmen Not sure if this is all you need to do since the directory structure underwent further changes. See my question on Stackoverflow. The new directory structure adds some more files. Especially the code-<sha> directory leaves me concerned:

.vscode-server
├── cli
│   └── servers
├── code-e170252f762678dec6ca2cc69aba1570769a5d39
├── data
│   ├── CachedProfilesData
│   ├── logs
│   ├── Machine
│   ├── machineid
│   └── User
└── extensions
    └── extensions.json

@sp7412
Copy link

sp7412 commented Apr 21, 2024

Anyone know how to add in a list of extensions to download as well for offline install?

@b01
Copy link
Author

b01 commented Apr 22, 2024

OK. I'm looking at this now, this is gonna be a fun little project. Especially since VSCode Server is standalone with CLI support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment