[mythtv-users] UPDATED: Bash/MySQL script for copying and/or deleting mythfrontend profiles
Jeffrey J. Kosowsky
mythtv at kosowsky.org
Mon Jan 11 19:31:02 UTC 2010
Jeffrey J. Kosowsky wrote at about 22:57:29 -0500 on Sunday, January 10, 2010:
> OK. I spent way too much time today learning mysql on the fly :)
> But here is a combined Bash/MySQL script that I came up with to
> robustly either copy or delete mythfrontend profiles. I owe much
> gratitude to Ronald Frazier for coming up with the core SQL queries --
> I just added some robustness and extensions...
>
> The script does some reasonable error checking to make sure that you
> are not deleting the last frontend profile and that the profile you
> are copying actually exists.
>
> The routine also by default (and in the interest of healthy paranoia)
> dumps a copy of your existing database before doing anything...
>
> Use the '-h' flag for usage information to figure out how to use the
> routine.
>
> Of course, I am the most newbie of newbies to mysql, so check through
> the code before using, don't turn off the default backups, and test it
> first, etc....
>
> Here is the code:
BTW it works like a charm and now I can see my myth recordings on my
XP laptop -- woohooo....
Here is an updated version of the code with some minor usability
enhancements:
-----------------------------------------------------------------------------
# !/bin/bash
#mythfrontendprofiledup
#Jeff Kosowsky (with MUCH help from Ronald Frazier)
#Script to automatically copy and/or delete mythfrontend profiles.
##############################################################################
#Default values
MYTHDB=mythconverg
USER=mythtv
PASSWD= #Blank means it will query
#############################################################################
function usage () {
cat <<EOF
Copy (or delete) a frontend from the mythtv database
Usage: ${0##*/} [options] OLDHOSTNAME NEWHOSTNAME
Copy over frontend settings from OLDHOSTNAME to NEWHOSTNAME
(note existing entries for NEWHOSTNAME are deleted first)
${0##*/} -d|--deleteonly [options] HOSTNAME
Delete HOSTNAME frontend from database
${0##*/} -h
Display this usage message
where options are:
--mythdb|-m MYTHDB Use MYTHDB database [default is to use 'mythconverg']
--nobackup|-n Don't backup database to MYTHDB.<date>.sql
before editing database [default is to backup]
--passwd|-p PASSWD Use password PASSWD [Default is to query for password]
--user|-u USER Use user USER [default is 'mythtv']
Note: program will not delete the last mythfrontend profile nor will it make
any changes to NEWHOSTNAME unless OLDHOSTNAME exists.
EOF
}
############################################################################
SHORT_OPTIONS="d,h,m:,n,p:,u:"
LONG_OPTIONS="deleteonly,help,mythdb:,nobackup,passwd:,user:"
PARSED_OPTIONS=$(getopt -n "${0##*/}" -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@")
OPTIONS_RET=$?
eval set -- "$PARSED_OPTIONS"
# Parsing error or no flags
if [ $OPTIONS_RET -ne 0 ] || [ $# -le 0 ]; then
usage
exit 1
fi
while [ $# -ge 1 ]; do
case $1 in
--deleteonly | -d) deleteonly=1 ;;
--help | -h) usage; exit 0 ;;
--mythdb | -m) shift; MYTHDB="$1" ;;
--nobackup | -n) nobackup=1 ;;
--passwd | -p) shift; PASSWD="$1" ;;
--user | -u) shift; USER="$1" ;;
-- ) shift; break;;
* ) echo "ERROR: unknown flag $1"; usage; exit 1;;
esac
shift
done
OLDHOST=$1
NEWHOST=$2
if [ -n "$deleteonly" -a $# -ne 1 ] || [ -z "$deleteonly" -a $# -ne 2 ] ; then
usage
exit 1
fi
if [ "$OLDHOST" = "$NEWHOST" ] ; then
echo "Error: NEWHOSTNAME can't equal OLDHOSTNAME"
exit 2
fi
if [ -z "$nobackup" ] ; then
backup=$MYTHDB-`date "+%m%d%y.%H%M%S"`.sql
echo "** Backing up myth database to: $backup"
mysqldump --order-by-primary -u $USER -p$PASSWD $MYTHDB > $backup
fi
if [ -n "$deleteonly" ] ; then
NEWHOST=$OLDHOST
unset OLDHOST
fi
#########################################################################
# Inject mysql queries
mysql --skip-column-names -u $USER -p$PASSWD $MYTHDB < <( sed "s/<OLDHOSTNAME>/$OLDHOST/g;s/<NEWHOSTNAME>/$NEWHOST/g" <<EOF
-- DELETE:
-- Calculate number of hosts left other than NEWHOSTNAME (the one changing)
set @numotherhosts := (select count(distinct hostname) from
displayprofilegroups where hostname != '<NEWHOSTNAME>');
-- Check if OLDHOSTNAME exists
-- NOTE in the deletion case "<OLDHOSTNAME>" = "", so we always try to delete
set @oldhostexists := if("<OLDHOSTNAME>" = "", 1,
(select count(distinct hostname) from displayprofilegroups where hostname = '<OLDHOSTNAME>'));
-- Only do deletions and insertions if:
-- @doit = @numotherhosts * @oldhostexists > 0
set @doit := @oldhostexists * @numotherhosts;
select if(@oldhostexists > 0, if(@numotherhosts > 0,
"** Deleting any frontend settings for '<NEWHOSTNAME>'...",
"Error: No other hosts left. Aborting deletions..."),
"Error: '<OLDHOSTNAME>' doesn't exist. Aborting all database changes...");
-- First delete entries for <NEWHOSTNAME> from the following tables:
-- settings, keybindings, jumppoints
DELETE FROM settings WHERE hostname ='<NEWHOSTNAME>' AND @doit > 0;
DELETE FROM keybindings WHERE hostname ='<NEWHOSTNAME>' AND @doit > 0;
DELETE FROM jumppoints WHERE hostname ='<NEWHOSTNAME>' AND @doit > 0;
-- Second Delete any existing entries and profiles corresponding to
-- NEWHOSTNAME from displayprofiles and displayprofilegroups tables
-- NOTE: We assume that the profilegroupids are unique to each hostname
-- (and they will be if you use this script to copy frontend settings)
DELETE FROM displayprofiles WHERE profilegroupid IN (SELECT profilegroupid
FROM displayprofilegroups WHERE hostname = '<NEWHOSTNAME>') AND @doit > 0;
DELETE FROM displayprofilegroups WHERE hostname = '<NEWHOSTNAME>' AND @doit > 0;
-- Third, reset AUTO_INCREMENT values for the profile tables
-- Note you need the PREPARE/EXECUTE because you cannot assign a variable to
-- AUTO_INCREMENT directly
SET @lastgroupid := (select max(profilegroupid) FROM displayprofilegroups);
SET @s = CONCAT("ALTER TABLE displayprofilegroups AUTO_INCREMENT=", @lastgroupid+1);
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @lastprofileid := (select max(profileid) FROM displayprofiles);
SET @s = CONCAT("ALTER TABLE displayprofiles AUTO_INCREMENT=", @lastprofileid+1);
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
EOF
[ -z "$deleteonly" ] && sed "s/<OLDHOSTNAME>/$OLDHOST/g;s/<NEWHOSTNAME>/$NEWHOST/g" <<EOF
-- COPY OLDHOSTNAME SETTINGS TO NEWHOSTNAME
select if(@doit,
"** Copying over frontend profile from '<OLDHOSTNAME>' to '<NEWHOSTNAME>'...",
"");
-- First copy over settings for tables: settings, keybindings, jumppoints
INSERT INTO settings(value, data, hostname) SELECT value, data,
'<NEWHOSTNAME>' FROM settings WHERE hostname = '<OLDHOSTNAME>' AND @doit > 0;
INSERT INTO keybindings(context, action, description, keylist,
hostname) SELECT context, action, description, keylist,
'<NEWHOSTNAME>' FROM keybindings WHERE hostname = '<OLDHOSTNAME>' AND @doit > 0;
INSERT INTO jumppoints(destination, description, keylist, hostname)
SELECT destination, description, keylist, '<NEWHOSTNAME>' FROM
jumppoints WHERE hostname = '<OLDHOSTNAME>' AND @doit > 0;
-- Second copy over settings for profiles.
-- Create temporary Tables GroupIDMap and ProfileIDMap to map profilegroup's
-- and profileid's from displayprofilegroup and displayprofiles tables
-- so as to avoid conflicts and minimize wasted key space
CREATE TEMPORARY TABLE GroupIDMap (oldid INT UNSIGNED , newid INT
UNSIGNED);
INSERT INTO GroupIDMap(oldid, newid) SELECT DISTINCT profilegroupid,
@lastgroupid := @lastgroupid+1 FROM displayprofilegroups WHERE
hostname='<OLDHOSTNAME>' AND @doit > 0;
CREATE TEMPORARY TABLE ProfileIDMap (oldid INT UNSIGNED, newid INT
UNSIGNED);
INSERT into ProfileIDMap(oldid) SELECT DISTINCT profileid FROM
displayprofiles WHERE profilegroupid IN (SELECT oldid FROM
GroupIDMap) AND @doit > 0;
UPDATE ProfileIDMap set newid=(@lastprofileid := @lastprofileid+1)
where @doit > 0;
-- Third, use the temporary tables to copy the profiles
INSERT INTO displayprofilegroups (name, hostname, profilegroupid)
SELECT name, '<NEWHOSTNAME>', newid FROM displayprofilegroups INNER
JOIN GroupIDMap ON profilegroupid=oldid where @doit > 0;
INSERT INTO displayprofiles(profilegroupid, profileid, value, data)
SELECT G.newid, P.newid, value, data
FROM displayprofiles INNER JOIN GroupIDMap G ON profilegroupid=G.oldid
INNER JOIN ProfileIDMap P ON profileid=P.oldid where @doit > 0;
EOF
)
###########################################################################
More information about the mythtv-users
mailing list