download_data.py
Go to the documentation of this file.
1 from __future__ import print_function
2 
3 import hashlib
4 import os
5 import os.path as osp
6 import re
7 import shlex
8 import subprocess
9 import shutil
10 import stat
11 import sys
12 import tarfile
13 import zipfile
14 
15 import rosbag.rosbag_main
16 import rospkg
17 
18 
19 def is_file_writable(path):
20  if not os.path.exists(path):
21  return True # if file does not exist, any file is writable there
22  st = os.stat(path)
23  return (bool(st.st_mode & stat.S_IWUSR) and
24  bool(st.st_mode & stat.S_IWGRP) and
25  bool(st.st_mode & stat.S_IWOTH))
26 
27 
28 def extract_file(path, to_directory='.', chmod=True):
29  print('[%s] Extracting to %s' % (path, to_directory))
30  if path.endswith('.zip'):
31  opener, mode, getnames = zipfile.ZipFile, 'r', lambda f: f.namelist()
32  elif path.endswith('.tar.gz') or path.endswith('.tgz'):
33  opener, mode, getnames = tarfile.open, 'r:gz', lambda f: f.getnames()
34  elif path.endswith('.tar.bz2') or path.endswith('.tbz'):
35  opener, mode, getnames = tarfile.open, 'r:bz2', lambda f: f.getnames()
36  else:
37  raise ValueError("Could not extract '%s' as no appropriate "
38  "extractor is found" % path)
39 
40  cwd = os.getcwd()
41  os.chdir(to_directory)
42  root_files = []
43  try:
44  file = opener(path, mode)
45  try:
46  file.extractall()
47  root_files = list(set(name.split('/')[0]
48  for name in getnames(file)))
49  finally:
50  file.close()
51  finally:
52  if chmod:
53  for fname in root_files:
54  if not is_file_writable(fname):
55  os.chmod(os.path.abspath(fname), 0777)
56  os.chdir(cwd)
57  print('[%s] Finished extracting to %s' % (path, to_directory))
58  return root_files
59 
60 
61 def decompress_rosbag(path, quiet=False, chmod=True):
62  print('[%s] Decompressing the rosbag' % path)
63  argv = [path]
64  if quiet:
65  argv.append('--quiet')
66  try:
67  rosbag.rosbag_main.decompress_cmd(argv)
68  finally:
69  if chmod:
70  if not is_file_writable(path):
71  os.chmod(path, 0777)
72  orig_path = osp.splitext(path)[0] + '.orig.bag'
73  if not is_file_writable(orig_path):
74  os.chmod(orig_path, 0777)
75  print('[%s] Finished decompressing the rosbag' % path)
76 
77 
78 def download(client, url, output, quiet=False, chmod=True):
79  print('[%s] Downloading from %s' % (output, url))
80  cmd = '{client} {url} -O {output}'.format(client=client, url=url,
81  output=output)
82  if quiet:
83  cmd += ' --quiet'
84  try:
85  subprocess.call(shlex.split(cmd))
86  finally:
87  if chmod:
88  if not is_file_writable(output):
89  os.chmod(output, 0766)
90  print('[%s] Finished downloading' % output)
91 
92 
93 def check_md5sum(path, md5):
94  # validate md5 string length if it is specified
95  if md5 and len(md5) != 32:
96  raise ValueError('md5 must be 32 charactors\n'
97  'actual: {} ({} charactors)'.format(md5, len(md5)))
98  print('[%s] Checking md5sum (%s)' % (path, md5))
99  is_same = hashlib.md5(open(path, 'rb').read()).hexdigest() == md5
100  print('[%s] Finished checking md5sum' % path)
101  return is_same
102 
103 
105  m = re.match('^https?://drive.google.com/uc\?id=.*$', url)
106  return m is not None
107 
108 
109 def download_data(pkg_name, path, url, md5, download_client=None,
110  extract=False, compressed_bags=None, quiet=True, chmod=True):
111  """Install test data checking md5 and rosbag decompress if needed.
112  The downloaded data are located in cache_dir, and then linked to specified path.
113  cache_dir is set by environment variable `JSK_DATA_CACHE_DIR` if defined, set by ROS_HOME/data otherwise."""
114  if download_client is None:
115  if is_google_drive_url(url):
116  download_client = 'gdown'
117  else:
118  download_client = 'wget'
119  if compressed_bags is None:
120  compressed_bags = []
121  if not osp.isabs(path):
122  # get package path
123  rp = rospkg.RosPack()
124  try:
125  pkg_path = rp.get_path(pkg_name)
126  except rospkg.ResourceNotFound:
127  print('\033[31m{name} is not found in {path}\033[0m'
128  .format(name=pkg_name, path=rp.list()))
129  return
130  pkg_path = rp.get_path(pkg_name)
131  path = osp.join(pkg_path, path)
132  if not osp.exists(osp.dirname(path)):
133  try:
134  os.makedirs(osp.dirname(path))
135  except OSError as e:
136  # can fail on running with multiprocess
137  if not osp.isdir(path):
138  raise
139  # prepare cache dir
140  if "JSK_DATA_CACHE_DIR" in os.environ:
141  cache_root_dir = os.getenv("JSK_DATA_CACHE_DIR")
142  else:
143  cache_root_dir = osp.join(os.getenv('ROS_HOME', osp.expanduser('~/.ros')), "data")
144  cache_dir = osp.join(cache_root_dir, pkg_name)
145  if not osp.exists(cache_dir):
146  try:
147  os.makedirs(cache_dir)
148  except OSError as e:
149  # can fail on running with multiprocess
150  if not osp.isdir(path):
151  raise
152  finally:
153  if chmod:
154  if not is_file_writable(cache_dir):
155  os.chmod(cache_dir, 0777)
156  cache_file = osp.join(cache_dir, osp.basename(path))
157  # check if cache exists, and update if necessary
158  if not (osp.exists(cache_file) and check_md5sum(cache_file, md5)):
159  if osp.exists(cache_file):
160  os.remove(cache_file)
161  download(download_client, url, cache_file, quiet=quiet, chmod=chmod)
162  if osp.islink(path):
163  # overwrite the link
164  os.remove(path)
165  os.symlink(cache_file, path)
166  elif not osp.exists(path):
167  os.symlink(cache_file, path) # create link
168  else:
169  # not link and exists so skipping
170  print('[%s] File exists, so skipping creating symlink.' % path,
171  file=sys.stderr)
172  return
173  if extract:
174  # extract files in cache dir and create symlink for them
175  extracted_files = extract_file(cache_file, to_directory=cache_dir, chmod=True)
176  for file_ in extracted_files:
177  file_ = osp.join(cache_dir, file_)
178  dst_path = osp.join(osp.split(path)[0], osp.basename(file_))
179  if osp.islink(dst_path):
180  os.remove(dst_path)
181  elif osp.exists(dst_path) and not osp.isdir(dst_path):
182  os.remove(dst_path)
183  elif osp.exists(dst_path) and osp.isdir(dst_path):
184  shutil.rmtree(dst_path)
185  os.symlink(file_, dst_path)
186  for compressed_bag in compressed_bags:
187  if not osp.isabs(compressed_bag):
188  rp = rospkg.RosPack()
189  pkg_path = rp.get_path(pkg_name)
190  compressed_bag = osp.join(pkg_path, compressed_bag)
191  decompress_rosbag(compressed_bag, quiet=quiet, chmod=chmod)
def check_md5sum(path, md5)
def decompress_rosbag(path, quiet=False, chmod=True)
def download(client, url, output, quiet=False, chmod=True)
def extract_file(path, to_directory='.', chmod=True)
def download_data(pkg_name, path, url, md5, download_client=None, extract=False, compressed_bags=None, quiet=True, chmod=True)


jsk_data
Author(s):
autogenerated on Tue Feb 6 2018 03:45:36