Just out of curiosity: what's your definition of "real world"?
Pavel

On 3/13/18 03:49, CCTBX commit wrote:
Repository : ssh://g18-sc-serv-04.diamond.ac.uk/cctbx
On branch  : master




commit 914c74bf195b5e5d4fa2c4145da3e5f89c7e5872
Author: Markus Gerstel <[email protected]>
Date:   Tue Mar 13 10:43:22 2018 +0000

    New command: libtbx.install
    
    This downloads and configures from a select list of cctbx/libtbxish
    modules in a similar manner to pip in the real world. This will not
    update or install any libraries in the base build, but assuming
    those libraries are present libtbx.install should work.





914c74bf195b5e5d4fa2c4145da3e5f89c7e5872
libtbx/command_line/install.py | 118 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 118 insertions(+)

diff --git a/libtbx/command_line/install.py b/libtbx/command_line/install.py
new file mode 100644
index 000000000..47ad94eb5
--- /dev/null
+++ b/libtbx/command_line/install.py
@@ -0,0 +1,118 @@
+from __future__ import absolute_import, division, print_function
+
+import collections
+import os
+import sys
+from optparse import SUPPRESS_HELP, OptionParser
+
+import procrunner
+
+import libtbx.load_env
+from libtbx.auto_build.bootstrap import Toolbox
+
+# Basically 'pip' for selected libtbx/cctbx modules.
+
+
+def is_source_repository(path):
+  return (path / '.git').isdir() or (path / '.svn').isdir()
+
+def run(args):
+  parser = OptionParser(usage="libtbx.install [package]",
+                        description="Installs an additional cctbx package")
+  parser.add_option("-?", action="help", help=SUPPRESS_HELP)
+  options, args = parser.parse_args(args)
+
+  modules_directory = list(filter(lambda dir: not is_source_repository(dir), libtbx.env.repository_paths))
+  if not modules_directory:
+    sys.exit("No repository path candidate found. Can't install modules without an installation root.")
+  if len(modules_directory) > 1:
+    print("More than one repository path candidate found.")
+  installation_root = modules_directory[0]
+  print("Using %s as installation root" % abs(installation_root))
+
+  packages_to_configure = set()
+
+  errors = False
+  for package in args:
+    if (installation_root / package).isdir():
+      print("Skipping package %s: Directory already exists in installation root" % package)
+      errors = True
+      continue
+    if package not in warehouse:
+      print("Skipping package %s: Never heard of this before" % package)
+      errors = True
+      continue
+
+    downloaded = False
+    for mech, call in mechanisms.items():
+      if mech in warehouse[package]:
+        print("Attempting to obtain %s using %s..." % (package, mech), end='')
+        sys.stdout.flush()
+        if call(abs(installation_root / package), warehouse[package][mech]):
+          assert (installation_root / package).isdir(), "Installation failed"
+          downloaded = True
+          print("success")
+          break
+        else:
+          assert not (installation_root / package).isdir(), "Install mechanism %s did not fail cleanly" % mech
+          print("failed")
+    if not downloaded:
+      print("Skipping package %s: Could not install" % package)
+      errors = True
+      continue
+
+    packages_to_configure.add(package)
+
+  if packages_to_configure:
+    packages_to_configure = sorted(packages_to_configure)
+    print("Configuring packages %s" % ", ".join(packages_to_configure))
+    os.chdir(abs(libtbx.env.build_path))
+    result = procrunner.run_process(['libtbx.configure'] + packages_to_configure)
+    if result['exitcode']: errors = True
+
+  if errors:
+    sys.exit(1)
+
+def install_git(location, source):
+  try:
+    result = procrunner.run_process(['git', 'clone', '--recursive', source, location], print_stdout=False, print_stderr=False)
+    if result['exitcode']:
+      return False
+    Toolbox.set_git_repository_config_to_rebase(os.path.join(location, '.git', 'config'))
+    return True
+  except OSError:
+    return False # git may not be installed
+
+def install_zip(location, source):
+  os.mkdir(location)
+  tempfile = os.path.join(location, '.tmp.zip')
+  etagfile = os.path.join(location, '..tmp.zip.etag')
+  def cleanup():
+    try: os.remove(tempfile)
+    except OSError: pass
+    try: os.remove(etagfile)
+    except OSError: pass
+  if Toolbox.download_to_file(source['url'], tempfile) <= 0:
+    cleanup()
+    os.rmdir(location)
+    return False
+  Toolbox.unzip(tempfile, location, trim_directory=source.get('trim', 0))
+  cleanup()
+  return True
+
+mechanisms = collections.OrderedDict((
+  ('git-auth', install_git),
+  ('git-anon', install_git),
+  ('http-zip', install_zip),
+))
+
+warehouse = {
+  'i19': {
+    'git-auth': '[email protected]:/xia2/i19',
+    'git-anon': 'https://github.com/xia2/i19.git',
+    'http-zip': { 'url': 'https://github.com/xia2/i19/archive/master.zip', 'trim': 1 },
+  },
+}
+
+if __name__ == '__main__':
+  run(sys.argv[1:])