~ubuntu-branches/ubuntu/precise/bittornado/precise

« back to all changes in this revision

Viewing changes to .pc/32_use_hashlib_for_sha.patch/BitTornado/BT1/makemetafile.py

  • Committer: Barry Warsaw
  • Date: 2011-08-10 23:17:46 UTC
  • mfrom: (7.1.1 bittornado)
  • Revision ID: barry@python.org-20110810231746-5buiob6p54m266s8
Tags: 0.3.18-10ubuntu2
* switch to dh_python2 (LP: #788514)
  - install btmakemetafile.py and btcompletedir.py via pyinstall
  - add build depend on python-all
  - bump debhelper depend to 7 for dh_auto_install

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Written by Bram Cohen
 
2
# multitracker extensions by John Hoffman
 
3
# see LICENSE.txt for license information
 
4
 
 
5
from os.path import getsize, split, join, abspath, isdir
 
6
from os import listdir
 
7
from sha import sha
 
8
from copy import copy
 
9
from string import strip
 
10
from BitTornado.bencode import bencode
 
11
from btformats import check_info
 
12
from threading import Event
 
13
from time import time
 
14
from traceback import print_exc
 
15
try:
 
16
    from sys import getfilesystemencoding
 
17
    ENCODING = getfilesystemencoding()
 
18
except:
 
19
    from sys import getdefaultencoding
 
20
    ENCODING = getdefaultencoding()
 
21
 
 
22
defaults = [
 
23
    ('announce_list', '',
 
24
        'a list of announce URLs - explained below'),
 
25
    ('httpseeds', '',
 
26
        'a list of http seed URLs - explained below'),
 
27
    ('piece_size_pow2', 0,
 
28
        "which power of 2 to set the piece size to (0 = automatic)"),
 
29
    ('comment', '',
 
30
        "optional human-readable comment to put in .torrent"),
 
31
    ('filesystem_encoding', '',
 
32
        "optional specification for filesystem encoding " +
 
33
        "(set automatically in recent Python versions)"),
 
34
    ('target', '',
 
35
        "optional target file for the torrent")
 
36
    ]
 
37
 
 
38
default_piece_len_exp = 18
 
39
 
 
40
ignore = ['core', 'CVS']
 
41
 
 
42
def print_announcelist_details():
 
43
    print ('    announce_list = optional list of redundant/backup tracker URLs, in the format:')
 
44
    print ('           url[,url...][|url[,url...]...]')
 
45
    print ('                where URLs separated by commas are all tried first')
 
46
    print ('                before the next group of URLs separated by the pipe is checked.')
 
47
    print ("                If none is given, it is assumed you don't want one in the metafile.")
 
48
    print ('                If announce_list is given, clients which support it')
 
49
    print ('                will ignore the <announce> value.')
 
50
    print ('           Examples:')
 
51
    print ('                http://tracker1.com|http://tracker2.com|http://tracker3.com')
 
52
    print ('                     (tries trackers 1-3 in order)')
 
53
    print ('                http://tracker1.com,http://tracker2.com,http://tracker3.com')
 
54
    print ('                     (tries trackers 1-3 in a randomly selected order)')
 
55
    print ('                http://tracker1.com|http://backup1.com,http://backup2.com')
 
56
    print ('                     (tries tracker 1 first, then tries between the 2 backups randomly)')
 
57
    print ('')
 
58
    print ('    httpseeds = optional list of http-seed URLs, in the format:')
 
59
    print ('            url[|url...]')
 
60
    
 
61
def make_meta_file(file, url, params = {}, flag = Event(),
 
62
                   progress = lambda x: None, progress_percent = 1):
 
63
    if params.has_key('piece_size_pow2'):
 
64
        piece_len_exp = params['piece_size_pow2']
 
65
    else:
 
66
        piece_len_exp = default_piece_len_exp
 
67
    if params.has_key('target') and params['target'] != '':
 
68
        f = params['target']
 
69
    else:
 
70
        a, b = split(file)
 
71
        if b == '':
 
72
            f = a + '.torrent'
 
73
        else:
 
74
            f = join(a, b + '.torrent')
 
75
            
 
76
    if piece_len_exp == 0:  # automatic
 
77
        size = calcsize(file)
 
78
        if   size > 8L*1024*1024*1024:   # > 8 gig =
 
79
            piece_len_exp = 21          #   2 meg pieces
 
80
        elif size > 2*1024*1024*1024:   # > 2 gig =
 
81
            piece_len_exp = 20          #   1 meg pieces
 
82
        elif size > 512*1024*1024:      # > 512M =
 
83
            piece_len_exp = 19          #   512K pieces
 
84
        elif size > 64*1024*1024:       # > 64M =
 
85
            piece_len_exp = 18          #   256K pieces
 
86
        elif size > 16*1024*1024:       # > 16M =
 
87
            piece_len_exp = 17          #   128K pieces
 
88
        elif size > 4*1024*1024:        # > 4M =
 
89
            piece_len_exp = 16          #   64K pieces
 
90
        else:                           # < 4M =
 
91
            piece_len_exp = 15          #   32K pieces
 
92
    piece_length = 2 ** piece_len_exp
 
93
 
 
94
    encoding = None
 
95
    if params.has_key('filesystem_encoding'):
 
96
        encoding = params['filesystem_encoding']
 
97
    if not encoding:
 
98
        encoding = ENCODING
 
99
    if not encoding:
 
100
        encoding = 'ascii'
 
101
    
 
102
    info = makeinfo(file, piece_length, encoding, flag, progress, progress_percent)
 
103
    if flag.isSet():
 
104
        return
 
105
    check_info(info)
 
106
    h = open(f, 'wb')
 
107
    data = {'info': info, 'announce': strip(url), 'creation date': long(time())}
 
108
    
 
109
    if params.has_key('comment') and params['comment']:
 
110
        data['comment'] = params['comment']
 
111
        
 
112
    if params.has_key('real_announce_list'):    # shortcut for progs calling in from outside
 
113
        data['announce-list'] = params['real_announce_list']
 
114
    elif params.has_key('announce_list') and params['announce_list']:
 
115
        l = []
 
116
        for tier in params['announce_list'].split('|'):
 
117
            l.append(tier.split(','))
 
118
        data['announce-list'] = l
 
119
        
 
120
    if params.has_key('real_httpseeds'):    # shortcut for progs calling in from outside
 
121
        data['httpseeds'] = params['real_httpseeds']
 
122
    elif params.has_key('httpseeds') and params['httpseeds']:
 
123
        data['httpseeds'] = params['httpseeds'].split('|')
 
124
        
 
125
    h.write(bencode(data))
 
126
    h.close()
 
127
 
 
128
def calcsize(file):
 
129
    if not isdir(file):
 
130
        return getsize(file)
 
131
    total = 0L
 
132
    for s in subfiles(abspath(file)):
 
133
        total += getsize(s[1])
 
134
    return total
 
135
 
 
136
 
 
137
def uniconvertl(l, e):
 
138
    r = []
 
139
    try:
 
140
        for s in l:
 
141
            r.append(uniconvert(s, e))
 
142
    except UnicodeError:
 
143
        raise UnicodeError('bad filename: '+join(*l))
 
144
    return r
 
145
 
 
146
def uniconvert(s, e):
 
147
    try:
 
148
        if s.__class__.__name__ != 'unicode':
 
149
            s = unicode(s,e)
 
150
    except UnicodeError:
 
151
        raise UnicodeError('bad filename: '+s)
 
152
    return s.encode('utf-8')
 
153
 
 
154
def makeinfo(file, piece_length, encoding, flag, progress, progress_percent=1):
 
155
    file = abspath(file)
 
156
    if isdir(file):
 
157
        subs = subfiles(file)
 
158
        subs.sort()
 
159
        pieces = []
 
160
        sh = sha()
 
161
        done = 0L
 
162
        fs = []
 
163
        totalsize = 0.0
 
164
        totalhashed = 0L
 
165
        for p, f in subs:
 
166
            totalsize += getsize(f)
 
167
 
 
168
        for p, f in subs:
 
169
            pos = 0L
 
170
            size = getsize(f)
 
171
            fs.append({'length': size, 'path': uniconvertl(p, encoding)})
 
172
            h = open(f, 'rb')
 
173
            while pos < size:
 
174
                a = min(size - pos, piece_length - done)
 
175
                sh.update(h.read(a))
 
176
                if flag.isSet():
 
177
                    return
 
178
                done += a
 
179
                pos += a
 
180
                totalhashed += a
 
181
                
 
182
                if done == piece_length:
 
183
                    pieces.append(sh.digest())
 
184
                    done = 0
 
185
                    sh = sha()
 
186
                if progress_percent:
 
187
                    progress(totalhashed / totalsize)
 
188
                else:
 
189
                    progress(a)
 
190
            h.close()
 
191
        if done > 0:
 
192
            pieces.append(sh.digest())
 
193
        return {'pieces': ''.join(pieces),
 
194
            'piece length': piece_length, 'files': fs, 
 
195
            'name': uniconvert(split(file)[1], encoding) }
 
196
    else:
 
197
        size = getsize(file)
 
198
        pieces = []
 
199
        p = 0L
 
200
        h = open(file, 'rb')
 
201
        while p < size:
 
202
            x = h.read(min(piece_length, size - p))
 
203
            if flag.isSet():
 
204
                return
 
205
            pieces.append(sha(x).digest())
 
206
            p += piece_length
 
207
            if p > size:
 
208
                p = size
 
209
            if progress_percent:
 
210
                progress(float(p) / size)
 
211
            else:
 
212
                progress(min(piece_length, size - p))
 
213
        h.close()
 
214
        return {'pieces': ''.join(pieces), 
 
215
            'piece length': piece_length, 'length': size, 
 
216
            'name': uniconvert(split(file)[1], encoding) }
 
217
 
 
218
def subfiles(d):
 
219
    r = []
 
220
    stack = [([], d)]
 
221
    while len(stack) > 0:
 
222
        p, n = stack.pop()
 
223
        if isdir(n):
 
224
            for s in listdir(n):
 
225
                if s not in ignore and s[:1] != '.':
 
226
                    stack.append((copy(p) + [s], join(n, s)))
 
227
        else:
 
228
            r.append((p, n))
 
229
    return r
 
230
 
 
231
 
 
232
def completedir(dir, url, params = {}, flag = Event(),
 
233
                vc = lambda x: None, fc = lambda x: None):
 
234
    files = listdir(dir)
 
235
    files.sort()
 
236
    ext = '.torrent'
 
237
    if params.has_key('target'):
 
238
        target = params['target']
 
239
    else:
 
240
        target = ''
 
241
 
 
242
    togen = []
 
243
    for f in files:
 
244
        if f[-len(ext):] != ext and (f + ext) not in files:
 
245
            togen.append(join(dir, f))
 
246
        
 
247
    total = 0
 
248
    for i in togen:
 
249
        total += calcsize(i)
 
250
 
 
251
    subtotal = [0]
 
252
    def callback(x, subtotal = subtotal, total = total, vc = vc):
 
253
        subtotal[0] += x
 
254
        vc(float(subtotal[0]) / total)
 
255
    for i in togen:
 
256
        fc(i)
 
257
        try:
 
258
            t = split(i)[-1]
 
259
            if t not in ignore and t[0] != '.':
 
260
                if target != '':
 
261
                    params['target'] = join(target,t+ext)
 
262
                make_meta_file(i, url, params, flag, progress = callback, progress_percent = 0)
 
263
        except ValueError:
 
264
            print_exc()