Statistics
| Branch: | Revision:

amiro-apps / tools / ide / QtCreator / QtCreatorSetup.sh @ 21f9c863

History | View | Annotate | Download (28.9 KB)

1
################################################################################
2
# AMiRo-Apps is a collection of applications and configurations for the        #
3
# Autonomous Mini Robot (AMiRo).                                               #
4
# Copyright (C) 2018..2020  Thomas Schöpping et al.                            #
5
#                                                                              #
6
# This program is free software: you can redistribute it and/or modify         #
7
# it under the terms of the GNU General Public License as published by         #
8
# the Free Software Foundation, either version 3 of the License, or            #
9
# (at your option) any later version.                                          #
10
#                                                                              #
11
# This program is distributed in the hope that it will be useful,              #
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
14
# GNU General Public License for more details.                                 #
15
#                                                                              #
16
# You should have received a copy of the GNU General Public License            #
17
# along with this program.  If not, see <http://www.gnu.org/licenses/>.        #
18
#                                                                              #
19
# This research/work was supported by the Cluster of Excellence Cognitive      #
20
# Interaction Technology 'CITEC' (EXC 277) at Bielefeld University, which is   #
21
# funded by the German Research Foundation (DFG).                              #
22
################################################################################
23

    
24
#!/bin/bash
25

    
26
# load library
27
source "$(dirname ${BASH_SOURCE[0]})/../../bash/setuplib.sh"
28

    
29
### print welcome text #########################################################
30
# Prints a welcome message to standard out.
31
#
32
# usage:      printWelcomeText
33
# arguments:  n/a
34
# return:     n/a
35
#
36
function printWelcomeText {
37
  printf "######################################################################\n"
38
  printf "#                                                                    #\n"
39
  printf "#                  Welcome to the QtCreator setup!                   #\n"
40
  printf "#                                                                    #\n"
41
  printf "######################################################################\n"
42
  printf "#                                                                    #\n"
43
  printf "# Copyright (c) 2018..2020  Thomas Schöpping                         #\n"
44
  printf "#                                                                    #\n"
45
  printf "# This is free software; see the source for copying conditions.      #\n"
46
  printf "# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n"
47
  printf "# A PARTICULAR PURPOSE. The development of this software was         #\n"
48
  printf "# supported by the Excellence Cluster EXC 227 Cognitive Interaction  #\n"
49
  printf "# Technology. The Excellence Cluster EXC 227 is a grant of the       #\n"
50
  printf "# Deutsche Forschungsgemeinschaft (DFG) in the context of the German #\n"
51
  printf "# Excellence Initiative.                                             #\n"
52
  printf "#                                                                    #\n"
53
  printf "######################################################################\n"
54
}
55

    
56
### print help #################################################################
57
# Prints a help text to standard out.
58
#
59
# usage:      printHelp
60
# arguments:  n/a
61
# return:     n/a
62
#
63
function printHelp {
64
  printInfo "printing help text\n"
65
  printf "usage:    $(basename ${BASH_SOURCE[0]}) [-h|--help] [-c|--create=<configuration>] [-d|--delete=<configuration>] [-q|--quit] [--log=<file>]\n"
66
  printf "\n"
67
  printf "options:  -h, --help\n"
68
  printf "              Print this help text.\n"
69
  printf "          -c, --create <configuration>\n"
70
  printf "              Create projects for a single configuration or for all configurations (<configuration>='*').\n"
71
  printf "          -d, --delete <configuration>\n"
72
  printf "              Delete projet files of a single configuration or of all configurations (<configuration>='*').\n"
73
  printf "          -q, --quit\n"
74
  printf "              Quit the script.\n"
75
  printf "          --log=<file>\n"
76
  printf "              Specify a log file.\n"
77
}
78

    
79
### read directory where to create/delete projects #############################
80
# Read the directory where to create/delete project files from user.
81
#
82
# usage:      getProjectsDir <pathvar>
83
# arguments:  <pathvar>
84
#                 Variable to store the selected path to.
85
# return:     n/a
86
#
87
function getProjectsDir {
88
  local amiroappsdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../../)
89
  local input=""
90

    
91
  printLog "reading path for project files from user...\n"
92
  read -p "Path where to create/delete project files: " -i $amiroappsdir -e input
93
  printLog "user selected path $(realpath $input)\n"
94
  eval $1="$(realpath $input)"
95
}
96

    
97
### retrieves the ARM-NONE-EABI-GCC include directory ##########################
98
# Retrieves the include directory of the currently set arm-none-eabi-gcc.
99
#
100
# usage:      retrieveGccIncludeDir <path>
101
# arguments:  <path>
102
#                 Variable to store the path to.
103
# return:    0
104
#                 No error or warning occurred.
105
#            -1
106
#                 Error: Command 'arm-none-eabi-gcc' not found.
107
#            -2
108
#                 Error: include directory could not be resolved.
109
#
110
function retrieveGccIncludeDir {
111
  local binpath=$(which arm-none-eabi-gcc)
112
  local gccincpath=""
113

    
114
  # retrieve binary path or link
115
  if [ -z "$binpath" ]; then
116
    printError "command 'arm-none-eabi-gcc' not found\n"
117
    return -1
118
  else 
119

    
120
    # traverse any links
121
    while [ -L "$binpath" ]; do
122
      binpath=$(realpath $(dirname $binpath)/$(readlink $binpath))
123
    done
124
    printInfo "gcc-arm-none-eabi detected: $binpath\n"
125

    
126
    # return include path
127
    gccincpath=$(realpath $(dirname ${binpath})/../arm-none-eabi/include/)
128
    if [ ! -d "$gccincpath" ]; then
129
      printWarning "$gccincpath does not exist\n"
130
      return -2
131
    else
132
      eval $1="$gccincpath"
133
      return 0
134
    fi
135
  fi
136
}
137

    
138
### detect available configurations ############################################
139
# Detect all avalable configurations.
140
#
141
# usage:      detectConfigurations <configurationsarray>
142
# arguments:  <configurationsarray>
143
#                 Array variable to store all detected configurations to.
144
# return:     n/a
145
#
146
function detectConfigurations {
147
  local configs_detected=()
148
  local configsdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../../configurations)
149

    
150
  # detect all available modules (via directories)
151
  for dir in $(ls -d ${configsdir}/*/); do
152
    configs_detected[${#configs_detected[@]}]=$(basename $dir)
153
  done
154

    
155
  # set the output variable
156
  eval "$1=(${configs_detected[*]})"
157
}
158

    
159
### create project files for a single or for all configurations ################
160
# Create project files for all modules of a single or of all configurations.
161
#
162
# usage:      createProject <configurations> [-c|--configuration=<configuration>] [-p|--path=<path>] [--gcc=<path>] [-o|--out=<var>] [--gccout=<var>]
163
# arguments:  <configurations>
164
#                 Array containing all configurations available.
165
#             -c, --configuration <configuration>
166
#                 Name (folder name) of the configuration for which project files shall be generated.
167
#                 Set <configuration> to '*' in order to generate projects for all available configurations.
168
#             -p, --path <path>
169
#                 Path where to create the project files.
170
#             --gcc=<path>
171
#                 Path to the GCC include directory.
172
#             -o, --out <var>
173
#                 Variable to store the path to.
174
#             --gccout=<var>
175
#                 Variable to store the path to the GCC include directory to.
176
#                 If this optional arguments is absent, ths function will ask for user input.
177
# return:     0
178
#                 No error or warning occurred.
179
#             1
180
#                 Aborted by user.
181
#             2
182
#                 The selected configuration does not contain any modules.
183
#             -1
184
#                 No configurations available.
185
#             -2
186
#                 The specified <configuration> could not be found.
187
#             -3
188
#                 Parsing the project for the specified configuration failed.
189
#             -4
190
#                 Missing dependencies.
191
#
192
function createProject {
193
  local config=""
194
  local configs=("${!1}")
195
  local configs2generate=()
196
  local configsdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../../configurations)
197
  local gccincludedir=""
198
  local gccoutvar=""
199
  local includes=()
200
  local makedir=""
201
  local makedirs=()
202
  local modules=()
203
  local otherargs=()
204
  local outvar=""
205
  local parse_state=""
206
  local projectfiles=()
207
  local projects=()
208
  local projectsdir=""
209
  local quotes="\'\"\´\`\„\“"
210
  local rawout=""
211
  local sourcefile=""
212
  local sourcefiles=()
213
  local userdir=$(pwd)
214
  local userinput=""
215

    
216
  # check dependencies
217
  checkCommands make
218
  if [ $? -ne 0 ]; then
219
    printError "Missing dependencies detected.\n"
220
    return -4
221
  fi
222

    
223
  # parse arguments
224
  while [ $# -gt 0 ]; do
225
    if ( parseIsOption $1 ); then
226
      case "$1" in
227
        -c=*|--configuration=*)
228
          config="${1#*=}"; shift 1;;
229
        -c|--configuration)
230
          config="$2"; shift 2;;
231
        -p=*|--path=*)
232
          projectsdir=$(realpath "${1#*=}"); shift 1;;
233
        -p|--path)
234
          projectsdir=$(realpath "$2"); shift 2;;
235
        --gcc=*)
236
          gccincludedir=$(realpath "${1#*=}"); shift 1;;
237
        --gcc)
238
          gccincludedir=$(realpath "$2"); shift 2;;
239
        -o=*|--out=*)
240
          outvar=${1#*=}; shift 1;;
241
        -o|--out)
242
          outvar=$2; shift 2;;
243
        --gccout=*)
244
          gccoutvar=$(realpath "${1#*=}"); shift 1;;
245
        --gccout)
246
          gccoutvar=$(realpath "$2"); shift 2;;
247
        *)
248
          printError "invalid option: $1\n"; shift 1;;
249
      esac
250
    else
251
      otherargs+=("$1")
252
      shift 1
253
    fi
254
  done
255

    
256
  # sanity check for the configs variable
257
  if [ -z "${configs[*]}" ]; then
258
    printError "no configurations available\n"
259
    return -1
260
  fi
261

    
262
  # select configuration
263
  if [ -z $config ]; then
264
    # list all available configurations
265
    printInfo "select a configuration, type '*' for all or type 'A' to abort:\n"
266
    for (( idx=0; idx<${#configs[@]}; ++idx )); do
267
      printf "%4u: %s\n" $(($idx + 1)) "${configs[$idx]}"
268
    done
269
    # read user input
270
    printLog "read user selection\n"
271
    userinput=""
272
    while [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#configs[@]} ] && [[ ! "$userinput" =~ ^(\*|[Aa])$ ]]; do
273
      read -p "your selection: " -e userinput
274
      printLog "user selection: $userinput\n"
275
      if [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#configs[@]} ] && [[ ! "$userinput" =~ ^(\*|[Aa])$ ]]; then
276
        printWarning "Please enter an integer between 1 and ${#configs[@]}, '*' to select all or 'A' to abort.\n"
277
      fi
278
    done
279
    if [[ "$userinput" =~ ^[0-9]+$ ]]; then
280
      # store selection
281
      configs2generate=(${configs[$(($userinput - 1))]})
282
    elif [[ "$userinput" =~ ^\*$ ]]; then
283
      configs2generate=(${configs[@]})
284
    elif [[ "$userinput" =~ ^[Aa]$ ]]; then
285
      printWarning "aborted by user\n"
286
      return 1
287
    fi
288
    printf "\n"
289
  else
290
    # check whether the specified configuration is available
291
    if [[ ! "${configs[@]}" =~ "$config" ]]; then
292
      printError "configuration '$config' not available\n"
293
      return -2
294
    else
295
      configs2generate=($config)
296
    fi
297
  fi
298

    
299
  # generate project names for all modules of all selected configurations
300
  for config in ${configs2generate[@]}; do
301
    if [ -d ${configsdir}/${config}/modules ]; then
302
      modules=($(find ${configsdir}/${config}/modules/ -mindepth 1 -maxdepth 1 -type d))
303
      if [ ${#modules[@]} -gt 0 ]; then
304
        for module in ${modules[@]}; do
305
          projects+=("${config}_$(basename ${module})")
306
        done
307
      else
308
        printWarning "configuration '${config}' does not contain any modules\n"
309
      fi
310
    else
311
      printWarning "no 'modules/' folder exists in configuration '${config}'\n"
312
    fi
313
  done
314
  if [ ${#projects[@]} -eq 0 ]; then
315
    printWarning "no modules detected, aborting\n"
316
    return 2
317
  fi
318

    
319
  # read absolute project directory if required
320
  if [ -z "$projectsdir" ]; then
321
    getProjectsDir projectsdir
322
    printf "\n"
323
  fi
324

    
325
  # check for existing project files
326
  for project in ${projects[@]}; do
327
    projectfiles+=($(find ${projectsdir} -maxdepth 1 -type f -regextype posix-extended -regex "^.*/${project}\.(includes|files|config|creator)$" | sort))
328
  done
329
  if [ ${#projectfiles[@]} != 0 ]; then
330
    printWarning "The following files will be overwritten:\n"
331
    for pfile in ${projectfiles[@]}; do
332
      printWarning "\t$(basename $pfile)\n"
333
    done
334
    userinput=""
335
    printInfo "Continue and overwrite? [y/n]\n"
336
    readUserInput "YyNn" userinput
337
    case "$userinput" in
338
      Y|y)
339
        ;;
340
      N|n)
341
        printWarning "project generation aborted by user\n"
342
        return 1
343
        ;;
344
      *)
345
        printError "unexpected input: ${userinput}\n"; return -999;;
346
    esac
347
    printf "\n"
348
  fi
349

    
350
  # retrieve absolute GCC include path
351
  if [ -z "$gccincludedir" ]; then
352
    retrieveGccIncludeDir gccincludedir
353
  fi
354

    
355
  # generate for all configurations
356
  cd "$projectsdir"
357
  for config in ${configs2generate[@]}; do
358
    # retrieve all modules
359
    modules=()
360
    for dir in $(find ${configsdir}/${config}/modules -mindepth 1 -maxdepth 1 -type d); do
361
      modules+=($(basename $dir))
362
    done
363
    # silently skip this configuration if it contains no modules
364
    if [ ${#modules[@]} == 0 ]; then
365
      continue
366
    fi
367

    
368
    printInfo "generating QtCreator projects for configuration '${config}'...\n"
369
    for module in ${modules[@]}; do
370
      # run make, but only run the GCC preprocessor and produce no binaries
371
      sourcefiles=()
372
      sourcefile=""
373
      parse_state="WAIT_FOR_INCLUDE_COMPILE_MAKE"
374
      makedir=""
375
      makedirs=()
376
      # capture all output from make and GCC and append the return value of make as last line
377
      printInfo "processing module ${module} (this may take a while)...\n"
378
      rawout=$(make --directory ${configsdir}/${config}/modules/${module} --always-make USE_OPT="-v -E -H" USE_VERBOSE_COMPILE="no" OUTFILES="" 2>&1 && echo $?)
379
      # check whether the make call was successfull
380
      if [[ $(echo "${rawout}" | tail -n 1) != "0" ]]; then
381
        printError "executing 'make' in configuration directory failed\n"
382
        cd "$userdir"
383
        return -3
384
      else
385
        # cleanup
386
        make --directory ${configsdir}/${config}/modules/${module} clean &>/dev/null
387
      fi
388
      # extract file names from raw output
389
      IFS=$'\n'; rawout=($rawout); unset IFS
390
      for line in "${rawout[@]}"; do
391
        case $parse_state in
392
          WAIT_FOR_INCLUDE_COMPILE_MAKE)
393
            # lines stating include files look like:
394
            # ... <../relative/path/to/file>
395
            if [[ "$line" =~ ^\.+[[:blank:]].+\..+$ ]]; then
396
              sourcefile=${line##* }
397
              if [[ ! "$sourcefile" =~ ^/ ]]; then
398
                sourcefile=$(realpath ${makedirs[-1]}/${sourcefile})
399
              fi
400
              sourcefiles[${#sourcefiles[@]}]="$sourcefile"
401
            # whenever the next source file is processed, a message appears like:
402
            # Compiling <filename>
403
            elif [[ "$line" =~ ^Compiling[[:blank:]](.+\..+)$ ]]; then
404
              printf "."
405
              sourcefile=${BASH_REMATCH[1]}
406
              parse_state="WAIT_FOR_COMPILERCALL"
407
            # if make is called again in another directory or a nested make call leaves the directory, a message appears like:
408
            # make[1]: Entering directory 'directory'
409
            # make[999]: Verzeichnis „directory“ wird verlassen
410
            elif [[ "$line" =~ ^make(\[[0-9]+\])?:([[:alnum:]]|[[:blank:]])*[$quotes].*[$quotes]([[:alnum:]]|[[:blank:]])*$ ]]; then
411
              # extract directory path
412
              makedir=$(echo ${line} | grep -oE "[${quotes}].*[${quotes}]" | grep -oE "[^${quotes}].*[^${quotes}]")
413
              # if the makedirs stack is empty or the directory does not mathc the last entry
414
              if [ ${#makedirs[@]} == 0 ] || [ "${makedir}" != "${makedirs[-1]}" ]; then
415
                # push the directory to the stack
416
                makedirs+=(${makedir})
417
              else
418
                # pop the directory from the stack
419
                unset makedirs[-1]
420
              fi
421
            fi;;
422
          WAIT_FOR_COMPILERCALL)
423
            # wait for the actual call of the compiler to retrieve the full path to the source file
424
            if [[ "$line" == *${sourcefile}* ]]; then
425
              line="${line%%${sourcefile}*}${sourcefile}"
426
              line="${line##* }"
427
              if [[ "$line" =~ ^/ ]]; then
428
                # aboslute path
429
                sourcefile=$line
430
              else
431
                # relative path
432
                sourcefile=$(realpath ${makedirs[-1]}/${line##* })
433
              fi
434
              sourcefiles[${#sourcefiles[@]}]="$sourcefile"
435
              parse_state="WAIT_FOR_INCLUDE_COMPILE_MAKE"
436
            fi;;
437
        esac
438
      done
439
      printf "\n"
440
      # sort and remove duplicates
441
      IFS=$'\n'; sourcefiles=($(sort --unique <<< "${sourcefiles[*]}")); unset IFS
442

    
443
      # extract include paths
444
      for source in ${sourcefiles[*]}; do
445
        includes[${#includes[@]}]="$(dirname ${source})"
446
      done
447
      # sort and remove duplicates
448
      IFS=$'\n'; includes=($(sort --unique <<< "${includes[*]}")); unset IFS
449

    
450
      # generate the .incldues file, containing all include paths
451
      echo "" > ${projectsdir}/${config}_${module}.includes
452
      for inc in ${includes[*]}; do
453
        echo "$inc" >> ${projectsdir}/${config}_${module}.includes
454
      done
455
      # generate the .files file, containing all source files
456
      echo "" > ${projectsdir}/${config}_${module}.files
457
      for source in ${sourcefiles[*]}; do
458
        # skip GCC files
459
        if [[ ! "$source" =~ .*/gcc.* ]]; then
460
          echo "$source" >> ${projectsdir}/${config}_${module}.files
461
        fi
462
      done
463
      # generate a default project configuration file if it doesn't exits yet
464
      if [ ! -f ${projectsdir}/${config}_${module}.config ]; then
465
        echo "// Add predefined macros for your project here. For example:" > ${projectsdir}/${config}_${module}.config
466
        echo "// #define YOUR_CONFIGURATION belongs here" >> ${projectsdir}/${config}_${module}.config
467
      fi
468
      # generate a default .creator file if it doesn't exist yet
469
      if [ ! -f ${projectsdir}/${config}_${module}.creator ]; then
470
        echo "[general]" > ${projectsdir}/${config}_${module}.creator
471
      fi
472
    done
473
  done
474

    
475
  # go back to user directory
476
  cd "$userdir"
477

    
478
  # fill the output variables
479
  if [ ! -z "$outvar" ]; then
480
    eval $outvar="$projectsdir"
481
  fi
482
  if [ ! -z "$gccoutvar" ]; then
483
    eval $gccoutvar="$gccincludedir"
484
  fi
485

    
486
  return 0
487
}
488

    
489
### delete project files for a single or all modules ###########################
490
# Deletes all project files and optionally .user files, too.
491
#
492
# usage:      deleteProject [-p|--path=<path>] [-m|--module=<project>] [-o|--out=<var>] [-w|-wipe=<flag>]
493
# arguments:  -p, --path <path>
494
#                 Path where to delete the project files.
495
#             -m, --module <project>
496
#                 Project name for which the project files shall be deleted or '*' to delete for all modules.
497
#             -o, --out <var>
498
#                 Variable to store the path to.
499
#             -w, --wipe <flag>
500
#                 Flag whether to delete .user files as well (must be either "true" or "false").
501
# return:     0
502
#               No error or warning occurred.
503
#             1
504
#               Aborted by user.
505
#             2
506
#               There are no project files for the specified module at the specified location.
507
#
508
function deleteProject {
509
  local files=()
510
  local otherargs=()
511
  local outvar=""
512
  local project=""
513
  local projects=()
514
  local projects2delete=()
515
  local projectsdir=""
516
  local userinput=""
517
  local wipe=""
518

    
519
  # parse arguments
520
  while [ $# -gt 0 ]; do
521
    if ( parseIsOption $1 ); then
522
      case "$1" in
523
        -p=*|--path=*)
524
          projectsdir=$(realpath "${1#*=}"); shift 1;;
525
        -p|--path)
526
          projectsdir=$(realpath "$2"); shift 2;;
527
        -m=*|--module=*)
528
          project="${1#*=}"; shift 1;;
529
        -m|--module)
530
          project="${2}"; shift 2;;
531
        -o=*|--out=*)
532
          outvar=${1#*=}; shift 1;;
533
        -o|--out)
534
          outvar=$2; shift 2;;
535
        -w=*|--wipe=*)
536
          wipe="${1#*=}"; shift 1;;
537
        -w|--wipe)
538
          wipe="$2"; shift 2;;
539
        *)
540
          printError "invalid option: $1\n"; shift 1;;
541
      esac
542
    else
543
      otherargs+=("$1")
544
      shift 1
545
    fi
546
  done
547

    
548
  # sanity checks on parameters
549
  if [ ! -z $wipe ] && [[ ! "$wipe" =~ ^(true|false)$ ]]; then
550
    printWarning "invalid value set to 'wipe' argument\n"
551
    printInfo "I will act as if there was no '--wipe' argument and ask for input later.\n"
552
    wipe=""
553
  fi
554

    
555
  # read absolute project directory if required
556
  if [ -z "$projectsdir" ]; then
557
    getProjectsDir projectsdir
558
    printf "\n"
559
  fi
560

    
561
  # retrieve all projects in the specified directory
562
  projects=($(find "${projectsdir}" -maxdepth 1 -type f -regextype posix-extended -regex "^.+\.(includes|files|config|creator|cflags|cxxflags|creator\.user(\..+)?)$" | grep -oE "/[^/\.]+\." | grep -oE "[^/].+[^\.]" | sort --unique))
563

    
564
  # check whether there are any project files at the specified location
565
  if [ ${#projects[@]} -eq 0 ]; then
566
    printWarning "no projects detected at '${projectsdir}'\n"
567
    return 2
568
  fi
569

    
570
  # select project
571
  if [ -z "$project" ]; then
572
    # list all available projects
573
    printInfo "select a project, type '*' for all or type 'A' to abort:\n"
574
    for (( idx=0; idx<${#projects[@]}; ++idx )); do
575
      printf "%4u: %s\n" $(($idx + 1)) "${projects[$idx]}"
576
    done
577
    # read user input
578
    printLog "read user selection\n"
579
    userinput=""
580
    while [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#projects[@]} ] && [[ ! "$userinput" =~ ^(\*|[Aa])$ ]]; do
581
      read -p "your selection: " -e userinput
582
      printLog "user selection: $userinput\n"
583
      if [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#projects[@]} ] && [[ ! "$userinput" =~ ^(\*|[Aa])$ ]]; then
584
        printWarning "Please enter an integer between 1 and ${#projects[@]}, '*' to select all or 'A' to abort.\n"
585
      fi
586
    done
587
    if [[ "$userinput" =~ ^[0-9]+$ ]]; then
588
      # store selection
589
      projects2delete=(${projects[$(($userinput - 1))]})
590
    elif [[ "$userinput" =~ ^\*$ ]]; then
591
      projects2delete=(${projects[@]})
592
    elif [[ "$userinput" =~ ^[Aa]$ ]]; then
593
      printWarning "aborted by user\n"
594
      return 1
595
    else
596
      printError "unexpected user input: ${userinput}\n"
597
      return -999
598
    fi
599
    printf "\n"
600
  else
601
    # check whether the specified project is available
602
    if [[ ! "${projects[@]}" =~ "$project" ]]; then
603
      printWarning "there are no files for project '$project' at location '$projectsdir'\n"
604
      return 2
605
    else
606
      projects2delete=($project)
607
    fi
608
  fi
609

    
610
  # check for .user files
611
  files=()
612
  for project in ${projects2delete[@]}; do
613
    files+=($(find "${projectsdir}" -maxdepth 1 -type f -regextype posix-extended -regex "^.*${project}\.creator\.user(\..+)?$"))
614
  done
615

    
616
  # read wipe information if required
617
  if [ ${#files[@]} -gt 0 ] && [ -z "$wipe" ]; then
618
    userinput=""
619
    printInfo "Wipe user data as well? [y/n]\n"
620
    readUserInput "YyNn" userinput
621
    case "$userinput" in
622
      Y|y)
623
        wipe="true";;
624
      N|n)
625
        wipe="false";;
626
      *)
627
        printError "unexpected input: ${userinput}\n"; return -999;;
628
    esac
629
    printf "\n"
630
  fi
631

    
632
  # retrieve all files
633
  files=()
634
  for project in ${projects2delete[@]}; do
635
    if [ "$wipe" == "true" ]; then
636
      files+=($(find "${projectsdir}" -maxdepth 1 -type f -regextype posix-extended -regex "^.*${project}\.(includes|files|config|creator|cflags|cxxflags|creator\.user(\..+)?)$"))
637
    else
638
      files+=($(find "${projectsdir}" -maxdepth 1 -type f -regextype posix-extended -regex "^.*${project}\.(includes|files|config|creator|cflags|cxxflags)$"))
639
    fi
640
  done
641

    
642
  # list all files to be deleted and ask for confirmation
643
  if [ ${#files[@]} -gt 0 ]; then
644
    printWarning "The following files will be deleted:\n"
645
    for file in ${files[@]}; do
646
      printWarning "\t$(basename ${file})\n"
647
    done
648
    userinput=""
649
    printInfo "Do you want to continue? [y/n]\n"
650
    readUserInput "YyNn" userinput
651
    case "$userinput" in
652
      Y|y)
653
        ;;
654
      N|n)
655
        printWarning "aborted by user\n"
656
        return 1;;
657
      *)
658
        printError "unexpected input: ${userinput}\n"; return -999;;
659
    esac
660
  else
661
    printInfo "no files to delete\n"
662
  fi
663

    
664
  # finally delete the files
665
  for file in ${files[@]}; do
666
    rm ${file} 2>&1 | tee -a $LOG_FILE
667
  done
668
  printInfo "${#files[@]} files have been deleted\n"
669

    
670
  # store the path to the output variable, if required
671
  if [ ! -z "$outvar" ]; then
672
    eval $outvar="$projectsdir"
673
  fi
674

    
675
  return 0
676
}
677

    
678
### main function of this script ###############################################
679
# Creates, deletes and wipes QtCreator project files.
680
#
681
# usage:      see function printHelp
682
# arguments:  see function printHelp
683
# return:     0
684
#                 No error or warning ocurred.
685
#
686
function main {
687
  local cmd=""
688
  local cmdidx=""
689
  local configurations=()
690
  local filenameidx=""
691
  local logfile=""
692
  local otherargs=()
693
  local userinput=""
694

    
695
  # print welcome/info text if not suppressed
696
  if [[ $@ != *"--noinfo"* ]]; then
697
    printWelcomeText
698
  else
699
    printf "######################################################################\n"
700
  fi
701
  printf "\n"
702

    
703
  # if --help or -h was specified, print the help text and exit
704
  if [[ $@ == *"--help"* || $@ == *"-h"* ]]; then
705
    printHelp
706
    printf "\n"
707
    quitScript
708
  fi
709

    
710
  # set log file if specified
711
  if [[ $@ == *"--log"* ]] || [[ $@ == *"--LOG"* ]]; then
712
    # get the parameter (file name)
713
    cmdidx=1
714
    while [[ ! "${!cmdidx}" = "--log"* ]] && [[ ! "${!cmdidx}" = "--LOG"* ]]; do
715
      cmdidx=$[cmdidx + 1]
716
    done
717
    cmd="${!cmdidx}"
718
    logfile=""
719
    if [[ "$cmd" = "--log="* ]] || [[ "$cmd" = "--LOG="* ]]; then
720
      logfile=${cmd#*=}
721
    else
722
      filenameidx=$((cmdidx + 1))
723
      logfile="${!filenameidx}"
724
    fi
725
    # optionally force silent appending
726
    if [[ "$cmd" = "--LOG"* ]]; then
727
      setLogFile --option=c --quiet "$logfile" LOG_FILE
728
    else
729
      setLogFile "$logfile" LOG_FILE
730
      printf "\n"
731
    fi
732
  fi
733
  # log script name
734
  printLog "this is $(realpath ${BASH_SOURCE[0]})\n"
735

    
736
  # detect available configurations and inform user
737
  detectConfigurations configurations
738
  case "${#configurations[@]}" in
739
    0)
740
      printInfo "no configuration has been detected\n";;
741
    1)
742
      printInfo "1 configuration has been detected:\n";;
743
    *)
744
      printInfo "${#configurations[@]} configurations have been detected:\n";;
745
  esac
746
  for (( idx=0; idx<${#configurations[@]}; ++idx )); do
747
    printInfo "  - ${configurations[$idx]}\n"
748
  done
749
  printf "\n"
750

    
751
  # parse arguments
752
  while [ $# -gt 0 ]; do
753
    if ( parseIsOption $1 ); then
754
      case "$1" in
755
        -h|--help) # already handled; ignore
756
          shift 1;;
757
        -c=*|--create=*)
758
          createProject configurations[@] --configuration="${1#*=}"; printf "\n"; shift 1;;
759
        -c|--create)
760
          createProject configurations[@] --configuration="${2}"; printf "\n"; shift 2;;
761
        -d=*|--delete=*)
762
          deleteProject --module="${1#*=}"; printf "\n"; shift 1;;
763
        -d|--delete)
764
          deleteProject --module="${2}"; printf "\n"; shift 2;;
765
        -q|--quit)
766
          quitScript; shift 1;;
767
        --log=*|--LOG=*) # already handled; ignore
768
          shift 1;;
769
        --log|--LOG) # already handled; ignore
770
          shift 2;;
771
        --noinfo) # already handled; ignore
772
          shift 1;;
773
        *)
774
          printError "invalid option: $1\n"; shift 1;;
775
      esac
776
    else
777
      otherargs+=("$1")
778
      shift 1
779
    fi
780
  done
781

    
782
  # interactive menu
783
  while ( true ); do
784
    # main menu info prompt and selection
785
    printInfo "QtCreator setup main menu\n"
786
    printf "Please select one of the following actions:\n"
787
    printf "  [C] - create project files\n"
788
    printf "  [D] - delete project files\n"
789
    printf "  [Q] - quit this setup\n"
790
    userinput=""
791
    readUserInput "CcDdQq" userinput
792
    printf "\n"
793

    
794
    # evaluate user selection
795
    case "$userinput" in
796
      C|c)
797
        createProject configurations[@]; printf "\n";;
798
      D|d)
799
        deleteProject; printf "\n";;
800
      Q|q)
801
        quitScript;;
802
      *) # sanity check (exit with error)
803
        printError "unexpected argument: $userinput\n";;
804
    esac
805
  done
806

    
807
  exit 0
808
}
809

    
810
################################################################################
811
# SCRIPT ENTRY POINT                                                           #
812
################################################################################
813

    
814
main "$@"