text: """Move files to local Galaxy upload directory and add to Galaxy Data Libraries.
  
  Required configurable variables in upload:
    dir
  """
  from __future__ import print_function
  import collections
  import os
  import shutil
  import time
  
  from bcbio import utils
  from bcbio.log import logger
  from bcbio.upload import filesystem
  from bcbio.pipeline import qcsummary
  
  # Avoid bioblend import errors, raising at time of use
  try:
      import bioblend
      from bioblend.galaxy import GalaxyInstance
      import simplejson
  except ImportError:
      GalaxyInstance, bioblend, simplejson = None, None, None
  
  def update_file(finfo, sample_info, config):
      """Update file in Galaxy data libraries.
      """
      if GalaxyInstance is None:
          raise ImportError("Could not import bioblend.galaxy")
      if "dir" not in config:
          raise ValueError("Galaxy upload requires `dir` parameter in config specifying the "
                           "shared filesystem path to move files to.")
      if "outputs" in config:
          _galaxy_tool_copy(finfo, config["outputs"])
      else:
          _galaxy_library_upload(finfo, sample_info, config)
  
  def _galaxy_tool_copy(finfo, outputs):
      """Copy information directly to pre-defined outputs from a Galaxy tool.
  
      XXX Needs generalization
      """
      tool_map = {"align": "bam", "variants": "vcf.gz"}
      for galaxy_key, finfo_type in tool_map.items():
          if galaxy_key in outputs and finfo.get("type") == finfo_type:
              shutil.copy(finfo["path"], outputs[galaxy_key])
  
  def _galaxy_library_upload(finfo, sample_info, config):
      """Upload results to galaxy library.
      """
      folder_name = "%s_%s" % (config["fc_date"], config["fc_name"])
      storage_dir = utils.safe_makedir(os.path.join(config["dir"], folder_name))
      if finfo.get("type") == "directory":
          storage_file = None
          if finfo.get("ext") == "qc":
              pdf_file = qcsummary.prep_pdf(finfo["path"], config)
              if pdf_file:
                  finfo["path"] = pdf_file
                  finfo["type"] = "pdf"
                  storage_file = filesystem.copy_finfo(finfo, storage_dir, pass_uptodate=True)
      else:
          storage_file = filesystem.copy_finfo(finfo, storage_dir, pass_uptodate=True)
      if "galaxy_url" in config and "galaxy_api_key" in config:
          galaxy_url = config["galaxy_url"]
          if not galaxy_url.endswith("/"):
              galaxy_url += "/"
          gi = GalaxyInstance(galaxy_url, config["galaxy_api_key"])
      else:
          raise ValueError("Galaxy upload requires `galaxy_url` and `galaxy_api_key` in config")
      if storage_file and sample_info and not finfo.get("index", False) and not finfo.get("plus", False):
          _to_datalibrary_safe(storage_file, gi, folder_name, sample_info, config)
  
  def _to_datalibrary_safe(fname, gi, folder_name, sample_info, config):
      """Upload with retries for intermittent JSON failures.
      """
      num_tries = 0
      max_tries = 5
      while 1:
          try:
              _to_datalibrary(fname, gi, folder_name, sample_info, config)
              break
          except (simplejson.scanner.JSONDecodeError, bioblend.galaxy.client.ConnectionError) as e:
              num_tries += 1
              if num_tries > max_tries:
                  raise
              print("Retrying upload, failed with:", str(e))
              time.sleep(5)
  
  def _to_datalibrary(fname, gi, folder_name, sample_info, config):
      """Upload a file to a Galaxy data library in a project specific folder.
      """
      library = _get_library(gi, sample_info, config)
      libitems = gi.libraries.show_library(library.id, contents=True)
      folder = _get_folder(gi, folder_name, library, libitems)
      _file_to_folder(gi, fname, sample_info, libitems, library, folder)
  
  def _file_to_folder(gi, fname, sample_info, libitems, library, folder):
      """Check if file exists on Galaxy, if not upload to specified folder.
      """
      full_name = os.path.join(folder["name"], os.path.basename(fname))
  
      # Handle VCF: Galaxy reports VCF files without the gzip extension
      file_type = "vcf_bgzip" if full_name.endswith(".vcf.gz") else "auto"
      if full_name.endswith(".vcf.gz"):
          full_name = full_name.replace(".vcf.gz", ".vcf")
  
      for item in libitems:
          if item["name"] == full_name:
              return item
      logger.info("Uploading to Galaxy library '%s': %s" % (library.name, full_name))
      return gi.libraries.upload_from_galaxy_filesystem(str(library.id), fname, folder_id=str(folder["id"]),
                                                        link_data_only="link_to_files",
                                                        dbkey=sample_info["genome_build"],
                                                        file_type=file_type,
                                                        roles=str(library.roles) if library.roles else None)
  
  def _get_folder(gi, folder_name, library, libitems):
      """Retrieve or create a folder inside the library with the specified name.
      """
      for item in libitems:
          if item["type"] == "folder" and item["name"] == "/%s" % folder_name:
              return item
      return gi.libraries.create_folder(library.id, folder_name)[0]
  
  GalaxyLibrary = collections.namedtuple("GalaxyLibrary", ["id", "name", "roles"])
  
  def _get_library(gi, sample_info, config):
      """Retrieve the appropriate data library for the current user.
      """
      galaxy_lib = sample_info.get("galaxy_library",
                                   config.get("galaxy_library"))
      role = sample_info.get("galaxy_role",
                             config.get("galaxy_role"))
      if galaxy_lib:
          return _get_library_from_name(gi, galaxy_lib, role, sample_info, create=True)
      elif config.get("private_libs") or config.get("lab_association") or config.get("researcher"):
          return _library_from_nglims(gi, sample_info, config)
      else:
          raise ValueError("No Galaxy library specified for sample: %s" %
                           sample_info["description"])
  
  def _get_library_from_name(gi, name, role, sample_info, create=False):
      for lib in gi.libraries.get_libraries():
          if lib["name"].lower() == name.lower() and not lib.get("deleted", False):
              return GalaxyLibrary(lib["id"], lib["name"], role)
      if create and name:
          logger.info("Creating Galaxy library: '%s'" % name)
          lib = gi.libraries.create_library(name)
          librole = str(gi.users.get_current_user()["id"] if not role else role)
          try:
              gi.libraries.set_library_permissions(str(lib["id"]), librole, librole, librole, librole)
          # XXX Returns error on Galaxy side but seems to work -- ugly
          except:
              pass
          return GalaxyLibrary(lib["id"], lib["name"], role)
      else:
          raise ValueError("Could not find Galaxy library matching '%s' for sample %s" %
                           (name, sample_info["description"]))
  
  def _library_from_nglims(gi, sample_info, config):
      """Retrieve upload library from nglims specified user libraries.
      """
      names = [config.get(x, "").strip() for x in ["lab_association", "researcher"]
               if config.get(x)]
      for name in names:
          for ext in ["sequencing", "lab"]:
              check_name = "%s %s" % (name.split()[0], ext)
              try:
                  return _get_library_from_name(gi, check_name, None, sample_info)
              except ValueError:
                  pass
      check_names = set([x.lower() for x in names])
      for libname, role in config["private_libs"]:
          # Try to find library for lab or rsearcher
          if libname.lower() in check_names:
              return _get_library_from_name(gi, libname, role, sample_info)
      # default to first private library if available
      if len(config.get("private_libs", [])) > 0:
          libname, role = config["private_libs"][0]
          return _get_library_from_name(gi, libname, role, sample_info)
      # otherwise use the lab association or researcher name
      elif len(names) > 0:
          return _get_library_from_name(gi, names[0], None, sample_info, create=True)
      else:
          raise ValueError("Could not find Galaxy library for sample %s" % sample_info["description"])
  