Review Board

beta

Sort files in the diff intelligently

Updated 1 year, 5 months ago

Christian Hammond Reviewers
trunk reviewboard
159
None Review Board SVN
Sorts files in the diff when a diff is being uploaded. The files are alphabetical, except we put header files before implementation files in order to ease reviews and give reviewers an overview of the structure before seeing the implementation.

We do this at diff creation time instead of view time. This means that existing diffs will retain their sorting, which is actually important because files contain index-based anchors and we don't want to break existing links.
Created a diff with several .c and .h files and saw that the order was as expected: alphabetical, but with .h files before .c files.

Diff revision 1 (Latest)

  1. /trunk/reviewboard/diffviewer/forms.py: 3 changes [ 1 2 3 ]
/trunk/reviewboard/diffviewer/forms.py
Revision 814 New Change
17
    # XXX: it'd be really nice to have "required" for these things be
17
    # XXX: it'd be really nice to have "required" for these things be
18
    # dependent on the scmtool for the repository
18
    # dependent on the scmtool for the repository
19
    basedir = forms.CharField(required=False)
19
    basedir = forms.CharField(required=False)
20
    path = forms.CharField(widget=forms.FileInput())
20
    path = forms.CharField(widget=forms.FileInput())
21
21
22
    # Extensions used for intelligent sorting of header files
23
    # before implementation files.
24
    HEADER_EXTENSIONS = ["h", "H", "hh", "hpp", "hxx", "h++"]
25
    IMPL_EXTENSIONS   = ["c", "C", "cc", "cpp", "cxx", "c++", "m", "mm", "M"]
26
22
    def create(self, file, diffset_history=None):
27
    def create(self, file, diffset_history=None):
23
        # Parse the diff
28
        # Parse the diff
24
        repository = Repository.objects.get(pk=self.cleaned_data['repositoryid'])
29
        repository = Repository.objects.get(pk=self.cleaned_data['repositoryid'])
25
        tool = repository.get_scmtool()
30
        tool = repository.get_scmtool()
26
        files = tool.getParser(file["content"]).parse()
31
        files = tool.getParser(file["content"]).parse()
50
                          history=diffset_history,
55
                          history=diffset_history,
51
                          diffcompat=DEFAULT_DIFF_COMPAT_VERSION)
56
                          diffcompat=DEFAULT_DIFF_COMPAT_VERSION)
52
        diffset.repository = repository
57
        diffset.repository = repository
53
        diffset.save()
58
        diffset.save()
54
59
60
        # Sort the files so that header files come before implementation.
61
        files.sort(cmp=self._compare_files, key=lambda f: f.origFile)
62
55
        for f in files:
63
        for f in files:
56
            filediff = FileDiff(diffset=diffset,
64
            filediff = FileDiff(diffset=diffset,
57
                                source_file=f.origFile,
65
                                source_file=f.origFile,
58
                                dest_file=os.path.join(basedir, f.newFile),
66
                                dest_file=os.path.join(basedir, f.newFile),
59
                                source_revision=str(f.origInfo),
67
                                source_revision=str(f.origInfo),
60
                                dest_detail=f.newInfo,
68
                                dest_detail=f.newInfo,
61
                                diff=f.data,
69
                                diff=f.data,
62
                                binary=f.binary)
70
                                binary=f.binary)
63
            filediff.save()
71
            filediff.save()
64
72
65
        return diffset
73
        return diffset
74
75
    def _compare_files(self, filename1, filename2):
76
        """
77
        Compares two files, giving precedence to header files over source
78
        files. This allows the resulting list of files to be more
79
        intelligently sorted.
80
        """
81
        if filename1.find('.') != -1 and filename2.find('.') != -1:
82
            basename1, ext1 = filename1.rsplit('.')
83
            basename2, ext2 = filename2.rsplit('.')
84
85
            if basename1 == basename2:
86
                if ext1 in self.HEADER_EXTENSIONS and \
87
                   ext2 in self.IMPL_EXTENSIONS:
88
                    return -1
89
                elif ext1 in self.IMPL_EXTENSIONS and \
90
                     ext2 in self.HEADER_EXTENSIONS:
91
                    return 1
92
93
        return cmp(filename1, filename2)
  1. /trunk/reviewboard/diffviewer/forms.py: 3 changes [ 1 2 3 ]