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  try:
419  os.remove(f)
420  except FileNotFoundError:
421  pass # just ignore the file if it does not exist
422 
423 def list(options, args):
424  if os.path.isdir(options.manifest):
425  options.manifest = "%s/%s" % (options.manifest, MANIFEST_BASENAME)
426  with open(options.manifest, 'rb') as manifest:
427  manifest = json.load(manifest)
428  if options.info:
429  for f, info in manifest["files"].items():
430  if not options.tag or info["tag"] == options.tag:
431  if info.get('symlink'):
432  print("%s %s, -> %s" % (f, info["tag"], info["symlink"]))
433  else:
434  print("%s %s, %s bytes, %s" % (f, info["tag"], info["size"], info["checksum"]))
435  elif options.tag:
436  for f, info in manifest["files"].items():
437  if info["tag"] == options.tag:
438  print(f)
439  else:
440  for f in manifest["files"]:
441  print(f)
442 
443 def generate(options, args):
444  if not options.base_manifest and os.path.isfile("%s/%s" % (options.directory, MANIFEST_BASENAME)):
445  options.base_manifest = "%s/%s" % (options.directory, MANIFEST_BASENAME)
446 
447  manifest = None
448  if options.base_manifest and os.path.isfile(options.base_manifest) and os.path.getsize(options.base_manifest):
449  with open(options.base_manifest, 'rb') as base_manifest:
450  manifest = json.load(base_manifest)
451  else:
452  manifest = {"checksum_bytes": options.checksum_bytes, "tags": []}
453 
454  manifest["tags"] = [options.tag]
455 
456  os.chdir(options.directory)
457 
458  all_files = getFileList(options.exclude, options.include)
459 
460  if options.name:
461  manifest['name'] = options.name
462 
463  files_entries = manifest.get("files", {})
464 
465  # delete entries not in the directory
466  files_to_delete = []
467  if "files" in manifest:
468  for path, info in manifest["files"].items():
469  if path not in all_files:
470  files_to_delete.append(path)
471  for path in files_to_delete:
472  del files_entries[path]
473 
474  for f in all_files:
475  if os.path.basename(f) == MANIFEST_BASENAME:
476  continue
477 
478  current_entry = files_entries.get(f)
479  if os.path.islink(f):
480  linkValue = os.readlink(f)
481  if not current_entry or current_entry.get("symlink") != linkValue:
482  info = {"symlink": linkValue, "tag": options.tag}
483  files_entries[f] = info
484  else:
485  fileSize = os.path.getsize(f)
486  checksum = _get_checksum(manifest, f)
487  if not current_entry or current_entry.get('size') != fileSize or current_entry.get('checksum') != checksum:
488  info = {
489  "checksum": checksum,
490  "size": fileSize,
491  "mode": os.stat(f).st_mode,
492  "tag": options.tag
493  }
494  files_entries[f] = info
495  manifest["files"] = files_entries
496  print(json.dumps(manifest, indent=4, sort_keys=True))
497 
498 def download(options, args):
499  manifest = None
500  manifest_filename = "%s/%s" % (options.dest_dir, MANIFEST_BASENAME)
501 
502  if not os.path.isdir(options.dest_dir):
503  os.makedirs(options.dest_dir)
504 
505  if options.local_dir:
506  if options.save_dir:
507  print("Error: Can not have --local_dir and --save_dir")
508  return 1
509 
510  if not options.tag or not options.name:
511  if not os.path.isfile(manifest_filename):
512  print("must have -t and -n or %s" % (manifest_filename))
513  return 1
514  with open(manifest_filename, 'rb') as manifest:
515  manifest = json.load(manifest)
516  if not options.tag:
517  options.tag = manifest['tags'][-1]
518  if not options.name:
519  options.name = manifest['name']
520 
521  if not _download_file(options, MANIFEST_BASENAME):
522  return 1
523 
524  with open(manifest_filename, 'rb') as manifest:
525  manifest = json.load(manifest)
526 
527  modified_files = _check_directory_against_manifest(options, options.dest_dir, manifest)
528 
529  # if files on command line only look at those
530  if options.files and options.files[0]:
531  newList = {}
532  for f in options.files[0]:
533  try:
534  newList[f] = modified_files[f]
535  except:
536  pass
537  modified_files = newList
538 
539  if not modified_files:
540  if options.verbose:
541  print("No files require downloading")
542  else:
543  _download_files(options, modified_files)
544 
545  if options.save_dir:
546  for path, info in manifest['files'].items():
547  if info.get('checksum'):
548  src = "%s/%s" % (options.dest_dir, path)
549  dest = "%s/%s/%s/%s" % (options.save_dir, info["tag"], options.name, path)
550  destDir = os.path.dirname(dest)
551  if not os.path.isdir(destDir):
552  os.makedirs(destDir)
553  shutil.copy(src, dest)
554  os.chmod(dest, info["mode"])
555 
556 def get_tags(options, args):
557  tag_list = []
558  tempDir = tempfile.TemporaryDirectory(prefix="manifest-")
559  status = 0
560  url = options.base_url + "/"
561  if options.wget:
562  command = "cd %s; wget -q %s" % (tempDir.name, url)
563  run_command(command)
564  else:
565  parts = urllib.parse.urlparse(url)
566  host = parts.netloc
567  request = parts.path
568  status = httpdl(host, request, localpath=tempDir.name,
569  outputfilename="index.html",
570  verbose=options.verbose,
571  force_download=True,
572  chunk_size=options.chunk_size)
573  if status == 0:
574  with open("%s/index.html" % (tempDir.name)) as f:
575  inBody = False
576  for line in f:
577  if "<body>" in line:
578  inBody = True
579  if "</body>" in line:
580  break
581  if inBody:
582  if line.startswith("<a href="):
583  parts = line.split('"')
584  s = parts[1].split("/")[0]
585  if s != "..":
586  tag_list.append(s)
587  return tag_list
588  else:
589  print("Error downloading list of tags : return code =", status)
590  return tag_list
591 
592 def list_tags(options, args):
593  for tag in get_tags(options, args):
594  print(tag)
595 
596 def check_tag(options, args):
597  for tag in get_tags(options, args):
598  if tag == options.tag:
599  return True
600  return False
601 
602 def _get_checksum(manifest, path):
603  checksum = hashlib.sha256()
604  with open(path, 'rb') as current_file:
605  checksum.update(current_file.read(manifest['checksum_bytes']))
606  return checksum.hexdigest()
607 
608 def _check_directory_against_manifest(options, directory, manifest):
609  modified_files = {}
610  for path, info in manifest['files'].items():
611  dest = os.path.join(directory, path)
612  if os.path.islink(dest):
613  if info.get('symlink') != os.readlink(dest):
614  modified_files[path] = info
615  elif os.path.isfile(dest):
616  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:
617  modified_files[path] = info
618  else:
619  modified_files[path] = info
620  return modified_files
621 
622 def _download_file(options, fileName):
623  dest = "%s/%s" % (options.dest_dir, fileName)
624  dest_dir = os.path.dirname(dest)
625  if not os.path.isdir(dest_dir):
626  os.makedirs(dest_dir)
627 
628  if options.local_dir:
629  src = "%s/%s/%s/%s" % (options.local_dir, options.tag, options.name, fileName)
630  if options.verbose:
631  print("Copying %s from %s" % (fileName, src))
632  shutil.copy(src, dest)
633  return True
634 
635  url = "%s/%s/%s/%s" % (options.base_url, options.tag, options.name, fileName)
636  if options.verbose:
637  print("Downloading %s from %s" % (fileName, url))
638  if options.wget:
639  if os.path.isfile(dest):
640  os.remove(dest)
641  command = "cd %s; wget -q %s" % (dest_dir, url)
642  run_command(command)
643  else:
644  parts = urllib.parse.urlparse(url)
645  #host = "%s://%s" % (parts.scheme, parts.netloc)
646  host = parts.netloc
647  request = parts.path
648  status = httpdl(host, request, localpath=dest_dir,
649  outputfilename=os.path.basename(dest),
650  verbose=options.verbose,
651  force_download=True,
652  chunk_size=options.chunk_size)
653  if status != 0:
654  print("Error downloading", dest, ": return code =", status)
655  return False
656 
657  if options.save_dir:
658  src = "%s/%s" % (options.dest_dir, fileName)
659  dest = "%s/%s/%s/%s" % (options.save_dir, options.tag, options.name, fileName)
660  destDir = os.path.dirname(dest)
661  if not os.path.isdir(destDir):
662  os.makedirs(destDir)
663  shutil.copy(src, dest)
664  return True
665 
666 def _download_files(options, file_list):
667  if options.local_dir:
668  for path, info in file_list.items():
669  dest = "%s/%s" % (options.dest_dir, path)
670  dest_dir = os.path.dirname(dest)
671  if not os.path.isdir(dest_dir):
672  os.makedirs(dest_dir)
673  if info.get('checksum'):
674  src = "%s/%s/%s/%s" % (options.local_dir, info["tag"], options.name, path)
675  shutil.copy(src, dest)
676  os.chmod(dest, info["mode"])
677  else:
678  src = info['symlink']
679  os.symlink(src, dest)
680  return
681 
682  if options.wget:
683  if not os.path.isdir(options.dest_dir):
684  os.makedirs(options.dest_dir)
685  with tempfile.NamedTemporaryFile(prefix="manifest-") as txt_file:
686  for path, info in file_list.items():
687  if info.get('checksum'):
688  txt_file.write("%s\n" % path)
689  else:
690  dest = "%s/%s" % (options.dest_dir, path)
691  src = info['symlink']
692  os.symlink(src, dest)
693  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)
694  run_command(command)
695  for path, info in file_list.items():
696  if info.get('checksum'):
697  os.chmod(dest, info["mode"])
698  return
699 
700  for path, info in file_list.items():
701  dest = "%s/%s" % (options.dest_dir, path)
702  dest_dir = os.path.dirname(dest)
703  if not os.path.isdir(dest_dir):
704  os.makedirs(dest_dir)
705 
706  if info.get('checksum'):
707  if os.path.islink(dest) or os.path.exists(dest):
708  os.remove(dest)
709  url = "%s/%s/%s/%s" % (options.base_url, info["tag"], options.name, path)
710  if options.verbose:
711  print("Downloading %s from %s" % (path, url))
712  parts = urllib.parse.urlparse(url)
713  host = parts.netloc
714  request = parts.path
715  status = httpdl(host, request, localpath=dest_dir,
716  outputfilename=os.path.basename(dest),
717  verbose=options.verbose,
718  force_download=True,
719  chunk_size=options.chunk_size)
720  if status == 0:
721  os.chmod(dest, info["mode"])
722  else:
723  print("Error downloading", dest, ": return code =", status)
724  else:
725  src = info['symlink']
726  if options.verbose:
727  print("Making symlink %s -> %s" % (dest, src))
728  if os.path.islink(dest) or os.path.exists(dest):
729  os.remove(dest)
730  os.symlink(src, dest)
731 
732 
733 if __name__ == "__main__":
734  sys.exit(run())
def getSession(verbose=0, ntries=5)
Definition: manifest.py:45
def get_tags(options, args)
Definition: manifest.py:556
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:423
void print(std::ostream &stream, const char *format)
Definition: PrintDebug.hpp:38
def download(options, args)
Definition: manifest.py:498
def generate(options, args)
Definition: manifest.py:443
def clean(options, args)
Definition: manifest.py:395
def list_tags(options, args)
Definition: manifest.py:592
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:596
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