2 # -*- coding: utf-8; -*-
4 # dput — Debian package upload tool.
5 # Part of Debian ‘dput’ package.
7 # Copyright © 2015 Ben Finney <ben+debian@benfinney.id.au>
8 # Copyright © 2008–2013 Y Giridhar Appaji Nag <appaji@debian.org>
9 # Copyright © 2006–2008 Thomas Viehmann <tv@beamnet.de>
10 # Copyright © 2000–2005 Christian Kurz <shorty@debian.org>
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License along
23 # with this program; if not, write to the Free Software Foundation, Inc.,
24 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 """ dput — Debian package upload tool. """
38 from hashlib import md5, sha1
42 # Now import our modules
45 app_library_path = "/usr/share/dput"
46 sys.path.insert(0, app_library_path)
47 from helper import dputhelper
50 dput_version = "dput 0.9.6"
55 simulate = unsigned_upload = delay_upload = 0
56 debug = dinstall = check_only = 0
60 def import_upload_functions():
61 """ Import files from the /usr/share/dput and make them available. """
62 package_name = "methods"
63 modules_path = os.path.join(app_library_path, package_name)
65 name for (__, name, ispkg) in
66 pkgutil.iter_modules([modules_path])
69 print "D: modules_found: %r" % modules_found
70 for module_name in modules_found:
71 module = importlib.import_module("{package}.{module}".format(
72 package=package_name, module=module_name))
74 print "D: Module: %s (%r)" % (module_name, module)
75 method_name = module_name
77 print "D: Method name: %s" % method_name
79 register_upload_function(method_name, module.upload)
82 def register_upload_function(name, function):
83 """ Add function to upload_methods dictionary using key of name. """
86 upload_methods[name] = function
89 def parse_changes(chg_fd):
90 """ Parse the changes file. """
91 check = chg_fd.read(5)
95 # found a PGP header, gonna ditch the next 3 lines
96 # eat the rest of the line
102 if not chg_fd.readline().find('Format') != -1:
104 changes = rfc822.Message(chg_fd)
105 for a in changes.dict['files'].split('\n'):
106 if len(a.split()) != 5:
107 sys.stderr.write("Invalid Files line in .changes:\n %s\n" % a)
112 def read_configs(extra_config, debug):
113 """ Read configuration settings from config files.
115 Read configs in this order:
116 * If specified on the command line, only read `extra_config`.
117 * Otherwise, read ‘/etc/dput.cf’ then ‘~/.dput.cf’.
118 The config parser will layer values.
123 config = ConfigParser.ConfigParser()
125 config.set('DEFAULT', 'login', 'username')
126 config.set('DEFAULT', 'method', 'scp')
127 config.set('DEFAULT', 'hash', 'md5')
128 config.set('DEFAULT', 'allow_unsigned_uploads', '0')
129 config.set('DEFAULT', 'allow_dcut', '0')
130 config.set('DEFAULT', 'distributions', '')
131 config.set('DEFAULT', 'allowed_distributions', '')
132 config.set('DEFAULT', 'run_lintian', '0')
133 config.set('DEFAULT', 'run_dinstall', '0')
134 config.set('DEFAULT', 'check_version', '0')
135 config.set('DEFAULT', 'scp_compress', '0')
136 config.set('DEFAULT', 'default_host_main', '')
137 config.set('DEFAULT', 'post_upload_command', '')
138 config.set('DEFAULT', 'pre_upload_command', '')
139 config.set('DEFAULT', 'ssh_config_options', '')
140 config.set('DEFAULT', 'passive_ftp', '1')
141 config.set('DEFAULT', 'progress_indicator', '0')
142 config.set('DEFAULT', 'delayed', '')
145 config_files = (extra_config,)
147 config_files = ('/etc/dput.cf', os.path.expanduser("~/.dput.cf"))
149 for config_file in config_files:
151 fd = open(config_file)
154 sys.stderr.write("%s: %s, skipping\n" % (e[1], config_file))
157 print "D: Parsing Configuration File %s" % config_file
160 except ConfigParser.ParsingError as e:
161 sys.stderr.write("Error parsing config file:\n%s\n" % str(e))
166 "Error: Could not open any configfile, tried %s\n"
167 % (', '.join(config_files)))
169 # only check for fqdn and incoming dir, rest have reasonable defaults
171 for section in config.sections():
172 if config.get(section, 'method') == 'local':
173 config.set(section, 'fqdn', 'localhost')
175 not config.has_option(section, 'fqdn') and
176 config.get(section, 'method') != 'local'):
178 "Config error: %s must have a fqdn set\n" % section)
180 if not config.has_option(section, 'incoming'):
182 "Config error: %s must have an incoming directory set\n"
189 hexStr = string.hexdigits
192 def hexify_string(string):
193 """ Convert a hex string into readable characters. """
196 char = char + hexStr[(ord(c) >> 4) & 0xF] + hexStr[ord(c) & 0xF]
200 def checksum_test(filename, hash):
201 """ Generate a checksum for a file.
203 Currently supports md5, sha1. ripemd may come in the future.
207 file_to_test = open(filename, 'r')
209 print "Can't open %s" % filename
217 check_obj = hash_type()
220 data = file_to_test.read(65536)
223 check_obj.update(data)
226 checksum = hexify_string(check_obj.digest())
231 def check_signature(filename):
232 """ Verify the GnuPG signature on a file. """
233 if os.access(filename, os.R_OK):
234 if os.access("/usr/bin/gpg", os.X_OK):
236 "/usr/bin/gpg --status-fd 1 --verify --batch %s"
238 if stream.count('[GNUPG:] GOODSIG'):
239 print "Good signature on %s." % filename
240 elif stream.count('[GNUPG:] BADSIG'):
241 print "Bad signature on %s." % filename
243 elif stream.count('[GNUPG:] ERRSIG'):
244 print "Error verifying signature on %s." % filename
246 elif stream.count('[GNUPG:] NODATA'):
247 print "No signature on %s." % filename
250 print "Error in finding signature verification status."
252 print "Can't verify signature on %s without GnuPG" % filename
253 print "If you are still using PGP, please read this:"
254 print "http://www.gnupg.org/gph/en/pgp2x.html"
257 print "Can't read %s" % filename
261 def check_upload_variant(changes, debug):
262 """ Check if this is a binary_upload only or not. """
264 if 'architecture' in changes.dict:
265 arch = changes.dict['architecture']
267 print "D: Architecture: %s" % arch
268 if arch.find('source') < 0:
270 print "D: Doing a binary upload only."
275 def verify_signature(
276 host, changes_file, dsc_file, check_only, debug,
277 unsigned_upload, binary_upload):
278 """ Check the signature on the two files given via function call. """
281 print "D: .changes-File: %s" % changes_file
282 print "D: .dsc-File: %s" % dsc_file
283 if ((check_only or config.getboolean(host, 'allow_unsigned_uploads') == 0)
284 and unsigned_upload == 0):
285 print "Checking signature on .changes"
286 check_signature(changes_file)
287 if not binary_upload:
288 print "Checking signature on .dsc"
289 check_signature(dsc_file)
292 def source_check(changes, debug):
293 """ Check if a source tarball has to be included in the package or not. """
294 include_orig = include_tar = 0
295 if 'version' in changes.dict:
296 version = changes.dict['version']
298 print "D: Package Version: %s" % version
299 # versions with a dash in them are for non-native only
300 if version.find('-') == -1:
304 if version.find(':') > 0:
306 print "D: Epoch found"
307 epoch, version = version.split(':', 1)
308 pos = version.rfind('-')
309 upstream_version = version[0:pos]
310 debian_version = version[pos + 1:]
312 print "D: Upstream Version: %s" % upstream_version
313 print "D: Debian Version: %s" % debian_version
315 debian_version == '0.1' or debian_version == '1'
316 or debian_version == '1.1'):
320 return (include_orig, include_tar)
324 path, filename, host, check_only, check_version,
325 unsigned_upload, debug):
326 """ Run some tests on the files to verify that they are in good shape. """
328 file_seen = include_orig_tar_gz = include_tar_gz = binary_only = 0
330 name_of_file = filename
332 change_file = os.path.join(path, name_of_file)
335 print "D: Validating contents of changes file %s" % change_file
337 chg_fd = open(change_file, 'r')
339 print "Can't open %s" % change_file
341 changes = parse_changes(chg_fd)
344 # Find out if it's a binary only upload or not
345 binary_upload = check_upload_variant(changes, debug)
351 for file in changes.dict['files'].split('\n'):
353 filename = string.split(file)[4]
354 if filename.find('.dsc') != -1:
356 print "D: dsc-File: %s" % filename
357 dsc_file = os.path.join(path, filename)
359 sys.stderr.write("Error: no dsc file found in sourceful upload\n")
362 # Run the check to verify that the package has been tested.
364 if config.getboolean(host, 'check_version') == 1 or check_version:
365 version_check(path, changes, debug)
366 except ConfigParser.NoSectionError as e:
367 sys.stderr.write("Error in config file:\n%s\n" % str(e))
370 # Verify the signature of the maintainer
372 host, change_file, dsc_file, check_only, debug,
373 unsigned_upload, binary_upload)
376 (include_orig_tar_gz, include_tar_gz) = source_check(changes, debug)
378 # Check md5sum and the size
379 file_list = changes.dict['files'].split('\n')
380 hash_to_use = config.get('DEFAULT', 'hash')
381 for line in file_list:
382 (check_sum, size, section, priority, file) = line.split()
383 file_to_upload = os.path.join(path, file)
385 print "D: File to upload: %s" % file_to_upload
386 if checksum_test(file_to_upload, hash_to_use) != check_sum:
388 print "D: Checksum from .changes: %s" % check_sum
390 "D: Generated Checksum: %s" %
391 checksum_test(file_to_upload, hash_to_use))
392 print "Checksum doesn't match for %s" % file_to_upload
396 print "D: Checksum for %s is fine" % file_to_upload
397 if os.stat(file_to_upload)[stat.ST_SIZE] != int(size):
399 print "D: size from .changes: %s" % size
401 "D: calculated size: %s" %
402 os.stat(file_to_upload)[stat.ST_SIZE])
403 print "size doesn't match for %s" % file_to_upload
405 files_to_upload.append(file_to_upload)
408 for file in files_to_upload:
409 if file[-12:] == '.orig.tar.gz' and not include_orig_tar_gz:
411 print "D: Filename: %s" % file
412 print "D: Suffix: %s" % file[-12:]
414 "Package includes an .orig.tar.gz file although"
415 " the debian revision suggests")
417 "that it might not be required."
418 " Multiple uploads of the .orig.tar.gz may be")
419 print "rejected by the upload queue management software."
421 file[-7:] == '.tar.gz' and not include_tar_gz
422 and not include_orig_tar_gz):
424 print "D: Filename: %s" % file
425 print "D: Suffix: %s" % file[-7:]
427 "Package includes a .tar.gz file although"
428 " the version suggests that it might")
431 " Multiple uploads of the .tar.gz may be rejected by the")
432 print "upload queue management software."
434 distribution = changes.get('distribution')
435 allowed_distributions = config.get(host, 'allowed_distributions')
436 if distribution and allowed_distributions:
439 "D: Checking: distribution %s matches %s"
440 % (distribution, allowed_distributions))
441 if not re.match(allowed_distributions, distribution):
442 raise dputhelper.DputUploadFatalException(
443 "Error: uploading files for distribution %s to %s"
445 % (distribution, host))
448 print "D: File to upload: %s" % change_file
449 files_to_upload.append(change_file)
452 def print_config(config, debug):
453 """ Print the configuration and exit. """
455 config.write(sys.stdout)
459 def create_upload_file(package, host, path, files_to_upload, debug):
460 """ Write a logfile of the upload and call it ‘.upload’. """
462 # only need first part
463 base = os.path.splitext(package)[0]
464 logfile_name = os.path.join(path, base + '.' + host + '.upload')
465 if config.get(host, 'method') == 'local':
468 fqdn = config.get(host, 'fqdn')
470 print "D: Writing logfile: %s" % logfile_name
472 if os.access(logfile_name, os.R_OK):
473 logfile_fd = open(logfile_name, 'a')
475 logfile_fd = open(logfile_name, 'w')
477 sys.stderr.write("Could not write %s\n" % logfile_name)
480 for file in files_to_upload:
481 entry_for_logfile = (
482 'Successfully uploaded ' + os.path.basename(file) +
483 ' to ' + fqdn + ' for ' + host + '.\n')
484 logfile_fd.write(entry_for_logfile)
488 def run_lintian_test(changes_file):
489 """ Run lintian on the changes file and stop if it finds errors. """
491 if os.access(changes_file, os.R_OK):
492 if os.access("/usr/bin/lintian", os.R_OK):
493 old_signal = signal.signal(signal.SIGPIPE, signal.SIG_DFL)
494 print "Package is now being checked with lintian."
495 if dputhelper.spawnv(
496 os.P_WAIT, "/usr/bin/lintian",
497 ['lintian', '-i', changes_file]):
500 "Lintian says this package is not compliant" +
501 " with the current policy.")
502 print "Please check the current policy and your package."
503 print "Also see lintian documentation about overrides."
506 signal.signal(signal.SIGPIPE, old_signal)
509 print "lintian is not installed, skipping package test."
511 print "Can't read %s" % changes_file
515 def guess_upload_host(path, filename):
516 """ Guess the host where the package should be uploaded to.
518 This is based on information from the changes file.
523 dist_re = re.compile(r'^Distribution: (.*)')
525 name_of_file = filename
526 changes_file = os.path.join(path, name_of_file)
529 changes_file_fd = open(changes_file, 'r')
531 print "Can't open %s" % changes_file
533 lines = changes_file_fd.readlines()
535 match = dist_re.search(line)
537 distribution = match.group(1)
539 # Try to guess a host based on the Distribution: field
541 for section in config.sections():
542 host_dists = config.get(section, 'distributions')
545 for host_dist in host_dists.split(','):
546 if distribution == host_dist.strip():
549 "D: guessing host %s based on distribution %s"
550 % (section, host_dist))
553 if len(config.get('DEFAULT', 'default_host_main')) != 0:
554 print "Trying to upload package to %s" % config.get(
555 'DEFAULT', 'default_host_main')
556 return config.get('DEFAULT', 'default_host_main')
558 print "Trying to upload package to ftp-master (ftp.upload.debian.org)"
562 def dinstall_caller(filename, host, login, incoming, debug):
563 """ Run dinstall in test-mode and present the output to the user.
565 This is so the user can see if the package would be installed
570 'ssh', '%s@%s' % (login, config.get(host, 'fqdn')),
571 'cd', '%s' % incoming,
572 ';', 'dinstall', '-n', '%s' % filename]
574 print "D: Logging into %s@%s:%s" % (login, host, incoming)
575 print "D: dinstall -n %s" % filename
576 if config.getboolean(host, 'run_dinstall') == 1 or dinstall:
577 if dputhelper.spawnv(os.P_WAIT, '/usr/bin/ssh', command):
579 "Error occured while trying to connect, or while " +
580 "attempting to run dinstall.")
584 def version_check(path, changes, debug):
585 """ Check if the caller has installed the package also on his system.
587 This is for testing purposes before uploading it. If not, we
594 (dpkg_stdin, dpkg_stdout, dpkg_stderr) = os.popen3(
595 'dpkg --print-architecture')
597 dpkg_architecture = dpkg_stdout.read().strip()
599 dpkg_stderr_output = dpkg_stderr.read()
601 if debug and dpkg_stderr_output:
602 print "D: dpkg-architecture stderr output:", repr(dpkg_stderr_output)
604 print "D: detected architecture: '%s'" % dpkg_architecture
606 # Get filenames of deb files:
607 for file in changes.dict['files'].split('\n'):
608 filename = os.path.join(path, string.split(file)[4])
609 if filename.endswith('.deb'):
611 print "D: Debian Package: %s" % filename
612 (dpkg_stdin, dpkg_stdout, dpkg_stderr) = os.popen3(
613 'dpkg --field %s' % filename)
615 dpkg_output = rfc822.Message(dpkg_stdout)
617 dpkg_stderr_output = dpkg_stderr.read()
619 if debug and dpkg_stderr_output:
620 print "D: dpkg stderr output:", repr(dpkg_stderr_output)
623 and dpkg_output['architecture'] not in [
624 'all', dpkg_architecture]):
627 "D: not install-checking %s due to arch mismatch"
630 package_name = dpkg_output['package']
631 version_number = dpkg_output['version']
633 print "D: Package to Check: %s" % package_name
635 print "D: Version to Check: %s" % version_number
636 files_to_check.append((package_name, version_number))
638 for file, version_to_check in files_to_check:
640 print "D: Name of Package: %s" % file
641 dpkg_stdin, dpkg_stdout, dpkg_stderr = os.popen3('dpkg -s %s' % file)
643 dpkg_output = rfc822.Message(dpkg_stdout)
645 dpkg_stderr_output = dpkg_stderr.read()
647 if debug and dpkg_stderr_output:
648 print "D: dpkg stderr output:", repr(dpkg_stderr_output)
649 if 'version' in dpkg_output:
650 installed_version = dpkg_output.dict['version']
652 print "D: Installed-Version: %s" % installed_version
655 "D: Check-Version: %s" % version_to_check)
656 if installed_version != version_to_check:
658 "Package to upload is not installed, but it appears " +
659 "you have an older version installed.")
661 print "Uninstalled Package. Test it before uploading it."
665 def execute_command(host, debug, type):
666 """ Run a command that the user-defined in the config_file. """
668 lookup_command = type + '_upload_command'
670 print "D: Command: %s" % config.get(host, lookup_command)
671 if os.system(config.get(host, lookup_command)):
672 raise dputhelper.DputUploadFatalException(
673 "Error: %s upload command failed." % type)
676 def check_upload_logfile(
677 changes_file, host, check_only,
678 call_lintian, force_upload, debug):
679 """ Check if the user already put this package on the specified host. """
682 upload_logfile = changes_file[:-8] + '.' + host + '.upload'
683 if not check_only and not force_upload:
684 if not os.path.exists(upload_logfile):
687 fd_logfile = open(upload_logfile)
689 print "Couldn't open %s" % upload_logfile
691 for line in fd_logfile.readlines():
692 if config.get(host, 'method') == 'local':
695 fqdn = config.get(host, 'fqdn')
696 if line.find(fqdn) != -1:
700 "Package has already been uploaded to %s on %s"
702 print "Nothing more to do for %s" % changes_file
705 # Help Message to print
706 USAGE = """Usage: dput [options] [host] <package(s).changes>
707 Supported options (see man page for long forms):
708 -c: Config file to parse.
709 -d: Enable debug messages.
710 -D: Run dinstall after upload.
711 -e: Upload to a delayed queue. Takes an argument from 0 to 15.
713 -h: Display this help message.
714 -H: Display a list of hosts from the config file.
715 -l: Run lintian before upload.
716 -U: Do not write a .upload file after uploading.
717 -o: Only check the package.
718 -p: Print the configuration.
719 -P: Use passive mode for ftp uploads.
720 -s: Simulate the upload only.
721 -u: Don't check GnuPG signature.
722 -v: Display version information.
723 -V: Check the package version and then upload it.
728 """ Main function, no further comment needed. :) """
734 global unsigned_upload
738 check_version = config_print = force_upload = 0
739 call_lintian = no_upload_log = config_host_list = 0
743 # Parse Command Line Options.
744 (opts, args) = dputhelper.getopt(
746 'c:dDe:fhHlUopPsuvV', [
747 'debug', 'dinstall', 'check-only',
748 'check-version', 'config=', 'force', 'help',
749 'host-list', 'lintian', 'no-upload-log',
750 'passive', 'print', 'simulate', 'unchecked',
751 'delayed=', 'version'])
752 for option, arg in opts:
753 if option in ('-h', '--help'):
756 elif option in ('-v', '--version'):
759 elif option in ('-d', '--debug'):
761 elif option in ('-D', '--dinstall'):
763 elif option in ('-c', '--config'):
765 elif option in ('-f', '--force'):
767 elif option in ('-H', '--host-list'):
769 elif option in ('-l', '--lintian'):
771 elif option in ('-U', '--no-upload-log'):
773 elif option in ('-o', '--check-only'):
775 elif option in ('-p', '--print'):
777 elif option in ('-P', '--passive'):
779 elif option in ('-s', '--simulate'):
781 elif option in ('-u', '--unchecked'):
783 elif option in ('-e', '--delayed'):
784 if arg in map(str, range(16)):
788 "Incorrect delayed argument,"
789 " dput only understands 0 to 15.")
791 elif option in ('-V', '--check_version'):
794 # Always print the version number in the debug output
795 # so that in case of bugreports, we know which version
796 # the user has installed
798 print "D: %s" % dput_version
800 # Try to get the login from the enviroment
801 if 'USER' in os.environ:
802 login = os.environ['USER']
804 print "D: Login: %s" % login
806 print "$USER not set, will use login information."
807 # Else use the current username
808 login = pwd.getpwuid(os.getuid())[0]
810 print "D: User-ID: %s" % os.getuid()
811 print "D: Login: %s" % login
813 # Start Config File Parsing.
814 read_configs(config_file, debug)
817 print_config(config, debug)
822 print "Default Method: %s" % config.get('DEFAULT', 'method')
824 for section in config.sections():
826 if config.get(section, 'distributions'):
828 ", distributions: %s" %
829 config.get(section, 'distributions'))
830 print "%s => %s (Upload method: %s%s)" % (
832 config.get(section, 'fqdn'), config.get(section, 'method'),
837 # Process further command line options.
839 print "No package or host has been provided, see dput -h"
841 elif len(args) == 1 and not check_only:
842 package_to_upload = args[0:]
846 print "D: Checking if a host was named on the command line."
847 if config.has_section(args[0]):
849 print "D: Host %s found in config" % args[0]
850 # Host was also named, so only the rest will be a list
851 # of packages to upload.
852 preferred_host = args[0]
853 package_to_upload = args[1:]
855 not config.has_section(args[0])
856 and not args[0].endswith('.changes')):
857 sys.stderr.write("No host %s found in config\n" % args[0])
858 if args[0] == 'gluck_delayed':
860 The delayed upload queue has been moved back to
861 ftp-master (aka ftp.upload.debian.org).
866 print "D: No host named on command line."
867 # Only packages have been named on the command line.
869 package_to_upload = args[0:]
872 print "D: Checking for the package name."
873 if config.has_section(args[0]):
874 print "D: Host %s found in config." % args[0]
875 preferred_host = args[0]
876 package_to_upload = args[1:]
877 elif not config.has_section(args[0]):
878 print "D: No host %s found in config" % args[0]
879 package_to_upload = args[0:]
881 # Now Import the Upload functions
882 import_upload_functions()
884 # Run the same checks for all packages that have been given on
886 for package_name in package_to_upload:
887 # Check that a .changes file was given on the command line
888 # and no matching .upload file exists.
889 if package_name[-8:] != '.changes':
890 print "Not a .changes file."
891 print "Please select a .changes file to upload."
892 print "Tried to upload: %s" % package_name
894 files_to_upload[:] = []
896 # Construct the package name for further usage.
897 path, name_of_package = os.path.split(package_name)
901 # Define the host to upload to.
902 if preferred_host == '':
903 host = guess_upload_host(path, name_of_package)
905 host = preferred_host
907 # Check if we already did this upload or not
908 check_upload_logfile(
909 package_name, host, check_only,
910 call_lintian, force_upload, debug)
912 # Run the change file tests.
914 path, name_of_package, host, check_only, check_version,
915 unsigned_upload, debug)
917 # Run the lintian test if the user asked us to do so.
920 config.getboolean(host, 'run_lintian') == 1):
921 run_lintian_test(os.path.join(path, name_of_package))
923 print "Warning: The option -o does not automatically include "
924 print "a lintian run any more. Please use the option -ol if "
925 print "you want to include running lintian in your checking."
927 # don't upload, skip to the next item
929 print "Package checked by dput."
932 # Pre-Upload Commands
933 if len(config.get(host, 'pre_upload_command')) != 0:
935 execute_command(host, debug, type)
937 # Check the upload methods that we have as default and per host
940 "D: Default Method: %s" %
941 config.get('DEFAULT', 'method'))
942 if config.get('DEFAULT', 'method') not in upload_methods:
944 "Unknown upload method: %s" %
945 config.get('DEFAULT', 'method'))
948 print "D: Host Method: %s" % config.get(host, 'method')
949 if config.get(host, 'method') not in upload_methods:
950 print "Unknown upload method: %s" % config.get(host, 'method')
953 # Inspect the Config and set appropriate upload method
954 if not config.get(host, 'method'):
955 method = config.get('DEFAULT', 'method')
957 method = config.get(host, 'method')
959 # Check now the login and redefine it if needed
961 len(config.get(host, 'login')) != 0 and
962 config.get(host, 'login') != 'username'):
963 login = config.get(host, 'login')
965 print "D: Login %s from section %s used" % (login, host)
967 len(config.get('DEFAULT', 'login')) != 0 and
968 config.get('DEFAULT', 'login') != 'username'):
969 login = config.get('DEFAULT', 'login')
971 print "D: Default login %s used" % login
975 "D: Neither host %s nor default login used. Using %s"
978 # Messy, yes. But it isn't referenced by the upload method anyway.
979 if config.get(host, 'method') == 'local':
982 fqdn = config.get(host, 'fqdn')
983 incoming = config.get(host, 'incoming')
985 # if delay_upload wasn't passed via -e/--delayed
987 delay_upload = config.get(host, 'delayed')
989 delay_upload = config.get('DEFAULT', 'delayed')
992 if int(delay_upload) == 0:
993 print "Uploading to DELAYED/0-day."
994 if incoming[-1] == '/':
998 incoming += first_char + 'DELAYED/' + delay_upload + '-day'
999 delayed = ' [DELAYED/' + delay_upload + ']'
1003 # Do the actual upload
1006 "Uploading to %s%s (via %s to %s):"
1007 % (host, delayed, method, fqdn))
1009 print "D: FQDN: %s" % fqdn
1010 print "D: Login: %s" % login
1011 print "D: Incoming: %s" % incoming
1012 progress = config.getint(host, 'progress_indicator')
1013 if not os.isatty(1):
1017 fqdn, port = fqdn.rsplit(":", 1)
1020 ftp_mode = config.getboolean(host, 'passive_ftp')
1021 if ftp_passive_mode == 1:
1024 print "D: FTP port: %s" % port
1026 print "D: Using passive ftp"
1028 print "D: Using active ftp"
1029 upload_methods[method](
1030 fqdn, login, incoming,
1031 files_to_upload, debug, ftp_mode,
1032 progress=progress, port=port)
1033 elif method == 'scp':
1034 if debug and config.getboolean(host, 'scp_compress'):
1035 print "D: Setting compression for scp"
1036 scp_compress = config.getboolean(host, 'scp_compress')
1037 ssh_config_options = [
1040 config.get(host, 'ssh_config_options').split('\n'))
1044 "D: ssh config options:\n "
1045 + '\n '.join(ssh_config_options))
1046 upload_methods[method](
1047 fqdn, login, incoming,
1048 files_to_upload, debug, scp_compress,
1051 upload_methods[method](
1052 fqdn, login, incoming,
1053 files_to_upload, debug, 0, progress=progress)
1054 # Or just simulate it.
1056 for file in files_to_upload:
1057 print 'Uploading with %s: %s to %s:%s' % (
1058 method, file, fqdn, incoming)
1060 # Create the logfile after the package has
1061 # been put into the archive.
1063 if not no_upload_log:
1065 name_of_package, host, path,
1066 files_to_upload, debug)
1067 print "Successfully uploaded packages."
1069 print "Simulated upload."
1071 # Run dinstall if the user asked us to do so.
1073 print "D: dinstall: %s" % dinstall
1075 "D: Host Config: %s"
1076 % config.getboolean(host, 'run_dinstall'))
1077 if config.getboolean(host, 'run_dinstall') == 1 or dinstall:
1079 dinstall_caller(name_of_package, host, login, incoming, debug)
1081 print "Will run dinstall now."
1083 # Post-Upload Command
1084 if len(config.get(host, 'post_upload_command')) != 0:
1086 execute_command(host, debug, type)
1091 if __name__ == '__main__':
1094 except KeyboardInterrupt:
1095 print "Exiting due to user interrupt."
1097 except dputhelper.DputException as e:
1098 sys.stderr.write("%s\n" % e)
1106 # vim: fileencoding=utf-8 filetype=python :