• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2import sys
3import os
4
5class FileContextsNode:
6    path = None
7    fileType = None
8    context = None
9    Type = None
10    meta = None
11    stemLen = None
12    strLen = None
13    Type = None
14    def __init__(self, path, fileType, context, meta, stemLen, strLen):
15        self.path = path
16        self.fileType = fileType
17        self.context = context
18        self.meta = meta
19        self.stemLen = stemLen
20        self.strlen = strLen
21        self.Type = context.split(":")[2]
22
23metaChars = frozenset(['.', '^', '$', '?', '*', '+', '|', '[', '(', '{'])
24escapedMetaChars = frozenset(['\.', '\^', '\$', '\?', '\*', '\+', '\|', '\[', '\(', '\{'])
25
26def getStemLen(path):
27    global metaChars
28    stemLen = 0
29    i = 0
30    while i < len(path):
31        if path[i] == "\\":
32            i += 1
33        elif path[i] in metaChars:
34            break
35        stemLen += 1
36        i += 1
37    return stemLen
38
39
40def getIsMeta(path):
41    global metaChars
42    global escapedMetaChars
43    metaCharsCount = 0
44    escapedMetaCharsCount = 0
45    for c in metaChars:
46        if c in path:
47            metaCharsCount += 1
48    for c in escapedMetaChars:
49        if c in path:
50            escapedMetaCharsCount += 1
51    return metaCharsCount > escapedMetaCharsCount
52
53def CreateNode(line):
54    global metaChars
55    if (len(line) == 0) or (line[0] == '#'):
56        return None
57
58    split = line.split()
59    path = split[0].strip()
60    context = split[-1].strip()
61    fileType = None
62    if len(split) == 3:
63        fileType = split[1].strip()
64    meta = getIsMeta(path)
65    stemLen = getStemLen(path)
66    strLen = len(path.replace("\\", ""))
67
68    return FileContextsNode(path, fileType, context, meta, stemLen, strLen)
69
70def ReadFileContexts(files):
71    fc = []
72    for f in files:
73        fd = open(f)
74        for line in fd:
75            node = CreateNode(line.strip())
76            if node != None:
77                fc.append(node)
78    return fc
79
80# Comparator function for list.sort() based off of fc_sort.c
81# Compares two FileContextNodes a and b and returns 1 if a is more
82# specific or -1 if b is more specific.
83def compare(a, b):
84    # The regex without metachars is more specific
85    if a.meta and not b.meta:
86        return -1
87    if b.meta and not a.meta:
88        return 1
89
90    # The regex with longer stemlen (regex before any meta characters) is more specific.
91    if a.stemLen < b.stemLen:
92        return -1
93    if b.stemLen < a.stemLen:
94        return 1
95
96    # The regex with longer string length is more specific
97    if a.strLen < b.strLen:
98        return -1
99    if b.strLen < a.strLen:
100        return 1
101
102    # A regex with a fileType defined (e.g. file, dir) is more specific.
103    if a.fileType is None and b.fileType is not None:
104        return -1
105    if b.fileType is None and a.fileType is not None:
106        return 1
107
108    # Regexes are equally specific.
109    return 0
110
111def FcSort(files):
112    for f in files:
113        if not os.path.exists(f):
114            sys.exit("Error: File_contexts file " + f + " does not exist\n")
115
116    Fc = ReadFileContexts(files)
117    Fc.sort(cmp=compare)
118
119    return Fc
120
121if __name__ == '__main__':
122    if len(sys.argv) < 2:
123        sys.exit("Usage: fc_sort.py <file_contexts 1> <file_contexts 2> <file_contexts 3>")
124
125    FcSorted = FcSort(sys.argv[1:])
126