Revision 21f9c863

View differences:

tools/ide/QtCreator/QtCreatorSetup.sh
62 62
#
63 63
function printHelp {
64 64
  printInfo "printing help text\n"
65
  printf "usage:    $(basename ${BASH_SOURCE[0]}) [-h|--help] [-p|--project=<project>] [-a|--all] [-c|--clean] [-w|--wipe] [-q|--quit] [--log=<file>]\n"
65
  printf "usage:    $(basename ${BASH_SOURCE[0]}) [-h|--help] [-c|--create=<configuration>] [-d|--delete=<configuration>] [-q|--quit] [--log=<file>]\n"
66 66
  printf "\n"
67 67
  printf "options:  -h, --help\n"
68 68
  printf "              Print this help text.\n"
69
  printf "          -p, --project <project>\n"
70
  printf "              Create projects for a single configuration.\n"
71
  printf "          -a, --all\n"
72
  printf "              Create projects for all configurations.\n"
73
  printf "          -c, --clean\n"
74
  printf "              Delete project files.\n"
75
  printf "          -w, --wipe\n"
76
  printf "              Delete project and .user files.\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"
77 73
  printf "          -q, --quit\n"
78 74
  printf "              Quit the script.\n"
79 75
  printf "          --log=<file>\n"
......
89 85
# return:     n/a
90 86
#
91 87
function getProjectsDir {
92
  printLog "reading path for project files from user...\n"
93 88
  local amiroappsdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../../)
94 89
  local input=""
90

  
91
  printLog "reading path for project files from user...\n"
95 92
  read -p "Path where to create/delete project files: " -i $amiroappsdir -e input
96 93
  printLog "user selected path $(realpath $input)\n"
97 94
  eval $1="$(realpath $input)"
......
111 108
#                 Error: include directory could not be resolved.
112 109
#
113 110
function retrieveGccIncludeDir {
114
  # retrieve binary path or link
115 111
  local binpath=$(which arm-none-eabi-gcc)
116 112
  local gccincpath=""
113

  
114
  # retrieve binary path or link
117 115
  if [ -z "$binpath" ]; then
118 116
    printError "command 'arm-none-eabi-gcc' not found\n"
119 117
    return -1
......
146 144
# return:     n/a
147 145
#
148 146
function detectConfigurations {
149
  local configsdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../../configurations)
150 147
  local configs_detected=()
148
  local configsdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../../configurations)
151 149

  
152 150
  # detect all available modules (via directories)
153 151
  for dir in $(ls -d ${configsdir}/*/); do
......
158 156
  eval "$1=(${configs_detected[*]})"
159 157
}
160 158

  
161
### create project files for a single configuration ############################
162
# Create project files for all modules of a configuration.
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.
163 161
#
164
# usage:      createConfigProjects <configurations> [-c|--config=<configuration>] [-p|--path=<path>] [--gcc=<path>] [-o|--out=<var>] [--gccout=<var>]
162
# usage:      createProject <configurations> [-c|--configuration=<configuration>] [-p|--path=<path>] [--gcc=<path>] [-o|--out=<var>] [--gccout=<var>]
165 163
# arguments:  <configurations>
166 164
#                 Array containing all configurations available.
167
#             -c, --config <configuration>
165
#             -c, --configuration <configuration>
168 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.
169 168
#             -p, --path <path>
170 169
#                 Path where to create the project files.
171 170
#             --gcc=<path>
......
190 189
#             -4
191 190
#                 Missing dependencies.
192 191
#
193
function createConfigProjects {
194
  local userdir=$(pwd)
195
  local configsdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../../configurations)
196
  local configs=("${!1}")
192
function createProject {
197 193
  local config=""
198
  local configidx=""
199
  local projectsdir=""
194
  local configs=("${!1}")
195
  local configs2generate=()
196
  local configsdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../../configurations)
200 197
  local gccincludedir=""
201
  local outvar=""
202 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=""
203 215

  
204 216
  # check dependencies
205 217
  checkCommands make
......
209 221
  fi
210 222

  
211 223
  # parse arguments
212
  local otherargs=()
213 224
  while [ $# -gt 0 ]; do
214 225
    if ( parseIsOption $1 ); then
215 226
      case "$1" in
216
        -c=*|--config=*)
227
        -c=*|--configuration=*)
217 228
          config="${1#*=}"; shift 1;;
218
        -c|--config)
229
        -c|--configuration)
219 230
          config="$2"; shift 2;;
220 231
        -p=*|--path=*)
221 232
          projectsdir=$(realpath "${1#*=}"); shift 1;;
......
251 262
  # select configuration
252 263
  if [ -z $config ]; then
253 264
    # list all available configurations
254
    printInfo "choose a configuration or type 'A' to abort:\n"
265
    printInfo "select a configuration, type '*' for all or type 'A' to abort:\n"
255 266
    for (( idx=0; idx<${#configs[@]}; ++idx )); do
256 267
      printf "%4u: %s\n" $(($idx + 1)) "${configs[$idx]}"
257 268
    done
258 269
    # read user input
259 270
    printLog "read user selection\n"
260
    local userinput=""
261
    while [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#configs[@]} ] && [[ ! "$userinput" =~ ^[Aa]$ ]]; do
271
    userinput=""
272
    while [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#configs[@]} ] && [[ ! "$userinput" =~ ^(\*|[Aa])$ ]]; do
262 273
      read -p "your selection: " -e userinput
263 274
      printLog "user selection: $userinput\n"
264
      if [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#configs[@]} ] && [[ ! "$userinput" =~ ^[Aa]$ ]]; then
265
        printWarning "Please enter an integer between 1 and ${#configs[@]} or 'A' to abort.\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"
266 277
      fi
267 278
    done
268
    if [[ "$userinput" =~ ^[Aa]$ ]]; then
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
269 285
      printWarning "aborted by user\n"
270 286
      return 1
271 287
    fi
272
    # store selection
273
    configidx=$(($userinput - 1))
274
    config="${configs[$configidx]}"
275 288
    printf "\n"
276 289
  else
277
    # search all configurations for the selected one
278
    for (( idx=0; idx<${#configs[@]}; ++idx )); do
279
      if [ "${configs[$idx]}" = "$config" ]; then
280
        configidx=$idx
281
        break
282
      fi
283
    done
284
    # error if the configurations could not be found
285
    if [ -z $configidx ]; then
286
      printError "configuration ($config) not available\n"
290
    # check whether the specified configuration is available
291
    if [[ ! "${configs[@]}" =~ "$config" ]]; then
292
      printError "configuration '$config' not available\n"
287 293
      return -2
294
    else
295
      configs2generate=($config)
288 296
    fi
289 297
  fi
290 298

  
291
  # retrieve modules in the configuration
292
  local modules=()
293
  if [ -d ${configsdir}/${config}/modules ]; then
294
    for dir in $(ls -d ${configsdir}/${config}/modules/*/); do
295
      modules[${#modules[@]}]=$(basename $dir)
296
    done
297
    if [ ${#modules[@]} -eq 0 ]; then
298
      printWarning "configuration ${config} does not contain any modules\n"
299
      return 2
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"
300 312
    fi
301
  else
302
    printWarning "'module/' folder does not exist in configuration ${config}\n"
313
  done
314
  if [ ${#projects[@]} -eq 0 ]; then
315
    printWarning "no modules detected, aborting\n"
303 316
    return 2
304 317
  fi
305 318

  
......
310 323
  fi
311 324

  
312 325
  # check for existing project files
313
  local projectfiles=""
314
  for module in ${modules[@]}; do
315
    projectfiles+="$(find ${projectsdir} -maxdepth 1 -type f | grep -E "${config}_${module}\.(includes|files|config|creator)$")"
326
  for project in ${projects[@]}; do
327
    projectfiles+=($(find ${projectsdir} -maxdepth 1 -type f -regextype posix-extended -regex "^.*/${project}\.(includes|files|config|creator)$" | sort))
316 328
  done
317
  IFS=$'\n'; projectfiles=($projectfiles); unset IFS
318
  if [ ! -z "${projectfiles[*]}" ]; then
329
  if [ ${#projectfiles[@]} != 0 ]; then
319 330
    printWarning "The following files will be overwritten:\n"
320 331
    for pfile in ${projectfiles[@]}; do
321 332
      printWarning "\t$(basename $pfile)\n"
322 333
    done
323
    local userinput=""
334
    userinput=""
324 335
    printInfo "Continue and overwrite? [y/n]\n"
325 336
    readUserInput "YyNn" userinput
326 337
    case "$userinput" in
327 338
      Y|y)
328 339
        ;;
329 340
      N|n)
330
        printWarning "Project generation for ${config} configuration aborted by user\n"
341
        printWarning "project generation aborted by user\n"
331 342
        return 1
332 343
        ;;
333 344
      *)
......
336 347
    printf "\n"
337 348
  fi
338 349

  
339
  # print message
340
  printInfo "generating QtCreator project files for the $config configuration...\n"
341

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

  
347
  # change to project directory
355
  # generate for all configurations
348 356
  cd "$projectsdir"
349

  
350
  # create project files for each module of the selected configuration
351
  for module in ${modules[@]}; do
352
    # run make, but only run the GCC preprocessor and produce no binaries
353
    local sourcefiles=()
354
    local sourcefile=""
355
    local parse_state="WAIT_FOR_INCLUDE_COMPILE_MAKE"
356
    local makedirs=()
357
    # capture all output from make and GCC and append the return value of make as last line
358
    printInfo "processing module ${module} (this may take a while)...\n"
359
    local rawout=$(make --directory ${configsdir}/${config}/modules/${module} --always-make USE_OPT="-v -E -H" USE_VERBOSE_COMPILE="no" OUTFILES="" 2>&1 && echo $?)
360
    # check whether the make call was successfull
361
    if [[ $(echo "${rawout}" | tail -n 1) != "0" ]]; then
362
      printError "executing 'make' in configuration directory failed\n"
363
      cd "$userdir"
364
      return -3
365
    else
366
      # cleanup
367
      make --directory ${configsdir}/${config}/modules/${module} clean &>/dev/null
368
    fi
369
    # extract file names from raw output
370
    IFS=$'\n'; rawout=($rawout); unset IFS
371
    for line in "${rawout[@]}"; do
372
      case $parse_state in
373
        WAIT_FOR_INCLUDE_COMPILE_MAKE)
374
          # lines stating include files look like:
375
          # ... <../relative/path/to/file>
376
          if [[ "$line" =~ ^\.+[[:blank:]].+\..+$ ]]; then
377
            sourcefile=${line##* }
378
            if [[ ! "$sourcefile" =~ ^/ ]]; then
379
              sourcefile=$(realpath ${makedirs[-1]}/${sourcefile})
380
            fi
381
            sourcefiles[${#sourcefiles[@]}]="$sourcefile"
382
          # whenever the next source file is processed, a message appears like:
383
          # Compiling <filename>
384
          elif [[ "$line" =~ ^Compiling[[:blank:]](.+\..+)$ ]]; then
385
            printf "."
386
            sourcefile=${BASH_REMATCH[1]}
387
            parse_state="WAIT_FOR_COMPILERCALL"
388
          # if make is called again in another directory, a message appears like:
389
          # make[1]: Entering directory 'directory'
390
          elif [[ "$line" =~ ^make(\[[0-9]+\])?:\ Entering\ directory\ \'.+\'$ ]]; then
391
            makedirs+=($(echo "$line" | (cut -d "'" -f 2)))
392
          # if make is leaving a directory, a message appears like:
393
          # make[1]: Leaving directory 'directory'
394
          elif [[ "$line" =~ ^make(\[[0-9]+\])?:\ Leaving\ directory\ \'.+\'$ ]]; then
395
            unset makedirs[-1]
396
          fi;;
397
        WAIT_FOR_COMPILERCALL)
398
          # wait for the actual call of the compiler to retrieve the full path to the source file
399
          if [[ "$line" == *${sourcefile}* ]]; then
400
            line="${line%%${sourcefile}*}${sourcefile}"
401
            line="${line##* }"
402
            if [[ "$line" =~ ^/ ]]; then
403
              # aboslute path
404
              sourcefile=$line
405
            else
406
              # relative path
407
              sourcefile=$(realpath ${makedirs[-1]}/${line##* })
408
            fi
409
            sourcefiles[${#sourcefiles[@]}]="$sourcefile"
410
            parse_state="WAIT_FOR_INCLUDE_COMPILE_MAKE"
411
          fi;;
412
      esac
413
    done
414
    unset rawout
415
    printf "\n"
416
    # sort and remove duplicates
417
    IFS=$'\n'; sourcefiles=($(sort --unique <<< "${sourcefiles[*]}")); unset IFS
418

  
419
    # extract include paths
420
    local includes=()
421
    for source in ${sourcefiles[*]}; do
422
      includes[${#includes[@]}]="$(dirname ${source})"
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))
423 362
    done
424
    # sort and remove duplicates
425
    IFS=$'\n'; includes=($(sort --unique <<< "${includes[*]}")); unset IFS
363
    # silently skip this configuration if it contains no modules
364
    if [ ${#modules[@]} == 0 ]; then
365
      continue
366
    fi
426 367

  
427
    # generate the .incldues file, containing all include paths
428
    echo "" > ${projectsdir}/${config}_${module}.includes
429
    for inc in ${includes[*]}; do
430
      echo "$inc" >> ${projectsdir}/${config}_${module}.includes
431
    done
432
    # generate the .files file, containing all source files
433
    echo "" > ${projectsdir}/${config}_${module}.files
434
    for source in ${sourcefiles[*]}; do
435
      # skip GCC files
436
      if [[ ! "$source" =~ .*/gcc.* ]]; then
437
        echo "$source" >> ${projectsdir}/${config}_${module}.files
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
438 471
      fi
439 472
    done
440
    # generate a default project configuration file if it doesn't exits yet
441
    if [ ! -f ${projectsdir}/${config}_${module}.config ]; then
442
      echo "// Add predefined macros for your project here. For example:" > ${projectsdir}/${config}_${module}.config
443
      echo "// #define YOUR_CONFIGURATION belongs here" >> ${projectsdir}/${config}_${module}.config
444
    fi
445
    # generate a default .creator file if it doesn't exist yet
446
    if [ ! -f ${projectsdir}/${config}_${module}.creator ]; then
447
      echo "[general]" > ${projectsdir}/${config}_${module}.creator
448
    fi
449 473
  done
450 474

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

  
454 478
  # fill the output variables
455 479
  if [ ! -z "$outvar" ]; then
......
462 486
  return 0
463 487
}
464 488

  
465
### create project files for all configurations ################################
466
# Create project files for all configurations.
489
### delete project files for a single or all modules ###########################
490
# Deletes all project files and optionally .user files, too.
467 491
#
468
# usage:      createAllProjects <configurations> [-p|--path=<path>] [--gcc=<path>] [-o|--out=<var>] [--gccout=<var>]
469
# arguments:  <configurations>
470
#                 Array containing all configurations available.
471
#             -p, --path <path>
472
#                 Path where to create the project files.
473
#             --gcc=<path>
474
#                 Path to the GCC include directory.
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.
475 497
#             -o, --out <var>
476 498
#                 Variable to store the path to.
477
#             --gccout=<var>
478
#                 Variable to store the path to the GCC include directory to.
479
#                 If this optional arguments is absent, ths function will ask for user input.
499
#             -w, --wipe <flag>
500
#                 Flag whether to delete .user files as well (must be either "true" or "false").
480 501
# return:     0
481
#                 No error or warning occurred.
502
#               No error or warning occurred.
482 503
#             1
483
#                 Aborted by user.
484
#             -1
485
#                 No configurations available.
504
#               Aborted by user.
505
#             2
506
#               There are no project files for the specified module at the specified location.
486 507
#
487
function createAllProjects {
488
  local configs=("${!1}")
489
  local projectsdir=""
490
  local gccincludedir=""
508
function deleteProject {
509
  local files=()
510
  local otherargs=()
491 511
  local outvar=""
492
  local gccoutvar=""
512
  local project=""
513
  local projects=()
514
  local projects2delete=()
515
  local projectsdir=""
516
  local userinput=""
517
  local wipe=""
493 518

  
494 519
  # parse arguments
495
  local otherargs=()
496 520
  while [ $# -gt 0 ]; do
497 521
    if ( parseIsOption $1 ); then
498 522
      case "$1" in
......
500 524
          projectsdir=$(realpath "${1#*=}"); shift 1;;
501 525
        -p|--path)
502 526
          projectsdir=$(realpath "$2"); shift 2;;
503
        --gcc=*)
504
          gccincludedir=$(realpath "${1#*=}"); shift 1;;
505
        --gcc)
506
          gccincludedir=$(realpath "$2"); shift 2;;
527
        -m=*|--module=*)
528
          project="${1#*=}"; shift 1;;
529
        -m|--module)
530
          project="${2}"; shift 2;;
507 531
        -o=*|--out=*)
508 532
          outvar=${1#*=}; shift 1;;
509 533
        -o|--out)
510 534
          outvar=$2; shift 2;;
511
        --gccout=*)
512
          gccoutvar=$(realpath "${1#*=}"); shift 1;;
513
        --gccout)
514
          gccoutvar=$(realpath "$2"); shift 2;;
535
        -w=*|--wipe=*)
536
          wipe="${1#*=}"; shift 1;;
537
        -w|--wipe)
538
          wipe="$2"; shift 2;;
515 539
        *)
516 540
          printError "invalid option: $1\n"; shift 1;;
517 541
      esac
......
521 545
    fi
522 546
  done
523 547

  
524
  # sanity check for the configurations variable
525
  if [ -z "${configs[*]}" ]; then
526
    printError "no configurations available\n"
527
    return -1
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=""
528 553
  fi
529 554

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

  
535
  # check for existing project files
536
  local projectfiles=""
537
  for config in ${configs[@]}; do
538
    for module in ${modules[@]}; do
539
      projectfiles+="$(find ${projectsdir} -maxdepth 1 -type f | grep -E "${config}_${module}\.(includes|files|config|creator)$")"
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]}"
540 576
    done
541
  done
542
  IFS=$'\n'; projectfiles=($projectfiles); unset IFS
543
  if [ ! -z "${projectfiles[*]}" ]; then
544
    printWarning "The following files will be removed:\n"
545
    for pfile in ${projectfiles[@]}; do
546
      printWarning "\t$(basename $pfile)\n"
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
547 586
    done
548
    local userinput=""
549
    printInfo "Continue and overwrite? [y/n]\n"
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"
550 620
    readUserInput "YyNn" userinput
551
    case "${userinput}" in
621
    case "$userinput" in
552 622
      Y|y)
553
        for pfile in ${projectfiles[*]}; do
554
          rm "$pfile"
555
        done
556
        ;;
623
        wipe="true";;
557 624
      N|n)
558
        printWarning "Project generation aborted by user\n"
559
        return 1
560
        ;;
625
        wipe="false";;
561 626
      *)
562
        printError "unexpected input: ${userinput}\n"
563
        return 999
564
        ;;
627
        printError "unexpected input: ${userinput}\n"; return -999;;
565 628
    esac
629
    printf "\n"
566 630
  fi
567 631

  
568
  # print message
569
  printf "\n"
570
  printInfo "generating QtCreator project files for all configurations...\n"
571

  
572
  # retrieve absolute GCC include path
573
  if [ -z "$gccincludedir" ]; then
574
    retrieveGccIncludeDir gccincludedir
575
  fi
576

  
577
  # iterate over all configurations
578
  local retval=1
579
  for config in ${configs[@]}; do
580
    if [ $retval != 0 ]; then
581
      printf "\n"
582
    fi
583
    createConfigProjects configs[@] --config="$config" --path="$projectsdir" --gcc="$gccincludedir"
584
    retval=$?
585
  done
586

  
587
  return 0
588
}
589

  
590
### delete project files #######################################################
591
# Deletes all project files and optionally .user files, too.
592
#
593
# usage:      deleteProjects [-p|--path=<path>] [-c|--config=<configuration>] [-o|--out=<var>] [-w|-wipe]
594
# arguments:  -p, --path <path>
595
#                 Path where to delete the project files.
596
#             -c, --config <configuration>
597
#                 Configuration name for which the project files shall be deleted.
598
#             -o, --out <var>
599
#                 Variable to store the path to.
600
#             -w, --wipe
601
#                 Delete .user files as well.
602
# return:
603
#  -  0: no error
604
#
605
function deleteProjects {
606
  local config=""
607
  local projectsdir=""
608
  local outvar=""
609
  local wipe=false
610
  local files=""
611

  
612
  # parse arguments
613
  local otherargs=()
614
  while [ $# -gt 0 ]; do
615
    if ( parseIsOption $1 ); then
616
      case "$1" in
617
        -p=*|--path=*)
618
          projectsdir=$(realpath "${1#*=}"); shift 1;;
619
        -p|--path)
620
          projectsdir=$(realpath "$2"); shift 2;;
621
        -c=*|--config=*)
622
          config="${1#*=}"; shift 1;;
623
        -c|--config)
624
          config="${2}"; shift 2;;
625
        -o=*|--out=*)
626
          outvar=${1#*=}; shift 1;;
627
        -o|--out)
628
          outvar=$2; shift 2;;
629
        -w|--wipe)
630
          wipe=true; shift 1;;
631
        *)
632
          printError "invalid option: $1\n"; shift 1;;
633
      esac
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(\..+)?)$"))
634 637
    else
635
      otherargs+=("$1")
636
      shift 1
638
      files+=($(find "${projectsdir}" -maxdepth 1 -type f -regextype posix-extended -regex "^.*${project}\.(includes|files|config|creator|cflags|cxxflags)$"))
637 639
    fi
638 640
  done
639 641

  
640
  # read absolute project directory if required
641
  if [ -z "$projectsdir" ]; then
642
    getProjectsDir projectsdir
643
  fi
644

  
645
  # list all files to be deleted
646
  if [ -z "$config" ]; then
647
    if [ $wipe != true ]; then
648
      files=$(find "${projectsdir}" -maxdepth 1 -type f | grep -E "^.+\.(includes|files|config|creator|cflags|cxxflags)$")
649
    else
650
      files=$(find "${projectsdir}" -maxdepth 1 -type f | grep -E "^.+\.(includes|files|config|creator|cflags|cxxflags|creator(\.user(\..+)?)?)$")
651
    fi
652
  else
653
    if [ $wipe != true ]; then
654
      files=$(find "${projectsdir}" -maxdepth 1 -type f | grep -E "^${config}_.+\.(includes|files|config|creator|cflags|cxxflags)$")
655
    else
656
      files=$(find "${projectsdir}" -maxdepth 1 -type f | grep -E "^${config}_.+\.(includes|files|config|creator|cflags|cxxflags|creator(\.user(\..+)?)?)$")
657
    fi
658
  fi
659
  if [ ! -z "$files" ]; then
660
    printInfo "Deleting the following files:\n"
661
    while read line; do
662
      printInfo "\t$(basename ${line})\n"
663
      rm ${line} 2>&1 | tee -a $LOG_FILE
664
    done <<< "${files}"
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
665 660
  else
666
    printInfo "No project files found\n"
661
    printInfo "no files to delete\n"
667 662
  fi
668 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

  
669 670
  # store the path to the output variable, if required
670 671
  if [ ! -z "$outvar" ]; then
671 672
    eval $outvar="$projectsdir"
......
683 684
#                 No error or warning ocurred.
684 685
#
685 686
function main {
686
# print welcome/info text if not suppressed
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
687 696
  if [[ $@ != *"--noinfo"* ]]; then
688 697
    printWelcomeText
689 698
  else
......
701 710
  # set log file if specified
702 711
  if [[ $@ == *"--log"* ]] || [[ $@ == *"--LOG"* ]]; then
703 712
    # get the parameter (file name)
704
    local cmdidx=1
713
    cmdidx=1
705 714
    while [[ ! "${!cmdidx}" = "--log"* ]] && [[ ! "${!cmdidx}" = "--LOG"* ]]; do
706 715
      cmdidx=$[cmdidx + 1]
707 716
    done
708
    local cmd="${!cmdidx}"
709
    local logfile=""
717
    cmd="${!cmdidx}"
718
    logfile=""
710 719
    if [[ "$cmd" = "--log="* ]] || [[ "$cmd" = "--LOG="* ]]; then
711 720
      logfile=${cmd#*=}
712 721
    else
713
      local filenameidx=$((cmdidx + 1))
722
      filenameidx=$((cmdidx + 1))
714 723
      logfile="${!filenameidx}"
715 724
    fi
716 725
    # optionally force silent appending
......
725 734
  printLog "this is $(realpath ${BASH_SOURCE[0]})\n"
726 735

  
727 736
  # detect available configurations and inform user
728
  local configurations=()
729 737
  detectConfigurations configurations
730 738
  case "${#configurations[@]}" in
731 739
    0)
......
741 749
  printf "\n"
742 750

  
743 751
  # parse arguments
744
  local otherargs=()
745 752
  while [ $# -gt 0 ]; do
746 753
    if ( parseIsOption $1 ); then
747 754
      case "$1" in
748 755
        -h|--help) # already handled; ignore
749 756
          shift 1;;
750
        -p=*|--project=*)
751
          createConfigProjects configurations[@] --configuration="${1#*=}"; printf "\n"; shift 1;;
752
        -p|--project)
753
          createConfigProjects configurations[@] --configuration="${2}"; printf "\n"; shift 2;;
754
        -a|--all)
755
          createAllProjects configurations[@]; shift 1;;
756
        -c|--clean)
757
          deleteProjects; printf "\n"; shift 1;;
758
        -w|--wipe)
759
          deleteProjects --wipe; printf "\n"; 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;;
760 765
        -q|--quit)
761 766
          quitScript; shift 1;;
762 767
        --log=*|--LOG=*) # already handled; ignore
......
779 784
    # main menu info prompt and selection
780 785
    printInfo "QtCreator setup main menu\n"
781 786
    printf "Please select one of the following actions:\n"
782
    printf "  [P] - create projects for a single configuration\n"
783
    printf "  [A] - create projects for all configurations\n"
784
    printf "  [C] - clean project files\n"
785
    printf "  [W] - wipe project and .user files\n"
787
    printf "  [C] - create project files\n"
788
    printf "  [D] - delete project files\n"
786 789
    printf "  [Q] - quit this setup\n"
787
    local userinput=""
788
    readUserInput "PpAaCcWwQq" userinput
790
    userinput=""
791
    readUserInput "CcDdQq" userinput
789 792
    printf "\n"
790 793

  
791 794
    # evaluate user selection
792 795
    case "$userinput" in
793
      P|p)
794
        createConfigProjects configurations[@]; printf "\n";;
795
      A|a)
796
        createAllProjects configurations[@]; printf "\n";;
797 796
      C|c)
798
        deleteProjects; printf "\n";;
799
      W|w)
800
        deleteProjects --wipe; printf "\n";;
797
        createProject configurations[@]; printf "\n";;
798
      D|d)
799
        deleteProject; printf "\n";;
801 800
      Q|q)
802 801
        quitScript;;
803 802
      *) # sanity check (exit with error)
......
813 812
################################################################################
814 813

  
815 814
main "$@"
816

  

Also available in: Unified diff