16053: Merge branch 'master'
authorTom Clegg <tom@tomclegg.ca>
Tue, 31 Mar 2020 17:52:23 +0000 (13:52 -0400)
committerTom Clegg <tom@tomclegg.ca>
Tue, 31 Mar 2020 17:52:23 +0000 (13:52 -0400)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@tomclegg.ca>

21 files changed:
apps/workbench/Gemfile.lock
apps/workbench/config/initializers/actionview_xss_fix.rb [new file with mode: 0644]
apps/workbench/test/unit/helpers/javascript_helper_test.rb [new file with mode: 0644]
build/build-dev-docker-jobs-image.sh
build/run-build-packages.sh
build/run-tests.sh
lib/boot/supervisor.go
sdk/cwl/arvados_cwl/__init__.py
sdk/cwl/arvados_cwl/arvworkflow.py
sdk/cwl/arvados_cwl/runner.py
sdk/cwl/setup.py
sdk/cwl/test_with_arvbox.sh
sdk/cwl/tests/test_container.py
sdk/cwl/tests/test_submit.py
sdk/cwl/tests/wf/scatter2_subwf.cwl
sdk/java-v2/src/main/java/org/arvados/client/api/client/LinksApiClient.java [new file with mode: 0644]
sdk/java-v2/src/main/java/org/arvados/client/api/model/Link.java [new file with mode: 0644]
sdk/java-v2/src/main/java/org/arvados/client/api/model/LinkList.java [new file with mode: 0644]
sdk/python/arvados/commands/arv_copy.py
sdk/python/setup.py
services/api/Gemfile.lock

index b02161c598e75772895fe0dc1dccf111c124ac6b..2af9c8b16f0b282ef3abc1a4d7c3880e690f7420 100644 (file)
@@ -122,7 +122,7 @@ GEM
     coffee-script-source (1.12.2)
     commonjs (0.2.7)
     concurrent-ruby (1.1.5)
-    crass (1.0.4)
+    crass (1.0.5)
     deep_merge (1.2.1)
     docile (1.3.1)
     erubis (2.7.0)
@@ -167,7 +167,7 @@ GEM
       railties (>= 4)
       request_store (~> 1.0)
     logstash-event (1.2.02)
-    loofah (2.2.3)
+    loofah (2.3.1)
       crass (~> 1.0.2)
       nokogiri (>= 1.5.9)
     mail (2.7.1)
@@ -195,7 +195,7 @@ GEM
     net-ssh-gateway (2.0.0)
       net-ssh (>= 4.0.0)
     nio4r (2.3.1)
-    nokogiri (1.10.4)
+    nokogiri (1.10.8)
       mini_portile2 (~> 2.4.0)
     npm-rails (0.2.1)
       rails (>= 3.2)
@@ -247,7 +247,7 @@ GEM
       method_source
       rake (>= 0.8.7)
       thor (>= 0.18.1, < 2.0)
-    rake (12.3.2)
+    rake (13.0.1)
     raphael-rails (2.1.2)
     rb-fsevent (0.10.3)
     rb-inotify (0.10.0)
diff --git a/apps/workbench/config/initializers/actionview_xss_fix.rb b/apps/workbench/config/initializers/actionview_xss_fix.rb
new file mode 100644 (file)
index 0000000..3f5e239
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+# This is related to:
+# * https://github.com/advisories/GHSA-65cv-r6x7-79hv
+# * https://nvd.nist.gov/vuln/detail/CVE-2020-5267
+#
+# Until we upgrade to rails 5.2, this monkeypatch should be enough
+ActionView::Helpers::JavaScriptHelper::JS_ESCAPE_MAP.merge!(
+  {
+    "`" => "\\`",
+    "$" => "\\$"
+  }
+)
+
+module ActionView::Helpers::JavaScriptHelper
+  alias :old_ej :escape_javascript
+  alias :old_j :j
+
+  def escape_javascript(javascript)
+    javascript = javascript.to_s
+    if javascript.empty?
+      result = ""
+    else
+      result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"']|[`]|[$])/u, JS_ESCAPE_MAP)
+    end
+    javascript.html_safe? ? result.html_safe : result
+  end
+
+  alias :j :escape_javascript
+end
\ No newline at end of file
diff --git a/apps/workbench/test/unit/helpers/javascript_helper_test.rb b/apps/workbench/test/unit/helpers/javascript_helper_test.rb
new file mode 100644 (file)
index 0000000..9d5a553
--- /dev/null
@@ -0,0 +1,17 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+require 'test_helper'
+
+# Tests XSS vulnerability monkeypatch
+# See: https://github.com/advisories/GHSA-65cv-r6x7-79hv
+class JavascriptHelperTest < ActionView::TestCase
+  def test_escape_backtick
+    assert_equal "\\`", escape_javascript("`")
+  end
+
+  def test_escape_dollar_sign
+    assert_equal "\\$", escape_javascript("$")
+  end
+end
index 52df80f58229c906858bf7a93be3c5e161cb287d..a3d439be6f37fd76affd7a95d7eff30f910a5a3e 100755 (executable)
@@ -16,7 +16,7 @@ Syntax:
 WORKSPACE=path         Path to the Arvados source tree to build packages from
 CWLTOOL=path           (optional) Path to cwltool git repository.
 SALAD=path             (optional) Path to schema_salad git repository.
-PYCMD=pythonexec       (optional) Specify the python executable to use in the docker image. Defaults to "python".
+PYCMD=pythonexec       (optional) Specify the python executable to use in the docker image. Defaults to "python3".
 
 EOF
 
@@ -36,13 +36,13 @@ fi
 
 cd "$WORKSPACE"
 
-py=python
+py=python3
 pipcmd=pip
 if [[ -n "$PYCMD" ]] ; then
     py="$PYCMD"
-    if [[ $py = python3 ]] ; then
-       pipcmd=pip3
-    fi
+fi
+if [[ $py = python3 ]] ; then
+    pipcmd=pip3
 fi
 
 (cd sdk/python && python setup.py sdist)
@@ -79,6 +79,7 @@ if [[ $python_sdk_ts -gt $cwl_runner_ts ]]; then
     cwl_runner_version=$(cd sdk/python && nohash_version_from_git 1.0)
 fi
 
-docker build --build-arg sdk=$sdk --build-arg runner=$runner --build-arg salad=$salad --build-arg cwltool=$cwltool --build-arg pythoncmd=$py --build-arg pipcmd=$pipcmd -f "$WORKSPACE/sdk/dev-jobs.dockerfile" -t arvados/jobs:$cwl_runner_version "$WORKSPACE/sdk"
+set -x
+docker build --no-cache --build-arg sdk=$sdk --build-arg runner=$runner --build-arg salad=$salad --build-arg cwltool=$cwltool --build-arg pythoncmd=$py --build-arg pipcmd=$pipcmd -f "$WORKSPACE/sdk/dev-jobs.dockerfile" -t arvados/jobs:$cwl_runner_version "$WORKSPACE/sdk"
 echo arv-keepdocker arvados/jobs $cwl_runner_version
 arv-keepdocker arvados/jobs $cwl_runner_version
index e38d1fd24e5f56cd19a6715b09aeb43593a8e362..4faa1c6b0d4b0e83d12d27b997615fbf78031284 100755 (executable)
@@ -322,10 +322,10 @@ package_go_binary tools/keep-exercise keep-exercise \
 # The Python SDK - Should be built first because it's needed by others
 fpm_build_virtualenv "arvados-python-client" "sdk/python"
 
-# Arvados cwl runner
-fpm_build_virtualenv "arvados-cwl-runner" "sdk/cwl"
+# The Python SDK - Python3 package
+fpm_build_virtualenv "arvados-python-client" "sdk/python" "python3"
 
-# Arvados cwl runner - Python3 package
+# Arvados cwl runner - Only supports Python3 now
 fpm_build_virtualenv "arvados-cwl-runner" "sdk/cwl" "python3"
 
 # The PAM module
@@ -340,9 +340,6 @@ fpm_build_virtualenv "arvados-node-manager" "services/nodemanager"
 # The Arvados crunchstat-summary tool
 fpm_build_virtualenv "crunchstat-summary" "tools/crunchstat-summary"
 
-# The Python SDK - Python3 package
-fpm_build_virtualenv "arvados-python-client" "sdk/python" "python3"
-
 # The Docker image cleaner
 fpm_build_virtualenv "arvados-docker-cleaner" "services/dockercleaner" "python3"
 
index 113404338a91008c46647685c1a471393f78e239..721269b88eeba295d570838687297a0b634ba806 100755 (executable)
@@ -127,7 +127,7 @@ sdk/go/blockdigest
 sdk/go/asyncbuf
 sdk/go/stats
 sdk/go/crunchrunner
-sdk/cwl
+sdk/cwl:py3
 sdk/R
 sdk/java-v2
 tools/sync-groups
@@ -1004,7 +1004,6 @@ pythonstuff=(
     sdk/pam
     sdk/python
     sdk/python:py3
-    sdk/cwl
     sdk/cwl:py3
     services/dockercleaner:py3
     services/fuse
@@ -1282,7 +1281,8 @@ else
                         ${verb}_${target}
                         ;;
                     *)
-                        testargs["$target"]="${opts}"
+                       argstarget=${target%:py3}
+                        testargs["$argstarget"]="${opts}"
                         tt="${testfuncargs[${target}]}"
                         tt="${tt:-$target}"
                         do_$verb $tt
index 8ef7e6ac1f921aa3559495b28193b070303321d2..9f50013e39841517fb486f35d226ea344b359946 100644 (file)
@@ -546,14 +546,17 @@ func (super *Supervisor) autofillConfig(cfg *arvados.Config) error {
                if svc == &cluster.Services.DispatchCloud && super.ClusterType == "test" {
                        continue
                }
-               if svc.ExternalURL.Host == "" && (svc == &cluster.Services.Controller ||
-                       svc == &cluster.Services.GitHTTP ||
-                       svc == &cluster.Services.Keepproxy ||
-                       svc == &cluster.Services.WebDAV ||
-                       svc == &cluster.Services.WebDAVDownload ||
-                       svc == &cluster.Services.Websocket ||
-                       svc == &cluster.Services.Workbench1) {
-                       svc.ExternalURL = arvados.URL{Scheme: "https", Host: fmt.Sprintf("%s:%s", super.ListenHost, nextPort(super.ListenHost))}
+               if svc.ExternalURL.Host == "" {
+                       if svc == &cluster.Services.Controller ||
+                               svc == &cluster.Services.GitHTTP ||
+                               svc == &cluster.Services.Keepproxy ||
+                               svc == &cluster.Services.WebDAV ||
+                               svc == &cluster.Services.WebDAVDownload ||
+                               svc == &cluster.Services.Workbench1 {
+                               svc.ExternalURL = arvados.URL{Scheme: "https", Host: fmt.Sprintf("%s:%s", super.ListenHost, nextPort(super.ListenHost))}
+                       } else if svc == &cluster.Services.Websocket {
+                               svc.ExternalURL = arvados.URL{Scheme: "wss", Host: fmt.Sprintf("%s:%s", super.ListenHost, nextPort(super.ListenHost))}
+                       }
                }
                if len(svc.InternalURLs) == 0 {
                        svc.InternalURLs = map[arvados.URL]arvados.ServiceInstance{
index 2b2acd5688ff3475c24af8242ae0a7c5ef3ffcd9..3dd04040ab5d728b5eac21bab601225135ce810e 100644 (file)
@@ -16,43 +16,6 @@ import sys
 import re
 import pkg_resources  # part of setuptools
 
-### begin monkey patch ###
-# Monkey patch solution for bug #16169
-#
-# There is a bug in upstream cwltool where the version updater needs
-# to replace the document fragments in the loader index with the
-# updated ones, but actually it only does it for the root document.
-# Normally we just fix the bug in upstream but that's challenging
-# because current cwltool dropped support for Python 2.7 and we're
-# still supporting py2 in Arvados 2.0 (although py2 support will most
-# likely be dropped in Arvados 2.1).  Making a bugfix fork comes with
-# its own complications (it would need to be added to PyPi) so monkey
-# patching is the least disruptive fix (and is relatively safe because
-# our cwltool dependency is pinned to a specific version).  This
-# should be removed as soon as a bugfix goes into upstream cwltool and
-# we upgrade to it.
-#
-import cwltool.load_tool
-from cwltool.utils import visit_class
-from six.moves import urllib
-original_resolve_and_validate_document = cwltool.load_tool.resolve_and_validate_document
-def wrapped_resolve_and_validate_document(
-        loadingContext,            # type: LoadingContext
-        workflowobj,               # type: Union[CommentedMap, CommentedSeq]
-        uri,                       # type: Text
-        preprocess_only=False,     # type: bool
-        skip_schemas=None,         # type: Optional[bool]
-        ):
-    loadingContext, uri = original_resolve_and_validate_document(loadingContext, workflowobj, uri, preprocess_only, skip_schemas)
-    if loadingContext.do_update in (True, None):
-        fileuri = urllib.parse.urldefrag(uri)[0]
-        def update_index(pr):
-            loadingContext.loader.idx[pr["id"]] = pr
-        visit_class(loadingContext.loader.idx[fileuri], ("CommandLineTool", "Workflow", "ExpressionTool"), update_index)
-    return loadingContext, uri
-cwltool.load_tool.resolve_and_validate_document = wrapped_resolve_and_validate_document
-### end monkey patch ###
-
 from schema_salad.sourceline import SourceLine
 import schema_salad.validate as validate
 import cwltool.main
index 604ad39de78877b96121fae730eb12ea0da080d6..ddd3c00764c7b0fb42fe97adf50622bd1b23e9cb 100644 (file)
@@ -11,9 +11,10 @@ import copy
 import logging
 
 from schema_salad.sourceline import SourceLine, cmap
+import schema_salad.ref_resolver
 
 from cwltool.pack import pack
-from cwltool.load_tool import fetch_document
+from cwltool.load_tool import fetch_document, resolve_and_validate_document
 from cwltool.process import shortname
 from cwltool.workflow import Workflow, WorkflowException, WorkflowStep
 from cwltool.pathmapper import adjustFileObjs, adjustDirObjs, visit_class
@@ -172,7 +173,6 @@ class ArvadosWorkflow(Workflow):
         with SourceLine(self.tool, None, WorkflowException, logger.isEnabledFor(logging.DEBUG)):
             if "id" not in self.tool:
                 raise WorkflowException("%s object must have 'id'" % (self.tool["class"]))
-        document_loader, workflowobj, uri = (self.doc_loader, self.doc_loader.fetch(self.tool["id"]), self.tool["id"])
 
         discover_secondary_files(self.arvrunner.fs_access, builder,
                                  self.tool["inputs"], joborder)
@@ -180,18 +180,22 @@ class ArvadosWorkflow(Workflow):
         with Perf(metrics, "subworkflow upload_deps"):
             upload_dependencies(self.arvrunner,
                                 os.path.basename(joborder.get("id", "#")),
-                                document_loader,
+                                self.doc_loader,
                                 joborder,
                                 joborder.get("id", "#"),
                                 False)
 
             if self.wf_pdh is None:
-                workflowobj["requirements"] = dedup_reqs(self.requirements)
-                workflowobj["hints"] = dedup_reqs(self.hints)
+                packed = pack(self.loadingContext, self.tool["id"], loader=self.doc_loader)
 
-                packed = pack(document_loader, workflowobj, uri, self.metadata)
+                for p in packed["$graph"]:
+                    if p["id"] == "#main":
+                        p["requirements"] = dedup_reqs(self.requirements)
+                        p["hints"] = dedup_reqs(self.hints)
 
                 def visit(item):
+                    if "requirements" in item:
+                        item["requirements"] = [i for i in item["requirements"] if i["class"] != "DockerRequirement"]
                     for t in ("hints", "requirements"):
                         if t not in item:
                             continue
@@ -211,9 +215,6 @@ class ArvadosWorkflow(Workflow):
                                                     raise WorkflowException("Non-top-level ResourceRequirement in single container cannot have expressions")
                                 if not dyn:
                                     self.static_resource_req.append(req)
-                            if req["class"] == "DockerRequirement":
-                                if "http://arvados.org/cwl#dockerCollectionPDH" in req:
-                                    del req["http://arvados.org/cwl#dockerCollectionPDH"]
 
                 visit_class(packed["$graph"], ("Workflow", "CommandLineTool"), visit)
 
@@ -222,9 +223,9 @@ class ArvadosWorkflow(Workflow):
 
                 upload_dependencies(self.arvrunner,
                                     runtimeContext.name,
-                                    document_loader,
+                                    self.doc_loader,
                                     packed,
-                                    uri,
+                                    self.tool["id"],
                                     False)
 
                 # Discover files/directories referenced by the
@@ -301,6 +302,10 @@ class ArvadosWorkflow(Workflow):
             if job_res_reqs[0].get("ramMin", 1024) < 128:
                 job_res_reqs[0]["ramMin"] = 128
 
+        arguments = ["--no-container", "--move-outputs", "--preserve-entire-environment", "workflow.cwl", "cwl.input.yml"]
+        if runtimeContext.debug:
+            arguments.insert(0, '--debug')
+
         wf_runner = cmap({
             "class": "CommandLineTool",
             "baseCommand": "cwltool",
@@ -320,7 +325,7 @@ class ArvadosWorkflow(Workflow):
                     }]
             }],
             "hints": self.hints,
-            "arguments": ["--no-container", "--move-outputs", "--preserve-entire-environment", "workflow.cwl#main", "cwl.input.yml"],
+            "arguments": arguments,
             "id": "#"
         })
         return ArvadosCommandTool(self.arvrunner, wf_runner, self.loadingContext).job(joborder_resolved, output_callback, runtimeContext)
index 2239e0f9df952b9ab75a7e9a96ab46953ab29f94..f0be83032415bf64e0a64c793c8b0b7e9974bdd3 100644 (file)
@@ -424,8 +424,9 @@ def packed_workflow(arvrunner, tool, merged_map):
     A "packed" workflow is one where all the components have been combined into a single document."""
 
     rewrites = {}
-    packed = pack(tool.doc_loader, tool.doc_loader.fetch(tool.tool["id"]),
-                  tool.tool["id"], tool.metadata, rewrite_out=rewrites)
+    packed = pack(arvrunner.loadingContext, tool.tool["id"],
+                  rewrite_out=rewrites,
+                  loader=tool.doc_loader)
 
     rewrite_to_orig = {v: k for k,v in viewitems(rewrites)}
 
index d4bb6d102a935780e13921fe546119244c0364e1..95730a69b11199bff6f20f7051ab91141d9c1acd 100644 (file)
@@ -39,14 +39,11 @@ setup(name='arvados-cwl-runner',
       # file to determine what version of cwltool and schema-salad to
       # build.
       install_requires=[
-          'cwltool==1.0.20190831161204',
-          'schema-salad==4.5.20190815125611',
-          'typing >= 3.6.4',
-          'ruamel.yaml >=0.15.54, <=0.15.77',
+          'cwltool==3.0.20200317203547',
+          'schema-salad==5.0.20200302192450',
           'arvados-python-client{}'.format(pysdk_dep),
           'setuptools',
-          'ciso8601 >= 2.0.0',
-          'networkx < 2.3'
+          'ciso8601 >= 2.0.0'
       ],
       extras_require={
           ':os.name=="posix" and python_version<"3"': ['subprocess32 >= 3.5.1'],
@@ -55,8 +52,8 @@ setup(name='arvados-cwl-runner',
       data_files=[
           ('share/doc/arvados-cwl-runner', ['LICENSE-2.0.txt', 'README.rst']),
       ],
+      python_requires=">=3.5, <4",
       classifiers=[
-          'Programming Language :: Python :: 2',
           'Programming Language :: Python :: 3',
       ],
       test_suite='tests',
index 39c834ed60f93da64db19db3c744c8a1279231b1..76aa43d61180f44882409ac3fb513eeb41921661 100755 (executable)
@@ -12,8 +12,9 @@ fi
 reset_container=1
 leave_running=0
 config=dev
+devcwl=0
 tag="latest"
-pythoncmd=python
+pythoncmd=python3
 suite=conformance
 runapi=containers
 
@@ -40,6 +41,10 @@ while test -n "$1" ; do
             build=1
             shift
             ;;
+        --devcwl)
+            devcwl=1
+            shift
+            ;;
         --pythoncmd)
             pythoncmd=$2
             shift ; shift
@@ -53,7 +58,7 @@ while test -n "$1" ; do
             shift ; shift
             ;;
         -h|--help)
-            echo "$0 [--no-reset-container] [--leave-running] [--config dev|localdemo] [--tag docker_tag] [--build] [--pythoncmd python(2|3)] [--suite (integration|conformance-v1.0|conformance-v1.1)]"
+            echo "$0 [--no-reset-container] [--leave-running] [--config dev|localdemo] [--tag docker_tag] [--build] [--pythoncmd python(2|3)] [--suite (integration|conformance-v1.0|conformance-*)]"
             exit
             ;;
         *)
@@ -107,11 +112,12 @@ if [[ "$suite" = "conformance-v1.0" ]] ; then
      git clone https://github.com/common-workflow-language/common-workflow-language.git
    fi
    cd common-workflow-language
-elif [[ "$suite" = "conformance-v1.1" ]] ; then
-   if ! test -d cwl-v1.1 ; then
-     git clone https://github.com/common-workflow-language/cwl-v1.1.git
+elif [[ "$suite" =~ conformance-(.*) ]] ; then
+   version=\${BASH_REMATCH[1]}
+   if ! test -d cwl-\${version} ; then
+     git clone https://github.com/common-workflow-language/cwl-\${version}.git
    fi
-   cd cwl-v1.1
+   cd cwl-\${version}
 fi
 
 if [[ "$suite" != "integration" ]] ; then
@@ -145,12 +151,18 @@ exec arvados-cwl-runner --api=containers \\\$@
 EOF2
 chmod +x /tmp/cwltest/arv-cwl-containers
 
+EXTRA=--compute-checksum
+
+if [[ $devcwl == 1 ]] ; then
+   EXTRA="\$EXTRA --enable-dev"
+fi
+
 env
 if [[ "$suite" = "integration" ]] ; then
    cd /usr/src/arvados/sdk/cwl/tests
    exec ./arvados-tests.sh $@
 else
-   exec ./run_test.sh RUNNER=/tmp/cwltest/arv-cwl-${runapi} EXTRA=--compute-checksum $@
+   exec ./run_test.sh RUNNER=/tmp/cwltest/arv-cwl-${runapi} EXTRA="\$EXTRA" $@
 fi
 EOF
 
index cb6cfbadbdb00dcfe56872683b5851017eeb0f8f..d331e3552d8210aafeed636c43530114288a4239 100644 (file)
@@ -18,6 +18,7 @@ import os
 import functools
 import cwltool.process
 import cwltool.secrets
+from cwltool.update import INTERNAL_VERSION
 from schema_salad.ref_resolver import Loader
 from schema_salad.sourceline import cmap
 
@@ -60,7 +61,7 @@ class TestContainer(unittest.TestCase):
         cwltool.process._names = set()
 
     def helper(self, runner, enable_reuse=True):
-        document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("v1.1")
+        document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema(INTERNAL_VERSION)
 
         make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess,
                                          collection_cache=arvados_cwl.CollectionCache(runner.api, None, 0))
@@ -69,7 +70,7 @@ class TestContainer(unittest.TestCase):
              "basedir": "",
              "make_fs_access": make_fs_access,
              "loader": Loader({}),
-             "metadata": {"cwlVersion": "v1.1", "http://commonwl.org/cwltool#original_cwlVersion": "v1.0"}})
+             "metadata": {"cwlVersion": INTERNAL_VERSION, "http://commonwl.org/cwltool#original_cwlVersion": "v1.0"}})
         runtimeContext = arvados_cwl.context.ArvRuntimeContext(
             {"work_api": "containers",
              "basedir": "",
@@ -402,7 +403,7 @@ class TestContainer(unittest.TestCase):
         runner.api.collections().get().execute.return_value = {
             "portable_data_hash": "99999999999999999999999999999993+99"}
 
-        document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("v1.1")
+        document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema(INTERNAL_VERSION)
 
         tool = cmap({
             "inputs": [],
@@ -848,7 +849,7 @@ class TestWorkflow(unittest.TestCase):
         cwltool.process._names = set()
 
     def helper(self, runner, enable_reuse=True):
-        document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("v1.1")
+        document_loader, avsc_names, schema_metadata, metaschema_loader = cwltool.process.get_schema("v1.0")
 
         make_fs_access=functools.partial(arvados_cwl.CollectionFsAccess,
                                          collection_cache=arvados_cwl.CollectionCache(runner.api, None, 0))
@@ -863,7 +864,7 @@ class TestWorkflow(unittest.TestCase):
              "basedir": "",
              "make_fs_access": make_fs_access,
              "loader": document_loader,
-             "metadata": {"cwlVersion": "v1.1", "http://commonwl.org/cwltool#original_cwlVersion": "v1.0"},
+             "metadata": {"cwlVersion": INTERNAL_VERSION, "http://commonwl.org/cwltool#original_cwlVersion": "v1.0"},
              "construct_tool_object": runner.arv_make_tool})
         runtimeContext = arvados_cwl.context.ArvRuntimeContext(
             {"work_api": "containers",
@@ -928,7 +929,7 @@ class TestWorkflow(unittest.TestCase):
                     "--no-container",
                     "--move-outputs",
                     "--preserve-entire-environment",
-                    "workflow.cwl#main",
+                    "workflow.cwl",
                     "cwl.input.yml"
                 ],
                 "container_image": "99999999999999999999999999999993+99",
@@ -1076,7 +1077,7 @@ class TestWorkflow(unittest.TestCase):
                     u'--no-container',
                     u'--move-outputs',
                     u'--preserve-entire-environment',
-                    u'workflow.cwl#main',
+                    u'workflow.cwl',
                     u'cwl.input.yml'
                 ],
                 'use_existing': True,
index 397ae142253d26b41d11aee03586fbc3e352bb31..562664c698b34df87ec2f19eb64d867ec5461698 100644 (file)
@@ -18,6 +18,7 @@ import mock
 import sys
 import unittest
 import cwltool.process
+import re
 
 from io import BytesIO
 
@@ -1312,7 +1313,7 @@ class TestSubmit(unittest.TestCase):
 
                 self.assertEqual(exited, 1)
                 self.assertRegexpMatches(
-                    capture_stderr.getvalue(),
+                    re.sub(r'[ \n]+', ' ', capture_stderr.getvalue()),
                     r"Expected collection uuid zzzzz-4zz18-zzzzzzzzzzzzzzz to be 99999999999999999999999999999998\+99 but API server reported 99999999999999999999999999999997\+99")
             finally:
                 cwltool_logger.removeHandler(stderr_logger)
index 7a07de5bd23885b25a4627b6260b0e04ac82daba..c54e1707ff0ef7fdb741305ff6804bb19cfdbaac 100644 (file)
@@ -5,8 +5,11 @@
 {
   "$graph": [
     {
+      "$namespaces": {
+        "arv": "http://arvados.org/cwl#"
+      },
       "class": "Workflow",
-      "cwlVersion": "v1.1",
+      "cwlVersion": "v1.0",
       "hints": [],
       "id": "#main",
       "inputs": [
           "run": {
             "baseCommand": "sleep",
             "class": "CommandLineTool",
-            "id": "#main/sleep1/run/subtool",
+            "id": "#main/sleep1/subtool",
             "inputs": [
               {
-                "id": "#main/sleep1/run/subtool/sleeptime",
+                "id": "#main/sleep1/subtool/sleeptime",
                 "inputBinding": {
                   "position": 1
                 },
@@ -71,7 +74,7 @@
             ],
             "outputs": [
               {
-                "id": "#main/sleep1/run/subtool/out",
+                "id": "#main/sleep1/subtool/out",
                 "outputBinding": {
                   "outputEval": "out"
                 },
@@ -83,5 +86,5 @@
       ]
     }
   ],
-  "cwlVersion": "v1.1"
-}
+  "cwlVersion": "v1.0"
+}
\ No newline at end of file
diff --git a/sdk/java-v2/src/main/java/org/arvados/client/api/client/LinksApiClient.java b/sdk/java-v2/src/main/java/org/arvados/client/api/client/LinksApiClient.java
new file mode 100644 (file)
index 0000000..c64e1fb
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) The Arvados Authors. All rights reserved.
+ *
+ * SPDX-License-Identifier: AGPL-3.0 OR Apache-2.0
+ *
+ */
+
+package org.arvados.client.api.client;
+
+import org.arvados.client.api.model.Link;
+import org.arvados.client.api.model.LinkList;
+import org.arvados.client.config.ConfigProvider;
+
+public class LinksApiClient extends BaseStandardApiClient<Link, LinkList> {
+
+    private static final String RESOURCE = "links";
+
+    public LinksApiClient(ConfigProvider config) {
+        super(config);
+    }
+
+    @Override
+    String getResource() {
+        return RESOURCE;
+    }
+
+    @Override
+    Class<Link> getType() {
+        return Link.class;
+    }
+
+    @Override
+    Class<LinkList> getListType() {
+        return LinkList.class;
+    }
+}
diff --git a/sdk/java-v2/src/main/java/org/arvados/client/api/model/Link.java b/sdk/java-v2/src/main/java/org/arvados/client/api/model/Link.java
new file mode 100644 (file)
index 0000000..a24f02a
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) The Arvados Authors. All rights reserved.
+ *
+ * SPDX-License-Identifier: AGPL-3.0 OR Apache-2.0
+ *
+ */
+
+package org.arvados.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonPropertyOrder({ "name", "head_kind", "head_uuid", "link_class" })
+public class Link extends Item {
+
+    @JsonProperty("name")
+    private String name;
+    @JsonProperty("head_kind")
+    private String headKind;
+    @JsonProperty("head_uuid")
+    private String headUuid;
+    @JsonProperty("link_class")
+    private String linkClass;
+
+    public String getName() {
+        return name;
+    }
+
+    public String getHeadKind() {
+        return headKind;
+    }
+
+    public String getHeadUuid() {
+        return headUuid;
+    }
+
+    public String getLinkClass() {
+        return linkClass;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setHeadKind(String headKind) {
+        this.headKind = headKind;
+    }
+
+    public void setHeadUuid(String headUuid) {
+        this.headUuid = headUuid;
+    }
+
+    public void setLinkClass(String linkClass) {
+        this.linkClass = linkClass;
+    }
+
+}
diff --git a/sdk/java-v2/src/main/java/org/arvados/client/api/model/LinkList.java b/sdk/java-v2/src/main/java/org/arvados/client/api/model/LinkList.java
new file mode 100644 (file)
index 0000000..5bccbe5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) The Arvados Authors. All rights reserved.
+ *
+ * SPDX-License-Identifier: AGPL-3.0 OR Apache-2.0
+ *
+ */
+
+package org.arvados.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+import java.util.List;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonPropertyOrder({ "items" })
+public class LinkList extends ItemList {
+
+    @JsonProperty("items")
+    private List<Link> items;
+
+    public List<Link> getItems() {
+        return this.items;
+    }
+
+    public void setItems(List<Link> items) {
+        this.items = items;
+    }
+}
index 0ba3f0a483fac785a6d080adf5ea494c480d02b3..5f12b62eebe28bc97a874b907caff735dace3151 100755 (executable)
@@ -8,8 +8,8 @@
 #
 # By default, arv-copy recursively copies any dependent objects
 # necessary to make the object functional in the new instance
-# (e.g. for a pipeline instance, arv-copy copies the pipeline
-# template, input collection, docker images, git repositories). If
+# (e.g. for a workflow, arv-copy copies the workflow,
+# input collections, and docker images). If
 # --no-recursive is given, arv-copy copies only the single record
 # identified by object-uuid.
 #
@@ -86,9 +86,6 @@ def main():
     copy_opts.add_argument(
         '-f', '--force', dest='force', action='store_true',
         help='Perform copy even if the object appears to exist at the remote destination.')
-    copy_opts.add_argument(
-        '--force-filters', action='store_true', default=False,
-        help="Copy pipeline template filters verbatim, even if they act differently on the destination cluster.")
     copy_opts.add_argument(
         '--src', dest='source_arvados', required=True,
         help='The name of the source Arvados instance (required) - points at an Arvados config file. May be either a pathname to a config file, or (for example) "foo" as shorthand for $HOME/.config/arvados/foo.conf.')
@@ -101,18 +98,9 @@ def main():
     copy_opts.add_argument(
         '--no-recursive', dest='recursive', action='store_false',
         help='Do not copy any dependencies. NOTE: if this option is given, the copied object will need to be updated manually in order to be functional.')
-    copy_opts.add_argument(
-        '--dst-git-repo', dest='dst_git_repo',
-        help='The name of the destination git repository. Required when copying a pipeline recursively.')
     copy_opts.add_argument(
         '--project-uuid', dest='project_uuid',
-        help='The UUID of the project at the destination to which the pipeline should be copied.')
-    copy_opts.add_argument(
-        '--allow-git-http-src', action="store_true",
-        help='Allow cloning git repositories over insecure http')
-    copy_opts.add_argument(
-        '--allow-git-http-dst', action="store_true",
-        help='Allow pushing git repositories over insecure http')
+        help='The UUID of the project at the destination to which the collection or workflow should be copied.')
 
     copy_opts.add_argument(
         'object_uuid',
@@ -121,7 +109,7 @@ def main():
     copy_opts.set_defaults(recursive=True)
 
     parser = argparse.ArgumentParser(
-        description='Copy a pipeline instance, template, workflow, or collection from one Arvados instance to another.',
+        description='Copy a workflow or collection from one Arvados instance to another.',
         parents=[copy_opts, arv_cmd.retry_opt])
     args = parser.parse_args()
 
@@ -144,15 +132,6 @@ def main():
         result = copy_collection(args.object_uuid,
                                  src_arv, dst_arv,
                                  args)
-    elif t == 'PipelineInstance':
-        set_src_owner_uuid(src_arv.pipeline_instances(), args.object_uuid, args)
-        result = copy_pipeline_instance(args.object_uuid,
-                                        src_arv, dst_arv,
-                                        args)
-    elif t == 'PipelineTemplate':
-        set_src_owner_uuid(src_arv.pipeline_templates(), args.object_uuid, args)
-        result = copy_pipeline_template(args.object_uuid,
-                                        src_arv, dst_arv, args)
     elif t == 'Workflow':
         set_src_owner_uuid(src_arv.workflows(), args.object_uuid, args)
         result = copy_workflow(args.object_uuid, src_arv, dst_arv, args)
@@ -225,67 +204,6 @@ def check_git_availability():
     except Exception:
         abort('git command is not available. Please ensure git is installed.')
 
-# copy_pipeline_instance(pi_uuid, src, dst, args)
-#
-#    Copies a pipeline instance identified by pi_uuid from src to dst.
-#
-#    If the args.recursive option is set:
-#      1. Copies all input collections
-#           * For each component in the pipeline, include all collections
-#             listed as job dependencies for that component)
-#      2. Copy docker images
-#      3. Copy git repositories
-#      4. Copy the pipeline template
-#
-#    The only changes made to the copied pipeline instance are:
-#      1. The original pipeline instance UUID is preserved in
-#         the 'properties' hash as 'copied_from_pipeline_instance_uuid'.
-#      2. The pipeline_template_uuid is changed to the new template uuid.
-#      3. The owner_uuid of the instance is changed to the user who
-#         copied it.
-#
-def copy_pipeline_instance(pi_uuid, src, dst, args):
-    # Fetch the pipeline instance record.
-    pi = src.pipeline_instances().get(uuid=pi_uuid).execute(num_retries=args.retries)
-
-    if args.recursive:
-        check_git_availability()
-
-        if not args.dst_git_repo:
-            abort('--dst-git-repo is required when copying a pipeline recursively.')
-        # Copy the pipeline template and save the copied template.
-        if pi.get('pipeline_template_uuid', None):
-            pt = copy_pipeline_template(pi['pipeline_template_uuid'],
-                                        src, dst, args)
-
-        # Copy input collections, docker images and git repos.
-        pi = copy_collections(pi, src, dst, args)
-        copy_git_repos(pi, src, dst, args.dst_git_repo, args)
-        copy_docker_images(pi, src, dst, args)
-
-        # Update the fields of the pipeline instance with the copied
-        # pipeline template.
-        if pi.get('pipeline_template_uuid', None):
-            pi['pipeline_template_uuid'] = pt['uuid']
-
-    else:
-        # not recursive
-        logger.info("Copying only pipeline instance %s.", pi_uuid)
-        logger.info("You are responsible for making sure all pipeline dependencies have been updated.")
-
-    # Update the pipeline instance properties, and create the new
-    # instance at dst.
-    pi['properties']['copied_from_pipeline_instance_uuid'] = pi_uuid
-    pi['description'] = "Pipeline copied from {}\n\n{}".format(
-        pi_uuid,
-        pi['description'] if pi.get('description', None) else '')
-
-    pi['owner_uuid'] = args.project_uuid
-
-    del pi['uuid']
-
-    new_pi = dst.pipeline_instances().create(body=pi, ensure_unique_name=True).execute(num_retries=args.retries)
-    return new_pi
 
 def filter_iter(arg):
     """Iterate a filter string-or-list.
@@ -340,82 +258,6 @@ def exception_handler(handler, *exc_types):
     except exc_types as error:
         handler(error)
 
-def migrate_components_filters(template_components, dst_git_repo):
-    """Update template component filters in-place for the destination.
-
-    template_components is a dictionary of components in a pipeline template.
-    This method walks over each component's filters, and updates them to have
-    identical semantics on the destination cluster.  It returns a list of
-    error strings that describe what filters could not be updated safely.
-
-    dst_git_repo is the name of the destination Git repository, which can
-    be None if that is not known.
-    """
-    errors = []
-    for cname, cspec in template_components.items():
-        def add_error(errmsg):
-            errors.append("{}: {}".format(cname, errmsg))
-        if not isinstance(cspec, dict):
-            add_error("value is not a component definition")
-            continue
-        src_repository = cspec.get('repository')
-        filters = cspec.get('filters', [])
-        if not isinstance(filters, list):
-            add_error("filters are not a list")
-            continue
-        for cfilter in filters:
-            if not (isinstance(cfilter, list) and (len(cfilter) == 3)):
-                add_error("malformed filter {!r}".format(cfilter))
-                continue
-            if attr_filtered(cfilter, 'repository'):
-                with exception_handler(add_error, ValueError):
-                    migrate_repository_filter(cfilter, src_repository, dst_git_repo)
-            if attr_filtered(cfilter, 'script_version'):
-                with exception_handler(add_error, ValueError):
-                    migrate_script_version_filter(cfilter)
-    return errors
-
-# copy_pipeline_template(pt_uuid, src, dst, args)
-#
-#    Copies a pipeline template identified by pt_uuid from src to dst.
-#
-#    If args.recursive is True, also copy any collections, docker
-#    images and git repositories that this template references.
-#
-#    The owner_uuid of the new template is changed to that of the user
-#    who copied the template.
-#
-#    Returns the copied pipeline template object.
-#
-def copy_pipeline_template(pt_uuid, src, dst, args):
-    # fetch the pipeline template from the source instance
-    pt = src.pipeline_templates().get(uuid=pt_uuid).execute(num_retries=args.retries)
-
-    if not args.force_filters:
-        filter_errors = migrate_components_filters(pt['components'], args.dst_git_repo)
-        if filter_errors:
-            abort("Template filters cannot be copied safely. Use --force-filters to copy anyway.\n" +
-                  "\n".join(filter_errors))
-
-    if args.recursive:
-        check_git_availability()
-
-        if not args.dst_git_repo:
-            abort('--dst-git-repo is required when copying a pipeline recursively.')
-        # Copy input collections, docker images and git repos.
-        pt = copy_collections(pt, src, dst, args)
-        copy_git_repos(pt, src, dst, args.dst_git_repo, args)
-        copy_docker_images(pt, src, dst, args)
-
-    pt['description'] = "Pipeline template copied from {}\n\n{}".format(
-        pt_uuid,
-        pt['description'] if pt.get('description', None) else '')
-    pt['name'] = "{} copied from {}".format(pt.get('name', ''), pt_uuid)
-    del pt['uuid']
-
-    pt['owner_uuid'] = args.project_uuid
-
-    return dst.pipeline_templates().create(body=pt, ensure_unique_name=True).execute(num_retries=args.retries)
 
 # copy_workflow(wf_uuid, src, dst, args)
 #
@@ -518,53 +360,6 @@ def copy_collections(obj, src, dst, args):
         return type(obj)(copy_collections(v, src, dst, args) for v in obj)
     return obj
 
-def migrate_jobspec(jobspec, src, dst, dst_repo, args):
-    """Copy a job's script to the destination repository, and update its record.
-
-    Given a jobspec dictionary, this function finds the referenced script from
-    src and copies it to dst and dst_repo.  It also updates jobspec in place to
-    refer to names on the destination.
-    """
-    repo = jobspec.get('repository')
-    if repo is None:
-        return
-    # script_version is the "script_version" parameter from the source
-    # component or job.  If no script_version was supplied in the
-    # component or job, it is a mistake in the pipeline, but for the
-    # purposes of copying the repository, default to "master".
-    script_version = jobspec.get('script_version') or 'master'
-    script_key = (repo, script_version)
-    if script_key not in scripts_copied:
-        copy_git_repo(repo, src, dst, dst_repo, script_version, args)
-        scripts_copied.add(script_key)
-    jobspec['repository'] = dst_repo
-    repo_dir = local_repo_dir[repo]
-    for version_key in ['script_version', 'supplied_script_version']:
-        if version_key in jobspec:
-            jobspec[version_key] = git_rev_parse(jobspec[version_key], repo_dir)
-
-# copy_git_repos(p, src, dst, dst_repo, args)
-#
-#    Copies all git repositories referenced by pipeline instance or
-#    template 'p' from src to dst.
-#
-#    For each component c in the pipeline:
-#      * Copy git repositories named in c['repository'] and c['job']['repository'] if present
-#      * Rename script versions:
-#          * c['script_version']
-#          * c['job']['script_version']
-#          * c['job']['supplied_script_version']
-#        to the commit hashes they resolve to, since any symbolic
-#        names (tags, branches) are not preserved in the destination repo.
-#
-#    The pipeline object is updated in place with the new repository
-#    names.  The return value is undefined.
-#
-def copy_git_repos(p, src, dst, dst_repo, args):
-    for component in p['components'].values():
-        migrate_jobspec(component, src, dst, dst_repo, args)
-        if 'job' in component:
-            migrate_jobspec(component['job'], src, dst, dst_repo, args)
 
 def total_collection_size(manifest_text):
     """Return the total number of bytes in this collection (excluding
@@ -590,17 +385,16 @@ def create_collection_from(c, src, dst, args):
     available."""
 
     collection_uuid = c['uuid']
-    del c['uuid']
-
-    if not c["name"]:
-        c['name'] = "copied from " + collection_uuid
+    body = {}
+    for d in ('description', 'manifest_text', 'name', 'portable_data_hash', 'properties'):
+        body[d] = c[d]
 
-    if 'properties' in c:
-        del c['properties']
+    if not body["name"]:
+        body['name'] = "copied from " + collection_uuid
 
-    c['owner_uuid'] = args.project_uuid
+    body['owner_uuid'] = args.project_uuid
 
-    dst_collection = dst.collections().create(body=c, ensure_unique_name=True).execute(num_retries=args.retries)
+    dst_collection = dst.collections().create(body=body, ensure_unique_name=True).execute(num_retries=args.retries)
 
     # Create docker_image_repo+tag and docker_image_hash links
     # at the destination.
@@ -665,7 +459,7 @@ def copy_collection(obj_uuid, src, dst, args):
             c = items[0]
         if not c:
             # See if there is a collection that's in the same project
-            # as the root item (usually a pipeline) being copied.
+            # as the root item (usually a workflow) being copied.
             for i in items:
                 if i.get("owner_uuid") == src_owner_uuid and i.get("name"):
                     c = i
@@ -815,68 +609,6 @@ def select_git_url(api, repo_name, retries, allow_insecure_http, allow_insecure_
     return (git_url, git_config)
 
 
-# copy_git_repo(src_git_repo, src, dst, dst_git_repo, script_version, args)
-#
-#    Copies commits from git repository 'src_git_repo' on Arvados
-#    instance 'src' to 'dst_git_repo' on 'dst'.  Both src_git_repo
-#    and dst_git_repo are repository names, not UUIDs (i.e. "arvados"
-#    or "jsmith")
-#
-#    All commits will be copied to a destination branch named for the
-#    source repository URL.
-#
-#    The destination repository must already exist.
-#
-#    The user running this command must be authenticated
-#    to both repositories.
-#
-def copy_git_repo(src_git_repo, src, dst, dst_git_repo, script_version, args):
-    # Identify the fetch and push URLs for the git repositories.
-
-    (src_git_url, src_git_config) = select_git_url(src, src_git_repo, args.retries, args.allow_git_http_src, "--allow-git-http-src")
-    (dst_git_url, dst_git_config) = select_git_url(dst, dst_git_repo, args.retries, args.allow_git_http_dst, "--allow-git-http-dst")
-
-    logger.debug('src_git_url: {}'.format(src_git_url))
-    logger.debug('dst_git_url: {}'.format(dst_git_url))
-
-    dst_branch = re.sub(r'\W+', '_', "{}_{}".format(src_git_url, script_version))
-
-    # Copy git commits from src repo to dst repo.
-    if src_git_repo not in local_repo_dir:
-        local_repo_dir[src_git_repo] = tempfile.mkdtemp()
-        arvados.util.run_command(
-            ["git"] + src_git_config + ["clone", "--bare", src_git_url,
-             local_repo_dir[src_git_repo]],
-            cwd=os.path.dirname(local_repo_dir[src_git_repo]),
-            env={"HOME": os.environ["HOME"],
-                 "ARVADOS_API_TOKEN": src.api_token,
-                 "GIT_ASKPASS": "/bin/false"})
-        arvados.util.run_command(
-            ["git", "remote", "add", "dst", dst_git_url],
-            cwd=local_repo_dir[src_git_repo])
-    arvados.util.run_command(
-        ["git", "branch", dst_branch, script_version],
-        cwd=local_repo_dir[src_git_repo])
-    arvados.util.run_command(["git"] + dst_git_config + ["push", "dst", dst_branch],
-                             cwd=local_repo_dir[src_git_repo],
-                             env={"HOME": os.environ["HOME"],
-                                  "ARVADOS_API_TOKEN": dst.api_token,
-                                  "GIT_ASKPASS": "/bin/false"})
-
-def copy_docker_images(pipeline, src, dst, args):
-    """Copy any docker images named in the pipeline components'
-    runtime_constraints field from src to dst."""
-
-    logger.debug('copy_docker_images: {}'.format(pipeline['uuid']))
-    for c_name, c_info in pipeline['components'].items():
-        if ('runtime_constraints' in c_info and
-            'docker_image' in c_info['runtime_constraints']):
-            copy_docker_image(
-                c_info['runtime_constraints']['docker_image'],
-                c_info['runtime_constraints'].get('docker_image_tag', 'latest'),
-                src, dst, args)
-
-
 def copy_docker_image(docker_image, docker_image_tag, src, dst, args):
     """Copy the docker image identified by docker_image and
     docker_image_tag from src to dst. Create appropriate
@@ -917,7 +649,7 @@ def git_rev_parse(rev, repo):
 #    the second field of the uuid.  This function consults the api's
 #    schema to identify the object class.
 #
-#    It returns a string such as 'Collection', 'PipelineInstance', etc.
+#    It returns a string such as 'Collection', 'Workflow', etc.
 #
 #    Special case: if handed a Keep locator hash, return 'Collection'.
 #
index ff68e2a7fd8888d10d56b96e13a5a9bf2690a177..a726b49fe3814a7d51d7fcb32420ad98abb4150d 100644 (file)
@@ -51,7 +51,7 @@ setup(name='arvados-python-client',
           'google-api-python-client >=1.6.2, <1.7',
           'httplib2 >=0.9.2',
           'pycurl >=7.19.5.1',
-          'ruamel.yaml >=0.15.54, <=0.15.77',
+          'ruamel.yaml >=0.15.54, <=0.16.5',
           'setuptools',
           'ws4py >=0.4.2',
       ],
index 2c780d4771724aa822247c248f51fedc8a4b4dd5..24d5ad5b64982c1e5d10e8f218336978d1e2b857 100644 (file)
@@ -157,7 +157,7 @@ GEM
     net-ssh-gateway (2.0.0)
       net-ssh (>= 4.0.0)
     nio4r (2.3.1)
-    nokogiri (1.10.2)
+    nokogiri (1.10.8)
       mini_portile2 (~> 2.4.0)
     oauth2 (1.4.1)
       faraday (>= 0.8, < 0.16.0)
@@ -213,7 +213,7 @@ GEM
       method_source
       rake (>= 0.8.7)
       thor (>= 0.18.1, < 2.0)
-    rake (12.3.2)
+    rake (13.0.1)
     rb-fsevent (0.10.3)
     rb-inotify (0.9.10)
       ffi (>= 0.5.0, < 2)