docs: def install(package, hash=None, version=None, tag=None, force=False, meta_only=False):
      """
      Download a Quilt data package from the server and install locally.
  
      At most one of `hash`, `version`, or `tag` can be given. If none are
      given, `tag` defaults to "latest".
  
      `package` may be a node tree - in which case, its fragments get downloaded.
      No other parameters are allowed.
      """
      if isinstance(package, nodes.Node):
          if not (hash is version is tag is None and force is meta_only is False):
              raise ValueError("Parameters not allowed when installing a node")
          _materialize(package)
          return
  
      if hash is version is tag is None:
          tag = LATEST_TAG
  
      # @filename ==> read from file
      # newline = multiple lines ==> multiple requirements
      package = package.strip()
      if len(package) == 0:
          raise CommandException("package name is empty.")
  
      if package[0] == '@' or '\n' in package:
          return install_via_requirements(package, force=force)
  
      assert [hash, version, tag].count(None) == 2
  
      team, owner, pkg, subpath = parse_package(package, allow_subpath=True)
      _check_team_id(team)
      session = _get_session(team)
      store = PackageStore()
      existing_pkg = store.get_package(team, owner, pkg)
  
      print("Downloading package metadata...")
  
      try:
          if version is not None:
              response = session.get(
                  "{url}/api/version/{owner}/{pkg}/{version}".format(
                      url=get_registry_url(team),
                      owner=owner,
                      pkg=pkg,
                      version=version
                  )
              )
              pkghash = response.json()['hash']
          elif tag is not None:
              response = session.get(
                  "{url}/api/tag/{owner}/{pkg}/{tag}".format(
                      url=get_registry_url(team),
                      owner=owner,
                      pkg=pkg,
                      tag=tag
                  )
              )
              pkghash = response.json()['hash']
          else:
              pkghash = _match_hash(package, hash)
      except HTTPResponseException as e:
          logged_in_team = _find_logged_in_team()
          if (team is None and logged_in_team is not None
                  and e.response.status_code == requests.codes.not_found):
              raise CommandException("Package {owner}/{pkg} does not exist. "
                                     "Maybe you meant {team}:{owner}/{pkg}?".format(
                                     owner=owner, pkg=pkg, team=logged_in_team))
          else:
              raise
  
      assert pkghash is not None
  
      response = session.get(
          "{url}/api/package/{owner}/{pkg}/{hash}".format(
              url=get_registry_url(team),
              owner=owner,
              pkg=pkg,
              hash=pkghash
          ),
          params=dict(
              subpath='/'.join(subpath),
              meta_only='true' if meta_only else ''
          )
      )
      assert response.ok # other responses handled by _handle_response
  
      if existing_pkg is not None and not force:
          print("{package} already installed.".format(package=package))
          overwrite = input("Overwrite? (y/n) ")
          if overwrite.lower() != 'y':
              return
  
      dataset = response.json(object_hook=decode_node)
      contents = dataset['contents']
  
      # Verify contents hash
      if pkghash != hash_contents(contents):
          raise CommandException("Mismatched hash. Try again.")
  
      # TODO: Shouldn't need this? At least don't need the contents
      store.install_package(team, owner, pkg, contents)
  
      obj_urls = dataset['urls']
      obj_sizes = dataset['sizes']
  
      # Skip the objects we already have
      for obj_hash in list(obj_urls):
          if os.path.exists(store.object_path(obj_hash)):
              del obj_urls[obj_hash]
              del obj_sizes[obj_hash]
  
      if obj_urls:
          success = download_fragments(store, obj_urls, obj_sizes)
          if not success:
              raise CommandException("Failed to download fragments")
      else:
          print("Fragments already downloaded")
  
      store.save_package_contents(contents, team, owner, pkg)