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
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 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)
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', '.')
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', '.')