content: #!/usr/bin/env python3
  
  # Copyright 2019-2020 CERN and copyright holders of ALICE O2.
  # See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
  # All rights not expressly granted are reserved.
  #
  # This software is distributed under the terms of the GNU General Public
  # License v3 (GPL Version 3), copied verbatim in the file "COPYING".
  #
  # In applying this license CERN does not waive the privileges and immunities
  # granted to it by virtue of its status as an Intergovernmental Organization
  # or submit itself to any jurisdiction.
  
  """
  Script to update the CCDB with timestamp non-overlapping objects.
  If an object is found in the range specified, the object is split into two.
  If the requested range was overlapping three objects are uploaded on CCDB:
  1) latest object with requested timestamp validity
  2) old object with validity [old_lower_validity-requested_lower_bound]
  3) old object with validity [requested_upper_bound, old_upper_validity]
  Author: Nicolo' Jacazio on 2020-06-22
  TODO add support for 3 files update
  """
  
  import subprocess
  from datetime import datetime
  import matplotlib.pyplot as plt
  import argparse
  
  
  def convert_timestamp(ts):
      """
      Converts the timestamp in milliseconds in human readable format
      """
      return datetime.utcfromtimestamp(ts/1000).strftime('%Y-%m-%d %H:%M:%S')
  
  
  def get_ccdb_obj(path, timestamp, dest="/tmp/", verbose=0):
      """
      Gets the ccdb object from 'path' and 'timestamp' and downloads it into 'dest'
      """
      if verbose:
          print("Getting obj", path, "with timestamp",
                timestamp, convert_timestamp(timestamp))
      cmd = f"o2-ccdb-downloadccdbfile --path {path} --dest {dest} --timestamp {timestamp}"
      subprocess.run(cmd.split())
  
  
  def get_ccdb_obj_validity(path, dest="/tmp/", verbose=0):
      """
      Gets the timestamp validity for an object downloaded from CCDB.
      Returns a list with the initial and end timestamps.
      """
      cmd = f"o2-ccdb-inspectccdbfile {dest}{path}/snapshot.root"
      process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
      output, error = process.communicate()
      output = output.decode("utf-8").split("\n")
      error = error.decode("utf-8").split("\n") if error is not None else error
      if verbose:
          print("out:")
          print(*output, "\n")
          print("err:")
          print(error)
      result = list(filter(lambda x: x.startswith('Valid-'), output))
      ValidFrom = result[0].split()
      ValidUntil = result[1].split()
      return [int(ValidFrom[-1]), int(ValidUntil[-1])]
  
  
  def upload_ccdb_obj(path, timestamp_from, timestamp_until, dest="/tmp/", meta=""):
      """
      Uploads a new object to CCDB in the 'path' using the validity timestamp specified
      """
      print("Uploading obj", path, "with timestamp", [timestamp_from, timestamp_until],
            convert_timestamp(timestamp_from), convert_timestamp(timestamp_until))
      key = path.split("/")[-1]
      cmd = f"o2-ccdb-upload -f {dest}{path}/snapshot.root "
      cmd += f"--key {key} --path {path} "
      cmd += f"--starttimestamp {timestamp_from} --endtimestamp {timestamp_until} --meta \"{meta}\""
      subprocess.run(cmd.split())
  
  
  def main(path, timestamp_from, timestamp_until, verbose=0, show=False):
      """
      Used to upload a new object to CCDB in 'path' valid from 'timestamp_from' to 'timestamp_until'
      Gets the object from CCDB specified in 'path' and for 'timestamp_from-1'
      Gets the object from CCDB specified in 'path' and for 'timestamp_until+1'
      If required plots the situation before and after the update
      """
      get_ccdb_obj(path, timestamp_from-1)
      val_before = get_ccdb_obj_validity(path, verbose=verbose)
      get_ccdb_obj(path, timestamp_until+1)
      val_after = get_ccdb_obj_validity(path, verbose=verbose)
      overlap_before = val_before[1] > timestamp_from
      overlap_after = val_after[0] < timestamp_until
      if verbose:
          if overlap_before:
              print("Previous objects overalps")
          if overlap_after:
              print("Next objects overalps")
      trimmed_before = val_before if not overlap_before else [
          val_before[0], timestamp_from - 1]
      trimmed_after = val_after if not overlap_after else [
          timestamp_until+1, val_after[1]]
      if show:
          fig, ax = plt.subplots()
          fig
  
          def bef_af(v, y):
              return [v[0] - 1] + v + [v[1] + 1], [0, y, y, 0]
          if True:
              ax.plot(*bef_af(val_before, 0.95), label='before')
              ax.plot(*bef_af(val_after, 1.05), label='after')
          if False:
              ax.plot(*bef_af(trimmed_before, 0.9), label='trimmed before')
              ax.plot(*bef_af(trimmed_after, 1.1), label='trimmed after')
          ax.plot(*bef_af([timestamp_from, timestamp_until], 1), label='object')
          xlim = 10000000
          plt.xlim([timestamp_from-xlim, timestamp_until+xlim])
          plt.ylim(0, 2)
          plt.xlabel('Timestamp')
          plt.ylabel('Validity')
          plt.legend()
          plt.show()
  
  
  if __name__ == "__main__":
      parser = argparse.ArgumentParser(
          description="Uploads timestamp non overlapping objects to CCDB."
          "Basic example: `./update_ccdb.py qc/TOF/TOFTaskCompressed/hDiagnostic 1588956517161 1588986517161 --show --verbose`")
      parser.add_argument('path', metavar='path_to_object', type=str,
                          help='Path of the object in the CCDB repository')
      parser.add_argument('timestamp_from', metavar='from_timestamp', type=int,
                          help='Timestamp of start for the new object to use')
      parser.add_argument('timestamp_until', metavar='until_timestamp', type=int,
                          help='Timestamp of stop for the new object to use')
      parser.add_argument('--verbose', '-v', action='count', default=0)
      parser.add_argument('--show', '-s', action='count', default=0)
  
      args = parser.parse_args()
      main(path=args.path,
           timestamp_from=args.timestamp_from,
           timestamp_until=args.timestamp_until,
           verbose=args.verbose,
           show=args.show)
  