Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/freebsd/freebsd-ports.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorTobias C. Berner <tcberner@FreeBSD.org>2022-11-11 23:10:34 +0300
committerTobias C. Berner <tcberner@FreeBSD.org>2022-11-11 23:18:53 +0300
commit95fe54732a25fcf021f52574bb400a862230f129 (patch)
tree4428c4ec2fdadf590e3b473389f4047b6c5e4c98 /misc
parent7b5781edc5684a31c0bf34157d69219907b03053 (diff)
misc/vote: cleanup port
- fix wrong version number inside script Reported by: diizzy
Diffstat (limited to 'misc')
-rw-r--r--misc/vote/0001-misc-vote-cleanup-port.patch55
-rw-r--r--misc/vote/Makefile13
-rw-r--r--misc/vote/distinfo6
-rw-r--r--misc/vote/fetch.out723
4 files changed, 791 insertions, 6 deletions
diff --git a/misc/vote/0001-misc-vote-cleanup-port.patch b/misc/vote/0001-misc-vote-cleanup-port.patch
new file mode 100644
index 000000000000..2a42eea651b1
--- /dev/null
+++ b/misc/vote/0001-misc-vote-cleanup-port.patch
@@ -0,0 +1,55 @@
+From 33a1a9ccf0df2fc73cd8d85ab4bcdbf585dce94b Mon Sep 17 00:00:00 2001
+From: "Tobias C. Berner" <tcberner@FreeBSD.org>
+Date: Fri, 11 Nov 2022 21:10:34 +0100
+Subject: [PATCH] misc/vote: cleanup port
+
+Reported by: diizzy
+---
+ misc/vote/Makefile | 12 +++++++++---
+ misc/vote/distinfo | 6 +++---
+ 2 files changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/misc/vote/Makefile b/misc/vote/Makefile
+index 9f9a4b897479..e851900e94c7 100644
+--- a/misc/vote/Makefile
++++ b/misc/vote/Makefile
+@@ -1,16 +1,22 @@
+ PORTNAME= vote
+-DISTVERSION= 1.1
++DISTVERSION= 1.2
+ CATEGORIES= misc
+-MASTER_SITES= https://codeberg.org/tcberner/${PORTNAME}/archive/
++MASTER_SITES= https://codeberg.org/tcberner/${PORTNAME}/raw/v${DISTVERSION}/
++DISTFILES= ${PORTNAME}
++DIST_SUBDIR= vote-${DISTVERSION}
++EXTRACT_ONLY=
+
+ MAINTAINER= tcberner@FreeBSD.org
+ COMMENT= Transparent git based voting system
+
++LICENSE= BSD2CLAUSE
++
++NO_ARCH= yes
+ NO_BUILD= yes
+
+ PLIST_FILES= bin/vote
+
+ do-install:
+- ${INSTALL_SCRIPT} ${WRKDIR}/vote/vote ${STAGEDIR}${PREFIX}/bin
++ ${INSTALL_SCRIPT} ${DISTDIR}/${DIST_SUBDIR}/vote ${STAGEDIR}${PREFIX}/bin
+
+ .include <bsd.port.mk>
+diff --git a/misc/vote/distinfo b/misc/vote/distinfo
+index d9414c8ce104..05be2b48d93c 100644
+--- a/misc/vote/distinfo
++++ b/misc/vote/distinfo
+@@ -1,3 +1,3 @@
+-TIMESTAMP = 1668195518
+-SHA256 (vote-1.1.tar.gz) = de2ad0d28cf777239fdb7e6c7c44a5dda528283bef6b807ade5ca02246497705
+-SIZE (vote-1.1.tar.gz) = 5196
++TIMESTAMP = 1668197328
++SHA256 (vote-1.2/vote) = 4c0769cd4ea4578f4d72377afd1404ae0cc08cd8008486557aa4f17eadbeca0e
++SIZE (vote-1.2/vote) = 16615
+--
+2.38.1
+
diff --git a/misc/vote/Makefile b/misc/vote/Makefile
index 9f9a4b897479..db31d0f28693 100644
--- a/misc/vote/Makefile
+++ b/misc/vote/Makefile
@@ -1,16 +1,23 @@
PORTNAME= vote
-DISTVERSION= 1.1
+DISTVERSION= 1.2
CATEGORIES= misc
-MASTER_SITES= https://codeberg.org/tcberner/${PORTNAME}/archive/
+MASTER_SITES= https://codeberg.org/tcberner/${PORTNAME}/raw/v${DISTVERSION}/
+DISTFILES= ${PORTNAME}
+DIST_SUBDIR= vote-${DISTVERSION}
+EXTRACT_ONLY= #
MAINTAINER= tcberner@FreeBSD.org
COMMENT= Transparent git based voting system
+WWW= https://codeberg.org/tcberner/vote
+LICENSE= BSD2CLAUSE
+
+NO_ARCH= yes
NO_BUILD= yes
PLIST_FILES= bin/vote
do-install:
- ${INSTALL_SCRIPT} ${WRKDIR}/vote/vote ${STAGEDIR}${PREFIX}/bin
+ ${INSTALL_SCRIPT} ${DISTDIR}/${DIST_SUBDIR}/vote ${STAGEDIR}${PREFIX}/bin
.include <bsd.port.mk>
diff --git a/misc/vote/distinfo b/misc/vote/distinfo
index d9414c8ce104..05be2b48d93c 100644
--- a/misc/vote/distinfo
+++ b/misc/vote/distinfo
@@ -1,3 +1,3 @@
-TIMESTAMP = 1668195518
-SHA256 (vote-1.1.tar.gz) = de2ad0d28cf777239fdb7e6c7c44a5dda528283bef6b807ade5ca02246497705
-SIZE (vote-1.1.tar.gz) = 5196
+TIMESTAMP = 1668197328
+SHA256 (vote-1.2/vote) = 4c0769cd4ea4578f4d72377afd1404ae0cc08cd8008486557aa4f17eadbeca0e
+SIZE (vote-1.2/vote) = 16615
diff --git a/misc/vote/fetch.out b/misc/vote/fetch.out
new file mode 100644
index 000000000000..925be6ae4b9c
--- /dev/null
+++ b/misc/vote/fetch.out
@@ -0,0 +1,723 @@
+#!/bin/sh
+
+VERSION=1.0
+
+#
+# Simple git based voting system
+#
+# if $VOTE_DIR is no defined the checkout happens in the shell-script directory
+#
+# To setup a new shared VOTE_DIR, use:
+# freefall> git init --bare /path/to/votes.git
+# local> git clone freefall:/path/to/votes.git votes
+# local> cd votes
+# local> git checkout -b main
+# Create the voters file (username:Name <email>)
+# local> git add voters
+# local> git commit -m "Initialize votes directory"
+# local> git push -u origin main:main
+#
+#
+# The mark_* and color_* values can be overriden in ~/.voterc
+#
+col_reset="\033[0m"
+# Color used to to show the output of shelled-out git calls.
+col_git="\033[32m"
+# Color for highlights within the script
+col_highlight="\033[33m"
+
+mark_ys="👍"
+mark_no="👎"
+mark_ab="💁"
+mark_dn="💤"
+
+mark_op="🔓"
+mark_cl="🔒"
+
+###
+base_dir="$(dirname $(realpath $0))"
+vote_dir="${VOTE_DIR:-${base_dir}/votes}"
+
+###
+text_ys="y"
+text_no="n"
+text_ab="a"
+text_dn="-"
+
+text_op="o"
+text_op="c"
+
+###
+if [ -f ~/.voterc ] ; then
+ . ~/.voterc ;
+fi
+
+###
+__message () {
+ echo -e "$@"
+}
+
+__error () {
+ echo -e "$@" >&2
+ exit 1
+}
+__usage() {
+ __error "No command given. Available commands are:\n\n" \
+ "- help\t\tShow this message:\n" \
+ "\t\t${col_highlight}% vote help${col_reset}\n\n" \
+ "- init\t\tInitialize a repository:\n" \
+ "\t\t${col_highlight}% vote init <url>${col_reset}\n" \
+ "- update\tUpdate the repository:\n" \
+ "\t\t${col_highlight}% vote update${col_reset}\n\n" \
+ "- list\t\tList current ongoing votes:\n" \
+ "\t\t${col_highlight}% vote list${col_reset}\n" \
+ "- all\t\tList all votes:\n" \
+ "\t\t${col_highlight}% vote all${col_reset}\n" \
+ "- info\t\tShow information on a vote:\n" \
+ "\t\t${col_highlight}% vote info <vid>${col_reset}\n\n" \
+ "- create\tCreate a new vote:\n" \
+ "\t\t${col_highlight}% vote create <subject> <duedate> <further description>${col_reset}\n" \
+ "- close\tMark a vote as closed:\n" \
+ "\t\t${col_highlight}% vote close <vid>${col_reset}\n" \
+ "- reopen\tReopen a vote:\n" \
+ "\t\t${col_highlight}% vote reopen <vid>${col_reset}\n\n" \
+ "- changedate\tChange the Due Date to something new\n" \
+ "\t\t${col_highlight}% vote changedate <vid> <date>${col_reset}\n" \
+ "- changesubject\tChange the Subject to something new\n" \
+ "\t\t${col_highlight}% vote changesubject <vid> <subject>${col_reset}\n\n" \
+ "- vote\t\tPlace a vote:\n" \
+ "\t\t${col_highlight}% vote vote <vid> <yes/no/abstain>${col_reset}\n" \
+ "- votefor\tPlace a vote for another person:\n" \
+ "\t\t${col_highlight}% vote votefor <vid> <yes/no/abstain> <voter>${col_reset}\n\n" \
+ "The checkout directory can be overridden using then ${col_highlight}VOTE_DIR${col_reset}\n" \
+ "\n" \
+ "Vote version ${VERSION}."
+}
+
+__want_args() {
+ local count=$1
+ shift
+
+ if [ $# -ne ${count} ] ; then
+ __error "Expected ${count} arguments, but got $#."
+ fi
+}
+
+__username () {
+ __want_args 1 "$@"
+ local vote_dir="$1"
+
+ username=$(git -C ${vote_dir} config user.email | awk -F '@' '{print $1}')
+ if [ $? -eq 0 ] ; then
+ echo "${username}"
+ return 0
+ fi
+
+ __error "Could not evaluate git user name"
+}
+
+__setup_voters() {
+ __want_args 2 "$@"
+ local votes_dir="$1"
+ local voters="$2"
+
+ if [ -d ${votes_dir} ] ; then
+ if [ -f ${voters} ] ; then
+ for voter in $(awk -F ':' '{print $1}' ${voters}) ; do
+ ln -s zzz ${votes_dir}/${voter}
+ done
+ fi
+ fi
+}
+
+# Managing votes
+create_vote () {
+ __want_args 4 "$@"
+ local vote_dir="$1"
+ update_votes "${vote_dir}"
+
+ local subject="$2"
+ local duedate="$3"
+ local description="$4"
+
+ if [ $? -ne 0 ] ; then
+ __error "Could not update votes prior to creation"
+ fi
+
+ local vid=$(__next_vid "${vote_dir}")
+ local voters=$(awk -F ':' 'BEGIN{OFS=":"}{print " ",$0}' ${vote_dir}/voters | column -t -s ':')
+ local commit_message=$(printf "<${vid}> [CREATE] ${subject} (${duedate})\n\n${description}\n\nVoters:\n${voters}\n")
+ echo -e "${col_git}"
+ cd ${vote_dir} && \
+ mkdir -p ${vid} && \
+ cd ${vid} && \
+ echo "${subject}" > subject && \
+ echo "${duedate}" > duedate && \
+ echo "${description} " > description && \
+ mkdir votes && \
+ __setup_voters $(realpath votes) $(realpath ${vote_dir}/voters) && \
+ git add subject duedate description votes && \
+ git commit -m "${commit_message}" && \
+ git push
+ echo -e "${col_reset}"
+
+ __message ""
+ __pretty_print ${vote_dir} ${vid}
+}
+
+change_date () {
+ __want_args 3 "$@"
+ local vote_dir="$1"
+ update_votes "${vote_dir}"
+ local vid=$(__make_vid "$2")
+ local newdate="$3"
+
+ open=$(__is_open_vote ${vote_dir} ${vid})
+ if [ $? -ne 0 ] ; then
+ __error "Cannot modify a closed vote. ${vote_dir} ${vid}"
+ fi
+ local olddate=$(cat ${vote_dir}/${vid}/duedate)
+
+ local commit_message=$(printf "<${vid}> [CHANGE DATE] ${subject} (${olddate}->${newdate})\n")
+ echo -e "${col_git}"
+ cd ${vote_dir} && \
+ cd ${vid} && \
+ echo "${newdate}" > duedate && \
+ git add duedate && \
+ git commit -m "${commit_message}" && \
+ git push
+ echo -e "${col_reset}"
+
+ list_votes ${vote_dir}
+}
+
+change_subject () {
+ __want_args 3 "$@"
+ local vote_dir="$1"
+ update_votes "${vote_dir}"
+ local vid=$(__make_vid "$2")
+ local newsubject="$3"
+
+ open=$(__is_open_vote ${vote_dir} ${vid})
+ if [ $? -ne 0 ] ; then
+ __error "Cannot modify a closed vote. ${vote_dir} ${vid}"
+ fi
+ local oldsubject=$(cat ${vote_dir}/${vid}/subject)
+
+ local commit_message=$(printf "<${vid}> [CHANGE DATE] ${oldsubject} -> ${newsubject}\n")
+ echo -e "${col_git}"
+ cd ${vote_dir} && \
+ cd ${vid} && \
+ echo "${newsubject}" > subject && \
+ git add subject && \
+ git commit -m "${commit_message}" && \
+ git push
+ echo -e "${col_reset}"
+
+ list_votes ${vote_dir}
+}
+
+
+info_vote () {
+ __want_args 2 "$@"
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+
+ __pretty_print ${vote_dir} ${vid}
+}
+
+__is_open_vote () {
+ __want_args 2 "$@"
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+
+ if [ -f ${vote_dir}/${vid}/closeddate ] ; then
+ return 1
+ fi
+ return 0
+}
+
+__set_vote() {
+ __want_args 4 "$@"
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+ local username="$3"
+ local value="$4"
+
+ open=$(__is_open_vote ${vote_dir} ${vid})
+ if [ $? -ne 0 ] ; then
+ __error "Cannot vote on a closed vote. ${vote_dir} ${vid}"
+ fi
+
+ if [ ! -L ${vote_dir}/${vid}/votes/${username} ] ; then
+ __error "Invalid voter ${username}"
+ fi
+
+ local target=""
+ case "${value}" in
+ "yes") target="yes" ;;
+ "no") target="no" ;;
+ "abstain") target="abstain" ;;
+ *) __error "Invalid vote '${value}' (valid: yes, no, abstain)" ;;
+ esac
+
+ result=$(cd ${vote_dir}/${vid}/votes && ln -sf ${value} ${username})
+ return $?
+}
+
+__short_result () {
+ __want_args 2 "$@"
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+
+ echo $(__tally_vote ${vote_dir} ${vid})
+ return 0
+}
+__pretty_print () {
+ __want_args 2 "$@"
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+
+ local subject=$(cat ${vote_dir}/${vid}/subject)
+
+ local y_voters=""
+ local n_voters=""
+ local a_voters=""
+ local d_voters=""
+ for vote in $(find -s ${vote_dir}/${vid}/votes -type l) ; do
+ value=$(readlink ${vote})
+ voter=$(basename ${vote})
+ case "${value}" in
+ "yes")
+ y_voters="${y_voters}${y_voters:+, }${voter}"
+ ;;
+ "no")
+ n_voters="${n_voters}${n_voters:+, }${voter}"
+ ;;
+ "abstain")
+ a_voters="${a_voters}${a_voters:+, }${voter}"
+ ;;
+ "zzz")
+ d_voters="${d_voters}${d_voters:+, }${voter}"
+ ;;
+ *) __error "Invalid vote value ${value} in ${vote} (${vid})"
+ esac
+ done
+
+ result=$(printf "Vote on ${subject}.\n\nYes:\t\t${y_voters}\nNo:\t\t${n_voters}\nAbstained:\t${a_voters}\n\nDid not vote:\t${d_voters}")
+
+ echo "${result}"
+ return 0
+}
+
+reopen_vote () {
+ __want_args 2 "$@"
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+
+ open=$(__is_open_vote ${vote_dir} ${vid})
+ if [ $? -eq 0 ] ; then
+ __error "Vote already open"
+ fi
+
+ local closeddate=$(cat ${vote_dir}/${vid}/closeddate)
+ rm ${vote_dir}/${vid}/closeddate
+
+ local tally=$(__short_result ${vote_dir} ${vid})
+ local pretty=$(__pretty_print ${vote_dir} ${vid})
+ local commit_message=$(printf "<${vid}> [REOPEN] ${tally}\n\n${pretty}\nOld Closed Date:\t${closeddate}")
+
+ echo -e "${col_git}"
+ cd ${vote_dir} && \
+ git add ${vote_dir}/${vid}/closeddate && \
+ git commit -m "${commit_message}" && \
+ git push
+ echo -e "${col_reset}"
+
+ __pretty_print ${vote_dir} ${vid}
+ return 0
+}
+
+close_vote () {
+ __want_args 2 "$@"
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+
+ open=$(__is_open_vote ${vote_dir} ${vid})
+ if [ $? -ne 0 ] ; then
+ __error "Vote already closed"
+ fi
+
+ echo $(date -u '+%Y%m%d') > ${vote_dir}/${vid}/closeddate
+
+ local tally=$(__short_result ${vote_dir} ${vid})
+ local pretty=$(__pretty_print ${vote_dir} ${vid})
+ local commit_message=$(printf "<${vid}> [CLOSE] ${tally}\n\n${pretty}")
+
+ echo -e "${col_git}"
+ cd ${vote_dir} && \
+ git add ${vote_dir}/${vid}/closeddate && \
+ git commit -m "${commit_message}" && \
+ git push
+ echo -e "${col_reset}"
+
+ __pretty_print ${vote_dir} ${vid}
+ return 0
+}
+
+# Interacting with votes
+init_votes () {
+ __want_args 2 "$@"
+ local vote_dir="$1"
+ local url="$2"
+
+ if [ -d "${vote_dir}" ] ; then
+ __error "Directory '${vote_dir}' already exists."
+ fi
+
+ echo -e "${col_git}"
+ git clone ${url} ${vote_dir}
+ if [ $? -ne 0 ] ; then
+ echo -e "${col_reset}"
+ __error "Could not clone ${url} to ${vote_dir}"
+ fi
+ echo -e "${col_reset}"
+
+ list_all_votes ${vote_dir}
+ return 0
+}
+
+update_votes () {
+ __want_args 1 "$@"
+
+ local vote_dir="$1"
+ __check_git ${vote_dir}
+ if [ $? -ne 0 ] ; then
+ __error "Directory '${vote_dir}' is not a repository."
+ fi
+
+ echo -e "${col_git}"
+ cd "${vote_dir}" && git pull --rebase --autostash
+ if [ $? -ne 0 ] ; then
+ echo -e "${col_reset}"
+ __error "Failed to update '${vote_dir}' -- please try manual merge."
+ fi
+ echo -e "${col_reset}"
+
+ list_votes ${vote_dir}
+
+ return 0
+}
+
+__list_vids () {
+ local vote_dir="$1"
+
+ vids=$(find -E "${vote_dir}" -type d -regex ".*/[0-9][0-9][0-9][0-9]$" | sort | awk -F '/' '{print $NF}')
+
+ if [ $? -ne 0 ] ; then
+ __error "Failed to enumerate vids"
+ fi
+
+ echo "${vids}"
+ return 0
+}
+
+__last_vid () {
+ local vote_dir="$1"
+ result=$(__list_vids "${vote_dir}" | tail -n1)
+ echo ${result}
+}
+
+__make_vid () {
+ __want_args 1 "$@"
+ echo $(printf "%04d" $(expr $1 + 0))
+ return 0
+}
+
+__next_vid () {
+ __want_args 1 "$@"
+
+ local vote_dir="$1"
+ last=$(__last_vid "${vote_dir}")
+ if [ -z ${last} ] ; then
+ last=0
+ fi
+
+ echo $(__make_vid $(expr ${last} + 1))
+ return 0
+}
+
+__list_vote_entry () {
+ __want_args 3 "$@"
+
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+ local include_closed="$3"
+
+ if [ ! -d ${vote_dir}/${vid} ] ; then
+ __error "Failed to read info on ${vid} from ${vote_dir}"
+ fi
+
+ local state=${mark_cl}
+ __is_open_vote ${vote_dir} ${vid}
+ if [ $? -eq 0 ] ; then
+ state=${mark_op}
+ fi
+ local duedate=$(cat ${vote_dir}/${vid}/duedate)
+ local subject=$(cut -c 1-50 ${vote_dir}/${vid}/subject)
+ local votes=$(__tally_vote ${vote_dir} ${vid})
+ local own_vote=$(__own_vote ${vote_dir} ${vid})
+ local closed_info=""
+ if [ "${include_closed}" = "yes" ] ; then
+ if [ -f ${vote_dir}/${vid}/closeddate ] ; then
+ closed_info="|$(cat ${vote_dir}/${vid}/closeddate)"
+ else
+ closed_info="|"
+ fi
+ fi
+ echo "${state}|${duedate}|${vid}|${subject}|${votes}|${own_vote}${closed_info}"
+}
+
+__vote_mark () {
+ __want_args 1 "$@"
+
+ local result=${mark_dn}
+ case "$1" in
+ "yes") result=${mark_ys} ;;
+ "no") result=${mark_no} ;;
+ "abstain") result=${mark_ab} ;;
+ esac
+ echo "${result}"
+}
+
+__vote_text() {
+ __want_args 1 "$@"
+
+ local result=${text_dn}
+ case "$1" in
+ "yes") result=${text_ys} ;;
+ "no") result=${text_no} ;;
+ "abstain") result=${text_ab} ;;
+ esac
+ echo "${result}"
+}
+
+__get_vote () {
+ __want_args 3 "$@"
+
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+ local username="$3"
+
+ if [ ! -d ${vote_dir}/${vid} ] ; then
+ __error "Failed to read info on ${vid} from ${vote_dir}"
+ fi
+
+ local uservote=""
+
+ local vote=${vote_dir}/${vid}/votes/${username}
+ voted=1
+
+ local result=${mark_dn}
+ if [ -L ${vote} ] ; then
+ vote_value=$(readlink ${vote})
+ if [ "${vote_value}" != "zzz" ] ; then
+ voted=0
+ fi
+ result=$(__vote_mark ${vote_value})
+ fi
+
+ echo "${result}"
+ return ${voted}
+}
+
+__own_vote () {
+ __want_args 2 "$@"
+
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+
+ local username=$(__username ${vote_dir})
+ local result=$(__get_vote ${vote_dir} ${vid} ${username})
+
+ echo "${result}"
+ return 0
+}
+
+
+__tally_vote () {
+ __want_args 2 "$@"
+
+ local vote_dir="$1"
+ local vid=$(__make_vid "$2")
+
+ if [ ! -d ${vote_dir}/${vid} ] ; then
+ __error "Failed to read info on ${vid} from ${vote_dir}"
+ fi
+
+ local count_yes=0
+ local count_no=0
+ local count_abstain=0
+ local count_dnv=0
+
+ for vote in $(find ${vote_dir}/${vid}/votes -type l) ; do
+ value=$(readlink ${vote})
+ voter=$(basename ${vote})
+ case "${value}" in
+ "yes") count_yes=$(expr ${count_yes} + 1) ;;
+ "no") count_no=$(expr ${count_no} + 1) ;;
+ "abstain") count_abstain=$(expr ${count_abstain} + 1) ;;
+ "zzz") count_dnv=$(expr ${count_dnv} + 1) ;;
+ *) __error "Invalid vote value ${value} in ${vote} (${vid})"
+ esac
+ done
+
+ result=$(printf "${mark_ys}%2d, ${mark_no}%2d, ${mark_ab}%2d, ${mark_dn}%2d" ${count_yes} ${count_no} ${count_abstain} ${count_dnv})
+ echo "${result}"
+
+ return 0
+}
+
+list_votes () {
+ __want_args 1 "$@"
+ local vote_dir="$1"
+
+ result=""
+ for vid in $(__list_vids "$@") ; do
+ __is_open_vote ${vote_dir} ${vid}
+ if [ $? -eq 0 ] ; then
+ result="${result}\n$(__list_vote_entry ${vote_dir} ${vid} no)"
+ fi
+ done
+
+ result=$(echo -e "${result}" | sort -r)
+ result=$(printf "State|Due Date|VID|Subject|Tally|Own Vote\n${result}")
+ echo "${result}" | column -t -s '|'
+}
+
+
+list_all_votes () {
+ __want_args 1 "$@"
+ local vote_dir="$1"
+
+ result=""
+ for vid in $(__list_vids "$@") ; do
+ result="${result}\n$(__list_vote_entry ${vote_dir} ${vid} yes)"
+ done
+
+ result=$(echo -e "${result}" | sort -r)
+ result=$(printf "State|Due Date|VID|Subject|Tally|Own Vote|Closed On\n${result}")
+ echo "${result}" | column -t -s '|'
+}
+
+place_vote () {
+ __vote "$@"
+}
+
+place_vote_for () {
+ __vote_for "$@"
+}
+
+__vote_for () {
+ __want_args 4 "$@"
+ local vote_dir="$1"
+ update_votes "${vote_dir}"
+
+ local vid=$(__make_vid "$2")
+ local value="$3"
+ local username="$4"
+
+ if [ ! -L ${vote_dir}/${vid}/votes/${username} ] ; then
+ __error "Invalid voter ${username}"
+ fi
+
+ local author=$(awk -F : "/${username}/{print \$NF}" ${vote_dir}/voters)
+ if [ -z "${author}" ] ; then
+ __error "Could not read author for ${username}"
+ fi
+
+ local action=""
+ local msg=""
+ oldvote=$(__get_vote ${vote_dir} ${vid} ${username})
+ if [ $? -eq 0 ] ; then
+ action="[CHANGE VOTE]"
+ message="${oldvote} -> $(__vote_text ${value})"
+ else
+ action="[SET VOTE]"
+ message="$(__vote_text ${value})"
+ fi
+
+ local foreignvote=""
+ gituser=$(__username ${vote_dir})
+ if [ ${username} != ${gituser} ] ; then
+ foreignvote=" (vote placed by ${gituser})"
+ fi
+
+ __set_vote "${vote_dir}" "${vid}" "${username}" "${value}"
+ if [ $? -ne 0 ] ; then
+ __error "Could not place vote ${value} on ${vid}"
+ fi
+
+ local subject=$(cut -c 1-50 ${vote_dir}/${vid}/subject)
+
+ local commit_message=$(printf "<${vid}> ${action} ${subject} :: ${username} ${message}${foreignvote}\n\n$(__pretty_print ${vote_dir} ${vid})")
+
+ echo -e "${col_git}"
+ cd ${vote_dir} && \
+ git add ${vid}/votes/${username} && \
+ git commit -m "${commit_message}" --author="${author}" && \
+ git push
+ echo -e "${col_reset}"
+
+ __message ""
+ __pretty_print ${vote_dir} ${vid}
+}
+
+
+__vote () {
+ __want_args 3 "$@"
+ local username=$(__username ${vote_dir})
+ if [ -z "${username}" ] ; then
+ __error "Could not read your git username"
+ fi
+ __vote_for "$@" ${username}
+}
+
+# utils
+__check_git () {
+ local git_dir=$(realpath "$1")
+ if [ ! -d "${git_dir}" ] ; then
+ return 1
+ fi
+ (
+ cd "${git_dir}"
+ git rev-parse --is-inside-work-tree > /dev/null 2>&1
+ if [ $? -ne 0 ] ; then
+ return 1
+ fi
+ )
+ return 0
+}
+
+if [ -z $1 ] ; then
+ __usage
+fi
+
+command=$1
+shift
+case "${command}" in
+ "help") __usage ;;
+ "init") init_votes ${vote_dir} "$@" ;;
+ "update") update_votes ${vote_dir} ;;
+ "list") list_votes ${vote_dir} ;;
+ "all") list_all_votes ${vote_dir} ;;
+ "create") create_vote ${vote_dir} "$@" ;;
+ "info") info_vote ${vote_dir} "$@" ;;
+ "close") close_vote ${vote_dir} "$@" ;;
+ "reopen") reopen_vote ${vote_dir} "$@" ;;
+ "changedate") change_date ${vote_dir} "$@" ;;
+ "changesubject") change_subject ${vote_dir} "$@" ;;
+ "vote") place_vote ${vote_dir} "$@" ;;
+ "votefor") place_vote_for ${vote_dir} "$@" ;;
+ *) __usage ;;
+esac