177 lines
5.7 KiB
Python
177 lines
5.7 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2015 Google LLC. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Common helper methods for Genomics commands."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
import tempfile
|
|
|
|
from apitools.base.protorpclite.messages import DecodeError
|
|
from apitools.base.py import encoding
|
|
from apitools.base.py import exceptions as apitools_exceptions
|
|
from apitools.base.py import extra_types
|
|
from apitools.base.py import transfer
|
|
|
|
from googlecloudsdk.api_lib.genomics import exceptions as genomics_exceptions
|
|
from googlecloudsdk.api_lib.util import apis as core_apis
|
|
from googlecloudsdk.calliope import exceptions as calliope_exceptions
|
|
from googlecloudsdk.core import log
|
|
from googlecloudsdk.core import properties
|
|
from googlecloudsdk.core import yaml
|
|
from googlecloudsdk.core.resource import resource_printer
|
|
from googlecloudsdk.core.util import files
|
|
import six
|
|
|
|
GCS_PREFIX = 'gs://'
|
|
|
|
|
|
def InfoValuesToAPI(values):
|
|
"""Converts a list of strings to the API JsonValue equivalent.
|
|
|
|
Args:
|
|
values: the string values to be converted
|
|
Returns:
|
|
An equivalent list of JsonValue strings
|
|
"""
|
|
return [extra_types.JsonValue(string_value=v) for v in values]
|
|
|
|
|
|
def InfoValuesFromAPI(values):
|
|
"""Converts a list of strings to an API JsonValue equivalent.
|
|
|
|
Args:
|
|
values: the list of JsonValue strings to be converted
|
|
Returns:
|
|
An equivalent list of strings
|
|
"""
|
|
return [v.string_value for v in values]
|
|
|
|
|
|
def PrettyPrint(resource, print_format='json'):
|
|
"""Prints the given resource."""
|
|
resource_printer.Print(
|
|
resources=[resource],
|
|
print_format=print_format,
|
|
out=log.out)
|
|
|
|
|
|
def GetGenomicsClient(version='v1'):
|
|
return core_apis.GetClientInstance('genomics', version)
|
|
|
|
|
|
def GetGenomicsMessages(version='v1'):
|
|
return core_apis.GetMessagesModule('genomics', version)
|
|
|
|
|
|
def GetProjectId():
|
|
return properties.VALUES.core.project.Get(required=True)
|
|
|
|
|
|
def IsGcsPath(path):
|
|
return path.startswith(GCS_PREFIX)
|
|
|
|
|
|
def GetFileAsMessage(path, message, client):
|
|
"""Reads a YAML or JSON object of type message from path (local or GCS).
|
|
|
|
Args:
|
|
path: A local or GCS path to an object specification in YAML or JSON format.
|
|
message: The message type to be parsed from the file.
|
|
client: The storage_v1 client to use.
|
|
|
|
Returns:
|
|
Object of type message, if successful.
|
|
Raises:
|
|
files.Error, genomics_exceptions.GenomicsInputFileError
|
|
"""
|
|
if IsGcsPath(path):
|
|
# Download remote file to a local temp file
|
|
tf = tempfile.NamedTemporaryFile(delete=False)
|
|
tf.close()
|
|
|
|
bucket, obj = _SplitBucketAndObject(path)
|
|
storage_messages = core_apis.GetMessagesModule('storage', 'v1')
|
|
get_request = storage_messages.StorageObjectsGetRequest(
|
|
bucket=bucket, object=obj)
|
|
try:
|
|
download = transfer.Download.FromFile(tf.name, overwrite=True)
|
|
client.objects.Get(get_request, download=download)
|
|
del download # Explicitly close the stream so the results are there
|
|
except apitools_exceptions.HttpError as e:
|
|
raise genomics_exceptions.GenomicsInputFileError(
|
|
'Unable to read remote file [{0}] due to [{1}]'.format(
|
|
path, six.text_type(e)))
|
|
path = tf.name
|
|
|
|
# Read the file.
|
|
in_text = files.ReadFileContents(path)
|
|
if not in_text:
|
|
raise genomics_exceptions.GenomicsInputFileError(
|
|
'Empty file [{0}]'.format(path))
|
|
|
|
# Parse it, first trying YAML then JSON.
|
|
try:
|
|
result = encoding.PyValueToMessage(message, yaml.load(in_text))
|
|
except (ValueError, AttributeError, yaml.YAMLParseError):
|
|
try:
|
|
result = encoding.JsonToMessage(message, in_text)
|
|
except (ValueError, DecodeError) as e:
|
|
# ValueError is raised when JSON is badly formatted
|
|
# DecodeError is raised when a tag is badly formatted (not Base64)
|
|
raise genomics_exceptions.GenomicsInputFileError(
|
|
'Pipeline file [{0}] is not properly formatted YAML or JSON '
|
|
'due to [{1}]'.format(path, six.text_type(e)))
|
|
return result
|
|
|
|
|
|
def ArgDictToAdditionalPropertiesList(argdict, message):
|
|
result = []
|
|
if argdict is None:
|
|
return result
|
|
# For consistent results (especially for deterministic testing), make
|
|
# the return list ordered by key
|
|
for k, v in sorted(six.iteritems(argdict)):
|
|
result.append(message(key=k, value=v))
|
|
return result
|
|
|
|
|
|
def _SplitBucketAndObject(gcs_path):
|
|
"""Split a GCS path into bucket & object tokens, or raise BadFileException."""
|
|
tokens = gcs_path[len(GCS_PREFIX):].strip('/').split('/', 1)
|
|
if len(tokens) != 2:
|
|
raise calliope_exceptions.BadFileException(
|
|
'[{0}] is not a valid Google Cloud Storage path'.format(gcs_path))
|
|
return tokens
|
|
|
|
|
|
def GetQueryFields(referenced_fields, prefix):
|
|
"""Returns the comma separated list of field names referenced by the command.
|
|
|
|
Args:
|
|
referenced_fields: A list of field names referenced by the format and filter
|
|
expressions.
|
|
prefix: The referenced field name resource prefix.
|
|
|
|
Returns:
|
|
The comma separated list of field names referenced by the command.
|
|
"""
|
|
if not referenced_fields:
|
|
return None
|
|
return ','.join(['nextPageToken'] +
|
|
['.'.join([prefix, field]) for field in referenced_fields])
|