svneol.py 3.41 KB
Newer Older
1
#! /usr/bin/env python3
2 3 4 5

"""
SVN helper script.

6 7
Try to set the svn:eol-style property to "native" on every .py, .txt, .c and
.h file in the directory tree rooted at the current directory.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

Files with the svn:eol-style property already set (to anything) are skipped.

svn will itself refuse to set this property on a file that's not under SVN
control, or that has a binary mime-type property set.  This script inherits
that behavior, and passes on whatever warning message the failing "svn
propset" command produces.

In the Python project, it's safe to invoke this script from the root of
a checkout.

No output is produced for files that are ignored.  For a file that gets
svn:eol-style set, output looks like:

    property 'svn:eol-style' set on 'Lib\ctypes\__init__.py'

For a file not under version control:

    svn: warning: 'patch-finalizer.txt' is not under version control

and for a file with a binary mime-type property:

    svn: File 'Lib\test\test_pep263.py' has binary mime type property
"""

33
import re
34
import os
35 36 37
import sys
import subprocess

38

39
def propfiles(root, fn):
40
    default = os.path.join(root, ".svn", "props", fn + ".svn-work")
41 42 43
    try:
        format = int(open(os.path.join(root, ".svn", "format")).read().strip())
    except IOError:
44
        return []
Benjamin Peterson's avatar
Benjamin Peterson committed
45 46 47
    if format in (8, 9):
        # In version 8 and 9, committed props are stored in prop-base, local
        # modifications in props
48 49 50 51
        return [os.path.join(root, ".svn", "prop-base", fn + ".svn-base"),
                os.path.join(root, ".svn", "props", fn + ".svn-work")]
    raise ValueError("Unknown repository format")

52

53
def proplist(root, fn):
54
    """Return a list of property names for file fn in directory root."""
55
    result = []
56 57 58 59 60 61 62
    for path in propfiles(root, fn):
        try:
            f = open(path)
        except IOError:
            # no properties file: not under version control,
            # or no properties set
            continue
63
        while True:
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
            # key-value pairs, of the form
            # K <length>
            # <keyname>NL
            # V length
            # <value>NL
            # END
            line = f.readline()
            if line.startswith("END"):
                break
            assert line.startswith("K ")
            L = int(line.split()[1])
            key = f.read(L)
            result.append(key)
            f.readline()
            line = f.readline()
            assert line.startswith("V ")
            L = int(line.split()[1])
            value = f.read(L)
            f.readline()
        f.close()
84 85
    return result

86 87 88 89 90 91 92

def set_eol_native(path):
    cmd = 'svn propset svn:eol-style native "{}"'.format(path)
    propset = subprocess.Popen(cmd, shell=True)
    propset.wait()


93
possible_text_file = re.compile(r"\.([hc]|py|txt|sln|vcproj)$").search
94

95 96 97 98 99

def main():
    for arg in sys.argv[1:] or [os.curdir]:
        if os.path.isfile(arg):
            root, fn = os.path.split(arg)
100
            if 'svn:eol-style' not in proplist(root, fn):
101 102 103 104 105 106 107 108 109 110 111 112 113 114
                set_eol_native(arg)
        elif os.path.isdir(arg):
            for root, dirs, files in os.walk(arg):
                if '.svn' in dirs:
                    dirs.remove('.svn')
                for fn in files:
                    if possible_text_file(fn):
                        if 'svn:eol-style' not in proplist(root, fn):
                            path = os.path.join(root, fn)
                            set_eol_native(path)


if __name__ == '__main__':
    main()