From b70ef4dba11489680d0e5d547020431ed4fb7975 Mon Sep 17 00:00:00 2001 From: Nathan Broadbent Date: Sat, 22 Oct 2011 01:52:04 +0800 Subject: [PATCH] Added design() function to manage synchronization of design development assets for git repos, without checking them in --- lib/design.sh | 107 ++++++++++++++++++++++++++++++++++++++++ lib/scm_breeze.sh | 22 +++++---- scm_breeze.sh | 9 +++- scmbrc.example | 13 +++++ test/lib/design_test.sh | 86 ++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+), 11 deletions(-) create mode 100644 lib/design.sh create mode 100644 scmbrc.example create mode 100755 test/lib/design_test.sh diff --git a/lib/design.sh b/lib/design.sh new file mode 100644 index 0000000..f1b79cb --- /dev/null +++ b/lib/design.sh @@ -0,0 +1,107 @@ +# ------------------------------------------------------- +# Design Assets Management (for Git projects) +# Written by Nathan Broadbent (www.madebynathan.com) +# ------------------------------------------------------- +# +# * The `design` function manages the 'design assets' directories for the current project, +# including folders such as Backgrounds, Logos, Icons, and Samples. The actual directories are +# created in the root design directory, symlinked into the project, and ignored from source control. +# This is because we usually don't want to check in design development files such as bitmaps or wav files. +# It also gives us the option to sync the root design directory via Dropbox. +# +# Examples: +# +# $ design link # Requires SCM Breeze - Links existing design directories into each of your projects +# $ design init # Creates default directory structure at $root_design_dir/**/ubuntu_config and symlinks into project. +# (Images Backgrounds Logos Icons Mockups Screenshots) +# $ design init --av # Creates extra directories for audio/video assets +# (Images Backgrounds Logos Icons Mockups Screenshots Animations Videos Flash Music Samples) +# $ design rm # Removes any design directories for ubuntu_config +# $ design trim # Trims empty design directories for ubuntu_config +# + + +# Add ignore rule to .git/info/exclude if not already present +_design_add_git_exclude(){ + if [ -e "$1/.git/info/exclude" ] && ! $(grep -q "$project_design_dir" "$1/.git/info/exclude"); then + echo "$project_design_dir" >> "$1/.git/info/exclude" + fi +} + +# Manage design directories for project. +design() { + local project=`basename $(pwd)` + local all_project_dirs="$design_base_dirs $design_av_dirs" + # Ensure design dir contains all subdirectories + unset IFS + for dir in $design_ext_dirs $design_base_dirs $design_av_dirs; do mkdir -p "$root_design_dir/$dir"; done + + if [ -z "$1" ]; then + echo "design: Manage design directories for project assets that are external to source control." + echo + echo " Examples:" + echo + echo " $ design init # Creates default directory structure at $root_design_dir/**/$project and symlinks into project." + echo " ($design_base_dirs)" + echo " $ design link # Links existing design directories into existing repos" + echo " $ design init --av # Adds extra directories for audio/video assets" + echo " ($design_base_dirs $design_av_dirs)" + echo " $ design rm # Removes any design directories for $project" + echo " $ design trim # Trims empty design directories for $project" + echo + return 1 + fi + + if [ "$1" = "init" ]; then + create_dirs="$design_base_dirs" + if [ "$2" = "--av" ]; then create_dirs+=" $design_av_dirs"; fi + echo "Creating the following design directories for $project: $create_dirs" + mkdir -p "$project_design_dir" + # Create and symlink each directory + for dir in $create_dirs; do + mkdir -p "$root_design_dir/$dir/$project" + if [ ! -e ./$project_design_dir/$dir ]; then ln -sf "$root_design_dir/$dir/$project" $project_design_dir/$dir; fi + done + _design_add_git_exclude $PWD + + elif [ "$1" = "link" ]; then + enable_nullglob + echo "== Linking existing Design directories into existing repos..." + for dir in $all_project_dirs; do + for design_path in $root_design_dir/$dir/*; do + proj=$(basename $design_path) + repo_path=$(grep "/$proj$" $GIT_REPO_DIR/.git_index) + if [ -n "$repo_path" ]; then + mkdir -p "$repo_path/$project_design_dir" + if [ -e "$repo_path/$project_design_dir/*" ]; then rm $repo_path/$project_design_dir/*; fi + _design_add_git_exclude $repo_path + if ! [ -e "$repo_path/$project_design_dir/$dir" ]; then ln -fs "$design_path" "$repo_path/$project_design_dir/$dir"; fi + echo "=> $repo_path/$project_design_dir/$dir" + fi + done + done + disable_nullglob + + elif [ "$1" = "rm" ]; then + echo "Removing all design directories for $project..." + for dir in $all_project_dirs; do rm -rf "$root_design_dir/$dir/$project"; done + rm -rf $project_design_dir + + elif [ "$1" = "trim" ]; then + echo "Trimming empty design directories for $project..." + for dir in $(find -L $project_design_dir/ -type d -empty); do + asset=$(basename $dir) + rm -rf "$root_design_dir/$asset/$project" + rm -f $project_design_dir/$asset + done + # Remove design dir from project if there's nothing in it. + if find $project_design_dir -type d -empty | grep -q $project_design_dir; then + rm -rf $project_design_dir + fi + + else + printf "Invalid command.\n\n" + design + fi +} + diff --git a/lib/scm_breeze.sh b/lib/scm_breeze.sh index 170085e..73b3cc3 100644 --- a/lib/scm_breeze.sh +++ b/lib/scm_breeze.sh @@ -5,6 +5,9 @@ if [ $shell = "zsh" ]; then zsh_shwordsplit=$( (setopt | grep -q shwordsplit) && # Switch on/off shwordsplit for functions that require it. zsh_compat(){ if [ $shell = "zsh" ] && [ -z $zsh_shwordsplit ]; then setopt shwordsplit; fi; } zsh_reset(){ if [ $shell = "zsh" ] && [ -z $zsh_shwordsplit ]; then unsetopt shwordsplit; fi; } +# Enable/disable nullglob for zsh or bash +enable_nullglob() { if [ $shell = "zsh" ]; then setopt NULL_GLOB; else shopt -s nullglob; fi; } +disable_nullglob() { if [ $shell = "zsh" ]; then unsetopt NULL_GLOB; else shopt -u nullglob; fi; } # Alias wrapper that ignores errors if alias is not defined. _alias(){ alias "$@" 2> /dev/null; } @@ -27,22 +30,23 @@ update_scm_breeze() { # Create '~/.*.scmbrc' files, or attempt to patch them if passed a previous revision _create_or_patch_scmbrc() { patchfile=$(mktemp -t tmp.XXXXXXXXXX) - for scm in git; do + # Process '~/.scmbrc' and '~/.*.scmbrc' + for prefix in "" "git."; do # Create file from example if it doesn't already exist - if ! [ -e "$HOME/.$scm.scmbrc" ]; then - cp "$scmbDir/$scm.scmbrc.example" "$HOME/.$scm.scmbrc" - printf "== '~/.$scm.scmbrc' has been created. Please edit this file to change SCM Breeze settings for '$scm'.\n" + if ! [ -e "$HOME/.$prefix""scmbrc" ]; then + cp "$scmbDir/$prefix""scmbrc.example" "$HOME/.$prefix""scmbrc" + printf "== '~/.$prefix""scmbrc' has been created. Please edit this file to change SCM Breeze settings.\n" # If file exists, attempt to update it with any new settings elif [ -n "$1" ]; then # Create diff of example file, substituting example file for user's config. - git diff $1 "$scm.scmbrc.example" | sed "s/$scm.scmbrc.example/.$scm.scmbrc/g" > $patchfile + git diff $1 "$prefix""scmbrc.example" | sed "s/$prefix""scmbrc.example/.$prefix""scmbrc/g" > $patchfile if [ -s $patchfile ]; then # If patchfile is not empty cd $HOME # If the patch cannot be applied cleanly, show the updates and tell user to update file manually. - if ! patch -f "$HOME/.$scm.scmbrc" $patchfile; then - printf "== \e[0;31mUpdates could not be applied to '\e[1m~/.$scm.scmbrc\e[0;31m'.\e[0m\n" - printf "== Please look at the following changes and manually update '~/.$scm.scmbrc', if necessary.\n\n" - cat "$HOME/.$scm.scmbrc.rej" + if ! patch -f "$HOME/.$prefix""scmbrc" $patchfile; then + printf "== \e[0;31mUpdates could not be applied to '\e[1m~/.$prefix""scmbrc\e[0;31m'.\e[0m\n" + printf "== Please look at the following changes and manually update '~/.$prefix""scmbrc', if necessary.\n\n" + cat "$HOME/.$prefix""scmbrc.rej" fi cd "$scmbDir" fi diff --git a/scm_breeze.sh b/scm_breeze.sh index 56bdf9c..a928c00 100644 --- a/scm_breeze.sh +++ b/scm_breeze.sh @@ -4,13 +4,18 @@ # ------------------------------------------------------------ export scmbDir="$(dirname ${BASH_SOURCE:-$0})" -# Load shared functions. +# Load config +. "$HOME/.scmbrc" + +# Shared functions . "$scmbDir/lib/scm_breeze.sh" +# Design assets management +. "$scmbDir/lib/design.sh" # Git # ------------------------------------------------------------ if [[ -s "$HOME/.git.scmbrc" ]]; then - # Load config + # Load git config . "$HOME/.git.scmbrc" . "$scmbDir/lib/git/aliases_and_bindings.sh" . "$scmbDir/lib/git/status_shortcuts.sh" diff --git a/scmbrc.example b/scmbrc.example new file mode 100644 index 0000000..2e97bed --- /dev/null +++ b/scmbrc.example @@ -0,0 +1,13 @@ +# +# Design Assets Management Config +# ---------------------------------------------------------------- +# Directory where design assets are stored +export root_design_dir="$HOME/Dropbox/Design" +# Directory where symlinks are created within each project +export project_design_dir="design_assets" +# Directories for per-project design assets +export design_base_dirs="Images Backgrounds Logos Icons Mockups Screenshots" +export design_av_dirs="Animations Videos Flash Music Samples" +# Directories for global design assets (not symlinked into projects) +export design_ext_dirs="Fonts IconSets" + diff --git a/test/lib/design_test.sh b/test/lib/design_test.sh new file mode 100755 index 0000000..b461002 --- /dev/null +++ b/test/lib/design_test.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# ------------------------------------------------------------------------------ +# SCM Breeze - Streamline your SCM workflow. +# Copyright 2011 Nathan Broadbent (http://madebynathan.com). All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# ------------------------------------------------------------------------------ +# +# Unit tests for git shell scripts + +export scmbDir="$( cd -P "$( dirname "$0" )" && pwd )/../.." + +# Zsh compatibility +if [ -n "${ZSH_VERSION:-}" ]; then shell="zsh"; SHUNIT_PARENT=$0; setopt shwordsplit; fi + +# Load test helpers +. "$scmbDir/test/support/test_helper" + +# Load functions to test +. "$scmbDir/lib/scm_breeze.sh" +. "$scmbDir/lib/design.sh" + + +# Setup and tear down +#----------------------------------------------------------------------------- +oneTimeSetUp() { + root_design_dir=$(mktemp -d -t tmp.XXXXXXXXXX) + project_design_dir="design" + design_base_dirs="a b c d e" + design_av_dirs="aa bb cc dd ee" + design_ext_dirs="x y z" + + project_dir=$(mktemp -d -t tmp.XXXXXXXXXX) + project_name=$(basename $project_dir) +} + +oneTimeTearDown() { + rm -rf $project_dir $root_design_dir +} + +#----------------------------------------------------------------------------- +# Unit tests +#----------------------------------------------------------------------------- + +test_design() { + cd $project_dir + # Test creation of base and extra design directories + design init > /dev/null + for dir in $design_ext_dirs; do + assertTrue "Root design dir not created! ($dir)" "[ -d $root_design_dir/$dir ]" || return + done + for dir in $design_base_dirs; do + assertTrue "Root design dir not created! ($dir)" "[ -d $root_design_dir/$dir/$project_name ]" || return + assertTrue "Project design dir not created! ($dir)" "[ -d $project_dir/design/$dir ]" || return + done + + # Test creation of 'av' design directories + design init --av > /dev/null + for dir in $design_base_dirs $design_av_dirs; do + assertTrue "Root design dir not created! ($dir)" "[ -d $root_design_dir/$dir/$project_name ]" || return + assertTrue "Project design dir not created! ($dir)" "[ -d $project_dir/design/$dir ]" || return + done + + # Test that 'design trim' removes empty directories, but doesn't touch non-empty directories + touch design/a/testfile design/c/testfile + design trim > /dev/null + assertTrue "[ -d $project_dir/design/a ] && [ -d $root_design_dir/a/$project_name ]" + assertFalse "[ -d $project_dir/design/b ] || [ -d $root_design_dir/b/$project_name ]" + assertTrue "[ -d $project_dir/design/c ] && [ -d $root_design_dir/c/$project_name ]" + assertFalse "[ -d $project_dir/design/d ] || [ -d $root_design_dir/d/$project_name ]" + assertFalse "[ -d $project_dir/design/e ] || [ -d $root_design_dir/e/$project_name ]" + + # Test that 'design rm' removes all directories + touch design/a/testfile design/c/testfile + design rm > /dev/null + assertFalse "[ -d $project_dir/design/a ] || [ -d $root_design_dir/a/$project_name ]" + assertFalse "[ -d $project_dir/design/b ] || [ -d $root_design_dir/b/$project_name ]" + assertFalse "[ -d $project_dir/design/c ] || [ -d $root_design_dir/c/$project_name ]" + assertFalse "[ -d $project_dir/design/d ] || [ -d $root_design_dir/d/$project_name ]" + assertFalse "[ -d $project_dir/design/e ] || [ -d $root_design_dir/e/$project_name ]" +} + + +# load and run shUnit2 +# Call this function to run tests +. "$scmbDir/test/support/shunit2" +