github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/install.py (about) 1 #!/usr/bin/env python 2 3 # Copyright 2018-2021 The NATS Authors 4 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # you may not use this file except in compliance with the License. 6 # You may obtain a copy of the License at 7 # 8 # http://www.apache.org/licenses/LICENSE-2.0 9 # 10 # Unless required by applicable law or agreed to in writing, software 11 # distributed under the License is distributed on an "AS IS" BASIS, 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 # See the License for the specific language governing permissions and 14 # limitations under the License. 15 # 16 # This installer mostly inspired by 17 # https://github.com/denoland/deno_install/blob/master/install.py 18 19 from __future__ import print_function 20 21 import io 22 import os 23 import re 24 import sys 25 import zipfile 26 import zlib 27 28 try: 29 from urllib.request import urlopen 30 except ImportError: 31 from urllib2 import urlopen 32 33 NSC_REPO_URL = "https://github.com/nats-io/nsc" 34 FILENAME_LOOKUP = { 35 "darwin": { 36 "amd64": "nsc-darwin-amd64.zip", 37 "arm64": "nsc-darwin-arm64.zip", 38 }, 39 "linux": { 40 "amd64": "nsc-linux-amd64.zip", 41 "arm64": "nsc-linux-arm64.zip", 42 }, 43 "win32": { 44 "amd64": "nsc-windows-amd64.zip", 45 }, 46 } 47 48 49 def release_url(platform, arch, tag): 50 if "linux" in platform: 51 # convert any linux regardless of version reported to "linux" 52 platform = "linux" 53 if arch == "x86_64": 54 arch = "amd64" 55 elif arch == "aarch64": 56 arch = "arm64" 57 try: 58 filename = FILENAME_LOOKUP[platform][arch] 59 except KeyError: 60 print("Unable to locate appropriate filename for", platform, "with archtecture", arch) 61 sys.exit(1) 62 63 release_base = NSC_REPO_URL + '/releases/' 64 if tag: 65 return release_base + 'download/' + tag + '/' + filename 66 return release_base + 'latest/download/' + filename 67 68 69 def download_with_progress(url): 70 print("Downloading", url) 71 72 remote_file = urlopen(url) 73 total_size = int(remote_file.headers['Content-Length'].strip()) 74 75 data = [] 76 bytes_read = 0.0 77 78 while True: 79 d = remote_file.read(8192) 80 81 if not d: 82 print() 83 break 84 85 bytes_read += len(d) 86 data.append(d) 87 sys.stdout.write('\r%2.2f%% downloaded' % (bytes_read / total_size * 100)) 88 sys.stdout.flush() 89 90 return b''.join(data) 91 92 93 def main(): 94 url = release_url(sys.platform, os.uname()[4], sys.argv[1] if len(sys.argv) > 1 else None) 95 bin_dir = nsc_bin_dir() 96 exe_fn = os.path.join(bin_dir, "nsc") 97 windows = "windows" in url 98 if windows: 99 exe_fn = os.path.join(bin_dir, "nsc.exe") 100 101 compressed = download_with_progress(url) 102 if url.endswith(".zip"): 103 with zipfile.ZipFile(io.BytesIO(compressed), 'r') as z: 104 with open(exe_fn, 'wb+') as exe: 105 if windows: 106 exe.write(z.read('nsc.exe')) 107 else: 108 exe.write(z.read('nsc')) 109 else: 110 # Note: gzip.decompress is not available in python2. 111 content = zlib.decompress(compressed, 15 + 32) 112 with open(exe_fn, 'wb+') as exe: 113 exe.write(content) 114 os.chmod(exe_fn, 0o744) 115 116 print("NSC: " + exe_fn) 117 if maybe_symlink(exe_fn): 118 return 119 120 print("Now manually add %s to your $PATH" % bin_dir) 121 if windows: 122 print("Windows Cmd Prompt Example:") 123 print(" setx path %%path;\"%s\"" % bin_dir) 124 print() 125 else: 126 print("Bash Example:") 127 print(" echo 'export PATH=\"$PATH:%s\"' >> $HOME/.bashrc" % bin_dir) 128 print(" source $HOME/.bashrc") 129 print() 130 print("Zsh Example:") 131 print(" echo 'export PATH=\"$PATH:%s\"' >> $HOME/.zshrc" % bin_dir) 132 print(" source $HOME/.zshrc") 133 print() 134 135 136 # Returns True if install instructions are not needed 137 def maybe_symlink(exe_fn): 138 sym_dir = nsc_symlink_dir() 139 if not sym_dir: 140 return False 141 link_path = os.path.join(sym_dir, os.path.basename(exe_fn)) 142 if os.path.exists(link_path): 143 if os.path.islink(link_path): 144 try: 145 os.unlink(link_path) 146 except Exception: 147 return False 148 else: 149 print("Not touching non-symlink: " + link_path) 150 return False 151 try: 152 os.symlink(exe_fn, link_path) 153 print("NSC: " + link_path) 154 if dir_in_PATH(sym_dir): 155 return True 156 return False 157 except Exception: 158 # Python2 does not support symlinks on Windows, amongst other 159 # reasons this might have failed. 160 return False 161 162 163 def dir_in_PATH(dirname): 164 try: 165 envPath = os.environ['PATH'] 166 except Exception: 167 return False 168 return dirname in envPath.split(os.pathsep) 169 170 171 def mkdir(d): 172 if not os.path.exists(d): 173 print("mkdir", d) 174 os.mkdir(d) 175 176 177 def nsc_bin_dir(): 178 home = os.path.expanduser("~") 179 nsccli = os.path.join(home, ".nsccli") 180 mkdir(nsccli) 181 bin_dir = os.path.join(nsccli, "bin") 182 mkdir(bin_dir) 183 return bin_dir 184 185 186 def nsc_symlink_dir(): 187 home = os.path.expanduser("~") 188 sym_dir = os.path.join(home, "bin") 189 if os.path.exists(sym_dir): 190 return sym_dir 191 return None 192 193 194 if __name__ == '__main__': 195 main()