Skip to content

Commit

Permalink
integrate untox into rtox
Browse files Browse the repository at this point in the history
Adds untox script to rtox and allows using it
as --untox parameter.

Fixes #8

Signed-off-by: Sorin Sbarnea <[email protected]>
  • Loading branch information
ssbarnea committed Feb 19, 2018
1 parent 5f6afd4 commit cc6d8a7
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 5 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
/ChangeLog
/dist
/rtox.egg-info
/tests/untox/tox.ini
*.log
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ clean:
@rm -rf .tox dist/* docs/build/*

test:
tox
@tox

uninstall:
$(PREFIX)pip uninstall -y $(PACKAGE_NAME)

dist:
rm -rf dist/*
@rm -rf dist/*
$(PREFIX)python setup.py sdist bdist_wheel

upload: dist
Expand Down
46 changes: 44 additions & 2 deletions rtox/rtox.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,25 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
from __future__ import absolute_import
import argparse
try:
import ConfigParser as configparser
except ImportError:
import configparser
import getpass
import hashlib
import inspect
import os.path
import subprocess
import sys
import time

import paramiko

from rtox import __version__
import rtox.untox as untox_code


class Client(object):
"""An SSH client that can runs remote commands as if they were local."""
Expand Down Expand Up @@ -114,10 +120,30 @@ def shell_escape(arg):

def cli():
"""Run the command line interface of the program."""

parser = \
argparse.ArgumentParser(
description='rtox runs tox on a remote machine instead of '
'current one.',
add_help=True)

parser.add_argument('--version',
action='version',
version='%%(prog)s %s' % __version__)
parser.add_argument('--untox',
dest='untox',
action='store_true',
default=False,
help='untox obliterates any package installation from \
tox.ini files in order to allow testing with \
system packages only')
args, tox_args = parser.parse_known_args()

config = load_config()

repo = local_repo()
remote_repo_path = '~/.rtox/%s' % hashlib.sha1(repo).hexdigest()
remote_untox = '~/.rtox/untox'

client = Client(
config.get('ssh', 'hostname'),
Expand Down Expand Up @@ -151,9 +177,25 @@ def cli():
config.get('ssh', 'hostname'),
remote_repo_path)])

if args.untox:
subprocess.check_call([
'rsync',
'--no-R',
'--no-implied-dirs',
'--chmod=ugo=rwx',
'--update',
'-a',
inspect.getsourcefile(untox_code),
'%s@%s:%s' % (
config.get('ssh', 'user'),
config.get('ssh', 'hostname'),
remote_untox)])

# removing .tox folder is done
command = ['cd %s ; PY_COLORS=1 python -m tox' % remote_repo_path]
command.extend(sys.argv[1:])
command = ['cd %s ; %s PY_COLORS=1 python -m tox' %
(remote_repo_path,
'%s ; ' % remote_untox if args.untox else '')]
command.extend(tox_args)
status_code = client.run(' '.join(command))

raise SystemExit(status_code)
Expand Down
70 changes: 70 additions & 0 deletions rtox/untox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env python
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# Wipes any packet installation code from tox.ini in order to be able
# to run tox commands using system packages.
#
import os
import re


def main():
f = open('tox.ini', 'r+')
data = f.read()

# comments to avoid weird accidents while parsing
data = re.sub(r'\s*\#.*\n', '', data)

# consolidate contiuation line breaks
data = re.sub(r'^(.*)\\\n\s*([^\r\n]+)\n',
r'\1\2\n',
data,
flags=re.MULTILINE)

# remove install_commands
data = re.sub(r'\s*install_command.*', '', data)

# remove pip install commands (including multiline)
data = re.sub(r'(?m)^\s*pip (.*)?install.*\n?', '', data)

# remove deps, single and multiline ones
data = re.sub(r'^\s*deps.*\n(([^\S\n]+[^\n]+\n)+)?',
r'',
data,
flags=re.MULTILINE)

# replace any existing sitepackages value as True
data = re.sub(r'\s*sitepackages.*', '\nsitepackages = True', data)

# adds sitepackages=True to [testenv*] section(s) if needed
pattern = re.compile(r'^\[testenv[^\]\r\n]+](?:\r?\n(?:[^[\r\n].*)?)*',
flags=re.MULTILINE)
for s in re.findall(pattern, data):
if 'sitepackages' not in s:
data = data.replace(s, s + 'sitepackages = True\n')

f.seek(0)
f.write(data)
f.truncate()

# truncates requirement files just in case they are used in a different way
for reqs in ['requirements.txt', 'test-requirements.txt']:
if os.path.isfile(reqs):
open(reqs, "w").truncate(0)

# logs changes made as a diff file
os.system("git diff | tee untox-diff.log")

if __name__ == '__main__':
main()
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ packages =
[entry_points]
console_scripts =
rtox=rtox.rtox:cli
untox=rtox.untox:main

[egg_info]
egg_base = .
Expand Down
29 changes: 29 additions & 0 deletions tests/untox/tox.ini.clean
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[tox]
minversion = 1.6
skipsdist = True
envlist = py27,pep8

[testenv]
usedevelop = True
sitepackages = True
commands =
bash tools/pretty_tox.sh '{posargs}'

[testenv:pep8]
commands =
flake8 {posargs} . foo
sitepackages = True
[testenv:pylint]

commands = bash tools/lintstack.sh

sitepackages = True
[testenv:cover]
commands =
python setup.py testr --coverage --testr-args='^(?!.*test.*coverage).*$ --concurrency 1'

sitepackages = True
[testenv:venv]
commands =
{posargs}
sitepackages = True
42 changes: 42 additions & 0 deletions tests/untox/tox.ini.orig
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[tox]
minversion = 1.6
skipsdist = True
envlist = py27,pep8

[testenv]
usedevelop = True
sitepackages = False
commands =
pip install pip>=9.0.1
pip install -c{toxinidir}/upper-constraints.txt -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt
bash tools/pretty_tox.sh '{posargs}'

[testenv:pep8]
deps = pip>=9.0.1
commands =
pip install pip>=9.0.1
pip install -c{toxinidir}/upper-constraints.txt -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt
flake8 {posargs} . foo
# Check that .po and .pot files are valid:

[testenv:pylint]
deps = -r{toxinidir}/requirements.txt
pylint==0.26.0
foo

commands = bash tools/lintstack.sh

[testenv:cover]
commands =
pip install pip>=9.0.1
pip install -c{toxinidir}/upper-constraints.txt \
-r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt
python setup.py testr --coverage \
--testr-args='^(?!.*test.*coverage).*$ --concurrency 1'

[testenv:venv]
commands =
pip install pip>=9.0.1
pip install -c{toxinidir}/upper-constraints.txt -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt
{posargs}
sitepackages=False
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ whitelist_externals =
commands =
pip install -q 'pip>=9.0.1'
pip install -q --upgrade-strategy=only-if-needed -e .
bash -c "cd {toxinidir}/tests/untox && cp -f tox.ini.orig tox.ini && untox && diff tox.ini tox.ini.clean"
# do not try default target to avoid recursive call (rtox would call tox on remote machine)
rtox -v -e func
#rtox -v -e func
passenv =
PY_*
SSH_AUTH_SOCK
Expand Down

0 comments on commit cc6d8a7

Please sign in to comment.