def ov_perror(errorcode, src_path): '''print error message for source path''' if errorcode >= 0: # this is not an error but a valid group number return if errorcode == OV_NOT_MY_GROUP: # this is not an error but a normal condition return if errorcode == OV_NO_GROUP_EXT: if synctool_param.TERSE: terse(synctool_lib.TERSE_ERROR, 'no group on %s' % src_path) else: stderr('no underscored group extension on %s, skipped' % synctool_lib.prettypath(src_path)) elif errorcode == OV_UNKNOWN_GROUP: if synctool_param.TERSE: terse(synctool_lib.TERSE_ERROR, 'invalid group on %s' % src_path) else: stderr('unknown group on %s, skipped' % synctool_lib.prettypath(src_path))
def run_command(cmd): '''run a shell command''' if cmd[0] != '/': # if relative path, use scriptdir cmd = synctool_param.SCRIPT_DIR + '/' + cmd # a command can have arguments arr = shlex.split(cmd) cmdfile = arr[0] stat = synctool_stat.SyncStat(cmdfile) if not stat.exists(): stderr('error: command %s not found' % synctool_lib.prettypath(cmdfile)) return if not stat.isExec(): stderr("warning: file '%s' is not executable" % synctool_lib.prettypath(cmdfile)) return # run the shell command synctool_lib.shell_command(cmd)
def mkdir_basepath(self): '''call mkdir -p if the destination directory does not exist yet''' if synctool_lib.DRY_RUN: return # check if the directory exists basedir = os.path.dirname(self.dest_path) stat = synctool_stat.SyncStat(basedir) if not stat.exists(): # create the directory verbose('making directory %s' % synctool_lib.prettypath(basedir)) unix_out('mkdir -p %s' % basedir) synctool_lib.mkdir_p(basedir)
def overlay_pass2(filelist, filedict): '''do pass #2 of 2; create dictionary of destination paths from list Each element in the dictionary is an instance of OverlayEntry''' for entry in filelist: if filedict.has_key(entry.dest_path): entry2 = filedict[entry.dest_path] if entry.groupnum < entry2.groupnum: # this group is more important, so override it del filedict[entry.dest_path] entry2 = None # duplicate paths are a problem, unless they are directories ... elif (not (entry.src_isDir() and entry2.src_isDir())) \ and entry.groupnum == entry2.groupnum: if synctool_param.TERSE: synctool_lib.terse(synctool_lib.TERSE_ERROR, 'duplicate source paths in repository for:') synctool_lib.terse(synctool_lib.TERSE_ERROR, entry.src_path) synctool_lib.terse(synctool_lib.TERSE_ERROR, entry2.src_path) else: stderr('error: duplicate source paths in repository for:\n' 'error: %s\n' 'error: %s\n' % (synctool_lib.prettypath(entry.src_path), synctool_lib.prettypath(entry2.src_path)) ) continue else: # this group is less important, skip it continue # add or update filedict filedict[entry.dest_path] = entry
def upload(interface, upload_filename, upload_suffix=None): '''copy a file from a node into the overlay/ tree''' if not synctool_param.SCP_CMD: stderr('%s: error: scp_cmd has not been defined in %s' % (os.path.basename(sys.argv[0]), synctool_param.CONF_FILE)) sys.exit(-1) if upload_filename[0] != '/': stderr('error: the filename to upload must be an absolute path') sys.exit(-1) trimmed_upload_fn = upload_filename[1:] # remove leading slash import synctool_overlay # make the known groups lists synctool_config.remove_ignored_groups() synctool_param.MY_GROUPS = synctool_config.get_my_groups() synctool_param.ALL_GROUPS = synctool_config.make_all_groups() if upload_suffix and not upload_suffix in synctool_param.ALL_GROUPS: stderr("no such group '%s'" % upload_suffix) sys.exit(-1) # shadow DRY_RUN because that var can not be used correctly here if '-f' in PASS_ARGS or '--fix' in PASS_ARGS: dry_run = False else: dry_run = True if not synctool_lib.QUIET: stdout('DRY RUN, not uploading any files') terse(synctool_lib.TERSE_DRYRUN, 'not uploading any files') node = NODESET.get_nodename_from_interface(interface) # pretend that the current node is now the given node; # this is needed for find() to find the most optimal reference for the file orig_NODENAME = synctool_param.NODENAME synctool_param.NODENAME = node synctool_config.insert_group(node, node) orig_MY_GROUPS = synctool_param.MY_GROUPS[:] synctool_param.MY_GROUPS = synctool_config.get_my_groups() # see if file is already in the repository (obj, err) = synctool_overlay.find_terse(synctool_overlay.OV_OVERLAY, upload_filename) if err == synctool_overlay.OV_FOUND_MULTIPLE: # multiple source possible # possibilities have already been printed sys.exit(1) if err == synctool_overlay.OV_NOT_FOUND: # no source path found if string.find(upload_filename, '...') >= 0: stderr("%s is not in the repository, don't know what to map this path to\n" "Please give the full path instead of a terse path, or touch the source file\n" "in the repository first and try again" % os.path.basename(upload_filename)) sys.exit(1) # it wasn't a terse path, throw a source path together # This picks the first overlay dir as default source, which may not be correct # but it is a good guess repos_filename = os.path.join(synctool_param.OVERLAY_DIRS[0], trimmed_upload_fn) if upload_suffix: repos_filename = repos_filename + '._' + upload_suffix else: repos_filename = repos_filename + '._' + node # use _nodename as default suffix else: if upload_suffix: # remove the current group suffix an add the specified suffix to the filename arr = string.split(obj.src_path, '.') if len(arr) > 1 and arr[-1][0] == '_': repos_filename = string.join(arr[:-1], '.') repos_filename = repos_filename + '._' + upload_suffix else: repos_filename = obj.src_path synctool_param.NODENAME = orig_NODENAME synctool_param.MY_GROUPS = orig_MY_GROUPS verbose('%s:%s uploaded as %s' % (node, upload_filename, repos_filename)) terse(synctool_lib.TERSE_UPLOAD, repos_filename) unix_out('%s %s:%s %s' % (synctool_param.SCP_CMD, interface, upload_filename, repos_filename)) if dry_run: stdout('would be uploaded as %s' % synctool_lib.prettypath(repos_filename)) else: # first check if the directory in the repository exists repos_dir = os.path.dirname(repos_filename) stat = synctool_stat.SyncStat(repos_dir) if not stat.exists(): verbose('making directory %s' % synctool_lib.prettypath(repos_dir)) unix_out('mkdir -p %s' % repos_dir) synctool_lib.mkdir_p(repos_dir) # make scp command array scp_cmd_arr = shlex.split(synctool_param.SCP_CMD) scp_cmd_arr.append('%s:%s' % (interface, upload_filename)) scp_cmd_arr.append(repos_filename) synctool_lib.run_with_nodename(scp_cmd_arr, NODESET.get_nodename_from_interface(interface)) if os.path.isfile(repos_filename): stdout('uploaded %s' % synctool_lib.prettypath(repos_filename))
def overlay_pass1(overlay_dir, filelist, dest_dir = '/', highest_groupnum = sys.maxint, handle_postscripts = True): '''do pass #1 of 2; create list of source and dest files Each element in the list is an instance of SyncObject''' global POST_SCRIPTS for entry in os.listdir(overlay_dir): src_path = os.path.join(overlay_dir, entry) src_statbuf = synctool_stat.SyncStat(src_path) if src_statbuf.isDir(): if synctool_param.IGNORE_DOTDIRS and entry[0] == '.': continue isDir = True else: if synctool_param.IGNORE_DOTFILES and entry[0] == '.': continue isDir = False # check any ignored files with wildcards # before any group extension is examined if synctool_param.IGNORE_FILES_WITH_WILDCARDS: wildcard_match = False for wildcard_entry in synctool_param.IGNORE_FILES_WITH_WILDCARDS: if fnmatch.fnmatchcase(entry, wildcard_entry): wildcard_match = True break if wildcard_match: continue (name, groupnum, isPost) = split_extension(entry, not isDir) if groupnum < 0: # not a relevant group, so skip it # Note that this also prunes trees if you have group-specific subdirs if groupnum != OV_NOT_MY_GROUP: # "not my group" is a rather normal error code, but if it is # something else, it's a serious error that we should report ov_perror(groupnum, os.path.join(overlay_dir, entry)) continue if name in synctool_param.IGNORE_FILES: continue # inherit lower group level from parent directory if groupnum > highest_groupnum: groupnum = highest_groupnum if isPost: if handle_postscripts: if not src_statbuf.isExec(): stderr('warning: .post script %s is not executable, ignored' % synctool_lib.prettypath(src_path)) continue # register .post script # trigger is the source file that would trigger the .post script to run trigger = os.path.join(overlay_dir, name) if POST_SCRIPTS.has_key(trigger): if groupnum >= POST_SCRIPTS[trigger].groupnum: continue POST_SCRIPTS[trigger] = synctool_object.SyncObject(src_path, dest_dir, groupnum, src_statbuf) else: # unfortunately, the name has been messed up already # so therefore just ignore the file and issue a warning if synctool_param.TERSE: terse(synctool_lib.TERSE_WARNING, 'ignoring %s' % src_path) else: stderr('warning: ignoring .post script %s' % synctool_lib.prettypath(src_path)) continue dest_path = os.path.join(dest_dir, name) filelist.append(synctool_object.SyncObject(src_path, dest_path, groupnum, src_statbuf)) if isDir: # recurse into subdir overlay_pass1(src_path, filelist, dest_path, groupnum, handle_postscripts)
def print_dest(self): return synctool_lib.prettypath(self.dest_path)
def print_src(self): return synctool_lib.prettypath(self.src_path)