Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(119)

Side by Side Diff: client/libs/arfile/cli.py

Issue 2049523004: luci-py: Tools for working with BSD style ar archives. (Closed) Base URL: https://github.com/luci/luci-py.git@master
Patch Set: Actually fix the unicode problem properly. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « client/libs/arfile/arfile_test.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file.
4
5 """Command line tool for creating and extracting ar files."""
6
7 from __future__ import print_function
8
9 import argparse
10 import io
11 import os
12 import shutil
13 import stat
14 import sys
15 import time
16
17 # pylint: disable=relative-import
18 import arfile
19
20
21 class ProgressReporter(object):
22 def __init__(self, every):
23 self.every = int(every)
24 self.start = time.time()
25 self.filecount = 0
26 self.lastreport = 0
27
28 def inc(self):
29 self.filecount += 1
30 if (self.filecount - self.lastreport) >= self.every:
31 self.report()
32
33 def report(self):
34 if self.every:
35 t = time.time()-self.start
36 print(u'Took %f for %i files == %f files/second' % (
37 t, self.filecount, self.filecount/t), file=sys.stderr)
38 self.lastreport = self.filecount
39
40 def __del__(self):
41 self.report()
42
43
44 def create_cmd(
45 filename, dirs, progress, read_ahead, verbose, dont_use_defaults):
46 afw = arfile.ArFileWriter(filename)
47 try:
48 for path in dirs:
49 for dirpath, child_dirs, filenames in os.walk(path):
50 # In-place sort the child_dirs so we walk in lexicographical order
51 child_dirs.sort()
52 filenames.sort()
53 for fn in filenames:
54 fp = os.path.join(dirpath, fn)
55
56 if verbose:
57 print(fp, file=sys.stderr)
58
59 progress.inc()
60
61 with open(fp, 'rb') as f:
62 if dont_use_defaults:
63 afw.addfile(
64 arfile.ArInfo.frompath(fp[len(path)+1:], cwd=path),
65 f)
66 continue
67
68 # If a file is small, it is cheaper to just read the file rather
69 # than doing a stat
70 data = f.read(read_ahead)
71 if len(data) < read_ahead:
72 afw.addfile(arfile.ArInfo.fromdefault(
73 fp[len(path)+1:], len(data)), io.BytesIO(data))
74 else:
75 size = os.stat(fp).st_size
76 f.seek(0)
77 afw.addfile(arfile.ArInfo.fromdefault(
78 fp[len(path)+1:], size), f)
79 finally:
80 afw.close()
81
82
83 def list_cmd(filename, progress):
84 afr = arfile.ArFileReader(filename, fullparse=False)
85 for ai, _ in afr:
86 print(ai.name)
87 progress.inc()
88
89
90 def extract_cmd(
91 filename, progress, verbose, dont_use_defaults, blocksize=1024*64):
92 afr = arfile.ArFileReader(filename, fullparse=dont_use_defaults)
93 for ai, ifd in afr:
94 assert not ai.name.startswith('/')
95 if verbose:
96 print(ai.name, file=sys.stderr)
97
98 try:
99 os.makedirs(os.path.dirname(ai.name))
100 except OSError:
101 pass
102
103 with open(ai.name, 'wb') as ofd:
104 written = 0
105 while written < ai.size:
106 readsize = min(blocksize, ai.size-written)
107 ofd.write(ifd.read(readsize))
108 written += readsize
109
110 progress.inc()
111
112
113 def main(name, args):
114 parser = argparse.ArgumentParser(
115 prog=name,
116 description=sys.modules[__name__].__doc__)
117 subparsers = parser.add_subparsers(
118 dest='mode', help='sub-command help')
119
120 # Create command
121 parser_create = subparsers.add_parser(
122 'create', help='Create a new ar file')
123 parser_create.add_argument(
124 '-r', '--read-ahead',
125 type=int, default=1024*64,
126 help='Amount of data to read-ahead before doing a stat.')
127 parser_create.add_argument(
128 '-f', '--filename',
129 type=argparse.FileType('wb'), default=sys.stdout,
130 help='ar file to use')
131 parser_create.add_argument(
132 'dirs', nargs='+', help='Directory or file to add to the ar file')
133
134 # List command
135 parser_list = subparsers.add_parser('list', help='List a new ar file')
136
137 # Extract command
138 parser_extract = subparsers.add_parser(
139 'extract', help='Extract an existing ar file to current directory')
140
141 # Add to output commands
142 for p in parser_list, parser_extract:
143 p.add_argument(
144 '-f', '--filename',
145 type=argparse.FileType('rb'), default=sys.stdin,
146 help='ar file to use')
147
148 for p in parser_create, parser_extract:
149 p.add_argument(
150 '--dont-use-defaults',
151 action='store_true', default=False,
152 help='Don\'t use default value for file information.')
153
154 p.add_argument(
155 '-v', '--verbose',
156 action='store_true',
157 help='Output file names to stderr while running.')
158
159 # Add to all commands
160 for p in parser_create, parser_list, parser_extract:
161 p.add_argument(
162 '-p', '--progress',
163 type=ProgressReporter, default='10000',
164 help='Output progress information every N files.')
165
166 args = parser.parse_args(args)
167 mode = getattr(sys.modules[__name__], args.mode + '_cmd')
168 del args.mode
169 return mode(**args.__dict__)
170
171
172 if __name__ == '__main__':
173 sys.exit(main('artool', (a.decode('utf-8') for a in sys.argv[1:])))
OLDNEW
« no previous file with comments | « client/libs/arfile/arfile_test.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698