OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
manifest.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 import argparse
4 import hashlib
5 import json
6 import os
7 import os.path
8 import re
9 import sys
10 import urllib.request
11 import subprocess
12 import shutil
13 import logging
14 from contextlib import closing
15 from datetime import datetime, timedelta, date
16 import requests
17 from requests.adapters import HTTPAdapter
18 import tempfile
19 
20 DEFAULT_BASE_URL = "https://oceandata.sci.gsfc.nasa.gov/manifest/tags"
21 MANIFEST_BASENAME = "manifest.json"
22 
23 
24 # ------------------ DANGER -------------------
25 #
26 # The next 5 functions:
27 # getSession
28 # isRequestAuthFailure
29 # httpdl
30 # uncompressFile
31 # get_file_time
32 #
33 # exist in two places:
34 # OCSSWROOT/src/manifest/manifest.py
35 # OCSSWROOT/src/scripts/seadasutils/ProcUtils.py
36 #
37 # Make sure changes get into both files.
38 #
39 
40 DEFAULT_CHUNK_SIZE = 131072
41 
42 # requests session object used to keep connections around
43 obpgSession = None
44 
45 def getSession(verbose=0, ntries=5):
46  global obpgSession
47 
48  if not obpgSession:
49  # turn on debug statements for requests
50  if verbose > 1:
51  logging.basicConfig(level=logging.DEBUG)
52 
53  obpgSession = requests.Session()
54  obpgSession.mount('https://', HTTPAdapter(max_retries=ntries))
55 
56  if verbose:
57  print("OBPG session started")
58  else:
59  if verbose > 1:
60  print("reusing existing OBPG session")
61 
62  return obpgSession
63 
64 # ------------------ DANGER -------------------
65 # See comment above
67  ctype = req.headers.get('Content-Type')
68  if ctype and ctype.startswith('text/html'):
69  if "<title>Earthdata Login</title>" in req.text:
70  return True
71  return False
72 
73 # ------------------ DANGER -------------------
74 # See comment above
75 def httpdl(server, request, localpath='.', outputfilename=None, ntries=5,
76  uncompress=False, timeout=30., verbose=0, force_download=False,
77  chunk_size=DEFAULT_CHUNK_SIZE):
78 
79  status = 0
80  urlStr = 'https://' + server + request
81 
82  global obpgSession
83 
84  getSession(verbose=verbose, ntries=ntries)
85 
86  modified_since = None
87  headers = {}
88 
89  if not force_download:
90  if outputfilename:
91  ofile = os.path.join(localpath, outputfilename)
92  modified_since = get_file_time(ofile)
93  else:
94  ofile = os.path.join(localpath, os.path.basename(request.rstrip()))
95  modified_since = get_file_time(ofile)
96 
97  if modified_since:
98  headers = {"If-Modified-Since":modified_since.strftime("%a, %d %b %Y %H:%M:%S GMT")}
99 
100  with closing(obpgSession.get(urlStr, stream=True, timeout=timeout, headers=headers)) as req:
101 
102  if req.status_code != 200:
103  status = req.status_code
104  elif isRequestAuthFailure(req):
105  status = 401
106  else:
107  if not os.path.exists(localpath):
108  os.umask(0o02)
109  os.makedirs(localpath, mode=0o2775)
110 
111  if not outputfilename:
112  cd = req.headers.get('Content-Disposition')
113  if cd:
114  outputfilename = re.findall("filename=(.+)", cd)[0]
115  else:
116  outputfilename = urlStr.split('/')[-1]
117 
118  ofile = os.path.join(localpath, outputfilename)
119 
120  # This is here just in case we didn't get a 304 when we should have...
121  download = True
122  if 'last-modified' in req.headers:
123  remote_lmt = req.headers['last-modified']
124  remote_ftime = datetime.strptime(remote_lmt, "%a, %d %b %Y %H:%M:%S GMT").replace(tzinfo=None)
125  if modified_since and not force_download:
126  if (remote_ftime - modified_since).total_seconds() < 0:
127  download = False
128  if verbose:
129  print("Skipping download of %s" % outputfilename)
130 
131  if download:
132  with open(ofile, 'wb') as fd:
133  for chunk in req.iter_content(chunk_size=chunk_size):
134  if chunk: # filter out keep-alive new chunks
135  fd.write(chunk)
136 
137  if uncompress and re.search(".(Z|gz|bz2)$", ofile):
138  compressStatus = uncompressFile(ofile)
139  if compressStatus:
140  status = compressStatus
141  else:
142  status = 0
143 
144  return status
145 
146 
147 # ------------------ DANGER -------------------
148 # See comment above
149 def uncompressFile(compressed_file):
150  """
151  uncompress file
152  compression methods:
153  bzip2
154  gzip
155  UNIX compress
156  """
157 
158  compProg = {"gz": "gunzip -f ", "Z": "gunzip -f ", "bz2": "bunzip2 -f "}
159  exten = os.path.basename(compressed_file).split('.')[-1]
160  unzip = compProg[exten]
161  p = subprocess.Popen(unzip + compressed_file, shell=True)
162  status = os.waitpid(p.pid, 0)[1]
163  if status:
164  print("Warning! Unable to decompress %s" % compressed_file)
165  return status
166  else:
167  return 0
168 
169 # ------------------ DANGER -------------------
170 # See comment above
171 def get_file_time(localFile):
172  ftime = None
173  if not os.path.isfile(localFile):
174  localFile = re.sub(r".(Z|gz|bz2)$", '', localFile)
175 
176  if os.path.isfile(localFile):
177  ftime = datetime.fromtimestamp(os.path.getmtime(localFile))
178 
179  return ftime
180 
181 def run():
182  parser = argparse.ArgumentParser()
183  parser.set_defaults(func=download)
184  subparsers = parser.add_subparsers()
185 
186  _add_subparser_reprint(subparsers)
187  _add_subparser_update_file(subparsers)
188  _add_subparser_add_tag(subparsers)
189  _add_subparser_get_value(subparsers)
190  _add_subparser_get_first_tag(subparsers)
191  _add_subparser_list(subparsers)
192  _add_subparser_clean(subparsers)
193  _add_subparser_download(subparsers)
194  _add_subparser_generate(subparsers)
195  _add_subparser_list_tags(subparsers)
196 
197  options, args = parser.parse_known_args()
198  return options.func(options, args)
199 
200 def _add_subparser_reprint(subparsers):
201  parser_reprint = subparsers.add_parser('reprint')
202  parser_reprint.add_argument("manifest", help="manifest to reprint")
203  parser_reprint.set_defaults(func=reprint)
204  if os.path.isfile(MANIFEST_BASENAME):
205  parser_reprint.set_defaults(manifest=MANIFEST_BASENAME)
206 
207 def _add_subparser_update_file(subparsers):
208  parser_update_file = subparsers.add_parser('update-file')
209  parser_update_file.add_argument("manifest", help="manifest to update")
210  parser_update_file.add_argument("path", help="file to update")
211  parser_update_file.set_defaults(func=update_file)
212  if os.path.isfile(MANIFEST_BASENAME):
213  parser_update_file.set_defaults(manifest=MANIFEST_BASENAME)
214 
215 def _add_subparser_add_tag(subparsers):
216  parser_add_tag = subparsers.add_parser('add-tag')
217  parser_add_tag.add_argument("-m", "--manifest", help="manifest to update")
218  parser_add_tag.add_argument("tag", help="tag to add to tags attribute")
219  parser_add_tag.set_defaults(func=add_tag)
220  if os.path.isfile(MANIFEST_BASENAME):
221  parser_add_tag.set_defaults(manifest=MANIFEST_BASENAME)
222 
223 def _add_subparser_get_value(subparsers):
224  parser_get_value = subparsers.add_parser('get-value')
225  parser_get_value.add_argument("-m", "--manifest", help="manifest from which to retrieve the value")
226  parser_get_value.add_argument("xpath", help="key to print, colon separated for nested values")
227  parser_get_value.set_defaults(func=get_value)
228  if os.path.isfile(MANIFEST_BASENAME):
229  parser_get_value.set_defaults(manifest=MANIFEST_BASENAME)
230 
231 def _add_subparser_get_first_tag(subparsers):
232  parser_get_first_tag = subparsers.add_parser('get-first-tag')
233  parser_get_first_tag.add_argument("-m", "--manifest", help="manifest from which to retrieve the first tag")
234  parser_get_first_tag.set_defaults(func=get_first_tag)
235  if os.path.isfile(MANIFEST_BASENAME):
236  parser_get_first_tag.set_defaults(manifest=MANIFEST_BASENAME)
237 
238 def _add_subparser_list(subparsers):
239  parser_list = subparsers.add_parser('list')
240  parser_list.add_argument("manifest", help="manifest to list")
241  parser_list.add_argument("-i", "--info", action="store_const", const=1, help="include extra info")
242  parser_list.add_argument("-t", "--tag", help="tag to list files for")
243  parser_list.set_defaults(func=list)
244  if os.path.isfile(MANIFEST_BASENAME):
245  parser_list.set_defaults(manifest=MANIFEST_BASENAME)
246 
247 def _add_subparser_clean(subparsers):
248  parser_clean = subparsers.add_parser('clean')
249  parser_clean.add_argument("-d", "--dry-run", action="store_const", const=1, help="don't actually delete files")
250  parser_clean.add_argument("directory", default=".", nargs='?', help="directory to clean (must contain %s)" % MANIFEST_BASENAME)
251  parser_clean.add_argument("-e", "--exclude", nargs="+", action='append', help="relative paths to ignore")
252  parser_clean.add_argument("-i", "--include", nargs="+", action='append', help="relative paths to include (ignore *)")
253  parser_clean.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
254  parser_clean.set_defaults(func=clean)
255 
256 def _add_subparser_download(subparsers):
257  parser_download = subparsers.add_parser('download')
258  parser_download.add_argument("-d", "--dest-dir", help="destination directory")
259  parser_download.add_argument("-t", "--tag", help="tag to download")
260  parser_download.add_argument("-b", "--base-url", default=DEFAULT_BASE_URL, help="base URL")
261  parser_download.add_argument("-n", "--name", help="bundle name")
262  parser_download.add_argument("--chunk-size", type=int, default=DEFAULT_CHUNK_SIZE, help="download chunk size")
263  parser_download.add_argument("-s", "--save-dir", help="save a copy of the manifest files to this directory")
264  parser_download.add_argument("-l", "--local-dir", help="directory containing local manifest files")
265  parser_download.add_argument("-w", "--wget", default=False, action="store_true", help="use wget to download")
266  parser_download.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
267  parser_download.add_argument("files", action="append", nargs="*", default=None, type=str, help="files to download if needed")
268 
269  parser_download.set_defaults(func=download)
270  parser_download.set_defaults(dest_dir=".")
271 
272 def _add_subparser_generate(subparsers):
273  parser_gen = subparsers.add_parser('generate')
274  parser_gen.add_argument("-b", "--base-manifest", help="base manifest file")
275  parser_gen.add_argument("-c", "--checksum-bytes", default=1000000, help="how many bytes to checksum per file")
276  parser_gen.add_argument("-t", "--tag", required=True, help="new tag for manifest")
277  parser_gen.add_argument("-f", "--force", action="store_const", const=1, help="generate manifest despite warnings")
278  parser_gen.add_argument("-e", "--exclude", nargs="+", action='append', help="relative paths to ignore")
279  parser_gen.add_argument("-i", "--include", nargs="+", action='append', help="relative paths to include (ignore *)")
280  parser_gen.add_argument("-n", "--name", help="bundle name")
281  parser_gen.add_argument("directory", help="directory to generate a manifest for")
282  parser_gen.set_defaults(func=generate)
283 
284 def _add_subparser_list_tags(subparsers):
285  parser_list_tags = subparsers.add_parser('list_tags')
286  parser_list_tags.add_argument("-b", "--base-url", default=DEFAULT_BASE_URL, help="base URL")
287  parser_list_tags.add_argument("--chunk-size", type=int, default=DEFAULT_CHUNK_SIZE, help="download chunk size")
288  parser_list_tags.add_argument("-w", "--wget", default=False, action="store_true", help="use wget to download")
289  parser_list_tags.add_argument("-v", "--verbose", action="count", default=0, help="increase output verbosity")
290  parser_list_tags.set_defaults(func=list_tags)
291 
293  options = argparse.Namespace(
294  verbose=0,
295  dest_dir=None,
296  tag=None,
297  base_url=DEFAULT_BASE_URL,
298  name=None,
299  chunk_size=DEFAULT_CHUNK_SIZE,
300  save_dir=None,
301  local_dir=None,
302  wget=False,
303  files=None,
304  func=list_tags)
305  return options
306 
307 def run_command(command):
308  proc = subprocess.run(command, shell=True)
309  if proc.returncode != 0:
310  print("Error: return =", proc.returncode, ": trying to run command =", command)
311  sys.exit(1)
312 
313 def reprint(options, args):
314  with open(options.manifest, 'rb') as manifest:
315  manifest = json.load(manifest)
316  print(json.dumps(manifest, indent=4, sort_keys=True))
317 
318 def update_file(options, args):
319  with open(options.manifest, 'rb') as manifest:
320  manifest = json.load(manifest)
321  current_entry = manifest['files'].get(options.path)
322  if os.path.islink(options.path):
323  linkValue = os.readlink(options.path)
324  if not current_entry or current_entry.get("symlink") != linkValue:
325  info = {"symlink": linkValue, "tag": options.tag}
326  manifest['files'][options.path] = info
327  else:
328  checksum = _get_checksum(manifest, options.path)
329  if not current_entry or current_entry.get('checksum') != checksum:
330  info = {
331  "checksum": checksum,
332  "size": os.stat(options.path).st_size,
333  "mode": os.stat(options.path).st_mode,
334  "tag": manifest['tag']
335  }
336  manifest['files'][options.path] = info
337 
338  print(json.dumps(manifest, indent=4, sort_keys=True))
339 
340 def add_tag(options, args):
341  with open(options.manifest, 'rb') as manifest:
342  manifest = json.load(manifest)
343  if options.tag not in manifest["tags"]:
344  manifest["tags"].append(options.tag)
345  else:
346  print("%s is already in the tags attribute" % (options.tag), file=sys.stderr)
347 
348  print(json.dumps(manifest, indent=4, sort_keys=True))
349 
350 def get_value(options, args):
351  with open(options.manifest, 'rb') as manifest:
352  manifest = json.load(manifest)
353  for part in options.xpath.split(":"):
354  if part in manifest:
355  manifest = manifest[part]
356  else:
357  print("Path not found, invalid part: %s" % part)
358  return
359  print(manifest)
360 
361 def get_first_tag(options, args):
362  with open(options.manifest, 'rb') as manifest:
363  manifest = json.load(manifest)
364  print(manifest['tags'][0])
365 
366 def getFileList(excludeList=None, includeList=None):
367  allFiles = []
368 
369  for root, _, files in os.walk(".", followlinks=True):
370  for f in files:
371  if '/' in root:
372  name = root[2:]+'/'+f
373  else:
374  name = f
375 
376  # exclude files if not in include list
377  addIt = True
378  if excludeList:
379  for exclude in excludeList:
380  if exclude[0] == "." or name.startswith(exclude[0]):
381  addIt = False
382  if includeList:
383  for include in includeList:
384  if name.startswith(include[0]):
385  addIt = True
386  break
387  if not addIt:
388  break
389  if addIt:
390  if "__pycache__" not in name:
391  allFiles.append(name)
392 
393  return allFiles
394 
395 def clean(options, args):
396  os.chdir(options.directory)
397 
398  # check for exclude wild card
399  if options.exclude:
400  for exclude in options.exclude:
401  if exclude[0] == ".":
402  return
403 
404  if not os.path.isfile(MANIFEST_BASENAME):
405  print("directory needs to contain a", MANIFEST_BASENAME)
406  return 1
407 
408  with open(MANIFEST_BASENAME, 'rb') as manifest:
409  manifest = json.load(manifest)
410  files = manifest["files"]
411  for f in getFileList(options.exclude, options.include):
412  if f == MANIFEST_BASENAME:
413  continue
414  if not files.get(f):
415  if options.verbose or options.dry_run:
416  print("cleaning %s" % (f))
417  if not options.dry_run:
418  os.remove(f)
419 
420 def list(options, args):
421  if os.path.isdir(options.manifest):
422  options.manifest = "%s/%s" % (options.manifest, MANIFEST_BASENAME)
423  with open(options.manifest, 'rb') as manifest:
424  manifest = json.load(manifest)
425  if options.info:
426  for f, info in manifest["files"].items():
427  if not options.tag or info["tag"] == options.tag:
428  if info.get('symlink'):
429  print("%s %s, -> %s" % (f, info["tag"], info["symlink"]))
430  else:
431  print("%s %s, %s bytes, %s" % (f, info["tag"], info["size"], info["checksum"]))
432  elif options.tag:
433  for f, info in manifest["files"].items():
434  if info["tag"] == options.tag:
435  print(f)
436  else:
437  for f in manifest["files"]:
438  print(f)
439 
440 def generate(options, args):
441  if not options.base_manifest and os.path.isfile("%s/%s" % (options.directory, MANIFEST_BASENAME)):
442  options.base_manifest = "%s/%s" % (options.directory, MANIFEST_BASENAME)
443 
444  manifest = None
445  if options.base_manifest and os.path.isfile(options.base_manifest) and os.path.getsize(options.base_manifest):
446  with open(options.base_manifest, 'rb') as base_manifest:
447  manifest = json.load(base_manifest)
448  else:
449  manifest = {"checksum_bytes": options.checksum_bytes, "tags": []}
450 
451  manifest["tags"] = [options.tag]
452 
453  os.chdir(options.directory)
454 
455  all_files = getFileList(options.exclude, options.include)
456 
457  if options.name:
458  manifest['name'] = options.name
459 
460  files_entries = manifest.get("files", {})
461 
462  # delete entries not in the directory
463  files_to_delete = []
464  if "files" in manifest:
465  for path, info in manifest["files"].items():
466  if path not in all_files:
467  files_to_delete.append(path)
468  for path in files_to_delete:
469  del files_entries[path]
470 
471  for f in all_files:
472  if os.path.basename(f) == MANIFEST_BASENAME:
473  continue
474 
475  current_entry = files_entries.get(f)
476  if os.path.islink(f):
477  linkValue = os.readlink(f)
478  if not current_entry or current_entry.get("symlink") != linkValue:
479  info = {"symlink": linkValue, "tag": options.tag}
480  files_entries[f] = info
481  else:
482  fileSize = os.path.getsize(f)
483  checksum = _get_checksum(manifest, f)
484  if not current_entry or current_entry.get('size') != fileSize or current_entry.get('checksum') != checksum:
485  info = {
486  "checksum": checksum,
487  "size": fileSize,
488  "mode": os.stat(f).st_mode,
489  "tag": options.tag
490  }
491  files_entries[f] = info
492  manifest["files"] = files_entries
493  print(json.dumps(manifest, indent=4, sort_keys=True))
494 
495 def download(options, args):
496  manifest = None
497  manifest_filename = "%s/%s" % (options.dest_dir, MANIFEST_BASENAME)
498 
499  if not os.path.isdir(options.dest_dir):
500  os.makedirs(options.dest_dir)
501 
502  if options.local_dir:
503  if options.save_dir:
504  print("Error: Can not have --local_dir and --save_dir")
505  return 1
506 
507  if not options.tag or not options.name:
508  if not os.path.isfile(manifest_filename):
509  print("must have -t and -n or %s" % (manifest_filename))
510  return 1
511  with open(manifest_filename, 'rb') as manifest:
512  manifest = json.load(manifest)
513  if not options.tag:
514  options.tag = manifest['tags'][-1]
515  if not options.name:
516  options.name = manifest['name']
517 
518  if not _download_file(options, MANIFEST_BASENAME):
519  return 1
520 
521  with open(manifest_filename, 'rb') as manifest:
522  manifest = json.load(manifest)
523 
524  modified_files = _check_directory_against_manifest(options, options.dest_dir, manifest)
525 
526  # if files on command line only look at those
527  if options.files and options.files[0]:
528  newList = {}
529  for f in options.files[0]:
530  try:
531  newList[f] = modified_files[f]
532  except:
533  pass
534  modified_files = newList
535 
536  if not modified_files:
537  if options.verbose:
538  print("No files require downloading")
539  else:
540  _download_files(options, modified_files)
541 
542  if options.save_dir:
543  for path, info in manifest['files'].items():
544  if info.get('checksum'):
545  src = "%s/%s" % (options.dest_dir, path)
546  dest = "%s/%s/%s/%s" % (options.save_dir, info["tag"], options.name, path)
547  destDir = os.path.dirname(dest)
548  if not os.path.isdir(destDir):
549  os.makedirs(destDir)
550  shutil.copy(src, dest)
551  os.chmod(dest, info["mode"])
552 
553 def get_tags(options, args):
554  tag_list = []
555  tempDir = tempfile.TemporaryDirectory(prefix="manifest-")
556  status = 0
557  url = options.base_url + "/"
558  if options.wget:
559  command = "cd %s; wget -q %s" % (tempDir.name, url)
560  run_command(command)
561  else:
562  parts = urllib.parse.urlparse(url)
563  host = parts.netloc
564  request = parts.path
565  status = httpdl(host, request, localpath=tempDir.name,
566  outputfilename="index.html",
567  verbose=options.verbose,
568  force_download=True,
569  chunk_size=options.chunk_size)
570  if status == 0:
571  with open("%s/index.html" % (tempDir.name)) as f:
572  inBody = False
573  for line in f:
574  if "<body>" in line:
575  inBody = True
576  if "</body>" in line:
577  break
578  if inBody:
579  if line.startswith("<a href="):
580  parts = line.split('"')
581  s = parts[1].split("/")[0]
582  if s != "..":
583  tag_list.append(s)
584  return tag_list
585  else:
586  print("Error downloading list of tags : return code =", status)
587  return tag_list
588 
589 def list_tags(options, args):
590  for tag in get_tags(options, args):
591  print(tag)
592 
593 def check_tag(options, args):
594  for tag in get_tags(options, args):
595  if tag == options.tag:
596  return True
597  return False
598 
599 def _get_checksum(manifest, path):
600  checksum = hashlib.sha256()
601  with open(path, 'rb') as current_file:
602  checksum.update(current_file.read(manifest['checksum_bytes']))
603  return checksum.hexdigest()
604 
605 def _check_directory_against_manifest(options, directory, manifest):
606  modified_files = {}
607  for path, info in manifest['files'].items():
608  dest = os.path.join(directory, path)
609  if os.path.islink(dest):
610  if info.get('symlink') != os.readlink(dest):
611  modified_files[path] = info
612  elif os.path.isfile(dest):
613  if info.get('size') != os.path.getsize(dest) or info.get('checksum') != _get_checksum(manifest, dest) or info.get('mode') != os.stat(dest).st_mode:
614  modified_files[path] = info
615  else:
616  modified_files[path] = info
617  return modified_files
618 
619 def _download_file(options, fileName):
620  dest = "%s/%s" % (options.dest_dir, fileName)
621  dest_dir = os.path.dirname(dest)
622  if not os.path.isdir(dest_dir):
623  os.makedirs(dest_dir)
624 
625  if options.local_dir:
626  src = "%s/%s/%s/%s" % (options.local_dir, options.tag, options.name, fileName)
627  if options.verbose:
628  print("Copying %s from %s" % (fileName, src))
629  shutil.copy(src, dest)
630  return True
631 
632  url = "%s/%s/%s/%s" % (options.base_url, options.tag, options.name, fileName)
633  if options.verbose:
634  print("Downloading %s from %s" % (fileName, url))
635  if options.wget:
636  if os.path.isfile(dest):
637  os.remove(dest)
638  command = "cd %s; wget -q %s" % (dest_dir, url)
639  run_command(command)
640  else:
641  parts = urllib.parse.urlparse(url)
642  #host = "%s://%s" % (parts.scheme, parts.netloc)
643  host = parts.netloc
644  request = parts.path
645  status = httpdl(host, request, localpath=dest_dir,
646  outputfilename=os.path.basename(dest),
647  verbose=options.verbose,
648  force_download=True,
649  chunk_size=options.chunk_size)
650  if status != 0:
651  print("Error downloading", dest, ": return code =", status)
652  return False
653 
654  if options.save_dir:
655  src = "%s/%s" % (options.dest_dir, fileName)
656  dest = "%s/%s/%s/%s" % (options.save_dir, options.tag, options.name, fileName)
657  destDir = os.path.dirname(dest)
658  if not os.path.isdir(destDir):
659  os.makedirs(destDir)
660  shutil.copy(src, dest)
661  return True
662 
663 def _download_files(options, file_list):
664  if options.local_dir:
665  for path, info in file_list.items():
666  dest = "%s/%s" % (options.dest_dir, path)
667  dest_dir = os.path.dirname(dest)
668  if not os.path.isdir(dest_dir):
669  os.makedirs(dest_dir)
670  if info.get('checksum'):
671  src = "%s/%s/%s/%s" % (options.local_dir, info["tag"], options.name, path)
672  shutil.copy(src, dest)
673  os.chmod(dest, info["mode"])
674  else:
675  src = info['symlink']
676  os.symlink(src, dest)
677  return
678 
679  if options.wget:
680  if not os.path.isdir(options.dest_dir):
681  os.makedirs(options.dest_dir)
682  with tempfile.NamedTemporaryFile(prefix="manifest-") as txt_file:
683  for path, info in file_list.items():
684  if info.get('checksum'):
685  txt_file.write("%s\n" % path)
686  else:
687  dest = "%s/%s" % (options.dest_dir, path)
688  src = info['symlink']
689  os.symlink(src, dest)
690  command = "cd %s; wget -x -nH -i %s --cut-dirs=3 --base=%s/%s/%s/" % (options.dest_dir, txt_file.name, options.base_url, info["tag"], options.name)
691  run_command(command)
692  for path, info in file_list.items():
693  if info.get('checksum'):
694  os.chmod(dest, info["mode"])
695  return
696 
697  for path, info in file_list.items():
698  dest = "%s/%s" % (options.dest_dir, path)
699  dest_dir = os.path.dirname(dest)
700  if not os.path.isdir(dest_dir):
701  os.makedirs(dest_dir)
702 
703  if info.get('checksum'):
704  if os.path.islink(dest) or os.path.exists(dest):
705  os.remove(dest)
706  url = "%s/%s/%s/%s" % (options.base_url, info["tag"], options.name, path)
707  if options.verbose:
708  print("Downloading %s from %s" % (path, url))
709  parts = urllib.parse.urlparse(url)
710  host = parts.netloc
711  request = parts.path
712  status = httpdl(host, request, localpath=dest_dir,
713  outputfilename=os.path.basename(dest),
714  verbose=options.verbose,
715  force_download=True,
716  chunk_size=options.chunk_size)
717  if status == 0:
718  os.chmod(dest, info["mode"])
719  else:
720  print("Error downloading", dest, ": return code =", status)
721  else:
722  src = info['symlink']
723  if options.verbose:
724  print("Making symlink %s -> %s" % (dest, src))
725  if os.path.islink(dest) or os.path.exists(dest):
726  os.remove(dest)
727  os.symlink(src, dest)
728 
729 
730 if __name__ == "__main__":
731  sys.exit(run())
def getSession(verbose=0, ntries=5)
Definition: manifest.py:45
def get_tags(options, args)
Definition: manifest.py:553
def run()
Definition: manifest.py:181
def reprint(options, args)
Definition: manifest.py:313
def run_command(command)
Definition: manifest.py:307
def list(options, args)
Definition: manifest.py:420
def download(options, args)
Definition: manifest.py:495
def generate(options, args)
Definition: manifest.py:440
def clean(options, args)
Definition: manifest.py:395
def list_tags(options, args)
Definition: manifest.py:589
def create_default_options()
Definition: manifest.py:292
def update_file(options, args)
Definition: manifest.py:318
def add_tag(options, args)
Definition: manifest.py:340
def uncompressFile(compressed_file)
Definition: manifest.py:149
def get_file_time(localFile)
Definition: manifest.py:171
def get_first_tag(options, args)
Definition: manifest.py:361
def get_value(options, args)
Definition: manifest.py:350
def isRequestAuthFailure(req)
Definition: manifest.py:66
def check_tag(options, args)
Definition: manifest.py:593
def httpdl(server, request, localpath='.', outputfilename=None, ntries=5, uncompress=False, timeout=30., verbose=0, force_download=False, chunk_size=DEFAULT_CHUNK_SIZE)
Definition: manifest.py:75
def getFileList(excludeList=None, includeList=None)
Definition: manifest.py:366