357 This function returns a list of "email" tuples (subject, content, None). |
358 This function returns a list of "email" tuples (subject, content, None). |
358 The list is always one message long in that case. |
359 The list is always one message long in that case. |
359 """ |
360 """ |
360 ui = repo.ui |
361 ui = repo.ui |
361 _charsets = mail._charsets(ui) |
362 _charsets = mail._charsets(ui) |
362 subj = (opts.get('subject') |
363 subj = (opts.get(r'subject') |
363 or prompt(ui, 'Subject:', 'A bundle for your repository')) |
364 or prompt(ui, 'Subject:', 'A bundle for your repository')) |
364 |
365 |
365 body = _getdescription(repo, '', sender, **opts) |
366 body = _getdescription(repo, '', sender, **opts) |
366 msg = emailmod.MIMEMultipart.MIMEMultipart() |
367 msg = emailmod.MIMEMultipart.MIMEMultipart() |
367 if body: |
368 if body: |
368 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get('test'))) |
369 msg.attach(mail.mimeencode(ui, body, _charsets, opts.get(r'test'))) |
369 datapart = emailmod.MIMEBase.MIMEBase('application', 'x-mercurial-bundle') |
370 datapart = emailmod.MIMEBase.MIMEBase('application', 'x-mercurial-bundle') |
370 datapart.set_payload(bundle) |
371 datapart.set_payload(bundle) |
371 bundlename = '%s.hg' % opts.get('bundlename', 'bundle') |
372 bundlename = '%s.hg' % opts.get(r'bundlename', 'bundle') |
372 datapart.add_header('Content-Disposition', 'attachment', |
373 datapart.add_header('Content-Disposition', 'attachment', |
373 filename=bundlename) |
374 filename=bundlename) |
374 emailmod.Encoders.encode_base64(datapart) |
375 emailmod.Encoders.encode_base64(datapart) |
375 msg.attach(datapart) |
376 msg.attach(datapart) |
376 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get('test')) |
377 msg['Subject'] = mail.headencode(ui, subj, _charsets, opts.get(r'test')) |
377 return [(msg, subj, None)] |
378 return [(msg, subj, None)] |
378 |
379 |
379 def _makeintro(repo, sender, revs, patches, **opts): |
380 def _makeintro(repo, sender, revs, patches, **opts): |
380 """make an introduction email, asking the user for content if needed |
381 """make an introduction email, asking the user for content if needed |
381 |
382 |
382 email is returned as (subject, body, cumulative-diffstat)""" |
383 email is returned as (subject, body, cumulative-diffstat)""" |
383 ui = repo.ui |
384 ui = repo.ui |
384 _charsets = mail._charsets(ui) |
385 _charsets = mail._charsets(ui) |
385 |
386 |
386 # use the last revision which is likely to be a bookmarked head |
387 # use the last revision which is likely to be a bookmarked head |
387 prefix = _formatprefix(ui, repo, revs.last(), opts.get('flag'), |
388 prefix = _formatprefix(ui, repo, revs.last(), opts.get(r'flag'), |
388 0, len(patches), numbered=True) |
389 0, len(patches), numbered=True) |
389 subj = (opts.get('subject') or |
390 subj = (opts.get(r'subject') or |
390 prompt(ui, '(optional) Subject: ', rest=prefix, default='')) |
391 prompt(ui, '(optional) Subject: ', rest=prefix, default='')) |
391 if not subj: |
392 if not subj: |
392 return None # skip intro if the user doesn't bother |
393 return None # skip intro if the user doesn't bother |
393 |
394 |
394 subj = prefix + ' ' + subj |
395 subj = prefix + ' ' + subj |
395 |
396 |
396 body = '' |
397 body = '' |
397 if opts.get('diffstat'): |
398 if opts.get(r'diffstat'): |
398 # generate a cumulative diffstat of the whole patch series |
399 # generate a cumulative diffstat of the whole patch series |
399 diffstat = patch.diffstat(sum(patches, [])) |
400 diffstat = patch.diffstat(sum(patches, [])) |
400 body = '\n' + diffstat |
401 body = '\n' + diffstat |
401 else: |
402 else: |
402 diffstat = None |
403 diffstat = None |
403 |
404 |
404 body = _getdescription(repo, body, sender, **opts) |
405 body = _getdescription(repo, body, sender, **opts) |
405 msg = mail.mimeencode(ui, body, _charsets, opts.get('test')) |
406 msg = mail.mimeencode(ui, body, _charsets, opts.get(r'test')) |
406 msg['Subject'] = mail.headencode(ui, subj, _charsets, |
407 msg['Subject'] = mail.headencode(ui, subj, _charsets, |
407 opts.get('test')) |
408 opts.get(r'test')) |
408 return (msg, subj, diffstat) |
409 return (msg, subj, diffstat) |
409 |
410 |
410 def _getpatchmsgs(repo, sender, revs, patchnames=None, **opts): |
411 def _getpatchmsgs(repo, sender, revs, patchnames=None, **opts): |
411 """return a list of emails from a list of patches |
412 """return a list of emails from a list of patches |
412 |
413 |
413 This involves introduction message creation if necessary. |
414 This involves introduction message creation if necessary. |
414 |
415 |
415 This function returns a list of "email" tuples (subject, content, None). |
416 This function returns a list of "email" tuples (subject, content, None). |
416 """ |
417 """ |
|
418 bytesopts = pycompat.byteskwargs(opts) |
417 ui = repo.ui |
419 ui = repo.ui |
418 _charsets = mail._charsets(ui) |
420 _charsets = mail._charsets(ui) |
419 patches = list(_getpatches(repo, revs, **opts)) |
421 patches = list(_getpatches(repo, revs, **opts)) |
420 msgs = [] |
422 msgs = [] |
421 |
423 |
422 ui.write(_('this patch series consists of %d patches.\n\n') |
424 ui.write(_('this patch series consists of %d patches.\n\n') |
423 % len(patches)) |
425 % len(patches)) |
424 |
426 |
425 # build the intro message, or skip it if the user declines |
427 # build the intro message, or skip it if the user declines |
426 if introwanted(ui, opts, len(patches)): |
428 if introwanted(ui, bytesopts, len(patches)): |
427 msg = _makeintro(repo, sender, revs, patches, **opts) |
429 msg = _makeintro(repo, sender, revs, patches, **opts) |
428 if msg: |
430 if msg: |
429 msgs.append(msg) |
431 msgs.append(msg) |
430 |
432 |
431 # are we going to send more than one message? |
433 # are we going to send more than one message? |
670 sender = (opts.get('from') or ui.config('email', 'from') or |
673 sender = (opts.get('from') or ui.config('email', 'from') or |
671 ui.config('patchbomb', 'from') or |
674 ui.config('patchbomb', 'from') or |
672 prompt(ui, 'From', ui.username())) |
675 prompt(ui, 'From', ui.username())) |
673 |
676 |
674 if bundle: |
677 if bundle: |
675 bundledata = _getbundle(repo, dest, **opts) |
678 stropts = pycompat.strkwargs(opts) |
676 bundleopts = opts.copy() |
679 bundledata = _getbundle(repo, dest, **stropts) |
677 bundleopts.pop('bundle', None) # already processed |
680 bundleopts = stropts.copy() |
|
681 bundleopts.pop(r'bundle', None) # already processed |
678 msgs = _getbundlemsgs(repo, sender, bundledata, **bundleopts) |
682 msgs = _getbundlemsgs(repo, sender, bundledata, **bundleopts) |
679 else: |
683 else: |
680 msgs = _getpatchmsgs(repo, sender, revs, **opts) |
684 msgs = _getpatchmsgs(repo, sender, revs, **pycompat.strkwargs(opts)) |
681 |
685 |
682 showaddrs = [] |
686 showaddrs = [] |
683 |
687 |
684 def getaddrs(header, ask=False, default=None): |
688 def getaddrs(header, ask=False, default=None): |
685 configkey = header.lower() |
689 configkey = header.lower() |