OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
manifest_ocssw.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 """
4 Created on Wed Aug 22 15:11:27 2018
5 
6 @author: dshea
7 """
8 
9 import sys
10 import argparse
11 import os
12 import json
13 import subprocess
14 import shutil
15 
16 
17 MANIFEST_BASENAME = "manifest.json"
18 BUNDLELIST_BASENAME = "bundleList.json"
19 
20 # configInfo contains global info about the ocssw_manifest
21 # baseDir - base directory holding the manifest bundles
22 # tag - current installed tag
23 configInfo = {}
24 configInfoFilename = ".manifest_ocssw.json"
25 startingDir = ""
26 
27 manifestCommand = os.path.dirname(__file__) + "/manifest.py"
28 manifestFilename = "manifest.json"
29 
30 #remoteHosts = ["ocssw@oceanrepo401"]
31 remoteHosts = ["ocssw@gs616-container101"]
32 remoteRepoDir = "/manifest/tags"
33 
34 
38 initialBundleList = [
39  {"name":"root", "dir":".", "help":"random files in the root dir", "extra":"--exclude . --include bundleList.json --include OCSSW_bash.env --include OCSSW.env", "commandLine":True},
40  {"name":"bin_linux_64", "dir":"bin_linux_64", "help":"executables for Linux", "commandLine":False},
41  {"name":"bin_macosx_intel", "dir":"bin_macosx_intel", "help":"executables for Mac", "commandLine":False},
42  {"name":"bin_odps", "dir":"bin_odps", "help":"executables for ODPS", "commandLine":False},
43  {"name":"lib_linux_64", "dir":"lib_linux_64", "help":"shared libraries for Linux", "commandLine":False},
44  {"name":"lib_macosx_intel", "dir":"lib_macosx_intel", "help":"shared libraries for Mac", "commandLine":False},
45  {"name":"lib_odps", "dir":"lib_odps", "help":"shared libraries for ODPS", "commandLine":False},
46  {"name":"opt_linux_64", "dir":"opt_linux_64", "help":"3rd party library for Linux", "extra": "--exclude src", "commandLine":False},
47  {"name":"opt_macosx_intel", "dir":"opt_macosx_intel", "help":"3rd party library for Mac", "extra": "--exclude src", "commandLine":False},
48  {"name":"opt_odps", "dir":"opt_odps", "help":"3rd party library for ODPS", "extra": "--exclude src", "commandLine":False},
49 
50  {"name":"ocssw_src", "dir":"ocssw_src", "help":"OCSSW source code", "commandLine":False},
51  {"name":"opt_src", "dir":"opt/src", "help":"3rd party library sources", "extra":"--exclude .buildit.db", "commandLine":True},
52 
53  {"name":"afrt", "dir":"share/afrt", "help":"Ahmad-Fraser RT data", "commandLine":True},
54  {"name":"aquaverse", "dir":"share/aquaverse", "help":"Algorithm based on Mixture Density Networks", "commandLine":True},
55  {"name":"avhrr", "dir":"share/avhrr", "help":"AVHRR", "commandLine":True},
56  {"name":"aviris", "dir":"share/aviris", "help":"AVIRIS", "commandLine":True},
57  {"name":"common", "dir":"share/common", "help":"common", "commandLine":True},
58  {"name":"czcs", "dir":"share/czcs", "help":"CZCS", "commandLine":True},
59  {"name":"eval", "dir":"share/eval", "help":"evaluation", "commandLine":True},
60  {"name":"goci", "dir":"share/goci", "help":"GOCI", "commandLine":True},
61  {"name":"hawkeye", "dir":"share/hawkeye", "help":"Hawkeye", "commandLine":True},
62  {"name":"hico", "dir":"share/hico", "help":"HICO", "commandLine":True},
63  {"name":"l5tm", "dir":"share/l5tm", "help":"l5tm", "commandLine":True},
64  {"name":"l7etmp", "dir":"share/l7etmp", "help":"l7etmp", "commandLine":True},
65  {"name":"meris", "dir":"share/meris", "help":"MERIS", "commandLine":True},
66  {"name":"misr", "dir":"share/misr", "help":"MISR", "commandLine":True},
67  {"name":"modis", "dir":"share/modis", "help":"MODIS common", "extra":"--exclude aqua --exclude terra", "commandLine":False},
68  {"name":"modisa", "dir":"share/modis/aqua", "help":"MODIS AQUA", "commandLine":True},
69  {"name":"modist", "dir":"share/modis/terra", "help":"MODIS TERRA", "commandLine":True},
70  {"name":"mos", "dir":"share/mos", "help":"MOS", "commandLine":True},
71  {"name":"msi", "dir":"share/msi", "help":"MSI Sentinel 2 common", "extra":"--exclude s2a --exclude s2b", "commandLine":False},
72  {"name":"msis2a", "dir":"share/msi/s2a", "help":"MSI Sentinel 2A", "commandLine":True},
73  {"name":"msis2b", "dir":"share/msi/s2b", "help":"MSI Sentinel 2B", "commandLine":True},
74  {"name":"oci", "dir":"share/oci", "help":"PACE OCI", "commandLine":True},
75  {"name":"ocia", "dir":"share/ocia", "help":"PACE OCI AVIRIS", "commandLine":True},
76  {"name":"ocip", "dir":"share/ocip", "help":"PACE OCI PRISM", "commandLine":True},
77  {"name":"ocis", "dir":"share/ocis", "help":"PACE OCI Simulated data", "commandLine":True},
78  {"name":"ocm1", "dir":"share/ocm1", "help":"OCM1", "commandLine":True},
79  {"name":"ocm2", "dir":"share/ocm2", "help":"OCM2", "commandLine":True},
80  {"name":"ocrvc", "dir":"share/ocrvc", "help":"OC Virtual Constellation", "commandLine":True},
81  {"name":"octs", "dir":"share/octs", "help":"OCTS", "commandLine":True},
82  {"name":"olci", "dir":"share/olci", "help":"OLCI Sentinel 3 common", "extra":"--exclude s3a --exclude s3b", "commandLine":False},
83  {"name":"olcis3a", "dir":"share/olci/s3a", "help":"OLCI Sentinel 3A", "commandLine":True},
84  {"name":"olcia3b", "dir":"share/olci/s3b", "help":"OLCI Sentinel 3B", "commandLine":True},
85  {"name":"oli", "dir":"share/oli", "help":"OLI Landsat", "extra":"--exclude l8 --exclude l9", "commandLine":False},
86  {"name":"olil8", "dir":"share/oli/l8", "help":"OLI Landsat 8", "commandLine":True},
87  {"name":"olil9", "dir":"share/oli/l9", "help":"OLI Landsat 9", "commandLine":True},
88  {"name":"osmi", "dir":"share/osmi", "help":"OSMI", "commandLine":True},
89  {"name":"prism", "dir":"share/prism", "help":"PRISM", "commandLine":True},
90  {"name":"sabiamar", "dir":"share/sabiamar", "help":"Sabiamar", "commandLine":True},
91  {"name":"seawifs", "dir":"share/seawifs", "help":"SeaWiFS", "commandLine":True},
92  {"name":"sgli", "dir":"share/sgli", "help":"SGLI", "commandLine":True},
93  {"name":"spexone_remotap", "dir":"share/spexone/remotap", "help":"SPEX One RemoTAP", "commandLine":True},
94  {"name":"viirs", "dir":"share/viirs", "extra":"--exclude dem --exclude j1 --exclude j2 --exclude npp", "help":"VIIRS common", "commandLine":False},
95  {"name":"viirsdem", "dir":"share/viirs/dem", "help":"VIIRS Digital Elevation", "commandLine":True},
96  {"name":"viirsj1", "dir":"share/viirs/j1", "help":"VIIRS JPSS1", "commandLine":True},
97  {"name":"viirsj2", "dir":"share/viirs/j2", "help":"VIIRS JPSS2", "commandLine":True},
98  {"name":"viirsn", "dir":"share/viirs/npp", "help":"VIIRS NPP", "commandLine":True},
99  {"name":"wv3", "dir":"share/wv3", "help":"WV3", "commandLine":True},
100  {"name":"aerosol", "dir":"share/aerosol", "help":"aerosol processing with dtdb", "commandLine":True},
101  {"name":"cloud", "dir":"share/cloud", "help":"cloud properties processing", "commandLine":True},
102  {"name":"benchmark", "dir":"benchmark", "help":"benchmark MOSIS Aqua, level0 -> level3 Mapped", "commandLine":True},
103  {"name":"viirs_l1_benchmark", "dir":"viirs_l1_benchmark", "help":"VIIRS benchmark data", "commandLine":True},
104  {"name":"viirs_l1_bin_macosx_intel", "dir":"viirs_l1_bin_macosx_intel", "help":"Subset of binary files for VIIRS", "commandLine":False},
105  {"name":"viirs_l1_bin_linux_64", "dir":"viirs_l1_bin_linux_64", "help":"Subset of binary files for VIIRS", "commandLine":False},
106  {"name":"viirs_l1_bin_odps", "dir":"viirs_l1_bin_odps", "help":"Subset of binary files for VIIRS", "commandLine":False}
107 ]
108 
109 def add_subparser_init_dir(subparsers):
110  newParser = subparsers.add_parser('init', help="Initialize the directory to be the root of the OCSSW manifest bundles")
111  newParser.add_argument("dir", help="directory to initialize", nargs='?', default='.')
112  newParser.set_defaults(func=init_dir)
113 
114 def add_subparser_status(subparsers):
115  newParser = subparsers.add_parser('status', help="List the files that differ from the manifest")
116  newParser.add_argument("tag", nargs='?', help="tag name to use")
117  newParser.set_defaults(func=status)
118 
119 def add_subparser_push(subparsers):
120  newParser = subparsers.add_parser('push', help="Create a new tag and push to the server")
121  newParser.add_argument("tag", help="tag name to use")
122  newParser.add_argument("-o", "--overwrite", default=False, action="store_true", help="overwrite the tag if it already exists")
123  newParser.set_defaults(func=push)
124 
125 def add_subparser_pull(subparsers):
126  newParser = subparsers.add_parser('pull', help="Download a tag from the server")
127  newParser.add_argument("tag", help="tag name to use")
128  newParser.add_argument("-c", "--clean", default=False, action="store_true", help="clean the directory after downloading")
129  newParser.set_defaults(func=pull)
130 
131 def add_subparser_list(subparsers):
132  newParser = subparsers.add_parser('list', help="List the tags on the remote system")
133  newParser.set_defaults(func=list_tags)
134 
135 
136 def init_dir(options):
137  global configInfo
138 
139  if os.path.exists(options.dir):
140  if not os.path.isdir(options.dir):
141  print("Error:", options.dir, "exists and is not a directory")
142  else:
143  os.mkdir(options.dir)
144 
145  fileName = os.path.join(os.path.abspath(options.dir), configInfoFilename)
146  if os.path.exists(fileName):
147  print("Error: manifest_ocssw config file", fileName, "already exists")
148  sys.exit(1)
149 
150  # fill up an initial config structure
151  configInfo["baseDir"] = os.path.abspath(options.dir)
152  configInfo["tag"] = "Unknown"
153 
154  # save as a JSON file
155  with open(fileName, 'w') as outfile:
156  json.dump(configInfo, outfile, indent=4, sort_keys=True)
157 
158  fileName = os.path.join(os.path.abspath(options.dir), "bundleList.json")
159  with open(fileName, 'w') as outfile:
160  json.dump(initialBundleList, outfile, indent=4, sort_keys=True)
161 
162 
163 def runCommand(command, pipe=False, shellVal=False):
164  if pipe:
165  proc = subprocess.run(command, stdout=subprocess.PIPE, shell=shellVal)
166  else:
167  proc = subprocess.run(command, shell=shellVal)
168  if proc.returncode != 0:
169  print("Error: trying to run = ", command)
170  sys.exit(1)
171  if pipe:
172  return proc.stdout
173 
174 
175 def tagExists(tag):
176  command = ["ssh", "-q", remoteHosts[0], "[ -d %s/%s ]" % (remoteRepoDir, tag) ]
177  proc = subprocess.run(command)
178  if proc.returncode == 0:
179  return True
180  else:
181  return False
182 
183 
184 def bundleExists(tag, name):
185  command = ["ssh", "-q", remoteHosts[0], "[ -d %s/%s/%s ]" % (remoteRepoDir, tag, name) ]
186  proc = subprocess.run(command)
187  if proc.returncode == 0:
188  return True
189  else:
190  return False
191 
192 def findBundleInList(name, bundleList):
193  if bundleList:
194  for info in bundleList:
195  if info["name"] == name:
196  return info
197  return None
198 
199 def status(options, bundleInfo):
200  global startingDir
201 
202  # only do a status if user is sitting in the bundel directory
203  bundleDir = os.path.abspath(os.path.join(configInfo["baseDir"], bundleInfo["dir"]))
204  if startingDir not in bundleDir:
205  return
206 
207  print(bundleInfo["name"], end=' ', flush=True)
208 
209  statusTag = "tempStatusTag"
210  os.chdir(configInfo["baseDir"])
211 
212  currentManifest = {}
213  if hasattr(options, "tag") and options.tag:
214  if tagExists(options.tag):
215  if bundleExists(options.tag, bundleInfo["name"]):
216  command = ["scp", "-q", "%s:%s/%s/%s/%s" % (remoteHosts[0], remoteRepoDir, options.tag, bundleInfo["name"], manifestFilename), "/tmp"]
217  runCommand(command)
218  with open("/tmp/" + manifestFilename, 'rb') as manifest:
219  currentManifest = json.load(manifest)
220  os.remove("/tmp/" + manifestFilename)
221  else:
222  print("Warning: bundle %s does not exist in tag %s on server." % (bundleInfo["name"], options.tag))
223  else:
224  print("Error: tag:", options.tag, "does not exist on server")
225  sys.exit(1)
226  else:
227  # open current manifest
228  if bundleExists(configInfo["tag"], bundleInfo["name"]):
229  command = ["scp", "-q", "%s:%s/%s/%s/%s" % (remoteHosts[0], remoteRepoDir, configInfo["tag"], bundleInfo["name"], manifestFilename), "/tmp"]
230  runCommand(command)
231  with open("/tmp/" + manifestFilename, 'rb') as manifest:
232  currentManifest = json.load(manifest)
233  os.remove("/tmp/" + manifestFilename)
234 
235  if not os.path.isdir(bundleInfo["dir"]):
236  print("Warning: bundle directory %s does not exist." % (bundleInfo["dir"]))
237  return
238 
239  command = [manifestCommand, "generate",
240  "-n", bundleInfo["name"],
241  "-t", statusTag,
242  bundleInfo["dir"]]
243  if "extra" in bundleInfo:
244  command += bundleInfo["extra"].split()
245  statusManifest = json.loads(runCommand(command, pipe=True))
246 
247  if "tags" in currentManifest:
248  tagList = currentManifest["tags"]
249  versionStr = "("
250  if len(tagList) > 1:
251  versionStr += tagList[0] + ".."
252  versionStr += tagList[-1] + ")"
253  print(versionStr)
254  else:
255  print()
256 
257  # list new files
258  fileList = []
259  for f, info in statusManifest["files"].items():
260  if ("files" not in currentManifest) or (f not in currentManifest["files"]):
261  fileList.append(f)
262  if fileList:
263  print(" New Files:")
264  for f in fileList:
265  print(" %s/%s" % (bundleInfo["dir"], f))
266 
267  # list modified files
268  fileList = []
269  for f, info in statusManifest["files"].items():
270  if ("files" in currentManifest) and (f in currentManifest["files"]):
271  if info["tag"] != currentManifest["files"][f]["tag"]:
272  fileList.append(f)
273  if fileList:
274  print(" Modified Files:")
275  for f in fileList:
276  print(" %s/%s" % (bundleInfo["dir"], f))
277 
278  # deleted file
279  fileList = []
280  if "files" in currentManifest:
281  for f, info in currentManifest["files"].items():
282  if f not in statusManifest["files"]:
283  fileList.append(f)
284  if fileList:
285  print(" Deleted Files:")
286  for f in fileList:
287  print(" %s/%s" % (bundleInfo["dir"], f))
288 
289 
290 def push(options, bundleInfo):
291  os.chdir(configInfo["baseDir"])
292  command = [manifestCommand, "generate",
293  "-n", bundleInfo["name"],
294  "-t", options.tag,
295  bundleInfo["dir"]]
296  if "extra" in bundleInfo:
297  command += bundleInfo["extra"].split()
298  newManifest = json.loads(runCommand(command, pipe=True))
299 
300  print(bundleInfo["name"])
301  os.chdir(bundleInfo["dir"])
302 
303  # list files to upload
304  fileList = []
305  for f, info in newManifest["files"].items():
306  if info["tag"] == options.tag:
307  fileList.append(f)
308 
309  # check if files were deleted
310  filesWereDeleted = False
311  if bundleExists(configInfo["tag"], bundleInfo["name"]):
312  command = ["scp", "-q", "%s:%s/%s/%s/%s" % (remoteHosts[0], remoteRepoDir, configInfo["tag"], bundleInfo["name"], manifestFilename), "/tmp"]
313  runCommand(command)
314  with open("/tmp/" + manifestFilename, 'rb') as manifest:
315  currentManifest = json.load(manifest)
316 
317  for f, info in currentManifest["files"].items():
318  if f not in newManifest["files"]:
319  filesWereDeleted = True
320  break
321  os.remove("/tmp/" + manifestFilename)
322 
323  if fileList or filesWereDeleted:
324  # save manifest file
325  with open(manifestFilename, 'w') as outfile:
326  json.dump(newManifest, outfile, indent=4, sort_keys=True)
327 
328  # make tmp file with list of files to upload
329  tmpFilename = "/tmp/changeList.txt"
330  with open(tmpFilename, 'w') as changeFile:
331  changeFile.write(manifestFilename)
332  changeFile.write("\n")
333  for f in fileList:
334  if not os.path.islink(f):
335  changeFile.write(f)
336  changeFile.write("\n")
337 
338  # upload files
339  for host in remoteHosts:
340  command = ["ssh", "-q", host, "mkdir -p %s/%s/%s" % (remoteRepoDir, options.tag, bundleInfo["name"]) ]
341  runCommand(command)
342 
343  command = ["rsync", "-hav", "--files-from=" + tmpFilename, ".", "%s:%s/%s/%s/" % (host, remoteRepoDir, options.tag, bundleInfo["name"]) ]
344  runCommand(command)
345  os.remove(tmpFilename)
346 
347  else:
348  print(" No files Changed, creating symbolic link")
349 
350  # add tag to manifest
351  command = [manifestCommand, "add-tag", options.tag]
352  newManifest = json.loads(runCommand(command, pipe=True))
353  with open(manifestFilename, 'w') as outfile:
354  json.dump(newManifest, outfile, indent=4, sort_keys=True)
355 
356  firstTag = newManifest['tags'][0]
357 
358  # update remote manifest and make symbolic link
359  for host in remoteHosts:
360  command = ["ssh", "-q", host, "mkdir -p %s/%s" % (remoteRepoDir, options.tag)]
361  runCommand(command)
362 
363  command = [ "scp", "-q", manifestFilename, "%s:%s/%s/%s/%s" % (host, remoteRepoDir, firstTag, bundleInfo["name"], manifestFilename) ]
364  runCommand(command)
365 
366  command = ["ssh", "-q", host, "ln -s %s/%s/%s %s/%s/%s" %
367  (remoteRepoDir, firstTag, bundleInfo["name"],
368  remoteRepoDir, options.tag, bundleInfo["name"]) ]
369  runCommand(command)
370 
371 def pull(options, bundleInfo):
372  print(bundleInfo["name"])
373  if bundleExists(options.tag, bundleInfo["name"]):
374  os.chdir(configInfo["baseDir"])
375  command = [manifestCommand, "download",
376  "-n", bundleInfo["name"],
377  "-t", options.tag,
378  "-d", bundleInfo["dir"]]
379  runCommand(command)
380  if options.clean:
381  command = [manifestCommand, "clean", bundleInfo["dir"]]
382  if "extra" in bundleInfo:
383  command += bundleInfo["extra"].split()
384  runCommand(command)
385  else:
386  print("Warning: Bundle %s does not exist in tag %s on the server" %(bundleInfo["name"], options.tag))
387  if options.clean:
388  if os.path.isdir(bundleInfo["dir"]):
389  print("Cleaning bundle directory", bundleInfo["dir"])
390  shutil.rmtree(bundleInfo["dir"])
391 
392 def list_tags(options):
393  command = ["ssh", "-q", remoteHosts[0], "ls " + remoteRepoDir]
394  runCommand(command)
395 
396 
397 def run():
398  global configInfo
399  global startingDir
400 
401  parser = argparse.ArgumentParser(description="Work on the minifest directories for OCSSW")
402  parser.set_defaults(func=status)
403  subparsers = parser.add_subparsers()
404 
405  add_subparser_init_dir(subparsers)
406  add_subparser_status(subparsers)
407  add_subparser_push(subparsers)
408  add_subparser_pull(subparsers)
409  add_subparser_list(subparsers)
410 
411  options = parser.parse_args()
412 
413  # check if we are initializing a new OCSSW manifest
414  if options.func == init_dir:
415  options.func(options)
416  return 0
417 
418  # check if we are listing the tags
419  if options.func == list_tags:
420  options.func(options)
421  return 0
422 
423  # if making a new tag, make sure tag does not exist or the --overwite flag is used
424  if options.func == push:
425  if tagExists(options.tag):
426  if options.overwrite:
427  for host in remoteHosts:
428  command = ["ssh", "-q", host, "rm -rf " + remoteRepoDir + "/" + options.tag]
429  runCommand(command)
430  else:
431  print("Error: tag", options.tag, "exists.")
432  print("Use --overwrite (-o) to continue (will delete old version)")
433  return 1
434 
435  # find the config file
436  baseDir = os.path.abspath(os.getcwd())
437  startingDir = baseDir
438  while(baseDir != "/"):
439  fileName = os.path.join(baseDir, configInfoFilename)
440  if os.path.exists(fileName):
441  with open(fileName, 'rb') as configFile:
442  configInfo = json.load(configFile)
443  if configInfo["baseDir"] != baseDir:
444  print("Error: config file has been moved")
445  print(" real baseDir = ", baseDir)
446  print(" configFile baseDir =", configInfo["baseDir"])
447  return 1
448  else:
449  break
450  baseDir = os.path.dirname(baseDir)
451  if baseDir == "/":
452  print("Error: manifest_ocssw config file not found in current or parent directories")
453  print(" Run: manifest_ocssw init")
454  return 1
455 
456  print("current tag =", configInfo["tag"])
457 
458  #load local bundleList json file
459  localBundleList = None
460  localBundleListFile = "%s/%s" % (baseDir, BUNDLELIST_BASENAME)
461  if not os.path.isfile(localBundleListFile):
462  print("Must have a %s file in the root directory" % (BUNDLELIST_BASENAME))
463  sys.exit(1)
464  with open(localBundleListFile, 'rb') as jsonFile:
465  localBundleList = json.load(jsonFile)
466  if not localBundleList:
467  print("Must have a valid %s file in the root directory" % (BUNDLELIST_BASENAME))
468  sys.exit(1)
469 
470  # download remote bundleList json files
471  remoteBundleList = None
472  remoteBundleListFile = "/tmp/%s" % (BUNDLELIST_BASENAME)
473  remoteManifest = None
474  remoteManifestFile = "/tmp/%s" % (MANIFEST_BASENAME)
475  tag = configInfo["tag"]
476  if options.func == pull:
477  tag = options.tag
478  elif options.func == status:
479  if hasattr(options, "tag") and options.tag:
480  tag = options.tag
481 
482  if tagExists(tag):
483  # download manifest file first
484  command = ["scp", "-q", "%s:%s/%s/root/%s" %
485  (remoteHosts[0], remoteRepoDir, tag, MANIFEST_BASENAME),
486  remoteManifestFile]
487  runCommand(command)
488  with open(remoteManifestFile, 'rb') as jsonFile:
489  remoteManifest = json.load(jsonFile)
490  os.remove(remoteManifestFile)
491 
492  # download bundleList
493  command = ["scp", "-q", "%s:%s/%s/root/%s" %
494  (remoteHosts[0], remoteRepoDir, remoteManifest['files'][BUNDLELIST_BASENAME]['tag'],
495  BUNDLELIST_BASENAME), remoteBundleListFile]
496  runCommand(command)
497  with open(remoteBundleListFile, 'rb') as jsonFile:
498  remoteBundleList = json.load(jsonFile)
499  os.remove(remoteBundleListFile)
500 
501  # check for new local bundles
502  for bundleInfo in localBundleList:
503  if not findBundleInList(bundleInfo["name"], remoteBundleList):
504  print("New local bundle -", bundleInfo["name"])
505 
506  # check for deleted bundles
507  if remoteBundleList:
508  for bundleInfo in remoteBundleList:
509  if not findBundleInList(bundleInfo["name"], localBundleList):
510  print("Deleted local bundle -", bundleInfo["name"])
511 
512  bundleList = localBundleList
513  if options.func == pull:
514  bundleList = remoteBundleList
515 
516  # actually run the function
517  #for bundleInfo in bundleList:
518  for bundleInfo in bundleList:
519  options.func(options, bundleInfo)
520 
521  # update the tag in the configInfo
522  if options.func == push or options.func == pull:
523  configInfo["tag"] = options.tag
524 
525  # save as a JSON file
526  fileName = os.path.join(baseDir, configInfoFilename)
527  with open(fileName, 'w') as outfile:
528  json.dump(configInfo, outfile, indent=4, sort_keys=True)
529 
530  return 0
531 
532 
533 if __name__ == "__main__":
534  sys.exit(run())
535 
def add_subparser_status(subparsers)
def list_tags(options)
def add_subparser_push(subparsers)
def init_dir(options)
def findBundleInList(name, bundleList)
def push(options, bundleInfo)
def status(options, bundleInfo)
def add_subparser_pull(subparsers)
def bundleExists(tag, name)
def runCommand(command, pipe=False, shellVal=False)
def add_subparser_list(subparsers)
def add_subparser_init_dir(subparsers)
def pull(options, bundleInfo)
def tagExists(tag)
while(++r<=NROOTS)
Definition: decode_rs.h:169