From 91cb8199e6e27648d675a4832391d00a4da22821 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 6 Apr 2017 16:45:18 +0300 Subject: Rewrite yarn IMPLEMENTS in Python --- check | 10 +++ yarns/900-implements.yarn | 200 ++++++++++++++++++++++------------------------ yarns/lib.py | 69 ++++++++++++++++ 3 files changed, 175 insertions(+), 104 deletions(-) create mode 100755 check create mode 100644 yarns/lib.py diff --git a/check b/check new file mode 100755 index 0000000..f4c6167 --- /dev/null +++ b/check @@ -0,0 +1,10 @@ +#!/bin/sh + +set -eu + +yarn yarns/*.yarn \ + --shell python2 \ + --shell-arg '' \ + --shell-library yarns/lib.py \ + --cd-datadir \ + "$@" diff --git a/yarns/900-implements.yarn b/yarns/900-implements.yarn index 2931361..ab3c44c 100644 --- a/yarns/900-implements.yarn +++ b/yarns/900-implements.yarn @@ -20,108 +20,82 @@ we do this by keeping track ourselves of where the scenario wants to be, and changing there when running various commands. IMPLEMENTS WHEN user changes working directory to (\S+) - printf "%s" "$MATCH_1" > "$DATADIR/cwd" + newdir = get_next_match() + olddir = vars['cwd'] or '.' + vars['cwd'] = os.path.abspath(os.path.join(datadir, olddir, newdir)) + print os.listdir('.') + runcmd(['pwd'], cwd=vars['cwd']) IMPLEMENTS WHEN user attempts to run distix ([^$]*) - - # Yarn sets $HOME to point at an empty temporary directory. - # Set up a simple git config so tests can use git. - git config --global user.email 'Tomjon ' - git config --global user.name 'Tomjon Tester' - - cd "$DATADIR" - rm -f attempt.exit attempt.stdout attempt.stderr - cd "$(cat cwd || echo .)" - if "$SRCDIR/distix" --no-default-config --quiet \ - --log "$DATADIR/distix.log" \ - $MATCH_1 \ - > "$DATADIR/attempt.stdout" 2> "$DATADIR/attempt.stderr" - then - echo 0 > "$DATADIR/attempt.exit" - else - echo "$?" > "$DATADIR/attempt.exit" - fi + args = get_next_match() + configure_git() + run_distix(args.split()) IMPLEMENTS WHEN user attempts to run distix show \$PREFIX - # Yarn sets $HOME to point at an empty temporary directory. - # Set up a simple git config so tests can use git. - git config --global user.email 'Tomjon ' - git config --global user.name 'Tomjon Tester' - - cd "$DATADIR" - rm -f attempt.exit attempt.stdout attempt.stderr - cd "$(cat cwd || echo .)" - if "$SRCDIR/distix" --no-default-config --quiet \ - --log "$DATADIR/distix.log" \ - show "$(cat "$DATADIR/tid-prefix")"\ - > "$DATADIR/attempt.stdout" 2> "$DATADIR/attempt.stderr" - then - echo 0 > "$DATADIR/attempt.exit" - else - echo "$?" > "$DATADIR/attempt.exit" - fi + configure_git() + run_distix(['show', vars['tid-prefix']]) IMPLEMENTS WHEN user sets all tickets in (\S+) to (\S+) - cd "$DATADIR/$MATCH_1" - - "$SRCDIR/distix" --no-default-config --quiet \ - --log "$DATADIR/distix.log" list | - awk '/^ / { print $2 }' > "$DATADIR/tickets.list" - - cat "$DATADIR/tickets.list" | - while read ticket - do - "$SRCDIR/distix" --no-default-config --quiet \ - --log "$DATADIR/distix.log" \ - set "$MATCH_2" "$ticket" - done + repo = get_next_match() + keyvalue = get_next_match() + run_distix(['list'], cwd=repo) + list_output = vars['stdout'] + tickets = [ + line.split()[1] + for line in list_output.splitlines() + if line.startswith(' ') + ] + run_distix(['set', keyvalue] + tickets) We also need steps for inspecting the results of attempting to run distix. IMPLEMENTS THEN attempt succeeded - cat "$DATADIR/attempt.exit" - cat "$DATADIR/attempt.stderr" - if ! grep -Fx 0 "$DATADIR/attempt.exit" - then - echo "Attempt should have succeeded, but didn't" 1>&2 - exit 1 - fi + print 'stdout:', repr(vars['stdout']) + print 'stderr:', repr(vars['stderr']) + print 'exit:', vars['exit'] + assert vars['exit'] == 0 IMPLEMENTS THEN output is "(.*)" - cat "$DATADIR/attempt.stdout" - printf "$MATCH_1" > "$DATADIR/temp-stdout" - diff -u "$DATADIR/temp-stdout" "$DATADIR/attempt.stdout" + wanted = unescape(get_next_match()) + output = vars['stdout'] + print 'wanted:', repr(wanted) + print 'output:', repr(output) + assert wanted == unescape(vars['stdout']) IMPLEMENTS THEN output matches "(.*)" - cat "$DATADIR/attempt.stdout" - grep -P -e "$MATCH_1" "$DATADIR/attempt.stdout" + import re + pattern = get_next_match().decode('utf8') + print 'stdout:', repr(vars['stdout']) + print 'pattern:', repr(pattern) + assert re.search(pattern, vars['stdout'], re.M) is not None IMPLEMENTS THEN output doesn't match "(.*)" - cat "$DATADIR/attempt.stdout" - if grep -P -e "$MATCH_1" "$DATADIR/attempt.stdout" - then - echo "$DATADIR/attempt.stdout unexpected matches $MATCH_1" 1>&2 - exit 1 - fi + import re + pattern = get_next_match() + output = unicode(vars['stdout'], 'utf8') + print 'pattern:', repr(pattern) + print 'stdout:', repr(output) + assert re.search(pattern, output) is None IMPLEMENTS THEN first ticket id is captured as \$TID # We assume previous command run was distix list. - # Each line starts with a full ticket id. - awk 'NR == 2 { print $2; exit }' "$DATADIR/attempt.stdout" \ - > "$DATADIR/ticket-id-1" + list_output = vars['stdout'] + tickets = [ + line.split()[1] + for line in list_output.splitlines() + if line.startswith(' ') + ] + vars['tickets'] = tickets + vars['ticket-id-1'] = tickets[0] IMPLEMENTS THEN attempt failed - cat "$DATADIR/attempt.exit" # helps debugging scenarios - if grep -Fx 0 "$DATADIR/attempt.exit" - then - echo "Attempt should have failed, but didn't" 1>&2 - exit 1 - fi + assert vars['exit'] != 0 IMPLEMENTS THEN error message matches (.*) - cat "$DATADIR/attempt.stderr" - grep -e "$MATCH_1" "$DATADIR/attempt.stderr" + import re + pattern = get_next_match() + assert re.search(pattern, vars['stderr']) is not None File creation @@ -131,7 +105,9 @@ We need to provide a way for scenarios to create files with known content. IMPLEMENTS GIVEN file (\S+) containing "(.*)" - printf "$MATCH_2" > "$DATADIR/$MATCH_1" + filename = get_next_match() + content = get_next_match() + write_file(filename, unescape(content).encode('utf8')) Maildir creation @@ -140,14 +116,16 @@ Maildir creation We need to create a maildir with mails in it. IMPLEMENTS GIVEN maildir (\S+) containing a mail with subject "(.+)" - dirname="$DATADIR/$MATCH_1" - mkdir -p "$dirname/new" "$dirname/cur" "$dirname/tmp" - cat < "$dirname/new/message" + dirname = get_next_match() + subject = get_next_match() + mkmaildir(dirname) + mailfile = os.path.join(dirname, 'new', 'msg') + write_file(mailfile, """\ From: user@example.com - Subject: $MATCH_2 + Subject: {subject} Message body goes here. - EOF + """.format(subject=subject).encode('utf8')) File tests ----------- @@ -155,8 +133,8 @@ File tests Does a file or directory exist? IMPLEMENTS THEN (\S+) exists - test -e "$DATADIR/$MATCH_1" - + filename = get_next_match() + assert os.path.exists(filename) Repository/ticket tests ----------------------- @@ -164,18 +142,26 @@ Repository/ticket tests How many tickets does a repository have? IMPLEMENTS THEN repository (\S+) has (\d+) tickets? - n="$(ls "$DATADIR/$MATCH_1/tickets" | wc -l)" - [ "$n" = "$MATCH_2" ] + repo = get_next_match() + count = int(get_next_match()) + ticketdir = os.path.join(repo, 'tickets') + assert len(os.listdir(ticketdir)) == count How many copies of a given message does a repository have? In any tickets? IMPLEMENTS THEN repository (\S+) has one copy of message in (\S+) - find "$DATADIR/$MATCH_1/tickets" -type f -exec md5sum '{}' + \ - > "$DATADIR/md5sums" - msgsum="$(md5sum < "$DATADIR/$MATCH_2" | awk '{ print $1 }')" - n="$(grep -c -e "$msgsum" "$DATADIR/md5sums" | wc -l)" - [ "$n" = 1 ] + repo = get_next_match() + msgfile = get_next_match() + msg = cat_file(msgfile) + tickets = os.path.join(repo, 'tickets') + for dirname, subdirs, basenames in os.walk(repo): + for basename in basenames: + filename = os.path.join(dirname, basename) + candidate = cat_file(filename) + if candidate == msg: + sys.exit(0) + sys.exit(1) Git operations -------------- @@ -183,26 +169,32 @@ Git operations Clone a repository. IMPLEMENTS WHEN user clones (\S+) to (\S+) - cd "$DATADIR" - git clone "$MATCH_1" "$MATCH_2" + url = get_next_match() + dirname = get_next_match() + print repr(vars['cwd']) + print repr(vars._dict) + print runcmd(['pwd']) + print os.listdir('.') + print os.listdir(url) + print repr(['git', 'clone', url, dirname]) + print runcmd(['git', 'clone', url, dirname]) + print runcmd(['pwd'], cwd=dirname) + + Check that everything is in git. IMPLEMENTS THEN everything in (\S+) is committed to git - cd "$DATADIR/$MATCH_1" - if git status --short | grep . - then - echo "Not everything is in git" 1>&2 - exit 1 - fi + ex, out, err = runcmd(['git', 'status', '--short']) + print 'stdout:', repr(out) + assert out == '' Ticket id manipulation ---------------------- IMPLEMENTS THEN ticket id \$TID 7-nybble prefix is \$PREFIX - cut -c1-7 "$DATADIR/ticket-id-1" > "$DATADIR/tid-prefix" + vars['tid-prefix'] = vars['ticket-id-1'][:7] IMPLEMENTS THEN output contains ticket id \$TID - grep -f "$DATADIR/ticket-id-1" "$DATADIR/attempt.stdout" - + assert vars['ticket-id-1'] in vars['stdout'] diff --git a/yarns/lib.py b/yarns/lib.py new file mode 100644 index 0000000..45bcb03 --- /dev/null +++ b/yarns/lib.py @@ -0,0 +1,69 @@ +import os +import sys + +import cliapp + +import yarnutils + +datadir = os.environ['DATADIR'] +srcdir = os.environ['SRCDIR'] + +vars = yarnutils.Variables(datadir) + + + +_next_match = 1 + +def get_next_match(): + global _next_match + name = 'MATCH_{}'.format(_next_match) + _next_match += 1 + return os.environ[name] + + +def cat_file(filename): + with open(filename) as f: + return f.read() + + +def write_file(filename, content): + with open(filename, 'w') as f: + f.write(content) + + +def runcmd(argv, **kwargs): + if 'cwd' not in kwargs: + kwargs['cwd'] = vars['cwd'] + return cliapp.runcmd_unchecked(argv, **kwargs) + + +def configure_git(): + # Yarn sets $HOME to point at an empty temporary directory. + # Set up a simple git config so tests can use git. + runcmd(['git', 'config', '--global', 'user.email', 'tomjon@example.com']) + runcmd(['git', 'config', '--global', 'user.name', 'Tomjon Tester']) + + +def run_distix(args, cwd=None): + if cwd is None: + cwd = vars['cwd'] + + distix = os.path.join(srcdir, 'distix') + log_file = os.path.join(datadir, 'distix.log') + exit_code, out, err = runcmd( + [distix, '--no-default-config', '--quiet', '--log', log_file] + + args, + cwd=cwd) + vars['exit'] = exit_code + vars['stdout'] = out + vars['stderr'] = err + + +def mkmaildir(dirname): + os.makedirs(dirname) + for subdir in ['cur', 'tmp', 'new']: + os.mkdir(os.path.join(dirname, subdir)) + + +def unescape(s): + return '\n'.join(s.split('\\n')) -- cgit v1.2.1