#!/bin/sh
#
# File: mtbrowse.sh
# Description: Text based browser for monotone source control.
# url: http://www.monotone.ca/
# Licence: GPL
# Author: Henry Nestler <Henry at BigFoot.de>
#
# Simple text based browser for Monotone repositories, written as shell script.
# Can select branch, revision. Views diff from revision, logs, certs and more.
# Base is dialog function and "automate" command of Monotone, with some
# sorting and grepping functionaly.
#
# To use:
# - Copy this script into a bin PATH
# - Run from working copy of existing project.
# Or give full filename to database.
# - Change your configuration
# Delete the "VISUAL", to use the "PAGER", deleto both for internal viewer.
# Save configuration.
# - Begin with menu "S Select revision"
# - Browse in branches, revisions, diff files, view logs ...
#
# Needed tools:
# Monotone (tested 0.19, 0.23, mtn 0.26-0.33)
# dialog (tested Version 0.9b)
# bash, sh, dash
# less, vi or vim (use $VISUAL or $PAGER)
# cat, cut, echo, eval, head, sort, tail, tr, wc, xargs ...
#
# Known Bugs / ToDo-List:
# * better make "sed -n -e '1p'" for merge two different branches.
VERSION="0.3.0"
# Binary
MTN="mtn"
# Save users settings
# Default values, can overwrite on .mtbrowserc
CONFIGFILE="$HOME/.mtbrowserc"
# Store lists for menu here
TEMPDIR="$HOME/.mtbrowse"
TEMPFILE="$TEMPDIR/tmp"
# Called with filename.
VISUAL="vim -R"
# Called with stdin redirection.
# Set VISUAL empty to use PAGER!
# If VISUAL and PAGER are empty, than use an internal viewer.
PAGER="less"
# 1=Certs Cached, 0=Clean at end (slow and save mode)
CACHE="1"
# T=Toposort revisions, D=Date sort, R=Date reverse (reverse toposort),
# N=None (unsorted from list)
TOPOSORT="T"
# count of certs to get from DB, "0" for all
CERTS_MAX="20"
# Trim hash code
HASH_TRIM="10"
# Format for Date/Time
FORMAT_DATE="L"
# Format Branch: F=Full,S=Short,N=None
FORMAT_BRANCH="N"
# Format author: F=Full, S=strip domain from mail address, N=None
FORMAT_AUTHOR="S"
# Changelog format
FORMAT_LOG="F"
# Author coloring?
FORMAT_COLOR="\\Z7\\Zb"
# How get automate ancestors: I=interal function, A=automate ancestors,
# L=log brief with changelog, B=brief log
ANCESTORS="L"
# Don't view merges. Can overwrite in .mtbrowserc
NOMERGES="--no-merges"
# read saved settings
if [ -f $CONFIGFILE ]
then
. $CONFIGFILE
fi
# Clear cached files
do_clear_cache()
{
rm -f $TEMPFILE.certs.$BRANCH \
$TEMPFILE.changelog.$BRANCH
}
# clear temp files
do_clear_on_exit()
{
rm -f $TEMPFILE.branches $TEMPFILE.ancestors $TEMPFILE.toposort \
$TEMPFILE.action-select $TEMPFILE.menu $TEMPFILE.input \
$TEMPFILE.ncolor $TEMPFILE.tfc $TEMPFILE.error
if [ "$CACHE" != "1" ]
then
do_clear_cache
fi
}
# View any file (with vim, less or dialog)
do_pager()
{
if [ -n "$VISUAL" ]
then
$VISUAL $1
elif [ -n "$PAGER" ]
then
$PAGER < $1
else
dialog --textbox $1 0 0
fi
rm $1
}
# Add the date, author and changlog to the list of revisions
# Scanning for:
# Key : name@domain.de
# Sig : ok
# Name : date
# Value : 2005-05-31T22:29:50 <<---
# --------------------------------------
# Key : name@domain.de
# Sig : ok
# Name : changelog
# Value : Handle merged parents <<---
# Output
# 123456 "2005-05-31 22:29 name@domain.de Handle merged parents"
fill_date_key()
{
local in_file=$1
local out_file=$2
local hash short_hash dat bra aut log lineno color tfc
line_count=`wc -l < $in_file`
if [ "$line_count" -eq 0 ]
then
unset line_count
fi
lineno=0
rm -f $out_file
tfc=$TEMPFILE.tfc
# Read Key and Date value from certs
cat $in_file | \
while read hash
do
if [ -n "$line_count" ]
then
lineno=$(( $lineno+1 ))
echo "$(( 100*$lineno/$line_count ))"
else
echo -n "." 1>&2
fi
short_hash=`echo $hash | cut -c 1-$HASH_TRIM`
# get certs of revision, remove special chars, cache it
LANG=POSIX $MTN --db=$DB list certs $hash | tr '\\\t\042' '/ \047' > $tfc
# Date format
case $FORMAT_DATE in
F) # 2005-12-31T23:59:59
dat=`sed -n -r -e \
'/^Name : date/,+1s/Value : (.+)$/\1 /p' \
< $tfc | sed -n -e '1p'`
;;
L) # 2005-12-31 23:59
dat=`sed -n -r -e \
'/^Name : date/,+1s/Value : (.{10})T(.{5}).+$/\1 \2 /p' \
< $tfc | sed -n -e '1p'`
;;
D) # 2005-12-31
dat=`sed -n -r -e \
'/^Name : date/,+1s/Value : (.+)T.+$/\1 /p' \
< $tfc | sed -n -e '1p'`
;;
S) # 12-31 23:59
dat=`sed -n -r -e \
'/^Name : date/,+1s/Value : .{4}-(.+)T(.{5}).+$/\1 \2 /p' \
< $tfc | sed -n -e '1p'`
;;
T) # 23:59:59
dat=`sed -n -r -e \
'/^Name : date/,+1s/Value : .{10}T(.+{8})$/\1 /p' \
< $tfc | sed -n -e '1p'`
;;
esac
# Branch format
case $FORMAT_BRANCH in
F) # full
bra=`sed -n -r -e \
'/^Name : branch/,+1s/Value :(.+)$/\1 /p' \
< $tfc | sed -n -e '1p'`
;;
S) # short
bra=`sed -n -r -e \
'/^Name : branch/,+1s/Value :.*\.([^\.]+)$/\1 /p' \
< $tfc | sed -n -e '1p'`
;;
esac
# Author format
case $FORMAT_AUTHOR in
F) # full
aut=`sed -n -r -e \
'/^Name : author/,+1s/Value : (.+)$/\1/p' \
< $tfc | sed -n -e '1p'`
;;
S) # short
aut=`sed -n -r -e \
'/^Name : author/,+1s/Value : (.{1,10}).*[@ ].+$/\1/p' \
< $tfc | sed -n -e '1p'`
;;
esac
# Changelog format
case $FORMAT_LOG in
F) # full
log=`sed -n -r -e \
'/^Name : changelog/,+1s/Value : (.+)$/ \1/p' \
< $tfc | sed -n -e '1p'`
;;
S) # short
log=`sed -n -r -e \
'/^Name : changelog/,+1s/Value : (.{1,20}).*$/ \1/p' \
< $tfc | sed -n -e '1p'`
;;
esac
# Author coloring?
if [ -n "$FORMAT_COLOR" -a "$FORMAT_AUTHOR" != "N" ]
then
# Bug in dialog: Don't allow empty string after \\Zn
test -z "$log" && log=" "
if [ "$last_aut" != "$aut" ]
then
# Automatic color by author?
if [ "$FORMAT_COLOR" = "A" ]
then
color=`grep -n "$aut" $TEMPFILE.ncolor | cut -d ':' -f 1`
if [ -z "$color" ]
then
color=$(( `wc -l < $TEMPFILE.ncolor` % 16 + 1 ))
echo "$aut" >> $TEMPFILE.ncolor
fi
if [ $color -le 8 ]
then
color="\\Zb\\Z$color"
else
color8=$(( $color - 8 ))
color="\\Z$color8"
fi
else
color="$FORMAT_COLOR"
fi
last_aut="$aut"
fi
echo "$short_hash \"$dat$bra\\ZR$color$aut\\Zn$log\"" \
>> $out_file
else
echo "$short_hash \"$dat$bra\\ZR$aut$log\"" >> $out_file
fi
done | dialog --gauge "$line_count certs reading" 6 60
rm $tfc
}
do_log_brief_ancestors()
{
local out_file=$1
local hash short_hash dat bra aut lineno color
# Brief output
# e51dc90425c6371a176e87df294b47fcdba3f0bb Full Name <name@domain.de> 2005-11-20T20:31:34 mtbrowse
lineno=0
$MTN log --brief --last=$CERTS_MAX $ARG_FROM=$HEAD --db=$DB $NO_GRAPH $NOMERGES |\
while read line
do
lineno=$(( $lineno+1 ))
# TODO: Why MT give more than "--last"?
if [ $lineno -le $CERTS_MAX ]
then
echo "$(( 100*$lineno/$CERTS_MAX ))"
fi
set -- `echo "$line" | sed -n -r -e 's/^([^ ]+) (.+) ([0-9\-]{10})T([0-9:]{8}) (.+)$/\1 \3 \4 \5/p'`
author=`echo "$line" | sed -n -r -e 's/^([^ ]+) (.+) ([0-9\-]{10})T([0-9:]{8}) (.+)$/\2/p'`
hash=$1
date=$2
time=$3
branch="$4"
# Skip wrong formats, special case
# 37416b924fc25a48bba11ed8b2cd62e9dab7e637 First Name <name@domain.de>,name2@domain.com.au,third@domain.org 2006-01-20T08:21:37,2006-01-20T08:35:46,2006-01-20T08:35:33 net.venge.monotone
if [ -n "$hash" -a -n "$date" -a -n "$time" -a -n "$author" ]
then
short_hash=`echo $hash | cut -c 1-$HASH_TRIM`
# Date format
case $FORMAT_DATE in
F) # 2005-12-31T23:59:59
dat="${date}T$time "
;;
L) # 2005-12-31 23:59
dat="`echo "$date $time" | cut -c 1-16` "
;;
D) # 2005-12-31
dat=$date
;;
S) # 12-31 23:59
dat=`echo "$date $time" | sed -n -r -e \
'.{4}-(.+) (.{5}).+/\1 \2 /p'`
;;
T) # 23:59:59
dat=$time
;;
esac
# Branch format
case $FORMAT_BRANCH in
F) # full
bra=$branch
;;
S) # short
bra=`echo "$branch" | sed -n -r -e \
'/.*\.([^\.]+)$/\1 /p' `
;;
esac
# Author format
case $FORMAT_AUTHOR in
F) # full
aut="$author"
;;
S) # short
aut=`echo "$author " | sed -n -r -e \
's/(.{1,10}).*[@ ].+$/\1/p'`
;;
esac
# TODO: Copied from fill_date_key
# Author coloring?
if [ -n "$FORMAT_COLOR" -a "$FORMAT_AUTHOR" != "N" ]
then
if [ "$last_aut" != "$aut" ]
then
# Automatic color by author?
if [ "$FORMAT_COLOR" = "A" ]
then
color=`grep -n "$aut" $TEMPFILE.ncolor | cut -d ':' -f 1`
if [ -z "$color" ]
then
color=$(( `wc -l < $TEMPFILE.ncolor` % 16 + 1 ))
echo "$aut" >> $TEMPFILE.ncolor
fi
if [ $color -le 8 ]
then
color="\\Zb\\Z$color"
else
color8=$(( $color - 8 ))
color="\\Z$color8"
fi
else
color="$FORMAT_COLOR"
fi
last_aut="$aut"
fi
echo "$short_hash \"$dat$bra\\ZR$color$aut\"" >> $out_file
else
echo "$short_hash \"$dat$bra\\ZR$aut\"" >> $out_file
fi
fi
done | dialog --gauge "$CERTS_MAX certs reading" 6 60
}
# Select a branch
# Is parameter given: No user select, if branch known.
do_branch_sel()
{
local OLD_BRANCH
if [ ! -f "$DB" ]
then
echo "$DB: File not found! (mtbrowse)"
exit 1
fi
if [ ! -r "$DB" ]
then
echo "$DB: Can't read file! (mtbrowse)"
exit 1
fi
SHORT_DB=`basename $DB`
# is Branch set, than can return
if [ -n "$BRANCH" -a -n "$1" ]
then
return
fi
# New DB?
if [ "$DB" != "`cat $TEMPFILE.fname`" ]
then
echo "$DB" > $TEMPFILE.fname
unset BRANCH
fi
OLD_BRANCH=$BRANCH
# Get branches from DB
if [ ! -f $TEMPFILE.branches -o $DB -nt $TEMPFILE.branches \
-o "$CACHE" != "1" ]
then
$MTN --db=$DB list branches \
| sed -n -r -e 's/^(.+)$/\1\t-/p' > $TEMPFILE.branches \
|| exit 200
fi
if [ ! -s $TEMPFILE.branches ]
then
echo "Error: No branches found."
exit 1
fi
dialog --begin 1 2 \
--default-item "$OLD_BRANCH" \
--menu "Select branch" 0 0 0 \
`cat $TEMPFILE.branches` \
2> $TEMPFILE.input
BRANCH=`cat $TEMPFILE.input`
# Clear Head, if branch changed
if [ "$OLD_BRANCH" != "$BRANCH" ]
then
# Clear cached files
do_clear_cache
do_clear_on_exit
unset HEAD
unset SHORT_HEAD
fi
}
# Get head from DB (need for full log)
# Is parameter given: No user select, if head known.
do_head_sel()
{
# is Head set, than can return
if [ -n "$HEAD" -a -n "$1" ]
then
return
fi
if ! $MTN --db=$DB automate heads $BRANCH > $TEMPFILE.heads 2>$TEMPFILE.error
then
cat $TEMPFILE.error
exit -1
fi
# Only one head ?
if [ `wc -l < $TEMPFILE.heads` -eq 1 -a -n "$1" ]
then
HEAD=`head -n 1 < $TEMPFILE.heads`
else
# List heads with author and date. Select by user.
$MTN --db=$DB heads --branch=$BRANCH \
| sed -n -r -e 's/^([^ ]+) ([^ ]+) ([^ ]+)$/\1 \"\2 \3\"/p' \
| xargs dialog --begin 1 2 --menu "Select head" 0 0 0 \
2> $TEMPFILE.input
HEAD=`cat $TEMPFILE.input`
fi
# trim for some outputs
SHORT_HEAD=`echo $HEAD | cut -c 1-$HASH_TRIM`
rm -f $TEMPFILE.heads
}
# User menu for current branch
do_action_sel()
{
# Action-Menu
while dialog \
--backtitle "h:$HEAD b:$BRANCH f:$SHORT_DB" \
--menu "Action for $REVISION" 0 60 0 \
"L" "Logview of current revision" \
"P" "Diff files from parent" \
"W" "Diff files from working copy head" \
"S" "Diff files from selected revision" \
"C" "List Certs" \
"F" "List changed file revision" \
"-" "-" \
"Q" "Return" \
2> $TEMPFILE.action-select
do
case `cat $TEMPFILE.action-select` in
L)
# LOG
# 0.19 monotone log --depth=n --revision=id
# 0.19+ monotone log --last=n --revision=id
# 0.29 monotone log --last=n --revision=id
# 0.33 monotone log --last=n --from=id --no-graph
$MTN --db=$DB log $DEPTH_LAST=1 $ARG_FROM=$REVISION $NO_GRAPH \
> $TEMPFILE.change.log || exit 200
do_pager $TEMPFILE.change.log
;;
P)
# DIFF parent
$MTN --db=$DB automate parents $REVISION > $TEMPFILE.parents
if [ `wc -l < $TEMPFILE.parents` -ne 1 ]
then
# multiple parents (from merge)
# Create, if used a cached list
touch $TEMPFILE.ncolor
# Set DATE/KEY information
fill_date_key $TEMPFILE.parents $TEMPFILE.certs3tmp
cat $TEMPFILE.certs3tmp | \
xargs dialog --begin 1 2 --colors \
--default-item "$PARENT" \
--menu "Select parent for $REVISION" 0 0 0 \
2> $TEMPFILE.input \
&& PARENT=`cat $TEMPFILE.input`
rm $TEMPFILE.certs3tmp
else
# Single parent only
PARENT=`cat $TEMPFILE.parents`
fi
rm $TEMPFILE.parents
if [ -z "$PARENT" ]
then
dialog --msgbox "No parent found\n$REVISION" 6 45
else
$MTN --db=$DB diff \
--revision=$PARENT --revision=$REVISION \
> $TEMPFILE.parent.diff || exit 200
do_pager $TEMPFILE.parent.diff
fi
;;
W)
# DIFF
# $MTN diff --revision=id
if [ "$HEAD" = "$REVISION" ]
then
dialog --msgbox "Can't diff with head self\n$HEAD" 6 45
else
# exist working copy?
if [ -f $BK_DIR/options ]
then
$MTN --db=$DB diff \
--revision=$REVISION \
> $TEMPFILE.cwd.diff || exit 200
else
# w/o MT dir don't work:
# Help MT with HEAD info ;-)
$MTN --db=$DB diff \
--revision=$HEAD --revision=$REVISION \
> $TEMPFILE.cwd.diff || exit 200
fi
do_pager $TEMPFILE.cwd.diff
fi
;;
S)
# DIFF2: from other revision (not working dir)
# Select second revision
if cat $TEMPFILE.certs.$BRANCH | \
xargs dialog --default-item "$REV2" --colors --menu \
"Select _older_ revision for branch:$BRANCH\nrev:$REVISION" \
0 0 0 2> $TEMPFILE.revision-select
then
REV2=`cat $TEMPFILE.revision-select`
# $MTN diff --revision=id1 --revision=id2
$MTN --db=$DB diff \
--revision=$REV2 --revision=$REVISION \
> $TEMPFILE.ref.diff || exit 200
do_pager $TEMPFILE.ref.diff
fi
rm -f $TEMPFILE.revision-select
;;
C)
# List certs
$MTN --db=$DB list certs $REVISION > $TEMPFILE.certs.log \
|| exit 200
do_pager $TEMPFILE.certs.log
;;
F)
# List changed files
# 0.22: monotone cat revision <id>
# 0.23: monotone automate get_revision <id>
$MTN --db=$DB automate get_revision $REVISION > $TEMPFILE.rev.changed \
|| exit 200
do_pager $TEMPFILE.rev.changed
;;
Q)
# Menu return
return
;;
esac
done
}
# Get parents recursive.
# Same as automate ancestors, but limit the depth
# Function called recursive!
do_automate_ancestors_depth()
{
locale depth head rev
depth=$1
head=$2
# Empty parm?
if [ -z "$depth" -o -z "$depth" ]
then
return 0
fi
# Limit by depth?
if [ "$depth" -gt $CERTS_MAX -o "$depth" -gt 200 ]
then
return 0
fi
depth=$(( $depth+1 ))
$MTN --db=$DB automate parents $head |\
while read rev
do
if ! grep -q -l -e "$rev" $TEMPFILE.ancestors
then
echo "$rev" >> $TEMPFILE.ancestors
do_automate_ancestors_depth $depth $rev || return $?
fi
done
depth=$(( $depth-1 ))
return 0
}
# Select a revision
do_revision_sel()
{
local SHORT_REV
# if branch or head not known, ask user
echo "branch check..."
do_branch_sel check
echo "head check..."
do_head_sel check
# Building revisions list
if [ ! -f $TEMPFILE.certs.$BRANCH -o $DB -nt $TEMPFILE.certs.$BRANCH ]
then
# Name color new
rm -f $TEMPFILE.ncolor
touch $TEMPFILE.ncolor
echo "Reading ancestors ($HEAD)"
case $ANCESTORS in
B) # TODO:
# Get ancestors from log, brief format
do_log_brief_ancestors $TEMPFILE.certs3tmp
;;
L)
# Get ancestors from log
$MTN log --brief --last=$CERTS_MAX $ARG_FROM=$HEAD $NO_GRAPH $NOMERGES \
--db=$DB | cut -d ' ' -f 1 > $TEMPFILE.ancestors
# Check empty output, if fails
test -s $TEMPFILE.ancestors || exit 200
;;
I)
# Get only 'CERTS_MAX' of ancestors
echo "$HEAD" > $TEMPFILE.ancestors
do_automate_ancestors_depth 1 $HEAD || exit 200
;;
*)
# Get all ancestors
echo "$HEAD" > $TEMPFILE.ancestors
$MTN --db=$DB automate ancestors $HEAD \
>> $TEMPFILE.ancestors || exit 200
;;
esac
if [ "$ANCESTORS" != "B" ]
then
# Must toposort, if enabled by user, or before tailing
if [ "$TOPOSORT" = "T" -o "$CERTS_MAX" -gt 0 -a "$ANCESTORS" != "L" ]
then
echo "Toposort..."
$MTN --db=$DB automate toposort `cat $TEMPFILE.ancestors` \
> $TEMPFILE.toposort || exit 200
if [ "$CERTS_MAX" -gt 0 ]
then
# Only last certs. Remember: Last line is newest!
tail -n "$CERTS_MAX" < $TEMPFILE.toposort \
> $TEMPFILE.toposort2
mv $TEMPFILE.toposort2 $TEMPFILE.toposort
fi
else
mv $TEMPFILE.ancestors $TEMPFILE.toposort
fi
# Reading revisions and fill with date, names and changelog
fill_date_key $TEMPFILE.toposort $TEMPFILE.certs3tmp
fi
case $TOPOSORT in
D)
# Sort by date+time
sort -k 2 < $TEMPFILE.certs3tmp > $TEMPFILE.certs.$BRANCH
rm $TEMPFILE.certs3tmp
;;
R)
# Reverse sort by date+time
sort -k 2 -r < $TEMPFILE.certs3tmp > $TEMPFILE.certs.$BRANCH
rm $TEMPFILE.certs3tmp
;;
*)
# Not sorted, or toposort
mv $TEMPFILE.certs3tmp $TEMPFILE.certs.$BRANCH
;;
esac
fi
# if first rev is empty, use head instand
if [ -z "$REVISION" ]
then
SHORT_REV=`echo $HEAD | cut -c 1-$HASH_TRIM`
else
SHORT_REV=`echo $REVISION | cut -c 1-$HASH_TRIM`
fi
# Select revision
while cat $TEMPFILE.certs.$BRANCH | \
xargs dialog \
--backtitle "h:$HEAD b:$BRANCH f:$SHORT_DB" \
--no-shadow \
--colors \
--default-item "$SHORT_REV" \
--menu "Select revision for branch:$BRANCH" \
0 0 0 2> $TEMPFILE.revision-select
do
SHORT_REV=`cat $TEMPFILE.revision-select`
# Remove old marker, set new marker
if [ "$FORMAT_DATE" = "N" -a "$FORMAT_BRANCH" = "N" ]
then
sed -r \
-e "s/^(.+\")\*(.+)\$/\1\2/" \
-e "s/^($SHORT_REV.* \")(.+)\$/\1\*\2/" \
< $TEMPFILE.certs.$BRANCH > $TEMPFILE.marker
else
sed -r \
-e "s/^(.+\")\\\\Zr(.+)\$/\1\2/" \
-e "s/^($SHORT_REV.* \")(.+)\$/\1\\\\Zr\2/" \
< $TEMPFILE.certs.$BRANCH > $TEMPFILE.marker
fi
mv $TEMPFILE.marker $TEMPFILE.certs.$BRANCH
# Error, on "monotone automate parents XXXXXX", if short revision. :-(
# Expand revision here, if short revision (is alway short now)
REVISION=`$MTN --db=$DB complete revision $SHORT_REV`
# OK Button: Sub Menu
do_action_sel
done
rm -f $TEMPFILE.revision-select
}
# Menu for configuration
do_config()
{
local item
while dialog --default-item "$item" \
--menu "Configuration" 0 0 0 \
"V" "VISUAL [$VISUAL]" \
"Vd" "Set VISUAL default to vim -R" \
"P" "PAGER [$PAGER]" \
"Pd" "set PAGER default to less" \
"T" "Time and date format [$FORMAT_DATE]" \
"B" "Branch format [$FORMAT_BRANCH]" \
"A" "Author format [$FORMAT_AUTHOR]" \
"Ac" "Author Color format [$FORMAT_COLOR]" \
"L" "changeLog format [$FORMAT_LOG]" \
"C" "Certs limit in Select-List [$CERTS_MAX]" \
"D" "Depth limit for ancestors [$ANCESTORS]" \
"S" "Sort by Toposort, Date or none [$TOPOSORT]" \
"-" "-" \
"W" "Write configuration file" \
"R" "Return to main menu" \
2> $TEMPFILE.menu
do
item=`cat $TEMPFILE.menu`
case $item in
V)
# Setup for VISUAL
if dialog --inputbox \
"Config for file viewer\nuse in sample: \"vim -R changes.diff\"" \
9 70 "$VISUAL" 2> $TEMPFILE.input
then
VISUAL=`cat $TEMPFILE.input`
fi
;;
Vd)
# set Visual default
VISUAL="vim -R"
;;
P)
# Setup for PAGER
if dialog --inputbox \
"Config for pipe pager\nuse in sample: \"$MTN log | less\"" \
9 70 "$PAGER" 2> $TEMPFILE.input
then
PAGER=`cat $TEMPFILE.input`
fi
;;
Pd)
# set Pager default
PAGER="less"
;;
S)
# change T=Toposort revisions, D=Date sort, N=None (from list)
if dialog --default-item "$TOPOSORT" \
--menu "Sort revisions by" 0 0 0 \
"T" "Toposort, oldest top (from Monotone)" \
"D" "Date/Time, oldest top (internal function)" \
"R" "Reverse Date/Time (reverse toposort)" \
"N" "None. Simple get from list" \
2> $TEMPFILE.input
then
TOPOSORT=`cat $TEMPFILE.input`
fi
;;
T)
# change date/time format
if dialog --default-item "$FORMAT_DATE" \
--menu "Format for date and time" 0 0 0 \
"F" "2005-12-31T23:59:59 -- Full date and time" \
"L" "2005-12-31 23:59 -- Long date and time" \
"D" "2005-21-31 -- Date only" \
"S" "12-31 23:59:59 -- Short date and time" \
"T" "23:59:59 -- Time only" \
"N" "no date and no time" \
2> $TEMPFILE.input
then
FORMAT_DATE=`cat $TEMPFILE.input`
fi
;;
B)
# change branch format
if dialog --default-item "$FORMAT_BRANCH" \
--menu "Format for branch" 0 0 0 \
"F" "Full branch" \
"S" "Short branch, right side only" \
"N" "no branch" \
2> $TEMPFILE.input
then
FORMAT_BRANCH=`cat $TEMPFILE.input`
fi
;;
A)
# change author's format
if dialog --default-item "$FORMAT_AUTHOR" \
--menu "Format for author" 0 0 0 \
"F" "Full author" \
"S" "Short author, strip domain from email address" \
"N" "no author" \
2> $TEMPFILE.input
then
FORMAT_AUTHOR=`cat $TEMPFILE.input`
fi
;;
Ac)
# Author coloring
if dialog --default-item \
"`test -n \"$FORMAT_COLOR\" && echo \"yes\" || echo \"no\"`" \
--menu "Color author in selection" 0 0 0 \
"yes" "author is color" \
"no" "author has no special color" \
2> $TEMPFILE.input
then
if [ "`cat $TEMPFILE.input`" = "yes" ]
then
dialog --colors \
--default-item "$FORMAT_COLOR" \
--menu "Select color for author" 0 0 0 \
"A" "Automatic color" \
"\\Z0" "\Z0Color\Zn 0" \
"\\Z1" "\Z1Color\Zn 1" \
"\\Z2" "\Z2Color\Zn 2" \
"\\Z3" "\Z3Color\Zn 3" \
"\\Z4" "\Z4Color\Zn 4" \
"\\Z5" "\Z5Color\Zn 5" \
"\\Z6" "\Z6Color\Zn 6" \
"\\Z7" "\Z7Color\Zn 7" \
"\\Zb\\Z0" "\Zb\Z0Color\Zn 0b" \
"\\Zb\\Z1" "\Zb\Z1Color\Zn 1b" \
"\\Zb\\Z2" "\Zb\Z2Color\Zn 2b" \
"\\Zb\\Z3" "\Zb\Z3Color\Zn 3b" \
"\\Zb\\Z4" "\Zb\Z4Color\Zn 4b" \
"\\Zb\\Z5" "\Zb\Z5Color\Zn 5b" \
"\\Zb\\Z6" "\Zb\Z6Color\Zn 6b" \
"\\Zb\\Z7" "\Zb\Z7Color\Zn 7b" \
"\\Zb" "\ZbBold\Zn b" \
"\\Zu" "\ZuUnderline\Zn u" \
2> $TEMPFILE.input \
&& FORMAT_COLOR=`cat $TEMPFILE.input`
else
FORMAT_COLOR=""
fi
fi
;;
L)
# Changelog format
dialog \
--default-item "$FORMAT_LOG" \
--menu "Format for ChangeLog in selection" 0 0 0 \
"F" "Full changelog line" \
"S" "Short changelog" \
"N" "no changelog in selection" \
2> $TEMPFILE.input \
&& FORMAT_LOG=`cat $TEMPFILE.input`
;;
D)
# How to get ancestors
if dialog --default-item "$ANCESTORS" \
--menu "Get ancestors by using" 0 0 0 \
"B" "Brief log, without changelog (fastest)" \
"L" "Monotone \"log --brief\" with changelog" \
"I" "Internal function with depth limit (faster)" \
"A" "Monotone \"automate ancestor\" (save mode, very slow)" \
2> $TEMPFILE.input
then
ANCESTORS=`cat $TEMPFILE.input`
if [ "$ANCESTORS" = "A" ]
then
# functions don't work with big database
dialog --title " Info " --msgbox \
"\"automate ancestor\":
Big database can overflow command line.
It's saver to use internal function (I)." 0 0
fi
fi
;;
C)
# Change CERTS_MAX
dialog --inputbox \
"Set maximum lines for revision selction menu\n(0=disabled)" \
9 70 "$CERTS_MAX" 2> $TEMPFILE.input \
&& CERTS_MAX=`cat $TEMPFILE.input`
;;
W)
# Save environment
cat > $CONFIGFILE << EOF
# File: ~/.mtbrowserc
# Created for Monotone $MT_MAJOR.$MT_MINOR
DB="$DB"
BRANCH="$BRANCH"
VISUAL="$VISUAL"
PAGER="$PAGER"
TEMPDIR="$TEMPDIR"
TEMPFILE="$TEMPFILE"
TOPOSORT="$TOPOSORT"
CACHE="$CACHE"
CERTS_MAX="$CERTS_MAX"
FORMAT_DATE="$FORMAT_DATE"
FORMAT_BRANCH="$FORMAT_BRANCH"
FORMAT_AUTHOR="$FORMAT_AUTHOR"
FORMAT_LOG="$FORMAT_LOG"
FORMAT_COLOR="$FORMAT_COLOR"
ANCESTORS="$ANCESTORS"
NOMERGES="$NOMERGES"
EOF
dialog --title " Info " --sleep 2 --infobox \
"Configration wrote to\n$CONFIGFILE" 0 0
echo "config saved"
;;
*)
# Return to Main
rm -f $TEMPFILE.input
return
;;
esac
# Check non working combinations
if [ $ANCESTORS = "L" -a \( $MT_MAJOR -eq 0 -a $MT_MINOR -lt 20 \) ]
then
dialog --title " Info " --msgbox \
"\"log brief\" is only supported on Monotone version 0.20 or newer
Automatic corrected" 0 0
ANCESTORS="I"
fi
if [ "$CERTS_MAX" -le 0 -a "$ANCESTORS" != "A" ]
then
# functions don't work without limit
dialog --title " Info " --msgbox \
"Certs limit in Select-List:
Negative or zero limit not allowed
Automatic corrected" 0 0
CERTS_MAX=20
fi
if [ \( "$TOPOSORT" = "D" -o "$TOPOSORT" = "R" \) -a "$FORMAT_DATE" = "N" ]
then
dialog --title " Info " --msgbox \
"\"Sort Date/Time\" is not usable, if no time in list
Automatic corrected" 0 0
FORMAT_DATE="L"
fi
done
}
# Is dialog installed?
if ! dialog --version </dev/null >/dev/null 2>&1
then
# Hm, need this here
echo
echo "dialog - display dialog boxes from shell scripts."
echo "Dialog is needed for this tool, please install it!"
echo
exit -1
fi
# Save args
arg1=$1
# Check for binary
if [ -z "`which $MTN 2>/dev/null`" ]
then
if [ -n "`which monotone 2>/dev/null`" ]
then
# fall back to older binary name
MTN="monotone"
fi
fi
# Get $MTN version
set -- `$MTN --version | sed -n -r -e 's/^.+ ([0-9]+)\.([0-9]+).+$/\1 \2/p'`
MT_MAJOR=$1
MT_MINOR=$2
if [ -z "$MT_MAJOR" -o -z "$MT_MINOR" ]
then
# Hm, need this here
echo
echo "$MTN - distributed version control system."
echo "Can't execute!"
echo
exit -1
fi
# "log --depth=n" was changed to "log --last=n" in 0.20
# 0.19 monotone log --depth=n
# 0.20+ monotone log --last=n
if [ $MT_MAJOR -eq 0 -a $MT_MINOR -lt 20 ]
then
DEPTH_LAST="--depth"
else
DEPTH_LAST="--last"
fi
# New bookkeeping directory is _MTN, in 0.26+
if [ $MT_MAJOR -eq 0 -a $MT_MINOR -lt 26 ]
then
BK_DIR="MT"
else
BK_DIR="_MTN"
fi
# "log --revision=n" was changed to "log --from=n" in 0.32
if [ $MT_MAJOR -eq 0 -a $MT_MINOR -lt 32 ]
then
ARG_FROM="--revision"
else
ARG_FROM="--from"
fi
# "log --no-graph" need for 0.33
if [ $MT_MAJOR -eq 0 -a $MT_MINOR -lt 33 ]
then
NO_GRAPH=""
else
NO_GRAPH="--no-graph"
fi
# exist working copy?
if [ -f $BK_DIR/options ]
then
# Read parameters from file
# branch "mtbrowse"
#database "/home/hn/mtbrowse.db"
# key ""
eval `sed -n -r \
-e 's/^[ ]*(branch) \"([^\"]+)\"$/\1=\2/p' \
-e 's/^[ ]*(database) \"([^\"]+)\"$/\1=\2/p' < $BK_DIR/options`
if [ -n "$database" ]
then
DB=$database
BRANCH=$branch
fi
fi
# Simple program args supported
if [ -n "$arg1" ]
then
case $arg1 in
--version)
echo "mtbrowse $VERSION"
exit 0
;;
--help|-h)
echo "mtbrowse [dbfile]"
exit 0
;;
*)
# Databasefile from command line
DB="$arg1"
unset BRANCH
# MT change the options, if you continue with other DB here!
if [ -f $BK_DIR/options ]
then
if ! dialog --cr-wrap \
--title " *********** WARNING! ********** " \
--defaultno --colors --yesno "
Your \Zb\Z1$BK_DIR/options\Zn will be overwrite, if
continue with different DB file or branch
in exist working directory!
YES confirm / NO abbort" 0 0
then
echo "abbort"
exit 1
fi
fi
;;
esac
fi
mkdir -p $TEMPDIR
while dialog \
--cancel-label "Exit" \
--backtitle "$DB" \
--menu "Main - mtbrowse v$VERSION" 0 0 0 \
"S" "Select revision" \
"I" "Input revision" \
"F" "Change DB File [`basename $DB`]" \
"B" "Branch select [$BRANCH]" \
"H" "Head select [$SHORT_HEAD]" \
"R" "Reload DB, clear cache" \
"-" "-" \
"l" "Sumary complete log" \
"t" "List Tags" \
"h" "List Heads" \
"k" "List Keys" \
"-" "-" \
"C" "Configuration" \
"-" "-" \
"X" "eXit" \
2> $TEMPFILE.menu
do
case `cat $TEMPFILE.menu` in
S)
# Revision selection
do_revision_sel
;;
I)
# Input Revision
if dialog --inputbox \
"Input 5 to 40 digits of known revision" 8 60 "$REVISION" \
2> $TEMPFILE.input
then
REVISION=`cat $TEMPFILE.input`
if [ `echo "$REVISION" | wc -L` -lt 40 ]
then
# Error, on "$MTN automate parents XXXXXX", if short revision. :-(
# Expand revision here, if short revision
REVISION=`$MTN --db=$DB complete revision $REVISION`
fi
do_action_sel
do_revision_sel
fi
;;
R)
# Cache del and Revision selection
do_clear_cache
do_revision_sel
;;
B)
# Branch config
rm -f $TEMPFILE.branches
do_branch_sel
;;
H)
# Select head
# if branch or head not known, ask user
do_branch_sel check
do_head_sel
do_clear_cache
;;
F)
# Change DB file
DNAME=`dirname $DB`
if [ -z "$DNAME" ]
then
DNAME=`pwd`
fi
if dialog --fselect $DNAME/`basename $DB` 15 70 2> $TEMPFILE.name-db
then
DB=`cat $TEMPFILE.name-db`
dialog --msgbox "file changed to\n$DB" 0 0
unset BRANCH
else
dialog --msgbox "filename unchanged" 0 0
fi
rm -f $TEMPFILE.name-db
;;
C)
do_config
# Clear cache
do_clear_cache
;;
l)
# Sumary complete LOG
# if not branch known, ask user
do_branch_sel check
do_head_sel check
if [ ! -f $TEMPFILE.changelog.$BRANCH -o \
$DB -nt $TEMPFILE.changelog.$BRANCH ]
then
echo "Reading log...($BRANCH)"
$MTN --db=$DB log $ARG_FROM=$HEAD $NO_GRAPH \
> $TEMPFILE.changelog.$BRANCH || exit 200
fi
cp $TEMPFILE.changelog.$BRANCH $TEMPFILE.change.log
do_pager $TEMPFILE.change.log
;;
t)
# List Tags
echo "Reading Tags..."
$MTN --db=$DB list tags > $TEMPFILE.tags.log || exit 200
do_pager $TEMPFILE.tags.log
;;
h)
# if not branch known, ask user
do_branch_sel check
$MTN --db=$DB heads --branch=$BRANCH > $TEMPFILE.txt || exit 200
do_pager $TEMPFILE.txt
;;
k)
# List keys
$MTN --db=$DB list keys > $TEMPFILE.txt || exit 200
do_pager $TEMPFILE.txt
;;
X)
do_clear_on_exit
clear
exit 0
;;
*)
echo "Error in Menu!"
exit 250
;;
esac
done
do_clear_on_exit
clear
syntax highlighted by Code2HTML, v. 0.9.1