Created
October 17, 2009 04:48
-
-
Save colinmollenhour/212246 to your computer and use it in GitHub Desktop.
Module Manager (old version)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Module Manager | |
# Version 1.0.1 | |
# 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 | |
# Copyright 2009 Colin Mollenhour | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
script=${0##*/} | |
usage=" | |
---------------------- | |
Module Manager | |
---------------------- | |
Usage: $script <module> <action> [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 <svn_path> <real_path> add a file/dir to the modman file and working copy | |
delete <svn_path> 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 | |
# Import another modman module! | |
@import modules/Fooman_Speedster | |
# Execute a command on the shell! | |
@shell rm -rf ../../var/cache/* | |
---- End example modman file ---- | |
One modman file can import another modman file using @import and the root of the | |
module relative to the parent working copy. Typically, this means you will have | |
used svn:externals so that the working copy contains the code in a subdirectory. | |
For example: | |
> svn propget svn:externals . | |
^/modules/Fooman_Speedster modules/Fooman_Speedster | |
In this example, modules/Fooman_Speedster would contain it's own modman file which | |
contains definitions which are relative to the same root as the parent module it | |
was imported from. Therefore, an @import has the exact same effect as running | |
\"modman xxx checkout\" from the same project root. | |
Author: | |
Colin Mollenhour | |
http://colin.mollenhour.com/ | |
[email protected] | |
" | |
# 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 | |
elif [ "$1" = "--help" ]; then | |
echo -e "$usage" | |
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 | |
echo "Updating module: $module" | |
$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 | |
if ! [ -r $wc_dir/.modman ]; then | |
echo "ERROR: The '$module' module does not contain a \"modman\" module description file."; exit 1 | |
else | |
echo "The '.modman' file should be renamed to 'modman'. Rename the file and run svn update manually and then run modman update."; exit 1 | |
fi | |
fi | |
return 0 | |
} | |
create_links () | |
{ | |
grep -v '^#' $1 | grep -v '^\s*$' | \ | |
while read svn real; do | |
module_dir=`dirname $1` | |
src=$module_dir/$svn | |
dest=$root/${real%/} | |
# Import other module definitions (which are typically imported via svn:externals) | |
if [[ "$svn" == "@import" ]]; then | |
import=$module_dir/$real/modman | |
if ! [ -r $import ]; then | |
echo "Failed \"@import $real\", $import not found."; return 1 | |
else | |
create_links $import || return 1 | |
continue | |
fi | |
fi | |
# Run commands on the shell! | |
if [[ "$svn" == "@shell" ]]; then | |
echo $real | bash | |
continue | |
fi | |
# 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 | |
return 0 | |
} | |
copy_over () | |
{ | |
grep -v '^#' $1 | grep -v '^\s*$' | \ | |
while read svn real; do | |
module_dir=`dirname $1` | |
src=$module_dir/$svn | |
dest=$root/${real%/} | |
# Handle @import case | |
if [[ "$svn" == "@import" ]]; then | |
import=$module_dir/$real/modman | |
if ! [ -r $import ]; then | |
echo "Failed \"@import $real\", $import not found."; return 1 | |
else | |
copy_over $import || return 1 | |
continue | |
fi | |
fi | |
# Copy the files to their respective locations using hardlinks for efficiency | |
if ! [ -e `dirname $dest` ]; then | |
mkdir --parents `dirname $dest`; | |
fi | |
cp --recursive --link $src $dest || 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 | |
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 '^#' | grep -v '^\s*$' | \ | |
while read svn real; do | |
if [ -L $root/$real ]; then | |
rm $root/${real%/} | |
fi | |
done | |
rm .modman-old | |
create_links $wc_desc && echo "Update of module $module complete." | |
# remove dead symlinks | |
find -L $root -type l -delete | |
;; | |
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`" = "." ]; then mkdir -p `dirname $svn` || exit 1; fi | |
if ! [ -e `dirname $svn` ]; then echo "$svn does not exist"; exit 1; fi | |
if ! mv $root/$real $wc_dir/$svn | |
then | |
echo "Could not move $root/$real to $wc_dir/$svn, make sure the files are closed." | |
exit 1 | |
fi | |
if | |
svn add --parents $@ $svn && | |
echo "$svn $real" >> $wc_desc && | |
ln -s $wc_dir/$svn $root/${real%/} | |
then | |
echo "Scheduled add of $real under svn alias $svn" | |
create_links $wc_desc | |
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 $wc_desc | |
then | |
echo "Checkout of module $module complete" | |
# remove dead symlinks | |
find -L $root -type l -delete | |
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 $wc_desc | |
then | |
echo "Exported $module to $root" | |
else | |
echo "Failed to export module to $root" | |
fi | |
if [ -d $wc_dir ]; then rm -rf $wc_dir; fi | |
;; | |
*) | |
echo -e "$usage\nInvalid action: $action\n"; | |
exit; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment