Exemplo n.º 1
0
 def check_pyprc(self):
     output.part_title('Checking .pypirc for egg-release targets')
     pypirc_path = os.path.expanduser('~/.pypirc')
     if not os.path.isfile(pypirc_path):
         # ~/.pypirc required
         output.error('Could not find the file %s' % pypirc_path, exit=True)
     config = ConfigParser.ConfigParser()
     config.readfp(open(pypirc_path))
     indexservers = config.get('distutils', 'index-servers').strip().split('\n')
     sections = []
     basic_namespace = scm.get_package_name('.').split('.')[0]
     for srv in indexservers:
         # test if its properly configured
         if config.has_section(srv):
             print '* found target "%s"' % output.colorize(srv,
                                                           output.WARNING)
             sections.append(srv)
     if basic_namespace in sections:
         self.pypi_target = basic_namespace
     else:
         self.pypi_target = ''
     msg = 'Please specify a pypi target for the egg relase [%s]' % \
         output.colorize(self.pypi_target, output.BOLD_WARNING)
     pypi_target_input = input.prompt(msg, lambda v:\
                                          (self.pypi_target and not v) or v in
                                      sections
                                      and True or 'Please select a target listed above')
     if pypi_target_input:
         self.pypi_target = pypi_target_input
Exemplo n.º 2
0
 def check_versions(self):
     output.part_title('Checking package versions')
     version_file = os.path.join(scm.get_package_name('.').replace('.', '/'),
                                 'version.txt')
     trunk_version = open(version_file).read().strip()
     print ' * Current version of trunk:         %s' %\
         output.colorize(trunk_version, output.WARNING)
     next_version = trunk_version.split('-')[0]
     existing_tags = scm.get_existing_tags('.')
     if next_version in existing_tags.keys():
         output.warning('Tag %s already existing' % next_version)
     # ask for next tag version
     prompt_msg = 'Which version do you want to release now? [%s]' % \
         output.colorize(next_version, output.BOLD_WARNING)
     next_version_input = input.prompt(prompt_msg, lambda v:v in existing_tags.keys() and 'Tag already existing' or True)
     if next_version_input:
         next_version = next_version_input
     # ask for next trunk version
     next_trunk_version = next_version + '-dev'
     next_trunk_version = self.bump_version_proposal(next_trunk_version)
     prompt_msg = 'Which version should trunk have afterwards? [%s]' % \
         output.colorize(next_trunk_version, output.BOLD_WARNING)
     next_trunk_version_input = input.prompt(prompt_msg)
     if next_trunk_version_input:
         next_trunk_version = next_trunk_version_input
     print ' * The version of the tag will be:   %s' %\
         output.colorize(next_version, output.WARNING)
     print ' * New version of the trunk will be: %s' %\
         output.colorize(next_trunk_version, output.WARNING)
     self.new_tag_version = next_version
     self.new_trunk_version = next_trunk_version
Exemplo n.º 3
0
 def show_description(self, rows=None, higlight=None):
     description = self.get_description()
     if not rows:
         rows = range(len(description))
     for i in rows:
         p = '%i:' % (i + 1) + ' ' + description[i]
         if i == higlight:
             print output.colorize(p, output.WARNING)
         else:
             print p
Exemplo n.º 4
0
 def notify(self, state, problem='', solution='', problem_level=0,
            pause=True):
     """Notify the user of a problem
     """
     if state:
         print '  OK'
     else:
         prob_type, prob_color = self.PROBLEM_LEVELS[problem_level]
         print ' ', output.colorize(prob_type, prob_color), \
             output.colorize(problem, prob_color)
         if solution:
             print '  SOLUTION:', solution
         if pause:
             input.prompt('[ENTER TO CONTINUE]')
     print ''
Exemplo n.º 5
0
 def __call__(self):
     scm.tested_for_scms(('svn', 'gitsvn'), '.')
     svn_url = scm.get_svn_url('.').split('/')
     svn_root_url = scm.get_package_root_url('.').split('/')
     package_name = scm.get_package_name('.')
     path = os.path.abspath(os.path.join(
             (len(svn_url) - len(svn_root_url) - 1) * '../',
             package_name.replace('.', '/'),
             'version.txt',
             ))
     if not os.path.isfile(path):
         output.error('Could not find file %s' % path, exit=1)
     version = open(path).read().strip()
     print '  Version of %s: %s' % (
         output.colorize(package_name, output.WARNING),
         output.colorize(version, output.WARNING),
         )
Exemplo n.º 6
0
    def __call__(self):
        pinnings = self._get_pinnings_by_package()

        def _format_line(pkg, extra, version, file, current=False):
            pkgname = pkg
            if extra:
                pkgname += '[%s]' % extra
            if current:
                indent = ' ' * 4 + '*'
            else:
                indent = ' ' * 5
            txt = ' '.join((indent, pkgname, '=', version, '@', file))
            if current:
                return output.colorize(txt, output.WARNING)
            else:
                return txt
        first = True
        for pkg, dep_extra, dep_version in self._get_packages():
            current_version = None
            if first:
                first = False
            else:
                print ''
                print ''
            print output.colorize(pkg, output.INFO)
            if dep_version:
                current_version = None
                print _format_line(pkg, dep_extra, dep_version, './setup.py')
            if pkg.lower() in pinnings.keys():
                pkg_pinnings = pinnings[pkg.lower()][:]
                pkg_pinnings.reverse()
                for file, extra, version in pkg_pinnings:
                    if not current_version:
                        current_version = version
                        print _format_line(pkg, extra, version, file,
                                           current=True)
                    else:
                        print _format_line(pkg, extra, version, file)
            if self.options.new:
                new_dists = self._get_newer_versions_for(pkg, current_version)
                if len(new_dists) > 0:
                    print output.colorize('newer distributions than %s:' %
                                          current_version, output.ERROR)
                    for dist in new_dists:
                        print ' ' * 5, output.colorize(dist, output.ERROR)
Exemplo n.º 7
0
 def _add_rows(dependencies, indent=0):
     for package, extra, v in dependencies:
         color = None
         ctag = package in versions.keys() and \
             str(versions[package]) or ''
         info = scm.PackageInfoMemory().get_info(
             package,
             force_reload=force_reload,
             prompt=(not self.options.quiet))
         maintainer = scm.PackageInfoMemory().get_maintainer_for(
             package, with_extra=extra) or ''
         ntag = info and str(info['newest_tag']) or ''
         if ntag and ctag:
             if ntag < ctag:
                 ntag = output.colorize(ntag, output.WARNING)
                 color = output.WARNING
             elif ntag > ctag:
                 ntag = output.colorize(ntag, output.ERROR)
                 color = output.ERROR
                 pinnings[package] = ntag
             elif ntag == ctag:
                 ntag = output.colorize(ntag, output.INFO)
                 color = output.INFO
         elif ntag:
             pinnings[package] = ntag
         chg = ''
         if info and info['changes']:
             chg = output.colorize('YES', output.WARNING)
             color = output.WARNING
         name = extra and '%s[%s]' % (package, extra) or package
         name = '  ' * indent + name
         table.push((
                 color and output.colorize(name, color) or name,
                 ctag,
                 ntag,
                 chg,
                 maintainer,
                 ))
         if indent < limit:
             sub_deps = scm.PackageInfoMemory().get_dependencies_for(
                 package, with_extra=extra)
             if sub_deps:
                 _add_rows(sub_deps, indent + 1)
Exemplo n.º 8
0
 def _format_line(pkg, extra, version, file, current=False):
     pkgname = pkg
     if extra:
         pkgname += '[%s]' % extra
     if current:
         indent = ' ' * 4 + '*'
     else:
         indent = ' ' * 5
     txt = ' '.join((indent, pkgname, '=', version, '@', file))
     if current:
         return output.colorize(txt, output.WARNING)
     else:
         return txt
Exemplo n.º 9
0
 def __call__(self):
     if not os.path.isfile('setup.py'):
         output.error('File not found: %s' % os.path.abspath('setup.py'),
                      exit=1)
     cmd = '%s setup.py check --restructuredtext --strict' % sys.executable
     if self.options.show:
         self.show_description()
         return
     elif self.options.browser:
         description = '\n'.join(self.get_description())
         response = open('long_description.html', 'w+')
         publish_file(writer_name='html',
                      destination=response,
                      source=StringIO(description))
         runcmd_with_exitcode('open long_description.html')
         return
     code, response, error = runcmd_with_exitcode(cmd, log=True,
                                                  respond=True,
                                                  respond_error=True)
     if code == 0:
         print '* docs okay'
     else:
         xpr = re.compile('\(line ([\d]*)\)')
         description = self.get_description()
         error = error.strip().split('\n')
         for err in error:
             print output.colorize(err, output.ERROR)
             line = xpr.search(err)
             if line:
                 line_nr = int(line.groups()[0]) - 1
                 start_line = line_nr - self.options.offrows
                 start_line = start_line > 0 and start_line or 0
                 end_line = line_nr + self.options.offrows + 1
                 end_line = end_line < len(description) and \
                     end_line or len(description)
                 line_range = range(start_line, end_line)
                 self.show_description(line_range, higlight=line_nr)
                 print ''
Exemplo n.º 10
0
    def get_svn_url(self, package_name):
        # what's the svn url?
        svn_url = None
        namespace = package_name.split('.')[0]
        # are there already packages checked out with same namespace?
        dirs = [os.path.abspath(d) for d in os.listdir('.')]
        dirs += [os.path.join(git.get_gitsvn_cache_path(), d)
                 for d in os.listdir(git.get_gitsvn_cache_path())]
        for path in dirs:
            dir = os.path.basename(path)
            if dir.startswith('%s.' % namespace):
                try:
                    tmp_url = '/'.join(
                        scm.get_package_root_url(
                            path).split('/')[:-1])
                    if tmp_url and \
                            '%s/' % package_name in svn.listdir(tmp_url):
                        svn_url = os.path.join(tmp_url, package_name, 'trunk')
                        break
                except scm.NotAScm:
                    pass
        if svn_url:
            print ' * found a package under %s' % svn_url
            msg = 'SVN project trunk url [%s]' % \
                output.colorize(svn_url, output.BOLD_WARNING)

            def input_validator(v):
                if not v:
                    return True
                if not svn.isdir(v.strip()):
                    return 'URL not found'
                return True

            url_input = input.prompt(msg, input_validator)
            if url_input:
                svn_url = url_input.strip()
        else:
            msg = 'SVN project trunk url:'

            def input_validator2(v):
                if not v or not svn.isdir(v.strip()):
                    return 'URL not found'
                return True

            url_input = input.prompt(msg, input_validator2)
            svn_url = url_input.strip()
        # check svn layout, give the user a chance to create the dirs
        svn.check_project_layout(svn_url, raise_exception=False)
        return svn_url
Exemplo n.º 11
0
    def pre_build_check(self):
        """ Check if a build will work later. Check this before doing anything
        by building and loading the egg.
        """
        output.part_title('Make a test-build for preventing bad dists')
        cwd = os.getcwd()
        # make a sdist
        runcmd('%s setup.py sdist' % sys.executable)
        os.chdir('dist')
        # switch dir
        print output.colorize('cd dist', output.INFO)
        # extract
        runcmd('tar -xf *.tar.gz')
        # find extracted dir / chdir
        distdir = None
        for file_ in os.listdir('.'):
            if os.path.isdir(file_):
                distdir = file_
                break
        if not distdir:
            output.error('Something is wrong: could not find extracted dist directory',
                         exit=1)
        os.chdir(distdir)
        print output.colorize('cd %s' % distdir, output.INFO)
        # test setup.py
        cmd = '%s setup.py egg_info' % sys.executable
        state, response, error = runcmd_with_exitcode(cmd,
                                                      respond=True,
                                                      respond_error=True)
        # cd back to original dir
        os.chdir(cwd)
        # remove stuff
        runcmd('rm -rf dist')
        # did it work?
        if state != 0:
            output.error('Something\'s wrong: could not load setup.py on distribution, ' +\
                             'you may have a problem with your setup.py / MANIFEST.in:',
                         exit=(not error and True or False))
            if response:
                print output.colorize(response, output.INFO)
            if error:
                output.error(error, exit=True)

        # check locales
        locales_dir = os.path.join(scm.get_package_name('.').replace('.', '/'),
                                   'locales')
        if os.path.isdir(locales_dir):
            for basedir, dirs, files in os.walk(locales_dir):
                for file_ in files:
                    path = os.path.join(basedir, file_)
                    if path.endswith('.po'):
                        # check with msgfmt
                        exitcode, errors = runcmd_with_exitcode(
                            'msgfmt -o /dev/null %s' % path,
                            log=True,
                            respond_error=True)
                        if exitcode > 0:
                            output.error(errors, exit=True)

                        data = open(path).read()
                        if 'fuzzy' in data:
                            print path
                            output.error('You have "Fuzzy" entries in your '
                            'translations! I\'m not releasing '
                                         'it like this.', exit=True)
Exemplo n.º 12
0
    def check_manifest(self):
        """ Checks the MANIFEST.in file and gives advices. It returns if the
        release action can be continued
        """
        if self.options.release_egg_only:
            return True

        namespace = scm.get_package_name('.').split('.')[0]

        required_lines = (
            'recursive-include %s *' % namespace,
            'recursive-include docs *',
            'include *.txt',
            'global-exclude *.pyc',
            'global-exclude ._*',
            )

        unused_lines = (
            'include setup.py',
            'include README.txt',
            'include CONTRIBUTORS.txt',
            'global-exclude *pyc',
            'global-exclude *mo',
            'global-exclude *.mo',
            )

        created = False
        modified = False
        commit_message = ''

        if not os.path.isfile('MANIFEST.in'):
            output.warning('Could not find the file ./MANIFEST.in, creating one')
            f = open('MANIFEST.in', 'w')
            f.write('\n'.join(required_lines))
            f.close()
            print 'created MANIFEST.in with following content:'
            print output.colorize(open('MANIFEST.in').read(), output.INFO)
            print ''
            commit_message = 'added MANIFEST.in for %s' % scm.get_package_name('.')
            created = True

        else:
            # check the existing file
            current_lines = [x.strip() for x in open('MANIFEST.in').readlines()]
            missing_lines = [x for x in required_lines
                             if x.strip() not in current_lines]
            files_to_remove = [x for x in unused_lines
                               if x.strip() in current_lines]

            if len(missing_lines) > 0 or len(files_to_remove) > 0:
                new_lines = current_lines

                if len(missing_lines) > 0:
                    output.warning('./MANIFEST.in: added some required lines:')
                    print output.colorize('\n'.join(missing_lines), output.INFO)
                    print ''
                    new_lines += missing_lines

                if len(files_to_remove) > 0:
                    output.warning('./MANIFEST.in: removed some unused lines:')
                    print output.colorize('\n'.join(files_to_remove), output.ERROR)
                    print ''
                    new_lines = filter(lambda x:x.strip() not in files_to_remove,
                                       new_lines)

                f = open('MANIFEST.in', 'w')
                f.write('\n'.join(new_lines))
                f.close()
                commit_message = 'updated MANIFEST.in for %s' % scm.get_package_name('.')
                modified = True

        if created or modified:
            # commit it ?
            if input.prompt_bool('Would you like to commit the MANIFEST.in?'):
                if created:
                    scm.add_and_commit_files(commit_message, 'MANIFEST.in')
                    return True
                elif modified:
                    scm.commit_files(commit_message, 'MANIFEST.in')
                    return True
            return False

        else:
            return True
Exemplo n.º 13
0
 def notify_fix_completed(self):
     print output.colorize('Fix completed successfully', output.INFO)
     print ''
Exemplo n.º 14
0
 def notify_check(self, title):
     """Print check-title to the stdout
     """
     print output.colorize('CHECK:', output.BOLD_INFO), \
         output.colorize(title, output.INFO)
Exemplo n.º 15
0
    def check_requires(self):
        """ Checks, if there are missing dependencies
        """
        self.notify_part('Check dependencies')
        # get current requires
        requires = self.egginfo.install_requires

        # extend it with extra requires
        if self.egginfo.extras_require:
            for ename, erequires in self.egginfo.extras_require.items():
                requires.extend(erequires)

        print ' current requirements (including extras):'
        for egg in requires:
            print '    -', egg
        print ''

        # add the requirements without extras too
        for egg in requires[:]:
            if '[' in egg:
                requires.append(egg.split('[')[0])

        self.notify_check('Its not necessary to import some default plone / zope stuff')
        failures = False
        for egg in requires:
            if egg in PACKAGE_REQUIREMENTS_INADVISABLE and egg not in TESTING_PACKAGES:
                self.notify(False, 'Maybe you should remove the requirement ' +\
                                output.colorize(egg, output.ERROR) +\
                                output.colorize('. It seems to be in a python, ' +\
                                                    'zope or plone distribution and ' +\
                                                    'those packages should not be ' +\
                                                    'set as requirement.', output.WARNING),
                            problem_level=2)
                failures = True
        if not failures:
            self.notify(True)

        self.notify_check('Check imports on python files and zcml stuff')
        propose_requires = []

        # contains ipath:file mapping of python and zcml imports
        ipath_file_mapping = {}

        # SEARCH PYTHON FILES
        # make a grep on python files
        py_grep_results = runcmd("find . -name '*.py' -exec grep -Hr 'import ' {} \;",
                                 respond=True)
        # cleanup:
        # - strip rows
        # - remove the rows with spaces (they are not realle imports)
        # - remove "as xxx"
        py_grep_results = filter(lambda row: ' ' in row,
                                 [row.strip().split(' as ')[0] for row in py_grep_results])

        for row in py_grep_results:
            file_, statement = row.split(':')
            # make a import path
            ipath = statement.replace('from ', '').replace(' import ',
                                                           '.').replace('import', '').strip()
            ipath = ipath.replace('...', '').replace('>>>', '')
            ipath_parts = ipath.split('.')

            if '#' in ipath:
                continue

            # ignore namespace imports (python internals etc)
            if len(ipath_parts) == 1:
                continue

            ipath_file_mapping[ipath] = file_

        # SEARCH ZCML FILES
        cmd = "find . -name '*.zcml' -exec grep -Hr '\(layer\|package\|for\)=' {} \;"
        zcml_grep_results = runcmd(cmd, respond=True)

        # cleanup results
        zcml_xpr = re.compile('(for|layer)="(.*?)("|$)')
        for row in zcml_grep_results:
            file_, stmt = row.split(':', 1)
            stmt = stmt.strip()
            match = zcml_xpr.search(stmt)
            if not match:
                # maybe we have a more complicated statement (e.g. multiline)
                break
            ipath = match.groups()[1].strip()

            ipath = ipath.replace('*', '').strip()

            if '#' in ipath:
                continue

            if not ipath.startswith('.'):
                ipath_file_mapping[ipath] = file_

        # for later use
        guessed_related_packages = self._get_guessed_related_packages()

        # HANDLE ALL IMPORTS
        for ipath, file_ in ipath_file_mapping.items():
            ipath_parts = ipath.split('.')
            # ignore local imports
            if ipath.startswith(scm.get_package_name('.')):
                continue

            # is it already required?
            found = False
            for egg in requires:
                if ipath.startswith(egg):
                    found = True
                    break
            if not found:
                # is it already proposed?
                for egg in propose_requires:
                    if ipath.startswith(egg):
                        found = True
                        break
            if not found:
                # is it ignored?
                for egg in PACKAGE_REQUIREMENTS_INADVISABLE + TESTING_PACKAGES:
                    if ipath.startswith(egg):
                        found = True
                        break
            if found:
                continue

            # maybe we have a module which import relatively
            module_path = os.path.join(os.path.dirname(file_),
                                       ipath_parts[0])
            if os.path.isfile(module_path + '.py') or \
                    os.path.isfile(module_path + '/__init__.py'):
                continue

            # start on level 2 and for searching egg
            guessed_egg_names = ['.'.join(ipath_parts[:i])
                                 for i, part in enumerate(ipath_parts)
                                 if i > 1]

            # does one of the eggs exist?
            found = False

            # is there package in our src directory, if we are in one?
            for egg_name in guessed_egg_names:
                if egg_name.strip() in guessed_related_packages:
                    if egg_name.strip() not in propose_requires:
                        propose_requires.append(egg_name.strip())
                    found = True
                    break

            # .. in pypi
            if not found:
                for egg_name in guessed_egg_names:
                    if len(self.find_egg_in_index(egg_name)) > 0:
                        if egg_name.strip() not in propose_requires:
                            propose_requires.append(egg_name.strip())
                        found = True
                        break

            # .. or do we have one in the svn cache?
            if not found:
                for egg_name in guessed_egg_names:
                    if scm.guess_package_url(egg_name):
                        if egg_name.strip() not in propose_requires:
                            propose_requires.append(egg_name.strip())
                        found = True
                        break

            if not found:
                print '  ', output.colorize(ipath, output.INFO), 'in', \
                    output.colorize(file_, output.INFO), \
                    output.colorize('is not covered by requirements '
                                    'and I could find a egg with such a name',
                                    output.WARNING)

        if scm.get_package_name('.') in propose_requires:
            propose_requires.remove(scm.get_package_name('.'))

        if len(propose_requires)==0:
            self.notify(True)
            return
        propose_requires.sort()
        print ''
        print '  There are some requirements missing. I propose to add these:'
        for egg in propose_requires:
            print '   ', egg
        print ''

        # try to add them automatically:
        if input.prompt_bool('Should I try to add them?'):
            rows = open('setup.py').read().split('\n')
            # find "install_requires"
            frows = filter(lambda row:row.strip().startswith('install_requires='),
                           rows)
            if len(frows) != 1:
                output.error('Somethings wrong with your setup.py: expected only '
                             'one row containing "install_requires=", but '
                             'got %i' % len(frows), exit=1)
            insert_at = rows.index(frows[0]) + 1
            for egg in propose_requires:
                rows.insert(insert_at, ' ' * 8 + "'%s'," % egg)
            file_ = open('setup.py', 'w')
            file_.write('\n'.join(rows))
            file_.close()
            self._validate_setup_py()
            scm.add_and_commit_files('setup.py: added missing dependencies',
                                     'setup.py')
            self.notify_fix_completed()
Exemplo n.º 16
0
    def guess_url(self, package, prompt=False, required=False):
        """ Tries to guess the url of a package. If it's not able to guess, it asks
        or returns None, dependening on *prompt*
        """
        # first, we check if we already know the name
        if self.has_package(package):
            return self.get(package)
        # we will search some places, make a list of possible hint-directories
        hint_dirs = []
        # the parent directory may contain the package or other packages with the same
        # namespace (e.g. src-directory)
        hint_dirs.append(os.path.abspath(".."))
        # the gitsvn-cache directory contains several packages, the required package or
        # a package with the same namespace?
        hint_dirs.append(os.path.abspath(git.get_gitsvn_cache_path()))

        # now we try to find the package in the hint_dirs
        for dir in hint_dirs:
            path = os.path.join(dir, package)
            if os.path.isdir(path) and is_scm(path):
                try:
                    url = get_package_root_url(path)
                except NotAScm:
                    pass
                else:
                    self.set(package, url)
                    return url

        # now lets guess it with the namespace...
        # first we check the packages we alreay know the path:
        namespace = package.split(".")[0]
        for pkg, url in self._packages.items():
            if pkg.startswith("%s." % namespace):
                try:
                    dir_url = "/".join(url.split("/")[:-1])
                    if package + "/" in svn.listdir(dir_url):
                        url = os.path.join(dir_url, package)
                        self.set(package, url)
                        return url
                except NotAScm:
                    pass

        # could not find any? we may need to ask the user...
        if prompt:

            def input_validator(v):
                if not required and not v:
                    return True
                if not v or not svn.isdir(v.strip()):
                    return "Invalid SVN-URL"
                return True

            colorized_package = output.colorize(package, output.BOLD_WARNING)
            msg = output.colorize("I'm having trouble to guess the SVN-URL for the package", output.WARNING)
            msg += " " + colorized_package
            print msg
            msg = "SVN-URL of %s" % colorized_package
            if not required:
                msg += output.colorize(" or nothing", output.WARNING)
            url_input = input.prompt(msg, input_validator)
            if url_input:
                url = svn.get_package_root_url(url_input)
                self.set(package, url)
                return url
        return None