1"""zest.releaser entry points to support projects using distutils2-like
2setup.cfg files.  The only actual functionality this adds is to update the
3version option in a setup.cfg file, if it exists.  If setup.cfg does not exist,
4or does not contain a version option, then this does nothing.
5
6TODO: d2to1 theoretically supports using a different filename for setup.cfg;
7this does not support that.  We could hack in support, though I'm not sure how
8useful the original functionality is to begin with (and it might be removed) so
9we ignore that for now.
10
11TODO: There exists a proposal
12(http://mail.python.org/pipermail/distutils-sig/2011-March/017628.html) to add
13a 'version-from-file' option (or something of the like) to distutils2; if this
14is added then support for it should be included here as well.
15"""
16
17
18import logging
19import os
20
21from .extern.six import print_
22from .extern.six import moves as m
23ConfigParser = m.configparser.ConfigParser
24
25
26logger = logging.getLogger(__name__)
27
28
29def prereleaser_before(data):
30    # This monkey-patches the BaseVersionControl system class to support
31    # getting and setting a version string from the setup.cfg file
32    from zest.releaser.vcs import BaseVersionControl
33
34    orig_extract_version = BaseVersionControl._extract_version
35    orig_update_version = BaseVersionControl._update_version
36
37    def _extract_version(self):
38        return get_setupcfg_version() or orig_extract_version(self)
39
40    def _update_version(self, version):
41        if get_setupcfg_version():
42            update_setupcfg_version(version)
43            return
44
45        return orig_update_version(self, version)
46
47    BaseVersionControl._extract_version = _extract_version
48    BaseVersionControl._update_version = _update_version
49    BaseVersionControl.version = property(_extract_version, _update_version)
50
51
52def get_setupcfg_version():
53    from zest.releaser.pypi import SetupConfig
54
55    setup_cfg = SetupConfig()
56
57    if setup_cfg.config.has_option('metadata', 'version'):
58        return setup_cfg.config.get('metadata', 'version').strip()
59
60    return ''
61
62
63def update_setupcfg_version(version):
64    """Opens the given setup.cfg file, locates the version option in the
65    [metadata] section, updates it to the new version.
66    """
67
68    from zest.releaser.pypi import SetupConfig
69
70    setup_cfg = SetupConfig()
71    filename = setup_cfg.config_filename
72    setup_cfg_lines = open(filename).readlines()
73    current_section = None
74    updated = False
75
76    for idx, line in enumerate(setup_cfg_lines):
77        m = ConfigParser.SECTCRE.match(line)
78        if m:
79            if current_section == 'metadata':
80                # We already parsed the entire metadata section without finding
81                # a version line, and are now moving into a new section
82                break
83            current_section = m.group('header')
84            continue
85
86        if '=' not in line:
87            continue
88
89        opt, val = line.split('=', 1)
90        opt, val = opt.strip(), val.strip()
91        if current_section == 'metadata' and opt == 'version':
92            setup_cfg_lines[idx] = 'version = %s\n' % version
93            updated = True
94            break
95
96    if updated:
97        open(filename, 'w').writelines(setup_cfg_lines)
98        logger.info("Set %s's version to %r" % (os.path.basename(filename),
99                                                version))
100
101
102def releaser_middle(data):
103    """
104    releaser.middle hook to monkey-patch zest.releaser to support signed
105    tagging--currently this is the only way to do this.  Also monkey-patches to
106    disable an annoyance where zest.releaser only creates .zip source
107    distributions.  This is supposedly a workaround for a bug in Python 2.4,
108    but we don't care about Python 2.4.
109    """
110
111    import os
112    import sys
113
114    from zest.releaser.git import Git
115    from zest.releaser.release import Releaser
116
117    # Copied verbatim from zest.releaser, but with the cmd string modified to
118    # use the -s option to create a signed tag
119    def _my_create_tag(self, version):
120        msg = "Tagging %s" % (version,)
121        cmd = 'git tag -s %s -m "%s"' % (version, msg)
122        if os.path.isdir('.git/svn'):
123            print_("\nEXPERIMENTAL support for git-svn tagging!\n")
124            cur_branch = open('.git/HEAD').read().strip().split('/')[-1]
125            print_("You are on branch %s." % (cur_branch,))
126            if cur_branch != 'master':
127                print_("Only the master branch is supported for git-svn "
128                       "tagging.")
129                print_("Please tag yourself.")
130                print_("'git tag' needs to list tag named %s." % (version,))
131                sys.exit()
132            cmd = [cmd]
133            local_head = open('.git/refs/heads/master').read()
134            trunk = open('.git/refs/remotes/trunk').read()
135            if local_head != trunk:
136                print_("Your local master diverges from trunk.\n")
137                # dcommit before local tagging
138                cmd.insert(0, 'git svn dcommit')
139            # create tag in svn
140            cmd.append('git svn tag -m "%s" %s' % (msg, version))
141        return cmd
142
143    # Similarly copied from zer.releaser to support use of 'v' in front
144    # of the version number
145    def _my_make_tag(self):
146        from zest.releaser import utils
147        from os import system
148
149        if self.data['tag_already_exists']:
150            return
151        cmds = self.vcs.cmd_create_tag(self.data['version'])
152        if not isinstance(cmds, list):
153            cmds = [cmds]
154        if len(cmds) == 1:
155            print_("Tag needed to proceed, you can use the following command:")
156        for cmd in cmds:
157            print_(cmd)
158            if utils.ask("Run this command"):
159                print_(system(cmd))
160            else:
161                # all commands are needed in order to proceed normally
162                print_("Please create a tag for %s yourself and rerun." % \
163                        (self.data['version'],))
164                sys.exit()
165        if not self.vcs.tag_exists(self.data['version']):
166            print_("\nFailed to create tag %s!" % (self.data['version'],))
167            sys.exit()
168
169    # Normally all this does is to return '--formats=zip', which is currently
170    # hard-coded as an option to always add to the sdist command; they ought to
171    # make this actually optional
172    def _my_sdist_options(self):
173        return ''
174
175    Git.cmd_create_tag = _my_create_tag
176    Releaser._make_tag = _my_make_tag
177    Releaser._sdist_options = _my_sdist_options
178
179
180def postreleaser_before(data):
181    """
182    Fix the irritating .dev0 default appended to new development versions by
183    zest.releaser to just append ".dev" without the "0".
184    """
185
186    data['dev_version_template'] = '%(new_version)s.dev'
187