-
Notifications
You must be signed in to change notification settings - Fork 16
/
crossbuilder
executable file
·1394 lines (1264 loc) · 52.2 KB
/
crossbuilder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/bin/bash
# Copyright 2016 Canonical Ltd.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Author: Florian Boucault <florian.boucault@canonical.com>
# TODO:
# NOW
# - document commands PACKAGE parameter
# LATER
# - mount home directory using technique from http://insights.ubuntu.com/2016/12/08/mounting-your-home-directory-in-lxd/
# - support snaps by using snapcraft
# - support per project custom build rules and custom deploy rules
# - options passed after the command failed with poor messages
# - option to pass configure flags (DEB_CONFIGURE_EXTRA_FLAGS)
# - add support for icecc/distcc
# - support Debian package format 3.0 (quilt) when no upstream tarball is available (ex: libqofono)
# - check if a newer version of the container's image is available
# - option to cleanup device (undeploy)
#make sure we work with english outputs
export LC_ALL=C
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
LIGHT_RED='\033[1;31m'
LIGHT_GREEN='\033[1;32m'
NC='\033[0m'
ERROR_COLOR=$LIGHT_RED
POSITIVE_COLOR=$GREEN
PROGRAM_NAME=`basename $0`
display_help () {
echo "Usage: $PROGRAM_NAME [options] [command]"
echo ""
echo "If no command is passed '$PROGRAM_NAME' will detect the package located in the current directory, "
echo "create a container for it, download its dependencies, build it and deploy it to the connected device."
echo ""
echo "Available commands:"
echo " help - Display this help."
echo " setup-lxd - Setup LXD."
echo " new - Create a container to build in."
echo " delete - Delete a container."
# echo " list - List existing containers."
echo " shell - Executes a shell in a container (will create it if needed)."
echo " source - Download a source package from the repositories."
echo " dependencies - Download and install the dependencies of a package in a container (will create it if needed)"
echo " inst-foreign - Download and install the given package and sets the 'Multi-arch: foreign' field on them"
echo " build - Build a package in a container (will create it if needed)."
echo " clean - Clean up the artifacts generated by a build."
echo " deploy - Deploy built packages to a connected device."
# echo " undeploy - Remove previously deployed packages from a connected device."
echo ""
echo "Options:"
# echo " --verbose - Print verbose information."
echo " --packages - Packages to deploy [by default: all the ones already installed on device]."
echo " --architecture - Architecture to build for [defaults to architecture of connected device, if none then armhf]."
echo " --ubuntu - Version of Ubuntu to build for [defaults to version of connected device, if none then 16.04]."
echo " --extra-repo - Extra repository to enable (example: ppa:mardy/qbs-on-lts). This option can be repeated."
echo " --lxd-image - LXD image to use [defaults to the ones provided by the Ubuntu SDK (example: ubuntu-sdk-16.04-amd64-armhf-dev)."
echo " --privileged - Use a privileged container (disabled by default)."
echo " --ephemeral - Build using a short-lived container (disabled by default)."
echo " --ssh - Use ssh with provided address instead of adb to deploy to device."
echo " --password - User password of the device to deploy to [defaults to 0000]."
echo " --no-deb - Do not build Debian packages and uses rsync to deploy the build artifacts."
echo " --deploy-path - When deploying with --no-deb (rsync), installation path for the build artifacts [defaults to /]."
echo " --parallel - Set parallelism of the build. Defaults to the number of logical core + 1."
}
#
# SSH backend
#
ssh_exec () {
ssh -o "ConnectTimeout=5" "$SSH_ADDRESS" "$@" || true
}
ssh_push () {
local last="${!#}"
local argv=( "${@:1:$#-1}" )
scp ${argv[@]} "$SSH_ADDRESS:$last"
}
ssh_file_exists () {
ssh -o "ConnectTimeout=5" -q "$SSH_ADDRESS" '[ -e "'$1'" ]'
}
ssh_is_accessible () {
ssh -o "ConnectTimeout=5" -q "$SSH_ADDRESS" "exit"
}
#
# ADB backend
#
adb_exec () {
adb shell "$@"
}
adb_push () {
adb push "$@"
}
adb_file_exists () {
if ! adb pull "$1" /tmp 2>&1 >/dev/null ; then
# Some pull error, so we can assume, that the file doesn't exist.
return 1
fi
# Remove the pulled file.
rm -f "/tmp/$(basename $1)"
return 0
}
adb_is_accessible () {
local DEVICE_STATE=$(adb get-state 2>/dev/null || true)
test "$DEVICE_STATE" = "device"
}
device () {
if [ ! -z "$SSH_ADDRESS" ] ; then
DEVICE_BACKEND=ssh
else
DEVICE_BACKEND=adb
fi
ACTION="$1"
shift
${DEVICE_BACKEND}_${ACTION} "$@"
}
exec_container_root () {
command="$@"
#echo lxc exec $LXD_CONTAINER "$@"
lxc exec $LXD_CONTAINER -- sh -c "$command"
}
exec_container () {
command="$@"
#echo lxc exec $LXD_CONTAINER "$@"
lxc exec $LXD_CONTAINER -- su -l -c "cd $SOURCE_PATH_CONTAINER; $command" $USERNAME
}
variables () {
DEBS_TARBALL_ROOT=debs
if [ -n "$NEW_BUILD" ] ; then
NEW_PACKAGE_VERSION=$PACKAGE_VERSION"+1local~"`date +%s`
else
LATEST_DEBS_TARBALL=$(ls -1 --sort=time $DEBS_TARBALL_ROOT_*.tar 2> /dev/null | head -n1)
NEW_PACKAGE_VERSION=$(echo $LATEST_DEBS_TARBALL | sed "s/$DEBS_TARBALL_ROOT\_//" | sed "s/\.tar//")
fi
DEBS_TARBALL="$DEBS_TARBALL_ROOT"_"$NEW_PACKAGE_VERSION.tar"
LXD_IMAGE_NO_DOT=$(echo $LXD_IMAGE | sed "s|[./]|-|g")
LXD_IMAGE_NO_PREFIX=$(echo $LXD_IMAGE_NO_DOT | sed "s/.*\://")
LXD_IMAGE_NO_SDK=$(echo $LXD_IMAGE_NO_PREFIX | sed "s/ubuntu-sdk/usdk/")
LXD_CONTAINER_COMPAT=builder-$PACKAGE-$LXD_IMAGE_NO_PREFIX
LXD_CONTAINER=$PACKAGE-$LXD_IMAGE_NO_SDK
LXD_CONTAINER=$(echo $LXD_CONTAINER | sed "s/\./-/")
if ! echo "$LXD_CONTAINER" | grep -q "${HOST_ARCH}-${TARGET_ARCH}"; then
# Using non-sdk image, needs to append arch ourselve
LXD_CONTAINER="${LXD_CONTAINER}-${HOST_ARCH}-${TARGET_ARCH}"
fi
if lxc info $LXD_CONTAINER_COMPAT > /dev/null 2>&1 ; then
echo -e "${ERROR_COLOR}Containers are switching to shorter names, please manually delete your container: lxc delete -f $LXD_CONTAINER_COMPAT${NC}"
echo -e "${ERROR_COLOR}Next time it will be called $LXD_CONTAINER.${NC}"
LXD_CONTAINER=$LXD_CONTAINER_COMPAT
fi
# LXD container name can only have HOST_NAME_MAX characters
LXD_CONTAINER=$(echo $LXD_CONTAINER | cut -c 1-$((`getconf HOST_NAME_MAX` - 1)))
LXD_CONTAINER_FAILURE_MSG="${ERROR_COLOR}Failed to start container. See 'lxc info ${LXD_CONTAINER} --show-log'${NC}"
USERNAME=`id --user --name`
GROUPNAME=$USERNAME
if [ -n "$ENCRYPTED_HOME" ] || [ -n "$FORCE_PRIVILEGED" ] ; then
USERID=`id --user`
GROUPID=`id --group`
else
USERID=150000
GROUPID=150000
fi
USERDIR=/home/$USERNAME
SOURCE_REPOSITORY=$USERDIR/source_repository
SCRIPT_REALPATH=$(realpath "${0}")
SCRIPT_DIR=$(dirname "${SCRIPT_REALPATH}")
CREATE_REPO_SCRIPT=create_repository.sh
MOUNTED_DIRECTORY=$PWD
MOUNT_POINT=$USERDIR/$PACKAGE
SOURCE_PATH_LOCAL=$MOUNTED_DIRECTORY
SOURCE_PATH_CONTAINER=$MOUNT_POINT
POST_DEPLOY_SCRIPT=.crossbuilder/post_deploy
TMP_DIR="$(mktemp -d --tmpdir crossbuilder.XXXXXX)"
trap "rm -r $TMP_DIR" HUP INT TERM QUIT EXIT
unset HOST_FARCH TARGET_FARCH DEB_BUILD_PROFILES EXTRA_DEB_BUILD_OPTIONS
# To set the HOST_FARCH, TARGET_FARCH, DEB_BUILD_PROFILES and EXTRA_DEB_BUILD_OPTIONS variables,
# you need to call the "ensure_container" function.
}
# Runs action, provided as first argument, on lxd service detected in system.
lxd_service_action () {
local action=$1
# upstart
if which service > /dev/null 2>&1 && [ -f "/etc/init/lxd.conf" ] ; then
echo "sudo service lxd ${action}"
sudo service lxd ${action}
# snap
elif snap connections lxd > /dev/null 2>&1 ; then
echo "sudo snap ${action} lxd"
sudo snap ${action} lxd
# systemd
elif systemctl cat lxd > /dev/null 2>&1 ; then
echo "sudo systemctl ${action} lxd"
sudo systemctl ${action} lxd
else
echo -e "${ERROR_COLOR}Can't detect LXD service.${NC}"
return 1
fi
}
check_lxd_accessible () {
# /bin/lxd is replaced with a script which tells you to install the lxd snap
# on later versions of Ubuntu.
LXD=`which lxd`
if (grep 'snap install lxd' "$LXD" >/dev/null) && [ ! -f /snap/bin/lxd ] ; then
$LXD
exit 1
fi
if ! LXC_INFO_OUTPUT=$(lxc info 2>&1) ; then
case "$LXC_INFO_OUTPUT" in
'Error: Get "http://unix.socket/1.0":'*)
if ! lxd_service_action start || ! lxc info >/dev/null 2>&1 ; then
echo -e "${ERROR_COLOR}LXD service was not running and failed to start."
echo -e "For more information, run 'lxc info'.${NC}"
exit 1
fi
;;
*)
echo -e "${ERROR_COLOR}LXD was installed but is not accessible."
echo "Check the 'lxd' group exists and you are a member, then restart your computer."
echo -e "For more information, run 'lxc info'.${NC}"
exit 1
esac
fi
}
lxd_has_image_or_container () {
CONTAINER_COUNT=$(lxc list | wc -l)
IMAGE_COUNT=$(lxc image list | wc -l)
if [ $CONTAINER_COUNT = "3" ] && [ $IMAGE_COUNT = "3" ]; then
return 1
fi
return 0
}
is_subuid_setup () {
local USER_ID=$1
local GROUP_ID=$2
if ! grep "root:${USER_ID}:1" /etc/subuid > /dev/null ; then
return 1
fi
if ! grep "root:${GROUP_ID}:1" /etc/subgid > /dev/null ; then
return 1
fi
return 0
}
ensure_lxd_subuid () {
# Fetch user id and his group id to correctly setup subuid/subgid.
local USER_ID=$(id -u)
local GROUP_ID=$(id -g)
if test -z "$FORCE_PRIVILEGED" && ! is_subuid_setup $USER_ID $GROUP_ID ; then
echo -e "${ERROR_COLOR}LXD requires subuid to be setup adequately to mount directories in containers.${NC}"
echo -e "${POSITIVE_COLOR}Would you like to do that now? (y/n) ${NC}"
read REPLY
echo
if [ "$REPLY" = y ]
then
# Setup subuid.
if [ ! -f "/etc/subuid" ] ; then
sudo touch /etc/subuid
fi
sudo usermod --add-subuids "${USER_ID}-${USER_ID}" root
sudo usermod --add-subuids "100000-165535" root
# Setup subgid.
if [ ! -f "/etc/subgid" ] ; then
sudo touch /etc/subgid
fi
sudo usermod --add-subgids "${GROUP_ID}-${GROUP_ID}" root
sudo usermod --add-subgids "100000-165535" root
lxd_service_action restart
else
echo -e "${ERROR_COLOR}Unable to set up LXD for use in crossbuilder. Subuid setup refused.${NC}"
exit 1
fi
fi
}
setup_lxd () {
echo -e "${POSITIVE_COLOR}Setting up LXD.${NC}"
if [ "$(lsb_release -cs)" = "xenial" ]; then
echo -e "${ERROR_COLOR}You are running Ubuntu 16.04 (xenial).${NC}"
echo "We have found an issue where the default LXD setup on 16.04 does not allow"
echo "containers to connect to the internet."
echo "In the following dialog, set up an IPv4 and IPv6 subnet for your bridge so they"
echo "will be able to connect to the internet. The default options presented will do"
echo "this for you."
echo "Press Enter to start"
read KEY
unset $KEY
# Ubuntu 16.04 specific workaround to set up
sudo dpkg-reconfigure -p medium lxd
fi
if [ -n "$ENCRYPTED_HOME" ] ; then
echo -e -n "${ERROR_COLOR}Your home folder is encrypted. $PROGRAM_NAME will use priviledged "
echo -e -n "LXD containers and the default storage backend (slower).\n${NC}"
sudo lxd init --auto
else
echo -e -n "${POSITIVE_COLOR}Would you like to setup LXD with ZFS in your home directory? (y/n) \n${NC}"
echo -n "This is recommended for faster operation, and also in case there is not enough "
echo -n "space in your / partition. \n"
read REPLY
echo
if [ "$REPLY" = y ]
then
if ! which zpool > /dev/null ; then
echo -e "${POSITIVE_COLOR}Installing ZFS.${NC}"
if which apt-get > /dev/null 2>&1 ; then
echo "sudo apt-get install -y zfsutils-linux"
sudo apt-get install -y zfsutils-linux
elif which pacman > /dev/null 2>&1 ; then
echo "sudo pacman -Syu zfs-utils"
sudo pacman -Syu zfs-utils
else
echo -e "${ERROR_COLOR}No known package manager found to install zfs utilities.${NC}"
exit 1
fi
fi
LXD_POOL=~/zfs/lxd.img
echo -e "${POSITIVE_COLOR}Creating file $LXD_POOL to contain all of LXD's images and containers.${NC}"
mkdir -p `dirname $LXD_POOL`
truncate -s 32G $LXD_POOL
sudo zpool create -f lxd $LXD_POOL
sudo lxd init --auto --storage-backend zfs --storage-pool lxd
# add automatic mount of zfs pool upon boot
echo "zpool import -c /etc/zfs/zpool.cache -aN" | sudo tee /etc/rc.local
else
sudo lxd init --auto
fi
fi
}
config_container_dir_mount () {
if ! lxc config device get $LXD_CONTAINER current_dir_mount disk 2> /dev/null ; then
echo -e "${POSITIVE_COLOR}Mounting $MOUNTED_DIRECTORY in container.${NC}"
lxc config device add $LXD_CONTAINER current_dir_mount disk source=$MOUNTED_DIRECTORY path=$MOUNT_POINT
else
lxc config device set $LXD_CONTAINER current_dir_mount source $MOUNTED_DIRECTORY
fi
}
start_container () {
STATUS=$(lxc query "/1.0/containers/${LXD_CONTAINER}/state" | \
jq --raw-output '.status')
if [ $STATUS = 'Stopped' ]; then
# lxc start may give a failure code. It also may not, so we check
# again in a bit.
if ! lxc start $LXD_CONTAINER; then
echo $LXD_CONTAINER_FAILURE_MSG
exit 1
fi
fi
# Unfortunately we need to check again. We check for Started this time
# because the monitor may be hung with the container failing, which will
# give us much different output
STATUS=$(lxc query "/1.0/containers/${LXD_CONTAINER}/state" | \
jq --raw-output '.status')
if [ "$STATUS" != 'Running' ]; then
echo $LXD_CONTAINER_FAILURE_MSG
exit 1
fi
}
nonsdk_container_setup () {
# We want the variable to be expanded inside the container.
# shellcheck disable=SC2016
container_ubuntu_version=$(exec_container_root '. /etc/os-release && echo $VERSION_CODENAME')
case "$container_ubuntu_version" in
xenial|bionic) ubports_repo_line="deb http://repo.ubports.com/ $container_ubuntu_version main" ;;
focal) ubports_repo_line="deb http://repo2.ubports.com/ $container_ubuntu_version main" ;;
esac
if [ -n "$ubports_repo_line" ]; then
exec_container_root "echo '$ubports_repo_line' >/etc/apt/sources.list.d/ubports.list"
fi
# Skip multiarch setup if not crossbuilding
if [ "$HOST_ARCH" = "$TARGET_ARCH" ]; then
return
fi
exec_container_root "dpkg --add-architecture $TARGET_ARCH"
# i386 and amd64 archive is on http://archive.ubuntu.com/ubuntu/, while
# other architectures' are on http://ports.ubuntu.com/ubuntu-ports/. Some
# special handling for APT sources is needed.
case "${HOST_ARCH}-${TARGET_ARCH}" in
i386-amd64|amd64-i386)
# Both on archive, do nothing.
;;
i386-*|amd64-*)
# Host is on archive, target is on ports.
exec_container_root "sed -E \
-e 's:(archive|security)\.ubuntu\.com/ubuntu/:ports.ubuntu.com/ubuntu-ports/:' \
-e 's:^deb :deb [arch=${TARGET_ARCH}] :' \
/etc/apt/sources.list >/etc/apt/sources.list.d/ports.list"
exec_container_root "sed -i -E \
-e 's:^deb :deb [arch=${HOST_ARCH}] :' \
/etc/apt/sources.list"
;;
*-i386|*-amd64)
# Host is on ports, target is on archive.
exec_container_root "sed -E \
-e 's:ports\.ubuntu\.com/ubuntu-ports/ ([a-z]+)-security :security.ubuntu.com/ubuntu/ \1-security :' \
-e 's:ports\.ubuntu\.com/ubuntu-ports/ ([a-z-]+):archive.ubuntu.com/ubuntu/ \1 :' \
-e 's:^deb :deb [arch=${TARGET_ARCH}] :' \
/etc/apt/sources.list >/etc/apt/sources.list.d/non-ports.list"
exec_container_root "sed -i -E \
-e 's:^deb :deb [arch=${HOST_ARCH}] :' \
/etc/apt/sources.list"
;;
# Not matched: both on ports, do nothing.
esac
}
detect_farch_and_build_params_in_container () {
HOST_FARCH=$(exec_container dpkg-architecture -f -a$HOST_ARCH -qDEB_BUILD_MULTIARCH)
TARGET_FARCH=$(exec_container dpkg-architecture -f -a$TARGET_ARCH -qDEB_HOST_MULTIARCH)
if [ "$(exec_container dpkg-architecture -f -a$TARGET_ARCH -qDEB_BUILD_ARCH)" != "$TARGET_ARCH" ]; then
DEB_BUILD_PROFILES="cross nocheck nodoc noudeb"
EXTRA_DEB_BUILD_OPTIONS="nocheck nodoc noudeb"
else
DEB_BUILD_PROFILES="noudeb"
EXTRA_DEB_BUILD_OPTIONS="noudeb"
fi
}
create_container () {
lxc remote --protocol=simplestreams --public=true --accept-certificate=true add ubports-sdk https://sdk-images.ubports.com || true
lxc init $LXD_IMAGE $LXD_CONTAINER $EPHEMERAL_FLAG
if [ -n "$ENCRYPTED_HOME" ] || [ -n "$FORCE_PRIVILEGED" ] ; then
lxc config set $LXD_CONTAINER security.privileged true
else
if [ "$(lxc --version | cut -f1 -d. )" -ge "3" ]; then
IDMAP="lxc.idmap"
else
IDMAP="lxc.id_map"
fi
printf "$IDMAP = g $GROUPID `id --group` 1\n$IDMAP = u $USERID `id --user` 1" | lxc config set $LXD_CONTAINER raw.lxc -
fi
lxc start $LXD_CONTAINER
lxc exec --env GROUPID=$GROUPID --env GROUPNAME=$GROUPNAME $LXD_CONTAINER -- addgroup --gid $GROUPID $GROUPNAME
lxc exec --env GROUPID=$GROUPID --env USERNAME=$USERNAME --env USERID=$USERID $LXD_CONTAINER -- adduser --disabled-password --gecos "" --uid $USERID --gid $GROUPID $USERNAME
lxc exec --env USERNAME=$USERNAME $LXD_CONTAINER -- usermod -aG sudo $USERNAME
exec_container_root "sed -i 's/ENV_PATH.*PATH=/ENV_PATH\tPATH=\/usr\/lib\/ccache:/' /etc/login.defs"
# wait for the container's network connection
check_for_container_network
if [ "${TARGET_UBUNTU}" = "15.04" ]; then
# Fixup the SDK images; we should really try to get new SDK images for ubports
exec_container_root "sed -i 's/archive.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list"
exec_container_root "sed -i 's/ports.ubuntu.com\/ubuntu-ports/old-releases.ubuntu.com\/ubuntu/g' /etc/apt/sources.list"
exec_container_root "add-apt-repository -y ppa:ubports-developers/overlay"
exec_container_root "add-apt-repository 'deb http://repo.ubports.com vivid main' >> /etc/apt/sources.list"
fi
wget -qO - "https://repo.ubports.com/keyring.gpg" | exec_container_root 'cat >/etc/apt/trusted.gpg.d/ubports-keyring.gpg'
if ! echo "$LXD_IMAGE" | grep -q "ubuntu-sdk"; then
nonsdk_container_setup
fi
exec_container_root "printf 'APT::Periodic::Update-Package-Lists \"0\";\n\
APT::Periodic::Unattended-Upgrade \"0\";\n\
' > /etc/apt/apt.conf.d/20auto-upgrades"
for EXTRA_REPO in $EXTRA_REPOS
do
exec_container_root "add-apt-repository -y $EXTRA_REPO"
done
exec_container_root apt update
exec_container_root apt install -y sudo debhelper ccache software-properties-common devscripts equivs qemu-user-static
exec_container_root adduser $USERNAME sudo
# set empty password for the user
exec_container_root passwd --delete $USERNAME
detect_farch_and_build_params_in_container
exec_container_root "printf 'export PKG_CONFIG_PATH=/usr/lib/$TARGET_FARCH/pkgconfig\n\
export CROSS_COMPILE=$TARGET_FARCH-\n\
export CC=$TARGET_FARCH-gcc\n\
export CXX=$TARGET_FARCH-g++\n\
' >> /etc/profile.d/clickvars.sh"
# FIXME: image should have environment variables set from executing:
# dpkg-architecture --print-set --target-arch armhf
}
ensure_container () {
# setup the building container
if lxc info $LXD_CONTAINER > /dev/null 2>&1 ; then
echo -e "${POSITIVE_COLOR}LXD container $LXD_CONTAINER already exists.${NC}"
config_container_dir_mount
start_container
check_for_container_network
detect_farch_and_build_params_in_container
else
echo -e "${POSITIVE_COLOR}Creating LXD container $LXD_CONTAINER using $LXD_IMAGE.${NC}"
create_container
config_container_dir_mount
fi
}
start_container_if_exists () {
if lxc info $LXD_CONTAINER > /dev/null 2>&1 ; then
echo -e "${POSITIVE_COLOR}Starting LXD container $LXD_CONTAINER.${NC}"
config_container_dir_mount
start_container
else
echo -e "${ERROR_COLOR}LXD container $LXD_CONTAINER doesn't exist.${NC}"
exit 1
fi
}
delete_container () {
echo -e "${POSITIVE_COLOR}Deleting LXD container $LXD_CONTAINER.${NC}"
lxc delete -f $LXD_CONTAINER
}
shell_container () {
echo -e "${POSITIVE_COLOR}Entering shell in LXD container $LXD_CONTAINER.${NC}"
lxc exec $LXD_CONTAINER -- su --login $USERNAME
}
stop_container () {
echo -e "${POSITIVE_COLOR}Stopping LXD container $LXD_CONTAINER.${NC}"
lxc stop -f $LXD_CONTAINER
}
enable_overlay_source () {
OVERLAY_APT="/etc/apt/sources.list.d/ci-train-ppa-service-ubuntu-stable-phone-overlay-vivid.list"
if exec_container_root "grep '#.*deb-src' $OVERLAY_APT" ; then
exec_container_root "sed -i 's/#.*deb-src/deb-src/' $OVERLAY_APT"
exec_container_root apt-get update
fi
}
get_source_package () {
echo -e "${POSITIVE_COLOR}Downloading source package $PACKAGE for Ubuntu $TARGET_UBUNTU.${NC}"
# cleanup source repository potentially setup by copy_build_to_container before
exec_container rm -f $USERDIR/dependencies_installed
exec_container_root "rm -f /etc/apt/sources.list.d/localrepo.list /etc/apt/preferences.d/localrepo.pref"
enable_overlay_source
if ! lxc exec $LXD_CONTAINER -- su -l -c "cd $MOUNT_POINT; apt-get source --only-source $PACKAGE" $USERNAME ; then
echo -e "${ERROR_COLOR}No source package exists with the name $PACKAGE.${NC}"
echo -e "${ERROR_COLOR}Deleting container $LXD_CONTAINER.${NC}"
lxc delete -f $LXD_CONTAINER
exit 1
fi
PACKAGE_VERSION=$(exec_container dpkg-parsechangelog --show-field Version -l $PACKAGE*/debian/changelog)
exec_container "mv $PACKAGE*.orig.tar.* $PACKAGE*diff.* $PACKAGE*debian.tar* $PACKAGE*.dsc $USERDIR/" || true
mv $PACKAGE-*/* .
mv $PACKAGE-*/.[!.]* . || true
rmdir $PACKAGE-*
echo -e "${POSITIVE_COLOR}Source code for $PACKAGE is now available in $PACKAGE/.${NC}"
VCS=$(grep -i vcs debian/control | grep --invert-match Vcs-Browser)
if [ "$VCS" != "" ] ; then
echo -e "${POSITIVE_COLOR}'$PACKAGE' packaging is versioned and available at $VCS${NC}"
fi
}
backup_changelog () {
cp debian/changelog ${TMP_DIR}/$PACKAGE-changelog.orig
}
restore_changelog () {
mv ${TMP_DIR}/$PACKAGE-changelog.orig debian/changelog
}
backup_jenkinsfile_and_sourceloc() {
if [ -f Jenkinsfile ]; then
mv Jenkinsfile ${TMP_DIR}/$PACKAGE-Jenkinsfile
fi
if [ -f ubports.source_location ]; then
mv ubports.source_location ${TMP_DIR}/$PACKAGE-ubports.source_location
fi
}
restore_jenkinsfile_and_sourceloc() {
if [ -f ${TMP_DIR}/$PACKAGE-Jenkinsfile ]; then
mv ${TMP_DIR}/$PACKAGE-Jenkinsfile Jenkinsfile
fi
if [ -f ${TMP_DIR}/$PACKAGE-ubports.source_location ]; then
mv ${TMP_DIR}/$PACKAGE-ubports.source_location ubports.source_location
fi
}
workaround_multi_arch_deps () {
DEBIAN_CONTROL="$1"
for package in python3-setuptools python3-flake8 dh_translations xvfb qtdeclarative5-doc-html qtbase5-doc-html
do
sed -i "s/${package}\([, ]\)/${package}:native\1/" "${DEBIAN_CONTROL}"
done
}
apply_build_profiles_to_debian_control () {
DEBIAN_CONTROL="$1"
for profile in $DEB_BUILD_PROFILES
do
sed -i -e "/^ \+\S\+ .*<\!${profile}>/d" -e "s/: *\S\+ .*<\!${profile}>[^,]*,/:,/" "${DEBIAN_CONTROL}"
done
}
# Accepts file paths. Print the first file that exists, or nothing if none exists.
first_existing_file () {
while [ -n "$1" ]; do
if [ -e "$1" ]; then
echo "$1"
return
fi
shift
done
}
ensure_upstream_tarball () {
source_location_file=$(first_existing_file debian/ubports.source_location ubports.source_location)
if [ -n "$source_location_file" ]; then
while read -r SOURCE_URL && read -r TARGET_FILE; do
echo -e "${POSITIVE_COLOR}Downloading upstream source tarball of $PACKAGE in container to $TARGET_FILE.${NC}"
# /dev/null redirection is required. Otherwise, `lxc exec` will closes stdin (i.e. the file).
# https://github.com/lxc/lxd/issues/2200
exec_container "cd $USERDIR && wget --continue -O $TARGET_FILE $SOURCE_URL" </dev/null
done <"$source_location_file"
elif grep quilt debian/source/format > /dev/null 2>&1 ; then
echo -e "${POSITIVE_COLOR}Downloading upstream tarball of $PACKAGE in container.${NC}"
enable_overlay_source
# FIXME: try using dget instead so that we can specify a precise version
exec_container "cd $USERDIR && apt-get source --download-only $PACKAGE"
fi
}
install_dependencies () {
echo -e "${POSITIVE_COLOR}Installing $TARGET_ARCH (host $HOST_ARCH) build dependencies for $PACKAGE in container $LXD_CONTAINER.${NC}"
# install build dependencies in container
if ! exec_container test -e $USERDIR/dependencies_installed ; then
ensure_upstream_tarball
echo -e "${POSITIVE_COLOR}Installing $TARGET_ARCH build dependencies for $PACKAGE in container $LXD_CONTAINER.${NC}"
cp debian/control "${TMP_DIR}/"
workaround_multi_arch_deps ${TMP_DIR}/control
exec_container_root apt-get update
# TODO: add build profiles to mk-build-deps once wishlist bug
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=894732 is fixed and
# propagated to Ubuntu version we will use in the future.
# Meanwhile, have mk-build-deps operate on a stripped-down debian/control
apply_build_profiles_to_debian_control ${TMP_DIR}/control
lxc file push ${TMP_DIR}/control $LXD_CONTAINER$USERDIR/patched_debian_control
PROFILES_OPTION=$(echo "$DEB_BUILD_PROFILES" | sed "s/ /,/")
exec_container_root \
"mk-build-deps \
-t 'apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y' \
-i --host-arch $TARGET_ARCH \
$USERDIR/patched_debian_control"
rm ${TMP_DIR}/control
QMAKE=$(exec_container "find /usr -executable -type f -path '*/bin/*' -name '*qmake*' | grep $TARGET_FARCH" | head -1)
if [ -n "$QMAKE" ] && [ "$HOST_ARCH" != "$TARGET_ARCH" ]; then
echo -e "${POSITIVE_COLOR}Setting $QMAKE as the default qmake binary.${NC}"
exec_container_root "ln -s -f $QMAKE /usr/local/bin/qmake"
exec_container_root "printf '/usr/local/bin\n/usr/lib/$TARGET_FARCH\n' > /usr/share/qtchooser/qt5-$HOST_FARCH-$TARGET_FARCH.conf"
exec_container_root ln -f -s ../../../share/qtchooser/qt5-$HOST_FARCH-$TARGET_FARCH.conf /usr/lib/$HOST_FARCH/qtchooser/qt5.conf
# Fix moc and other missing tools for cmake
exec_container_root mkdir -p /usr/lib/$HOST_FARCH/qt5/bin/
for TOOL in moc qdbusxml2cpp rcc
do
exec_container_root ln -f -s ../../../qt5/bin/$TOOL /usr/lib/$HOST_FARCH/qt5/bin/
done
elif [ "$HOST_ARCH" != "$TARGET_ARCH" ]; then
echo "Note: qmake not found"
fi
exec_container touch $USERDIR/dependencies_installed
else
echo -e "${POSITIVE_COLOR}$TARGET_ARCH build dependencies for $PACKAGE already installed in container $LXD_CONTAINER.${NC}"
fi;
}
install_foreign () {
for dep in "$@"
do
echo "Installing $dep"
exec_container "mkdir -p foreign && cd foreign && apt-get download $dep && dpkg-deb -R $dep* tmp"
exec_container "grep -vi '^multi' foreign/tmp/DEBIAN/control > foreign/tmp/DEBIAN/control.tmp"
exec_container "mv foreign/tmp/DEBIAN/control.tmp foreign/tmp/DEBIAN/control"
exec_container "echo 'Multi-Arch: foreign' >> foreign/tmp/DEBIAN/control"
exec_container "cd foreign && dpkg-deb -b tmp $dep*"
exec_container_root "dpkg -i $SOURCE_PATH_CONTAINER/foreign/$dep*"
exec_container "rm -r foreign/"
done
}
build_deb () {
# build package in container
echo -e "${POSITIVE_COLOR}Building $PACKAGE for $TARGET_ARCH in parallel (-j$PARALLEL_BUILD).${NC}"
exec_container "rm -f ../*.deb ../*.changes ../$DEBS_TARBALL"
exec_container "rm -f ../*.ddeb"
exec_container "rm -f debian/*.debhelper.log"
exec_container "rm -f debian/files"
backup_changelog
trap restore_changelog HUP INT TERM QUIT
exec_container DEBEMAIL='crossbuilder@ubports.com' dch -v $NEW_PACKAGE_VERSION Crossbuilder
if ! exec_container "DEB_BUILD_PROFILES='$DEB_BUILD_PROFILES' DEB_BUILD_OPTIONS='parallel=$PARALLEL_BUILD nostrip $DEB_BUILD_OPTIONS $EXTRA_DEB_BUILD_OPTIONS' dpkg-buildpackage --target-arch $TARGET_ARCH -d -us -uc -nc -I -Iobj-* -Idebian/tmp/* -I.bzr* -b" ; then
restore_changelog
exit 1
fi
restore_changelog
# transfer resulting debian packages to local machine
echo -e "${POSITIVE_COLOR}Packing build artifacts in $DEBS_TARBALL.${NC}"
rm -f $DEBS_TARBALL_ROOT*
exec_container "tar cf ../$DEBS_TARBALL ../*.deb"
lxc file pull $LXD_CONTAINER$USERDIR/$DEBS_TARBALL .
}
build_make_install () {
echo -e "${POSITIVE_COLOR}Building $PACKAGE for $TARGET_ARCH in parallel (-j$PARALLEL_BUILD).${NC}"
exec_container "rm -f debian/*.debhelper.log"
exec_container "DEB_BUILD_PROFILES='$DEB_BUILD_PROFILES' DEB_BUILD_OPTIONS='parallel=$PARALLEL_BUILD nostrip $DEB_BUILD_OPTIONS $EXTRA_DEB_BUILD_OPTIONS' fakeroot debian/rules install"
}
build () {
if [ -n "$NO_DEB" ] ; then
build_make_install
else
build_deb
fi
}
copy_build_to_container () {
PREVIOUS_BUILD_FOLDER=$1
PREVIOUS_DEBS_TARBALL=$2
echo -e "${POSITIVE_COLOR}Copying and extracting $PREVIOUS_DEBS_TARBALL from $PREVIOUS_BUILD_FOLDER into container $LXD_CONTAINER.${NC}"
exec_container mkdir -p $SOURCE_REPOSITORY
lxc file push $PREVIOUS_BUILD_FOLDER/$PREVIOUS_DEBS_TARBALL $LXD_CONTAINER$SOURCE_REPOSITORY/
exec_container "tar xf $SOURCE_REPOSITORY/$PREVIOUS_DEBS_TARBALL --directory $SOURCE_REPOSITORY/"
lxc file push $SCRIPT_DIR/$CREATE_REPO_SCRIPT $LXD_CONTAINER$SOURCE_REPOSITORY/
exec_container $SOURCE_REPOSITORY/$CREATE_REPO_SCRIPT $SOURCE_REPOSITORY
exec_container_root "echo 'deb [trusted=yes] file://$SOURCE_REPOSITORY/ /' >/etc/apt/sources.list.d/localrepo.list"
exec_container_root "printf 'Package: *\nPin: release o=local\nPin-Priority: 2000' >/etc/apt/preferences.d/localrepo.pref"
}
clean () {
echo -e "${POSITIVE_COLOR}Cleaning previous build of $PACKAGE for $TARGET_ARCH.${NC}"
exec_container "DEB_BUILD_PROFILES='$DEB_BUILD_PROFILES' debian/rules clean"
}
check_for_container_network() {
NETWORK_UP=0
for i in `seq 1 10`
do
if lxc query "/1.0/containers/${LXD_CONTAINER}/state" | \
jq -e '.network.eth0.addresses | any( .family == "inet" )' \
> /dev/null 2>&1 ; then
NETWORK_UP=1
break
fi
sleep 1
done
if [ $NETWORK_UP -ne 1 ] ; then
# On manjaro the 16.04 containers can't get ip4 address.
# This can be corrected by running 'dhclient' in container.
exec_container_root "dhclient"
for i in `seq 1 10`
do
if lxc query "/1.0/containers/${LXD_CONTAINER}/state" | jq -e '.network.eth0.addresses | any( .family == "inet" )' > /dev/null 2>&1 ; then
echo -e "${POSITIVE_COLOR}Container is connected to the Internet.${NC}"
NETWORK_UP=1
break
fi
sleep 1
done
if [ $NETWORK_UP -ne 1 ] ; then
echo -e "${ERROR_COLOR}Container is not connected to the Internet.${NC}"
exit 1
fi
fi
}
check_for_device_network() {
NETWORK_UP=0
for i in `seq 1 5`
do
if device exec "ping -c1 -w1 google.com" | grep PING > /dev/null 2>&1 ; then
NETWORK_UP=1
break
fi
done
if [ $NETWORK_UP -ne 1 ] ; then
echo -e "${ERROR_COLOR}The connected device is not connected to the Internet.${NC}"
exit 1
fi
}
deploy_deb () {
if ! test -e $DEBS_TARBALL ; then
echo -e "${ERROR_COLOR}No Debian packages ($DEBS_TARBALL) to deploy to device. Run $PROGRAM_NAME build first.${NC}"
exit 1
fi
echo -e "${POSITIVE_COLOR}Transferring Debian packages to device.${NC}"
# tranfer debian packages to device
device exec mkdir -p /tmp/repo
device push $DEBS_TARBALL /tmp/repo/
device exec "cd /tmp/repo && tar xvf /tmp/repo/$DEBS_TARBALL && rm -f /tmp/repo/$DEBS_TARBALL_ROOT*"
# install debian packages on device
if [ ! -z "$PACKAGES_TO_DEPLOY" ] ; then
echo -e "${POSITIVE_COLOR}Installing manually specified packages:" $PACKAGES_TO_DEPLOY${NC}
DPKG_ARGS=""
for package in $PACKAGES_TO_DEPLOY ; do
DPKG_ARGS="$DPKG_ARGS /tmp/repo/$package"_"$NEW_PACKAGE_VERSION"_"$TARGET_ARCH.deb"
done
device exec SUDO_ASKPASS=/tmp/askpass.sh sudo -A dpkg -i $DPKG_ARGS
else
check_for_device_network
echo -e "${POSITIVE_COLOR}Upgrading packages already installed on device with newly built ones.${NC}"
# create local deb repository on device
if ! device file_exists /tmp/repo/$CREATE_REPO_SCRIPT ; then
device push $SCRIPT_DIR/$CREATE_REPO_SCRIPT /tmp/repo/
device exec /tmp/repo/$CREATE_REPO_SCRIPT /tmp/repo
device exec "printf 'deb [trusted=yes] file:/tmp/repo/ /\n' > /tmp/repo/sources.list"
device exec "cp /etc/apt/sources.list /tmp/repo/all.list"
device exec "cat /tmp/repo/sources.list >> /tmp/repo/all.list"
SERIES=$(device exec "lsb_release -cs" | tr -d '\r')
device exec "printf 'Package: *\nPin: release o=local\nPin-Priority: 2000\n\nPackage: *\nPin: release a=$SERIES*\nPin-Priority: 50' | SUDO_ASKPASS=/tmp/askpass.sh sudo -A tee /etc/apt/preferences.d/localrepo.pref"
# device exec SUDO_ASKPASS=/tmp/askpass.sh sudo -A apt-get update
else
device exec /tmp/repo/$CREATE_REPO_SCRIPT /tmp/repo
fi;
device exec "SUDO_ASKPASS=/tmp/askpass.sh sudo -A sed -i '/Pin-Priority/c\Pin-Priority: 50' /etc/apt/preferences.d/extra-ppas.pref"
device exec SUDO_ASKPASS=/tmp/askpass.sh sudo -A apt-get update -o Dir::Etc::sourcelist="/tmp/repo/sources.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"
device exec SUDO_ASKPASS=/tmp/askpass.sh sudo -A apt-get dist-upgrade -o Dir::Etc::sourcelist="/tmp/repo/all.list" --yes --force-yes
device exec "SUDO_ASKPASS=/tmp/askpass.sh sudo -A sed -i '/Pin-Priority/c\Pin-Priority: 1001' /etc/apt/preferences.d/extra-ppas.pref"
fi;
}
deploy_make_install () {
echo -e "${POSITIVE_COLOR}Transferring build artifacts to device.${NC}"
if [ -z "$PACKAGES_TO_DEPLOY" ] ; then
PACKAGES_TO_DEPLOY=$(grep Package debian/control | cut -d ' ' -f 2)
fi
for binary_package in $PACKAGES_TO_DEPLOY
do
FOLDERS_TO_DEPLOY="$FOLDERS_TO_DEPLOY debian/$binary_package/"
# clean up build artifacts from a potential previous Debian package build
rm -rf debian/$binary_package/DEBIAN
done
if [ -z "$DEPLOY_PATH" ] ; then
DEPLOY_PATH="/"
fi
if [ ! -z "$SSH_ADDRESS" ]; then
# There is an ssh address already provided, skip sync_with_device script and just run the rsync.
rsync --rsync-path='SUDO_ASKPASS=/tmp/askpass.sh sudo -A rsync' -vae "ssh" $FOLDERS_TO_DEPLOY $SSH_ADDRESS:$DEPLOY_PATH
return
fi
. "$SCRIPT_DIR/sync_with_device" $FOLDERS_TO_DEPLOY $DEPLOY_PATH
}
deploy_to_device () {
if ! device is_accessible ; then
echo -e "${ERROR_COLOR}No device connected to deploy to.${NC}"
exit 1
fi;
# setup sudo on device
device exec "printf '#\041/bin/sh\necho $DEVICE_PASSWORD' >/tmp/askpass.sh"
device exec chmod +x /tmp/askpass.sh
# check password is correct
device exec SUDO_ASKPASS=/tmp/askpass.sh sudo -A touch /tmp/password_ok
if device file_exists /tmp/password_ok ; then
device exec SUDO_ASKPASS=/tmp/askpass.sh sudo -A rm -f /tmp/password_ok
else
echo -e "${ERROR_COLOR}Device password incorrect. Use --password to pass the correct one or write it in $DEVICE_PASSWORD_FILE.${NC}"
exit 1
fi
device exec SUDO_ASKPASS=/tmp/askpass.sh sudo -A mount -o remount,rw /
if [ -n "$NO_DEB" ] ; then
deploy_make_install
else
deploy_deb
fi
# execute post deploy
if test -e $SOURCE_PATH_LOCAL/$POST_DEPLOY_SCRIPT ; then
echo -e "${POSITIVE_COLOR}Execute project specific post deploy script ($POST_DEPLOY_SCRIPT).${NC}"
device push $SOURCE_PATH_LOCAL/$POST_DEPLOY_SCRIPT /tmp
device exec sh /tmp/$(basename $POST_DEPLOY_SCRIPT)
else
echo -e "${POSITIVE_COLOR}If a script named $POST_DEPLOY_SCRIPT existed, it would be executed on device after every deploy.${NC}"
fi
}
detect_host_architecture() {
if which dpkg > /dev/null 2>&1 ; then
HOST_ARCH=`dpkg --print-architecture`
else
# To find out the host's debian architecture name, first find out debian multiarch tuple and use conversion table.
# Source: https://wiki.debian.org/Multiarch/Tuples
if [ -z $HOST_FARCH ] && which gcc > /dev/null 2>&1 ; then
HOST_FARCH=$(gcc -print-multiarch)
# On manjaro the 'gcc -print-multiarch' returns nothing.
# Use the 'gcc -dumpmachine' multiarch triplet result and strip the vendor part if the result contains it.
[ -z $HOST_FARCH ] && HOST_FARCH=$(gcc -dumpmachine | sed 's/^\([^-]\+\)-\([^-]\+\)-\([^-]\+\)-\([^-]\+\)$/\1-\3-\4/')
fi
declare -A MULTIARCH_TO_DEBIAN=( \
[x86_64-linux-gnu]=amd64 \
[arm-linux-gnu]=arm \
[aarch64-linux-gnu]=arm64 \
[aarch64-linux-gnu_ilp32]=arm64ilp32 \
[arm-linux-gnueabi]=armel \
[arm-linux-gnueabihf]=armhf \
[riscv64-linux-gnu]=riscv64 \
[x86_64-uefi]=uefi-amd6436 \
[aarch64-uefi]=uefi-arm6436 \
[arm-uefi]=uefi-armhf36 \
[i386-uefi]=uefi-i38636 \
[x86_64-linux-gnux32]=x32 \
)
HOST_ARCH=${MULTIARCH_TO_DEBIAN[$HOST_FARCH]}
fi
}
while [ "$1" != "" ]; do
OPTION=`echo $1 | awk -F= '{print $1}'`
VALUE=`echo $1 | awk -F= '{print $2}'`
case $1 in
-*)
case $OPTION in
--packages)
PACKAGES_TO_DEPLOY=$VALUE
;;
--architecture)
TARGET_ARCH=$VALUE
;;
--ubuntu)
TARGET_UBUNTU=$VALUE
;;
--extra-repo)
EXTRA_REPOS="$EXTRA_REPOS $VALUE"
;;
--lxd-image)
LXD_IMAGE=$VALUE
;;
--ssh)