summaryrefslogtreecommitdiffstats
path: root/tools/cmd_check.py
blob: bfe90c4392c729a092813cea3651343dbb4e25be (plain)
1
2
3
4
5
6
7
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/python3
# Command Checker
# Copyright (C) 2016 Cumulus Networks, Inc.
#
# This file is part of Quagga.
#
# Quagga is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version.
#
# Quagga is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Quagga; see the file COPYING.  If not, write to the Free
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#  02111-1307, USA.
#

# Parses a source file, ensuring that CLI definitions (DEFUNs, ALIASs, etc)
# have install_command called on them at some point.
import sys
import glob
import re
import os
from pprint import pprint

# patterns used to extract commands
command_patterns = [
  r'DEF.*\(.*\n\s*([0-9a-z_]*_cmd)',
  r'ALIAS.*\(.*\n\s*([0-9a-z_]*_cmd)',
]

# patterns that count as installing the command
install_patterns = [
    r'install_element.*\(.*{0}',
    r'INSTALL.*\(.*{0}'
]

def process(filename):
    cmds = []
    uninstalled = []
    sourcetext = ''
    headertext = ''

    # read source file and header file
    with open(filename) as cf:
        try:
            sourcetext = cf.read()
            headerfile = filename.replace('.c', '.h')
            if os.path.isfile(headerfile):
                with open(headerfile) as hf:
                  headertext = hf.read()
        except:
            print('Error reading {0}, skipping'.format(filename))
            return

    # build list of defined commands that aren't mentioned in header
    for pattern in command_patterns:
        matches = re.findall(pattern, sourcetext, re.M)
        cmds += filter(lambda x: re.search(x, headertext) is None, matches)
 
    # build list of not installed commands
    for cmd in cmds:
        pats = [ ip.format(cmd) for ip in install_patterns ]
        if all([ re.search(pat, sourcetext) is None for pat in pats ]):
            uninstalled.append(cmd)

    if len(uninstalled) > 0:
        print('\033[92m', end='')
        print('{0}'.format(filename))
        print('\033[0m', end='')
        for cmd in uninstalled:
            print('  {0}'.format(cmd))
        print('')

usage = """
Usage:
    ./cmd_check.py <path> [<path>...]

    where 'path' is a C source file or directory
    containing C source files
"""

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print(usage)
        exit()

    cwd = os.getcwd()
    for arg in sys.argv[1:]:
        # collect all c files
        globstr = arg
        if os.path.isdir(arg):
            os.chdir(arg)
            globstr = '*.c'
        for filename in glob.glob(globstr):
            process(filename)
        os.chdir(cwd)