project 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714
  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. printf '%s\n' "Patching failed with: ${patch_path##*$root/$PROJECTS/}"
  537. return 1
  538. fi
  539. diff_patch "$sources_path" "$patch_path"
  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. }