da02d85aefb91c853bba6b3b9342c2621441cf40
[config.git] / bash / bashject
1
2 # Project manager
3
4 # This project manager allows you to have a quick way to switch between several different work environments
5 # Projects config is stored on a centralized file
6 # Each project contains a local bash configuration, sourced when setting it
7 #  
8
9 BASHJECT_HELP_ADD="bashject a|add      name path     # Adds a project"
10 BASHJECT_HELP_SET="bashject s|set      name          # Enter a project"
11 BASHJECT_HELP_SOURCE="bashject source     name          # Source the project file of the specified project (useful to handle common envs)"
12 BASHJECT_HELP_EDIT="bashject edit       name          # Edit the project file of the specified project with ${EDITOR}"
13 BASHJECT_HELP_REMOVE="bashject rm|remove  name          # Remove the project (no filesystem modifications)"
14 BASHJECT_HELP_RENAME="bashject rename     old    new    # Rename the project (no filesystem modifications)"
15 BASHJECT_HELP_PATH="bashject path       name          # Echoes a project's path"
16 BASHJECT_HELP_NAMES="bashject names                    # Echoes all projects, separated by whitespaces"
17 BASHJECT_HELP_LIST="bashject list                     # Echoes all projects, separated by newlines (useful with dmenu, for example)"
18 BASHJECT_HELP_CD="bashject cd                       # cd to the current project root path"
19 BASHJECT_HELP_HELP="bashject help       [cmd]         # Display global or specific command help"
20
21 # Configuration defaults
22
23 BASHJECT_PRJ_STORE_DEFAULT=${HOME}/work/.projects
24 BASHJECT_PRJ_FILE_DEFAULT=".prj_env"
25 BASHJECT_CHANGE_PROMPT_DEFAULT=-1
26 BASHJECT_ALIAS_DEFAULT=""
27 BASHJECT_TMP_DEFAULT="/tmp/bashject.tmp"
28
29 # Configuration values
30
31 BASHJECT_PRJ_STORE=${BASHJECT_PRJ_STORE:-${BASHJECT_PRJ_STORE_DEFAULT}}
32 BASHJECT_PRJ_FILE=${BASHJECT_PRJ_FILE:-${BASHJECT_PRJ_FILE_DEFAULT}}
33 BASHJECT_CHANGE_PROMPT=${BASHJECT_CHANGE_PROMPT:-${BASHJECT_CHANGE_PROMPT_DEFAULT}}
34 BASHJECT_ALIAS=${BASHJECT_ALIAS:-${BASHJECT_ALIAS_DEFAULT}}
35 BASHJECT_TMP=${BASHJECT_TMP:-${BASHJECT_TMP_DEFAULT}}
36
37 read -d '' BASHJECT_HELP << EOF
38  Usage:
39     - Add a project with 'bashject add name path'
40     - Enter a project with 'bashject set name'
41     - Customize his environment with 'bashject edit name' (or editing his ${BASHJECT_PRJ_DIR}/${BASHJECT_PRJ_FILE})
42
43  Exported vars:
44     - BASHJECT_PRJ_NAME: name of the project
45     - BASHJECT_PRJ_PATH: path to the root of the project
46
47  Commands:
48     - ${BASHJECT_HELP_ADD}
49     - ${BASHJECT_HELP_SET}
50     - ${BASHJECT_HELP_SOURCE}
51     - ${BASHJECT_HELP_EDIT}
52     - ${BASHJECT_HELP_REMOVE}
53     - ${BASHJECT_HELP_RENAME}
54     - ${BASHJECT_HELP_PATH}
55     - ${BASHJECT_HELP_NAMES}
56     - ${BASHJECT_HELP_LIST}
57     - ${BASHJECT_HELP_CD}
58     - ${BASHJECT_HELP_HELP}
59
60  Configuration (to override values, define them before sourcing this file)
61     - BASHJECT_PRJ_STORE                # File in which we store all projects configuration  (default: '${BASHJECT_PRJ_STORE_DEFAULT}', current: '${BASHJECT_PRJ_STORE}')
62     - BASHJECT_PRJ_FILE                 # Name of the project file, created at his root and sourced on 'bashject set'  (default: '${BASHJECT_PRJ_FILE_DEFAULT}', current: '${BASHJECT_PRJ_FILE}')
63     - BASHJECT_CHANGE_PROMPT            # 1 to change the prompt to '[ BASHJECT_PRJ_NAME ] PS1' > on 'bashject set'  (default: '${BASHJECT_CHANGE_PROMPT_DEFAULT}', current: '${BASHJECT_CHANGE_PROMPT}')
64     - BASHJECT_ALIAS                    # Name of an alias for bashject to define (i.e: 'bj'), autocompletion will be handled (default: '${BASHJECT_ALIAS_DEFAULT}', current: '${BASHJECT_ALIAS}')
65     - BASHJECT_TMP                      # Temp file used for rename and remove operations (default: '${BASHJECT_TMP_DEFAULT}', current: '${BASHJECT_TMP}')
66 EOF
67 #
68 # End of help file
69
70 OLD_PS1="$PS1"
71 BASHJECT_COMMANDS="add set source remove rename edit path names list cd help"
72
73
74 # Real stuff
75 function _bj_help() {
76     if [ -z $1 ]; then 
77         echo -e "${BASHJECT_HELP}" >&2
78     else
79         case "$1" in
80             a|add)       echo -e "${BASHJECT_HELP_ADD}" ;;
81             s|set)       echo -e "${BASHJECT_HELP_SET}" ;;
82             source)      echo -e "${BASHJECT_HELP_SOURCE}" ;;
83             e|edit)      echo -e "${BASHJECT_HELP_EDIT}" ;;
84             rm|remove)   echo -e "${BASHJECT_HELP_REMOVE}" ;;
85             rename)      echo -e "${BASHJECT_HELP_RENAME}" ;;
86             path)        echo -e "${BASHJECT_HELP_PATH}" ;;
87             names)       echo -e "${BASHJECT_HELP_NAMES}" ;;
88             list)        echo -e "${BASHJECT_HELP_LIST}" ;;
89             cd)          echo -e "${BASHJECT_HELP_CD}" ;;
90             help)        echo -e "${BASHJECT_HELP_HELP}" ;;
91             *)
92                 echo "Unknown command: $1" >&2
93                 return 1
94                 ;;
95         esac
96     fi
97 }
98
99 _bj_add_project() {
100     if [ "$#" -eq "2" ]; then
101         local name=$1
102         local path=$(readlink -f $2)
103         echo "$name $path" >> ${BASHJECT_PRJ_STORE}
104         if [ ! -f ${path}/${BASHJECT_PRJ_FILE} ]; then
105             echo "Creating ${path}/${BASHJECT_PRJ_FILE}"
106             echo "# Project ${name} " > ${path}/${BASHJECT_PRJ_FILE}
107         fi
108     else
109         _bj_help "add"
110     fi
111 }
112
113 _bj_failed_path() {
114     echo "No project named '$1'." >&2
115     echo "Similar projects: " >&2
116     for name in $(compgen -W "$(_bj_get_project_names)" -- $1); do
117         echo "  - $name" >&2
118     done
119 }
120
121 _bj_get_project_path() {
122     if [ -f ${BASHJECT_PRJ_STORE} ]; then
123         while read name path; do
124             if [ "$1" = "$name" ]; then
125                 echo $path
126                 return 0
127             fi
128         done < ${BASHJECT_PRJ_STORE}
129     fi
130     return 1
131 }
132
133 _bj_source_project() {
134     local path=$(_bj_get_project_path $1)
135     if [ ! -z "$path" ]; then
136         source $path/${BASHJECT_PRJ_FILE}
137         return 0
138     else
139         _bj_failed_path $1
140     fi
141     return 1
142 }
143
144 _bj_edit_project() {
145     local path=$(_bj_get_project_path $1)
146     if [ ! -z "$path" ]; then
147         ${EDITOR} $path/${BASHJECT_PRJ_FILE}
148         return 0
149     else
150         _bj_failed_path $1
151     fi
152     return 1
153 }
154
155 _bj_set_project() {
156     # Find dir
157     BASHJECT_PRJ_NAME=$1
158     BASHJECT_PRJ_DIR=$(_bj_get_project_path $BASHJECT_PRJ_NAME)
159     if [ ! -z "$BASHJECT_PRJ_DIR" ]; then
160         export BASHJECT_PRJ_DIR
161         export BASHJECT_PRJ_NAME
162         cd $BASHJECT_PRJ_DIR
163         source $BASHJECT_PRJ_DIR/${BASHJECT_PRJ_FILE}
164         if [ "1" -eq "$BASHJECT_CHANGE_PROMPT" ]; then 
165             export PS1="[$BASHJECT_PRJ_NAME] $OLD_PS1"
166         fi
167     else
168         _bj_failed_path $BASHJECT_PRJ_NAME
169     fi
170 }
171
172 _bj_remove_project() {
173     if [ -f ${BASHJECT_PRJ_STORE} ]; then
174         while read name path; do
175             if [ ! "$1" = "$name" ]; then
176                 echo "$name $path" >> ${BASHJECT_TMP}
177             fi
178         done < ${BASHJECT_PRJ_STORE}
179         mv ${BASHJECT_TMP} ${BASHJECT_PRJ_STORE}
180     fi
181     return 0
182 }
183
184 _bj_rename_project() {
185     if [ -f ${BASHJECT_PRJ_STORE} ]; then
186         while read name path; do
187             if [ "$1" = "$name" ]; then
188                 echo "$2 $path" >> ${BASHJECT_TMP}
189             else
190                 echo "$name $path" >> ${BASHJECT_TMP}
191             fi
192         done < ${BASHJECT_PRJ_STORE}
193         mv ${BASHJECT_TMP} ${BASHJECT_PRJ_STORE}
194     fi
195     return 0
196 }
197
198 _bj_get_project_names() {
199     local NAMES=""
200     if [ -f ${BASHJECT_PRJ_STORE} ]; then
201         while read name path; do
202             NAMES="$NAMES $name"
203         done < ${BASHJECT_PRJ_STORE}
204         echo ${NAMES}
205     fi
206     return 0
207 }
208
209 _bj_get_project_list() {
210     local NAMES=""
211     if [ -f ${BASHJECT_PRJ_STORE} ]; then
212         while read name path; do
213             echo $name
214         done < ${BASHJECT_PRJ_STORE}
215     fi
216     return 0
217 }
218
219 function _bj_cd_project() {
220         cd $BASHJECT_PRJ_DIR
221 }
222
223 # Frontend
224 function bashject {
225     fun=$1
226     shift
227     case "$fun" in
228         a|add)       _bj_add_project           "$@" ; return $? ;;
229         s|set)       _bj_set_project           "$@" ; return $? ;;
230         source)      _bj_source_project        "$@" ; return $? ;;
231         e|edit)      _bj_edit_project          "$@" ; return $? ;;
232         rm|remove)   _bj_remove_project        "$@" ; return $? ;;
233         rename)      _bj_rename_project        "$@" ; return $? ;;
234         path)        _bj_get_project_path      "$@" ; return $? ;;
235         names)       _bj_get_project_names     "$@" ; return $? ;;
236         list)        _bj_get_project_list      "$@" ; return $? ;;
237         cd)          _bj_cd_project            "$@" ; return $? ;;
238         help)        _bj_help                  "$@" ; return $? ;;
239         "") 
240             echo "No command provided. Available:"
241             for cmd in ${BASHJECT_COMMANDS}; do
242                 echo "  - $cmd "
243             done
244             return 1
245             ;;
246         *)
247             echo "Unknown command: $fun" >&2
248             return 1
249             ;;
250     esac
251
252
253
254 # Define autocompletion functions 
255
256 _bj_complete_project_name()
257 {
258         local cur
259         _get_comp_words_by_ref cur
260         COMPREPLY=()
261         COMPREPLY=( $(compgen -W "$(_bj_get_project_names)" -- ${cur}) ) 
262         return 0
263
264
265 _bj_complete_command()
266 {
267         local cur
268         _get_comp_words_by_ref cur
269         COMPREPLY=()
270         COMPREPLY=($(compgen -W "${BASHJECT_COMMANDS}" -- "$cur"))
271         return 0
272
273
274 function _bj_complete() {
275     local cur
276     _get_comp_words_by_ref cur
277     COMPREPLY=()
278     # Complete command name 
279     if [ $COMP_CWORD -eq 1 ]; then
280         _bj_complete_command 1
281     else
282         if [ $COMP_CWORD -eq 2 ]; then
283             case ${COMP_WORDS[1]} in
284                 s|set|source|edit|path|rm|remove|rename)       _bj_complete_project_name           1 ;;
285                 help)                                          _bj_complete_command                1 ;;
286                 names|list|cd)                                                                       ;;
287                 a|add)                                                                               ;;
288             esac
289         fi
290     fi
291
292
293 complete -F _bj_complete bashject 
294
295 if [ ! -z "${BASHJECT_ALIAS}" ]; then
296     alias ${BASHJECT_ALIAS}='bashject'
297     complete -F _bj_complete ${BASHJECT_ALIAS} 
298 fi
299
300