]> sigrok.org Git - sigrok-util.git/blob - cross-compile/appimage/contrib/functions.sh
sigrok-cross-mingw: Also build PV manual
[sigrok-util.git] / cross-compile / appimage / contrib / functions.sh
1 # This file is supposed to be sourced by each Recipe
2 # that wants to use the functions contained herein
3 # like so:
4 # wget -q https://github.com/AppImage/AppImages/raw/${PKG2AICOMMIT}/functions.sh -O ./functions.sh
5 # . ./functions.sh
6
7 # RECIPE=$(realpath "$0")
8
9 # Specify a certain commit if you do not want to use master
10 # by using:
11 # export PKG2AICOMMIT=<git sha>
12 if [ -z "$PKG2AICOMMIT" ] ; then
13   PKG2AICOMMIT=master
14 fi
15
16 # Options for apt-get to use local files rather than the system ones
17 OPTIONS="-o Debug::NoLocking=1
18 -o APT::Cache-Limit=125829120
19 -o Dir::Etc::sourcelist=./sources.list
20 -o Dir::State=./tmp
21 -o Dir::Cache=./tmp
22 -o Dir::State::status=./status
23 -o Dir::Etc::sourceparts=-
24 -o APT::Get::List-Cleanup=0
25 -o APT::Get::AllowUnauthenticated=1
26 -o Debug::pkgProblemResolver=true
27 -o Debug::pkgDepCache::AutoInstall=true
28 -o APT::Install-Recommends=0
29 -o APT::Install-Suggests=0
30 "
31
32 # Detect system architecture to know which binaries of AppImage tools
33 # should be downloaded and used.
34 case "$(uname -i)" in
35   x86_64|amd64)
36 #    echo "x86-64 system architecture"
37     SYSTEM_ARCH="x86_64";;
38   i?86)
39 #    echo "x86 system architecture"
40     SYSTEM_ARCH="i686";;
41 #  arm*)
42 #    echo "ARM system architecture"
43 #    SYSTEM_ARCH="";;
44   unknown|AuthenticAMD|GenuineIntel)
45 #         uname -i not answer on debian, then:
46     case "$(uname -m)" in
47       x86_64|amd64)
48 #        echo "x86-64 system architecture"
49         SYSTEM_ARCH="x86_64";;
50       i?86)
51 #        echo "x86 system architecture"
52         SYSTEM_ARCH="i686";;
53     esac ;;
54   *)
55     echo "Unsupported system architecture"
56     exit 1;;
57 esac
58
59 # Either get the file from remote or from a static place.
60 # critical for builds without network access like in Open Build Service
61 cat_file_from_url()
62 {
63   cat_excludelist="wget -q $1 -O -"
64   [ -e "$STATIC_FILES/${1##*/}" ] && cat_excludelist="cat $STATIC_FILES/${1##*/}"
65   $cat_excludelist
66 }
67
68 git_pull_rebase_helper()
69 {
70   git reset --hard HEAD
71   git pull
72 }
73
74 # Patch /usr to ././ in ./usr
75 # to make the contents of usr/ relocateable
76 # (this requires us to cd ./usr before running the application; AppRun does that)
77 patch_usr()
78 {
79   find usr/ -type f -executable -exec sed -i -e "s|/usr|././|g" {} \;
80 }
81
82 # Download AppRun and make it executable
83 get_apprun()
84 {
85   TARGET_ARCH=${ARCH:-$SYSTEM_ARCH}
86   wget -c https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-${TARGET_ARCH} -O AppRun
87   chmod a+x AppRun
88 }
89
90 # Copy the library dependencies of all exectuable files in the current directory
91 # (it can be beneficial to run this multiple times)
92 copy_deps()
93 {
94   PWD=$(readlink -f .)
95   FILES=$(find . -type f -executable -or -name *.so.* -or -name *.so | sort | uniq )
96   for FILE in $FILES ; do
97     ldd "${FILE}" | grep "=>" | awk '{print $3}' | xargs -I '{}' echo '{}' >> DEPSFILE
98   done
99   DEPS=$(cat DEPSFILE | sort | uniq)
100   for FILE in $DEPS ; do
101     if [ -e $FILE ] && [[ $(readlink -f $FILE)/ != $PWD/* ]] ; then
102       cp -v --parents -rfL $FILE ./ || true
103     fi
104   done
105   rm -f DEPSFILE
106 }
107
108 # Move ./lib/ tree to ./usr/lib/
109 move_lib()
110 {
111   mkdir -p ./usr/lib ./lib && find ./lib/ -exec cp -v --parents -rfL {} ./usr/ \; && rm -rf ./lib
112   mkdir -p ./usr/lib ./lib64 && find ./lib64/ -exec cp -v --parents -rfL {} ./usr/ \; && rm -rf ./lib64
113 }
114
115 # Delete blacklisted files
116 delete_blacklisted()
117 {
118   BLACKLISTED_FILES=$(cat_file_from_url https://github.com/AppImage/AppImages/raw/${PKG2AICOMMIT}/excludelist | sed 's|#.*||g')
119   echo $BLACKLISTED_FILES
120   for FILE in $BLACKLISTED_FILES ; do
121     FILES="$(find . -name "${FILE}" -not -path "./usr/optional/*")"
122     for FOUND in $FILES ; do
123       rm -vf "$FOUND" "$(readlink -f "$FOUND")"
124     done
125   done
126
127   # Do not bundle developer stuff
128   rm -rf usr/include || true
129   rm -rf usr/lib/cmake || true
130   rm -rf usr/lib/pkgconfig || true
131   find . -name '*.la' | xargs -i rm {}
132 }
133
134 # Echo highest glibc version needed by the executable files in the current directory
135 glibc_needed()
136 {
137   find . -name *.so -or -name *.so.* -or -type f -executable  -exec strings {} \; | grep ^GLIBC_2 | sed s/GLIBC_//g | sort --version-sort | uniq | tail -n 1
138   # find . -name *.so -or -name *.so.* -or -type f -executable  -exec readelf -s '{}' 2>/dev/null \; | sed -n 's/.*@GLIBC_//p'| awk '{print $1}' | sort --version-sort | tail -n 1
139 }
140 # Add desktop integration
141 # Usage: get_desktopintegration name_of_desktop_file_and_exectuable
142 get_desktopintegration()
143 {
144   REALBIN=$(grep -o "^Exec=.*" *.desktop | sed -e 's|Exec=||g' | cut -d " " -f 1 | head -n 1)
145   cat_file_from_url https://raw.githubusercontent.com/AppImage/AppImageKit/master/desktopintegration > ./usr/bin/$REALBIN.wrapper
146   chmod a+x ./usr/bin/$REALBIN.wrapper
147
148   sed -i -e "s|^Exec=$REALBIN|Exec=$REALBIN.wrapper|g" $1.desktop
149 }
150
151 # Generate AppImage; this expects $ARCH, $APP and $VERSION to be set
152 generate_appimage()
153 {
154   # Download AppImageAssistant
155   URL="https://github.com/AppImage/AppImageKit/releases/download/6/AppImageAssistant_6-${SYSTEM_ARCH}.AppImage"
156   wget -c "$URL" -O AppImageAssistant
157   chmod a+x ./AppImageAssistant
158
159   # if [[ "$RECIPE" == *ecipe ]] ; then
160   #   echo "#!/bin/bash -ex" > ./$APP.AppDir/Recipe
161   #   echo "# This recipe was used to generate this AppImage." >> ./$APP.AppDir/Recipe
162   #   echo "# See http://appimage.org for more information." >> ./$APP.AppDir/Recipe
163   #   echo "" >> ./$APP.AppDir/Recipe
164   #   cat $RECIPE >> ./$APP.AppDir/Recipe
165   # fi
166   #
167   # Detect the architecture of what we are packaging.
168   # The main binary could be a script, so let's use a .so library
169   BIN=$(find . -name *.so* -type f | head -n 1)
170   INFO=$(file "$BIN")
171   if [ -z $ARCH ] ; then
172     if [[ $INFO == *"x86-64"* ]] ; then
173       ARCH=x86_64
174     elif [[ $INFO == *"i686"* ]] ; then
175       ARCH=i686
176     elif [[ $INFO == *"armv6l"* ]] ; then
177       ARCH=armhf
178     else
179       echo "Could not automatically detect the architecture."
180       echo "Please set the \$ARCH environment variable."
181      exit 1
182     fi
183   fi
184
185   mkdir -p ../out || true
186   rm ../out/$APP"-"$VERSION".glibc"$GLIBC_NEEDED"-"$ARCH".AppImage" 2>/dev/null || true
187   GLIBC_NEEDED=$(glibc_needed)
188   ./AppImageAssistant ./$APP.AppDir/ ../out/$APP"-"$VERSION".glibc"$GLIBC_NEEDED"-"$ARCH".AppImage"
189 }
190
191 # Generate AppImage type 2
192 # Additional parameters given to this routine will be passed on to appimagetool
193 #
194 # If the environment variable NO_GLIBC_VERSION is set, the required glibc version
195 # will not be added to the AppImage filename
196 generate_type2_appimage()
197 {
198   # Get the ID of the last successful build on Travis CI
199   # ID=$(wget -q https://api.travis-ci.org/repos/AppImage/appimagetool/builds -O - | head -n 1 | sed -e 's|}|\n|g' | grep '"result":0' | head -n 1 | sed -e 's|,|\n|g' | grep '"id"' | cut -d ":" -f 2)
200   # Get the transfer.sh URL from the logfile of the last successful build on Travis CI
201   # Only Travis knows why build ID and job ID don't match and why the above doesn't give both...
202   # URL=$(wget -q "https://s3.amazonaws.com/archive.travis-ci.org/jobs/$((ID+1))/log.txt" -O - | grep "https://transfer.sh/.*/appimagetool" | tail -n 1 | sed -e 's|\r||g')
203   # if [ -z "$URL" ] ; then
204   #   URL=$(wget -q "https://s3.amazonaws.com/archive.travis-ci.org/jobs/$((ID+2))/log.txt" -O - | grep "https://transfer.sh/.*/appimagetool" | tail -n 1 | sed -e 's|\r||g')
205   # fi
206   URL="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-${SYSTEM_ARCH}.AppImage"
207   wget -c "$URL" -O appimagetool
208   chmod a+x ./appimagetool
209   appimagetool=$(readlink -f appimagetool)
210
211   if [ "$DOCKER_BUILD" ]; then
212     appimagetool_tempdir=$(mktemp -d)
213     mv appimagetool "$appimagetool_tempdir"
214     pushd "$appimagetool_tempdir" &>/dev/null
215     ls -al
216     ./appimagetool --appimage-extract
217     rm appimagetool
218     appimagetool=$(readlink -f squashfs-root/AppRun)
219     popd &>/dev/null
220     _appimagetool_cleanup() { [ -d "$appimagetool_tempdir" ] && rm -r "$appimagetool_tempdir"; }
221     trap _appimagetool_cleanup EXIT
222   fi
223
224   if [ -z ${NO_GLIBC_VERSION+true} ]; then
225     GLIBC_NEEDED=$(glibc_needed)
226     VERSION_EXPANDED=$VERSION.glibc$GLIBC_NEEDED
227   else
228     VERSION_EXPANDED=$VERSION
229   fi
230
231   set +x
232   GLIBC_NEEDED=$(glibc_needed)
233   if ( [ ! -z "$KEY" ] ) && ( ! -z "$TRAVIS" ) ; then
234     wget https://github.com/AppImage/AppImageKit/files/584665/data.zip -O data.tar.gz.gpg
235     ( set +x ; echo $KEY | gpg2 --batch --passphrase-fd 0 --no-tty --skip-verify --output data.tar.gz --decrypt data.tar.gz.gpg )
236     tar xf data.tar.gz
237     sudo chown -R $USER .gnu*
238     mv $HOME/.gnu* $HOME/.gnu_old ; mv .gnu* $HOME/
239     VERSION=$VERSION_EXPANDED "$appimagetool" $@ -n -s --bintray-user $BINTRAY_USER --bintray-repo $BINTRAY_REPO -v ./$APP.AppDir/
240   else
241     VERSION=$VERSION_EXPANDED "$appimagetool" $@ -n --bintray-user $BINTRAY_USER --bintray-repo $BINTRAY_REPO -v ./$APP.AppDir/
242   fi
243   set -x
244   mkdir -p ../out/ || true
245   mv *.AppImage* ../out/
246 }
247
248 # Generate status file for use by apt-get; assuming that the recipe uses no newer
249 # ingredients than what would require more recent dependencies than what we assume
250 # to be part of the base system
251 generate_status()
252 {
253   mkdir -p ./tmp/archives/
254   mkdir -p ./tmp/lists/partial
255   touch tmp/pkgcache.bin tmp/srcpkgcache.bin
256   wget -q -c "https://github.com/AppImage/AppImages/raw/${PKG2AICOMMIT}/excludedeblist"
257   rm status 2>/dev/null || true
258   for PACKAGE in $(cat excludedeblist | cut -d "#" -f 1) ; do
259     printf "Package: $PACKAGE\nStatus: install ok installed\nArchitecture: all\nVersion: 9:999.999.999\n\n" >> status
260   done
261 }
262
263 # Find the desktop file and copy it to the AppDir
264 get_desktop()
265 {
266    find usr/share/applications -iname "*${LOWERAPP}.desktop" -exec cp {} . \; || true
267 }
268
269 fix_desktop() {
270     # fix trailing semicolons
271     for key in Actions Categories Implements Keywords MimeType NotShowIn OnlyShowIn; do
272       sed -i '/'"$key"'.*[^;]$/s/$/;/' $1
273     done
274 }
275
276 # Find the icon file and copy it to the AppDir
277 get_icon()
278 {
279   find ./usr/share/pixmaps/$LOWERAPP.png -exec cp {} . \; 2>/dev/null || true
280   find ./usr/share/icons -path *64* -name $LOWERAPP.png -exec cp {} . \; 2>/dev/null || true
281   find ./usr/share/icons -path *128* -name $LOWERAPP.png -exec cp {} . \; 2>/dev/null || true
282   find ./usr/share/icons -path *512* -name $LOWERAPP.png -exec cp {} . \; 2>/dev/null || true
283   find ./usr/share/icons -path *256* -name $LOWERAPP.png -exec cp {} . \; 2>/dev/null || true
284   ls -lh $LOWERAPP.png || true
285 }
286
287 # Find out the version
288 get_version()
289 {
290   THEDEB=$(find ../*.deb -name $LOWERAPP"_*" | head -n 1)
291   if [ -z "$THEDEB" ] ; then
292     echo "Version could not be determined from the .deb; you need to determine it manually"
293   fi
294   VERSION=$(echo $THEDEB | cut -d "~" -f 1 | cut -d "_" -f 2 | cut -d "-" -f 1 | sed -e 's|1%3a||g' | sed -e 's|.dfsg||g' )
295   echo $VERSION
296 }
297
298 # transfer.sh
299 transfer() { if [ $# -eq 0 ]; then echo "No arguments specified. Usage:\necho transfer /tmp/test.md\ncat /tmp/test.md | transfer test.md"; return 1; fi
300 tmpfile=$( mktemp -t transferXXX ); if tty -s; then basefile=$(basename "$1" | sed -e 's/[^a-zA-Z0-9._-]/-/g'); curl --progress-bar --upload-file "$1" "https://transfer.sh/$basefile" >> $tmpfile; else curl --progress-bar --upload-file "-" "https://transfer.sh/$1" >> $tmpfile ; fi; cat $tmpfile; rm -f $tmpfile; }
301
302 # Patch binary files; fill with padding if replacement is shorter than original
303 # http://everydaywithlinux.blogspot.de/2012/11/patch-strings-in-binary-files-with-sed.html
304 # Example: patch_strings_in_file foo "/usr/local/lib/foo" "/usr/lib/foo"
305 patch_strings_in_file() {
306     local FILE="$1"
307     local PATTERN="$2"
308     local REPLACEMENT="$3"
309     # Find all unique strings in FILE that contain the pattern
310     STRINGS=$(strings ${FILE} | grep ${PATTERN} | sort -u -r)
311     if [ "${STRINGS}" != "" ] ; then
312         echo "File '${FILE}' contain strings with '${PATTERN}' in them:"
313         for OLD_STRING in ${STRINGS} ; do
314             # Create the new string with a simple bash-replacement
315             NEW_STRING=${OLD_STRING//${PATTERN}/${REPLACEMENT}}
316             # Create null terminated ASCII HEX representations of the strings
317             OLD_STRING_HEX="$(echo -n ${OLD_STRING} | xxd -g 0 -u -ps -c 256)00"
318             NEW_STRING_HEX="$(echo -n ${NEW_STRING} | xxd -g 0 -u -ps -c 256)00"
319             if [ ${#NEW_STRING_HEX} -le ${#OLD_STRING_HEX} ] ; then
320                 # Pad the replacement string with null terminations so the
321                 # length matches the original string
322                 while [ ${#NEW_STRING_HEX} -lt ${#OLD_STRING_HEX} ] ; do
323                     NEW_STRING_HEX="${NEW_STRING_HEX}00"
324                 done
325                 # Now, replace every occurrence of OLD_STRING with NEW_STRING
326                 echo -n "Replacing ${OLD_STRING} with ${NEW_STRING}... "
327                 hexdump -ve '1/1 "%.2X"' ${FILE} | \
328                 sed "s/${OLD_STRING_HEX}/${NEW_STRING_HEX}/g" | \
329                 xxd -r -p > ${FILE}.tmp
330                 chmod --reference ${FILE} ${FILE}.tmp
331                 mv ${FILE}.tmp ${FILE}
332                 echo "Done!"
333             else
334                 echo "New string '${NEW_STRING}' is longer than old" \
335                      "string '${OLD_STRING}'. Skipping."
336             fi
337         done
338     fi
339 }