def test_ignore_unstaged(self, tmpcwd):
     '''
     Pre-commit must ignore unstaged changes
     '''
     self.create_project()
     git_('add', '.')
     mkproject & pb.FG  # install pre-commit hook
     remove_file(Path('README.md'))
     git_('commit', '-m', 'message')  # This fails if unstaged change is included
 def test_invalid_project(self, tmpcwd):
     '''
     Invalid project cancels the commit
     '''
     self.create_project()
     mkproject & pb.FG  # install pre-commit hook
     remove_file(Path('README.md'))
     git_('add', '.')
     with assert_process_fails(stderr_matches='Missing file: README.md'):
         git_('commit', '-m', 'message')  # runs the hook
 def test_new(self, tmpcwd):
     '''
     When project.py missing, ask for a name and generate template
     '''
     # When project.py is missing and git repo exists but has no commits
     create_project()
     remove_file(Path('project.py'))
     (mkproject << '{name}\n{pkg_name}\n{human_friendly_name}\n'.format(**project1.format_kwargs))()
     
     # Then project.py is created and contains the defaults we want
     project_py_path = Path('project.py')
     assert project_py_path.exists()
     assert read_file(project_py_path) == spec.project_py.format(**project1.format_kwargs)
     assert eval_file(project_py_path)['project'] == project_defaults  # double-check
示例#4
0
def main(debug):
    '''
    Generate project documentation
    
    Note: calls `ct-mkvenv` to ensure the venv is up to date
    '''
    with graceful_main(logger, app_name='mkdoc', debug=debug):
        pb.local['ct-mkvenv'] & pb.FG  # ensure venv is up to date

        venv_dir = Path(pb.local.env.get('CT_VENV_DIR', 'venv')).absolute()
        project_root = Path.cwd()
        project = get_project(project_root)
        pkg_root = get_pkg_root(project_root, project['package_name'])

        doc_root = project_root / 'docs'
        remove_file(doc_root / 'build')
        kwargs = dict(venv_activate=venv_dir / 'bin/activate',
                      doc_root=doc_root,
                      pkg_root=pkg_root,
                      pkg_root_root=project_root /
                      project['package_name'].split('.')[0])
        pb.local['sh']['-c', '. {venv_activate} && cd {doc_root} && make html'.
                       format(**kwargs)] & pb.FG
示例#5
0
def main(debug):
    '''
    Generate project documentation
    
    Note: calls `ct-mkvenv` to ensure the venv is up to date
    '''
    with graceful_main(logger, app_name='mkdoc', debug=debug):
        pb.local['ct-mkvenv'] & pb.FG  # ensure venv is up to date
        
        venv_dir = Path(pb.local.env.get('CT_VENV_DIR', 'venv')).absolute()
        project_root = Path.cwd()
        project = get_project(project_root)
        pkg_root = get_pkg_root(project_root, project['package_name'])
        
        doc_root = project_root / 'docs'
        remove_file(doc_root / 'build')
        kwargs = dict(
            venv_activate=venv_dir / 'bin/activate',
            doc_root=doc_root,
            pkg_root=pkg_root,
            pkg_root_root= project_root / project['package_name'].split('.')[0]
        )
        pb.local['sh']['-c', '. {venv_activate} && cd {doc_root} && make html'.format(**kwargs)] & pb.FG
 def test_missing_file(self, tmpcwd, missing_path, missing_requirements):
     '''
     Test handling of missing files:
     
     - When files are missing, create them if allowed, error otherwise
     - When files are present and may not be updated, they are left untouched
     '''
     create_project()
     remove_file(missing_path)
     if missing_requirements.permission == Permission.none:
         # When can't create, must raise error
         with assert_process_fails(stderr_matches=missing_path.name):
             mkproject()
     else:
         # When can create, create
         with ExitStack() as contexts:
             for file, requirements in project_file_requirements.items():
                 if missing_path != file and missing_path not in file.parents and requirements.permission <= Permission.create:
                     contexts.enter_context(assert_file_access(file, written=False, contents_changed=False))
             mkproject & pb.FG
         assert missing_path.exists()
         content = read_file(missing_path)
         missing_requirements.verify_default_content(content, project1.format_kwargs)
示例#7
0
def _main():
    pb.local['ct-mkproject'](
    )  # Ensure requirements.in files, ... are up to date

    project_root = Path.cwd()
    project = get_project(project_root)
    venv_dir = Path(pb.local.env.get('CT_VENV_DIR', 'venv')).absolute()

    # Create venv if missing
    if not venv_dir.exists():
        # Find the desired Python
        desired_python = 'python{}.{}'.format(*project['python_version'])
        python = pb.local.get(desired_python,
                              'python{}'.format(project['python_version'][0]),
                              'python')
        if python.executable.name != desired_python:
            logger.warning('{} not found, falling back to {}'.format(
                desired_python, python.executable))

        # Create venv
        logger.info('Creating venv')
        python('-m', 'venv', str(venv_dir))

    python = pb.local[str(venv_dir / 'bin/python')]
    pip = python[str(
        venv_dir / 'bin/pip'
    )]  # Note: setuptools sometimes creates shebangs that are longer than the max allowed, so we call pip with python directly, avoiding the shebang

    # These are always (implicitly) desired
    base_dependencies = {'pip': '', 'setuptools': '', 'wheel': ''}
    for editable, dependency, version_spec, _ in parse_requirements_file(
            Path('requirements.txt')):
        if dependency in base_dependencies:
            base_dependencies[dependency] = version_spec

    logger.info('Upgrading {}'.format(', '.join(sorted(base_dependencies))))
    pip(
        'install', '--upgrade',
        *(dependency + version_spec
          for dependency, version_spec in base_dependencies.items()))

    # Get desired dependencies from requirements.txt (note: requirements.txt contains no SIP deps)
    desired_dependencies = set(base_dependencies.keys())
    for editable, dependency, version_spec, _ in parse_requirements_file(
            Path('requirements.txt')):
        if dependency:
            desired_dependencies.add(get_dependency_name(editable, dependency))

    # Get installed dependencies
    venv = get_venv(venv_dir)
    installed_dependencies = {
        distribution.project_name.lower()
        for distribution in venv
    }

    # Remove installed packages not listed in requirements.txt
    extra_dependencies = installed_dependencies - desired_dependencies
    extra_dependencies.discard(
        'chicken-turtle-project')  # never uninstall chicken-turtle-project
    logger.debug('Installed packages: ' + ' '.join(installed_dependencies))
    logger.debug('Desired packages: ' + ' '.join(desired_dependencies))
    if extra_dependencies:
        if extra_dependencies != {project['name']}:
            logger.info('Removing packages not listed as dependencies: ' +
                        ', '.join(extra_dependencies))
        pip('uninstall', '-y', *extra_dependencies)

    # Install desired dependencies
    logger.info('Installing requirements.txt')
    pip('install', '-r', 'requirements.txt')

    # Get desired SIP dependencies
    desired_sip_dependencies = {}  # {(name :: str) : (version :: str)}
    input_file_paths = get_dependency_file_paths(project_root)
    for input_path in input_file_paths:
        for editable, dependency, version_spec, _ in parse_requirements_file(
                input_path):
            if not dependency:
                continue
            name = get_dependency_name(editable, dependency)
            if is_sip_dependency(name):
                assert version_spec.startswith('==')
                desired_sip_dependencies[name.lower()] = version_spec[2:]

    # Get installed SIP dependencies
    installed_sip_dependencies = set()
    for name, package in sip_packages.items():
        if python['-c', 'import {}'.format(package)] & pb.TF:
            installed_sip_dependencies.add(name)

    # Install SIP dependencies
    missing_sip_dependencies = desired_sip_dependencies.keys(
    ) - installed_sip_dependencies
    if missing_sip_dependencies:
        # Note: http://stackoverflow.com/a/1962076/1031434
        logger.info('Installing SIP dependencies')
        wget = pb.local['wget']
        tar = pb.local['tar']
        sh = pb.local['sh']
        for name in ['sip'] + list(missing_sip_dependencies - {'sip'}):
            logger.info('- installing ' + name)
            if name == 'sip':
                url = 'https://sourceforge.net/projects/pyqt/files/sip/sip-{version}/sip-{version}.tar.gz'
                unpack_path = 'sip-{version}'
            elif name == 'pyqt5':
                url = 'https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-{version}/PyQt-gpl-{version}.tar.gz'
                unpack_path = 'PyQt-gpl-{version}'
            else:
                assert False

            version = desired_sip_dependencies[name]
            unpack_path = Path(unpack_path.format(version=version))
            tar_path = unpack_path.with_name(unpack_path.name + '.tar.gz')
            try:
                wget(url.format(
                    version=version))  #XXX use CTU http.download_file instead
                tar('zxvf', str(tar_path))
                with pb.local.cwd(str(unpack_path)):
                    cmd = sh[
                        '-c',
                        '. {} && python configure.py && make && make install'.
                        format(str(venv_dir / 'bin/activate'))]
                    if name == 'pyqt5':
                        # say yes to license and ignore exit code as this script always fails (but still install correctly)
                        (cmd << 'yes\n')(retcode=None)
                    else:
                        cmd & pb.FG
            finally:
                if unpack_path.exists():
                    remove_file(unpack_path)
                if tar_path.exists():
                    remove_file(tar_path)

    # Install project package
    logger.info('Installing project package')
    pip('install', '-e', '.')
示例#8
0
def _main():
    pb.local['ct-mkproject']()  # Ensure requirements.in files, ... are up to date
    
    project_root = Path.cwd()
    project = get_project(project_root)
    venv_dir = Path(pb.local.env.get('CT_VENV_DIR', 'venv')).absolute()
    
    # Create venv if missing
    if not venv_dir.exists():
        # Find the desired Python
        desired_python = 'python{}.{}'.format(*project['python_version'])
        python = pb.local.get(desired_python, 'python{}'.format(project['python_version'][0]), 'python')
        if python.executable.name != desired_python:
            logger.warning('{} not found, falling back to {}'.format(desired_python, python.executable))
        
        # Create venv    
        logger.info('Creating venv')
        python('-m', 'venv', str(venv_dir))
        
    python = pb.local[str(venv_dir / 'bin/python')]
    pip = python[str(venv_dir / 'bin/pip')]  # Note: setuptools sometimes creates shebangs that are longer than the max allowed, so we call pip with python directly, avoiding the shebang
        
    # These are always (implicitly) desired
    base_dependencies = {'pip' : '', 'setuptools' : '', 'wheel' : ''}
    for editable, dependency, version_spec, _ in parse_requirements_file(Path('requirements.txt')):
        if dependency in base_dependencies:
            base_dependencies[dependency] = version_spec
    
    logger.info('Upgrading {}'.format(', '.join(sorted(base_dependencies))))
    pip('install', '--upgrade', *(dependency + version_spec for dependency, version_spec in base_dependencies.items()))
    
    # Get desired dependencies from requirements.txt (note: requirements.txt contains no SIP deps)
    desired_dependencies = set(base_dependencies.keys())
    for editable, dependency, version_spec, _ in parse_requirements_file(Path('requirements.txt')):
        if dependency:
            desired_dependencies.add(get_dependency_name(editable, dependency))
    
    # Get installed dependencies
    venv = get_venv(venv_dir)
    installed_dependencies = {distribution.project_name.lower() for distribution in venv}
            
    # Remove installed packages not listed in requirements.txt
    extra_dependencies = installed_dependencies - desired_dependencies
    extra_dependencies.discard('chicken-turtle-project')  # never uninstall chicken-turtle-project
    logger.debug('Installed packages: ' + ' '.join(installed_dependencies))
    logger.debug('Desired packages: ' + ' '.join(desired_dependencies))
    if extra_dependencies:
        if extra_dependencies != {project['name']}:
            logger.info('Removing packages not listed as dependencies: ' + ', '.join(extra_dependencies))
        pip('uninstall', '-y', *extra_dependencies)
    
    # Install desired dependencies
    logger.info('Installing requirements.txt')
    pip('install', '-r', 'requirements.txt')
    
    # Get desired SIP dependencies
    desired_sip_dependencies = {}  # {(name :: str) : (version :: str)}
    input_file_paths = get_dependency_file_paths(project_root)
    for input_path in input_file_paths:
        for editable, dependency, version_spec, _ in parse_requirements_file(input_path):
            if not dependency:
                continue
            name = get_dependency_name(editable, dependency)
            if is_sip_dependency(name):
                assert version_spec.startswith('==')
                desired_sip_dependencies[name.lower()] = version_spec[2:]
                
    # Get installed SIP dependencies
    installed_sip_dependencies = set()
    for name, package in sip_packages.items():
        if python['-c', 'import {}'.format(package)] & pb.TF:
            installed_sip_dependencies.add(name)
    
    # Install SIP dependencies
    missing_sip_dependencies = desired_sip_dependencies.keys() - installed_sip_dependencies
    if missing_sip_dependencies:
        # Note: http://stackoverflow.com/a/1962076/1031434
        logger.info('Installing SIP dependencies')
        wget = pb.local['wget']
        tar = pb.local['tar']
        sh = pb.local['sh']
        for name in ['sip'] + list(missing_sip_dependencies - {'sip'}):
            logger.info('- installing ' + name)
            if name == 'sip':
                url = 'https://sourceforge.net/projects/pyqt/files/sip/sip-{version}/sip-{version}.tar.gz'
                unpack_path = 'sip-{version}'
            elif name == 'pyqt5':
                url = 'https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-{version}/PyQt-gpl-{version}.tar.gz'
                unpack_path = 'PyQt-gpl-{version}'
            else:
                assert False
            
            version = desired_sip_dependencies[name]
            unpack_path = Path(unpack_path.format(version=version))
            tar_path = unpack_path.with_name(unpack_path.name + '.tar.gz')
            try:
                wget(url.format(version=version)) #XXX use CTU http.download_file instead
                tar('zxvf', str(tar_path))
                with pb.local.cwd(str(unpack_path)):
                    cmd = sh['-c', '. {} && python configure.py && make && make install'.format(str(venv_dir / 'bin/activate'))]
                    if name == 'pyqt5':
                        # say yes to license and ignore exit code as this script always fails (but still install correctly)
                        (cmd << 'yes\n')(retcode=None)
                    else:
                        cmd & pb.FG
            finally:
                if unpack_path.exists():
                    remove_file(unpack_path)
                if tar_path.exists():
                    remove_file(tar_path)
        
    # Install project package
    logger.info('Installing project package')
    pip('install', '-e', '.')