def _check_paths(self, diff): ''' Check that: (1) file named in diff spec exists (GIT format only) (2) file named in '---' line exists or is /dev/null (3) file named in '+++' line exists or is /dev/null (4) file to be created exists in new tree (5) file to be deleted does not exist in old tree ''' if (not ut.is_file(ut.join_path(self.sourcedir, diff.a_path))): self._error_msg('"a" file not found: %s' % diff.a_path, 2) return False if (diff.old_path != '/dev/null'): if (not ut.is_file(ut.join_path(self.sourcedir, diff.old_path))): self._error_msg('"old" file not found: %s' % diff.old_path, 2) return False else: if (ut.is_file(ut.join_path(self.sourcedir, diff.new_path))): self._error_msg('"new" file found in old tree: %s' % diff.new_path, 2) return False if (diff.new_path != '/dev/null'): if (not ut.is_file(ut.join_path(self.sourcedir, diff.new_path))): self._error_msg('"new" file not found: %s' % diff.new_path, 2) return False else: if (not ut.is_file(ut.join_path(self.sourcedir, diff.old_path))): self._error_msg('"old" file not found in old tree: %s' % diff.old_path, 2) return False return True
def _iterate(): r = c['sourcedir'] t = ut.join_path(c['tempdir'], 'encoding.dat') w = h.read('walk.txt') for file_ in w: path = ut.join_path(r, file_) s = ut.read_strings(path) ut.write_strings(s, t)
def vp2a(self, patchname, archpath, params): """ Display patch and archive diff sections that use its files Args: patchname (string): name of patch file archpath (string): path to archive file params (dict): parameters patchdir (string, required): path of patches folder tempdir (string, required): path to store temporary data Raises: PT_ParameterError for any missing files Notes: Launches the editor synchronously, since a temporary file is created to hold the archive sections. """ #-- if (not isinstance(params, dict)): raise PT_ParameterError(self.name, 'params') sourcedir = self._check_directory_param(params, 'sourcedir') patchdir = self._check_directory_param(params, 'patchdir') tempdir = self._check_directory_param(params, 'tempdir') patchpath = self._check_filename_param(patchdir, patchname, 'patchname') if (not ut.is_file(archpath)): raise PT_NotFoundError(self.name, archpath) # Get list of files used by the patch filelist = Patch.list_files(patchpath) filepaths = [ut.join_path(sourcedir, file_) for file_ in filelist] # Get archive diff sections that use any of the files strings = [] for diff in self._get_diffs(archpath, filepaths): strings += diff if (len(strings) == 0): return [] # Store the diff sections in a temporary file archname = archpath[archpath.rfind('/') + 1:] tempname = archname + '.tmp' temppath = ut.join_path(tempdir, tempname) ut.write_strings(strings, temppath) self._view([patchpath, temppath], True) # Note that we requested _view to wait for subprocess exit above, # so that we do not try to delete the file while it is in use. os.remove(temppath)
def get_patch_names(self, params=None): """ Return list of names of patches in our patch set Args: params (dict, optional): parameters excl_dirs (list, optional): directories to exclude incl_dirs (list, optional): directories to include Returns: list of patch names in the order found in patchset Notes: The "name" of a patch is the concatenation of the name of its parent folder and its filename, as shown in the patchset description. If params is None, names of all patches are returned. """ #-- if ((params is not None) and isinstance(params, dict)): excl_dirs = self._check_optional_param(params, 'excl_dirs', list, []) incl_dirs = self._check_optional_param(params, 'incl_dirs', list, []) else: excl_dirs = [] incl_dirs = [] names = [] groups = self.patchset['groups'] if (groups[0] in self.patchset): # old format? for group in groups: names += self.patchset[group] else: # new format if (len(incl_dirs) > 0): dirs = incl_dirs else: dirs = groups for dir_ in excl_dirs: if (dir_ in dirs): dirs.remove(dir_) for dir_ in dirs: dirnames = [] path = ut.join_path(self.patchdir, dir_) for (_, _, files) in os.walk(path): for file_ in files: name = ut.join_path(dir_, file_) dirnames += [name] dirnames.sort() names += dirnames return names
def _enumerate(self, dir_, files): results = [] for file_ in files: if (self.test_dirs): path = ut.join_path(dir_, file_) else: path = file_ if ((not self._is_file_excluded(path)) and self._is_file_included(path)): results += [ut.join_path(dir_, file_)] return results
def _sort_patches_new(self, patches): ''' In the "new" (kernel-3.8) format, the patchset "groups" item is a list of names of folders under self.patchdir, and the groups are intended to be processed in list order, apparently with the order of files within a group being controlled by the first four characters xof the file's name. ''' # Map the patches into a dict on the folder name dir_ = {} for patchname in patches: parts = patchname.split('/', 1) folder, filename = parts[0], parts[1] if (folder in dir_): dir_[folder] += [filename] else: dir_[folder] = [filename] # Extract the patch names in patchset order sorted_ = [] for group in self.patchset['groups']: if (group in dir_): files = dir_[group] if (len(files) > 1): files.sort() items = [ut.join_path(group, name) for name in files] sorted_ += items return sorted_
def vp2f(self, patchname, params): """ List patch and files it uses Args: patchname (string): name of patch file params (dict): parameters patchdir (string, required): path of patches folder Raises: PT_ParameterError for any missing files """ #-- if (not isinstance(params, dict)): raise PT_ParameterError(self.name, 'params') sourcedir = self._check_directory_param(params, 'sourcedir') patchdir = self._check_directory_param(params, 'patchdir') patchpath = self._check_filename_param(patchdir, patchname, 'patchname') # Get list of source filenames referenced in patch # Note that a patch may refer to files that do not exist in the source tree. filelist = Patch.list_files(patchpath) filepaths = [] for file_ in filelist: path = ut.join_path(sourcedir, file_) if (ut.is_file(path)): filepaths += [path] paths = [patchpath] + filepaths return self._view(paths)
def _sort_on_date(self, patches): ''' Sort patches on date field. The format is like: Fri, 28 Dec 2012 21:00:31 +0200 ''' records = [] for patch in patches: strings = ut.read_strings(ut.join_path(self.patchdir, patch)) for string in strings: if ("Date:" in string): # e.g. 'Date: Wed, 16 Jan 2013 19:09:47 +0000' fields = ut.string_to_words(string[6:].lstrip(' \t')) _, s_day, s_mon, s_year, s_hms, _ = fields s_hour, s_minute, s_second = s_hms.split(':') day, year = int(s_day), int(s_year) hour, minute, second = int(s_hour), int(s_minute), int(s_second) month = self.month_numbers[s_mon] # ignoring microseconds dt = datetime(year, month, day, hour, minute, second) records += [(dt, patch)] break records = sorted(records, key = lambda r: r[0]) patches = [patch for (_, patch) in records] return patches
def _sort_on_date(self, patches): ''' Sort patches on date field. The format is like: Fri, 28 Dec 2012 21:00:31 +0200 ''' records = [] for patch in patches: strings = ut.read_strings(ut.join_path(self.patchdir, patch)) for string in strings: if ("Date:" in string ): # e.g. 'Date: Wed, 16 Jan 2013 19:09:47 +0000' fields = ut.string_to_words(string[6:].lstrip(' \t')) _, s_day, s_mon, s_year, s_hms, _ = fields s_hour, s_minute, s_second = s_hms.split(':') day, year = int(s_day), int(s_year) hour, minute, second = int(s_hour), int(s_minute), int( s_second) month = self.month_numbers[s_mon] # ignoring microseconds dt = datetime(year, month, day, hour, minute, second) records += [(dt, patch)] break records = sorted(records, key=lambda r: r[0]) patches = [patch for (_, patch) in records] return patches
def _check(self, patchpath): self._misc_msg('\nPATCH: "%s"' % patchpath) patchpath = ut.join_path(self.patchdir, patchpath) pdata = Patch(patchpath) if (len(pdata.diffs) == 0): self._info_msg('skipping empty/commented patch', 1) return 0 if (pdata.patch_type == 'binary'): self._info_msg('skipping binary patch', 1) return -1 errors = 0 for diff in pdata.diffs: self._misc_msg('DIFF: "%s"' % diff.spec, 1) if (not self._check_paths(diff)): errors += 1 continue if (diff.old_path == '/dev/null'): # Can't fail on adding lines to a new file continue old_lines = ut.read_strings(ut.join_path(self.sourcedir, diff.old_path)) for hunk in diff.hunks: self._misc_msg('HUNK: "%s"' % hunk.spec, 2) edits = hunk.edits start = hunk.old_start count = hunk.old_count tag = 'old' note = hunk.note if (not self._check_hunk_format(start, count, len(old_lines), tag)): errors += 1 continue errors += self._check_hunk_edits(diff.old_path, edits, start, count, note, old_lines) self._info_msg("%d patch errors" % errors, 1) return errors
def _check_filename_param(self, prefix, value, name): if (not ut.is_string_type(value)): raise PT_ParameterError(self.name, name) path = ut.join_path(prefix, value) if (not ut.is_file(path)): raise PT_NotFoundError(self.name, value) return path
def is_text_file(string): if ('defkeymap.map' in string): pass path = ut.join_path(c['sourcedir'], string) inpt = open(path, "rb") fsiz = ut.file_size(path) abuf = inpt.read(min(1024, fsiz)) inpt.close() ret = chardetect(abuf) return (isinstance(ret, dict) and ('encoding' in ret) and (ret['encoding'] is not None))
def watch(self, archpath): """ View files related to archive diff sections Args: archpath (string): path to patch archive file Returns: None. Output is a series of launches of the Viewer to view the files. Raises: PT_ParameterError PT_NotFoundError """ #-- if (not ut.is_string_type(archpath)): raise PT_ParameterError(self.name, 'archpath') if (not ut.is_file(archpath)): raise PT_NotFoundError(self.name, archpath) tempfile = ut.join_path(self._tempdir, 'archdata.txt') filedata = self._patchset.get_file_data() filenames = [key for key in filedata] a = Archive(archpath) s = a.sections(filenames) print("Found %d matching sections" % len(s)) v = Viewer() for section in s: ut.write_strings(section, tempfile) filename = ut.get_string_filename(section[1]) filepath = ut.join_path(self._sourcedir, filename) patchfiles = [] for (fn, _) in filedata[filename]: patchfiles += [ut.join_path(self._patchdir, fn)] r = v.view([tempfile, filepath] + patchfiles) print(r)
def convert_api_data(config): srcroot = config['srcroot'] sources = config['sources'] data = [] for source in sources: print('extract: ' + source) path = ut.join_path(srcroot, source) strings = Strings(ut.read_strings(path)) sections = strings.extract('#++','#--') if (len(sections) > 0): sections = [conv_section(section) for section in sections] data += Strings.join(sections) else: pass ut.write_strings(data, './_rest/api.txt')
def _match_patterns(self, path): ''' Search files in self.paths for match to self.matcher. ''' filepath = ut.join_path(self.root_path, path) strings = ut.read_strings(filepath) for index in range(len(strings)): text = strings[index] if (self.debug > 1): print(' "%s"' % text) pattern = self.matcher(text) if (pattern is not None): if (self.trim_paths): path_ = path else: path_ = filepath if (pattern not in self.matches): self.matches[pattern] = [] self.matches[pattern] += [(path_, index + 1, text.lstrip())]
def vp2p(self, patchname, params): """ Display a patch file and the other patch files that use the same source files Args: patchname (string): name of patch file params (dict): parameters patchdir (string, required): path of patches folder patchset (dict, required): patchset description Raises: PT_ParameterError for any missing files """ #-- if (not isinstance(params, dict)): raise PT_ParameterError(self.name, 'params') patchdir = self._check_directory_param(params, 'patchdir') patchset = self._check_required_param(params, 'patchset', dict) patchpath = self._check_filename_param(patchdir, patchname, 'patchname') # Get list of files used by the patch filelist = Patch.list_files(patchpath) # Get list of patches that use the same files patchlist = [] patchset = PatchSet({'patchdir': patchdir, 'patchset': patchset}) patchdata = patchset.get_file_data() patchkeys = sorted(patchdata) # 2to3 for file_ in filelist: for key in patchkeys: if (file_ == patchdata[key][0]): patchlist += [key] break patchpaths = [ut.join_path(patchdir, patch) for patch in patchlist] paths = [patchpath] + patchpaths return self._view(paths)
def vcpf(self, checkpath, patchname, params): """ List checker output file, patch and files it uses Args: checkpath (string): path to Checker output file patchname (string): patch name params (dict) parameters: sourcedir (string, required): path of sources folder patchdir (string, required): path of patches folder Raises: PT_ParameterError PT_NotFoundError """ #-- if (not isinstance(params, dict)): raise PT_ParameterError(self.name, 'params') if (not ut.is_file(checkpath)): raise PT_NotFoundError(self.name, checkpath) sourcedir = self._check_directory_param(params, 'sourcedir') patchdir = self._check_directory_param(params, 'patchdir') patchpath = self._check_filename_param(patchdir, patchname, 'patchname') # Get list of source filenames referenced in patch. # Note that a patch may refer to files that do not exist in the source tree. filelist = Patch.list_files(patchpath) filepaths = [] for file_ in filelist: path = ut.join_path(sourcedir, file_) if (ut.is_file(path)): filepaths += [path] paths = [checkpath, patchpath] + filepaths return self._view(paths)
def vp2p(self, patchname, params): """ Display a patch file and the other patch files that use the same source files Args: patchname (string): name of patch file params (dict): parameters patchdir (string, required): path of patches folder patchset (dict, required): patchset description Raises: PT_ParameterError for any missing files """ #-- if (not isinstance(params, dict)): raise PT_ParameterError(self.name, 'params') patchdir = self._check_directory_param(params, 'patchdir') patchset = self._check_required_param(params, 'patchset', dict) patchpath = self._check_filename_param(patchdir, patchname, 'patchname') # Get list of files used by the patch filelist = Patch.list_files(patchpath) # Get list of patches that use the same files patchlist = [] patchset = PatchSet({ 'patchdir' : patchdir, 'patchset' : patchset }) patchdata = patchset.get_file_data() patchkeys = sorted(patchdata) # 2to3 for file_ in filelist: for key in patchkeys: if (file_ == patchdata[key][0]): patchlist += [key] break patchpaths = [ut.join_path(patchdir, patch) for patch in patchlist] paths = [patchpath] + patchpaths return self._view(paths)
def _get_data(self): ''' Scan patchset to get two mappings: filedata maps filenames to patches patchdata maps patches to filenames ''' filedata = {} patchdata = {} for patchname in self.get_patch_names(): filelist = [] strings = ut.read_strings(ut.join_path(self.patchdir, patchname)) for index in range(len(strings)): if (strings[index].startswith('diff --git ')): filename = ut.get_string_filename(strings[index]) if (filename in filedata): filedata[filename] += [(patchname, index)] else: filedata[filename] = [(patchname, index)] filelist += [(filename, index)] patchdata[patchname] = filelist self.filedata = filedata self.patchdata = patchdata
def vf2p(self, filename, params): """ List file and patches that use it Args: filename (string): name of patch file params (dict): parameters sourcedir (string, required): path of sources folder patchdir (string, required): path of patches folder patchset (dict, required): patchset description Raises: PT_ParameterError for any missing files """ if (not isinstance(params, dict)): raise PT_ParameterError(self.name, 'params') sourcedir = self._check_directory_param(params, 'sourcedir') patchdir = self._check_directory_param(params, 'patchdir') patchset = self._check_required_param(params, 'patchset', dict) filepath = self._check_filename_param(sourcedir, filename, 'filename') # Get list of patches that use the source file patchset = PatchSet({ 'patchdir' : patchdir, 'patchset' : patchset }) patchlist = patchset.get_file_patches(filename) # Arrange the patches in patchset group order. #patchlist = patchset.sort_patches({ "patches" : patchlist }) # Create abolute paths for the patches patchpaths = [] for patchname in patchlist: patchpaths += [ut.join_path(patchdir, patchname)] filepaths = [filepath] + patchpaths return self._view(filepaths)
def vf2p(self, filename, params): """ List file and patches that use it Args: filename (string): name of patch file params (dict): parameters sourcedir (string, required): path of sources folder patchdir (string, required): path of patches folder patchset (dict, required): patchset description Raises: PT_ParameterError for any missing files """ if (not isinstance(params, dict)): raise PT_ParameterError(self.name, 'params') sourcedir = self._check_directory_param(params, 'sourcedir') patchdir = self._check_directory_param(params, 'patchdir') patchset = self._check_required_param(params, 'patchset', dict) filepath = self._check_filename_param(sourcedir, filename, 'filename') # Get list of patches that use the source file patchset = PatchSet({'patchdir': patchdir, 'patchset': patchset}) patchlist = patchset.get_file_patches(filename) # Arrange the patches in patchset group order. #patchlist = patchset.sort_patches({ "patches" : patchlist }) # Create abolute paths for the patches patchpaths = [] for patchname in patchlist: patchpaths += [ut.join_path(patchdir, patchname)] filepaths = [filepath] + patchpaths return self._view(filepaths)
Created on Oct 2, 2014 @copyright 2014, Milton C Mobley This is a simple test of the Watcher and Archive classes. ''' from patchtools.lib.helper import Helper from patchtools.lib.exceptions import ExceptionHandler from patchtools.lib.functions import Functions as ut if __name__ == '__main__': global c, h exception_handler = ExceptionHandler() try: h = Helper('config.json') c = h.config archdir = ut.join_path(c['datadir'], 'archives') archpath = ut.join_path(archdir, 'patch-3.16.3') h.watch(archpath, c) except KeyboardInterrupt: pass except Exception as e: exception_handler(e) exit(-1) print('done')
def __init__(self, params): """ Constructor Args: params (dict, required) parameters: root_path (string, required): search root path incl_dirs (list, optional): top level subdirs to include excl_dirs (list, optional): top level subdirs to exclude incl_files (dict, optional): include file name filters excl_files (dict, optional): exclude file name filters test_dirs (bool, optional): True = include dir in tests Raises: PT_ParameterError Notes: The "root_path" parameter specifies the root of the search. If the "incl_dirs" option is specified, only those subdirs of the root will be searched. If the "excl_dirs" option is specified, those subdirs of the root will not be searched. If the "incl_files" option is specified, only those filetypes will be enumerated. If the "excl_files" option is specified, those filetypes will not be enumerated. If it is desired to search a folder that is a subfolder of an excluded folder, the search must be split into two operations. When callback functions need the containing directory to test a file name, the 'test_dirs' option should be set to True Walking a large file tree can take significant time and produce a large amount of data, but this tendency can be reduced by cleaning the tree of generated files beforehand, and by applying suitable directory and file filters. """ #-- self.name = 'Walker' if ((params is None) or (not isinstance(params, dict))): raise PT_ParameterError(self.name, 'params') self._root_path = self._check_required_string_param(params, 'root_path') self._check_path_param('root_path', self._root_path) incl_dirs = self._check_optional_param(params, 'incl_dirs', list, None) excl_dirs = self._check_optional_param(params, 'excl_dirs', list, None) incl_files = self._check_optional_param(params, 'incl_files', dict, None) excl_files = self._check_optional_param(params, 'excl_files', dict, None) self.test_dirs = self._check_optional_param(params, 'test_dirs', bool, False) self._trim_paths = self._check_optional_param(params, 'trim_paths', bool, True) if ((incl_dirs is None) and (excl_dirs is None)): self._folders = [self._root_path] elif (incl_dirs is not None): # only iterate over incl_dirs self._folders = [ut.join_path(self._root_path, d) for d in incl_dirs] else: # exclude subdirs in excl_dirs dirs = [d for d in os.listdir(self._root_path) if os.path.isdir(ut.join_path(self._root_path, d))] for x in excl_dirs: if x in dirs: dirs.remove(x) self._folders = [ut.join_path(self._root_path, d) for d in dirs] if (incl_files is not None): self._incl_files_filter = Matcher(incl_files) else: self._incl_files_filter = None if (excl_files is not None): self._excl_files_filter = Matcher(excl_files) else: self._excl_files_filter = None
def _check(self, patchpath): self._misc_msg('\nPATCH: "%s"' % patchpath) patchpath = ut.join_path(self.patchdir, patchpath) # print patchpath pdata = Patch(patchpath) if (len(pdata.diffs) == 0): self._info_msg('skipping empty/commented patch', 1) return 0 if (pdata.patch_type == 'binary'): self._info_msg('skipping binary patch', 1) return -1 errors = 0 context = [] logs = "" for diff in pdata.diffs: # print "a path :" + diff.a_path # print "old path :" + diff.old_path # print "new path :" + diff.new_path self._misc_msg('DIFF: "%s"' % diff.spec, 1) if (not self._check_paths(diff)): errors += 1 continue if (diff.old_path == '/dev/null' ): # Can't fail on adding lines to a new file continue # print "old file path :" + ut.join_path(self.sourcedir, diff.old_path) old_lines = ut.read_strings( ut.join_path(self.sourcedir, diff.old_path)) new_hunks = [] new_diff = [] for hunk in diff.hunks: self._misc_msg('HUNK: "%s"' % hunk.spec, 2) edits = hunk.edits start = hunk.old_start count = hunk.old_count tag = 'old' note = hunk.note if (not self._check_hunk_format(start, count, len(old_lines), tag)): errors += 1 continue # print "begin to change hunk edits" # errors += self._check_hunk_edits(diff.old_path, edits, start, count, note, old_lines) #获取并加入新的hunk信息 new_hunks.append( self._patch_hunk_edits(diff.old_path, edits, start, count, note, old_lines)) # print "end for this hunk" #写入当前hunk new_diff.append(diff.spec + "\n") # for (new_edits,new_start,context_start,new_count,context_count) in new_hunks: # new_diff.append("@@ " + str(new_start) + "," + str(context_count) + " " + str(context_start) + "," + str(new_count) + "@@\n") # for edit in new_edits: # new_diff.append(edit + "\n") # # context.append("".join(new_diff)) for (new_place, before_start, before_count, after_start, after_count, log) in new_hunks: new_diff.append("@@ -" + str(before_start) + "," + str(before_count) + " +" + str(after_start) + "," + str(after_count) + "@@\n") for (edit, new_line_current, new_line_edited) in new_place: new_diff.append(edit + "\n") logs += log context.append("".join(new_diff)) # print new_diff #将新的diffs信息写入文件 f = file("new.patch", "w") # print context f.write("".join(context)) f.close() logfile = file("log.txt", "w") logfile.write("".join(logs)) logfile.close() self._info_msg("%d patch errors" % errors, 1) return errors