OLD | NEW |
1 # This file is part of Adblock Plus <https://adblockplus.org/>, | 1 # This file is part of Adblock Plus <https://adblockplus.org/>, |
2 # Copyright (C) 2006-present eyeo GmbH | 2 # Copyright (C) 2006-present eyeo GmbH |
3 # | 3 # |
4 # Adblock Plus is free software: you can redistribute it and/or modify | 4 # Adblock Plus is free software: you can redistribute it and/or modify |
5 # it under the terms of the GNU General Public License version 3 as | 5 # it under the terms of the GNU General Public License version 3 as |
6 # published by the Free Software Foundation. | 6 # published by the Free Software Foundation. |
7 # | 7 # |
8 # Adblock Plus is distributed in the hope that it will be useful, | 8 # Adblock Plus is distributed in the hope that it will be useful, |
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 | 82 |
83 try: | 83 try: |
84 included, inherited_source = _get_and_parse_fragment( | 84 included, inherited_source = _get_and_parse_fragment( |
85 name, sources, default_source, include_stack) | 85 name, sources, default_source, include_stack) |
86 all_included = _process_includes( | 86 all_included = _process_includes( |
87 sources, inherited_source, include_stack, included) | 87 sources, inherited_source, include_stack, included) |
88 | 88 |
89 _logger.info('- including: %s', name) | 89 _logger.info('- including: %s', name) |
90 yield Comment('*** {} ***'.format(name)) | 90 yield Comment('*** {} ***'.format(name)) |
91 for line in all_included: | 91 for line in all_included: |
92 yield line | 92 if line.type not in {'header', 'metadata'}: |
| 93 yield line |
93 except (NotFound, ValueError) as exc: | 94 except (NotFound, ValueError) as exc: |
94 raise IncludeError(exc, include_stack) | 95 raise IncludeError(exc, include_stack) |
95 else: | 96 else: |
96 yield line | 97 yield line |
97 | 98 |
98 | 99 |
99 def _process_timestamps(lines): | 100 def _process_timestamps(lines): |
100 """Convert timestamp markers into actual timestamps.""" | 101 """Convert timestamp markers into actual timestamps.""" |
101 for line in lines: | 102 for line in lines: |
102 if line.type == 'comment' and '%timestamp%' in line.text: | 103 if line.type == 'metadata' and line.value == '%timestamp%': |
103 timestamp = time.strftime('%d %b %Y %H:%M UTC', time.gmtime()) | 104 timestamp = time.strftime('%d %b %Y %H:%M UTC', time.gmtime()) |
104 yield Comment(text=line.text.replace('%timestamp%', timestamp)) | 105 yield Metadata(line.key, timestamp) |
105 else: | 106 else: |
106 yield line | 107 yield line |
107 | 108 |
108 | 109 |
109 def _first_and_rest(iterable): | 110 def _first_and_rest(iterable): |
110 """Return the first item from the iterable and the rest as an iterator.""" | 111 """Return the first item from the iterable and the rest as an iterator.""" |
111 iterator = iter(iterable) | 112 iterator = iter(iterable) |
112 first_item = next(iterator) | 113 first_item = next(iterator) |
113 return first_item, iterator | 114 return first_item, iterator |
114 | 115 |
115 | 116 |
116 def _insert_version(lines): | 117 def _insert_version(lines): |
117 """Insert metadata comment with version (a.k.a. date).""" | 118 """Insert metadata comment with version (a.k.a. date).""" |
118 first_line, rest = _first_and_rest(lines) | 119 first_line, rest = _first_and_rest(lines) |
119 version = Metadata('Version', time.strftime('%Y%m%d%H%M', time.gmtime())) | 120 version = Metadata('Version', time.strftime('%Y%m%d%H%M', time.gmtime())) |
120 return itertools.chain([first_line, version], rest) | 121 return itertools.chain([first_line, version], rest) |
121 | 122 |
122 | 123 |
123 def _remove_duplicates(lines): | 124 def _remove_checksum(lines): |
124 """Remove duplicate metadata and headers.""" | 125 """Remove metadata comments giving a checksum. |
125 # Always remove checksum -- a checksum coming from a fragment | 126 |
126 # will not match for the rendered list. | 127 Adblock Plus is no longer verifying checksums, so we don't have to |
127 seen = {'checksum'} | 128 calculate the checksum for the resulting filter list. But we have |
128 for i, line in enumerate(lines): | 129 to strip them for compatibility with older versions of Adblock Plus |
129 if line.type == 'metadata': | 130 and other ad blockers which might still verify a checksum if given. |
130 key = line.key.lower() | 131 """ |
131 if key not in seen: | 132 for line in lines: |
132 seen.add(key) | 133 if line.type != 'metadata' or line.key.lower() != 'checksum': |
133 yield line | |
134 elif line.type == 'header': | |
135 if i == 0: | |
136 yield line | |
137 else: | |
138 yield line | 134 yield line |
139 | 135 |
140 | 136 |
141 def _validate(lines): | 137 def _validate(lines): |
142 """Validate the final list.""" | 138 """Validate the final list.""" |
143 first_line, rest = _first_and_rest(lines) | 139 first_line, rest = _first_and_rest(lines) |
144 if first_line.type != 'header': | 140 if first_line.type != 'header': |
145 raise MissingHeader('No header found at the beginning of the input.') | 141 raise MissingHeader('No header found at the beginning of the input.') |
146 return itertools.chain([first_line], rest) | 142 return itertools.chain([first_line], rest) |
147 | 143 |
(...skipping 22 matching lines...) Expand all Loading... |
170 ParseError | 166 ParseError |
171 When any of the fragments contain lines that can't be parsed. | 167 When any of the fragments contain lines that can't be parsed. |
172 MissingHeader | 168 MissingHeader |
173 If the top level fragment doesn't start with a valid header. This would | 169 If the top level fragment doesn't start with a valid header. This would |
174 lead to rendering an invalid filter list, so we immediately abort. | 170 lead to rendering an invalid filter list, so we immediately abort. |
175 | 171 |
176 """ | 172 """ |
177 _logger.info('Rendering: %s', name) | 173 _logger.info('Rendering: %s', name) |
178 lines, default_source = _get_and_parse_fragment(name, sources, top_source) | 174 lines, default_source = _get_and_parse_fragment(name, sources, top_source) |
179 lines = _process_includes(sources, default_source, [name], lines) | 175 lines = _process_includes(sources, default_source, [name], lines) |
180 for proc in [_process_timestamps, _insert_version, _remove_duplicates, | 176 for proc in [_process_timestamps, _insert_version, _remove_checksum, |
181 _validate]: | 177 _validate]: |
182 lines = proc(lines) | 178 lines = proc(lines) |
183 return lines | 179 return lines |
184 | 180 |
185 | 181 |
186 def _split_list_for_diff(list_in): | 182 def _split_list_for_diff(list_in): |
187 """Split a filter list into metadata and rules.""" | 183 """Split a filter list into metadata and rules.""" |
188 metadata = {} | 184 metadata = {} |
189 rules = set() | 185 rules = set() |
190 for line in parse_filterlist(list_in): | 186 for line in parse_filterlist(list_in): |
(...skipping 27 matching lines...) Expand all Loading... |
218 for key, latest in latest_metadata.items(): | 214 for key, latest in latest_metadata.items(): |
219 base = base_metadata.get(key) | 215 base = base_metadata.get(key) |
220 if not base or base.value != latest.value: | 216 if not base or base.value != latest.value: |
221 yield latest.to_string() | 217 yield latest.to_string() |
222 for key in set(base_metadata) - set(latest_metadata): | 218 for key in set(base_metadata) - set(latest_metadata): |
223 yield '! {}:'.format(base_metadata[key].key) | 219 yield '! {}:'.format(base_metadata[key].key) |
224 for rule in base_rules - latest_rules: | 220 for rule in base_rules - latest_rules: |
225 yield '- {}'.format(rule) | 221 yield '- {}'.format(rule) |
226 for rule in latest_rules - base_rules: | 222 for rule in latest_rules - base_rules: |
227 yield '+ {}'.format(rule) | 223 yield '+ {}'.format(rule) |
OLD | NEW |