Port python deps setup to windows
This commit is contained in:
parent
3630a78d1a
commit
74afd3c373
5 changed files with 252 additions and 1 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
name: Test Python Package Installation
|
name: Test Python Package Installation on Linux
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
60
.github/workflows/python-deps-windows.yml
vendored
Normal file
60
.github/workflows/python-deps-windows.yml
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
name: Test Python Package Installation on Windows
|
||||||
|
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
test-setup-python-scripts:
|
||||||
|
runs-on: windows-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- test_dir: examples/pipenv/requests-2
|
||||||
|
python_version: 2
|
||||||
|
- test_dir: examples/pipenv/requests-3
|
||||||
|
python_version: 3
|
||||||
|
|
||||||
|
- test_dir: examples/poetry/requests-2
|
||||||
|
python_version: 2
|
||||||
|
- test_dir: examples/poetry/requests-3
|
||||||
|
python_version: 3
|
||||||
|
|
||||||
|
- test_dir: examples/requirements/requests-2
|
||||||
|
python_version: 2
|
||||||
|
- test_dir: examples/requirements/requests-3
|
||||||
|
python_version: 3
|
||||||
|
|
||||||
|
- test_dir: examples/setup_py/requests-2
|
||||||
|
python_version: 2
|
||||||
|
- test_dir: examples/setup_py/requests-3
|
||||||
|
python_version: 3
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: python
|
||||||
|
|
||||||
|
- name: Test Auto Package Installation
|
||||||
|
run: |
|
||||||
|
$cmd = $Env:GITHUB_WORKSPACE + "\\python-setup\\install_tools.ps1"
|
||||||
|
powershell -File $cmd
|
||||||
|
|
||||||
|
cd $Env:GITHUB_WORKSPACE\\${{ matrix.test_dir }}
|
||||||
|
py -3 $Env:GITHUB_WORKSPACE\\python-setup\\auto_install_packages_windows.py C:\\hostedtoolcache\\windows\\CodeQL\\0.0.0-20200826\\x64\\codeql
|
||||||
|
- name: Setup for extractor
|
||||||
|
run: |
|
||||||
|
echo $Env:CODEQL_PYTHON
|
||||||
|
|
||||||
|
py -3 $Env:GITHUB_WORKSPACE\\python-setup\\tests\\from_python_exe.py $Env:CODEQL_PYTHON
|
||||||
|
- name: Verify packages installed
|
||||||
|
run: |
|
||||||
|
$cmd = $Env:GITHUB_WORKSPACE + "\\python-setup\\tests\\check_requests_123.ps1"
|
||||||
|
powershell -File $cmd ${{ matrix.python_version }}
|
||||||
150
python-setup/auto_install_packages_windows.py
Normal file
150
python-setup/auto_install_packages_windows.py
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from tempfile import mkdtemp
|
||||||
|
|
||||||
|
import extractor_version
|
||||||
|
|
||||||
|
|
||||||
|
def _check_call(command):
|
||||||
|
print('+ {}'.format(' '.join(command)), flush=True)
|
||||||
|
subprocess.check_call(command, stdin=subprocess.DEVNULL)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_output(command):
|
||||||
|
print('+ {}'.format(' '.join(command)), flush=True)
|
||||||
|
out = subprocess.check_output(command, stdin=subprocess.DEVNULL)
|
||||||
|
print(out, flush=True)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def install_packages_with_poetry():
|
||||||
|
os.environ['POETRY_VIRTUALENVS_PATH'] = os.environ['RUNNER_WORKSPACE'] + '\\virtualenvs'
|
||||||
|
try:
|
||||||
|
_check_call(['poetry', 'install', '--no-root'])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
sys.exit('package installation with poetry failed, see error above')
|
||||||
|
|
||||||
|
# poetry is super annoying with `poetry run`, since it will put lots of output on
|
||||||
|
# STDOUT if the current global python interpreter is not matching the one in the
|
||||||
|
# virtualenv for the package, which was the case for using poetry for Python 2 when
|
||||||
|
# default system interpreter was Python 3 :/
|
||||||
|
|
||||||
|
poetry_out = _check_output(['poetry', 'run', 'which', 'python'])
|
||||||
|
python_executable_path = poetry_out.decode('utf-8').splitlines()[-1]
|
||||||
|
|
||||||
|
return python_executable_path[2:]
|
||||||
|
|
||||||
|
|
||||||
|
def install_packages_with_pipenv():
|
||||||
|
os.environ['WORKON_HOME'] = os.environ['RUNNER_WORKSPACE'] + '\\virtualenvs'
|
||||||
|
try:
|
||||||
|
_check_call(['pipenv', 'install', '--keep-outdated', '--ignore-pipfile'])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
sys.exit('package installation with pipenv failed, see error above')
|
||||||
|
|
||||||
|
pipenv_out = _check_output(['pipenv', 'run', 'which', 'python'])
|
||||||
|
python_executable_path = pipenv_out.decode('utf-8').splitlines()[-1]
|
||||||
|
|
||||||
|
return python_executable_path[2:]
|
||||||
|
|
||||||
|
|
||||||
|
def _create_venv(version: int):
|
||||||
|
# create temporary directory ... that just lives "forever"
|
||||||
|
venv_path = os.environ['RUNNER_WORKSPACE']+'/codeql-action-python-autoinstall'
|
||||||
|
print ("Creating venv in "+venv_path, flush = True)
|
||||||
|
|
||||||
|
# virtualenv is a bit nicer for setting up virtual environment, since it will provide
|
||||||
|
# up-to-date versions of pip/setuptools/wheel which basic `python3 -m venv venv` won't
|
||||||
|
|
||||||
|
if version == 2:
|
||||||
|
_check_call(['py', '-2', '-m', 'virtualenv', venv_path])
|
||||||
|
elif version == 3:
|
||||||
|
_check_call(['py', '-3', '-m', 'virtualenv', venv_path])
|
||||||
|
|
||||||
|
return venv_path
|
||||||
|
|
||||||
|
|
||||||
|
def install_requirements_txt_packages(version: int):
|
||||||
|
venv_path = _create_venv(version)
|
||||||
|
venv_pip = os.path.join(venv_path, 'Scripts', 'pip')
|
||||||
|
venv_python = os.path.join(venv_path, 'Scripts', 'python')
|
||||||
|
|
||||||
|
try:
|
||||||
|
_check_call([venv_pip, 'install', '-r', 'requirements.txt'])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
sys.exit('package installation with `pip install -r requirements.txt` failed, see error above')
|
||||||
|
|
||||||
|
return venv_python
|
||||||
|
|
||||||
|
|
||||||
|
def install_with_setup_py(version: int):
|
||||||
|
venv_path = _create_venv(version)
|
||||||
|
venv_pip = os.path.join(venv_path, 'Scripts', 'pip')
|
||||||
|
venv_python = os.path.join(venv_path, 'Scripts', 'python')
|
||||||
|
|
||||||
|
try:
|
||||||
|
# We have to choose between `python setup.py develop` and `pip install -e .`.
|
||||||
|
# Modern projects use `pip install -e .` and I wasn't able to see any downsides
|
||||||
|
# to doing so. However, `python setup.py develop` has some downsides -- from
|
||||||
|
# https://stackoverflow.com/a/19048754 :
|
||||||
|
# > Note that it is highly recommended to use pip install . (install) and pip
|
||||||
|
# > install -e . (developer install) to install packages, as invoking setup.py
|
||||||
|
# > directly will do the wrong things for many dependencies, such as pull
|
||||||
|
# > prereleases and incompatible package versions, or make the package hard to
|
||||||
|
# > uninstall with pip.
|
||||||
|
|
||||||
|
_check_call([venv_pip, 'install', '-e', '.'])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
sys.exit('package installation with `pip install -e .` failed, see error above')
|
||||||
|
|
||||||
|
return venv_python
|
||||||
|
|
||||||
|
|
||||||
|
def install_packages() -> str:
|
||||||
|
if os.path.exists('poetry.lock'):
|
||||||
|
print('Found poetry.lock, will install packages with poetry', flush=True)
|
||||||
|
return install_packages_with_poetry()
|
||||||
|
|
||||||
|
if os.path.exists('Pipfile') or os.path.exists('Pipfile.lock'):
|
||||||
|
if os.path.exists('Pipfile.lock'):
|
||||||
|
print('Found Pipfile.lock, will install packages with Pipenv', flush=True)
|
||||||
|
else:
|
||||||
|
print('Found Pipfile, will install packages with Pipenv', flush=True)
|
||||||
|
return install_packages_with_pipenv()
|
||||||
|
|
||||||
|
version = extractor_version.get_extractor_version(sys.argv[1], quiet=False)
|
||||||
|
|
||||||
|
if os.path.exists('requirements.txt'):
|
||||||
|
print('Found requirements.txt, will install packages with pip', flush=True)
|
||||||
|
return install_requirements_txt_packages(version)
|
||||||
|
|
||||||
|
if os.path.exists('setup.py'):
|
||||||
|
print('Found setup.py, will install package with pip in editable mode', flush=True)
|
||||||
|
return install_with_setup_py(version)
|
||||||
|
|
||||||
|
print("was not able to install packages automatically", flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
sys.exit('Must provide base directory for codeql tool as only argument')
|
||||||
|
|
||||||
|
# The binaries for packages installed with `pip install --user` are not available on
|
||||||
|
# PATH by default, so we need to manually add them.
|
||||||
|
os.environ['PATH'] = os.path.expandvars('%APPDATA%\Python\\Python38\\scripts') + os.pathsep + os.environ['PATH']
|
||||||
|
|
||||||
|
python_executable_path = install_packages()
|
||||||
|
|
||||||
|
if python_executable_path is not None:
|
||||||
|
print("Setting CODEQL_PYTHON={}".format(python_executable_path))
|
||||||
|
print("::set-env name=CODEQL_PYTHON::{}".format(python_executable_path))
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# - no packages
|
||||||
|
# - poetry without version
|
||||||
|
# - pipenv without version
|
||||||
|
# - pipenv without lockfile
|
||||||
13
python-setup/install_tools.ps1
Normal file
13
python-setup/install_tools.ps1
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#! /usr/bin/pwsh
|
||||||
|
|
||||||
|
py -2 -m pip install --user --upgrade pip setuptools wheel
|
||||||
|
py -3 -m pip install --user --upgrade pip setuptools wheel
|
||||||
|
|
||||||
|
# virtualenv is a bit nicer for setting up virtual environment, since it will provide up-to-date versions of
|
||||||
|
# pip/setuptools/wheel which basic `python3 -m venv venv` won't
|
||||||
|
py -2 -m pip install --user virtualenv
|
||||||
|
py -3 -m pip install --user virtualenv
|
||||||
|
|
||||||
|
# poetry 1.0.10 has error (https://github.com/python-poetry/poetry/issues/2711)
|
||||||
|
py -3 -m pip install --user poetry!=1.0.10
|
||||||
|
py -3 -m pip install --user pipenv
|
||||||
28
python-setup/tests/check_requests_123.ps1
Normal file
28
python-setup/tests/check_requests_123.ps1
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#! /usr/bin/pwsh
|
||||||
|
|
||||||
|
$EXPECTED_VERSION=$args[0]
|
||||||
|
|
||||||
|
$FOUND_VERSION="$Env:LGTM_PYTHON_SETUP_VERSION"
|
||||||
|
$FOUND_PYTHONPATH="$Env:LGTM_INDEX_IMPORT_PATH"
|
||||||
|
|
||||||
|
write-host "FOUND_VERSION=$FOUND_VERSION FOUND_PYTHONPATH=$FOUND_PYTHONPATH "
|
||||||
|
|
||||||
|
if ($FOUND_VERSION -ne $EXPECTED_VERSION) {
|
||||||
|
write-host "Script told us to use Python $FOUND_VERSION, but expected $EXPECTED_VERSION"
|
||||||
|
exit 1
|
||||||
|
} else {
|
||||||
|
write-host "Script told us to use Python $FOUND_VERSION, which was expected"
|
||||||
|
}
|
||||||
|
|
||||||
|
$env:PYTHONPATH=$FOUND_PYTHONPATH
|
||||||
|
|
||||||
|
$INSTALLED_REQUESTS_VERSION = (py -3 -c "import requests; print(requests.__version__)")
|
||||||
|
|
||||||
|
$EXPECTED_REQUESTS="1.2.3"
|
||||||
|
|
||||||
|
if ($INSTALLED_REQUESTS_VERSION -ne $EXPECTED_REQUESTS) {
|
||||||
|
write-host "Using $FOUND_PYTHONPATH as PYTHONPATH, we found version $INSTALLED_REQUESTS_VERSION of requests, but expected $EXPECTED_REQUESTS"
|
||||||
|
exit 1
|
||||||
|
} else {
|
||||||
|
write-host "Using $FOUND_PYTHONPATH as PYTHONPATH, we found version $INSTALLED_REQUESTS_VERSION of requests, which was expected"
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue