Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verify sha256sum checksums in planemo dependency_script #538

Merged
merged 4 commits into from
Aug 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions planemo/commands/cmd_dependency_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@
fi
# Set full strict mode now, side stepping case $INSTALL_DIR not setup.
set -euo pipefail
export DOWNLOAD_CACHE=`(cd "$DOWNLOAD_CACHE"; pwd)`
export DOWNLOAD_CACHE="${DOWNLOAD_CACHE:-./download_cache}"
if [[ ! -d $DOWNLOAD_CACHE ]]
then
mkdir -p $DOWNLOAD_CACHE
fi
# Make this into an absolute path
export DOWNLOAD_CACHE=`(cd "$DOWNLOAD_CACHE"; pwd)`
echo "Using $DOWNLOAD_CACHE for cached downloads."
export INSTALL_DIR=`(cd "$INSTALL_DIR"; pwd)`
echo "Using $INSTALL_DIR for the installed files."
Expand Down Expand Up @@ -203,7 +205,7 @@ def cli(ctx, paths, recursive=False, fail_fast=True, download_cache=None):
# Effectively using this as a global variable, refactor this
# once using a visitor pattern instead of action.to_bash()
os.environ["DOWNLOAD_CACHE"] = os.path.abspath(download_cache)
print("Using $DOWNLOAD_CACHE=%r" % os.environ["DOWNLOAD_CACHE"])
print("Using $DOWNLOAD_CACHE=%r" % os.environ["DOWNLOAD_CACHE"])
failed = False
with open("env.sh", "w") as env_sh_handle:
with open("dep_install.sh", "w") as install_handle:
Expand Down
39 changes: 30 additions & 9 deletions planemo/shed2tap/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from six import iteritems

import os
import sys
import subprocess
import tarfile
import zipfile
from ftplib import all_errors as FTPErrors # tuple of exceptions
Expand Down Expand Up @@ -395,21 +397,24 @@ def _common_prefix(folders):
return common_prefix


def _cache_download(url, filename):
def _cache_download(url, filename, sha256sum=None):
"""Returns local path to cached copy of URL using given filename."""
try:
cache = os.environ["DOWNLOAD_CACHE"]
except KeyError:
# TODO - expose this as a command line option
raise ValueError("Dependencies cache location $DOWNLOAD_CACHE not set.")

if not os.path.isdir(cache):
os.mkdir(cache)

local = os.path.join(cache, filename)

if not os.path.isfile(local):
# Must download it...
try:
import sys # TODO - log this nicely...
sys.stderr.write("Downloading %s\n" % url)
# TODO - log this nicely...
sys.stderr.write("Downloading %s to %r\n" % (url, local))
urlretrieve(url, local)
except URLError:
# Most likely server is down, could be bad URL in XML action:
Expand All @@ -418,10 +423,17 @@ def _cache_download(url, filename):
# Most likely server is down, could be bad URL in XML action:
raise RuntimeError("Unable to download %s" % url)

if sha256sum:
# TODO - log this nicely...
sys.stderr.write("Verifying checksum for %s\n" % filename)
filehash = subprocess.check_output(['shasum', '-a', '256', local])[0:64].strip()
if filehash != sha256sum:
raise RuntimeError("Checksum failure for %s, got %r but wanted %r" % (local, filehash, sha256sum))

return local


def _determine_compressed_file_folder(url, downloaded_filename):
def _determine_compressed_file_folder(url, downloaded_filename, sha256sum=None):
"""Determine how to decompress the file & its directory structure.

Returns a list of shell commands. Consider this example where the
Expand All @@ -442,7 +454,8 @@ def _determine_compressed_file_folder(url, downloaded_filename):
how to decompress the file.
"""
answer = []
local = _cache_download(url, downloaded_filename)

local = _cache_download(url, downloaded_filename, sha256sum)

if tarfile.is_tarfile(local):
folders = _tar_folders(local)
Expand Down Expand Up @@ -477,7 +490,7 @@ def _determine_compressed_file_folder(url, downloaded_filename):
return answer


def _commands_to_download_and_extract(url, target_filename=None):
def _commands_to_download_and_extract(url, target_filename=None, sha256sum=None):
# TODO - Include checksum validation here?
if target_filename:
downloaded_filename = target_filename
Expand All @@ -504,7 +517,13 @@ def _commands_to_download_and_extract(url, target_filename=None):
' ln -s "$DOWNLOAD_CACHE/%s" "%s"' % (downloaded_filename, downloaded_filename),
'fi',
]
answer.extend(_determine_compressed_file_folder(url, downloaded_filename))

if sha256sum:
# Note double space between checksum and filename
answer.append('echo "%s %s" | shasum -a 256 -c -' % (sha256sum, downloaded_filename))

# Now should we unpack the tar-ball etc?
answer.extend(_determine_compressed_file_folder(url, downloaded_filename, sha256sum))
return answer, []


Expand All @@ -515,12 +534,13 @@ class DownloadByUrlAction(BaseAction):
def __init__(self, elem):
self.url = elem.text.strip()
assert self.url
self.sha256sum = elem.attrib.get("sha256sum", None)

def to_bash(self):
# See class DownloadByUrl in Galaxy,
# lib/tool_shed/galaxy_install/tool_dependencies/recipe/step_handler.py
# Do we need to worry about target_filename here?
return _commands_to_download_and_extract(self.url)
return _commands_to_download_and_extract(self.url, sha256sum=self.sha256sum)


class DownloadFileAction(BaseAction):
Expand All @@ -530,10 +550,11 @@ class DownloadFileAction(BaseAction):
def __init__(self, elem):
self.url = elem.text.strip()
self.extract = asbool(elem.attrib.get("extract", False))
self.sha256sum = elem.attrib.get("sha256sum", None)

def to_bash(self):
if self.extract:
return _commands_to_download_and_extract(self.url)
return _commands_to_download_and_extract(self.url, sha256sum=self.sha256sum)
else:
return ['wget %s' % self.url], []

Expand Down