#!/bin/bash # Magento Module Manager # Version 0.9 (Oct 2, 2009) # System Requirements: # - bash # - web server must follow symlinks # - The following utilities must be locatable in your $PATH # svn, grep (POSIX), find, ln, sed, cp, basename, dirname script=${0##*/} usage=" ---------------------- Magento Module Manager ---------------------- Usage: $script [svn args] Supported global actions (no module specified): init initialize the current directory as the modman root (no module name) update-all update all modules that are currently checked out Supported actions: (all svn commands support additional arguments) checkout checkout a new modman compatible module export export a modman compatible module (does real copy instead of symlinks) update [...] update module add add a file/dir to the .modman file and working copy delete remove a file/dir from the .modman file and working copy status show status of entire module diff [...] run svn diff on module commit [...] commit changes to module info show the module's working copy path and run svn info on working copy list list the definitions in the .modman file The repository should contain a file called \".modman\" which defines which files go where relative to the directory where modman was initialized. If additional arguments are given to commands such as commit, paths should be relative to the svn root. ---- Start example .modman file ---- # Comments are supported, begin a line with a hash code app/code/local/My/Module/ design app/design/frontend/default/default/mymodule/ locale/My_Module.xml app/locale/en_US/My_Module.xml My_Module.xml app/etc/modules/My_Module.xml ---- End example .modman file ---- Author: Colin Mollenhour http://colin.mollenhour.com/ colin@mollenhour.com " # bash implementation of realpath / readlink -f # arg1 - filename realpath() { fname=${1%/} # strips trailing '/' while [ -L "$fname" ]; do oldfname="$fname" fname="$(command ls -l $fname)" fname="${fname#*> }" if [ "$fname" = . ] ; then fname="$(dirname $oldfname)" elif echo $fname | grep -vq '^/' - ; then fname="$(dirname $oldfname)/$fname" fi done pushd $(dirname $fname) > /dev/null fname=$(pwd -P)/$(basename $fname) popd > /dev/null echo $fname } # Handle "init" command, simply create .modman directory if [ "$1" = "init" ]; then mkdir .modman && echo "Initialized Module Manager at `pwd`" exit 0 fi # Find the .modman directory and store parent path in $root _pwd=$(realpath `pwd`) rel='' mm_not_found="Module Manager directory not found.\nRun \"$script init\" in the web root of the Magento installation with which you would like to use Module Manager." root=$_pwd while ! [ -d $root/.modman ]; do if [ "$root" = "/" ]; then echo -e $mm_not_found && exit 1; fi rel=${root##*/}/$rel cd .. || (echo -e "ERROR: Could not traverse up from $root\n$mm_not_found" && exit 1) root=`pwd` done mm_dir=$root/.modman # path to .modman # Handle "update-all" command if [ "$1" = "update-all" ]; then if [ -n "$2" ]; then echo "Too many arguments to update-all command"; exit 1; fi for module in `ls $mm_dir`; do $0 $module update || exit 1 done echo "Successfully updated all modules." exit 0 fi module=$1; shift # module name wc_dir=$mm_dir/$module # working copy directory for module wc_desc=$wc_dir/.modman # path to modman structure descriptor file action=$1; shift # svn command to be used if [ -z "$module" ]; then echo -e "Not enough arguments (no module specified)\n$usage" && exit 1 fi if [ -z "$action" ]; then echo -e "Not enough arguments (no action specified)\n$usage" && exit 1 fi if [ "$1" == "--force" ]; then FORCE="1"; shift else FORCE="0" fi cd $_pwd; #restore old root require_wc () { if ! [ -d $wc_dir ]; then echo "ERROR: The '$module' module has not been checked out."; exit 1 fi if ! [ -r $wc_desc ]; then echo "ERROR: The '$module' module does not contain a .modman module description file."; exit 1 fi return 0 } create_links () { grep -v '^#' $wc_desc | \ while read svn real; do src=$wc_dir/$svn dest=$root/${real%/} # Handle aliases that do not exist if ! [ -e $src ]; then if [ -L $dest ]; then rm $dest && echo "Removed bad link to $real" fi echo "WARNING: Alias described in .modman does not exist in working copy: $svn" continue fi # Handle cases where files already exist at the destination if [ -e $dest ] && ! [ -L $dest ]; then if [ "$FORCE" == "0" ]; then echo -e "CONFLICT: $real already exists and is not a link.\nRun with --force to force removal of existing files." return 1 else rm -rf $dest fi fi # Create links if they do not already exist if ! [ -e $dest ]; then mkdir -p ${dest%/*} if ln -s $src $dest then echo "Created link for new module directive: $svn $real" else echo -e "Unable to create softlink for rule: $svn $real" return 1 fi fi done # remove dead symlinks find -L $root -type l -delete return 0 } copy_over () { grep -v '^#' $wc_desc | \ while read svn real; do cp -r $wc_dir/$svn $root/${real%/} || return 1 done return 0 } case "$action" in status) require_wc cd $wc_dir svn status $@ ;; diff) require_wc cd $wc_dir svn diff $@ ;; info) require_wc cd $wc_dir echo "$wc_dir" svn info $@ ;; commit) require_wc cd $wc_dir sed --in-place -e '/^$/d' $wc_desc svn commit $@ ;; update) require_wc cd $wc_dir cp .modman .modman-old svn update $@ || (echo "failed to update working copy"; rm .modman-old; exit 1) #remove any links that were removed from .modman file grep -F -vxf .modman .modman-old | grep -v '^#' | \ while read svn real; do if [ -L $root/$real ]; then rm $root/${real%/} fi done rm .modman-old create_links && echo "Update of module $module complete." ;; add) require_wc svn=$1; shift real=$1; shift if [ -z $svn ]; then echo -e "Not enough arguments to \"add\".\n$usage"; exit 1; fi if [ -z $real ] || ! [ -e $root/$real ]; then echo "Real path not specified or not found ($real)"; exit 1; fi cd $wc_dir if [ "`dirname $svn`" -ne "." ]; then mkdir -p `dirname $svn`; fi mv $root/$real $wc_dir/$svn || (echo "Could not move $root/$real to $wc_dir/$svn, make sure the files are closed."; exit 1) if svn add --parents $@ $svn && cat "$svn $real" >> $wc_desc && ln -s $wc_dir/$svn $root/${real%/} then echo "Scheduled add of $real under svn alias $svn" create_links else echo "An error occurred while trying to add $real under svn alias $svn" fi ;; delete) require_wc cd $wc_dir svn=$1; shift if [ -z $svn ]; then echo -e "You must specify an alias to delete.\n$usage"; exit 1; fi if [ `grep -c "'^$svn '" < $wc_desc` != "1" ]; then echo "Alias rule not found for '$svn'"; exit 1 fi if svn delete $@ && sed --in-place -e "'\\#^$svn #d'" $wc_desc then echo "Scheduled delete of svn alias $svn" else echo "An error occurred while trying to remove svn alias $svn" fi ;; checkout) cd $mm_dir if [ -d $wc_dir ]; then echo "A module by that name has already been checked out"; exit 1 fi if svn checkout $@ $module && require_wc && create_links then echo "Checkout of module $module complete" else if [ -d $wc_dir ]; then rm -rf $wc_dir; fi echo "Error checking out $module, operation cancelled." fi ;; list) require_wc echo "--Module Manager alias definitions for $module module:" cat $wc_desc ;; export) cd $mm_dir if [ -d $wc_dir ]; then echo "You cannot export a module that has already been checked out"; exit 1 fi if svn export $@ $module && require_wc && copy_over then echo "Exported $module to $root" else if [ -d $wc_dir ]; then rm -rf $wc_dir; fi echo "Failed to export module to $root" fi ;; *) echo -e "$usage\nInvalid action: $action\n"; exit; esac