github.com/kbehouse/nsc@v0.0.6/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/kbehouse/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()