Last active
August 29, 2015 14:10
-
-
Save peterjc/13653e6907d75c470d01 to your computer and use it in GitHub Desktop.
Galaxy Tool Shed diff command
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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