You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@steve.apache.org by ad...@apache.org on 2013/06/13 07:57:20 UTC
svn commit: r1492532 - in /steve/trunk: bin/ cmdline/make_issue.py
cmdline/votegroup.py docs/make.bat lib/steve.py requirements.txt setup.py
src/steve/
Author: adc
Date: Thu Jun 13 05:57:19 2013
New Revision: 1492532
URL: http://svn.apache.org/r1492532
Log:
Cleaned up per suggestions
Added:
steve/trunk/cmdline/votegroup.py
- copied, changed from r1492040, steve/trunk/bin/votegroup
Removed:
steve/trunk/bin/
steve/trunk/docs/make.bat
steve/trunk/src/steve/
Modified:
steve/trunk/cmdline/make_issue.py
steve/trunk/lib/steve.py
steve/trunk/requirements.txt
steve/trunk/setup.py
Modified: steve/trunk/cmdline/make_issue.py
URL: http://svn.apache.org/viewvc/steve/trunk/cmdline/make_issue.py?rev=1492532&r1=1492531&r2=1492532&view=diff
==============================================================================
--- steve/trunk/cmdline/make_issue.py (original)
+++ steve/trunk/cmdline/make_issue.py Thu Jun 13 05:57:19 2013
@@ -115,18 +115,18 @@ def augment_args(args, config):
if args.group is None:
args.group = steve.get_input_line('group name for voters on this issue', True)
if not re.match(r'^\w+$', args.group):
- die('group name must be an alphanumeric token')
+ steve.die('group name must be an alphanumeric token')
if args.start is None:
args.start = steve.get_input_line('YYYYMMDD date that voting starts', True)
if not re.match(r'^[2-9]\d\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])$',
args.start):
- die('start date must be formatted as YYYYMMDD, like 20090930')
+ steve.die('start date must be formatted as YYYYMMDD, like 20090930')
if args.issue is None:
args.issue = steve.get_input_line('short issue name to append to date', True)
if not re.match(r'^\w+$', args.issue):
- die('issue name must be an alphanumeric token')
+ steve.die('issue name must be an alphanumeric token')
if args.file is None:
args.file = steve.get_input_line('file pathname of issue info on %s'
@@ -134,17 +134,17 @@ def augment_args(args, config):
True)
args.file = os.path.realpath(args.file)
if not os.path.exists(args.file):
- die('info file does not exist: %s', args.file)
+ steve.die('info file does not exist: %s', args.file)
if args.file.startswith('/etc/'):
- die('forbidden to read info files from: /etc')
+ steve.die('forbidden to read info files from: /etc')
issue_dir = os.path.realpath(config.issue_dir)
if args.file.startswith(issue_dir + '/'):
- die('forbidden to read info files from: %s', issue_dir)
+ steve.die('forbidden to read info files from: %s', issue_dir)
if args.monitors is None:
args.monitors = steve.get_input_line('e-mail address(es) for vote monitors', True)
if '@' not in args.monitors:
- die('vote monitor must be an Internet e-mail address')
+ steve.die('vote monitor must be an Internet e-mail address')
if args.votetype is None:
args.votetype = steve.get_input_line('vote type; yna, stvN, or selectN (N=1-9)',
@@ -160,25 +160,25 @@ def augment_args(args, config):
args.selector = int(args.votetype[6:])
args.style = 'select %d of the candidates labeled [a-z0-9]' % (args.selector,)
else:
- die('vote type must be yna, stvN, or selectN (N=[1-9])')
+ steve.die('vote type must be yna, stvN, or selectN (N=[1-9])')
def get_voters(args, config):
if not os.path.isdir(config.issue_dir):
- die('cannot find: %s', config.issue_dir)
+ steve.die('cannot find: %s', config.issue_dir)
config.issue_dir += '/' + args.group
if not os.path.isdir(config.issue_dir):
- die('group "%s" has not been created yet, see votegroup', args.group)
+ steve.die('group "%s" has not been created yet, see votegroup', args.group)
if not os.access(config.issue_dir, os.R_OK | os.W_OK | os.X_OK):
- die('you lack permissions on: %s', config.issue_dir)
+ steve.die('you lack permissions on: %s', config.issue_dir)
uid = os.stat(config.issue_dir).st_uid
if uid != os.geteuid():
- die('you are not the effective owner of: %s', config.issue_dir)
+ steve.die('you are not the effective owner of: %s', config.issue_dir)
voters = steve.get_group(config.issue_dir + '/voters')
if not voters:
- die('"%s" must be an existing voter group: see votegroup', args.group)
+ steve.die('"%s" must be an existing voter group: see votegroup', args.group)
return voters
@@ -189,7 +189,7 @@ def create_issue_dir(issue_name, args, c
# Note that .issue_dir already has the group.
config.issue_dir += '/%s-%s' % (args.start, args.issue)
if os.path.exists(config.issue_dir):
- die('already exists: %s', config.issue_dir)
+ steve.die('already exists: %s', config.issue_dir)
os.mkdir(config.issue_dir, 0700)
@@ -328,15 +328,6 @@ def _use_template(template_fname, key, i
return buf.getvalue()
-### keep this? not sure that exceptions would be helpful since there is likely
-### no intent to trap them.
-def die(msg, *args):
- "Print an error message and exit with failure."
-
- print '%s: %s' % (steve.PROG, msg % args)
- sys.exit(1)
-
-
if __name__ == '__main__':
os.umask(0077)
main()
Copied: steve/trunk/cmdline/votegroup.py (from r1492040, steve/trunk/bin/votegroup)
URL: http://svn.apache.org/viewvc/steve/trunk/cmdline/votegroup.py?p2=steve/trunk/cmdline/votegroup.py&p1=steve/trunk/bin/votegroup&r1=1492040&r2=1492532&rev=1492532&view=diff
==============================================================================
--- steve/trunk/bin/votegroup (original)
+++ steve/trunk/cmdline/votegroup.py Thu Jun 13 05:57:19 2013
@@ -17,51 +17,133 @@
# specific language governing permissions and limitations
# under the License.
#
-"""
-A tool for creating a list of voters in the given issue group.
-"""
+# votegroup
+# A program for creating a list of voters in the given issue group
+#
+# o must be run by voter user (see wrapsuid.c for setuid wrapper)
+#
+# o creates a group directory (/home/voter/issues/group/),
+# and adds to it a "voters" file containing a list of e-mail addresses.
+#
+# Originally created by Roy Fielding
+#
+from collections import Counter
import os
+import re
+import subprocess
import sys
+import argparse
+
+import steve
+
+
+def accept_or_exit():
+ while True:
+ answer = steve.get_input_line('"ok" to accept, or "abort" to exit', False)
+ answer = answer.lower()
+ if answer == 'abort':
+ sys.exit(1)
+ if answer == 'ok':
+ return
+
+
+def main():
+ args = parse_argv()
+
+ # Expand the set of arguments (as a side-effect), if they were not provided
+ # on the cmdline.
+ augment_args(args)
+
+ voters = steve.get_group(args.file)
+ if not voters:
+ steve.die('No valid e-mail addresses were found in %s' % (args.file,))
+
+ print 'Here is the list of voter e-mail addresses:'
+ print '=============================================================='
+ for voter in voters:
+ print voter
+ print '=============================================================='
+
+ duplicates = len(voters) - len(set(voters))
+ if duplicates:
+ print 'Found duplicates:\n %s' % '\n '.join([x for x, y in Counter(voters).items() if y > 1])
+ steve.die('%s duplicate voter%s must be removed from the list' % (duplicates, 's' if duplicates > 1 else ''))
+
+ if not args.batch:
+ accept_or_exit()
+
+ diff_voters_file(args)
+
+ create_voters_file(args)
+
+
+def parse_argv():
+ parser = argparse.ArgumentParser(
+ prog=steve.PROG,
+ description='Make an issue for managing an on-line, '
+ 'anonymous voting process',
+ )
+ parser.add_argument('-b', '--batch', action='store_true',
+ help='batch processing: assume "ok" unless errors')
+ parser.add_argument('-g', '--group',
+ help='create an issue for an existing group of voters')
+ parser.add_argument('-f', '--file',
+ help='contains the list of voter e-mail addresses, one per line')
+
+ return parser.parse_args()
+
+
+def augment_args(args):
+ "Update ARGS in-place with missing values."
+
+ if args.group is None:
+ args.group = steve.get_input_line('group name for voters on this issue', True)
+ if not re.match(r'^\w+$', args.group):
+ steve.die('group name must be an alphanumeric token')
+
+ if args.file is None:
+ args.file = steve.get_input_line('file pathname voter e-mail addresses', True)
+ args.file = os.path.realpath(args.file)
+ if not os.path.exists(args.file):
+ steve.die('info file does not exist: %s', args.file)
+ if args.file.startswith('/etc/'):
+ steve.die('forbidden to read info files from: /etc')
+ if args.file.startswith(steve.ISSUE_DIR + os.path.sep):
+ steve.die('forbidden to read info files from: %s', steve.ISSUE_DIR)
+
+
+def _run_cmd(cmd, cwd=None):
+ process = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = process.communicate()
+
+ return process.returncode, stdout + stderr
+
+
+def diff_voters_file(args):
+ VOTERS_FILE = os.path.join(steve.ISSUE_DIR, 'voters')
+ VOTERS_FILE = os.path.join('.', 'voters')
+ if os.path.exists(VOTERS_FILE):
+ _, stdout = _run_cmd(['diff', '-u', VOTERS_FILE, args.file])
+
+ print 'Differences from existing list of voters:'
+ print '=============================================================='
+ print stdout
+ print '=============================================================='
+
+ if not args.batch:
+ accept_or_exit()
+
+ _run_cmd(['mv', '-f', VOTERS_FILE, VOTERS_FILE + os.path.extsep + 'old'])
+
-from asf.cli import entrypoint, prompt_yes_no
-from brownie.datastructures import Counter
+def create_voters_file(args):
+ VOTERS_FILE = os.path.join(steve.ISSUE_DIR, 'voters')
+ VOTERS_FILE = os.path.join('.', 'voters')
-from steve.voters import get_group, hash_file
+ _run_cmd(['cp', args.file, VOTERS_FILE])
+ print '\n\n%s: %s' % (steve.hash_file(VOTERS_FILE), VOTERS_FILE)
-@entrypoint
-def main(cli):
- cli.add_argument('group', help='group name for the voters')
- cli.add_argument('file', help='File containing the list of voter e-mail addresses, one per line')
- cli.add_argument('--non-interactive', action='store_true', dest='no_user_prompt', help='Disables interactive prompting. Assumes \'ok\' unless there are errors.')
-
- cli.register_exception(ValueError, cli.log.error)
-
- with cli.run():
- if not cli.args.group.isalnum():
- raise ValueError('Group name must be an alphanumeric token')
- if not os.path.exists(cli.args.file):
- raise ValueError('Voters list %s does not exist' % (cli.args.file,))
- if cli.args.file.startswith('/etc/'):
- raise ValueError('Must not use files in the /etc directory')
-
- voters = get_group(cli.args.file)
- if not voters:
- raise ValueError('No valid e-mail addresses were found in %s' % (cli.args.file,))
-
- print 'Here is the list of voter e-mail addresses:'
- print '=============================================================='
- for voter in voters:
- print voter
- print '=============================================================='
-
- duplicates = len(voters) - len(set(voters))
- if duplicates:
- print 'Found duplicates:\n %s' % '\n '.join([x for x, y in Counter(voters).items() if y > 1])
- raise ValueError('%s duplicate voters must be removed from the list' % (duplicates,))
-
- if not cli.args.no_user_prompt:
- if not prompt_yes_no('Proceed?', default=True):
- sys.exit(1)
- print '\n\n%s: %s' % (hash_file(cli.args.file), cli.args.file)
+if __name__ == '__main__':
+ main()
Modified: steve/trunk/lib/steve.py
URL: http://svn.apache.org/viewvc/steve/trunk/lib/steve.py?rev=1492532&r1=1492531&r2=1492532&view=diff
==============================================================================
--- steve/trunk/lib/steve.py (original)
+++ steve/trunk/lib/steve.py Thu Jun 13 05:57:19 2013
@@ -26,6 +26,9 @@ import time
import random
import ConfigParser
+HOME_DIR = os.path.join('home', 'voter')
+ISSUE_DIR = os.path.join(HOME_DIR, 'issues')
+
# Strip the .py extension, producing the setuid program name.
PROG = os.path.splitext(os.path.basename(sys.argv[0]))[0]
@@ -45,11 +48,14 @@ def get_input_line(prompt, quittable=Fal
# loop until we get an answer
-def get_group(fname):
- "Return the group of voters, as a set of email addresses."
+def get_group(filename):
+ """ Return the group of voters, as a list of email addresses
+ :param str filename: name of file that contains the group of voter email addresses
+ :rtype list(str): list of voter email addresses
+ """
- group = set()
- for line in open(fname).readlines():
+ group = []
+ for line in open(filename).readlines():
i = line.find('#')
if i >= 0:
line = line[:i]
@@ -58,7 +64,7 @@ def get_group(fname):
continue
if '@' not in line:
raise ValueError('%s: voter must be an Internet e-mail address.' % (line,))
- group.add(line)
+ group.append(line)
return group
@@ -166,3 +172,10 @@ def load_config(fname):
def __init__(self, items):
vars(self).update(items)
return _config(parser.items('general'))
+
+
+def die(msg, *args):
+ "Print an error message and exit with failure."
+
+ print '%s: %s' % (PROG, msg % args)
+ sys.exit(1)
Modified: steve/trunk/requirements.txt
URL: http://svn.apache.org/viewvc/steve/trunk/requirements.txt?rev=1492532&r1=1492531&r2=1492532&view=diff
==============================================================================
--- steve/trunk/requirements.txt (original)
+++ steve/trunk/requirements.txt Thu Jun 13 05:57:19 2013
@@ -1,4 +1 @@
-mock
nose
-
-asf-incubator-tools
Modified: steve/trunk/setup.py
URL: http://svn.apache.org/viewvc/steve/trunk/setup.py?rev=1492532&r1=1492531&r2=1492532&view=diff
==============================================================================
--- steve/trunk/setup.py (original)
+++ steve/trunk/setup.py Thu Jun 13 05:57:19 2013
@@ -102,11 +102,11 @@ setup(
# don't ever depend on refcounting to close files anywhere else
long_description=open('README', encoding='utf-8').read(),
- scripts=["bin/votegroup"],
+ # scripts=["bin/votegroup"],
- namespace_packages=['steve'],
- package_dir={'': 'src'},
- packages=find_packages('src'),
+ # namespace_packages=['steve'],
+ package_dir={'': 'lib'},
+ packages=find_packages('lib'),
zip_safe=False,
platforms='any',