1 # -*- coding: utf-8; -*-
3 # dput/helper/dputhelper.py
4 # Part of ‘dput’, a Debian package upload toolkit.
6 # This is free software, and you are welcome to redistribute it under
7 # certain conditions; see the end of this file for copyright
8 # information, grant of license, and disclaimer of warranty.
10 """ Helper code for Dput. """
22 class DputException(Exception):
26 class DputUploadFatalException(DputException
):
30 EXIT_STATUS_SUCCESS
= 0
31 EXIT_STATUS_FAILURE
= 1
32 EXIT_STATUS_COMMAND_NOT_FOUND
= 127
35 # This wrapper is intended as a migration target for the prior
36 # `spawnv` wrapper, and will produce the same output for now.
37 def check_call(args
, *posargs
, **kwargs
):
38 """ Wrap `subprocess.check_call` with error output. """
39 command_file_path
= args
[0]
41 subprocess
.check_call(args
, *posargs
, **kwargs
)
42 exit_status
= EXIT_STATUS_SUCCESS
43 except subprocess
.CalledProcessError
as exc
:
44 exit_status
= exc
.returncode
45 if exit_status
== EXIT_STATUS_COMMAND_NOT_FOUND
:
47 "Error: Failed to execute '{path}'.\n"
49 "The file may not exist or not be executable.\n".format(
50 path
=command_file_path
))
53 "Warning: The execution of '{path}' as\n"
55 " returned a nonzero exit code.\n".format(
56 path
=command_file_path
, command
=" ".join(args
)))
62 def __init__(self
, f
):
66 def __getattr__(self
, name
):
67 return getattr(self
.f
, name
)
71 idx
= self
.buf
.find('\n')
73 self
.f
.write(str(time
.time()) + ': ' + self
.buf
[:idx
+ 1])
74 self
.buf
= self
.buf
[idx
+ 1:]
75 idx
= self
.buf
.find('\n')
79 self
.f
.write(str(time
.time()) + ': ' + self
.buf
)
84 class FileWithProgress
:
85 """ Mimics a file (passed as f, an open file), but with progress.
87 FileWithProgress(f, args)
90 * ptype = 1,2 is the type ("|/-\" or numeric), default 0 (no progress)
91 * progressf = file to output progress to (default sys.stdout)
92 * size = size of file (or -1, the default, to ignore)
94 * step = stepsize (default 1024)
98 def __init__(self
, f
, ptype
=0, progressf
=sys
.stdout
, size
=-1, step
=1024):
104 self
.progresschars
= ['|', '/', '-', '\\']
105 self
.progressf
= progressf
110 def __getattr__(self
, name
):
111 return getattr(self
.f
, name
)
113 def read(self
, size
=-1):
114 a
= self
.f
.read(size
)
115 self
.count
= self
.count
+ len(a
)
116 if (self
.count
- self
.lastupdate
) > 1024:
118 self
.ppos
= (self
.ppos
+ 1) % len(self
.progresschars
)
119 self
.progressf
.write(
120 (self
.lastupdate
!= 0) * "\b" +
121 self
.progresschars
[self
.ppos
])
122 self
.progressf
.flush()
123 self
.lastupdate
= self
.count
124 elif self
.ptype
== 2:
125 s
= str(self
.count
// self
.step
) + "k"
128 '/' + str((self
.size
+ self
.step
- 1) // self
.step
)
130 s
+= min(self
.ppos
- len(s
), 0) * ' '
131 self
.progressf
.write(self
.ppos
* "\b" + s
)
132 self
.progressf
.flush()
142 self
.progressf
.write("\b \b")
143 self
.progressf
.flush()
144 elif self
.ptype
== 2:
145 self
.progressf
.write(
146 self
.ppos
* "\b" + self
.ppos
* " " + self
.ppos
* "\b")
147 self
.progressf
.flush()
153 def make_text_stream(stream
):
154 """ Make a text stream from the specified stream.
156 :param stream: An open file-like object.
157 :return: A stream object providing text I/O.
159 In the normal case, the specified stream is a stream providing
160 bytes I/O. We create an `io.TextIOWrapper` with the
161 appropriate encoding for the byte stream, and return that
164 The text encoding is determined by interrogating the file
165 object. If the file object has no declared encoding, the
166 default `locale.getpreferredencoding(False)` is used.
168 If the stream is a `io.TextIOBase` instance, it is already
169 providing text I/O. In this case, the stream is returned as
175 if hasattr(stream
, 'encoding'):
176 encoding
= stream
.encoding
178 encoding
= locale
.getpreferredencoding(False)
181 if sys
.version_info
>= (3, 0):
182 # We will never match an instance of this type, since it is
183 # not implemented in this Python version.
184 file = type(NotImplemented)
186 if isinstance(stream
, file):
187 # Python 2 `file` type doesn't work with the `io` types. Open
188 # the file again with a type we can use.
189 if stream
.mode
.endswith('b'):
190 text_mode
= stream
.mode
[:-1]
192 text_mode
= stream
.mode
193 fileno
= os
.dup(stream
.fileno())
194 result
= io
.open(fileno
, mode
=text_mode
, encoding
=encoding
)
195 elif isinstance(stream
, io
.TextIOBase
):
198 result
= io
.TextIOWrapper(stream
, encoding
=encoding
)
203 def get_progname(argv
=None):
204 """ Get the program name from the command line arguments.
206 :param argv: Sequence of command-line arguments.
207 Defaults to `sys.argv`.
208 :return: The program name used to invoke this program.
213 progname
= os
.path
.basename(argv
[0])
217 def get_distribution_version():
218 """ Get the version string for this distribution. """
219 distribution
= pkg_resources
.get_distribution("dput")
220 return distribution
.version
223 def getopt(args
, shortopts
, longopts
):
226 while args
and args
[0].startswith('-'):
232 if args
[0].startswith('--'):
233 opt
= args
.pop(0)[2:]
235 opt
, optarg
= opt
.split('=', 1)
238 prefixmatch
= [x
for x
in longopts
if x
.startswith(opt
)]
239 if len(prefixmatch
) == 0:
240 raise DputException('unknown option --%s' % opt
)
241 elif len(prefixmatch
) > 1:
242 raise DputException('non-unique prefix --%s' % opt
)
244 if opt
.endswith('=='):
246 optarg
= optarg
or ''
247 elif opt
.endswith('='):
252 'option --%s requires argument' % opt
)
255 if optarg
is not None:
257 'option --%s does not take arguments' % opt
)
259 optlist
.append(('--' + opt
, optarg
))
263 pos
= shortopts
.find(s
[0])
265 raise DputException('option -%s unknown' % s
[0])
266 if pos
+ 1 >= len(shortopts
) or shortopts
[pos
+ 1] != ':':
267 optlist
.append(('-' + s
[0], ''))
270 optlist
.append(('-' + s
[0], s
[1:]))
273 optlist
.append(('-' + s
, args
.pop(0)))
276 raise DputException('option -%s requires argument' % s
)
280 if __name__
== '__main__':
281 file_name
= "dput.py"
282 file_path
= os
.path
.join(os
.path
.dirname(__file__
), os
.pardir
, file_name
)
283 file_size
= os
.stat(file_path
).st_size
284 for i
in range(1, 3):
285 sys
.stdout
.write("Reading %s " % file_name
)
287 a
= FileWithProgress(open(file_path
), ptype
=i
, size
=file_size
)
296 # Copyright © 2015–2016 Ben Finney <bignose@debian.org>
297 # Copyright © 2009–2010 Y Giridhar Appaji Nag <appaji@debian.org>
298 # Copyright © 2007–2008 Thomas Viehmann <tv@beamnet.de>
300 # This is free software: you may copy, modify, and/or distribute this work
301 # under the terms of the GNU General Public License as published by the
302 # Free Software Foundation; version 2 of that license or any later version.
303 # No warranty expressed or implied. See the file ‘LICENSE.GPL-2’ for details.
310 # vim: fileencoding=utf-8 filetype=python :