project 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713
  1. #!/usr/bin/env bash
  2. # Copyright (C) 2016 Paul Kocialkowski <contact@paulk.fr>
  3. # Copyright (C) 2018,2019 Andrew Robbins <contact@andrewrobbins.info>
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation, either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. PROJECT_ACTIONS_GENERIC=(usage dependencies download extract update build install release clean)
  18. PROJECT_ACTIONS_GENERIC_IGNORE_CHECK=(usage clean)
  19. PROJECT_ACTIONS_HELPERS=(arguments dependencies)
  20. INSTALL_REGEX='\([^:]*\):\(.*\)'
  21. project_include() {
  22. local project=$1
  23. local project_path=$(project_path "$project")
  24. unset -f "${PROJECT_ACTIONS[@]}"
  25. source "$project_path/$project"
  26. project_helper_include "$project"
  27. }
  28. project_helper_include() {
  29. local project=$1
  30. local project_path=$(project_path "$project")
  31. local include="$project_path/$project-helper"
  32. if [[ -f "$include" ]]
  33. then
  34. source "$include"
  35. fi
  36. }
  37. project_check() {
  38. local project="${1##*/}"
  39. local project_path="$(project_path "$project")"
  40. if ! [[ -f "$project_path/$project" ]]; then
  41. return 1
  42. fi
  43. }
  44. project_dependencies() {
  45. local project=$1
  46. shift
  47. if [[ -n "${PROJECTS_FORCE[*]}" ]]; then
  48. local expanded
  49. local project_force
  50. for project_force in "${PROJECTS_FORCE[@]}"; do
  51. project_arguments_expand_recursive $project_force | while IFS='' read -r expanded; do
  52. project_dependencies_sort $expanded
  53. done
  54. done
  55. fi
  56. project_dependencies_sort "$project" "$@" | head -n -1
  57. }
  58. project_dependencies_collect() {
  59. local project=$1
  60. shift
  61. local argument
  62. local path
  63. for argument in "" "$@"; do
  64. if [[ -z $argument ]]; then
  65. path=$CONFIGS
  66. else
  67. path=$path/$argument
  68. fi
  69. project_file_contents "$project" "$path" "$DEPENDENCIES"
  70. done
  71. project_dependencies_collect_recursive "$project" "$@"
  72. }
  73. project_dependencies_collect_recursive() {
  74. local project=$1
  75. shift
  76. local argument
  77. local path
  78. for argument in "" "$@"; do
  79. if [[ -z $argument ]]; then
  80. path=$CONFIGS
  81. else
  82. path=$path/$argument
  83. fi
  84. done
  85. project_action_helper arguments "$project" "$@" | while IFS='' read -r argument; do
  86. project_file_contents "$project" "$path/$argument" "$DEPENDENCIES"
  87. project_dependencies_collect_recursive "$project" "$@" "$argument"
  88. done
  89. }
  90. project_dependencies_encode_recursive() {
  91. local project=$1
  92. shift
  93. local project_arguments=$(arguments_concat ' ' "$project" "$@")
  94. local project_arguments_encoded=$(base64 -w0 <<< "$project_arguments")
  95. local dependency
  96. project_dependencies_collect "$project" "$@" | while IFS='' read -r dependency; do
  97. local dependency_arguments=$(arguments_concat ' ' $dependency)
  98. local dependency_arguments_encoded=$(base64 -w0 <<< "$dependency_arguments")
  99. printf '%s\n' "$project_arguments_encoded $dependency_arguments_encoded"
  100. project_dependencies_encode_recursive $dependency
  101. done
  102. }
  103. project_dependencies_sort() {
  104. local project=$1
  105. shift
  106. (
  107. set -o pipefail
  108. project_dependencies_encode_recursive "$project" "$@" | tsort | base64 -d -w0 | tac
  109. )
  110. }
  111. project_dependencies_check() {
  112. local project=$1
  113. shift
  114. local dependency
  115. local -i missing=0
  116. project_dependencies "$project" "$@" | while read -r dependency; do
  117. project_check $dependency || let ++missing
  118. done
  119. return $missing
  120. }
  121. project_dependencies_sources_check() {
  122. local project=$1
  123. shift
  124. local dependency
  125. local -i missing=0
  126. project_dependencies "$project" "$@" | while read -r dependency; do
  127. project_sources_directory_filled_check $dependency || let ++missing
  128. done
  129. return $missing
  130. }
  131. project_dependencies_action_arguments() {
  132. local action=$1
  133. local project=$2
  134. shift 2
  135. local -a dependency
  136. project_dependencies "$project" "$@" | while read -ra dependency; do
  137. if project_function_check "${dependency[0]}" "$action"; then
  138. project_action_arguments "$action" "${dependency[@]}"
  139. fi
  140. done
  141. }
  142. project_function_check() {
  143. local project=$1
  144. local function=$2
  145. (
  146. project_include "$project"
  147. if ! function_check "$function"; then
  148. exit 1
  149. fi
  150. )
  151. }
  152. project_action() {
  153. local action="$1"
  154. shift
  155. local project="$1"
  156. shift
  157. local arguments="$*"
  158. if project_action_check "$action" "$project" "$@"; then
  159. return 0
  160. fi
  161. (
  162. set +e
  163. printf '%s\n' "Project $project $action (with ${arguments:-no argument})"
  164. (
  165. set -e
  166. "$action" "$@"
  167. )
  168. local -i exit_status=$?
  169. if ((exit_status)); then
  170. printf 1>&2 '%s\n' "Project $project $action (with ${arguments:-no argument}) failed"
  171. else
  172. printf '%s\n' "Project $project $action (with ${arguments:-no argument}) completed"
  173. fi
  174. exit $exit_status
  175. )
  176. }
  177. project_action_check() {
  178. local action="$1"
  179. shift
  180. local project="$1"
  181. shift
  182. (
  183. set +e
  184. if ! function_check "${action}_check"; then
  185. return 1
  186. fi
  187. for project_force in $PROJECTS_FORCE; do
  188. if [[ "$project_force" == "$project" ]]; then
  189. return 1
  190. fi
  191. done
  192. (
  193. set -e
  194. "${action}_check" "$@"
  195. )
  196. )
  197. }
  198. project_action_helper() {
  199. local helper="$1"
  200. shift
  201. local project="$1"
  202. shift
  203. (
  204. project_include "$project"
  205. if ! function_check "$helper"; then
  206. exit 0
  207. fi
  208. "$helper" "$@"
  209. )
  210. }
  211. project_action_arguments() {
  212. local action="$1"
  213. shift
  214. local project="$1"
  215. shift
  216. (
  217. project_include "$project"
  218. project_action_arguments_verify_recursive "$action" "$project" "$@"
  219. project_action_arguments_recursive "$action" "$project" "$@"
  220. )
  221. }
  222. project_action_arguments_verify_recursive() {
  223. local action="$1"
  224. shift
  225. local project="$1"
  226. shift
  227. local action_helper_arguments
  228. # Store final argument.
  229. local argument="${*:$#}"
  230. local test
  231. if [[ "$#" -gt 1 ]]; then
  232. # Set previous arguments.
  233. set "${@:1:$#-1}"
  234. elif [[ "$#" -eq 1 ]]; then
  235. shift
  236. else
  237. return 0
  238. fi
  239. action_helper_arguments="$(project_action_helper 'arguments' "$project" "$@")"
  240. if [[ -n "$action_helper_arguments" ]]; then
  241. test="$(printf '%s\n' "$action_helper_arguments" | grep -e "^$argument\$" || true)"
  242. if [[ -z "$test" ]]; then
  243. printf 1>&2 '%s\n' "Invalid argument $argument for project $project action $action"
  244. return 1
  245. fi
  246. fi
  247. project_action_arguments_verify_recursive "$action" "$project" "$@"
  248. }
  249. project_action_arguments_recursive() {
  250. local action="$1"
  251. shift
  252. local project="$1"
  253. shift
  254. local action_helper_arguments
  255. local argument
  256. action_helper_arguments="$(project_action_helper 'arguments' "$project" "$@" || true)"
  257. if [[ -z "$action_helper_arguments" ]]; then
  258. project_action "$action" "$project" "$@"
  259. else
  260. # This is to allow space characters in arguments.
  261. local ifs_save="$IFS"
  262. local IFS=$'\n'
  263. for argument in $(printf '%s\n' "$action_helper_arguments")
  264. do
  265. IFS="$ifs_save"
  266. # Only a single argument at a time is returned by the helper.
  267. project_action_arguments_recursive "$action" "$project" "$@" "$argument"
  268. done
  269. fi
  270. }
  271. project_action_projects() {
  272. local action="$1"
  273. shift
  274. local project="$1"
  275. shift
  276. local project_path="$(project_path "$project")"
  277. local project_projects_path="$project_path/$CONFIGS/$PROJECTS"
  278. local project_projects_action_path="$project_path/$CONFIGS/$PROJECTS-$action"
  279. local arguments
  280. local path
  281. if [[ -f "$project_projects_action_path" ]]; then
  282. path="$project_projects_action_path"
  283. else
  284. path="$project_projects_path"
  285. fi
  286. # Multiple arguments can be read from the file.
  287. while read -r arguments; do
  288. eval "project_action_arguments $action $arguments"
  289. done < "$path"
  290. }
  291. project_action_usage() {
  292. local project=$1
  293. shift
  294. (
  295. project_include "$project"
  296. project_action usage "$project" "$@"
  297. )
  298. }
  299. project_path() {
  300. local project=$1
  301. local project_path="$root/$PROJECTS/$project"
  302. printf '%s\n' "$project_path"
  303. }
  304. project_sources_path() {
  305. local project=$1
  306. shift
  307. local repository=$1
  308. shift
  309. local sources_path
  310. local argument
  311. local path
  312. # Check downloaded and extracted sources first, using "$project."
  313. path="$root/$SOURCES/$project"
  314. for argument in "" "$@"
  315. do
  316. if [[ -n "$argument" ]]
  317. then
  318. path="$path-$argument"
  319. fi
  320. if ! directory_filled_check "$path"
  321. then
  322. continue
  323. fi
  324. sources_path=$path
  325. done
  326. if [[ -n "$sources_path" ]]
  327. then
  328. printf '%s\n' "$sources_path"
  329. return
  330. fi
  331. # Check downloaded sources then, using "$repository."
  332. path="$root/$SOURCES/$repository"
  333. if directory_filled_check "$path"
  334. then
  335. printf '%s\n' "$path"
  336. return
  337. fi
  338. # Check project sources finally, using "$project."
  339. path="$root/$PROJECTS/$project/$SOURCES"
  340. for argument in "" "$@"
  341. do
  342. if [[ -n "$argument" ]]
  343. then
  344. path="$path/$argument"
  345. fi
  346. if ! directory_filled_check "$path"
  347. then
  348. continue
  349. fi
  350. sources_path=$path
  351. done
  352. if [[ -n "$sources_path" ]]
  353. then
  354. printf '%s\n' "$sources_path"
  355. return
  356. fi
  357. }
  358. project_sources_directory_filled_check() {
  359. local project=$1
  360. shift
  361. local sources_path=$(project_sources_path "$project" "$@")
  362. test ! -z "$sources_path"
  363. }
  364. project_sources_directory_filled_error() {
  365. local project=$1
  366. shift
  367. local arguments="$*"
  368. local sources_path=$(project_sources_path "$project" "$@")
  369. if [[ -n "$sources_path" ]]
  370. then
  371. printf 1>&2 '%s\n' "Sources directory for project $project (with ${arguments:-no argument}) already exists"
  372. return 1
  373. else
  374. return 0
  375. fi
  376. }
  377. project_sources_directory_missing_empty_error() {
  378. local project=$1
  379. shift
  380. local arguments="$*"
  381. local sources_path=$(project_sources_path "$project" "$@")
  382. if [[ -z "$sources_path" ]]
  383. then
  384. printf 1>&2 '%s\n' "Sources directory for project $project (with ${arguments:-no argument}) missing or empty"
  385. return 1
  386. else
  387. return 0
  388. fi
  389. }
  390. project_sources_archive() {
  391. local project=$1
  392. shift
  393. local sources_archive
  394. local argument
  395. local path="$root/$SOURCES/$project"
  396. for argument in "" "$@"
  397. do
  398. if [[ -n "$argument" ]]
  399. then
  400. path="$path-$argument"
  401. fi
  402. local archive="$path.$ARCHIVE"
  403. if ! [[ -f "$archive" ]]
  404. then
  405. continue
  406. fi
  407. sources_archive=$archive
  408. done
  409. if [[ -n "$sources_archive" ]]
  410. then
  411. printf '%s\n' "$sources_archive"
  412. fi
  413. }
  414. project_sources_archive_extract() {
  415. local project=$1
  416. shift
  417. local arguments="$*"
  418. local archive=$(project_sources_archive "$project" "$@")
  419. local destination=$(dirname "$archive")
  420. printf '%s\n' "Extracting source archive for $project (with ${arguments:-no argument})"
  421. file_verification_check "$archive"
  422. archive_extract "$archive" "$destination"
  423. }
  424. project_sources_archive_update() {
  425. local project=$1
  426. shift
  427. local arguments="$*"
  428. local repository=$project
  429. local sources_path=$(project_sources_path "$project" "$repository" "$@")
  430. local archive=$(project_sources_archive "$project" "$@")
  431. local destination=$(dirname "$archive")
  432. if [[ -d "$sources_path" ]]
  433. then
  434. rm -rf "$sources_path"
  435. fi
  436. printf '%s\n' "Extracting source archive for $project (with ${arguments:-no argument})"
  437. file_verification_check "$archive"
  438. archive_extract "$archive" "$destination"
  439. }
  440. project_sources_archive_missing_error() {
  441. local project=$1
  442. shift
  443. local arguments="$*"
  444. local archive=$(project_sources_archive "$project" "$@")
  445. if [[ -z "$archive" ]] || ! [[ -f "$archive" ]]
  446. then
  447. printf 1>&2 '%s\n' "Missing sources archive for $project (with ${arguments:-no argument})"
  448. return 1
  449. else
  450. return 0
  451. fi
  452. }
  453. project_sources_archive_missing_check() {
  454. local project=$1
  455. shift
  456. local archive=$(project_sources_archive "$project" "$@")
  457. if [[ -z "$archive" ]] || ! [[ -f "$archive" ]]
  458. then
  459. return 0
  460. else
  461. return 1
  462. fi
  463. }
  464. project_sources_prepare() {
  465. local project="$1"
  466. shift
  467. project_sources_prepare_blobs "$project" "$@"
  468. project_sources_prepare_patch "$project" "$@"
  469. }
  470. project_sources_prepare_blobs() {
  471. local project=$1
  472. shift
  473. local sources_path=$(project_sources_path "$project" "$project" "$@")
  474. (
  475. cd "$sources_path" || exit 1
  476. project_blobs "$project" "$@" | while IFS='' read -r blob; do
  477. rm -f -- "$blob"
  478. done
  479. )
  480. }
  481. project_sources_prepare_patch() {
  482. local project="$1"
  483. shift
  484. local argument
  485. local path
  486. for argument in "$@"; do
  487. if [[ -z $path ]]; then
  488. path=$argument
  489. else
  490. path=$path/$argument
  491. fi
  492. done
  493. if [[ -n $project ]]; then
  494. project_sources_patch_recursive "$project" "$path"
  495. fi
  496. }
  497. project_sources_prepare_check() {
  498. local project=$1
  499. shift
  500. local sources_path=$(project_sources_path "$project" "$project" "$@")
  501. directory_filled_check "$sources_path"
  502. }
  503. project_sources_patch_recursive() {
  504. local project=$1
  505. local path=$2
  506. local project_path=$(project_path "$project")
  507. local sources_path=$(project_sources_path "$project" "$project" "$@")
  508. local patches_path=$project_path/$PATCHES/$path
  509. if ! [[ -d $project_path/$PATCHES ]]; then
  510. return 0
  511. fi
  512. for patch in "$patches_path"/[!.]*.@(patch|diff); do
  513. project_sources_patch "$sources_path" "$patch" || return 1
  514. done
  515. if [[ -n $path && $path != . ]]; then
  516. project_sources_patch_recursive "$project" "$(dirname "$path")"
  517. fi
  518. }
  519. project_blobs() {
  520. local project=$1
  521. shift
  522. local blobs_path=$(project_blobs_path "$project" "$@")
  523. local blobs_ignore_path=$(project_blobs_ignore_path "$project" "$@")
  524. if [[ -n $blobs_path ]]; then
  525. if [[ -n $blobs_ignore_path ]]; then
  526. comm -23 <(sort "$blobs_path") <(sort "$blobs_ignore_path")
  527. else
  528. cat "$blobs_path"
  529. fi
  530. fi
  531. }
  532. project_sources_patch() {
  533. local sources_path=$1
  534. local patch_path=$2
  535. if diff_patch_check "$sources_path" "$patch_path"; then
  536. diff_patch "$sources_path" "$patch_path"
  537. else
  538. return 1
  539. fi
  540. }
  541. project_blobs_path() {
  542. local project=$1
  543. shift
  544. local project_path=$(project_path "$project")
  545. local configs_path="$project_path/$CONFIGS"
  546. local argument
  547. local path
  548. for argument in "" "$@"
  549. do
  550. if [[ -n "$argument" ]]
  551. then
  552. if [[ -z "$path" ]]
  553. then
  554. path="$argument"
  555. else
  556. path="$path/$argument"
  557. fi
  558. fi
  559. local blobs_path="$configs_path/$path/$BLOBS"
  560. if [[ -f "$blobs_path" ]]
  561. then
  562. printf '%s\n' "$blobs_path"
  563. return
  564. fi
  565. done
  566. }
  567. project_blobs_ignore_path() {
  568. local project=$1
  569. shift
  570. local project_path=$(project_path "$project")
  571. local configs_path="$project_path/$CONFIGS"
  572. local argument
  573. local path
  574. for argument in "" "$@"
  575. do
  576. if [[ -n "$argument" ]]
  577. then
  578. if [[ -z "$path" ]]
  579. then
  580. path="$argument"
  581. else
  582. path="$path/$argument"
  583. fi
  584. fi
  585. blobs_ignore_path="$configs_path/$path/$BLOBS_IGNORE"
  586. if [[ -f "$blobs_ignore_path" ]]
  587. then
  588. printf '%s\n' "$blobs_ignore_path"
  589. return
  590. fi
  591. done
  592. }
  593. project_arguments_targets() {
  594. local project=$1
  595. shift
  596. local project_path=$(project_path "$project")
  597. local targets_path="$project_path/$CONFIGS"
  598. local argument
  599. for argument in "$@"
  600. do
  601. targets_path="$targets_path/$argument"
  602. done
  603. targets_path="$targets_path/$TARGETS"
  604. if [[ -f "$targets_path" ]]
  605. then
  606. cat "$targets_path"
  607. fi
  608. }
  609. project_arguments_expand_recursive() {
  610. local project=$1
  611. shift
  612. local -a arguments
  613. readarray -t arguments < <(project_action_helper arguments "$project" "$@")
  614. if [[ -z "${arguments[*]}" ]]; then
  615. echo "$project" "$@"
  616. return 0
  617. fi
  618. local argument
  619. for argument in "${arguments[@]}"; do
  620. project_arguments_expand_recursive "$project" "$@" "$argument"
  621. done
  622. }
  623. project_usage_actions() {
  624. local project="$1"
  625. shift
  626. printf '\n%s\n' 'Generic actions:'
  627. (
  628. for action in "${PROJECT_ACTIONS_GENERIC[@]}"; do
  629. if function_check "$action"; then
  630. printf '%s\n' " $action"
  631. fi
  632. done
  633. )
  634. if [[ "$#" -gt 0 ]]; then
  635. printf '\n%s\n' 'Specific actions:'
  636. (
  637. for action in "$@"; do
  638. printf '%s\n' " $action"
  639. done
  640. )
  641. fi
  642. }
  643. project_usage_arguments() {
  644. local project="$1"
  645. shift
  646. printf '\n%s\n' 'Arguments:'
  647. project_usage_arguments_recursive "$project" ' ' "$@"
  648. }
  649. project_usage_arguments_recursive() {
  650. local project="$1"
  651. shift
  652. local spacing="$1"
  653. shift
  654. local action_helper_arguments
  655. local argument
  656. action_helper_arguments="$(project_action_helper 'arguments' "$project" "$@")"
  657. if [[ -n "$action_helper_arguments" ]]; then
  658. for argument in $action_helper_arguments; do
  659. printf '%s\n' "$spacing$argument"
  660. project_usage_arguments_recursive "$project" " $spacing" "$@" "$argument"
  661. done
  662. fi
  663. }
  664. project_download_git() {
  665. local project=$1
  666. shift
  667. local repository=$1
  668. shift
  669. local urls=$1
  670. shift
  671. requirements "git"
  672. if ! git_project_check "$repository"
  673. then
  674. project_sources_directory_filled_error "$project" "$repository" "$@"
  675. git_project_clone "$repository" "$urls"
  676. fi
  677. git_project_prepare "$project" "$repository" "$@"
  678. }
  679. project_download_check_git() {
  680. local project=$1
  681. shift
  682. local repository=$1
  683. shift
  684. requirements "git"
  685. git_project_check "$repository"
  686. git_project_prepare_check "$project" "$repository" "$@"
  687. }
  688. project_download_archive() {
  689. local project="$1"
  690. shift
  691. local archive_uri="$1"
  692. shift
  693. local archive_dsig_uri="$1"
  694. local archive="${archive_uri##*/}"
  695. local compress_fmt="${archive##*.tar}"
  696. local directory_prefix="$root/$SOURCES"
  697. local archive_path="$root/$SOURCES/$archive"
  698. local sources_path="$root/$SOURCES/$project"
  699. if [[ "${compress_fmt#*.}" != "${ARCHIVE#*.}" ]]; then
  700. ARCHIVE="tar$compress_fmt"
  701. fi
  702. # TODO: Split this code block into separate functions
  703. # Archive verification will be included at that point in time
  704. if ! project_sources_directory_filled_check "$project"; then
  705. download_wrapper "$directory_prefix" "$archive_uri" "$archive_dsig_uri"
  706. archive_extract "$archive_path" "$directory_prefix"
  707. mv "${archive_path%.tar*}" "$sources_path"
  708. fi
  709. project_sources_prepare "$project"
  710. }
  711. project_download_check_archive() {
  712. local project="$1"
  713. local sources_path="$2"
  714. # TODO: Write the following function
  715. #project_sources_archive_extract_check "$project" "$sources_path"
  716. }
  717. project_extract() {
  718. local project=$1
  719. shift
  720. local repository=$project
  721. if ! project_sources_directory_filled_check "$project" "$repository" "$@"
  722. then
  723. project_sources_archive_missing_error "$project" "$@" || return 1
  724. project_sources_archive_extract "$project" "$@"
  725. fi
  726. }
  727. project_extract_check() {
  728. local project=$1
  729. shift
  730. local repository=$project
  731. project_sources_directory_filled_check "$project" "$repository" "$@"
  732. }
  733. project_update_git() {
  734. local project=$1
  735. shift
  736. local repository=$1
  737. shift
  738. requirements "git"
  739. project_sources_directory_missing_empty_error "$project" "$repository" "$@"
  740. if git_project_check "$repository"
  741. then
  742. git_project_update "$project" "$repository" "$@"
  743. else
  744. if ! project_sources_archive_missing_check "$project" "$@"
  745. then
  746. project_sources_archive_update "$project" "$@"
  747. fi
  748. fi
  749. }
  750. project_update_check_git() {
  751. local project=$1
  752. shift
  753. local repository=$1
  754. shift
  755. requirements "git"
  756. if git_project_check "$repository"
  757. then
  758. # Git repository should always be updated (even if upstream didn't progress).
  759. # For instance, this is useful for testing new versions of patches without changing revision.
  760. return 1
  761. else
  762. project_sources_archive_missing_check "$project" "$@"
  763. fi
  764. }
  765. project_build_check() {
  766. local project=$1
  767. shift
  768. local project_path=$(project_path "$project")
  769. local build_path=$(project_build_path "$project" "$@")
  770. local source_file_path
  771. local argument
  772. local rule
  773. local path
  774. if ! [[ -d $build_path ]]
  775. then
  776. return 1
  777. fi
  778. for argument in "" "$@"
  779. do
  780. if [[ -n "$argument" ]]
  781. then
  782. if [[ -z "$path" ]]
  783. then
  784. path="$argument"
  785. else
  786. path="$path/$argument"
  787. fi
  788. fi
  789. configs_install_path="$project_path/$CONFIGS/$path/$INSTALL"
  790. if ! [[ -f "$configs_install_path" ]]
  791. then
  792. continue
  793. fi
  794. while read -r rule
  795. do
  796. source=$(printf '%s\n' "$rule" | sed "s/$INSTALL_REGEX/\\1/g")
  797. source_path="$build_path/$source"
  798. # Source may contain a wildcard.
  799. path_wildcard_expand "$source_path" | while read -r source_file_path
  800. do
  801. if ! [[ -f "$source_file_path" ]] && ! [[ -d "$source_file_path" ]]
  802. then
  803. return 1
  804. fi
  805. done
  806. done < "$configs_install_path"
  807. done
  808. }
  809. project_build_path() {
  810. local project=$1
  811. shift
  812. local build_path="$root/$BUILD/$project"
  813. local argument
  814. for argument in "$@"
  815. do
  816. build_path="$build_path-$argument"
  817. done
  818. printf '%s\n' "$build_path"
  819. }
  820. project_build_directory_missing_empty_error() {
  821. local project=$1
  822. shift
  823. local arguments="$*"
  824. local build_path=$(project_build_path "$project" "$@")
  825. if ! directory_filled_check "$build_path"
  826. then
  827. printf 1>&2 '%s\n' "Build directory for project $project (with ${arguments:-no argument}) missing or empty"
  828. return 1
  829. else
  830. return 0
  831. fi
  832. }
  833. project_install() {
  834. local project=$1
  835. shift
  836. local project_path=$(project_path "$project")
  837. local build_path=$(project_build_path "$project" "$@")
  838. local install_path=$(project_install_path "$project" "$@")
  839. local source_file_path
  840. local argument
  841. local rule
  842. local path
  843. # Install built files first.
  844. for argument in "" "$@"
  845. do
  846. if [[ -n "$argument" ]]
  847. then
  848. if [[ -z "$path" ]]
  849. then
  850. path="$argument"
  851. else
  852. path="$path/$argument"
  853. fi
  854. fi
  855. configs_install_path="$project_path/$CONFIGS/$path/$INSTALL"
  856. if ! [[ -f "$configs_install_path" ]]
  857. then
  858. continue
  859. fi
  860. project_build_directory_missing_empty_error "$project" "$@"
  861. while read -r rule
  862. do
  863. source=$(printf '%s\n' "$rule" | sed "s/$INSTALL_REGEX/\\1/g")
  864. source_path="$build_path/$source"
  865. destination=$(printf '%s\n' "$rule" | sed "s/$INSTALL_REGEX/\\2/g")
  866. destination_path="$install_path/$destination"
  867. destination_directory_path=$(dirname "$destination_path")
  868. mkdir -p "$destination_directory_path"
  869. # Source may contain a wildcard.
  870. path_wildcard_expand "$source_path" | while read -r source_file_path
  871. do
  872. cp -rT "$source_file_path" "$destination_path"
  873. done
  874. done < "$configs_install_path"
  875. done
  876. path=""
  877. # Install install files then.
  878. for argument in "" "$@"
  879. do
  880. if [[ -n "$argument" ]]
  881. then
  882. if [[ -z "$path" ]]
  883. then
  884. path="$argument"
  885. else
  886. path="$path/$argument"
  887. fi
  888. fi
  889. install_install_path="$project_path/$INSTALL/$path/$INSTALL"
  890. if ! [[ -f "$install_install_path" ]]
  891. then
  892. continue
  893. fi
  894. while read -r rule
  895. do
  896. source=$(printf '%s\n' "$rule" | sed "s/$INSTALL_REGEX/\\1/g")
  897. source_path="$project_path/$INSTALL/$path/$source"
  898. destination=$(printf '%s\n' "$rule" | sed "s/$INSTALL_REGEX/\\2/g")
  899. destination_path="$install_path/$destination"
  900. destination_directory_path=$(dirname "$destination_path")
  901. mkdir -p "$destination_directory_path"
  902. # Source may contain a wildcard.
  903. path_wildcard_expand "$source_path" | while read -r source_file_path
  904. do
  905. cp -rT "$source_file_path" "$destination_path"
  906. done
  907. done < "$install_install_path"
  908. done
  909. }
  910. project_install_check() {
  911. local project=$1
  912. shift
  913. local project_path=$(project_path "$project")
  914. local build_path=$(project_build_path "$project" "$@")
  915. local install_path=$(project_install_path "$project" "$@")
  916. local argument
  917. local rule
  918. local path
  919. if ! [[ -d $install_path ]]
  920. then
  921. return 1
  922. fi
  923. # Install built files first.
  924. for argument in "" "$@"
  925. do
  926. if [[ -n "$argument" ]]
  927. then
  928. if [[ -z "$path" ]]
  929. then
  930. path="$argument"
  931. else
  932. path="$path/$argument"
  933. fi
  934. fi
  935. configs_install_path="$project_path/$CONFIGS/$path/$INSTALL"
  936. if ! [[ -f "$configs_install_path" ]]
  937. then
  938. continue
  939. fi
  940. project_build_directory_missing_empty_error "$project" "$@"
  941. while read -r rule
  942. do
  943. destination=$(printf '%s\n' "$rule" | sed "s/$INSTALL_REGEX/\\2/g")
  944. destination_path="$install_path/$destination"
  945. if ! [[ -f "$destination_path" ]] && ! [[ -d "$destination_path" ]]
  946. then
  947. return 1
  948. fi
  949. done < "$configs_install_path"
  950. done
  951. path=""
  952. # Install install files then.
  953. for argument in "" "$@"
  954. do
  955. if [[ -n "$argument" ]]
  956. then
  957. if [[ -z "$path" ]]
  958. then
  959. path="$argument"
  960. else
  961. path="$path/$argument"
  962. fi
  963. fi
  964. install_install_path="$project_path/$INSTALL/$path/$INSTALL"
  965. if ! [[ -f "$install_install_path" ]]
  966. then
  967. continue
  968. fi
  969. while read -r rule
  970. do
  971. destination=$(printf '%s\n' "$rule" | sed "s/$INSTALL_REGEX/\\2/g")
  972. destination_path="$install_path/$destination"
  973. if ! [[ -f "$destination_path" ]] && ! [[ -d "$destination_path" ]]
  974. then
  975. return 1
  976. fi
  977. done < "$install_install_path"
  978. done
  979. }
  980. project_install_path() {
  981. local project=$1
  982. shift
  983. local install_path="$root/$INSTALL/$project"
  984. local argument
  985. for argument in "$@"
  986. do
  987. install_path="$install_path-$argument"
  988. done
  989. printf '%s\n' "$install_path"
  990. }
  991. project_install_directory_missing_empty_error() {
  992. local project=$1
  993. shift
  994. local arguments="$*"
  995. local install_path=$(project_install_path "$project" "$@")
  996. if ! directory_filled_check "$install_path"
  997. then
  998. printf 1>&2 '%s\n' "Install directory for project $project (with ${arguments:-no argument}) missing or empty"
  999. return 1
  1000. else
  1001. return 0
  1002. fi
  1003. }
  1004. project_release_path() {
  1005. local project=$1
  1006. shift
  1007. local prefix=$1
  1008. local release_path="$root/$RELEASE/$prefix"
  1009. # Special care for tools and systems, that depend on the host arch.
  1010. if [[ "$prefix" = "$SYSTEMS" ]] || [[ "$prefix" = "$TOOLS" ]]
  1011. then
  1012. local machine=$(uname -m)
  1013. release_path="$release_path/$machine/$project"
  1014. else
  1015. release_path="$release_path/$project"
  1016. fi
  1017. printf '%s\n' "$release_path"
  1018. }
  1019. project_release_archive_path() {
  1020. local project=$1
  1021. shift
  1022. local prefix=$1
  1023. shift
  1024. local release_path=$(project_release_path "$project" "$prefix")
  1025. local argument
  1026. local path="$project"
  1027. for argument in "$@"
  1028. do
  1029. path="$path-$argument"
  1030. done
  1031. local archive_path="$release_path/$path.$ARCHIVE"
  1032. printf '%s\n' "$archive_path"
  1033. }
  1034. project_release_rootfs_path() {
  1035. local project=$1
  1036. shift
  1037. local prefix=$1
  1038. shift
  1039. local release_path=$(project_release_path "$project" "$prefix")
  1040. local argument
  1041. local path="$project"
  1042. for argument in "$@"
  1043. do
  1044. path="$path-$argument"
  1045. done
  1046. local rootfs_path="$release_path/$path.$ARCHIVE"
  1047. printf '%s\n' "$rootfs_path"
  1048. }
  1049. project_release_sources_archive_path() {
  1050. local project=$1
  1051. shift
  1052. local repository="$project"
  1053. local sources_path="$(project_sources_path "$project" "$repository" "$@")"
  1054. local archive_path="$root/$RELEASE/$SOURCES/$project/${sources_path##*/}.$ARCHIVE"
  1055. printf '%s\n' "$archive_path"
  1056. }
  1057. project_release_sources_archive_create() {
  1058. local project=$1
  1059. shift
  1060. local arguments="$*"
  1061. local repository=$project
  1062. local archive_path=$(project_release_sources_archive_path "$project" "$@")
  1063. local sources_path=$(project_sources_path "$project" "$repository" "$@")
  1064. printf '%s\n' "Releasing sources archive for $project (with ${arguments:-no argument})"
  1065. archive_create "$archive_path" "$sources_path"
  1066. file_verification_create "$archive_path"
  1067. }
  1068. project_release_sources_archive_exists_check() {
  1069. local project=$1
  1070. shift
  1071. local archive_path=$(project_release_sources_archive_path "$project" "$@")
  1072. if [[ -z "$archive_path" ]] || ! [[ -f "$archive_path" ]]
  1073. then
  1074. return 1
  1075. else
  1076. return 0
  1077. fi
  1078. }
  1079. project_release_sources_git() {
  1080. local project=$1
  1081. shift
  1082. local repository=$1
  1083. shift
  1084. requirements "git"
  1085. project_sources_directory_missing_empty_error "$project" "$repository" "$@"
  1086. if git_project_check "$repository"
  1087. then
  1088. if ! git_project_release_check "$project" "$repository" "$@"
  1089. then
  1090. git_project_release "$project" "$repository" "$@"
  1091. fi
  1092. else
  1093. if ! project_release_sources_archive_exists_check "$project" "$@"
  1094. then
  1095. project_release_sources_archive_create "$project" "$@"
  1096. fi
  1097. fi
  1098. }
  1099. project_release_check_sources_git() {
  1100. local project=$1
  1101. shift
  1102. local repository=$1
  1103. shift
  1104. requirements "git"
  1105. if git_project_check "$repository"
  1106. then
  1107. git_project_release_check "$project" "$repository" "$@"
  1108. else
  1109. project_release_sources_archive_exists_check "$project" "$@"
  1110. fi
  1111. }
  1112. project_release_install() {
  1113. local project=$1
  1114. shift
  1115. local prefix=$1
  1116. shift
  1117. local install_path=$(project_install_path "$project" "$@")
  1118. local release_path=$(project_release_path "$project" "$prefix")
  1119. local directory_path
  1120. local path
  1121. project_install_directory_missing_empty_error "$project" "$@"
  1122. local files=$(find "$install_path" -type f || true)
  1123. local file
  1124. printf '%s\n' "$files" | while read -r file
  1125. do
  1126. path="$release_path/$file"
  1127. directory_path=$(dirname "$path")
  1128. mkdir -p "$directory_path"
  1129. cp "$install_path/$file" "$path"
  1130. file_verification_create "$path"
  1131. done
  1132. }
  1133. project_release_install_check() {
  1134. local project=$1
  1135. shift
  1136. local prefix=$1
  1137. shift
  1138. local install_path=$(project_install_path "$project" "$@")
  1139. local release_path=$(project_release_path "$project" "$prefix")
  1140. local path
  1141. project_install_directory_missing_empty_error "$project" "$@"
  1142. local files=$(find "$install_path" -type f || true)
  1143. local file
  1144. printf '%s\n' "$files" | while read -r file
  1145. do
  1146. path="$release_path/$file"
  1147. file_exists_check "$path"
  1148. done
  1149. }
  1150. project_release_install_archive() {
  1151. local project=$1
  1152. shift
  1153. local prefix=$1
  1154. shift
  1155. project_install_directory_missing_empty_error "$project" "$@"
  1156. project_release_install_archive_create "$project" "$prefix" "$@"
  1157. }
  1158. project_release_install_archive_check() {
  1159. local project=$1
  1160. shift
  1161. project_release_install_archive_exists_check "$project" "$@"
  1162. }
  1163. project_release_install_archive_create() {
  1164. local project=$1
  1165. shift
  1166. local prefix=$1
  1167. shift
  1168. local arguments="$*"
  1169. local install_path=$(project_install_path "$project" "$@")
  1170. local archive_path=$(project_release_archive_path "$project" "$prefix" "$@")
  1171. printf '%s\n' "Releasing $prefix archive for $project (with ${arguments:-no argument})"
  1172. archive_create "$archive_path" "$install_path"
  1173. file_verification_create "$archive_path"
  1174. }
  1175. project_release_install_archive_exists_check() {
  1176. local project=$1
  1177. shift
  1178. local prefix=$1
  1179. shift
  1180. local archive_path=$(project_release_archive_path "$project" "$prefix" "$@")
  1181. file_exists_check "$archive_path"
  1182. }
  1183. project_release_install_rootfs() {
  1184. local project=$1
  1185. shift
  1186. local prefix=$1
  1187. shift
  1188. project_install_directory_missing_empty_error "$project" "$@"
  1189. if ! project_release_install_rootfs_exists_check "$project" "$prefix" "$@"
  1190. then
  1191. project_release_install_rootfs_create "$project" "$prefix" "$@"
  1192. fi
  1193. }
  1194. project_release_install_rootfs_check() {
  1195. local project=$1
  1196. shift
  1197. project_release_install_rootfs_exists_check "$project" "$@"
  1198. }
  1199. project_release_install_rootfs_create() {
  1200. local project=$1
  1201. shift
  1202. local prefix=$1
  1203. shift
  1204. local arguments="$*"
  1205. local install_path=$(project_install_path "$project" "$@")
  1206. local rootfs_path=$(project_release_rootfs_path "$project" "$prefix" "$@")
  1207. printf '%s\n' "Releasing $prefix rootfs for $project (with ${arguments:-no argument})"
  1208. rootfs_create "$rootfs_path" "$install_path"
  1209. file_verification_create "$rootfs_path"
  1210. }
  1211. project_release_install_rootfs_exists_check() {
  1212. local project=$1
  1213. shift
  1214. local prefix=$1
  1215. shift
  1216. local rootfs_path=$(project_release_rootfs_path "$project" "$prefix" "$@")
  1217. file_exists_check "$rootfs_path"
  1218. }
  1219. project_clean() {
  1220. local project=$1
  1221. shift
  1222. project_clean_build "$project" "$@"
  1223. project_clean_install "$project" "$@"
  1224. project_clean_release "$project" "$@"
  1225. }
  1226. project_clean_build() {
  1227. local project=$1
  1228. shift
  1229. local build_path=$(project_build_path "$project" "$@")
  1230. rm -rf "$build_path"
  1231. }
  1232. project_clean_install() {
  1233. local project=$1
  1234. shift
  1235. local install_path=$(project_install_path "$project" "$@")
  1236. rm -rf "$install_path"
  1237. }
  1238. project_clean_release() {
  1239. local project=$1
  1240. shift
  1241. local prefix
  1242. for prefix in "$SOURCES" "$SYSTEMS" "$IMAGES" "$TOOLS" "$DOCS"
  1243. do
  1244. local release_path=$(project_release_path "$project" "$prefix")
  1245. rm -rf "$release_path"
  1246. done
  1247. }
  1248. project_clean_rootfs() {
  1249. local project=$1
  1250. shift
  1251. project_clean_build "$project" "$@"
  1252. project_clean_rootfs_install "$project" "$@"
  1253. project_clean_release "$project" "$@"
  1254. }
  1255. project_clean_rootfs_install() {
  1256. local project=$1
  1257. shift
  1258. local install_path=$(project_install_path "$project" "$@")
  1259. execute_root rm -rf "$install_path"
  1260. }
  1261. project_file_path() {
  1262. local project=$1
  1263. shift
  1264. local directory=$1
  1265. shift
  1266. local file=$1
  1267. shift
  1268. local project_path=$(project_path "$project")
  1269. local path="$project_path/$directory"
  1270. local argument
  1271. local file_path
  1272. for argument in "" "$@"
  1273. do
  1274. if [[ -n "$argument" ]]
  1275. then
  1276. path="$path/$argument"
  1277. fi
  1278. if ! [[ -f "$path/$file" ]]
  1279. then
  1280. continue
  1281. fi
  1282. file_path="$path/$file"
  1283. break
  1284. done
  1285. if [[ -z "$file_path" ]]
  1286. then
  1287. return 1
  1288. fi
  1289. printf '%s\n' "$file_path"
  1290. }
  1291. project_file_test() {
  1292. local file_path=$(project_file_path "$@")
  1293. test -f "$file_path"
  1294. }
  1295. project_file_contents() {
  1296. local file_path=$(project_file_path "$@")
  1297. if [[ -f "$file_path" ]]
  1298. then
  1299. cat "$file_path"
  1300. fi
  1301. }
  1302. project_file_contents_herit() {
  1303. local project=$1
  1304. shift
  1305. local directory=$1
  1306. shift
  1307. local file=$1
  1308. shift
  1309. local project_path=$(project_path "$project")
  1310. local path="$project_path/$directory"
  1311. local argument
  1312. local file_path
  1313. for argument in "" "$@"
  1314. do
  1315. if [[ -n "$argument" ]]
  1316. then
  1317. path="$path/$argument"
  1318. fi
  1319. file_path="$path/$file"
  1320. if ! [[ -f "$file_path" ]]
  1321. then
  1322. continue
  1323. fi
  1324. cat "$file_path"
  1325. done
  1326. }