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

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: Reworking API to better match zipfile/tarfile API. Created 4 years, 6 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
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 os
11 import stat
12 import sys
13 import shutil
14 import time
15
16 from cStringIO import StringIO
17
18 import arfile
19
20 class ProgressReporter(object):
21 def __init__(self, every):
22 self.every = int(every)
23 self.start = time.time()
24 self.filecount = 0
25 self.lastreport = 0
26
27 def inc(self):
28 self.filecount += 1
29 if (self.filecount - self.lastreport) >= self.every:
30 self.report()
31
32 def report(self):
33 if self.every:
34 t = time.time()-self.start
35 print('Took %f for %i files == %f files/second' % (
36 t, self.filecount, self.filecount/t), file=sys.stderr)
37 self.lastreport = self.filecount
38
39 def __del__(self):
40 self.report()
41
42
43 def create_cmd(filename, dirs, progress, read_ahead=0, verbose=True):
M-A Ruel 2016/06/16 14:57:05 remove all default argument, they are not needed
mithro 2016/06/17 06:44:50 Done.
44 afw = arfile.ArFileWriter(filename)
45 for path in dirs:
46 for dirpath, child_dirs, filenames in os.walk(path):
47 # In-place sort the child_dirs so we walk in lexicographical order
48 child_dirs.sort()
49
50 for fn in sorted(filenames):
M-A Ruel 2016/06/16 14:57:05 filenames.sort() would be faster?
mithro 2016/06/17 06:44:50 Done.
51 fp = os.path.join(dirpath, fn)
52
53 if verbose:
54 print(fp, file=sys.stderr)
55
56 with open(fp, 'rb') as f:
57 # If a file is small, it is cheaper to just read the file rather than
58 # doing a stat
59 data = f.read(read_ahead)
60 if len(data) < read_ahead:
61 afw.addfile(arfile.ArInfo.fromdefault(
62 fp[len(path)+1:], len(data)), StringIO(data))
63 else:
64 size = os.stat(fp).st_size
65 f.seek(0)
66 afw.addfile(arfile.ArInfo.fromdefault(
67 fp[len(path)+1:], size), f)
68
69 progress.inc()
70
71 afw.close()
M-A Ruel 2016/06/16 14:57:05 try / finally?
mithro 2016/06/17 06:44:50 Done.
72
73
74 def list_cmd(filename, progress):
75 afr = arfile.ArFileReader(filename, fullparse=False)
76 for ai, _ in afr:
77 print(ai.name)
78 progress.inc()
79
80
81 def extract_cmd(
82 filename, progress, verbose=False, blocksize=1024*64):
83 afr = arfile.ArFileReader(filename, fullparse=False)
84 for ai, ifd in afr:
85 assert not ai.name.startswith('/')
86 if verbose:
87 print(ai.name, file=sys.stderr)
88
89 try:
90 os.makedirs(os.path.dirname(ai.name))
91 except OSError:
92 pass
93
94 with open(ai.name, 'wb') as ofd:
95 written = 0
96 while written < ai.size:
97 readsize = min(blocksize, ai.size-written)
98 ofd.write(ifd.read(readsize))
99 written += readsize
100
101 progress.inc()
102
103
104 def main(name, args):
105 parser = argparse.ArgumentParser(
106 prog=name,
107 description=sys.modules[__name__].__doc__)
108 subparsers = parser.add_subparsers(
109 dest='mode', help='sub-command help')
110
111 # Create command
112 parser_create = subparsers.add_parser(
113 'create', help='Create a new ar file')
114 parser_create.add_argument(
115 "-r", "--read-ahead",
116 type=int, default=1024*64,
117 help="Amount of data to read-ahead before doing a stat.")
118 parser_create.add_argument(
119 "-f", "--filename",
120 type=argparse.FileType('wb'), default=sys.stdout,
121 help="ar file to use")
122 parser_create.add_argument(
123 'dirs', nargs='+', help='Directory or file to add to the ar file')
124
125 # List command
126 parser_list = subparsers.add_parser('list', help='List a new ar file')
127
128 # Extract command
129 parser_extract = subparsers.add_parser(
130 'extract', help='Extract an existing ar file to current directory')
131
132 # Add to output commands
133 for p in parser_list, parser_extract:
134 p.add_argument(
135 "-f", "--filename",
136 type=argparse.FileType('rb'), default=sys.stdin,
137 help="ar file to use")
138
139 for p in parser_create, parser_extract:
M-A Ruel 2016/06/16 14:57:05 Please at it at global level instead, and use modu
mithro 2016/06/17 06:44:50 The idea behind verbose mode for create and extrac
M-A Ruel 2016/06/17 13:26:49 Ok I didn't realize you tried to mimic an existing
140 p.add_argument(
141 "-v", "--verbose",
142 action="store_true",
143 help='Output file names to stderr while running.')
144
145 # Add to all commands
146 for p in parser_create, parser_list, parser_extract:
147 p.add_argument(
148 "-p", "--progress",
149 type=ProgressReporter, default='10000',
150 help='Output progress information every N files.')
151
152 args = parser.parse_args(args)
153 mode = getattr(sys.modules[__name__], args.mode + '_cmd')
154 del args.mode
155 mode(**args.__dict__)
M-A Ruel 2016/06/16 14:57:05 return mode(**args.__dict__)
mithro 2016/06/17 06:44:50 Done.
156
157
158 if __name__ == "__main__":
159 main("artool", sys.argv[1:])
M-A Ruel 2016/06/16 14:57:05 sys.exit(main("artool", sys.argv[1:]))
mithro 2016/06/17 06:44:50 Done.
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698