Rafaël Carré | 5b4a9b5 | 2010-05-31 00:46:04 +0000 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # -*- coding: utf8 -*- |
| 3 | # __________ __ ___. |
| 4 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 5 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 6 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 7 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 8 | # \/ \/ \/ \/ \/ |
| 9 | # |
| 10 | # Copyright © 2010 Rafaël Carré <rafael.carre@gmail> |
| 11 | # |
| 12 | # This program is free software; you can redistribute it and/or |
| 13 | # modify it under the terms of the GNU General Public License |
| 14 | # as published by the Free Software Foundation; either version 2 |
| 15 | # of the License, or (at your option) any later version. |
| 16 | # |
| 17 | # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | # KIND, either express or implied. |
| 19 | # |
| 20 | |
| 21 | # TODO: iram |
| 22 | |
| 23 | import sys |
| 24 | import os |
| 25 | import re |
| 26 | import stat |
| 27 | import fnmatch |
| 28 | |
| 29 | |
| 30 | def percent_diff(old, new): |
| 31 | if old == 0: |
| 32 | return '?' |
| 33 | diff = 100.0*(new-old)/old |
| 34 | return format(diff, '+2.2f') + '%' |
| 35 | |
| 36 | |
| 37 | def find_map(dir): |
| 38 | dirs = [] |
| 39 | for file in os.listdir(dir): |
| 40 | path = os.path.join(dir, file) |
| 41 | if stat.S_ISDIR(os.stat(path).st_mode) != 0: |
| 42 | dirs += find_map(path) |
| 43 | elif fnmatch.fnmatch(file, '*.map'): |
| 44 | dirs += [path] |
| 45 | return dirs |
| 46 | |
| 47 | |
| 48 | def rb_version(dir): |
| 49 | info = os.path.join(dir, 'rockbox-info.txt') |
| 50 | if not os.path.lexists(info): |
| 51 | return 'unknown' |
| 52 | info = open(info).read() |
| 53 | s = re.search('^Version: .*', info, re.MULTILINE) |
| 54 | if not s: |
| 55 | return 'unknown' |
| 56 | return re.sub('^Version: ', '', info[s.start():s.end()]) |
| 57 | |
| 58 | |
| 59 | def map_info(map): |
| 60 | file = os.path.basename(map) |
| 61 | name = file.rsplit('.map', 1)[0] |
| 62 | |
| 63 | # ignore ape-pre map, used to fill IRAM |
| 64 | if name == 'ape-pre': |
| 65 | return None |
| 66 | |
| 67 | # ignore overlays |
| 68 | ovlmap = os.path.join(os.path.dirname(map), name, file) |
| 69 | if os.path.lexists(ovlmap): |
| 70 | return None |
| 71 | |
| 72 | f = open(map).read() # read map content |
| 73 | |
| 74 | s = re.search('^PLUGIN_RAM *0x(\d|[abcdef])*', f, re.MULTILINE) |
Rafaël Carré | 3bc8fd0 | 2010-08-01 15:09:51 +0000 | [diff] [blame] | 75 | if not s: return (name, 0) |
Rafaël Carré | 5b4a9b5 | 2010-05-31 00:46:04 +0000 | [diff] [blame] | 76 | plugin_start = re.sub('^PLUGIN_RAM *0x0*', '', f[s.start():s.end()]) |
| 77 | |
| 78 | s = re.search('^\.pluginend *0x(\d|[abcdef])*', f, re.MULTILINE) |
Rafaël Carré | 3bc8fd0 | 2010-08-01 15:09:51 +0000 | [diff] [blame] | 79 | if not s: return (name, 0) |
Rafaël Carré | 5b4a9b5 | 2010-05-31 00:46:04 +0000 | [diff] [blame] | 80 | plugin_end = re.sub('^\.pluginend *0x0*', '', f[s.start():s.end()]) |
| 81 | |
| 82 | size = int(plugin_end, 16) - int(plugin_start, 16) |
| 83 | return (name, size) |
| 84 | |
| 85 | |
| 86 | def get_new(oldinfo, newinfo, name): |
| 87 | i = 0 |
| 88 | while i < len(oldinfo) and i < len(newinfo): |
| 89 | if newinfo[i][0] == name: |
| 90 | return newinfo[i] |
| 91 | i += 1 |
| 92 | return None |
| 93 | |
| 94 | |
| 95 | def compare(olddir, newdir, oldver, newer): |
| 96 | oldinfo = [] |
| 97 | for map in find_map(olddir): |
| 98 | info = map_info(map) |
| 99 | if info: |
| 100 | oldinfo += [info] |
| 101 | |
| 102 | newinfo = [] |
| 103 | for map in find_map(newdir): |
| 104 | info = map_info(map) |
| 105 | if info: |
| 106 | newinfo += [info] |
| 107 | |
| 108 | oldinfo.sort() |
| 109 | newinfo.sort() |
| 110 | |
| 111 | diff = [] |
| 112 | longest_name = 0 |
| 113 | for (name, old_size) in oldinfo: |
| 114 | new = get_new(oldinfo, newinfo, name) |
| 115 | if not new: |
| 116 | continue |
| 117 | (name, new_size) = new |
| 118 | if len(name) > longest_name: |
| 119 | longest_name = len(name) |
| 120 | diff += [(name, new_size - old_size, old_size)] |
| 121 | |
| 122 | spacelen = (longest_name + 3) |
| 123 | |
| 124 | print(' ' * spacelen + oldver + '\t\t' + newver + '\n') |
| 125 | |
| 126 | for (name, diff, old_size) in diff: |
| 127 | space = ' ' * (longest_name - len(name) + 3) |
| 128 | new_size = old_size + diff |
| 129 | pdiff = percent_diff(old_size, new_size) |
| 130 | diff = str(diff) |
| 131 | if diff[0] != '-': |
| 132 | diff = '+' + diff |
| 133 | |
| 134 | print(name + space + str(old_size) + '\t' + diff + \ |
| 135 | '\t=\t' + str(new_size) + '\t-->\t' + pdiff) |
| 136 | |
| 137 | |
| 138 | |
| 139 | |
| 140 | ### main |
| 141 | |
| 142 | |
| 143 | if len(sys.argv) != 3: |
| 144 | print('Usage: ' + sys.argv[0] + ' build-old build-new') |
| 145 | sys.exit(1) |
| 146 | |
| 147 | oldver = rb_version(sys.argv[1]) |
| 148 | newver = rb_version(sys.argv[2]) |
| 149 | |
| 150 | oldplugindir = sys.argv[1] + '/apps/plugins' |
| 151 | newplugindir = sys.argv[2] + '/apps/plugins' |
| 152 | oldcodecsdir = sys.argv[1] + '/apps/codecs' |
| 153 | newcodecsdir = sys.argv[2] + '/apps/codecs' |
| 154 | |
| 155 | if os.path.lexists(oldplugindir) and os.path.lexists(newplugindir): |
| 156 | compare(oldplugindir, newplugindir, oldver, newver) |
| 157 | |
| 158 | print('\n\n\n') |
| 159 | |
| 160 | if os.path.lexists(oldcodecsdir) and os.path.lexists(newcodecsdir): |
| 161 | compare(oldcodecsdir, newcodecsdir, oldver, newver) |