|  | @@ -9,197 +9,197 @@ answer_json = []
 | 
	
		
			
				|  |  |  verbose = 0
 | 
	
		
			
				|  |  |  db = None
 | 
	
		
			
				|  |  |  xattr_comment = "user.xdg.comment"
 | 
	
		
			
				|  |  | -xattr_author  = "user.xdg.comment.author"
 | 
	
		
			
				|  |  | -xattr_date    = "user.xdg.comment.date"
 | 
	
		
			
				|  |  | +xattr_author    = "user.xdg.comment.author"
 | 
	
		
			
				|  |  | +xattr_date      = "user.xdg.comment.date"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #======= debugging/verbose ===========
 | 
	
		
			
				|  |  |  def print_d(*a):
 | 
	
		
			
				|  |  | -  if verbose > 1:
 | 
	
		
			
				|  |  | -    print('>>',*a)
 | 
	
		
			
				|  |  | +    if verbose > 1:
 | 
	
		
			
				|  |  | +        print('>>',*a)
 | 
	
		
			
				|  |  |  def print_v(*a):
 | 
	
		
			
				|  |  | -  if verbose:
 | 
	
		
			
				|  |  | -    print('>',*a)
 | 
	
		
			
				|  |  | +    if verbose:
 | 
	
		
			
				|  |  | +        print('>',*a)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #============= the functions that are called from the main.loop ===============
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def file_copy(f,target,target_is_dir,force):
 | 
	
		
			
				|  |  | -  print_d(f"call file_copy with args={target},{target_is_dir} and {force}")
 | 
	
		
			
				|  |  | -  dest = target if not target_is_dir else target+'/'+os.path.basename(f)
 | 
	
		
			
				|  |  | -  if os.path.exists(dest) and not force:
 | 
	
		
			
				|  |  | -    go = input("The copy target <<" + dest + ">> exists. Overwrite? (y or n) ")
 | 
	
		
			
				|  |  | -    if go != 'y' and go != 'Y':
 | 
	
		
			
				|  |  | -      return
 | 
	
		
			
				|  |  | -  print_d(f"copy from {f} to {dest}")
 | 
	
		
			
				|  |  | +    print_d(f"call file_copy with args={target},{target_is_dir} and {force}")
 | 
	
		
			
				|  |  | +    dest = target if not target_is_dir else target+'/'+os.path.basename(f)
 | 
	
		
			
				|  |  | +    if os.path.exists(dest) and not force:
 | 
	
		
			
				|  |  | +        go = input("The copy target <<" + dest + ">> exists. Overwrite? (y or n) ")
 | 
	
		
			
				|  |  | +        if go != 'y' and go != 'Y':
 | 
	
		
			
				|  |  | +            return
 | 
	
		
			
				|  |  | +    print_d(f"copy from {f} to {dest}")
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def file_zap(f,all_flag):
 | 
	
		
			
				|  |  | -  print_d(f"zapping the comment history of {f}")
 | 
	
		
			
				|  |  | -  if all_flag:
 | 
	
		
			
				|  |  | -    print_d("zapping the entire database")
 | 
	
		
			
				|  |  | +    print_d(f"zapping the comment history of {f}")
 | 
	
		
			
				|  |  | +    if all_flag:
 | 
	
		
			
				|  |  | +        print_d("zapping the entire database")
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def file_modify_comment(f, create, append, erase):
 | 
	
		
			
				|  |  | -  print_d(f"modify the comment on file {f} with extra={(create,append,erase)}")
 | 
	
		
			
				|  |  | -  if not os.path.exists(f):
 | 
	
		
			
				|  |  | -    print(f"the target file does not exist; please check the spelling of the file: {f}")
 | 
	
		
			
				|  |  | -    # sys.exit() here?
 | 
	
		
			
				|  |  | +    print_d(f"modify the comment on file {f} with extra={(create,append,erase)}")
 | 
	
		
			
				|  |  | +    if not os.path.exists(f):
 | 
	
		
			
				|  |  | +        print(f"the target file does not exist; please check the spelling of the file: {f}")
 | 
	
		
			
				|  |  | +        # sys.exit() here?
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def file_display(f, listall, history, json, minimal):
 | 
	
		
			
				|  |  | -  print_d(f"list file details {f}")
 | 
	
		
			
				|  |  | -  x_comment = None
 | 
	
		
			
				|  |  | -  try:
 | 
	
		
			
				|  |  | -    x_comment = xattr.getxattr(f,xattr_comment).decode()
 | 
	
		
			
				|  |  | -    x_author  = xattr.getxattr(f,xattr_author).decode()
 | 
	
		
			
				|  |  | -    x_date    = xattr.getxattr(f,xattr_date).decode()
 | 
	
		
			
				|  |  | -  except:
 | 
	
		
			
				|  |  | -    pass
 | 
	
		
			
				|  |  | -  full_f = os.path.realpath(f)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  d_comment = getDbComment(full_f)
 | 
	
		
			
				|  |  | -  if d_comment:
 | 
	
		
			
				|  |  | -    d_comment, d_author, d_date = d_comment
 | 
	
		
			
				|  |  | -  print_d(f"for file {f}, database comment is <{d_comment}>, xattr comment is <{x_comment}>")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if os.path.isdir(f):
 | 
	
		
			
				|  |  | -    f = f+'/'
 | 
	
		
			
				|  |  | -  if x_comment or listall:
 | 
	
		
			
				|  |  | -    if x_comment and (d_comment != x_comment):
 | 
	
		
			
				|  |  | -      x_comment += '*'
 | 
	
		
			
				|  |  | -    if not json:
 | 
	
		
			
				|  |  | -      if minimal:
 | 
	
		
			
				|  |  | -        print(f"{x_comment}")
 | 
	
		
			
				|  |  | -      else:
 | 
	
		
			
				|  |  | -        print(f"{f}: {x_comment}")
 | 
	
		
			
				|  |  | -    else:
 | 
	
		
			
				|  |  | -      if verbose:
 | 
	
		
			
				|  |  | -        answer_json.append( {"file":f,"comment":x_comment,"author":x_author,"date":x_date } )
 | 
	
		
			
				|  |  | -      else:
 | 
	
		
			
				|  |  | -        answer_json.append( {"file":f,"comment":x_comment} )
 | 
	
		
			
				|  |  | +    print_d(f"list file details {f}")
 | 
	
		
			
				|  |  | +    x_comment = None
 | 
	
		
			
				|  |  | +    try:
 | 
	
		
			
				|  |  | +        x_comment = xattr.getxattr(f,xattr_comment).decode()
 | 
	
		
			
				|  |  | +        x_author    = xattr.getxattr(f,xattr_author).decode()
 | 
	
		
			
				|  |  | +        x_date      = xattr.getxattr(f,xattr_date).decode()
 | 
	
		
			
				|  |  | +    except:
 | 
	
		
			
				|  |  | +        pass
 | 
	
		
			
				|  |  | +    full_f = os.path.realpath(f)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    d_comment = getDbComment(full_f)
 | 
	
		
			
				|  |  | +    if d_comment:
 | 
	
		
			
				|  |  | +        d_comment, d_author, d_date = d_comment
 | 
	
		
			
				|  |  | +    print_d(f"for file {f}, database comment is <{d_comment}>, xattr comment is <{x_comment}>")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if os.path.isdir(f):
 | 
	
		
			
				|  |  | +        f = f+'/'
 | 
	
		
			
				|  |  | +    if x_comment or listall:
 | 
	
		
			
				|  |  | +        if x_comment and (d_comment != x_comment):
 | 
	
		
			
				|  |  | +            x_comment += '*'
 | 
	
		
			
				|  |  | +        if not json:
 | 
	
		
			
				|  |  | +            if minimal:
 | 
	
		
			
				|  |  | +                print(f"{x_comment}")
 | 
	
		
			
				|  |  | +            else:
 | 
	
		
			
				|  |  | +                print(f"{f}: {x_comment}")
 | 
	
		
			
				|  |  | +        else:
 | 
	
		
			
				|  |  | +            if verbose:
 | 
	
		
			
				|  |  | +                answer_json.append( {"file":f,"comment":x_comment,"author":x_author,"date":x_date } )
 | 
	
		
			
				|  |  | +            else:
 | 
	
		
			
				|  |  | +                answer_json.append( {"file":f,"comment":x_comment} )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def getDbComment(full_filename):
 | 
	
		
			
				|  |  | -  global db
 | 
	
		
			
				|  |  | -  print_d(f"db access for {full_filename}")
 | 
	
		
			
				|  |  | -  c = db.cursor()
 | 
	
		
			
				|  |  | -  c.execute("select comment,author,comment_date from dirnotes where name=? and comment<>'' order by comment_date desc",(full_filename,))
 | 
	
		
			
				|  |  | -  a = c.fetchone()
 | 
	
		
			
				|  |  | -  if a:
 | 
	
		
			
				|  |  | -    return a[0:3]
 | 
	
		
			
				|  |  | +    global db
 | 
	
		
			
				|  |  | +    print_d(f"db access for {full_filename}")
 | 
	
		
			
				|  |  | +    c = db.cursor()
 | 
	
		
			
				|  |  | +    c.execute("select comment,author,comment_date from dirnotes where name=? and comment<>'' order by comment_date desc",(full_filename,))
 | 
	
		
			
				|  |  | +    a = c.fetchone()
 | 
	
		
			
				|  |  | +    if a:
 | 
	
		
			
				|  |  | +        return a[0:3]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def openDb():
 | 
	
		
			
				|  |  | -  global db
 | 
	
		
			
				|  |  | -  dbName = "~/.dirnotes.db"
 | 
	
		
			
				|  |  | -  dbName = os.path.expanduser(dbName)
 | 
	
		
			
				|  |  | -  db = sqlite3.connect(dbName)
 | 
	
		
			
				|  |  | -  try:
 | 
	
		
			
				|  |  | -    c = db.cursor()
 | 
	
		
			
				|  |  | -    c.execute("select * from dirnotes")
 | 
	
		
			
				|  |  | -  except sqlite3.OperationalError:
 | 
	
		
			
				|  |  | -    c.execute("create table dirnotes (name TEXT, date DATETIME, size INTEGER, comment TEXT, comment_date DATETIME, author TEXT)")
 | 
	
		
			
				|  |  | -  return db 
 | 
	
		
			
				|  |  | +    global db
 | 
	
		
			
				|  |  | +    dbName = "~/.dirnotes.db"
 | 
	
		
			
				|  |  | +    dbName = os.path.expanduser(dbName)
 | 
	
		
			
				|  |  | +    db = sqlite3.connect(dbName)
 | 
	
		
			
				|  |  | +    try:
 | 
	
		
			
				|  |  | +        c = db.cursor()
 | 
	
		
			
				|  |  | +        c.execute("select * from dirnotes")
 | 
	
		
			
				|  |  | +    except sqlite3.OperationalError:
 | 
	
		
			
				|  |  | +        c.execute("create table dirnotes (name TEXT, date DATETIME, size INTEGER, comment TEXT, comment_date DATETIME, author TEXT)")
 | 
	
		
			
				|  |  | +    return db 
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def main(args):
 | 
	
		
			
				|  |  | -  parser = argparse.ArgumentParser(description="Display or add comments to files",
 | 
	
		
			
				|  |  | -    epilog="Some options conflict. Use only one of: -l -c -a -H -e -z -Z and one of -d -x")
 | 
	
		
			
				|  |  | -  parser.add_argument('-V',"--version", action="version",   version=f"dncli ver:{VERSION}")
 | 
	
		
			
				|  |  | -  parser.add_argument('-v',"--verbose", action='count',     help="verbose, almost debugging; do not use in scripts",default=0)
 | 
	
		
			
				|  |  | -  parser.add_argument('-j',"--json",    action="store_true",help="output in JSON format")
 | 
	
		
			
				|  |  | -  pars_m = parser.add_mutually_exclusive_group()
 | 
	
		
			
				|  |  | -  pars_m.add_argument('-l',"--listall", action="store_true",help="list all files, including those without comments")
 | 
	
		
			
				|  |  | -  parser.add_argument('-d',"--db",      action="store_true",help="list comments from database")
 | 
	
		
			
				|  |  | -  parser.add_argument('-x',"--xattr",   action="store_true",help="list comments from xattr")
 | 
	
		
			
				|  |  | -  parser.add_argument('-n',"--minimal", action="store_true",help="output only comments; useful in scripting")
 | 
	
		
			
				|  |  | -  parser.add_argument('-H',"--history", action="store_true",help="output the history of comments for a file")
 | 
	
		
			
				|  |  | -  pars_m.add_argument('-c',"--create",  metavar="comment",  help="add a comment to a file")
 | 
	
		
			
				|  |  | -  pars_m.add_argument('-a',"--append",  metavar="comment",  help="append to a comment on a file, separator=';'")
 | 
	
		
			
				|  |  | -  pars_m.add_argument('-C',"--copy",    action="store_true",help="copy a file with its comments")
 | 
	
		
			
				|  |  | -  parser.add_argument('-y',"--cp_force",action="store_true",help="copy over existing files")
 | 
	
		
			
				|  |  | -  pars_m.add_argument('-e',"--erase",   action="store_true",help="erase the comment on a file")
 | 
	
		
			
				|  |  | -  pars_m.add_argument('-z',"--zap",     action="store_true",help="clear the comment history on a file")
 | 
	
		
			
				|  |  | -  pars_m.add_argument('-Z',"--zapall",   action="store_true",help="clear the comment history in the entire database")
 | 
	
		
			
				|  |  | -  parser.add_argument('file_list',nargs='*',help="file(s); list commands may omit this")
 | 
	
		
			
				|  |  | -  args = parser.parse_args()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  # default is to display all files that have comments
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  # major modes are: display (<none> -l -H), add-comment (-a -c -e), clear-history(-z -Z), copy (-C)
 | 
	
		
			
				|  |  | -  # determine the major mode, then apply an appropriate function over the file_list
 | 
	
		
			
				|  |  | -  
 | 
	
		
			
				|  |  | -  args.display = not (args.create or args.append or args.copy or args.erase or args.zap or args.zapall)
 | 
	
		
			
				|  |  | -  if args.cp_force and not args.copy:
 | 
	
		
			
				|  |  | -    print("the -y/--cp_force options can only be used with the -C/--copy command")
 | 
	
		
			
				|  |  | -    sys.exit(3)   
 | 
	
		
			
				|  |  | -  if args.json and not args.display:
 | 
	
		
			
				|  |  | -    print("the -j/--json option can only be used with the display modes")
 | 
	
		
			
				|  |  | -    sys.exit(4)
 | 
	
		
			
				|  |  | -  if args.minimal and not args.display:
 | 
	
		
			
				|  |  | -    print("the -n/--minimal option only applies to the display modes")
 | 
	
		
			
				|  |  | -    sys.exit(5)
 | 
	
		
			
				|  |  | -  if args.history and not args.display:
 | 
	
		
			
				|  |  | -    print("the -H/--history option only applies to the display modes")
 | 
	
		
			
				|  |  | -    sys.exit(5)
 | 
	
		
			
				|  |  | -  if args.xattr and (args.zap or args.zapall):
 | 
	
		
			
				|  |  | -    print("the -x/--xattr option doesn't apply to the -z/--zap and -Z/--zapall commands")
 | 
	
		
			
				|  |  | -    sys.exit(7)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  global verbose
 | 
	
		
			
				|  |  | -  verbose = args.verbose
 | 
	
		
			
				|  |  | -  
 | 
	
		
			
				|  |  | -  #====== 1) build the file list =============
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  files = args.file_list
 | 
	
		
			
				|  |  | -  # for the list commands, auto-fill the file list with the current directory
 | 
	
		
			
				|  |  | -  if not files and args.display:
 | 
	
		
			
				|  |  | -    files = os.listdir(".")
 | 
	
		
			
				|  |  | -    files.sort()
 | 
	
		
			
				|  |  | -  # other command require explicity file lists, but 'dncli -c "new comment" *' will work
 | 
	
		
			
				|  |  | -  if not files:
 | 
	
		
			
				|  |  | -    print("please specify a file or files to use")
 | 
	
		
			
				|  |  | -    sys.exit(10)
 | 
	
		
			
				|  |  | -  print_d("got the files:", files)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  #======= 2) build the function
 | 
	
		
			
				|  |  | -  if args.create or args.append or args.erase:
 | 
	
		
			
				|  |  | -    print_d(f"create/append/erase: {args.create} . {args.append} . {args.erase}")
 | 
	
		
			
				|  |  | -    func = file_modify_comment
 | 
	
		
			
				|  |  | -    loop_args = (args.create, args.append, args.erase)
 | 
	
		
			
				|  |  | -  elif args.zap or args.zapall:
 | 
	
		
			
				|  |  | -    print_d(f"got a zap command {args.zap} . {args.zapall}")
 | 
	
		
			
				|  |  | -    func = file_zap
 | 
	
		
			
				|  |  | -    loop_args = (args.zapall,)
 | 
	
		
			
				|  |  | -    if args.zapall:
 | 
	
		
			
				|  |  | -      files = (1,)
 | 
	
		
			
				|  |  | -  elif args.copy:
 | 
	
		
			
				|  |  | -    print_d(f"got a copy command to {args.copy}")
 | 
	
		
			
				|  |  | -    # the last item on the file list is the target
 | 
	
		
			
				|  |  | -    n_files = len(files)
 | 
	
		
			
				|  |  | -    if n_files < 2:
 | 
	
		
			
				|  |  | -      print_d(f"the copy command requires at least two arguments, the last one is the destination")
 | 
	
		
			
				|  |  | -      sys.exit(1)
 | 
	
		
			
				|  |  | -    target = files[-1]
 | 
	
		
			
				|  |  | -    target_is_directory = os.path.isdir(target)
 | 
	
		
			
				|  |  | -    files = files[:-1]
 | 
	
		
			
				|  |  | -    print_d(f"copy from {files} to {target}")
 | 
	
		
			
				|  |  | -    if n_files > 2 and not target_is_directory:
 | 
	
		
			
				|  |  | -      print_d(f"multiple copy files must go to a target directory")
 | 
	
		
			
				|  |  | -      sys.exit(3)
 | 
	
		
			
				|  |  | -    func = file_copy
 | 
	
		
			
				|  |  | -    loop_args = (target, target_is_directory, args.cp_force)
 | 
	
		
			
				|  |  | -  else:
 | 
	
		
			
				|  |  | -    assert(args.display)
 | 
	
		
			
				|  |  | -    print_v(f"list files using {'database' if args.db else 'xattr'} priority")
 | 
	
		
			
				|  |  | -    print_d(f"display command with option: {args.listall} and {args.history} and {args.json} and {args.minimal}")
 | 
	
		
			
				|  |  | -    loop_args = (args.listall, args.history, args.json, args.minimal)
 | 
	
		
			
				|  |  | -    func = file_display
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  #====== 3) loop on the list, execute the function =============
 | 
	
		
			
				|  |  | -  global db
 | 
	
		
			
				|  |  | -  db = openDb()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  for f in files:
 | 
	
		
			
				|  |  | -    func(f,*loop_args)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if answer_json:
 | 
	
		
			
				|  |  | -    print(json.dumps(answer_json))
 | 
	
		
			
				|  |  | +    parser = argparse.ArgumentParser(description="Display or add comments to files",
 | 
	
		
			
				|  |  | +        epilog="Some options conflict. Use only one of: -l -c -a -H -e -z -Z and one of -d -x")
 | 
	
		
			
				|  |  | +    parser.add_argument('-V',"--version", action="version",     version=f"dncli ver:{VERSION}")
 | 
	
		
			
				|  |  | +    parser.add_argument('-v',"--verbose", action='count',           help="verbose, almost debugging; do not use in scripts",default=0)
 | 
	
		
			
				|  |  | +    parser.add_argument('-j',"--json",      action="store_true",help="output in JSON format")
 | 
	
		
			
				|  |  | +    pars_m = parser.add_mutually_exclusive_group()
 | 
	
		
			
				|  |  | +    pars_m.add_argument('-l',"--listall", action="store_true",help="list all files, including those without comments")
 | 
	
		
			
				|  |  | +    parser.add_argument('-d',"--db",            action="store_true",help="list comments from database")
 | 
	
		
			
				|  |  | +    parser.add_argument('-x',"--xattr",     action="store_true",help="list comments from xattr")
 | 
	
		
			
				|  |  | +    parser.add_argument('-n',"--minimal", action="store_true",help="output only comments; useful in scripting")
 | 
	
		
			
				|  |  | +    parser.add_argument('-H',"--history", action="store_true",help="output the history of comments for a file")
 | 
	
		
			
				|  |  | +    pars_m.add_argument('-c',"--create",    metavar="comment",  help="add a comment to a file")
 | 
	
		
			
				|  |  | +    pars_m.add_argument('-a',"--append",    metavar="comment",  help="append to a comment on a file, separator=';'")
 | 
	
		
			
				|  |  | +    pars_m.add_argument('-C',"--copy",      action="store_true",help="copy a file with its comments")
 | 
	
		
			
				|  |  | +    parser.add_argument('-y',"--cp_force",action="store_true",help="copy over existing files")
 | 
	
		
			
				|  |  | +    pars_m.add_argument('-e',"--erase",     action="store_true",help="erase the comment on a file")
 | 
	
		
			
				|  |  | +    pars_m.add_argument('-z',"--zap",           action="store_true",help="clear the comment history on a file")
 | 
	
		
			
				|  |  | +    pars_m.add_argument('-Z',"--zapall",     action="store_true",help="clear the comment history in the entire database")
 | 
	
		
			
				|  |  | +    parser.add_argument('file_list',nargs='*',help="file(s); list commands may omit this")
 | 
	
		
			
				|  |  | +    args = parser.parse_args()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    # default is to display all files that have comments
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    # major modes are: display (<none> -l -H), add-comment (-a -c -e), clear-history(-z -Z), copy (-C)
 | 
	
		
			
				|  |  | +    # determine the major mode, then apply an appropriate function over the file_list
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    args.display = not (args.create or args.append or args.copy or args.erase or args.zap or args.zapall)
 | 
	
		
			
				|  |  | +    if args.cp_force and not args.copy:
 | 
	
		
			
				|  |  | +        print("the -y/--cp_force options can only be used with the -C/--copy command")
 | 
	
		
			
				|  |  | +        sys.exit(3)     
 | 
	
		
			
				|  |  | +    if args.json and not args.display:
 | 
	
		
			
				|  |  | +        print("the -j/--json option can only be used with the display modes")
 | 
	
		
			
				|  |  | +        sys.exit(4)
 | 
	
		
			
				|  |  | +    if args.minimal and not args.display:
 | 
	
		
			
				|  |  | +        print("the -n/--minimal option only applies to the display modes")
 | 
	
		
			
				|  |  | +        sys.exit(5)
 | 
	
		
			
				|  |  | +    if args.history and not args.display:
 | 
	
		
			
				|  |  | +        print("the -H/--history option only applies to the display modes")
 | 
	
		
			
				|  |  | +        sys.exit(5)
 | 
	
		
			
				|  |  | +    if args.xattr and (args.zap or args.zapall):
 | 
	
		
			
				|  |  | +        print("the -x/--xattr option doesn't apply to the -z/--zap and -Z/--zapall commands")
 | 
	
		
			
				|  |  | +        sys.exit(7)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    global verbose
 | 
	
		
			
				|  |  | +    verbose = args.verbose
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    #====== 1) build the file list =============
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    files = args.file_list
 | 
	
		
			
				|  |  | +    # for the list commands, auto-fill the file list with the current directory
 | 
	
		
			
				|  |  | +    if not files and args.display:
 | 
	
		
			
				|  |  | +        files = os.listdir(".")
 | 
	
		
			
				|  |  | +        files.sort()
 | 
	
		
			
				|  |  | +    # other command require explicity file lists, but 'dncli -c "new comment" *' will work
 | 
	
		
			
				|  |  | +    if not files:
 | 
	
		
			
				|  |  | +        print("please specify a file or files to use")
 | 
	
		
			
				|  |  | +        sys.exit(10)
 | 
	
		
			
				|  |  | +    print_d("got the files:", files)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    #======= 2) build the function
 | 
	
		
			
				|  |  | +    if args.create or args.append or args.erase:
 | 
	
		
			
				|  |  | +        print_d(f"create/append/erase: {args.create} . {args.append} . {args.erase}")
 | 
	
		
			
				|  |  | +        func = file_modify_comment
 | 
	
		
			
				|  |  | +        loop_args = (args.create, args.append, args.erase)
 | 
	
		
			
				|  |  | +    elif args.zap or args.zapall:
 | 
	
		
			
				|  |  | +        print_d(f"got a zap command {args.zap} . {args.zapall}")
 | 
	
		
			
				|  |  | +        func = file_zap
 | 
	
		
			
				|  |  | +        loop_args = (args.zapall,)
 | 
	
		
			
				|  |  | +        if args.zapall:
 | 
	
		
			
				|  |  | +            files = (1,)
 | 
	
		
			
				|  |  | +    elif args.copy:
 | 
	
		
			
				|  |  | +        print_d(f"got a copy command to {args.copy}")
 | 
	
		
			
				|  |  | +        # the last item on the file list is the target
 | 
	
		
			
				|  |  | +        n_files = len(files)
 | 
	
		
			
				|  |  | +        if n_files < 2:
 | 
	
		
			
				|  |  | +            print_d(f"the copy command requires at least two arguments, the last one is the destination")
 | 
	
		
			
				|  |  | +            sys.exit(1)
 | 
	
		
			
				|  |  | +        target = files[-1]
 | 
	
		
			
				|  |  | +        target_is_directory = os.path.isdir(target)
 | 
	
		
			
				|  |  | +        files = files[:-1]
 | 
	
		
			
				|  |  | +        print_d(f"copy from {files} to {target}")
 | 
	
		
			
				|  |  | +        if n_files > 2 and not target_is_directory:
 | 
	
		
			
				|  |  | +            print_d(f"multiple copy files must go to a target directory")
 | 
	
		
			
				|  |  | +            sys.exit(3)
 | 
	
		
			
				|  |  | +        func = file_copy
 | 
	
		
			
				|  |  | +        loop_args = (target, target_is_directory, args.cp_force)
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +        assert(args.display)
 | 
	
		
			
				|  |  | +        print_v(f"list files using {'database' if args.db else 'xattr'} priority")
 | 
	
		
			
				|  |  | +        print_d(f"display command with option: {args.listall} and {args.history} and {args.json} and {args.minimal}")
 | 
	
		
			
				|  |  | +        loop_args = (args.listall, args.history, args.json, args.minimal)
 | 
	
		
			
				|  |  | +        func = file_display
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    #====== 3) loop on the list, execute the function =============
 | 
	
		
			
				|  |  | +    global db
 | 
	
		
			
				|  |  | +    db = openDb()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    for f in files:
 | 
	
		
			
				|  |  | +        func(f,*loop_args)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if answer_json:
 | 
	
		
			
				|  |  | +        print(json.dumps(answer_json))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  if __name__ == "__main__":
 | 
	
		
			
				|  |  | -  main(sys.argv)
 | 
	
		
			
				|  |  | +    main(sys.argv)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 |