aboutsummaryrefslogtreecommitdiffstats
path: root/bin/common/srtool_patcher.py
blob: 6bf65755e3255ba364820f902b15b04f97d36838 (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#!/usr/bin/env python3
#
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# Security Response Tool Implementation
#
# Copyright (C) 2019       Wind River Systems
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

#
# Theory of operation
#
#  * This script runs quick sanity tests
#  * The '--init-test' option will:
#    * Report the host package versions
#    * Report errors if any required tables are empty
#    * Report the running instance of the SRTool
#

import os
import sys
import argparse
import json

# Setup:
verbose = False

#################################
# extract_custom_patch
#

def extract_custom_patch(custom_file,clean_file,patch_file,label,patcher_dir):
    tag_begin = "%s_EXTENSION_BEGIN" % label
    tag_end = "%s_EXTENSION_END" % label
    ret = 0

    # Insure patcher working directory is ready
    if not patcher_dir:
        patcher_dir = os.path.dirname(custom_file)
    try:
        os.makedirs(patcher_dir)
    except:
        pass
    # Prepare defaults
    if not clean_file:
        clean_file = os.path.join(patcher_dir,os.path.basename(custom_file) + '.clean')
    if not patch_file:
        patch_file = os.path.join(patcher_dir,os.path.basename(custom_file) + '.patch')

    with open(custom_file, 'r') as fs:
        with open(clean_file, 'w') as fd:
            state = "find"
            for line in fs:
                #print("LINE(%s):%s" % (state,line.strip()))
                if state == "find":
                    if 0 < line.find(tag_begin):
                        #print("START:$line")
                        state = "found"
                        continue
                elif state == "found":
                    if 0 < line.find(tag_end):
                        #print("STOP:$line")
                        state = "blank"
                        continue
                elif state == "blank":
                    state = "find"
                    # if next line after stop is blank, hide that also
                    if not line.strip():
                        continue
                # Normal line?
                if state != "found":
                    fd.write('%s' % line)
            # Did we end cleanly?
            if state != "find":
                print("ERROR: START not STOPPED (%s)" % state)
    os.system("diff -u %s %s > %s" % (clean_file,custom_file,patch_file))
    print("Custom File: %s" % (custom_file))
    print("Clean  File: %s" % (clean_file))
    print("Patch  File: %s" % (patch_file))
    return(ret,clean_file,patch_file)

#################################
# merge_original
#

def merge_original(custom_file,original_file,patch_file,label,patcher_dir):
    ret,clean_file,patch_file = extract_custom_patch(custom_file,'',patch_file,label,patcher_dir)
    custom_saved = os.path.join(os.path.dirname(patch_file),os.path.basename(custom_file) + '.saved')
    if 0 == ret:
        print("* Preserving custom file as '%s'" % custom_saved)
        cmd = "cp %s %s" % (custom_file,custom_saved)
        print(cmd)
        os.system(cmd)
        print("* Merging original file '%s' into custom file" % original_file)
        cmd = "cp %s %s" % (original_file,custom_file)
        print(cmd)
        os.system(cmd)
        cmd = "patch %s %s" % (custom_file,patch_file)
        print(cmd)
        ret = os.system(cmd)
        if 0 != ret:
            print("* ERROR: Merge failed, restoring previous custom file")
            cmd = "cp %s %s" % (custom_saved,custom_file)
            print(cmd)
            os.system(cmd)
    return(ret)

#################################
# merge_custom
#

def merge_custom(custom_file,original_file,patch_file,label,patcher_dir):
    ret,clean_file,patch_file = extract_custom_patch(custom_file,'',patch_file,label,patcher_dir)
    if 0 == ret:
        print("== Copying clean version of custom file to '%s' ===" % original_file)
        cmd = "cp -f %s %s" % (clean_file, original_file)
        print(cmd)
        os.system(cmd)
    return(ret)

#################################
# diff_original
#

def diff_original(custom_file,original_file,patch_file,label,patcher_dir):
    ret,clean_file,patch_file = extract_custom_patch(custom_file,'',patch_file,label,patcher_dir)
    if 0 == ret:
        print("== DIFF from '%s' to clean version of custom file ===" % original_file)
        os.system("diff -u %s %s" % (original_file,clean_file))
    return(ret)

#################################
# load_json_list
#

def load_json_list(json_file):
    label = 'CUSTOM'
    patcher_dir = ''
    file_list = []

    with open(json_file) as json_data:
        dct = json.load(json_data)

        if 'label' in dct:
            label = dct['label']
        if 'patcher_dir' in dct:
            patcher_dir = dct['patcher_dir']
        if 'patch_set' in dct:
            for patch in dct['patch_set']:
                if 'DISABLE' in patch['options']:
                    continue
                file_list.append([patch['custom'],patch['original'],patch['patch'],patch['options']])
    return file_list,patcher_dir,label

#################################
# main loop
#

def main(argv):
    global verbose

    # setup
    parser = argparse.ArgumentParser(description='srtool_sanity_test.py: SRTool common sanity tests')

    parser.add_argument('--merge-original', '-O', action='store_const', const='merge_original', dest='command', help='Copy the (updated) original file, merge the custom patches')
    parser.add_argument('--merge-custom', '-C', action='store_const', const='merge_custom', dest='command', help='Copy the (updated) file to the original, without custom patches')

    parser.add_argument('--custom', '-c', help='Custom file')
    parser.add_argument('--original', '-o', help='Original file')
    parser.add_argument('--label', '-l', help='Custom label tag (default="CUSTOM")')
    parser.add_argument('--json', '-j', help='Use JSON file for file list')

    parser.add_argument('--extract-custom-patch', '-e', action='store_const', const='extract_custom_patch', dest='command', help='Extract a patch of the custom content')
    parser.add_argument('--apply-custom-patch', '-a', action='store_const', const='extract_custom_patch', dest='command', help='Apply the custom patch to the (reset) custom file')
    parser.add_argument('--patch', '-p', help='Patch file')
    parser.add_argument('--diff-original', '-d', action='store_const', const='diff_original', dest='command', help='Show how the file compares to original, ignoring custom patches')

    parser.add_argument('--verbose', '-v', action='store_true', dest='verbose', help='Debugging: verbose output')
    args = parser.parse_args()

    def validate_file(filename,msg):
        if not (filename or os.path.isfile(filename)):
            print("ERROR: %s file not found '%s'" % (msg,filename))
            exit(1)

    # Extract provided values
    verbose = args.verbose
    file_list = []
    if args.json:
        validate_file(args.json,"JSON")
        file_list,patcher_dir,label = load_json_list(args.json)
    else:
        custom_file = ''
        if args.custom:
            custom_file = args.custom
        original_file = ''
        if args.original:
            original_file = args.original
        patch_file = ''
        if args.patch:
            patch_file = args.patch
        options = ''
        file_list.append([custom_file,original_file,patch_file,options])
        label = 'CUSTOM'
        if args.label:
            label = args.label
        patcher_dir = os.path.join(os.path.dirname(custom_file),'patcher')

    ret = 0
    for custom_file,original_file,patch_file,options in file_list:
        #print("PATCH_FILE:%s,%s,%s,%s,%s" % (custom_file,original_file,patch_file,options,patcher_dir))
        if 'merge_original' == args.command:
            validate_file(custom_file,'Custom')
            validate_file(original_file,'Original')
            ret = merge_original(custom_file,original_file,patch_file,label,patcher_dir)
        elif 'merge_custom' == args.command:
            validate_file(custom_file,'Custom')
            validate_file(original_file,'Original')
            ret = merge_custom(custom_file,original_file,patch_file,label,patcher_dir)
        elif 'extract_custom_patch' == args.command:
            validate_file(custom_file,'Custom')
            ret,clean_file,patch_file = extract_custom_patch(custom_file,'',patch_file,label,patcher_dir)
        elif 'diff_original' == args.command:
            validate_file(custom_file,'Custom')
            validate_file(original_file,'Original')
            ret = diff_original(custom_file,original_file,patch_file,label,patcher_dir)
        else:
            print("Command not found '%s'" % args.command)
            ret = 1
        if 0 != ret:
            exit(ret)
    exit(ret)

if __name__ == '__main__':
    srtool_basepath = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0]))))
    main(sys.argv[1:])