Skip to content

Instantly share code, notes, and snippets.

@peterjc

peterjc/shed_diff

Last active Aug 29, 2015
Embed
What would you like to do?
Galaxy Tool Shed diff command
#!/usr/bin/env python
"""Galaxy Tool Shed diff command."""
import sys
import os
import subprocess
import tempfile
from optparse import OptionParser
VERSION = "v0.0.1"
if "-v" in sys.argv or "--version" in sys.argv:
print(VERSION)
sys.exit(0)
def stop_err(msg, err=1):
sys.stderr.write(msg.rstrip() + "\n")
sys.exit(err)
def run(cmd):
assert isinstance(cmd, list)
# Avoid using shell=True when we call subprocess to ensure if the Python
# script is killed, so too is the child process.
try:
child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except Exception, err:
stop_err("Error invoking command:\n%s\n\n%s\n" % (" ".join(cmd), err))
# Use .communicate as can get deadlocks with .wait(),
stdout, stderr = child.communicate()
return_code = child.returncode
if return_code:
cmd_str = " ".join(cmd)
if stderr and stdout:
stop_err("Return code %i from command:\n%s\n\n%s\n\n%s" % (return_code, cmd_str, stdout, stderr))
else:
stop_err("Return code %i from command:\n%s\n%s" % (return_code, cmd_str, stderr))
def fetch(tool_shed_url, folder):
if not tool_shed_url.startswith("http://") \
and not tool_shed_url.startswith("https://"):
stop_err("Expected an http:// or https:// URL, not %r" % tool_shed_url)
if "/view/" in tool_shed_url:
repo = tool_shed_url.replace("/view/", "/repos/")
elif "/repos/" in tool_shed_url:
repo = tool_shed_url
else:
stop_err("URL %r does not look like a ToolShed view or clone URL" % tool_shed_url)
sys.stderr.write("Fetching %s\n" % repo)
# Fetch the tool using mercurial
run(["hg", "clone", repo, folder])
# Remove the .hg subfolder (for a clean diff)
run(["rm", "-rf", "%s/.hg" % folder])
def go_remote(old, new):
# TODO - Context manager to restore working directory?
pwd = os.getcwd()
working = tempfile.mkdtemp(prefix="tool_shed_diff_")
os.chdir(working)
fetch(old, "A")
fetch(new, "B")
return_code = os.system("diff -r A B")
os.chdir(pwd)
# TODO - option to keep the temp folder?
run(["rm", "-rf", working])
return return_code
def go_local(repo):
# TODO - Context manager to restore working directory?
pwd = os.getcwd()
working = tempfile.mkdtemp(prefix="tool_shed_diff_")
os.chdir(working)
fetch(repo, "remote")
os.chdir(pwd)
errs = set()
remote_folder = os.path.join(working, "remote")
for root, dirs, files in os.walk(remote_folder):
for f in files:
remote = os.path.join(root, f)
local = os.path.join(pwd, os.path.relpath(remote, remote_folder))
assert local != remote
if os.path.isfile(local):
cmd = "diff %s %s" % (remote, local)
print(cmd)
errs.add(os.system(cmd))
else:
# Use diff -n here?
print("**** Missing %s" % local)
# TODO - option to keep the temp folder?
run(["rm", "-rf", working])
return max(errs)
#Parse Command Line
usage = """Galaxy Tool Shed diff command %s
Remote vs local
===============
To compare a published Tool Shed repository to the same tool in the
current directory, use:
$ shed_diff <TOOL_SHED_URL>
This will fetch the latest revisions of the specified tools to a temp
folder, and run a diff against matching local files to find any
differences between them.
It will ignore any files present locally but not in the remote tool.
This is to allow the tool to be run in a working folder containing
multiple tools (e.g. a multi-tool development repository).
Remote vs remote
================
To compare two published Tool Shed repositories, use as follows:
$ shed_diff <TOOL_SHED_URL1> <TOOL_SHED_URL2>
For example, to compare the main Tool Shed and Test Tool Shed versions
of my BLAST Reciprocal Best Hits (RBH) tool:
$ shed_diff https://toolshed.g2.bx.psu.edu/view/peterjc/blast_rbh https://testtoolshed.g2.bx.psu.edu/view/peterjc/blast_rbh
Or, using the clone URLs:
$ shed_diff https://toolshed.g2.bx.psu.edu/repos/peterjc/blast_rbh https://testtoolshed.g2.bx.psu.edu/repos/peterjc/blast_rbh
This will fetch the latest revisions of the specified tools to a temp
folder, and run a recursive diff to find any differences between them.
Return value
============
The tool uses any error level / return code from diff.
""" % VERSION
parser = OptionParser(usage=usage)
parser.add_option("-v", "--version", dest="version",
default=False, action="store_true",
help="Show version and quit")
options, args = parser.parse_args()
if len(args) == 1:
sys.exit(go_local(args[0]))
elif len(args) == 2:
old, new = args
sys.exit(go_remote(old, new))
else:
stop_err("Expected one or two arguments (Tool Shed repository URLs to compare). Use -h for help.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment