00001 from __future__ import print_function
00002
00003 import hashlib
00004 import os
00005 import os.path as osp
00006 import re
00007 import shlex
00008 import subprocess
00009 import shutil
00010 import sys
00011 import tarfile
00012 import zipfile
00013
00014 import rosbag.rosbag_main
00015 import rospkg
00016
00017
00018 def extract_file(path, to_directory='.', chmod=True):
00019 print('[%s] Extracting to %s' % (path, to_directory))
00020 if path.endswith('.zip'):
00021 opener, mode, getnames = zipfile.ZipFile, 'r', lambda f: f.namelist()
00022 elif path.endswith('.tar.gz') or path.endswith('.tgz'):
00023 opener, mode, getnames = tarfile.open, 'r:gz', lambda f: f.getnames()
00024 elif path.endswith('.tar.bz2') or path.endswith('.tbz'):
00025 opener, mode, getnames = tarfile.open, 'r:bz2', lambda f: f.getnames()
00026 else:
00027 raise ValueError("Could not extract '%s' as no appropriate "
00028 "extractor is found" % path)
00029
00030 cwd = os.getcwd()
00031 os.chdir(to_directory)
00032 root_files = []
00033 try:
00034 file = opener(path, mode)
00035 try:
00036 file.extractall()
00037 if chmod:
00038 for fname in getnames(file):
00039 os.chmod(fname, 0777)
00040 root_files = list(set(name.split('/')[0]
00041 for name in getnames(file)))
00042 finally:
00043 file.close()
00044 finally:
00045 os.chdir(cwd)
00046 print('[%s] Finished extracting to %s' % (path, to_directory))
00047 return root_files
00048
00049
00050 def decompress_rosbag(path, quiet=False, chmod=True):
00051 print('[%s] Decompressing the rosbag' % path)
00052 argv = [path]
00053 if quiet:
00054 argv.append('--quiet')
00055 rosbag.rosbag_main.decompress_cmd(argv)
00056 if chmod:
00057 orig_path = osp.splitext(path)[0] + '.orig.bag'
00058 os.chmod(orig_path, 0777)
00059 os.chmod(path, 0777)
00060 print('[%s] Finished decompressing the rosbag' % path)
00061
00062
00063 def download(client, url, output, quiet=False, chmod=True):
00064 print('[%s] Downloading from %s' % (output, url))
00065 cmd = '{client} {url} -O {output}'.format(client=client, url=url,
00066 output=output)
00067 if quiet:
00068 cmd += ' --quiet'
00069 subprocess.call(shlex.split(cmd))
00070 if chmod:
00071 os.chmod(output, 0766)
00072 print('[%s] Finished downloading' % output)
00073
00074
00075 def check_md5sum(path, md5):
00076
00077 if md5 and len(md5) != 32:
00078 raise ValueError('md5 must be 32 charactors\n'
00079 'actual: {} ({} charactors)'.format(md5, len(md5)))
00080 print('[%s] Checking md5sum (%s)' % (path, md5))
00081 is_same = hashlib.md5(open(path, 'rb').read()).hexdigest() == md5
00082 print('[%s] Finished checking md5sum' % path)
00083 return is_same
00084
00085
00086 def is_google_drive_url(url):
00087 m = re.match('^https?://drive.google.com/uc\?id=.*$', url)
00088 return m is not None
00089
00090
00091 def download_data(pkg_name, path, url, md5, download_client=None,
00092 extract=False, compressed_bags=None, quiet=True, chmod=True):
00093 """Install test data checking md5 and rosbag decompress if needed.
00094 The downloaded data are located in cache_dir, and then linked to specified path.
00095 cache_dir is set by environment variable `JSK_DATA_CACHE_DIR` if defined, set by ROS_HOME/data otherwise."""
00096 if download_client is None:
00097 if is_google_drive_url(url):
00098 download_client = 'gdown'
00099 else:
00100 download_client = 'wget'
00101 if compressed_bags is None:
00102 compressed_bags = []
00103 if not osp.isabs(path):
00104
00105 rp = rospkg.RosPack()
00106 try:
00107 pkg_path = rp.get_path(pkg_name)
00108 except rospkg.ResourceNotFound:
00109 print('\033[31m{name} is not found in {path}\033[0m'
00110 .format(name=pkg_name, path=rp.list()))
00111 return
00112 pkg_path = rp.get_path(pkg_name)
00113 path = osp.join(pkg_path, path)
00114 if not osp.exists(osp.dirname(path)):
00115 try:
00116 os.makedirs(osp.dirname(path))
00117 except OSError as e:
00118
00119 if not osp.isdir(path):
00120 raise
00121
00122 if "JSK_DATA_CACHE_DIR" in os.environ:
00123 cache_root_dir = os.getenv("JSK_DATA_CACHE_DIR")
00124 else:
00125 cache_root_dir = osp.join(os.getenv('ROS_HOME', osp.expanduser('~/.ros')), "data")
00126 cache_dir = osp.join(cache_root_dir, pkg_name)
00127 if not osp.exists(cache_dir):
00128 try:
00129 os.makedirs(cache_dir)
00130 except OSError as e:
00131
00132 if not osp.isdir(path):
00133 raise
00134 if chmod:
00135 os.chmod(cache_dir, 0777)
00136 cache_file = osp.join(cache_dir, osp.basename(path))
00137
00138 if not (osp.exists(cache_file) and check_md5sum(cache_file, md5)):
00139 if osp.exists(cache_file):
00140 os.remove(cache_file)
00141 download(download_client, url, cache_file, quiet=quiet, chmod=chmod)
00142 if osp.islink(path):
00143
00144 os.remove(path)
00145 os.symlink(cache_file, path)
00146 elif not osp.exists(path):
00147 os.symlink(cache_file, path)
00148 else:
00149
00150 print('[%s] File exists, so skipping creating symlink.' % path,
00151 file=sys.stderr)
00152 return
00153 if extract:
00154
00155 extracted_files = extract_file(cache_file, to_directory=cache_dir, chmod=True)
00156 for file_ in extracted_files:
00157 file_ = osp.join(cache_dir, file_)
00158 dst_path = osp.join(osp.split(path)[0], osp.basename(file_))
00159 if osp.islink(dst_path):
00160 os.remove(dst_path)
00161 elif osp.exists(dst_path) and not osp.isdir(dst_path):
00162 os.remove(dst_path)
00163 elif osp.exists(dst_path) and osp.isdir(dst_path):
00164 shutil.rmtree(dst_path)
00165 os.symlink(file_, dst_path)
00166 for compressed_bag in compressed_bags:
00167 if not osp.isabs(compressed_bag):
00168 rp = rospkg.RosPack()
00169 pkg_path = rp.get_path(pkg_name)
00170 compressed_bag = osp.join(pkg_path, compressed_bag)
00171 decompress_rosbag(compressed_bag, quiet=quiet, chmod=chmod)