From: "Luis R. Rodriguez" <mcgrof@xxxxxxxx> At times you may need to replace a patch series with an SmPL patch, but how can you grow certain that a patch series replaces that patch series perfectly ? How do you visualize such differences ? This provides support for such proof mechanism. It assumes you have a patch series and respective SmPL patch you wish to use to replace the patch series. Say you have a foo.cocci SmPL patch, you would also have a foo/ directory in which you have series of patches. The foo/ patches are the patches you wish to replace. You can use then for instance: pycocci --show-proof foo.cocci /path/some-src-tree/ If you don't have git yet set up on /path/some-src-tree/ we'll create a git repository for you there with the code there in place already as the base of the repository. Otherwise if you already have git set up we'll use that git tree to do work. pycocci will create two git branches for proving the work. We leave your original branch intact, whatever it was, and we'll return you back to that same git branch. As an example, you may end up with: Current branch: master Patch branch: pycocci-patch-dd6b2fa4 SmPL branch: pycocci-smpl-731f9863 A series of patches in the directory foo/ will be applied onto the pycocci-patch-dd6b2fa4 branch, the foo.cocci SmPL patch will be applied onto the pycocci-smpl-731f9863 branch. You get a perfect patch equivalence when: git diff pycocci-patch-dd6b2fa4..pycocci-smpl-731f9863 yields no results. If there is any delta we give you the diffstat through stdout, and tell you where to go and what to do (above command) to inspect the changes in detail. Below is a screenshot run: mcgrof@ergon ~ $ /home/mcgrof/devel/coccinelle/tools/pycocci \ --show-proof \ /home/mcgrof/backports/patches/collateral-evolutions/media/0002-no_dmabuf.cocci \ /home/mcgrof/build/backports-20150626-test Current branch: master Patch branch: pycocci-patch-3a9fc1a5 SmPL branch: pycocci-smpl-17d08bf3 Applying patch ...0002-no_dmabuf/v4l2.patch spatch --sp-file ...0002-no_dmabuf.cocci --in-place --recursive-includes --relax-include-path --timeout 120 --dir ...backports-20150626-test -max 4 -index 0 --use-coccigrep spatch --sp-file ...0002-no_dmabuf.cocci --in-place --recursive-includes --relax-include-path --timeout 120 --dir ...backports-20150626-test -max 4 -index 1 --use-coccigrep spatch --sp-file ...0002-no_dmabuf.cocci --in-place --recursive-includes --relax-include-path --timeout 120 --dir ...backports-20150626-test -max 4 -index 2 --use-coccigrep spatch --sp-file ...0002-no_dmabuf.cocci --in-place --recursive-includes --relax-include-path --timeout 120 --dir ...backports-20150626-test -max 4 -index 3 --use-coccigrep Differences found: Change directory to /home/mcgrof/build/backports-20150626-test and run: git diff pycocci-patch-3a9fc1a5..pycocci-smpl-17d08bf3 diffstat of the changes: drivers/media/pci/cobalt/cobalt-v4l2.c | 2 ++ drivers/media/platform/blackfin/bfin_capture.c | 2 ++ drivers/media/platform/exynos-gsc/gsc-m2m.c | 4 +++ drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 4 +++ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 4 +++ drivers/media/platform/s5p-tv/mixer_video.c | 4 +++ drivers/media/platform/soc_camera/soc_camera.c | 4 +++ drivers/media/platform/sti/bdisp/bdisp-v4l2.c | 2 ++ drivers/media/usb/uvc/uvc_queue.c | 2 -- drivers/media/usb/uvc/uvc_v4l2.c | 2 +- drivers/media/v4l2-core/Kconfig | 6 ++-- drivers/media/v4l2-core/v4l2-mem2mem.c | 4 --- drivers/media/v4l2-core/videobuf2-core.c | 20 ------------ drivers/media/v4l2-core/videobuf2-dma-contig.c | 34 ++++++++++++++++++-- drivers/media/v4l2-core/videobuf2-dma-sg.c | 38 +++++++++++++++++++++-- drivers/media/v4l2-core/videobuf2-vmalloc.c | 43 +++++++++++++++++++++++--- include/media/v4l2-mem2mem.h | 4 --- include/media/videobuf2-core.h | 8 ----- 18 files changed, 134 insertions(+), 53 deletions(-) Signed-off-by: Luis R. Rodriguez <mcgrof@xxxxxxxx> --- tools/pycocci | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/tools/pycocci b/tools/pycocci index 51d89f618add..18d72abc369b 100755 --- a/tools/pycocci +++ b/tools/pycocci @@ -12,6 +12,7 @@ from multiprocessing import Process, cpu_count, Queue import argparse, subprocess, os, sys, re import tempfile, shutil +import uuid class ReqError(Exception): pass @@ -321,6 +322,44 @@ class tempdir(object): else: shutil.rmtree(self._name) +def apply_patches(args, patch_src, target_dir, logwrite=lambda x:None): + """ + Given a path of a directories of patches apply the patches + """ + patches = [] + for root, dirs, files in os.walk(patch_src): + for f in files: + if f.endswith('.patch'): + patches.append(os.path.join(root, f)) + patches.sort() + prefix_len = len(patch_src) + 1 + for pfile in patches: + print_name = pfile[prefix_len:] + + logwrite("Applying patch %s\n" % pfile) + + process = subprocess.Popen(['patch', '-p1'], stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, stdin=subprocess.PIPE, + close_fds=True, universal_newlines=True, + cwd=target_dir) + output = process.communicate(input=open(pfile, 'r').read())[0] + output = output.split('\n') + if output[-1] == '': + output = output[:-1] + if process.returncode != 0: + if not args.verbose: + logwrite("Failed to apply changes from %s" % print_name) + for line in output: + logwrite('> %s' % line) + raise Exception('Patch failed') + + # remove orig/rej files that patch sometimes creates + for root, dirs, files in os.walk(target_dir): + for f in files: + if f[-5:] == '.orig' or f[-4:] == '.rej': + os.unlink(os.path.join(root, f)) + git_commit_all(tree=target_dir, message="apply patch %s" % (print_name)) + class CoccinelleError(Exception): pass @@ -465,6 +504,8 @@ def _main(): help='Target source directory to modify') parser.add_argument('-p', '--profile-cocci', const=True, default=False, action="store_const", help='Enable profile, this will pass --profile to Coccinelle.') + parser.add_argument('-s', '--show-proof', const=True, default=False, action="store_const", + help='Show proof that the provided SmPL patch can replace a respective patch series') parser.add_argument('-j', '--jobs', metavar='<jobs>', type=str, default=None, help='Only use the cocci file passed for Coccinelle, don\'t do anything else, ' + 'also creates a git repo on the target directory for easy inspection ' + @@ -475,6 +516,13 @@ def _main(): if not os.path.isfile(args.cocci_file): return -2 + if not os.path.isfile(args.target_dir) and not os.path.isdir(args.target_dir): + logwrite("Path (%s) is not a file or directory\n" % (args.target_dir)) + return -2 + + current_branch = None + smpl_branch_name = "pycocci-smpl-" + str(uuid.uuid4())[:8] + patch_branch_name = "pycocci-patch-" + str(uuid.uuid4())[:8] extra_spatch_args = [] if args.profile_cocci: @@ -498,6 +546,40 @@ def _main(): if git_reqs.reqs_match(): git_dir = gitname(args.target_dir) + if args.show_proof: + # As an example if you use --show-proof patches/collateral-evolutions/network/09-threaded-irq.cocci + # the patches under 09-threaded-irq will be used for the proof. + patch_src = args.cocci_file.split('/')[-1].split('.cocci')[0] + dirname = os.path.dirname(args.cocci_file) + patch_src = os.path.abspath(os.path.join(dirname, patch_src)) + if not os.path.isdir(patch_src): + logwrite("Path given (%s) must be a directory with patches\n" % (patch_src)) + return -2 + git_reqs = Req(chatty=True) + git_reqs.require('git') + if not git_dir: + if os.path.isfile(args.target_dir): + logwrite("Path given (%s) is a file, try passing the directory " + "(%s) if you are certain you want us to create a git repo to provide a" + "a proof there\n" % (args.target_dir, os.path.dirname(args.target_dir))) + return -2 + logwrite("Path (%s) not part of a git tree, creating one for you...\n" % (args.target_dir)) + git_init(tree=args.target_dir) + git_commit_all(tree=args.target_dir, message="Initial commit") + cmd = [ '--abbrev-ref', 'HEAD' ] + current_branch = git_rev_parse(tree=args.target_dir, extra_args = cmd) + logwrite("\n") + logwrite("Current branch: %s\n" % (current_branch)) + logwrite("Patch branch: %s\n" % (patch_branch_name)) + logwrite("SmPL branch: %s\n" % (smpl_branch_name)) + logwrite("\n") + git_checkout(tree=args.target_dir, extra_args = ['-b', smpl_branch_name]) + git_checkout(tree=args.target_dir, extra_args = ['-b', patch_branch_name]) + + apply_patches(args, patch_src, args.target_dir, logwrite) + + git_checkout(tree=args.target_dir, extra_args = [smpl_branch_name]) + if os.path.isfile(glimpse_index): extra_spatch_args.append('--use-glimpse') elif git_dir: @@ -521,6 +603,18 @@ def _main(): extra_args=extra_spatch_args) if args.verbose: logwrite(output) + if args.show_proof: + git_commit_all(tree=args.target_dir, message="Initial commit") + git_checkout(tree=args.target_dir, extra_args = [current_branch]) + cmd = [ '--stat', patch_branch_name + ".." + smpl_branch_name ] + diff_stat = git_diff(tree=args.target_dir, extra_args = cmd) + if len(diff_stat) == 0: + logwrite('\nSmPL patch fully replaces patch series!') + else: + logwrite('\nDifferences found:\n\n') + logwrite('Change directory to %s and run:\n\n\tgit diff %s..%s\n\n' % (args.target_dir, patch_branch_name, smpl_branch_name)) + logwrite('diffstat of the changes:\n') + logwrite(diff_stat) return 0 if __name__ == '__main__': -- 2.3.2.209.gd67f9d5.dirty -- To unsubscribe from this list: send the line "unsubscribe backports" in