· 6 years ago · Mar 09, 2019, 04:04 AM
1#!/bin/bash +x
2#
3# The primary useful functions are:
4# `srpmAutoBuild_build <...>`; where `<...>` can be a (list of) spec-file(s) and/or srpm(s). This function does "most of the work", including installing build dependencies and actually building the SRPMs.
5# `srpmAutoBuild_ALL`, which scripts the entire "find new SRPMs / download them / setup + enter mock / install build dependencies / build SRPMs into RPMs" process. This allows for a single command to run everything. There are several flags to control the behavior of this function (see help text in function header)
6#
7# To use the packages in a local repository with dnf, run `localrepo_setupDNF` to setup the repo and `localrepo_updateDatabase` to update its database with new packages.
8#
9# This is basically intended as a replacement for `dnf update` but for SRPMs, where it downloads and builds SRPMs rather than downloads and installs the pre-compiled RPMs
10#
11# Lists of files can use globs, and you can mix-and-match specs and srpms. Build dependencies will automatically be installed;
12# and several common but harmless rpm build errors are automatically dealt with, resulting in a very high build success rate
13# (though this comes at the cost of needlessly re-trying to build some packages that need manual attention prior to being built - packages will be
14# built up to 4 times with various tweaks applied, and will always follow the same workflow regardless of what the cause of the error was).
15#
16# These functions are designed to work with mock, but should (mostly) work in a standard OS environment too.. However, to accommodate the `mock` environment
17# (which doesnt necessarily have `sudo`) you will need to be root to successfully run many of these functions. They wont call `sudo` on their own, however, most will check whether you are root or not and prompt you to re-call the command as root automatically (this fetches the last command recorded in the history and re-calls it using `su`)
18#
19# Building in a mock environment is recommended. To do this, use `srpmAutoBuild_mock-chroot`./ This will run the commands given to it (non-interactively) in mock, --OR-- if no inputs are used it will drop you into an (interactive) mock chroot shell.
20#
21#
22# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
23# # # # # # # # # # # # # # # # # # # # # # # # # # # ----- EXAMPLE USAGE ----- # # # # # # # # # # # # # # # # # # # # # # # # # # #
24# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
25#
26# -----> EASY MODE:
27#
28# `srpmAutoBuild_ALL`: this *should* do literally everything related to downloading/building SRPMs for you automatically (assuming you want to rebuild EVERY rpm that you have currently installed and that has an available SRPM). several flags are available (run `srpmAutoBuild_help srpmAutoBuild_ALL` for more info)
29#
30# To use the rpms you built in a local repository with dnf, run `localrepo_setupDNF` to setup the repository and then run `localrepo_updateDatabase` to update whenever you have built new RPMs. To automatically install the just built rpms and update the repository, add '+r' to the end off one of the install flags (e.g., `srpmAutoBuild_ALL -i+r`)
31#
32# To fully automate all aspects of downloading SRPMs, installing dependencies, building them, and cleanup.
33# This is intended to be a function that is roughly equivalent to `dnf upgrade`, except it downloads and builds SRPMs rather than download and install pre-compiled RPMs
34#
35#
36# -----> MORE DETAIL:
37#
38# `srpmAutoBuild_ALL` more-or-less automates the following workflow. Actual commands are shown below.
39#
40# # (1) source srpmAutoBuild.sh,
41# # (2) Get RPM / MOCK dir paths
42# # (3) initialize mock;
43# # (4) download [all available] SRPMs into Mock,
44# # (5) enter mock chroot,
45# # (6) setup environment variables from inside of mock;
46# # (7) download / install all build dependencies for the SRPMs and build the SRPM packages (first into SPEC-files, then into RPMs),
47# # (7a) OPTIONAL: repeat (5-7) and start a 2nd build run that processes packages in the opposite order (use -r Flag with srpmAutoBuild_build )
48# # (8) exit the mock chroot, and
49# # (9) transfer all packages built in the mock chroot to ${LOCALREPO_DIR} and cleanup the mock environment.
50#
51#
52# ---------------------------------------------- PREP - SETUP MOCK AND GET SRPMS ----------------------------------------------
53#
54# source /usr/local/bin/my-scripts/srpmAutoBuild.sh # Source srpmAutoBuild package
55# srpmAutoBuild_mock-init # clean + [re]initialize + setup the mock environment
56# srpmAutoBuild_mock-downloadSRPMs # download SRPMs into Mock for all potential build able SRPMSs automatically
57# cd ${RPM_BUILD_DIR%/}/SRPMS && dnf download --source <...> # ALT: download only select SRPMS
58#
59#
60# ---------------------------------------------- BUILD - RUN COMMANDS INSIDE OF MOCK ----------------------------------------------
61#
62# srpmAutoBuild_mock-chroot # enter mock chroot.
63# srpmAutoBuild_rpmAutoBuild_build ${RPM_BUILD_DIR%/}/SRPMS/* [&] # build SRPMs and/or SPECs. This function does most of the work. Fork this if you also want to run the 2nd build from the same terminal.
64# srpmAutoBuild_rpmAutoBuild_build --REVERSE ${RPM_BUILD_DIR%/}/SRPMS/* [&] # OPTIONAL: 2nd build run going in reverse order
65# exit
66#
67# ----- OR -----
68#
69# srpmAutoBuild_generateBuildScripts # generates 2 script files to automate the build process: [${MOCK_ROOT_DIR}]/build-[main|secondary].sh.
70# srpmAutoBuild_mock-chroot # enter mock chroot.
71# /build-main.sh [&] # this basically does the same thing that the commands above do
72# /build-secondary.sh [&] # OPTIONAL: 2nd build run going in reverse order
73# exit
74#
75# ----- OR -----
76#
77# srpmAutoBuild_generateBuildScripts # generates 2 script files to automate the build process: [${MOCK_ROOT_DIR}]/build-[main|secondary].sh.
78# srpmAutoBuild_mock-chroot '/build-main.sh' [&] # runs /build-main.sh in mock non-interactively from a shell OUTSIDE of mock
79# srpmAutoBuild_mock-chroot '/build-secondary.sh' [&] # runs /build-secondary.sh in mock non-interactively from a shell OUTSIDE of mock
80#
81#
82# ---------------------------------------------- CLEAN - CLEANUP MOCK AND INSTALL BUILD RPMS----------------------------------------------
83#
84# dnf localinstall ${RPM_BUILD_DIR%/}/RPMS/*.rpm # optional - install packages. This will get ALL packages that were built, including debuginfo/debugsoure packages, so you may want to be more selective
85# mock-clean # transfer built RPMs (and SRPMs sources) into ${LOCALREPO_DIR} and cleanup mock
86# localrepo_updateDatabase # optional, if using ${LOCALREPO_DIR} as an actual dnf repository this will update it with the newly built packages
87# dnf upgrade --disablerepo=[a-z]* --enablerepo=localrepo-built # install upgrade using only the [newly/previously] built packages. This is probably better then using dnf localinstall in most cases
88#
89#
90# ---------------------------------------------- MISC NOTES ----------------------------------------------
91#
92# Notes regarding `srpmAutoBuild_mock-chroot[0]`:
93# running `srpmAutoBuild_mock-chroot[0]` without any function inputs gives you an interactive chroot shell inside of mock
94# running `srpmAutoBuild_mock-chroot[0]` with function inputs will run the input(s) as commands (non-interactively, using chroot) inside of mock
95# `srpmAutoBuild_mock-chroot` and `srpmAutoBuild_mock-chroot0` do the same thing, except `srpmAutoBuild_mock-chroot` automatically mounts/binds ${LOCALREPO_DIR} into mock before the command is run and and then unmounts ${LOCALREPO_DIR} in mock after the command has finished
96# `srpmAutoBuild_mock-chroot` and `srpmAutoBuild_mock-chroot0` both automatically source the srpmAutoBuild functions and setup environment variables
97#
98# run `srpmAutoBuild_checkBuildStatus` (from another non-SRPM-building terminal) to check the current build progress and build stats
99#
100# run `srpmAutoBuild_help [functionName]` to see help text for (most) srpmAutoBuild functions. Globs are accepted.
101#
102# Recommendation: customize the FLAGS in srpmAutoBuild_setEnvVars based on your hardware before using these functions for building anything.
103#
104# NOTE: IT IS NOT RECOMMENDED TO USE THESE CODES IF ANY OF THE SPEC / SRPM FILES CONTAIN SPACE CHARACTERS ANYWHERE IN THEIR PATH. It *should* still work, but A LOT of the code assumes everything is space-separated so this is asking for trouble.
105#
106# Note: if you see a build error related to major/minor/makedev on some c source file, you can fix it using `srpmAutoBuild_fixSpecFile_majorMinorMakedevError <specFilePath> <c-source code file path>`. This fix isnt automatically implemented, but running that command and then re-running `srpmAutoBuild_build <specFilePath>` on the file will (probably) build it correctly.
107#
108# NOTE: to make using these easier, run `srpmAutoBuild_makeAliases`. This will alias the functions and change the leading "srpmAutoBuild_" to "sab_" and the leading "localrepo_" to "lr_" (can also use user defined replacements)
109#
110# One item missing from these functions is automated gpg signing of the built RPM packages. Its on the to-do list, just havent gotten around to it yet.
111
112
113# # # # # # # # # # # # # # # # # # # # # # START OF FUNCTIONS # # # # # # # # # # # # # # # # # # # # # #
114
115# # # # # # # # # # # # # # # # MAIN FUNCTION FOR FULLY AUTOMATED UPDATING # # # # # # # # # # # # # # # #
116
117alias srpmAutoBuild_myALL='srpmAutoBuild_ALL -p -nc -sf -iu'
118
119srpmAutoBuild_ALL() {
120 # This function will run the entire process automated, starting with initializing the mock environment and ending with cleaning up the mock environment after all packages have been built.
121 #
122 # -------------------------- FLAGS --------------------------
123 #
124 # use flag '-ni' or '--no-init' to re-use the existing mock environment. The relevant script files will still be re-copied into mock, in case they are missing or have been modified/updated. If the mock root dir is empty then mock-init will still be called
125 #
126 # use flag '-nc' or '--no-clean' to skip running srpmAutoBuild_mock-clean after building and leave the mock environment intact
127 #
128 # use flag '-nd' or '--no-down' or '--no-download' to skip running srpmAutoBuild_mock-downloadSRPMs
129 # use flag '-da' or '--down-all' or '--download-all' to force downloading of ALL SRPMS of unbuilt and potentially upgradeable packages. srpmAutoBuild will try to avoid downloading srpms if it knows it cant build them
130 #
131 # use flag '-f' or '--force' to pass the --force flag to srpmAutoBuild_build. This causes it to build SRPMS (if it can) even if it thinks they have already been built.
132 # use flag '-na' or '--no-auto-match' to Flag to srpmAutoBuild_build to only accept exact filename matches. By default it tries to match files that are close (and likely what was intended) but not quite an exact match.
133 #
134 # use flag '-i0' or '-in' or '--no-install' to automatically not install them. Default behavior is to ask, and then if no response to not install anything.
135 # use flag '-i' or '--install' to use the default install flag hard-coded into the function
136 # use flag '-i1' or '-iu' or '--install-update' to automatically add packages to the local repo and then run `dnf update` with only 'localrepo-built' enabled./ Implies '+r' and requires that 'localrepo' (specifically, localrepo-built') is already setup as an actual dnf repository (manually run `localrepo_setupDNF` to set this up, if needed)
137 # use flag '-i2' or '-is' or '--install-standard[-only]' to automatically install packages after they are done building. This will install the main rpms, but not the debug rpms
138 # use flag '-i3' or '-id' --install-debug[-only]' to automatically install all the debug packages but none of the standard rpms packages after they are done building.
139 # use flag '-i4' or '-ia' or '--install-all' to automatically install all packages after they are done building. This includes the debug rpms
140 # add '+r' to end of install flag (e.g., -is+r') to also update the local repo with newly built packages
141 #
142 # use flag '-p' or '--parallel' to force using a 2nd build run
143 # use flag '-np' or '--no-parallel' to force using only 1 build run
144 # Note: default is to ask for user response with timeout, then (if no response) use 2 threads for systems with 8+ cores and 16+ gigs of ram and 'konsole' installed. Note: This is setup assuming you are using / have installed 'konsole'. It will need to be modified for other terminals.
145 #
146 # NOTE: any other inputs will be passed to srpmAutoBuild_build
147 #
148 # NOTE: FLAGS are NOT case sensitive. Actual flags accepted are slightly more general than described above. e.g., most allow for any number of leading dashes (so long as there is at least 1), and dont require the inter-word dashes. See the regex-based filters used to ID flags in the code for more info.
149 #
150 # Side note: personally, I often use something like `srpmAutoBuild_ALL -sf -p -i+r -nc`
151
152 local useParallelBuild=""
153 local parallelBuildUserResponse=""
154 local isolateKernelBuildUserResponse=""
155 local newlyBuiltRpmList=""
156 local rpmBuildFLAGS=""
157 local noInitFlag=0
158 local noDownloadFlag=0
159 local noCleanFlag=0
160 local forceFlag=0
161 local noAutoMatchFlag=0
162 local updateRepoFlag=0
163 local flagMatchCur=0
164 local installFlag=""
165 local flagCheckFlag=0
166 local isolateKernelBuildFlag
167 local userInstallFlag
168 local inAll=("${@}")
169
170 # OPTIONAL - set default install flag
171 local defaultInstallFlag="1"
172
173 # setup RPM_BUILD_DIR and MOCK_ROOT_DIR
174 srpmAutoBuild_rootUserCheck
175 srpmAutoBuild_mockSetupCheck
176 srpmAutoBuild_setRpmBuildDir -c
177 srpmAutoBuild_setEnvVars
178
179 echo -e "Beginning initial setup. This includes (unless disabled via flags): \n----> cleaning up an existing mock, if it exists \n----> (re)initializing mock \n----> setting up mock (e.g., copying files into mock and making build run scripts) \n----> downloading source SRPMs to build inside of the mock chroot environment"
180
181 # extract FLAGS
182
183 echo -e "\n\n${#inAll[@]} Inputs detected. Checking inputs for flags... \n"
184
185 #[[ "${inAll[*]}" =~ ^(.+ )?-+i([0-4]|((nstall)?(-?((u(pdate)?)|(a(ll)?)|(s(tandard(-?only)?))|(d(ebug(-?only)?))))?)?)( .+)? ]] || [[ -z "${defaultInstallFlag}" ]] && inAll[${#inAll[@]}]="-i${defaultInstallFlag#*-i}"
186
187 #while (( $# > 0 )); do
188 for nn in {"${inAll[@]}",''}; do
189
190 [[ -z "${nn}" ]] && [[ -z "${installFlag}" ]] && [[ -n "${defaultInstallFlag}" ]] && nn='-i' && flagMatchCur=9 || [[ -z "${nn}" ]] && flagMatchCur=8 || flagMatchCur=0
191
192 [[ -n "${nn}" ]] && echo "Checking input ${nn}" >&2
193
194 # run init function, unless --no-init Flag set, then run copyFilesIntoMock function
195 (( $flagMatchCur == 0 )) && [[ ${nn,,} =~ ^-+no?-?i(nit)?$ ]] && flagMatchCur=1 && echo "'noInit' flag enabled - mock will not be scrubbed+cleaned+reinitialized if it already exists" >&2 && ((noInitFlag++))
196
197 # download unbuilt / upgradeable srpms unless --no-download Flag given
198 (( $flagMatchCur == 0 )) && [[ ${nn,,} =~ ^-+no?-?d(own(load)?)?$ ]] && flagMatchCur=1 && echo "'noDownload' flag enabled - new SRPMs will not automatically be downloaded" >&2 && ((noDownloadFlag++))
199
200 # clean mock chroot after building, unless --no-clean Flag set, then leave it as it is
201 (( $flagMatchCur == 0 )) && [[ ${nn,,} =~ ^-+no?-?c(lean)?$ ]] && flagMatchCur=1 && echo "'noClean' flag enabled - the mock environment will be left as-is when building is completed" >&2 && ((noCleanFlag++))
202
203 # dont re-build already-built RPMS unless --force Flag is set (flag is for srppmAutpBuild_build)
204 (( $flagMatchCur == 0 )) && [[ ${nn,,} =~ ^-+f(orce)?$ ]] && flagMatchCur=1 && echo "'force' flag enabled - the '--force' flag will be passed to 'srpmAutoBuild_build' to force re-building already-built RPMs" >&2 && ((forceFlag++))
205
206 # try to find matching SRPMs / SPECs for incomplete filename inputs unless '--no-auto-match' Flag is set (flag is for srppmAutpBuild_build)
207 (( $flagMatchCur == 0 )) && [[ ${nn,,} =~ ^-+n(a|o?-?auto(-?match)?)$ ]] && flagMatchCur=1 && echo "'noAuto' flag enabled - the '--no-auto-match' flag will be passed to 'srpmAutoBuild_build' to prevent it from trying to match inputs that are not valid file paths to SRPMs/SPECs present on the system" >&2 && ((noAutoMatchFlag++))
208
209 # flag to install packages that were just built (or not install them). Default behavior is to ask, then if no response to not install
210 ( ( (( $flagMatchCur == 0 )) && [[ ${nn,,} =~ ^-+i(nstall)?(\+r)?$ ]] ) || ( (( $flagMatchCur == 9 )) && ( [[ ${nn,,} =~ ^-+i(nstall)?(\+r)?$ ]] || [[ -z "${nn}" ]] ) ) ) && [[ -n "${defaultInstallFlag}" ]] && nn="-i${defaultInstallFlag#*-i}$([[ ${nn} == *'+r' ]] && [[ ! "${defaultInstallFlag}" == *'+r' ]] && echo -n '+r' || echo -n '')" && echo "Input '-i' re-evaluated to '${nn}'" >&2
211 ( (( $flagMatchCur == 0 )) || (( $flagMatchCur == 9 )) ) && [[ ${nn,,} =~ ^-+i(0|((nstall)?-?n(one)?))$ ]] && installFlag=0 && flagMatchCur=$(( $flagMatchCur + 2 )) && echo "'install' flag set to level 0 - built RPM packages wont be installed" >&2
212 ( (( $flagMatchCur == 0 )) || (( $flagMatchCur == 9 )) ) && [[ ${nn,,} =~ ^-+i(1|((nstall)?-?u(pdate)?))(\+r)?$ ]] && installFlag=1 && updateRepoFlag=1 && flagMatchCur=$(( $flagMatchCur + 2 )) && echo "'install' flag set to level 1 - built packages will be added to the local repo, and 'dnf upgrade' will be run with only 'localrepo-built' enabled (this automatically sets the '+r' update repository flag)" >&2
213 ( (( $flagMatchCur == 0 )) || (( $flagMatchCur == 9 )) ) && [[ ${nn,,} =~ ^-+i(2|((nstall)?-?s(tandard(-?only)?)?))(\+r)?$ ]] && installFlag=2 && flagMatchCur=$(( $flagMatchCur + 2 )) && echo "'install' flag set to level 2 - all newly built standard RPM packages will be installed, but built debuginfo RPM packages wont be installed" >&2
214 ( (( $flagMatchCur == 0 )) || (( $flagMatchCur == 9 )) ) && [[ ${nn,,} =~ ^-+i(3|((nstall)?-?d(ebug(-?only)?)?))(\+r)?$ ]] && installFlag=3 && flagMatchCur=$(( $flagMatchCur + 2 )) && echo "'install' flag set to level 3 - all newly built debuginfo RPM packages will be installed, but built standard RPM packages wont be installed" >&2
215 ( (( $flagMatchCur == 0 )) || (( $flagMatchCur == 9 )) ) && [[ ${nn,,} =~ ^-+i(4|((nstall)?-?a(ll)?))(\+r)?$ ]] && installFlag=4 && flagMatchCur=$(( $flagMatchCur + 2 )) && echo "'install' flag set to level 4 - all newly built RPM packages (standard + debuginfo) will be installed"
216 ( (( $flagMatchCur == 2 )) || (( $flagMatchCur == 11 )) ) && [[ ${nn,,} =~ ^-+i.*\+r$ ]] && updateRepoFlag=1 && echo "'updateRepo' flag enabled - in addition to [some|all] packages being installed, the local repository 'localrepo' will be automatically updated as well" >&2
217 (( $flagMatchCur == 2 )) && flagMatchCur=1
218
219 # flag to force 1 or 2 build processes
220 (( $flagMatchCur == 0 )) && [[ ${nn,,} =~ ^-+p(arallel)?$ ]] && parallelBuildUserResponse=yes && flagMatchCur=1 && echo "'parallelBuild' flag enabled - a 2nd parallel build run will automatically be launched at the appropriate time to build SRPMs faster" >&2
221 (( $flagMatchCur == 0 )) && [[ ${nn,,} =~ ^-+no?-?p(arallel)?$ ]] && parallelBuildUserResponse=no && flagMatchCur=1 && echo "'parallelBuild' flag disabled - only a single build run will be used to build SRPMs" >&2
222
223 # flag to ask for confirmation of flags before continuing
224 (( $flagMatchCur == 0 )) && [[ ${nn,,} =~ ^-+((s(how)?)|(c(check)?))-?f(lags)?$ ]] && flagCheckFlag=1 && flagMatchCur=1 && echo "'flagCheck' flag enabled - flags will be displayed and you will be prompted for confirmation prior to running this functions main contents" >&2
225
226 # If no matching FLAGS then add it to $rpmBuildFLAGS --> it will be passed to srpmAutoBuild_build
227 (( $flagMatchCur == 0 )) && rpmBuildFLAGS="$(echo "${rpmBuildFLAGS}" "${1}")" && echo "${1} was not recognized as as explicitly defined flag...It will be passed to the setup functions called by this program for them to parse (if able)" >&2
228
229 (( $flagMatchCur < 5 )) && shift 1
230 echo ""
231
232 done
233
234 # get FLAGS from srpmAutoBuild_build to pass to srpmAutoBuild_generateBuildScripts and setup string of full command
235
236 (( $forceFlag > 0 )) && rpmBuildFLAGS="--force ${rpmBuildFLAGS}"
237 (( $noAutoMatchFlag > 0 )) && rpmBuildFLAGS="--no-auto-match ${rpmBuildFLAGS} "
238 rpmBuildFLAGS="${rpmBuildFLAGS## }"
239 rpmBuildFLAGS="${rpmBuildFLAGS%% }"
240
241 if (( $flagCheckFlag > 0 )); then
242 # list flags
243 echo -e "\nThe following flags have been set: \n" >&2
244 echo -e "\trpmBuildFLAGS = ${rpmBuildFLAGS}" >&2
245 echo -e "\tnoInitFlag = ${noInitFlag}" >&2
246 echo -e "\tnoDownloadFlag = ${noDownloadFlag}" >&2
247 echo -e "\tnoCleanFlag = ${noCleanFlag}" >&2
248 echo -e "\tupdateRepoFlag = ${updateRepoFlag}" >&2
249 echo -e "\tinstallFlag = ${installFlag}" >&2
250 echo -e "\tuseParallelBuildRuns = ${parallelBuildUserResponse}" >&2
251 echo -e "\n\nDo these look correct? A response of '' (<NULL>), 'y', or 'yes' will continue the program. Any other non-null response will exit the program. Timeout is 20 seconds." >&2
252
253 local tempVar=""
254 read -e -p "Response: " -t 20 tempVar
255
256 [[ -n "${tempVar}" ]] && [[ ! ${tempVar,,} =~ ^y(es)?$ ]] && exit
257 fi
258
259 #if (( $noInitFlag > 0 )); then
260 # srpmAutoBuild_copyFilesIntoMock
261 # srpmAutoBuild_generateBuildScripts "${rpmBuildFLAGS}"
262 #else
263 # [[ -n "${rpmBuildFLAGS}" ]] && srpmAutoBuild_mock-init "${rpmBuildFLAGS}" || srpmAutoBuild_mock-init
264 #fi
265
266 srpmAutoBuild_mock-init $(echo "$( (( $noInitFlag > 0 )) && echo '--no-clean' || echo "") ${rpmBuildFLAGS}" | sed -E s/' +'/' '/g | sed -E s/'^ $'//)
267
268 # download not-yet-built SRPMs into the Mock
269 (( $noDownloadFlag == 0 )) && srpmAutoBuild_mock-downloadSRPMs --enable-repos
270
271 # bind '${LOCALREPO_DIR}' into the mock environment
272 srpmAutoBuild_mock-bind-localrepo
273
274 # setup dnf cache in mock
275 echo -e "\nThe code will now attempt to generate the dnf cache in the mock environment... \nNote: you will not see the typical DNF text output during this command. \n" >&2
276 srpmAutoBuild_mock-makecache
277
278 # call setup and build commands in a non-interactive chroot shell
279 # If the machine has 8+ cores and 16+ gigs of memory, default is to run 2 build processes at once.
280
281 if [[ -n "${parallelBuildUserResponse}" ]] && [[ ! ${parallelBuildUserResponse,,} =~ ^((y(es)?)|(no?))$ ]]; then
282 # get user response for whether to use 2 parallel build runs
283
284 (( $(nproc) >= 8 )) && (( $(srpmAutoBuild_getTotalMem) >= ( 2 ** 24 ) )) && [[ -n $(rpm -qa | grep -E '^konsole') ]] && useParallelBuild=YES || useParallelBuild=NO
285
286 echo -e "\n\nWould you like to use 2 parallel build processes?? \n\nThe default based on CPU and memory and software availability is: ${useParallelBuild} \n\nWARNING: Spawning the parallel build run uses 'konsole'. If konsole is not installed and parallel builds are enabled then both build runs will fail. \n\nNote: Timeout is 20 seconds. After 20 seconds the default option will be chosen automatically. \n" >&2
287
288 read -ie -p "Enter y[es] or n[o]: " -t 20 parallelBuildUserResponse
289 fi
290
291 [[ ${parallelBuildUserResponse,,} =~ ^(y(es)?|no?)$ ]] && useParallelBuild="${parallelBuildUserResponse,,}"
292
293 if [[ -n "$(find "${RPM_BUILD_DIR%/}/SRPMS" -maxdepth 1 -type f -regex "^.*\/kernel-[0-9]+\.[0-9]+\.[0-9]+-[0-9]+\.[^\.]+\.src\.rpm$")" ]]; then
294 # new kernel SRPM detected
295
296 echo -e "\nNOTICE: a new kernel SRPM has been detected! \nWould you like to isolate building this kernel?\n\ny[es] --> (DEFAULT) Build the kernel in a newly initiated mock chroot after everything else has finished building. Selecting 'yes' will spawn a 2nd prompt asking you if youd like to install it. \n\nn[o] ---> treat the new kernel like all the other SRPM packages. It will be built with and use the same install options as all the other SRPMS. \n\nNote: Timeout is 20 seconds. After 20 seconds the default option will be chosen automatically. \n" >&2
297
298 read -ie -p "Enter y[es] or n[o]: " -t 20 isolateKernelBuildUserResponse
299
300 [[ ${isolateKernelBuildUserResponse,,} =~ ^no?$ ]] && isolateKernelBuildFlag=0 || isolateKernelBuildFlag=1
301
302 if (( $isolateKernelBuildFlag == 1)) && (( $noCleanFlag == 1)); then
303
304 echo -e "\nWARNING: \nIsolating the kernel build requires cleaning the mock chroot, and the '--no-clean' flag is currently set. \nIsolating the kernel build will leave the final post-kernel-build chroot intact, but the initial chroot \n(where all the non-kernel packages were built) will be cleaned+scrubbed to prepare for the isolated kernel build.\n\nDo you still want to isolate the new kernel build? \n\ny[es] --> (DEFAULT) Isolate the new kernel build and clean the intermediate chroot before the isolated kernel build \n\nn[o] ---> enforce the '--no-clean' flag and dont isolate the new kernel build. This will treat the new kernel like all the other SRPM packages. It will be built with and use the same install options as all the other SRPMS. \n\nNote: Timeout is 20 seconds. After 20 seconds the default option will be chosen automatically. \n" >&2
305
306 isolateKernelBuildUserResponse=""
307 read -ie -p "Enter y[es] or n[o]: " -t 20 isolateKernelBuildUserResponse
308
309 [[ ${isolateKernelBuildUserResponse,,} =~ ^no?$ ]] && isolateKernelBuildFlag=0 || isolateKernelBuildFlag=1
310 fi
311
312 if (( $isolateKernelBuildFlag == 1)); then
313
314 [[ -d ${LOCALREPO_DIR%/}/.MISC/kernel-temp ]] && chmod -R 777 ${LOCALREPO_DIR%/}/.MISC/kernel-temp || mkdir --parents ${LOCALREPO_DIR%/}/.MISC/kernel-temp
315 chmod 777 $(find "${RPM_BUILD_DIR%/}/SRPMS" -maxdepth 1 -type f -regex "^.*\/kernel-((headers-)|(tools-))?[0-9]+\.[0-9]+\.[0-9]+-[0-9]+\.[^\.]+\.src\.rpm$") && \mv -f $(find "${RPM_BUILD_DIR%/}/SRPMS" -maxdepth 1 -type f -regex "^.*\/kernel-((headers-)|(tools-))?[0-9]+\.[0-9]+\.[0-9]+-[0-9]+\.[^\.]+\.src\.rpm$") ${LOCALREPO_DIR%/}/.MISC/kernel-temp
316
317 echo -e "\nThe kernel build will be isolated.\n\nWould you also like to install the kernel, or just build the kernel RPMs? \n\ny[es] --> build the new kernel and install the standard rpm's for the new \n\nyes+debug --> build the new kernel and install the standard and debuginfo rpm's for the new kernel \n\nn[o] ---> (DEFAULT) build the new kernel but do not install the RPMs automatically \n\nNote: Timeout is 20 seconds. After 20 seconds the default option will be chosen automatically. \n" >&2
318
319 isolateKernelBuildUserResponse=""
320 read -ie -p "Enter y[es] or yes+debug or n[o]: " -t 20 isolateKernelBuildUserResponse
321
322 [[ "${isolateKernelBuildUserResponse,,}" == "yes+debug" ]] && isolateKernelBuildFlag=3
323 [[ ${isolateKernelBuildUserResponse,,} =~ ^y(es)?$ ]] && isolateKernelBuildFlag=2
324
325 fi
326
327 else
328 # no new kernel SRPM was found
329
330 isolateKernelBuildFlag=0
331 fi
332
333 # clear on-disk build stat files
334 for nn in {BUILD_LIST_1,BUILT_LIST_2,STATUS_1,STATUS_2,STATS_OVERALL,SECONDARY_BUILD.lock}; do
335 [[ -f "${RPM_BUILD_DIR%/}/.${nn}" ]] && chmod 777 "${RPM_BUILD_DIR%/}/.${nn}" && \rm -f "${RPM_BUILD_DIR%/}/.${nn}"
336 done
337
338 if [[ ${useParallelBuild,,} =~ ^y(es)?$ ]]; then
339 # use 2 build processes
340
341 # launch secondary build run forked. It will automatically wait for the main build run before starting
342
343 XDG_RUNTIME_DIR="/tmp/runtime-${USER}" && export XDG_RUNTIME_DIR
344 [[ -d "${XDG_RUNTIME_DIR}" ]] || mkdir --parents "${XDG_RUNTIME_DIR}"
345 chmod 0700 "${XDG_RUNTIME_DIR}"
346
347 #chmod 777 "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" && \rm -f "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" && touch "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock"
348
349 # make sure we can access directories
350 chmod 777 "${RPM_BUILD_DIR}"
351 chmod 777 ${RPM_BUILD_DIR%/}/*
352 #[[ -f "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" ]] && chmod 777 "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" || touch "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" && chmod 777 "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock"
353
354 chmod 777 "${MOCK_ROOT_DIR}"
355 chmod 777 ${MOCK_ROOT_DIR%/}/*
356 chmod 777 ${MOCK_ROOT_DIR%/}/builddir/*
357
358 ( [[ -f "${MOCK_ROOT_DIR%/}/build-main.sh" ]] && [[ -f "${MOCK_ROOT_DIR%/}/build-secondary.sh" ]] ) || srpmAutoBuild_generateBuildScripts
359 chmod 777 "${MOCK_ROOT_DIR%/}/build-main.sh" "${MOCK_ROOT_DIR%/}/build-secondary.sh"
360
361 # launch forked processes for main and secondary builds
362
363 echo "NOW LAUNCHING FORKED BUILD RUN PROCESSES. 2 NEW KONSOLE TERMINALS SHOULD APPEAR." >&2
364 sleep 2
365
366 #su -l -c "konsole --separate -e \"su -l -c \\\"source \\\\\\\"/usr/local/bin/my-scripts/srpmAutoBuild.sh\\\\\\\" && /bin/bash -c \\\\\\\"source /usr/local/bin/my-scripts/srpmAutoBuild.sh && ( while [[ \\\\\\\\\\\\\\\"x\$(srpmAutoBuild_mock-chroot0 \\\\\\\\\\\\\\\"echo\\\\\\\\\\\\\\\" 1>/dev/null 2>&1)\\\\\\\\\\\\\\\" != \\\\\\\\\\\\\\\"x\\\\\\\\\\\\\\\" ]]; do sleep 1; done ) && srpmAutoBuild_mock-chroot0 \\\\\\\\\\\\\\\"/build-main.sh\\\\\\\\\\\\\\\"\\\\\\\"\\\"\"" &
367
368 # run main build run in current session
369 #su -l -c "konsole --separate -e \"su -l -c \\\"source \\\\\\\"/usr/local/bin/my-scripts/srpmAutoBuild.sh\\\\\\\" && /bin/bash -c \\\\\\\"source /usr/local/bin/my-scripts/srpmAutoBuild.sh && sleep 10 && ( while [[ \\\\\\\\\\\\\\\"x\$(srpmAutoBuild_mock-chroot0 \\\\\\\\\\\\\\\"echo\\\\\\\\\\\\\\\" 1>/dev/null 2>&1)\\\\\\\\\\\\\\\" != \\\\\\\\\\\\\\\"x\\\\\\\\\\\\\\\" ]]; do sleep 1; done ) && srpmAutoBuild_mock-chroot0 \\\\\\\\\\\\\\\"/build-secondary.sh\\\\\\\\\\\\\\\"\\\\\\\"\\\"\"" &
370
371 su -l -c "konsole --separate -e \"su -p --session-command \\\"source \\\\\\\"/usr/local/bin/my-scripts/srpmAutoBuild.sh\\\\\\\" && sleep 1 && ( while [[ \\\\\\\"x\$(srpmAutoBuild_mock-chroot0 \\\\\\\"echo\\\\\\\" 1>/dev/null 2>&1)\\\\\\\" != \\\\\\\"x\\\\\\\" ]]; do sleep 1; done ) && srpmAutoBuild_mock-chroot0 \\\\\\\"/build-main.sh\\\\\\\"\\\"\"" &
372
373 # run main build run in current session
374 su -l -c "konsole --separate -e \"su -p --session-command \\\"source \\\\\\\"/usr/local/bin/my-scripts/srpmAutoBuild.sh\\\\\\\" && sleep 10 && ( while [[ \\\\\\\"x\$(srpmAutoBuild_mock-chroot0 \\\\\\\"echo\\\\\\\" 1>/dev/null 2>&1)\\\\\\\" != \\\\\\\"x\\\\\\\" ]]; do sleep 1; done ) && srpmAutoBuild_mock-chroot0 \\\\\\\"/build-secondary.sh\\\\\\\"\\\"\"" &
375
376 #srpmAutoBuild_mock-chroot0 '/build-main.sh' &
377 #srpmAutoBuild_mock-chroot0 '/build-main.sh' &
378
379 # wait for everything to finish
380 wait
381
382 else
383 # use 1 build process
384 [[ -f "${MOCK_ROOT_DIR%/}/build-main.sh" ]] || srpmAutoBuild_generateBuildScripts
385 chmod 777 "${MOCK_ROOT_DIR%/}/build-main.sh"
386
387 srpmAutoBuild_mock-chroot0 '/build-main.sh'
388
389 fi
390
391 # install packages. Ask for user response on if / which rpms to install if this wasnt given as a function input
392
393 [[ -z ${installFlag} ]] && echo -e "\n\nWould you like to install the RPM';'s that just finished building? \n(you have 10 seconds to make a selection - enter a number between 0-3)\n\n0: (DEFAULT) dont install anything \n1: (DEFAULT w/ active localrepo) update localrepo-built with the built RPMs using 'loicalrewpo_updateDatabase' and update packages using 'dnf update' with only the localrepo-built repo enabled \n2: install all standard rpms, but not debug rpms \n3: install all debug rpms, but not standard rpms \n4: install ALL rpms\n\nIf installing, add 0 to the response (making it one of {10,20,30,40}) to also update the local repo with the installed packages using \"localrepo_updateDatabase \n\nNote for response '1': updating the local repo is implied, but response '10' is also accepted. If localrepo[-built] doesnt exist, it will be created automatically.)\" \n\nNote: Timeout is 20 seconds. After 20 seconds the default option will be chosen automatically. \n" >&2 && read -ie -p "Your selection: " -t 20 userInstallFlag
394
395 [[ ${userInstallFlag} =~ ^[0-4]$ ]] && installFlag=${userInstallFlag}
396 [[ ${userInstallFlag} =~ ^((10)|(20)|(30)|(40))$ ]] && installFlag=$(( $userInstallFlag / 10 )) && updateRepoFlag=1
397
398 (( $installFlag == 1 )) && updateRepoFlag=1 && ( [[ -z "$(dnf repolist | grep 'localrepo-built')" ]] && localrepo_setupDNF )
399
400 if [[ -z ${installFlag} ]]; then
401 [[ -z "$(dnf repolist | grep 'localrepo-built')" ]] && installFlag=0 || installFlag=1
402 fi
403
404 # update localrepo if requested. This will copy packages, not move them, so they will still be in mock
405 (( $updateRepoFlag > 0 )) && localrepo_updateDatabase
406
407 if (( $installFlag > 1 )); then
408
409 newlyBuiltRpmList=""
410 newlyBuiltRpmList="$(find ${RPM_BUILD_DIR%/}/RPMS -type f -name "*.rpm")"
411
412 (( $installFlag == 2 )) && newlyBuiltRpmList="$(echo "${newlyBuiltRpmList}" | grep -v -E 'debug(info|source)')"
413 (( $installFlag == 3 )) && newlyBuiltRpmList="$(echo "${newlyBuiltRpmList}" | grep -E 'debug(info|source)')"
414
415 [[ -n "${newlyBuiltRpmList}" ]] && dnf -y localinstall ${newlyBuiltRpmList}
416
417 elif (( $installFlag == 1 )); then
418
419 dnf -y reinstall $(srpmAutoBuild_listDownloadRPMs ${RPM_BUILD_DIR%/}/RPMS)
420 dnf -y upgrade $(srpmAutoBuild_listDownloadRPMs ${RPM_BUILD_DIR%/}/RPMS)
421
422 localrepo_dnf --built --allowerasing -y upgrade
423
424 #dnf --refresh --skip-broken --allowerasing --disablerepo=[a-zA-Z0-9]* --enablerepo=localrepo-built -y update
425
426 fi
427
428 # build the new kernel now, if there is a new one and the user selected to isolate the build
429 if (( $isolateKernelBuildFlag > 0 )); then
430
431 srpmAutoBuild_mock-clean
432 srpmAutoBuild_mock-init
433 srpmAutoBuild_mock-bind-localrepo
434
435 \mv -f ${LOCALREPO_DIR%/}/.MISC/kernel-temp/*.src.rpm "${RPM_BUILD_DIR%/}/SRPMS"
436
437 srpmAutoBuild_mock-chroot0 '/build-main.sh'
438
439 if (( $isolateKernelBuildFlag > 1 )); then
440
441 newlyBuiltRpmList="$(find ${RPM_BUILD_DIR%/}/RPMS -type f -name "kernel{-,-headers-,-tools-}*.rpm")"
442
443 (( $isolateKernelBuildFlag == 2 )) && newlyBuiltRpmList="$(echo "${newlyBuiltRpmList}" | grep -v -E 'debug(info|source)')"
444 (( $isolateKernelBuildFlag == 3 )) && newlyBuiltRpmList="$(echo "${newlyBuiltRpmList}" | grep -E 'debug(info|source)')"
445
446 [[ -n "${newlyBuiltRpmList}" ]] && dnf -y localinstall ${newlyBuiltRpmList}
447
448 fi
449
450 fi
451
452 # cleanup mock environment, unless --no-clean Flag set
453 (( $noCleanFlag == 0 )) && srpmAutoBuild_mock-clean
454
455 # note: mock-clean will automatically un-mount '${LOCALREPO_DIR}' and transfer out all the built RPMs (as well as the SRPMs and the spec-files) to directories in '${LOCALREPO_DIR}' before running the actual cleaning function.
456}
457
458
459srpmAutoBuild_mock-config-setup() {
460 # modifies the original config file in /etc/mock so that it works better by default with srpmAutoBuild
461 # default behavior is to re-save the original config file as '/etc/mock/$(srpmAutoBuild_getMockName).cfg.orig'; and to only regenerate the config file if that file doesnt exist.
462 #
463 # # # # # FLAGS # # # # #
464 #
465 # use flag '-f' or '--force' to force regeneration even if the *.orig config file exists. in this case the current config is saves as '*.orig[#]', where '[#]' is the lowest number that creates a unique filename
466 #
467 # use flag '-f_[#]' or '--force_[#]' to use the backup config file '/etc/mock/$(srpmAutoBuild_getMockName).cfg.orig[#]' as the source config file that is modified
468 # # '-f_' --> use '/etc/mock/$(srpmAutoBuild_getMockName).cfg.orig'
469 # # '-f_0' --> use '/etc/mock/$(srpmAutoBuild_getMockName).cfg.orig0'
470 # # '-f_9999' --> use '/etc/mock/$(srpmAutoBuild_getMockName).cfg.orig9999'
471 #
472
473 # get mock config file path
474 local mockConfigCur=""
475 mockConfigCur="/etc/mock/$(srpmAutoBuild_getMockName).cfg"
476
477 # check original config file exists, otherwise exis with status 1
478 [[ ! ${1,,} =~ ^-+f(orce)?_[0-9]*$ ]] && [[ ! -f "${mockConfigCur}" ]] && echo -e "\nWARNING: original config file '${mockConfigCur}' not found, and thus cant be modified! \nExiting with status '1' \n" >&2 && return 1
479
480 # exit with status 0 if *.orig config file also exists and '--force' flag is not set
481 [[ -f "${mockConfigCur}.orig" ]] && [[ ! ${1,,} =~ ^-+f(orce)?(_[0-9]*)?$ ]] && echo -e "\nNOTICE: '${mockConfigCur}.orig' config file backup already exists. \n'${mockConfigCur}' config file will not be re-writen. \nTo force re-generating the config file, use flag '-f' or '--force'. \n" >&2 && return
482
483 # determine which config file to use as a source
484 local mockConfigSource=""
485 [[ ${1,,} =~ ^-+f(orce)?_[0-9]*$ ]] && mockConfigSource="${mockConfigCur}.orig$(echo "${1}" | sed -E s/'^-+[a-zA-Z]*_([0-9]*)$'/'\1'/)" || mockConfigSource="${mockConfigCur}"
486 [[ ! -f "${mockConfigSource}" ]] && echo -e "\nWARNING: The selected mock config source file '${mockConfigSource}' does not exist and thus cant be used as the configuration source. \nExiting with status '2' \n" >&2 && return 2 || echo "Using '${mockConfigSource}' as the source mock configuration file" >&2
487
488 # get name for config backup path
489 local mockConfigBackup=""
490 mockConfigBackup="$(srpmAutoBuild_getUniqueName "${mockConfigCur}.orig")"
491
492 # move orig config to backup path
493 [[ -f "${mockConfigCur}" ]] && echo "Moving '${mockConfigCur}' to '${mockConfigBackup}' ..." >&2 && mv "${mockConfigCur}" "${mockConfigBackup}" && [[ ! ${1,,} =~ ^-+f(orce)?_[0-9]*$ ]] && mockConfigSource="${mockConfigBackup}"
494
495 # modify original config file and resave it as current mock config file
496 echo "Writing new config file to '${mockConfigCur}' ..." >&2
497 echo "$(echo -n "$(cat "${mockConfigSource}" | sed -zE s/'^(.*)\n\# *[Rr]epos.*$'/'\1'/ | sed -E s/'yum'/'dnf'/g | sed -E s/'dnf\.repos\.d'/'yum\.repos\.d'/ | sed -E s/'\('"'"'x86_64'"'"'\,?\)'/'\('"'"'x86_64'"'"','"'"'noarch'"'"'\)'/ | grep -v -E '^(fastestmirror|reposdir|cachedir|timeout|gpg_check|repo_gpgcheck|syslog_ident|install_weak_deps|metadata_expire|config_opts\['"'"'chroot_setup_cmd'"'"'\])'; echo -e "fastestmirror=1\nreposdir=/etc/yum.repos.d/\ncachedir=/var/cache/dnf/\ntimeout=20\ngpgcheck=0\nrepo_gpgcheck=0\nsyslog_ident=root\ninstall_weak_deps=1\nmetadata_expire=1h\n")" | sed -zE s/'^(.*[^\n])\n?(\nconfig_opts\['"'"'dnf\.conf'"'"'\] *=.*)$'/'\1\nconfig_opts\['"'"'copy-in'"'"'\] = \[ '"'"'\/etc\/yum\/repos.d'"'"' \]\nconfig_opts\['"'"'chroot_setup_cmd'"'"'\] = '"'"'install @development-tools @rpm-development-tools @c-development @buildsys-build vim ShellCheck kernel-devel kernel-modules kernel-modules-extra kernel-headers kernel-cross-headers kernel-rpm-macros kernel-core dnf dnf-plugins-core python3-dnf dnf-yum'"'"'\n\2'/)" > "${mockConfigCur}"
498
499 # add repo info to config file
500 echo "Adding repo info to config file '${mockConfigCur}' ..." >&2
501 if [[ -z "$(find "/etc/yum.repos.d" -type f)" ]]; then
502 echo "$(cat "${mockConfigBackup}" | sed -zE s/'^.*(\n\# *[Rr]epos.*)$'/'\1'/)" >> "${mockConfigCur}"
503 else
504 local nn=""
505
506 echo -e "\n# repos" >> "${mockConfigCur}"
507 for nn in /etc/yum.repos.d/*; do
508 echo -e "\n# repos from ${nn##*/} \n" >> "${mockConfigCur}"
509 echo "$(cat "${nn}")" >> "${mockConfigCur}"
510 done
511 echo -e "\n\"\"\"" >> "${mockConfigCur}"
512 fi
513
514 echo -e "\nNew config file has been generated and saved to '${mockConfigCur}' \n" >&2
515
516}
517
518
519srpmAutoBuild_mockSetupCheck() {
520 # checks the following:
521 # # that "/etc/mock/$(srpmAutoBuild_getMockName).cfg" exists, else [re]installs mock using dnf
522 # # checks that "/etc/mock/$(srpmAutoBuild_getMockName).cfg.orig" exists, else runs srpmAutoBuild_mock-config-setup
523
524 [[ ! -f "/etc/mock/$(srpmAutoBuild_getMockName).cfg" ]] && [[ -z "$(rpm -qa | grep -E '^mock-[^a-zA-Z]*\.fc[0-9]+\.noarch')" ]] && dnf install -y mock
525 [[ ! -f "/etc/mock/$(srpmAutoBuild_getMockName).cfg" ]] && dnf reinstall -y mock
526 [[ ! -f "/etc/mock/$(srpmAutoBuild_getMockName).cfg.orig" ]] && srpmAutoBuild_mock-config-setup
527
528}
529
530
531srpmAutoBuild_mock-zfs-build() {
532 # re-downloads and re-builds a new set of zfs rpm packages inside of mock
533 # to automatically upgrade/install any (escept debuginfo/debugsource) rpm's built, use flag '-i' or '--install'
534
535 local installFlag=0
536 [[ ${1,,} =~ ^-+i(nstall)?$ ]] && installFlag=1
537
538 # setup
539 srpmAutoBuild_mock-clean
540 srpmAutoBuild_mock-init --mount=tmpfs
541
542 mock -r "$(srpmAutoBuild_getMockName)" --dnf --new-chroot --install '@development-tools' autoconf automake libtool wget libtirpc-devel rpm-build zlib-devel libuuid-devel libattr-devel libblkid-devel libselinux-devel libudev-devel libaio-devel parted lsscsi ksh openssl-devel elfutils-libelf-devel kernel-devel-$(uname -r) lcov git sudo python3 python3-devel
543
544 # build
545 srpmAutoBuild_mock-chroot 'srpmAutoBuild_setEnvVars ; cd \${RPM_BUILD_DIR}/BUILD ; git clone https://github.com/zfsonlinux/zfs.git ; cd \${RPM_BUILD_DIR%/}/BUILD/zfs && \${RPM_BUILD_DIR%/}/BUILD/zfs/autogen.sh && \${RPM_BUILD_DIR%/}/BUILD/zfs/configure -with-config=all --with-aix-soname=both --enable-debug --enable-debuginfo --enable-pyzfs --enable-systemd --enable-sysvinit -enable-code-coverage --enable-dependency-tracking --enable-shared --enable-static --enable-debug-kmem --enable-debug-kmem-tracking --with-python=3 && make -k -j$(nproc) && make -k -j1 pkg-utils srpm-utils srpm-common srpm-dkms srpm && cp -a \${RPM_BUILD_DIR%/}/BUILD/zfs/*.src.rpm \${RPM_BUILD_DIR%/}/SRPMS && cd \${RPM_BUILD_DIR} && srpmAutoBuild_build'
546
547 # install
548 if (( $installFlag == 1 )) && [[ -n "$(find "${RPM_BUILD_DIR}/RPMS" -type f -name "*.rpm")" ]]; then
549 srpmAutoBuild_copyFilesOutOfMock
550
551 [[ -n "$(dnf repolist 2>/dev/null | grep 'localrepo')" ]] && localrepo_updateDatabase && localrepo_dnf --built upgrade -y || dnf upgrade -y $(find "${RPM_BUILD_DIR}/RPMS" -type f -name "*.rpm")
552 dnf install -y $(find "${RPM_BUILD_DIR}/RPMS" -type f -name "*.rpm" | grep -v 'debug')
553
554 # ensure dkms kernel modules are built
555 [[ -n "$(find "${RPM_BUILD_DIR}/RPMS" -type f -name "zfs-dkms*.rpm")" ]] && [[ -n "$(rpm -qa | grep 'zfs-dkms')" ]] && dkms -m zfs autoinstall
556 fi
557
558 # cleanup
559 #srpmAutoBuild_mock-clean
560}
561
562
563# # # # # # # # # # # CODES TO MOUNT/BIND AND UNMOUNT A LOCAL PACKAGE REPO INTO MOCK # # # # # # # # # # #
564
565
566srpmAutoBuild_localrepoIsMounted() {
567 # Returns as "true" if ${MOCK_ROOT_DIR}${LOCALREPO_DIR} is a mount point (presumably bound to ${LOCALREPO_DIR})
568 # Returns as "false" if ${MOCK_ROOT_DIR}${LOCALREPO_DIR} is NOT currently a mount point
569
570 [[ -d "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR#/}" ]] && srpmAutoBuild_isMountPoint "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR#/}" && return 0 || return 1
571}
572
573
574srpmAutoBuild_isMountPoint() {
575 # Returns as "true" if input ( "${*}" ) IS a mount point
576 # Returns as "false" if input ( "${*}" ) IS NOT a mount point
577
578 [[ -z "$(mountpoint "${*}" | grep 'not')" ]] && return 0 || return 1
579
580}
581
582
583srpmAutoBuild_isNotEmpty() {
584 # checks if the directory/file is not empty (i.e., it either doesnt exist or exists but has no content)
585
586 [[ ! -e "${*}" ]] && return 1
587 [[ -d "${*}" ]] && [[ -z "$(find "${*}" -maxdepth 1 | grep -v -F "${*}")" ]] && return 1
588 [[ -f "${*}" ]] && [[ -z "$(cat "${*}")" ]] && return 1
589 return 0
590
591
592}
593
594
595srpmAutoBuild_mock-bind-localrepo() {
596 # mount/bind ${LOCALREPO_DIR} into mock environment
597 srpmAutoBuild_setEnvVars
598
599 if ! srpmAutoBuild_localrepoIsMounted; then
600
601 [[ -d "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR#/}" ]] || mkdir --parents "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR#/}"
602
603 [[ -d "${LOCALREPO_DIR}" ]] && ( srpmAutoBuild_isNotEmpty || ( [[ -d "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR#/}" ]] || mkdir "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR#/}" ) && mount -o bind,ro "${LOCALREPO_DIR}" "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR#/}" )
604
605 fi
606}
607
608
609srpmAutoBuild_mock-umount-localrepo() {
610 # sinple (non-forceful) umount of ${LOCALREPO_DIR} from mock
611 srpmAutoBuild_rootUserCheck
612
613 srpmAutoBuild_localrepoIsMounted && umount "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR#/}"
614}
615
616
617srpmAutoBuild_mock-force-umount-localrepo() {
618 # forceful umount of ${LOCALREPO_DIR} from mock.
619 # This should be run before cleaning mock (it is called automatically by srpmAutoBuild_mock-clean) to ensure that cleaning does not begin while ${LOCALREPO_DIR} is still mounted/bound in the mock environment, as this can lead to the entire ${LOCALREPO_DIR} being permanently deleted.
620 srpmAutoBuild_rootUserCheck
621
622 srpmAutoBuild_localrepoIsMounted && srpmAutoBuild_mock-umount-localrepo
623 srpmAutoBuild_localrepoIsMounted && umount -f "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR#/}"
624 srpmAutoBuild_localrepoIsMounted && srpmAutoBuild_mock-chroot0 'umount ${LOCALREPO_DIR}'
625 srpmAutoBuild_localrepoIsMounted && srpmAutoBuild_mock-chroot0 'umount -f ${LOCALREPO_DIR}'
626 srpmAutoBuild_localrepoIsMounted && echo -e "\n\nWARNING: The \"${LOCALREPO_DIR}\" bind/mount in the mock environment will not umount. \nCleaning the Mock environment with \"${LOCALREPO_DIR}\" bound / mounted, even in read-only mode, may lead to data loss. \n" >&2
627
628 if srpmAutoBuild_localrepoIsMounted; then
629
630 [[ -d "/DATA/${LOCALREPO_DIR#/}" ]] && [[ -n $(find "/DATA/${LOCALREPO_DIR#/}") ]] && LOCALREPO_BACKUP_DIR="/DATA/${LOCALREPO_DIR#/}"
631
632 if [[ -n ${LOCALREPO_BACKUP_DIR} ]]; then
633 echo -e "\"${LOCALREPO_DIR}\" will be backed up to the pre-set backup directory at ${LOCALREPO_BACKUP_DIR}"
634 rsync -avP "${LOCALREPO_DIR%/}/" "${LOCALREPO_BACKUP_DIR%/}/"
635
636 else
637
638 echo -e "A backup directory has not been setup for \"${LOCALREPO_DIR}\". Please enter a backup location to backup the repo. \nNOTE: if you respond with the response\"NONE\", the repo will not be backed up. Only do this is you know what you are doing or dont care about any of the data in \"${LOCALREPO_DIR}\" \n\nIf you respond with an empty/null response, the node will exit without cleaning mock, unless the '--no-fail- flag was given." >&2
639 read -ie -p "Backup Directory: " LOCALREPO_BACKUP_DIR
640
641 fi
642
643 ( [[ -z "${LOCALREPO_BACKUP_DIR}" ]] || [[ ${LOCALREPO_BACKUP_DIR} =~ ^\${LOCALREPO_DIR}(\/.*)?$ ]] ) && [[ ! ${1,,} =~ ^-+no-?fail$ ]] && exit 1
644 ( [[ -z "${LOCALREPO_BACKUP_DIR}" ]] || [[ ${LOCALREPO_BACKUP_DIR} =~ ^\${LOCALREPO_DIR}(\/.*)?$ ]] ) && LOCALREPO_BACKUP_DIR="${LOCALREPO_DIR}-backup"
645
646 if [[ "${LOCALREPO_BACKUP_DIR}" != "NONE" ]]; then
647
648 LOCALREPO_BACKUP_DIR="${LOCALREPO_BACKUP_DIR%/}"
649 [[ -d "${LOCALREPO_BACKUP_DIR}" ]] || mkdir --parents "${LOCALREPO_BACKUP_DIR}"
650 export LOCALREPO_BACKUP_DIR
651
652 rsync -avP "${LOCALREPO_DIR%/}/" "${LOCALREPO_BACKUP_DIR%/}/"
653 fi
654
655 fi
656}
657
658# # # # # # # # # # # # # CODES TO RUN COMMANDS / GET AN INTERACTIVE SHELL IN MOCK # # # # # # # # # # # # #
659
660srpmAutoBuild_mock-chroot0() {
661 # enter the mock chroot (if no functions inputs) or run specified command non-interactively in mock. In either case, ~/.bashrc is sourced, which (if using the other srpmAutoBuild_mock-* functions) will setup everything needed to run srpmAutoBuild from within mock.
662
663
664 #&& inputCmds='[[ -f "/usr/local/bin/my-scripts/srpmAutoBuild.sh" ]] && chmod 777 "/usr/local/bin/my-scripts/srpmAutoBuild.sh" && source "/usr/local/bin/my-scripts/srpmAutoBuild.sh" || [[ -f "/builddir/.bashrc" ]] && chmod 777 "/builddir/.bashrc" && source "/builddir/.bashrc";'
665
666 #(( $# == 0 )) && cmdType='--shell /bin/bash' || cmdType='--chroot' && inputCmds='/bin/bash -c '"'"'if [[ -f "/usr/local/bin/my-scripts/srpmAutoBuild.sh" ]]; then chmod 777 "/usr/local/bin/my-scripts/srpmAutoBuild.sh" && source "/usr/local/bin/my-scripts/srpmAutoBuild.sh"; elif [[ -f "/builddir/.bashrc" ]]; then chmod 777 "/builddir/.bashrc" && source "/builddir/.bashrc"; fi; sleep 1; srpmAutoBuild_setEnvVars; '"${*}"''"'"''
667 inputCmds='/bin/su -p --session-command "if [[ -f \"/usr/local/bin/my-scripts/srpmAutoBuild.sh\" ]]; then chmod 777 \"/usr/local/bin/my-scripts/srpmAutoBuild.sh\"; source \"/usr/local/bin/my-scripts/srpmAutoBuild.sh\"; elif [[ -f \"/builddir/.bashrc\" ]]; then chmod 777 \"/builddir/.bashrc\"; source \"/builddir/.bashrc\"; fi; sleep 1; srpmAutoBuild_setEnvVars; sleep 1; '"${*}"'" 2>/dev/null'
668
669 mock -r "$(srpmAutoBuild_getMockName)" --enable-network --dnf --new-chroot --shell $( (( $# == 0 )) && echo "'/bin/bash'" ) "${inputCmds}" 2>/dev/null
670
671 # || eval $(echo "mock -r \$(srpmAutoBuild_getMockName)\" --old-chroot --chroot $(echo "${*}" | sed -E s/'-+file=(("[^"]*")|('"'"'[^'"'"']*'"'"')|([^"'"'"'][^ ]*))'/'\< \<\(\1\)'/g)")
672}
673
674
675srpmAutoBuild_mock-chroot() {
676 # same ad srpmAutoBuild_downloadBuildableSRPMs, but start by mounting/binding ${LOCALREPO_DIR} to mock and end by umounting it
677
678 srpmAutoBuild_mock-bind-localrepo
679 (( $# == 0 )) && srpmAutoBuild_mock-chroot0 || srpmAutoBuild_mock-chroot0 "${*}"
680 srpmAutoBuild_mock-umount-localrepo
681}
682
683# # # # # # # # # # # # # CODES TO INITIALIZE / SETUP / COPY FILES INTO / CLEAN MOCK # # # # # # # # # # # # #
684
685srpmAutoBuild_mock-clean() {
686 # unmounts ${LOCALREPO_DIR} from mock, transfers built RPMs, source SRPMS and specfiles from mock into ${LOCALREPO_DIR}, and then runs `mock -r <...> --clean`
687
688 # if mock doesnt exist it doesnt need to be cleaned
689 srpmAutoBuild_existMock || return
690
691 srpmAutoBuild_copyFilesOutOfMock
692
693 [[ "$(pwd)" == ${MOCK_ROOT_DIR%/}* ]] && ( cd / ; cd ~/ )
694
695 mock -r "$(srpmAutoBuild_getMockName)" --umount
696 srpmAutoBuild_mock-force-umount-localrepo
697
698 [[ ! ${1,,} =~ ^-+no-?rpm-?check$ ]] && [[ -n "$(diff <(ls -1 ${RPM_BUILD_DIR}/RPMS) <(ls -1 ${LOCALREPO_DIR}/built/NEW) | grep -vE '^>' | grep -E '\.rpm$')" ]] && echo -e "\nWARNING: AT least 1 built RPM(s) from '${RPM_BUILD_DIR}/RPMS' \n were not found in localrepo directory '${LOCALREPO_DIR}/built/NEW' \n\n The mock environment will NOT be cleaned. \n\n To force cleaning, run 'srpmAutoBuild_mock-clean --no-rpm-check' \n" >&2 && return 1
699
700 mock -r "$(srpmAutoBuild_getMockName)" --scrub=all
701 mock -r "$(srpmAutoBuild_getMockName)" --clean
702}
703
704
705srpmAutoBuild_mock-init() {
706 # cleans, initialized, and sets up mock (including copying required scripts and setting up ~/.bashrc)
707 # if passed flag '-nc' or '--no-clean' or '--no-clear', then the function will initiate mock if it doesnt exist but if it does exist it will be left as-is
708 # mount tmpfs or zfs filesystem (FEDORA/ROOT/MOCK) to /var/lib/mock before init using flag --mount={tmpfs,zfs}
709
710 local noCleanFlag=0
711 local mountFlag=""
712
713
714 (( $# > 0 )) && [[ ${1,,} =~ ^-+no?-?c(lea[nr])$ ]] && noCleanFlag=1 && shift 1
715 (( $# > 0 )) && [[ ${1,,} =~ ^-+mount=[\'\"]?((zfs)|(tmpfs)|(zfs\+tmpfs)|(tmpfs\+zfs))[\'\"]?$ ]] && mountFlag="${1#*=}" && mountFlag="${mountFlag,,}" && shift 1 && (( $# > 0 )) && [[ ${1,,} =~ ^-+no?-?c(lea[nr])$ ]] && noCleanFlag=1 && shift 1
716
717 (( $noCleanFlag == 1 )) && echo "Not cleaning mock prior to initialization" >&2
718
719 [[ -n "${mountFlag}" ]] && mountFlag="$(echo "${mountFlag}" | sed -E s/'^["'"'"'](.*)["'"'"']'/'\1'/)"
720 #echo "mount flag: $mountFlag"
721
722 srpmAutoBuild_setEnvVars
723 srpmAutoBuild_mockSetupCheck
724
725 (( $noCleanFlag == 0 )) && srpmAutoBuild_mock-force-umount-localrepo && srpmAutoBuild_mock-clean
726
727 if ! ( (( $noCleanFlag == 1 )) && srpmAutoBuild_existMock ); then
728
729 if [[ -n "${mountFlag}" ]]; then
730 if [[ "${mountFlag,,}" =~ ^(tmpfs\+)?zfs(\+tpmfs)?$ ]]; then
731 echo "Mounting ZFS dataset FEDORA/ROOT/MOCK (if needed)" >&2
732 [[ -n "$(zpool list -H -o name | grep FEDORA)" ]] || zpool import -N FEDORA
733 [[ -n "$(zfs get -H -o value mounted FEDORA/ROOT/MOCK)" ]] || zfs mount -l FEDORA/ROOT/MOCK
734 fi
735 echo "Mounting tmpfs filesystem to '${MOCK_ROOT_DIR}'" >&2
736 if [[ "${mountFlag,,}" =~ ^(zfs\+)?tmpfs(\+zfs)? ]]; then
737 [[ -d "${MOCK_ROOT_DIR}" ]] || mkdir --parents "${MOCK_ROOT_DIR}"
738 [[ -z "$(cat /proc/self/mounts | grep ' '"${MOCK_ROOT_DIR}"' ' | grep 'tmpfs')" ]] && mount -t tmpfs tmpfs "${MOCK_ROOT_DIR}"
739 fi
740 fi
741
742 mock -r "$(srpmAutoBuild_getMockName)" --mount --copyin "/etc/yum.repos.d" --new-chroot --init --enable-network --dnf --install dnf dnf-utils dnf-yum python3-dnf python3-dnf-plugins-core vim @c-development @development-libs @development-tools @rpm-development-tools @buildsys-build
743 fi
744
745 if (( $# > 0 )); then
746 local copyItems=""
747 local buildScriptFlags=""
748
749 while (( $# > 0 )); do
750 ( [[ -d "${1}" ]] || [[ -f "${1}" ]] ) && copyItems="${copyItems} ${1}" || buildScriptFlags="${buildScriptFlags} ${1}"
751 shift 1
752 done
753
754 srpmAutoBuild_copyFilesIntoMock ${copyItems}
755 srpmAutoBuild_generateBuildScripts ${buildScriptFlags}
756 else
757 srpmAutoBuild_copyFilesIntoMock
758 srpmAutoBuild_generateBuildScripts
759 fi
760
761 srpmAutoBuild_mock-bind-localrepo
762
763 if [[ -f "${MOCK_ROOT_DIR%/}/usr/local/bin/my-scripts/srpmAutoBuild.sh" ]]; then
764
765 local bashrcAdd=""
766
767 bashrcAdd="$(echo -e "\n[[ -f \"/usr/local/bin/my-scripts/srpmAutoBuild.sh\" ]] && chmod 777 \"/usr/local/bin/my-scripts/srpmAutoBuild.sh\" && source \"/usr/local/bin/my-scripts/srpmAutoBuild.sh\" && srpmAutoBuild_setEnvVars \n")"
768
769 echo "$(echo "$(cat "${MOCK_ROOT_DIR%/}/builddir/.bashrc" | sed -z -E s/"$(srpmAutoBuild_escapeRegexChars --newline-mod "${bashrcAdd}")"//g)"; echo "${bashrcAdd}")" > "${MOCK_ROOT_DIR%/}/builddir/.bashrc"
770
771 fi
772
773}
774
775
776srpmAutoBuild_mock-makecache() {
777 local cmdOut=""
778 local nn=""
779
780 cmdOut="$(srpmAutoBuild_mock-chroot0 'dnf makecache' 2>&1)"
781 if [[ -n "$(echo "${cmdOut}" | tail -n 1)" ]] && [[ -n "$(echo "${cmdOut}" | tail -n 1 | grep -E '^Error\: Failed to synchronize cache for repo')" ]]; then
782
783 echo "Initial attempt to make dnf cache in mock failed. The code will now try cleaning and re-generating the local repository data + cache info and will then try making the mock dnf cache again." >&2
784
785 srpmAutoBuild_mock-force-umount-localrepo
786 srpmAutoBuild_mock-chroot0 'dnf clean all' 2>/dev/null
787 dnf clean all
788 localrepo_updateDatabase --clean
789 srpmAutoBuild_mock-bind-localrepo
790
791 for nn in {repodata,cache,drpms,built,downloaded,source}; do
792 ( chmod -R 777 "$(find "${MOCK_ROOT_DIR%/}/${LOCALREPO_DIR}" -type d -name "${nn}")" 2>/dev/null )
793 done
794
795 cmdOut="$(srpmAutoBuild_mock-chroot0 'dnf makecache' 2>&1)"
796
797 [[ -n "$(echo "${cmdOut}" | tail -n 1)" ]] && [[ -n "$(echo "${cmdOut}" | tail -n 1 | grep -E '^Error\: Failed to synchronize cache for repo')" ]] && echo -e "\n\nWARNING: an unknown error is preventing a repo from syncing. srpmAutoBuild functions will likely fail until this is fixed." >&2
798
799 fi
800}
801
802
803srpmAutoBuild_mock-build() {
804 # calls "srpmAutoBuild_mock-chroot 'srpmAutobuild_build ${*}'" and will, if needed, initialize mock if it is currently uninitialized.
805 # this allows one to call srpmAutoBuild_build from the hoist OS without needing to deal with mock setup or chroot
806 # by default it will not clean / re-initialize mock. Use flag '-c' or '--clean' to force this behavior.
807 # note that this flag MUST be the 1st input - all additional inputs are passed on to srpmAutobuild_build
808 # also note that, if called from within mock, this function will pass ALL inputs to srpmAutoBuild_build, and wont call srpmAutoBuild_mock-chroot
809 # If there are no inputs (or the only input is '-c' / '--clean') - srpmAutoBuild_build will build any SRPMs / specfiles in ${RPM_BUILD_DIR%/}/{SRPMS,SPECS}
810
811 if srpmAutoBuild_isMock; then
812 echo "RUNNING IN MOCK" >&2
813 (( $# > 0 )) && srpmAutoBuild_build "${@}" && return
814 (( $# == 0 )) && srpmAutoBuild_build ${RPM_BUILD_DIR%/}/SRPMS/*.src.rpm ${RPM_BUILD_DIR%/}/SPECS/*.spec && return
815 else
816 echo "RUNNING IN HOST OS" >&2
817 fi
818
819 (( $# > 0 )) && [[ ${1,,} =~ ^-+c(lean)?$ ]] && shift 1 && srpmAutoBuild_mock-clean
820
821 srpmAutoBuild_existMock || srpmAutoBuild_mock-init
822
823 (( $# > 0 )) && srpmAutoBuild_mock-chroot 'srpmAutoBuild_build '"${*}"'' && return
824 (( $# == 0 )) && srpmAutoBuild_mock-chroot 'srpmAutoBuild_build ${RPM_BUILD_DIR%/}/SRPMS/*.src.rpm ${RPM_BUILD_DIR%/}/SPECS/*.spec' && return
825
826}
827
828
829srpmAutoBuild_existMock() {
830 # returns true (exit status 0) is mock has been initialized and false (exit status 1) if it hasnt
831
832 srpmAutoBuild_isMock && return 0
833 [[ -d "${MOCK_ROOT_DIR}" ]] && return 0
834 srpmAutoBuild_isNotEmpty "${MOCK_ROOT_DIR}" && return 0 || return 1
835}
836
837
838srpmAutoBuild_copyFilesIntoMock() {
839 # copies needed scripts into mock. By default "${MOCK_ROOT_DIR%/}/usr/local/bin/my-scripts/" is always copied. Anyfunction inputs passed that are valid files or directories will be copied as well.
840
841 # make sure we have mock root directory
842 srpmAutoBuild_setEnvVars
843
844 local -a copyItems
845 local noScriptsFlag=0
846 local noCacheFlag=1
847
848 if (( $# > 0 )); then
849
850 if [[ ${1} =~ ^-+((n[dsc])|(no-?((default)|(cache)|(script))(-?copy)?)) ]]; then
851
852 [[ ${1} =~ ^-+((n[ds])|(no-?((default)|(script))(-?copy)?)) ]] && noScriptsFlag=1
853 [[ ! ${1} =~ ^-+((n[dc])|(no-?((default)|(cache))(-?copy)?)) ]] && noCacheFlag=0
854
855 shift 1
856 fi
857
858 copyItems=($(echo "${@}"))
859
860 # ensure directories exist and copy over srpmAutoBuild
861 (( $noScriptsFlag == 0)) && [[ -d "/usr/local/bin/my-scripts" ]] && copyItems[${#copyItems[@]}]="/usr/local/bin/my-scripts"
862 (( $noCacheFlag == 0)) && [[ -d "/var/cache/dnf" ]] && copyItems[${#copyItems[@]}]="/var/cache/dnf"
863
864 fi
865
866 copyItems[${#copyItems[@]}]="/usr/local/bin/my-scripts"
867 copyItems[${#copyItems[@]}]="/etc/yum.repos.d"
868
869 for nn in "${copyItems[@]}"; do
870
871 if [[ -d "${nn}" ]] || [[ -f "${nn}" ]]; then
872
873 nn="${nn%/}"
874 echo "Copying: \"${nn}\" --> \"${MOCK_ROOT_DIR}${nn}\""
875
876 [[ -d "${MOCK_ROOT_DIR}${nn%/*}" ]] || mkdir --parents "${MOCK_ROOT_DIR}${nn%/*}"
877 chmod -R 777 "${MOCK_ROOT_DIR%/}/${nn%/*}" "${nn}"
878
879 [[ -d "${nn}" ]] && ( [[ -d "${MOCK_ROOT_DIR}${nn}" ]] && \cp -rf ${nn%/}/* "${MOCK_ROOT_DIR}${nn%/}/" || \cp -rf "${nn}" "${MOCK_ROOT_DIR}${nn%/*%/}/" ) || ( [[ -f "${nn}" ]] && cp -f "${nn}" "${MOCK_ROOT_DIR}${nn}" )
880
881 fi
882
883 done
884
885}
886
887srpmAutoBuild_copyFilesOutOfMock() {
888 srpmAutoBuild_setEnvVars
889
890 [[ -d "${LOCALREPO_DIR%/}/built/NEW" ]] || mkdir --parents "${LOCALREPO_DIR%/}/built/NEW"
891 [[ -n $(find "${MOCK_ROOT_DIR%/}/builddir/build/RPMS/" -type f -name "*.rpm") ]] && \cp -au $(find "${RPM_BUILD_DIR%/}//RPMS/" -type f -name "*.rpm") "${LOCALREPO_DIR%/}/built/NEW/"
892
893 [[ -d "${LOCALREPO_DIR%/}/source/NEW" ]] || mkdir --parents "${LOCALREPO_DIR%/}/source/NEW"
894 [[ -n $(find "${MOCK_ROOT_DIR%/}/builddir/build/SRPMS/" -type f -name "*.src.rpm") ]] && \cp -au $(find "${RPM_BUILD_DIR%/}/SRPMS/" -type f -name "*.src.rpm") "${LOCALREPO_DIR%/}/source/NEW/"
895
896 [[ -d "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/SPECS" ]] || mkdir --parents "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/SPECS"
897 [[ -d "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/SPECS_OLD" ]] && \rm -rf "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/SPECS_OLD"
898 mkdir "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/SPECS_OLD"
899 [[ -n $(find "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/SPECS" -name "*.spec") ]] && \mv -f ${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/SPECS/* "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/SPECS_OLD/"
900 [[ -n $(find "${RPM_BUILD_DIR%/}/SPECS/" -type f -name "*.spec") ]] && \cp -af ${RPM_BUILD_DIR%/}/SPECS/* "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/SPECS/"
901
902 [[ -f "${RPM_BUILD_DIR%/}/.STATS_OVERALL" ]] && \cp -af "${RPM_BUILD_DIR%/}/.STATS_OVERALL" "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/.STATS_OVERALL"
903 [[ -f "${RPM_BUILD_DIR%/}/.STATUS_1" ]] && \cp -af "${RPM_BUILD_DIR%/}/.STATUS_1" "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/.STATUS_1"
904 [[ -f "${RPM_BUILD_DIR%/}/.STATUS_2" ]] && \cp -af "${RPM_BUILD_DIR%/}/.STATUS_2" "${LOCALREPO_DIR%/}/.MISC/FROM_MOCK/.STATUS_2"
905
906}
907
908srpmAutoBuild_generateBuildScripts() {
909 # produce scripts in the mock environment to call to start main and secondary build run with a single command
910 # any function inputs are assumed to be FLAGS for srpmAutoBuild_build and will be added to the start of the srpmAutoBuild_build function call
911
912 srpmAutoBuild_setEnvVars
913
914 local autoBuildCmdArgs=""
915 #local autoBuildCmd2=""
916
917 (( $# > 0 )) && autoBuildCmdArgs="${*}"
918
919 [[ -f "${MOCK_ROOT_DIR%/}/build-main.sh" ]] && chmod 777 "${MOCK_ROOT_DIR%/}/build-main.sh" && \rm -f "${MOCK_ROOT_DIR%/}/build-main.sh"
920 [[ -f "${MOCK_ROOT_DIR%/}/build-secondary.sh" ]] && chmod 777 "${MOCK_ROOT_DIR%/}/build-secondary.sh" && \rm -f "${MOCK_ROOT_DIR%/}/build-secondary.sh"
921
922 touch "${MOCK_ROOT_DIR%/}/build-main.sh" && chmod 777 "${MOCK_ROOT_DIR%/}/build-main.sh"
923 touch "${MOCK_ROOT_DIR%/}/build-secondary.sh" && chmod 777 "${MOCK_ROOT_DIR%/}/build-secondary.sh"
924
925 # [[ -d "${MOCK_ROOT_DIR%/}/builddir/" ]] || mkdir --parents "${MOCK_ROOT_DIR%/}/builddir/"
926
927 #autoBuildCmd2="$(echo "$(echo "${autoBuildCmd}" | sed -E s/'^(-+r(everse)?)?((.*[^\-])-+r(everse)?)*(.*[^\-])-+r(everse)?(.*)$'/'\4\6'/ | sed -E s/'^((.*[^\-])-+n(a|(o-?a(uto(-?match)?)?)))*(.*)$'/'\2\7'/ | sed -E s/'^ *([^ ].*[^ ]) *$'/'\1'/ | sed -E s/' +'/' '/) --reverse --no-auto-match")"
928
929cat << EOF > "${MOCK_ROOT_DIR%/}/build-main.sh"
930#!/bin/bash
931
932sleep 1
933
934# source srpmAutoBuild
935[[ -f "/usr/local/bin/my-scripts/srpmAutoBuild.sh" ]] && chmod 777 "/usr/local/bin/my-scripts/srpmAutoBuild.sh" && source "/usr/local/bin/my-scripts/srpmAutoBuild.sh" || [[ -f "/builddir/.bashrc" ]] && chmod 777 "/builddir/.bashrc" && source "/builddir/.bashrc"
936
937sleep 1
938
939# build all SRPMS
940srpmAutoBuild_build --build-main ${autoBuildCmdArgs} \${RPM_BUILD_DIR%/}/SRPMS/*.src.rpm
941
942# dont close window automatically
943echo -e "\n\n\nBUILD RUN #1 HAS FINISHED \n\n" >&2
944exitVar="" && read -e -p "Press 'ENTER' to close this window" exitVar
945
946EOF
947
948cat << EOF > "${MOCK_ROOT_DIR%/}/build-secondary.sh"
949#!/bin/bash
950
951sleep 10
952
953# source srpmAutoBuild
954[[ -f "/usr/local/bin/my-scripts/srpmAutoBuild.sh" ]] && chmod 777 "/usr/local/bin/my-scripts/srpmAutoBuild.sh" && source "/usr/local/bin/my-scripts/srpmAutoBuild.sh" || [[ -f "/builddir/.bashrc" ]] && chmod 777 "/builddir/.bashrc" && source "/builddir/.bashrc"
955
956sleep 1
957
958localTimeoutLimit=1800
959
960echo -e "\n\nNOTICE: This build instance will remain idle until the main build run has finished instsalling all dependencies and generated all required specfiles from SRPMS. \nAt that point, it will begin to build the specfiles along with the main build instance, but going in the opposite order (i.e., from Z --> A instead of from A --> Z). \nIf, however, this build instance has not started in the next \$((( ( \$localTimeoutLimit ) / 60 ))) minutes, it will start without waiting for confirmation from the main build instance. \n" >&2
961
962sleep 5
963
964# wait for indicator that primary run has built all specfiles, or timeout is reached
965tt=0
966hh=0
967while (( \$tt < \$localTimeoutLimit )) && [[ -f "\${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" ]]; do
968
969 sleep 1
970
971 ((tt++))
972 ((hh++))
973
974 if (( \$tt == \$localTimeoutLimit )); then
975
976 echo -e "\nTIMEOUT LIMIT REACHED. Would you like to add more time? \n\nn[o] --> dont add more time, start 2nd build run immediately. \ny[es] --> (DEFAULT) add 5 minutes to clock \n[0-9]+ --> add the specified number of minutes to the clock \n\n(timeout is 30 seconds)\n" >&2
977 read -ie -p "Response (Y/n/#): " -t 30 extendTimeoutResponse
978
979 if [[ \${extendTimeoutResponse,,} =~ ^no?$ ]]; then
980 extendTimeoutResponse=0
981
982 elif ! [[ \${extendTimeoutResponse} =~ ^[0-9]+$ ]]; then
983 extendTimeoutResponse=300
984 fi
985
986 (( \$extendTimeoutResponse > 0 )) && localTimeoutLimit=\$(( \${localTimeoutLimit} + \${extendTimeoutResponse} )) && echo -e "\nADDING \${extendTimeoutResponse} SECONDS TO TIMEOUT \nNEW TIMEOUT IS \$(( \${localTimeoutLimit} / 60 )) MINUTES \n\n"
987 fi
988
989 (( \$hh == 60 )) && echo "\$(( \$tt / 60 )) minute(s) elapsed. There are \$((( ( \$localTimeoutLimit - \$tt ) / 60 ))) minute(s) remaining until timeout is reached" >&2 && hh=0;
990
991done
992
993echo "NOW STARTING TO BUILD SPECFILES INTO RPMS" >&2
994
995# build all SPECS
996srpmAutoBuild_build --build-secondary ${autoBuildCmdArgs} --reverse --no-auto-match \${RPM_BUILD_DIR%/}/SPECS/*.spec
997
998# dont close window automatically
999echo -e "\n\n\nBUILD RUN #2 HAS FINISHED \n\n"
1000exitVar="" && read -e -p "Press 'ENTER' to close this window" exitVar
1001
1002EOF
1003
1004 sync
1005
1006 chmod 777 "${MOCK_ROOT_DIR%/}/build-main.sh" "${MOCK_ROOT_DIR%/}/build-secondary.sh"
1007
1008}
1009
1010
1011# # # # # # # # CODES TO ANALYSE WHICH [S]RPMS HAVE BEEN BUILT / HAVENT BEEN BUILT / HAVE UPDATES # # # # # # # #
1012# # # # # # # # # # # # # AND DOWNLOAD THE SRPMS THAT ARE AVAILABLE AND NOT YET BUILT # # # # # # # # # # # # #
1013
1014srpmAutoBuild_mock-downloadSRPMs() {
1015 # moves to rpm build tree SRPM directors, downloads srpms with srpmAutoBuild_downloadBuildableSRPMs, then moves back to starting directory
1016 srpmAutoBuild_rootUserCheck
1017
1018 (( $# > 0 )) && [[ ${1,,} =~ -+r(efresh(-?cache)?) ]] && dnf --refresh makecache --enablerepo='*source*' --disablerepo='*testing*'
1019
1020 srpmAutoBuild_setRpmBuildDir
1021
1022 cd "${RPM_BUILD_DIR%/}/SRPMS"
1023
1024 [[ ${1,,} =~ ^-+enable(-?all)?-?repos?$ ]] && srpmAutoBuild_downloadBuildableSRPMs "${1}" || srpmAutoBuild_downloadBuildableSRPMs
1025
1026 cd "${OLDPWD}"
1027}
1028
1029
1030srpmAutoBuild_listUnbuiltRPMs() {
1031 # lists any installed rpms that there isnt a built rpm found for (see srpmAutoBuild_listBuiltSRPMs)
1032
1033 if (( $# > 0 )) && [[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?(\+a(rch(itecture)?)?)?$ ]]; then
1034 echo "$(diff --width=512 -ywd --suppress-common-lines <(srpmAutoBuild_listInstalledRPMs "${1}") <(srpmAutoBuild_listBuiltRPMs "${1}") | grep -E '[\<\|]' | sed -E s/'^([^\<\|]*[^ \t])[ \t]*[\<\|].*$'/'\1'/)"
1035 else
1036 echo "$(diff --width=512 -ywd --suppress-common-lines <(srpmAutoBuild_listInstalledRPMs) <(srpmAutoBuild_listBuiltRPMs) | grep -E '[\<\|]' | sed -E s/'^([^\<\|]*[^ \t])[ \t]*[\<\|].*$'/'\1'/)"
1037 fi
1038}
1039
1040
1041srpmAutoBuild_listInstalledRPMs() {
1042 # List RPMs installed in the system
1043
1044 if (( $# > 0 )) && [[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?$ ]]; then
1045
1046 echo "$(dnf list --installed | sed -E s/'^([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1'/ | sed -E s/'^(.*)\.[^\.]*$'/'\1'/; rpm -qia | grep -E '^Name' | sed -E s/'Name {8}\: (.*)$'/'\1'/)" | sort -u
1047
1048 elif (( $# > 0 )) && [[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?\+a(rch(itecture)?)?$ ]]; then
1049
1050 echo "$(dnf list --installed | sed -E s/'^([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1'/; rpm -qia | grep -E '^((Name {8}\:)|(Architecture\:))' | sed -zE s/'Name {8}\: ([^\n]*)\nArchitecture\: ([^\n]*)'/'\1\.\2'/g)" | sort -u
1051
1052 else
1053
1054 echo "$(dnf list --installed | sed -E s/'^([a-zA-Z0-9][^ \t]*)\.([^\. \t]*)([ \t]*([0-9]+\:)?)([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1-\5\.\2'/; rpm -qa)" | sort -u
1055
1056 fi
1057}
1058
1059
1060srpmAutoBuild_listUpgradeRPMs() {
1061 # lists all the RPMs that dnf indicates have an available update
1062
1063 local dnfInstalledList=""
1064
1065 dnfInstalledList="$(dnf list --installed)"
1066
1067 if (( $# > 0 )) && [[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?(\+a(rch(itecture)?)?)?$ ]]; then
1068
1069 echo "$( \
1070 dnf check-upgrade --bugfix --enhancement --newpackage --security | tail -n +2 | sed -zE s/'^(.*\n)Obsoleting Packages.*$'/'\1'/ | sed -E s/'^([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1'/ | sort -u; \
1071 dnf check-update --bugfix --enhancement --newpackage --security | tail -n +2 | sed -zE s/'^(.*\n)Obsoleting Packages.*$'/'\1'/ | sed -E s/'^([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1'/ | sort -u; \
1072 echo "$(diff -ywd --width=512 <(dnf check-upgrade) <(echo "${dnfInstalledList}") --suppress-common-lines | grep -E '[\<\|]' | sed -E s/'^([^ \t]*)[ \t].*$'/'\1'/ | sed -zE s/'^(.*\n)Obsoleting.*$'/'\1'/)" | sort -u | grep -E '[a-zA-Z0-9]' | sed -E s/'^([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1'/ | sort -u; \
1073 echo "$(diff -ywd --width=512 <(dnf check-update) <(echo "${dnfInstalledList}") --suppress-common-lines | grep -E '[\<\|]' | sed -E s/'^([^ \t]*)[ \t].*$'/'\1'/ | sed -zE s/'^(.*\n)Obsoleting.*$'/'\1'/)" | sort -u | grep -E '[a-zA-Z0-9]' | sed -E s/'^([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1'/ | sort -u; \
1074 )" | sed -E s/'^(.*)'"$([[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?\+a(rch(itecture)?)?$ ]] || echo '\.[^\.]*')"'$'/'\1'/ | sort -u
1075
1076 else
1077
1078 echo "$( \
1079 dnf check-upgrade --bugfix --enhancement --newpackage --security | tail -n +2 | sed -zE s/'^(.*\n)Obsoleting Packages.*$'/'\1'/ | sed -E s/'^([a-zA-Z0-9][^ \t]*)\.([^\. \t]*)([ \t]*([0-9]+\:)?)([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1-\5\.\2'/ | sort -u; sleep 1; \
1080 dnf check-update --bugfix --enhancement --newpackage --security| tail -n +2 | sed -zE s/'^(.*\n)Obsoleting Packages.*$'/'\1'/ | sed -E s/'^([a-zA-Z0-9][^ \t]*)\.([^\. \t]*)([ \t]*([0-9]+\:)?)([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1-\5\.\2'/ | sort -u; sleep 1; \
1081 echo "$(diff -ywd --width=512 <(dnf check-upgrade) <(echo "${dnfInstalledList}") --suppress-common-lines | grep -E '[\<\|]' | sed -E s/'^([a-zA-Z0-9][^ \t]*)\.([^\. \t]*)([ \t]*([0-9]+\:)?)([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1-\5\.\2'/ | sed -zE s/'^(.*\n)Obsoleting.*$'/'\1'/)" | sort -u | grep -E '[a-zA-Z0-9]' | sed -E s/'^([a-zA-Z0-9][^ \t]*)\.([^\. \t]*)([ \t]*([0-9]+\:)?)([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1-\5\.\2'/ | sort -u; sleep 1; \
1082 echo "$(diff -ywd --width=512 <(dnf check-update) <(echo "${dnfInstalledList}") --suppress-common-lines | grep -E '[\<\|]' | sed -E s/'^([a-zA-Z0-9][^ \t]*)\.([^\. \t]*)([ \t]*([0-9]+\:)?)([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1-\5\.\2'/ | sed -zE s/'^(.*\n)Obsoleting.*$'/'\1'/)" | sort -u | grep -E '[a-zA-Z0-9]' | sed -E s/'^([a-zA-Z0-9][^ \t]*)\.([^\. \t]*)([ \t]*([0-9]+\:)?)([a-zA-Z0-9][^ \t]*)[ \t].*$'/'\1-\5\.\2'/ | sort -u; sleep 1; \
1083 )" | sed -E s/'^(.*)\.[^\.]*$'/'\1'/ | sort -u
1084
1085 fi
1086}
1087
1088
1089srpmAutoBuild_listBuiltRPMs() {
1090 # determines which RPMs have already been built. This is determined by the presence of the built RPM in [a subdirectory of] any of the following 3 locations:
1091 # # ${RPM_BUILD_DIR%/}/RPMS
1092 # # ${MOCK_ROOT_DIR}${LOCALREPO_DIR%/}/built.
1093 # # ${LOCALREPO_DIR%/}/built
1094
1095 srpmAutoBuild_setRpmBuildDir
1096 local rpmBuiltList=""
1097
1098 if (( $# > 0 )) && [[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?$ ]]; then
1099
1100 rpmBuiltList="$(echo "$(
1101 [[ -d ${RPM_BUILD_DIR%/}/RPMS ]] && [[ -n $(find ${RPM_BUILD_DIR%/}/RPMS -type f -name "*.rpm") ]] && echo "$(rpm -qip $(find ${RPM_BUILD_DIR%/}/RPMS -type f -name "*.rpm") | grep -E '^Name {8}\: ' | sed -E s/'^.*\: *(.*)$'/'\1'/ | sort -u)"; \
1102 [[ -d ${LOCALREPO_DIR%/}/built ]] && [[ -n $(find ${LOCALREPO_DIR%/}/built -type f -name "*.rpm") ]] && echo "$(rpm -qip $(find ${LOCALREPO_DIR%/}/built -type f -name "*.rpm") | grep -E '^Name {8}\: ' | sed -E s/'^.*\: *(.*)$'/'\1'/ | sort -u)"; \
1103 )" | sort -u)"
1104
1105 elif (( $# > 0 )) && [[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?\+a(rch(itecture)?)?$ ]]; then
1106
1107 rpmBuiltList="$(echo "$(
1108 [[ -d ${RPM_BUILD_DIR%/}/RPMS ]] && [[ -n $(find ${RPM_BUILD_DIR%/}/RPMS -type f -name "*.rpm") ]] && echo "$(rpm -qip $(find ${RPM_BUILD_DIR%/}/RPMS -type f -name "*.rpm") | grep -E '^((Name {8}\:)|(Architecture\:))' | sed -zE s/'Name {8}\: ([^\n]*)\nArchitecture\: ([^\n]*)'/'\1\.\2'/g | sort -u)"; \
1109 [[ -d ${LOCALREPO_DIR%/}/built ]] && [[ -n $(find ${LOCALREPO_DIR%/}/built -type f -name "*.rpm") ]] && echo "$(rpm -qip $(find ${LOCALREPO_DIR%/}/built -type f -name "*.rpm") | grep -E '^((Name {8}\:)|(Architecture\:))' | sed -zE s/'Name {8}\: ([^\n]*)\nArchitecture\: ([^\n]*)'/'\1\.\2'/g | sort -u)"; \
1110 )" | sort -u)"
1111
1112 else
1113
1114 rpmBuiltList="$(echo "$(
1115 [[ -d ${RPM_BUILD_DIR%/}/RPMS ]] && [[ -n $(find ${RPM_BUILD_DIR%/}/RPMS -type f -name "*.rpm") ]] && echo "$(find ${RPM_BUILD_DIR%/}/RPMS -type f -name "*.rpm" | sed -E s/'^.*\/([^\/]*)\.rpm$'/'\1'/ | sort -u)"; \
1116 [[ -d ${LOCALREPO_DIR%/}/built ]] && [[ -n $(find ${LOCALREPO_DIR%/}/built -type f -name "*.rpm") ]] && echo "$(find ${LOCALREPO_DIR%/}/built -type f -name "*.rpm" | sed -E s/'^.*\/([^\/]*)\.rpm$'/'\1'/ | sort -u)"; \
1117 )" | sort -u)"
1118
1119# [[ -d ${MOCK_ROOT_DIR}${LOCALREPO_DIR%/}/built ]] && [[ -n $(find ${MOCK_ROOT_DIR}${LOCALREPO_DIR%/}/built -type f -name "*.rpm") ]] && echo "$(find ${MOCK_ROOT_DIR}${LOCALREPO_DIR%/}/built -type f -name "*.rpm" | sed -E s/'^.*\/([^\/]*)\.rpm$'/'\1'/ | sort -u)"; \
1120
1121 fi
1122
1123 echo "$(echo "${rpmBuiltList}" | grep -v -E '\%{.+\}'; [[ -n $(echo "${rpmBuiltList}" | grep -E '\%{.+\}') ]] && rpm --eval $(echo "${rpmBuiltList}" | grep -E '\%{.+\}'))" | sort -u
1124}
1125
1126
1127srpmAutoBuild_listBuiltSRPMs() {
1128 # Lists installed RPMs that were built on the system
1129
1130 [[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?\+a(rch(itecture)?)?$ ]] && srpmAutoBuild_getSRPM_fromRPM $(srpmAutoBuild_listBuiltRPMs "${1}") || srpmAutoBuild_getSRPM_fromRPM $(srpmAutoBuild_listBuiltRPMs)
1131
1132}
1133
1134
1135srpmAutoBuild_listUpgradeSRPMs() {
1136 # Lists installed RPMs that were NOT built on the system (i.e., were downloaded as pre-compiled RPMs)
1137
1138 [[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?\+a(rch(itecture)?)?$ ]] && srpmAutoBuild_getSRPM_fromRPM $(srpmAutoBuild_listUpgradeRPMs "${1}") || srpmAutoBuild_getSRPM_fromRPM $(srpmAutoBuild_listUpgradeRPMs)
1139
1140}
1141
1142
1143srpmAutoBuild_getSRPM_fromRPM() {
1144 # determines the names of the source SRPMs needed to build the list of RPMs described in the in the function input(s)
1145
1146 (( $# > 0 )) && dnf info --best --skip-broken "${@}" | grep -E '^Source' | sed -E s/'^[^\:]*\:[ \t]*(.*)$'/'\1'/ | grep -v '^None$' | sort -u || echo ""
1147}
1148
1149
1150srpmAutoBuild_listExcludedSRPMs() {
1151 # any RPMs or SRPMs listed in ${RPM_BUILD_DIR%/}/.EXCLUDE will not be downloaded.
1152 # Note: If an RPM is listed its analogous SRPM will be blacklisted, even if that same SRPM can build other RPMs that were not explicitly excluded.
1153 # Note: this is not well tested, and may not work
1154
1155 srpmAutoBuild_setRpmBuildDir
1156
1157 [[ -f "${RPM_BUILD_DIR%/}/.EXCLUDE" ]] && [[ -n $(cat "${RPM_BUILD_DIR%/}/.EXCLUDE") ]] && echo "$( \
1158 [[ -n $(cat "${RPM_BUILD_DIR%/}/.EXCLUDE" | grep '.src.rpm$') ]] && echo "$(cat ${RPM_BUILD_DIR%/}/.EXCLUDE | grep '.src.rpm$')"; \
1159 [[ -n $(cat "${RPM_BUILD_DIR%/}/.EXCLUDE" | grep -v '.src.rpm$' | grep -v '.rpm$') ]] && echo "$(srpmAutoBuild_getSRPM_fromRPM $(echo "$(cat ${RPM_BUILD_DIR%/}/.EXCLUDE | grep -v '.src.rpm$' | grep -v '.rpm$')"))"; \
1160 )" | sed -E s/'^.*\/([^\/]*)$'/'\1'/ | grep -v "None" | sort -u
1161}
1162
1163
1164srpmAutoBuild_listDownloadRPMs() {
1165 # generate a list of RPMs to actually download SRPMs for. This is a combination of unbuilt (but available) SRPMS and SRPMs that have an updated version (vs the version that was built)
1166
1167 [[ ${1,,} =~ ^-+s((hort|imple)(-?names?))?(\+a(rch(itecture)?)?)?$ ]] && echo "$(srpmAutoBuild_listUnbuiltRPMs "${1}") $(srpmAutoBuild_listUpgradeRPMs "${1}")" | sort -u || echo "$(srpmAutoBuild_listUnbuiltRPMs) $(srpmAutoBuild_listUpgradeRPMs)" | sort -u
1168}
1169
1170
1171srpmAutoBuild_listDownloadRPMs_ALL() {
1172 # generated a list of RPMs to actually download SRPMs for, using all 3 naming styles
1173
1174 echo "$(srpmAutoBuild_listDownloadRPMs; srpmAutoBuild_listDownloadRPMs -s; srpmAutoBuild_listDownloadRPMs -s+a)" | sort -u
1175}
1176
1177
1178srpmAutoBuild_downloadBuildableSRPMs() {
1179 # Download (to the current directory) all build-able SRPMs that are available. Try looking using both `dnf --download source <RPM names>` and `dnf download <SRPM names>`
1180
1181 srpmAutoBuild_setEnvVars
1182
1183 local rpmDownloadList1=""
1184 local rpmDownloadList2=""
1185 local rpmDownloadList3=""
1186 local rpmDownloadList=""
1187 local srpmDownloadList=""
1188
1189 rpmDownloadList1="$(srpmAutoBuild_listDownloadRPMs)"
1190 rpmDownloadList2="$(srpmAutoBuild_listDownloadRPMs -s)"
1191 rpmDownloadList3="$(srpmAutoBuild_listDownloadRPMs -s+a)"
1192
1193 rpmDownloadList="$(echo ${rpmDownloadList1} ${rpmDownloadList2} ${rpmDownloadList3})"
1194
1195 srpmDownloadList="$(srpmAutoBuild_getSRPM_fromRPM ${rpmDownloadList} | sed -E s/'^(.*)\.rpm'/'\1'/ | sort -u)"
1196
1197 if [[ ${1,,} =~ ^-+enable(-?all)?-?repos?$ ]] ; then
1198 [[ -n ${rpmDownloadList} ]] && dnf download --source --best --skip-broken -y --enablerepo=[a-z]* $([[ ${1,,} =~ ^-+enable-?all-?repos?$ ]] || echo '--disablerepo=*testing*') ${rpmDownloadList}
1199 [[ -n ${srpmDownloadList} ]] && dnf download --best --skip-broken -y --enablerepo=[a-z]* $([[ ${1,,} =~ ^-+enable-?all-?repos?$ ]] || echo '--disablerepo=*testing*') ${srpmDownloadList}
1200 else
1201 [[ -n ${rpmDownloadList} ]] && dnf download --source --best -y --skip-broken ${rpmDownloadList}
1202 [[ -n ${srpmDownloadList} ]] && dnf download --best -y --skip-broken ${srpmDownloadList}
1203 fi
1204
1205 #rpmDownloadList_wget="${rpmDownloadList1}"
1206 #archListA=(${VALID_ARCH_LIST})
1207 #for nn in "${archListA[@]}"; do
1208 # rpmDownloadList_wget="${rpmDownloadList_wget//.${nn%/}/}"
1209 #done
1210 #rpmDownloadList_wget="$(echo "${rpmDownloadList_wget}" | sed -E s/'^(.*)\.rpm$'/'\1'/ | sed -E s/'^(.*)\.src$'/'\1'/)"
1211
1212 #$(echo "${rpmDownloadList_wget}" | sed -E s/'^(.*)-([^-]*)-([^\. t]*(\.[^\. \t]*)*)[ \t]*$'/'wget https\:\/\/kojipkgs\.fedoraproject\.org\/\/packages\/\1\/\2\/\3\/src\/ -O \1-\2\.\3\.src\.rpm\; '/ | grep 'https')
1213
1214 #eval $(echo "${rpmDownloadList_wget}" | sed -E s/'^((.*)-([^-]*)-([^\.]*\.[^\.]*)\.src)(\.rpm)?$'/'wget https\:\/\/kojipkgs\.fedoraproject\.org\/\/packages\/\2\/\3\/\4\/src\/\1\.rpm\;'/)
1215
1216 #eval $(echo "${rpmDownloadList_wget}" | sed -E s/'^(.*)-([^-]*)-([^\.]*\.[^\.]*)[ \t]*$'/'https\:\/\/kojipkgs\.fedoraproject\.org\/\/packages\/\1\/\2\/\3\/src\/\1-\2\.\3\.src\.rpm\;'/ | sed -E s/' '//g | sed -E s/'^(.*)$'/'wget '"'"'\1'"'"''/)
1217
1218 #dnf download --source --skip-broken $(srpmAutoBuild_listDownloadRPMs) $(echo "$(srpmAutoBuild_listBuiltSRPMs)" "$(srpmAutoBuild_listExcludedSRPMs)" | sort -u | sed -E s/'^(.*)\.src\.rpm$'/'-x \1'/)
1219 #dnf download --source --skip-broken $(diff -ywd --width=512 <(dnf check-upgrade) <(dnf list --installed) --suppress-common-lines | grep -E '[\<\|]' | sed -E s/'^([^ \t]*)[ \t].*$'/'\1'/ | sed -zE s/'^(.*)\nObsoleting.*$'/'\1\n'/)
1220}
1221
1222
1223srpmAutoBuild_listNewestRPMs() {
1224 # Scans through the SRPMs in the current directory (or the directory specified by function inputs, if it exists and it valid)
1225 # and returns the names of the newest version of each SRPM package. Useful to filter out old SRPMs mixed with new ones.
1226 #
1227 # scans $(pwd) unless input function exists and is a existing valid directory.
1228 #
1229 # use flag '-nr' or '--no-recursive' or '--no-recusrion' to only scan the top-level directories. otherwise the specified directories are scanned recursivelty
1230 # use flag --exclude=<...> to apply a regex-based filter (via `grep -vE`) to exclude matches
1231
1232 local rpmPath=""
1233 local inTemp=""
1234 local nn=""
1235 local rFlag=""
1236 local grepFilter=""
1237
1238 (( $# > 0 )) && [[ ${*,,} =~ ^(.+\ )?-+no?-?r(ecursi(ve|on)?)?(\ .+)?$ ]] && rFlag='-maxdepth 1'
1239
1240 inTemp="$(echo "$(for nn in "${@}"; do echo "${nn}"; done)" | while read -r nn; do if [[ "${nn}" =~ ^-+exclude=.*$ ]]; then grepFilter="${grepFilter}"'|('"${nn##*-exclude=}"')' && echo "${grepFilter}"; else [[ -e "${nn}" ]] && echo "${nn}"; fi; done)"
1241
1242 grepFilter="$(echo "${inTemp}" | grep -E '^\|' | sed -E s/'^\|(.*)$'/'\1'/ | tail -n 1)"
1243 inTemp="$(echo "${inTemp}" | grep -vE '^\|')"
1244
1245 rpmPath="$( [[ -z "${inTemp}" ]] && echo "$(pwd)" || echo "${inTemp}" | while read -r nn; do
1246 [[ -e "${nn}" ]] && echo "${nn}";
1247 done | while read -r nn; do
1248 if [[ -d "${nn}" ]]; then
1249 find "${nn}" ${rFlag} -type f -name "*.rpm" | grep -v cache | grep -v 'debug';
1250 else
1251 [[ "${nn,,}" == *.rpm ]] && echo "${nn}";
1252 fi
1253 done | sort -V)"
1254
1255 [[ -n "${grepFilter}" ]] && rpmPath="$(echo "${rpmPath}" | grep -vE '('"${grepFilter}"')')"
1256
1257 echo "${rpmPath}" | grep -E '\.src\.rpm$' | sort -Vr | while read -r nn; do echo "${nn} | $(srpmAutoBuild_getInfo -n "${nn}" 2>/dev/null)"; done | sort -u -k 2 -t '|' | sed -E s/'^(.*) \| .*$'/'\1'/
1258 echo "${rpmPath}" | grep -vE '\.src\.rpm$' | sort -Vr | while read -r nn; do echo "${nn} | $(srpmAutoBuild_getInfo -n "${nn}" 2>/dev/null)"; done | sort -u -k 2 -t '|' | sed -E s/'^(.*) \| .*$'/'\1'/
1259
1260}
1261
1262
1263#srpmAutoBuild_listNewestRPMs_OLD() {
1264# # Scans through the SRPMs in the current directory (or the directory specified by function inputs, if it exists and it valid)
1265# # and returns the names of the newest version of each SRPM package. Useful to filter out old SRPMs mixed with new ones.
1266# #
1267# # scans $(pwd) unless input function exists and is a existing valid directory.
1268# #
1269# # make 1st input '-r' to scan directories recursively. otherwise only the top level of the specified directories are scanned
1270# #
1271# # optional: hard code your choosen info function. using 'infoFunctionType' variable. valid options are 'getInfo' and 'getRpmNames'.
1272# # 'getInfo' is more robust (especially for filename inputs), but is slower (especially for directory inputs)
1273# # speed: getInfo is ~1/2 the speed for filelist inputs and ~1/10 the speed for directory inputs.
1274# # default is to use 'getInfo' for file list inputs and 'getRpmNames' for directory inputs
1275#
1276#
1277# local -a pkgAllA
1278# local pkgAll=""
1279# local pkgCur=""
1280# #local pkgNew=""
1281# local nameCur=""
1282# local nameNew=""
1283# local rFlag=0
1284#
1285# local infoFunctionType=""
1286# # infoFunctionType='getInfo'
1287# # infoFunctionType='getRpmNames'
1288#
1289# if [[ "${infoFunctionType}" != 'getInfo' ]] && [[ "${infoFunctionType}" != 'getRpmNames' ]]; then
1290# [[ -d "${*}" ]] && infoFunctionType='getRpmNames' || infoFunctionType='getInfo'
1291# fi
1292#
1293# (( $# > 0 )) && [[ ${1,,} =~ ^-+r$ ]] && rFlag=1 && shift 1
1294#
1295# pkgAllA=($(echo "$(eval "$(echo "${@}" | grep -E '\.rpm$' | sed -E s/'^(.*)$'/'\[\[ -f "\1" \]\] \&\&'/ | sed -zE s/'\n'/' '/g | sed -zE s/'^(.*) \&\& $'/'\1'/)" && echo "${@}" | grep -E '\.rpm$' || find "$( (( $# > 0 )) && [[ -d "${*}" ]] && echo "${*}" || echo "$(pwd)" )" $( (( $rFlag == 0 )) && echo -n '-maxdepth 1' || echo -n '' ) -type f -name "*.rpm" | sort -V)"))
1296#
1297# pkgCur="${pkgAllA[0]}"
1298# pkgAll=""
1299#
1300# if [[ "${infoFunctionType}" == 'getRpmNames' ]]; then
1301# local -a nameAll=""
1302# local kk=1
1303#
1304# if [[ -d "${*}" ]]; then
1305# nameAll=($(srpmAutoBuild_getRpmNames "$(echo "${pkgAllA[*]}" | sed -E s/'\.rpm \/'/'\.rpm\n\/'/g | sed -E s/'^(.*)\/[^\/]+$'/'\1'/ | sort -u)"))
1306# else
1307# nameAll=($(srpmAutoBuild_getRpmNames "${pkgAllA[@]}"))
1308# fi
1309#
1310# nameCur="${nameAll[0]}"
1311# nameAll[0]=""
1312# nameAll=( "${nameAll[@]}" )
1313#
1314# else
1315# nameCur="$(srpmAutoBuild_getInfo -n -v -a "$(echo -n "${pkgCur}")")"
1316# fi
1317#
1318# for nn in "${pkgAllA[@]}"; do
1319# [[ "${infoFunctionType}" == 'getInfo' ]] && nameNew="$(srpmAutoBuild_getInfo -n -v -a "$(echo -n "${nn}")")"
1320# [[ "${infoFunctionType}" == 'getRpmNames' ]] && nameNew="${nameAll[$kk]}" && ((kk++))
1321#
1322# if [[ "${nameCur}" != "${nameNew}" ]]; then
1323# pkgAll="$(echo "$(echo "${pkgAll}"; echo "${pkgCur##*/}" | sort -V | tail -n 1)")"
1324# pkgCur="${nn}"
1325# nameCur="${nameNew}"
1326# else
1327# pkgCur="$(echo "$(echo "${pkgCur}"; echo "${nn}")")"
1328# fi
1329# done
1330#
1331# pkgAll="$(echo "$(echo "${pkgAll}"; echo "${pkgCur##*/}" | sort -V | tail -n 1)" | sort -u | sort -V)"
1332#
1333# echo "${pkgAll}"
1334#}
1335
1336
1337srpmAutoBuild_listFunctionNames() {
1338 # lists all function names
1339 # flag '-s' / '-sab' / '--srpm[AutoBuild]' --> only list 'srpmAutoBuild_' functions
1340 # flag '-l' / '--localrepo' --> only list 'localrepo_' functions
1341 # default: list both 'srpmAutoBuild_' functions and 'localrepo_' functions
1342
1343 local filterString=""
1344
1345 (( $# > 0 )) && [[ ${1,,} =~ -+s((ab)?|(rpm(-?(auto)?(-?(build))))) ]] && filterString='srpmAutoBuild'
1346 (( $# > 0 )) && [[ ${1,,} =~ -+l((ocal)?-?r(epo)?)? ]] && filterString='localrepo'
1347 [[ -z "${filterString}" ]] && filterString='((srpmAutoBuild)|(localrepo))'
1348
1349 cat "/usr/local/bin/my-scripts/srpmAutoBuild.sh" | grep -E '^'"${filterString}"'_[^ ]+\(\) \{' | sed -E s/'^(.*)\(\) \{.*$'/'\1'/
1350}
1351
1352
1353srpmAutoBuild_searchFunctionNames() {
1354 # searches the list of function names for matching ones. Accepts globs
1355 # flag: '-n' --> dontadd newlines yto the response
1356
1357 local nn=""
1358 local useNewlines=1
1359
1360 (( $# > 0 )) && [[ "${1,,}" == "-n" ]] && useNewlines=0 && shift 1
1361
1362 (( $# == 0 )) && srpmAutoBuild_listFunctionNames && return
1363
1364 for nn in "${@}"; do
1365 (( $useNewlines == 1 )) && echo ""
1366 echo -n "$( srpmAutoBuild_listFunctionNames | grep -E "$(srpmAutoBuild_escapeRegexChars -g "${nn}")"; srpmAutoBuild_listFunctionNames | grep -F "${nn}" )" | sort -u
1367 (( $useNewlines == 1 )) && echo -e "\n--------------------------------------------------------------------------------\n" >&2
1368 done
1369}
1370
1371
1372srpmAutoBuild_help() {
1373 # searches for the specified name and returns the header help text. accepts globs
1374
1375 #local funcNameList=""
1376 local inCur=""
1377 local -a funcNamesCur
1378 local funcNameCur0=""
1379
1380 #funcNameList="$(srpmAutoBuild_listFunctionNames)"
1381
1382 (( $# == 0 )) && echo -e "\n\nTo get help with a specific function, run 'srpmAutoBuild_help <functionName>'. \n\nRun 'srpmAutoBuild_listFunctionNames' and/or 'srpmAutoBuild_searchFunctionNames <...>' to see valid srpmAutoBuild_ and localrepo_ function names.\n\n" && sleep 2 && cat "/usr/local/bin/my-scripts/srpmAutoBuild.sh" | sed -zE s/'^([^\n]*(\n[ \t]*\#[^\n]*)*).*$'/'\1'/ && echo -e "\n\n" && return
1383
1384 for inCur in "${@}"; do
1385 echo ""
1386 funcNamesCur=("$(srpmAutoBuild_searchFunctionNames -n "${inCur}")")
1387
1388 if [[ -z "${funcNamesCur[*]}" ]]; then
1389 echo "Input not recognized as a valid 'srpmAutoBuild_' or 'localrepo_' function name" >&2
1390 else
1391 for funcNameCur0 in "${funcNamesCur[@]}"; do
1392 cat "/usr/local/bin/my-scripts/srpmAutoBuild.sh" | sed -zE s/'^.*(\n'"$(srpmAutoBuild_escapeRegexChars "${funcNameCur0}")"'\(\) \{ *(\n[ \t]*(#[^\n]*)?)*).*$'/'\1'/
1393 echo ""
1394 done
1395 fi
1396
1397 echo -e "\n"
1398 (( $# > 0 )) && echo -e "--------------------------------------------------------------------------------\n\n" >&2
1399 done
1400}
1401
1402
1403srpmAutoBuild_makeAliases() {
1404 # replace the leading "srpmAutoBuild" and "localrepo" in function names with something shorter
1405 # input #1 defines srpmAutoBuild replacement, default if missing is 'sab'
1406 # input #2 defines localrepo replacement, default if missing is 'lr'
1407
1408 local srpmAutoBuild_abbr=""
1409 local localrepo_abbr=""
1410
1411 (( $# < 1 )) && srpmAutoBuild_abbr="sab" || srpmAutoBuild_abbr="${1}"
1412 (( $# < 2)) && localrepo_abbr="lr" || localrepo_abbr="${2}"
1413
1414 [[ -n ${srpmAutoBuild_abbr} ]] && eval $(cat "/usr/local/bin/my-scripts/srpmAutoBuild.sh" | grep -E '^srpmAutoBuild_[^ ]+\(\) \{' | sed -E s/'^(.*)\(\) \{.*$'/'\1'/ | sed -E s/'^(srpmAutoBuild)(.*)$'/'alias '"$(srpmAutoBuild_escapeRegexChars "${srpmAutoBuild_abbr}")"'\2='"'"'\1\2'"'"';'/)
1415
1416 [[ -n ${localrepo_abbr} ]] && eval $(cat "/usr/local/bin/my-scripts/srpmAutoBuild.sh" | grep -E '^localrepo_[^ ]+\(\) \{' | sed -E s/'^(.*)\(\) \{.*$'/'\1'/ | sed -E s/'^(localrepo)(.*)$'/'alias '"$(srpmAutoBuild_escapeRegexChars "${localrepo_abbr}")"'\2='"'"'\1\2'"'"';'/)
1417}
1418
1419
1420srpmAutoBuild_setRpmBuildDir() {
1421 # determines top level of rpm tree. In mock this is at /builddir/build, otherwise it is at ~/rpmbuild
1422 # for non-standard rpm build dirs set + export RPM_BUILD_DIR manually. If RPM_BUILD_DIR has been set externally and exported as a global environment variable this will NOT overwrite it. UNLESS input Flag '-c' or '--clear' or '--clean' is used
1423 #
1424 # Note: behavior is as follows:
1425 # # (1.) check if RPM_BUILD_DIR exists, and if so about, else
1426 # # (2.) check if we are in mock, if so return /builddir/build, else
1427 # # (3.) check if mock filesystem exists, if so return ${MOCK_ROOT_DIR%/}/builddir/build, else
1428 # # (4.) return ${HOME%/}/rpmbuild
1429 #
1430 # Note: this will also set / export MOCK_ROOT_DIR, so if calling this function there is no need to call srpmAutoBuild_setMockRootDir also
1431
1432 local cleanFlag=""
1433 local RPM_BUILD_DIR_orig="${RPM_BUILD_DIR}"
1434
1435 [[ ${1,,} =~ ^-+c(lea[nr])?$ ]] && cleanFlag="-c"
1436 [[ -n "${RPM_BUILD_DIR}" ]] && ( ( srpmAutoBuild_isMock && [[ ${RPM_BUILD_DIR} == /var/lib/mock/* ]] ) || ( ! srpmAutoBuild_isMock && [[ ${RPM_BUILD_DIR} != /var/lib/mock/* ]] && [[ "${RPM_BUILD_DIR}" != "${HOME%/}/rpmbuild" ]] ) ) && cleanFlag="-c"
1437
1438 srpmAutoBuild_setMockRootDir "${cleanFlag}"
1439
1440 if [[ -z "${RPM_BUILD_DIR}" ]] || [[ "${cleanFlag}" == "-c" ]]; then
1441
1442 if srpmAutoBuild_isMock; then
1443 RPM_BUILD_DIR='/builddir/build'
1444 else
1445 [[ "${MOCK_ROOT_DIR}" != "NONE" ]] && RPM_BUILD_DIR="${MOCK_ROOT_DIR%/}/builddir/build" || RPM_BUILD_DIR="${HOME%/}/rpmbuild"
1446 fi
1447
1448 elif [[ "${RPM_BUILD_DIR}" == "${RPM_BUILD_DIR%/}" ]] || [[ "${RPM_BUILD_DIR}" == *'//'* ]]; then
1449
1450 RPM_BUILD_DIR="${RPM_BUILD_DIR//'//'/'/'}"
1451 RPM_BUILD_DIR="${RPM_BUILD_DIR%/}"
1452
1453 fi
1454
1455 [[ "${RPM_BUILD_DIR}" != "${RPM_BUILD_DIR_orig}" ]] && echo -e "RPM_BUILD_DIR set to: '${RPM_BUILD_DIR}'" >&2 && export RPM_BUILD_DIR
1456
1457 [[ "${RPM_BUILD_DIR}" != "${MOCK_ROOT_DIR%/}/builddir/build" ]] && [[ ! -d "${RPM_BUILD_DIR}" ]] && srpmAutoBuild_setuptree
1458
1459}
1460
1461
1462srpmAutoBuild_isMock() {
1463 # determines if we are currently in mock or not
1464 # example usage: $(srpmAutoBuild_isMock) && $(commandToRunInMock) || $(commandToRunInHostOS)
1465
1466 (( $((( $( [[ "${PROMPT_COMMAND}" == *'<mock-chroot>'* ]] && echo 1 || echo 0 ) + $( [[ -n "$(env | grep 'PS1')" ]] && [[ "$(env | grep 'PS1')" == *'<mock-chroot>'* ]] && echo 1 || echo 0 ) ))) > 0 )) && return 0 || return 1
1467
1468}
1469
1470
1471
1472srpmAutoBuild_getMockName() {
1473 # get mock name. Should be something like '$(distro)-$(ver)-$(arch)' (ex: 'fedora-29-x86_64')
1474 # setr/export the environment variable 'SRPMAUTOBUILD_SETVERSION_MOCK' to force a specific mock version. Otherwise mock will be setup to use the same distro / os version / arch as the host system.
1475
1476 if [[ -n "${SRPMAUTOBUILD_SETVERSION_MOCK}" ]]; then
1477 [[ ! -d "/var/lib/mock/${SRPMAUTOBUILD_SETVERSION_MOCK}" ]] && [[ ! -f "/etc/mock/${SRPMAUTOBUILD_SETVERSION_MOCK}.cfg" ]] && echo -e "\n\nWARNING: The mock version set by environment variable SRPMAUTOBUILD_SETVERSION_MOCK does not appear to be a valid mock version installed on this system. \nsrpmAutoBuild will still attempt to use it. If this is an error, manually abourt code execution and either re-set/re-export or clear/remove SRPMAUTOBUILD_SETVERSION_MOCK \n" 1>&2
1478 echo "${SRPMAUTOBUILD_SETVERSION_MOCK}" && return
1479 fi
1480
1481 local distro=""
1482 distro="$(sed 's, release .*$,,g' /etc/system-release)"
1483
1484 echo "${distro,,}-$(uname -r | sed -E s/'.*\.fc([0-9]+\.[^\.]+)$'/'\1'/ | sed -E s/'\.'/'-'/)"
1485}
1486
1487
1488srpmAutoBuild_setMockRootDir() {
1489 # determines where the root of the mock environment is. This should return /var/lib/mock/*/root when run from from the main OS, and '/' when run from within mock. If MOCK_ROOT_DIR has been set externally and exported as a global environment variable this will NOT overwrite it.
1490
1491 local cleanFlag=""
1492 local MOCK_ROOT_DIR_orig="${MOCK_ROOT_DIR}"
1493
1494 [[ ${1,,} =~ ^-+c(lea[nr])?$ ]] && cleanFlag="-c"
1495
1496 [[ -n "${MOCK_ROOT_DIR}" ]] && ( ( srpmAutoBuild_isMock && [[ ${MOCK_ROOT_DIR} == /var/lib/mock/* ]] ) || ( ! srpmAutoBuild_isMock && [[ ${MOCK_ROOT_DIR} != /var/lib/mock/* ]] ) ) && cleanFlag="-c"
1497
1498 if [[ -z "${MOCK_ROOT_DIR}" ]] || [[ "${cleanFlag}" == "-c" ]]; then
1499
1500 srpmAutoBuild_isMock && MOCK_ROOT_DIR='' || MOCK_ROOT_DIR="$(mock -r "$(srpmAutoBuild_getMockName)" -p | sed -E s/'^(.*)\/$'/'\1'/)"
1501
1502 elif [[ "${MOCK_ROOT_DIR}" != "${MOCK_ROOT_DIR%/}" ]]; then
1503
1504 MOCK_ROOT_DIR="${MOCK_ROOT_DIR%/}"
1505
1506 fi
1507
1508 [[ "${MOCK_ROOT_DIR}" != "${MOCK_ROOT_DIR_orig}" ]] && echo -e "MOCK_ROOT_DIR set to: '${MOCK_ROOT_DIR}'" >&2 && export MOCK_ROOT_DIR
1509
1510}
1511
1512
1513srpmAutoBuild_setEnvVars() {
1514 # sets build environment variables + shortened aliases. These can be used, for example, to pass FLAGS about the system architecture and optimization level to gcc via the "CFLAGS/CPPFLAGS/CXXFLAGS/LDFLAGS" environment variables
1515 #
1516 # NOTE: any function inputs (except the flags listed below) will be added to the CFLAGS_DEFAULT variables specified below.
1517 # i.e., function inputs will be added to CFLAGS/CPPFLAGS/CXXFLAGS, but not LDFLAGS.
1518 # by default, LD flags only is set via the OFLAGS_DEFAULT, which sets default optimization level ('-O3', '-O2', etc)
1519 #
1520 # SPECIAL CASE : if the 1st input is the Flag '-c' or --clean' or '--clear', the default [CO]FLAGS_DEFAULT variables will not be used.
1521 #
1522 # ---------------------- FLAGS ----------------------
1523 #
1524 # DEFAULT behavior is to set CFLAGS/CPPFLAGS/CXXFLAGS/LDFLAGS + clear/re-set RPM_BUILD_DIR + set (if not already set) LOCALREPO_DIR
1525 # (note: use of '...clea[nr]' means you can use either '...clean' or '...clear')
1526 #
1527 # '-nc' or '--no-clea[nr]': if RPM_BUILD_DIR is already set, dont re-set it (so it has the same behavior as setting LOCALREPO_DIR)
1528 # '-ce' or '--clea[nr]-env': clear/re-set LOCALREPO_DIR (so it has the same behavior as setting RPM_BUILD_DIR)
1529 # '-c' or '--clea[nr]': do not use the default CFLAGS_DEFAULT and OFLAGS_DEFAULT when setting CFLAGS/CPPFLAGS/CXXFLAGS/LDFLAGS
1530 # This will clear LDFLAGS (i.e., set it to "") and will set CFLAGS/CPPFLAGS/CXXFLAGS to the function input(s) (minus flag(s))
1531 # If no additional function inputs are present (other than any flags), this will effectively un-set the CFLAGS/CPPFLAGS/CXXFLAGS variables completely
1532 # See below for more info (go to the line that says '# SET THESE, UNLESS YOU HAVE A SKYLAKE-X OR SKYLAKE-XEON CPU!!!')
1533 # '-cf' or '--clea[nr]-flags': this does the same as using '-c' or '--clean', and exists only to make it explicity clear that it controls setting [C|CXX|CPP|LD]FLAGS
1534 # '-ca' or '--clea[nr]-all': This is the same as setting both '-c(f)?'/'--clea[nr](-flags)?' and '-ce'/'-clea[nr]-env'
1535
1536 # Setup Environment Variables
1537
1538 local CFLAGS_DEFAULT=""
1539 local OFLAGS_DEFAULT=""
1540
1541 (( $# > 0 )) && [[ ${1,,} =~ ^-+no?-?c(lea[nr])?$ ]] && srpmAutoBuild_setRpmBuildDir || srpmAutoBuild_setRpmBuildDir -c
1542 (( $# > 0 )) && [[ ${1,,} =~ ^-+c(lea[nr])?-?((a(ll)?)|(e(nv)?))$ ]] && localrepo_setEnvVars -c || localrepo_setEnvVars
1543 (( $# > 0 )) && [[ ${1,,} =~ ^-+((no?-?c(lea[nr])?)|(c(lea[nr])?-?e(nv)?))$ ]] && shift 1
1544
1545 srpmAutoBuild_rpmbuildCheck
1546 srpmAutoBuild_makeAliases
1547
1548 if (( $# > 0 )) && [[ ${1,,} =~ ^-+c(lea[nr])?(-?((a(ll)?)|(f(lags?)?)))?$ ]]; then
1549 shift 1
1550
1551 else
1552 # SET THESE, UNLESS YOU HAVE A SKYLAKE-X OR SKYLAKE-XEON CPU!!!
1553 #
1554 # CFLAGS_DEFAULT apply to CFLAGS/CPPFLAGS/CXXFLAGS but not LDFLAGS
1555 # OFLAGS_DEFAULT apply to all 4 (CFLAGS/CPPFLAGS/CXXFLAGS/LDFLAGS)
1556 #
1557 # You can get better performance if you change these based on your hardware.
1558 # See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for more info.
1559
1560 if [[ -n "$(cat /proc/cpuinfo | grep 'avx512')" ]]; then
1561 # assume we have a skylake-x or skylake-xeon. This will become a worse and worse assumption as more avx512 processors are released, but for now it should be mostly correct.
1562 CFLAGS_DEFAULT="-m64 -march=skylake-avx512 -mtune=skylake-avx512 -mprefer-vector-width=512 -mavx512f -mavx512vl -mavx512cd -mavx512bw -mavx512dq"
1563 OFLAGS_DEFAULT="-O3"
1564 else
1565 CFLAGS_DEFAULT="-march=native -mtune=generic"
1566 OFLAGS_DEFAULT="-O2"
1567 fi
1568
1569 [[ ${1,,} =~ ^-+((c(lea[nr])?-?((a(ll)?)|(e(nv)?)|(f(lags?)?)))|(no?-?c(lea[nr])?))$ ]] && shift 1
1570 fi
1571
1572 if (( $# > 0 )); then
1573 CFLAGS_DEFAULT="${CFLAGS_DEFAULT} ${*}"
1574 fi
1575
1576 CFLAGS="${CFLAGS_DEFAULT} ${OFLAGS_DEFAULT}"
1577 CPPFLAGS="${CFLAGS_DEFAULT} ${OFLAGS_DEFAULT}"
1578 CXXFLAGS="${CFLAGS_DEFAULT} ${OFLAGS_DEFAULT}"
1579 LDFLAGS="${OFLAGS_DEFAULT}"
1580
1581 export CFLAGS
1582 export CPPFLAGS
1583 export CXXFLAGS
1584 export LDFLAGS
1585
1586 srpmAutoBuild_isMock && NO_SRPM_AUTO_BUILD_ROOT_CHECK_FLAG='TRUE' && export NO_SRPM_AUTO_BUILD_ROOT_CHECK_FLAG
1587
1588}
1589
1590
1591srpmAutoBuild_getTotalMem() {
1592 # grabs total system memory from /proc/meminfo. Output is in K[ilobytes] (same as used in /proc/meminfo )
1593
1594 cat "/proc/meminfo" | grep '^MemTotal' | sed -E s/'^[^0-9]*([0-9]*)[^0-9]**$'/'\1'/
1595}
1596
1597
1598srpmAutoBuild_rpmbuildCheck() {
1599 # checks that rpm build is installed. If missing asks the user to install it (requires sudo). If they refuse, exit the srpmAutoBuild.
1600
1601 if ! [[ -f /usr/bin/rpmbuild ]]; then
1602 # check that rpmbuild is installed. This isnt checked for by the standard build dependency checks
1603 local userResponse
1604 echo -n -e "\n\nRPMBUILD is required to build SRPMs. Would you like to automatically download and install it from using DNF? \n\n(Y/n) \t " >&2
1605 read userResponse
1606 if [[ ${userResponse,,} =~ ^no?$ ]]; then
1607 echo "rpmbuild will not be downloaded and installed. Exiting srpmAutoBuild." >&2
1608 exit
1609 else
1610 dnf install -y rpmbuild
1611 fi
1612 fi
1613}
1614
1615
1616srpmAutoBuild_rootUserCheck() {
1617 # Checks whether the user who called this function is root. If not, they are prompted to re-run the command as root.
1618
1619 history 1 | sed -E s/'[ \t]*[0-9]*[ \t]*([^ \t].*)[ \t]*$'/'\1'/
1620
1621 if [[ "${NO_SRPM_AUTO_BUILD_ROOT_CHECK_FLAG}" == "TRUE" ]] || [[ -z "${USER}" ]] || [[ "${USER}" == "root" ]] || [[ "$(history 1 | sed -E s/'[ \t]*[0-9]*[ \t]*([^ \t].*)[ \t]*$'/'\1'/)" =~ ^((exit)|(srpmAutoBuild_mock-chroot0?[\ \t]*.*))$ ]]; then
1622 return
1623
1624 else
1625 local userResponse_RunAsRoot
1626
1627 echo -e "\n\nWARNING: This code is not being run as the root user. (Detected user: ${USER}) \nMany functions will not work properly when run as a user other than root. \n\nWould you like to have the code modify itself to run as root? (timeout = 15 seconds) \n\ny[es]: (DEFAULT) automatically switch to run as root. \nn[o]: continue running as the current user. \nq[uit]: quit srpmAutoBuild \n\nSPECIAL CASE: Respon with 'NO STOP' (case-sensitive) to continue running as the current user AND do not ask again (can be reset by clearing global variable 'NO_SRPM_AUTO_BUILD_ROOT_CHECK_FLAG') \n" >&2
1628 read -ie -p "(Y/n/q): " -t 15 userResponse_RunAsRoot
1629
1630 [[ ${userResponse_RunAsRoot,,} =~ ^q(uit)?$ ]] && exit
1631
1632 [[ "${userResponse_RunAsRoot}" == "NO STOP" ]] && NO_SRPM_AUTO_BUILD_ROOT_CHECK_FLAG=TRUE && export NO_SRPM_AUTO_BUILD_ROOT_CHECK_FLAG && userResponse_RunAsRoot="no"
1633
1634 if ! [[ ${userResponse_RunAsRoot,,} =~ ^no?$ ]]; then
1635
1636 su -p -c "source /root/.bashrc; source /usr/local/bin/my-scripts/srpmAutoBuild.sh; sleep 2; $(echo "$(history 1)" | sed -E s/'^[^0-9]*[0-9]*[^0-9a-zA-Z]*([0-9a-zA-Z].*)$'/'\1'/)" && exit
1637 fi
1638 fi
1639
1640}
1641
1642
1643srpmAutoBuild_setuptree() {
1644 # setup directories used by srpmAutoBuild
1645
1646 [[ -z ${RPM_BUILD_DIR} ]] && srpmAutoBuild_setRpmBuildDir
1647
1648 # ensure standard rpm build tree is setup at ${RPM_BUILD_DIR}
1649 # [[ -f /usr/bin/rpmdev-setuptree ]] && rpmdev-setuptree # this doesnt allow for non-standard build tree locations
1650
1651 RPM_BUILD_DIR="${RPM_BUILD_DIR%/}"
1652 # make directories as long as the direcytory immediately under ${RPM_BUILD_DIR} exists. This prevents making directories in an un-initiated mock environment.
1653 if [[ -d "${RPM_BUILD_DIR%/*}" ]]; then
1654 [[ -d "${RPM_BUILD_DIR}" ]] || mkdir "${RPM_BUILD_DIR}"
1655 [[ -d "${RPM_BUILD_DIR%/}/SPECS" ]] || mkdir "${RPM_BUILD_DIR%/}/SPECS"
1656 [[ -d "${RPM_BUILD_DIR%/}/SRPMS" ]] || mkdir "${RPM_BUILD_DIR%/}/SRPMS"
1657 [[ -d "${RPM_BUILD_DIR%/}/RPMS" ]] || mkdir "${RPM_BUILD_DIR%/}/RPMS"
1658 [[ -d "${RPM_BUILD_DIR%/}/SOURCES" ]] || mkdir "${RPM_BUILD_DIR%/}/SOURCES"
1659 [[ -d "${RPM_BUILD_DIR%/}/BUILD" ]] || mkdir "${RPM_BUILD_DIR%/}/BUILD"
1660 [[ -d "${RPM_BUILD_DIR%/}/BUILDROOT" ]] || mkdir "${RPM_BUILD_DIR%/}/BUILDROOT"
1661 fi
1662
1663 # make sure the user owns the entire rpmbuild tree
1664 #chown -R ${USER}:${USER} "${RPM_BUILD_DIR}"
1665
1666}
1667
1668
1669srpmAutoBuild_getRpmNames() {
1670 # gets list of SRPM/RPM package names from all SRPM/RPM packages in the present working directory, or from the directory or (S)RPM package name given as a function input.
1671 # These names are the raw package names, and do not include the version/distro/arch info that the (s)rpm filenames do.
1672 # Multiple directories / (S)RPMs can be given as input, and you can mix-and-match.
1673 # the output RPM names will strip off version and distro and arch info to return just the raw package names.
1674 #
1675 # show all flags: Use Flag '-i' or '--installed' or '-a' or '-all' to list all installed RPMs. This can be combined with a list of directories / (S)RPM names. This Flag does not need to be the 1st input - Results will be output in the same order they are input in.
1676 # '-a' and '--all' will cause the current directory RPM names to be listed after any function inputs have been processed (which is the behavior without any inputs). '-i' and '--installed' will not do this.
1677 #
1678 # recursive dir search Flag: use Flag '-r' or '--recursive' to make and directories passed to this function get searched recursively. Otherwise, only the top level of the specified directory will be scanned for (S)RPMs
1679
1680 local listCurDirFlag=0
1681 local -a inArray
1682 local inArrayCur=""
1683 local rpmNameList=""
1684 local rpmNameListTemp=""
1685 local recursionFlag=0
1686
1687 (( $# == 0 )) && [[ ${1,,} =~ ^-+r(ecursive)?$ ]] && recursionFlag=$(( $recursionFlag + 1 )) && shift 1
1688
1689 (( $# == 0 )) && listCurDirFlag=1 || inArray=("${@}")
1690
1691 if (( $listCurDirFlag == 0 )); then
1692
1693 for inArrayCur in "${inArray[@]}"; do
1694
1695 if [[ ${inArrayCur,,} =~ ^-+a(ll)?$ ]] || [[ ${inArrayCur,,} =~ ^-+i(nstall(ed)?)?$ ]]; then
1696
1697 # gets list of ALL installed RPM package names
1698 rpmNameList="$(echo "${rpmNameList}" && rpm --eval "$(rpm -qia | grep -E '^Name {8}\: ' | sed -E s/'^.*\: *(.*)$'/'\1'/ | sort -u)" | sort -u)"
1699
1700 [[ ${inArrayCur,,} =~ ^-+a(ll)?$ ]] && listCurDirFlag=1
1701
1702 elif [[ -d "${inArrayCur}" ]]; then
1703
1704 # get names packages in directory specified in input
1705 rpmNameListTemp="$(rpm -qip $( (( $recursionFlag > 0 )) && find "${inArrayCur}" -type f -name "*.rpm" || find "${inArrayCur}" -maxdepth 1 -type f -name "*.rpm" ) | grep -E '^Name {8}\: ' | sed -E s/'^.*\: *(.*)$'/'\1'/ | sort -u)"
1706 rpmNameList="$(echo "${rpmNameList}" && echo "${rpmNameListTemp}" | grep -v -E '\%{.+\}' && echo "$(rpm --eval "$(echo "${rpmNameListTemp}" | grep -E '\%{.+\}')")" | sort -u)"
1707
1708 elif [[ "${inArrayCur}" == *".rpm" ]] && [[ -f "${inArrayCur}" ]]; then
1709
1710 # get name of the specific package specified in input
1711 rpmNameList="$(echo "${rpmNameList}" && echo "$(rpm --eval "$(rpm -qip ${inArrayCur} | grep -E '^Name {8}\: ' | sed -E s/'^.*\: *(.*)$'/'\1'/ | sort -u)")" | sort -u)"
1712
1713 elif [[ -n "$(dnf info "$(echo "${inArrayCur%.rpm}" | sed -E s/'(.*)\.((src)|(noarch)|(x86_64)|(i686))$'/'\1'/)" 2>/dev/null)" ]]; then
1714
1715 # get name using `dnf info`
1716 rpmNameList="$(echo "${rpmNameList}" && echo "$(dnf info "$(echo "${inArrayCur%.rpm}" | sed -E s/'(.*)\.((src)|(noarch)|(x86_64)|(i686))$'/'\1'/)" | grep -E '^Name' | sed -E s/'^Name *\: (.*)$'/'\1'/)")"
1717 #echo "${inArrayCur%.rpm}" | sed -E s/'(.*)\.((src)|(noarch)|(x86_64)|(i686))$'/'\1'/
1718
1719 else
1720
1721 echo -e "\n\nWARNING: Input ${inArrayCur} was not found as a directory nor a (S)RPM package name/path. \nIf this is infact a valid path of a directory or (S)RPM package, this likely means you do not have permission to access the said directory or file. \nIn this case, you should either re-run this as a different user with access (e.g., root), or change the owner/permissions using chown/chmod. \n\n" >&2
1722
1723 rpmNameList="$(echo "${rpmNameList}" && echo "UNKNOWN")"
1724
1725 fi
1726
1727 done
1728
1729 fi
1730
1731 if (( $listCurDirFlag == 1 )); then
1732
1733 rpmNameList="$(echo "${rpmNameList}" && echo "$(rpm --eval "$(rpm -qip -- *.rpm | grep -E '^Name {8}\: ' | sed -E s/'^.*\: *(.*)$'/'\1'/ | sort -u)")")"
1734
1735 fi
1736
1737 echo "${rpmNameList}"
1738
1739}
1740
1741
1742
1743srpmAutoBuild_filterByIndex() {
1744 # Filter ${1} by the indices described in ${2}. This uses a "logical indexing" approach.
1745 # Looks for matches where ${2} is equal to the number specified in ${3}.
1746 # If ${#} is missing it looks for matched where ${2} == 1.
1747 # if the 2 arrays arent the same length, the longer one will be truncated to match the length of the shorter one
1748 #
1749 # NOTE: this should be called as: `srpmAutoBuild_filterByIndex "${a[*]}" "${b[*]}" ${c}` ; where ${c} is optional if you want c == 1.
1750
1751 srpmAutoBuild_setRpmBuildDir
1752
1753 local -a arrayToFilter
1754 local -a indList
1755 local nn=0
1756 local numVals=0
1757 local indSelect=1
1758
1759 arrayToFilter=($(echo "${1}"))
1760 indList=($(echo "${2}"))
1761
1762 [[ -n ${3} ]] && [[ ${3} =~ ^[0-9]+$ ]] && indSelect=${3}
1763
1764 if (( ${#indList[@]} <= ${#arrayToFilter[@]} )); then
1765 numVals=${#indList[@]}
1766 (( ${#indList[@]} < ${#arrayToFilter[@]} )) && arrayToFilter=(${arrayToFilter[@]:0:$numVals})
1767 else
1768 numVals=${#arrayToFilter[@]}
1769 indList=(${indList[@]:0:$numVals})
1770 fi
1771 numVals=$(( $numVals - 1 ))
1772
1773 # filter and echo output
1774 # annoyingly, this doesnt work as intended in mock. Mock doesnt seem to support the <(...) notation...
1775 if srpmAutoBuild_isMock; then
1776 # we are in mock, and <(...) doesnt work
1777
1778 echo ${arrayToFilter[@]} | sed -E s/' '/'\n'/g > "${RPM_BUILD_DIR%/}/.tempList1"
1779 echo ${indList[@]} | sed -E s/' '/'\n'/g > "${RPM_BUILD_DIR%/}/.tempList2"
1780
1781 echo "$(diff --width=512 -ywd "${RPM_BUILD_DIR%/}/.tempList1" "${RPM_BUILD_DIR%/}/.tempList2" | grep -E '\|.*'"${indSelect}" | sed -E s/'^(.*)\|.*$'/'\1'/)"
1782
1783 \rm -rf "${RPM_BUILD_DIR%/}/.tempList1" "${RPM_BUILD_DIR%/}/.tempList2"
1784
1785 else
1786 # use better method
1787 echo "$(diff --width=512 -ywd <(echo ${arrayToFilter[@]} | sed -E s/' '/'\n'/g) <(echo ${indList[@]} | sed -E s/' '/'\n'/g) | grep -E '\|.*'"${indSelect}" | sed -E s/'^(.*)\|.*$'/'\1'/)"
1788 fi
1789
1790}
1791
1792
1793
1794srpmAutoBuild_SRPM_download() {
1795 # Download new/updated SRPM packages into ${RPM_BUILD_DIR%/}/SRPMS for all rpm packages in the current directory (or in directory specified by $2, or in ${RPM_BUILD_DIR%/}/SRPMS" if $2 is the Flag '--srpm-dir'
1796 # use Flag '--all' to download srpms for ALL installed RPMS and all spec files in ${RPM_BUILD_DIR%/}/SPECS
1797 # BUT do not download SRPMS for packages that are excluded from being built (listed in ${RPM_BUILD_DIR%/}/BUILD-EXCLUDE-LIST) OR that were just downloaded as build dependencies (listed in ${RPM_BUILD_DIR%/}/.srpmAutoBuild-database/installed-build-dependencies)
1798 # To download SRPMS for these excluded packages, rename/delete ${RPM_BUILD_DIR%/}/BUILD-EXCLUDE-LIST and/or ${RPM_BUILD_DIR%/}/.srpmAutoBuild-database/installed-build-dependencies and then re-run this function
1799 #
1800 # This initially composes 2 lists:
1801 # 1) list of installed RPM package names and names from current spec files, and
1802 # 2) list of packages excluded from being build and/or that were only downloaded as build dependencies
1803 # Next, *-devel, *-debuginfo and *-debugsource package names are removed (these all come from the base src.rpm package)
1804 # Then, the lists are sorted and have their duplicate entires removed
1805 # Finally, the lists are compared using `diff` and only packages that are present on list (1) but not list (2) have their srpm's downloaded via `dnf download --source`
1806
1807
1808 local downloadDir=""
1809 #local invalidArchList=""
1810 local dirOrig=""
1811 local downloadAllFlag=0
1812
1813 [[ ${1,,} =~ ^-+a(ll)?$ ]] && downloadAllFlag=1 && shift 1
1814
1815 [[ -d ${1} ]] && downloadDir="${1}"
1816 [[ ${1,,} =~ ^-+srpm(-?dir)?$ ]] && downloadDir="${RPM_BUILD_DIR%/}/SRPMS"
1817 [[ -z "${downloadDir}" ]] && downloadDir="$(pwd)"
1818
1819 echo "Checking DNF for new and updated SRPMs for ALL installed RPM packages" >&2
1820
1821 dirOrig="$(pwd)"
1822
1823 cd "${downloadDir}"
1824
1825 [[ -z $(rpm -qa | grep 'dnf-plugins-core') ]] && dnf install 'dnf-command(builddep)' 'dnf-command(download)'
1826
1827 [[ -n $(find ${dirOrig} -maxdepth 1 -type f -name "*.spec" ; find ${dirOrig} -maxdepth 1 -type f -name "*.rpm") ]] && ( dnf download --source --skip-broken $(find ${dirOrig} -maxdepth 1 -type f -name "*.spec" | sed -E s/'^.*\/([^\/]*)\.spec'/'\1'/) ; dnf download --source --skip-broken ${dirOrig%/}/*.rpm )
1828
1829 if (( $downloadAllFlag > 0 )); then
1830
1831 if srpmAutoBuild_isMock; then
1832 # we are in mock. No support for <(...)
1833
1834 # avoid re-downloading srpms with invalid archs
1835 #[[ -d "${RPM_BUILD_DIR%/}/SRPMS/.INVALID_ARCH" ]] && ( invalidArchList="$(find "${RPM_BUILD_DIR%/}/SRPMS/.INVALID_ARCH" -type f -name "*.rpm")" ; mv -n ${invalidArchList} "${downloadDir}" )
1836
1837 # download sources
1838 dnf download --source --skip-broken $(srpmAutoBuild_getRpmNames -i)
1839
1840 # move srpms with invalid arch's back
1841 #[[ -d "${RPM_BUILD_DIR%/}/SRPMS/.INVALID_ARCH" ]] && \mv -f $(echo "${invalidArchList}" | sed -E s/'^.*\/\.INVALID_ARCH\/(.*)$'/'\2'/) "${RPM_BUILD_DIR%/}/SRPMS/.INVALID_ARCH/"
1842
1843 else
1844 # not in mock...use the "better version"
1845
1846 dnf download --source --skip-broken $(diff --width=512 -ywd --suppress-common-lines <(echo "$(srpmAutoBuild_getRpmNames --installed) $(find ${RPM_BUILD_DIR%/}/SPECS/ -type f -name "*.spec" | sed -E s/'^.*\/([^\/]*)\.spec$'/'\1'/)" | grep -E -v '(-devel|-debuginfo|-debugsource)' | sort -u) <(echo "$(cat ${RPM_BUILD_DIR%/}/BUILD-EXCLUDE-LIST) $(cat ${RPM_BUILD_DIR%/}/.srpmAutoBuild-database/installed-build-dependencies)" | grep -E -v '(-devel|-debuginfo|-debugsource)' | sort -u) | grep -E '[\<\|]' | sed -E s/'^([^\<\|]*)[\<\|].*$'/'\1'/)
1847 fi
1848 fi
1849
1850 cd "${dirOrig}"
1851
1852}
1853
1854
1855srpmAutoBuild_build_SRPM_SPEC() {
1856 # build SPECfiles from SRPMs specified as function inputs or (if present) using the list at "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST" or (if no input using the SRPMS
1857 # FLAGS --update-specfile-database and --no-update-specfile-database will force enabling/disabling an on disk database to store some info
1858 # the database is mainly a legacy holdover from a previous version of the code, but the following files are used. They are all in the ${RPM_BUILD_DIR} directory
1859 #
1860 # ${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST: List of SRPMs to build into specs. If empty/missing then will use any srpms in ${RPM_BUILD_DIR%/}/SRPMS
1861 # ${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILt-LIST: List of SRPMS that were sucessfully built into specfiles
1862 # ${RPM_BUILD_DIR%/}/.SRPM-SPEC-FAILED-LIST: List of SRPMS that were NOT sucessfully built into specfiles, due to a failure during %prep of because the file couldnt be found
1863
1864 # make sure rpmbuild is installed
1865 srpmAutoBuild_setEnvVars
1866
1867 local -a srpmSpecBuildList # SPEC-files that need to be built from SRPMs
1868 local failedPrepFlagCur=0
1869 local updateDatabaseFlag=0
1870 local srpmCur=""
1871 local nn=0
1872 local forceFlag=0
1873 local specsForceRebuildFlag=0
1874 local skipCurFlag=0
1875 local nameMatchCur=""
1876 local forceFlagTempIndicator
1877
1878 if [[ ${1,,} =~ ^-+f(orce)?$ ]]; then
1879 forceFlag=1
1880 specsForceRebuildFlag=1
1881
1882 elif [[ ${1,,} =~ ^-+f(orce)?[0-9]?$ ]]; then
1883 forceFlagTempIndicator="$(echo "${1,,}" | sed -E s/'^[a-z]*([0-9])$'/'\1'/)"
1884 (( $forceFlagTempIndicator > 1 )) && forceFlag=1 && forceFlagTempIndicator=$(( $forceFlagTempIndicator - 2 ))
1885 (( $forceFlagTempIndicator > 1 )) && forceFlagTempIndicator=1
1886 specsForceRebuildFlag=${forceFlagTempIndicator}
1887 fi
1888
1889 # determine if we need to update the database.
1890 # Default when called without specfile inputs is to update unless unless '--no-update-database' is given and is the only input
1891 # Default when called with specfile inputs is to not update unless unless '--update-database' is given as 1st input
1892
1893 if [[ ${1,,} =~ ^-+no-?update(-?spec(file)?(-?data(base)?)?)?$ ]]; then
1894 updateDatabaseFlag=0
1895 shift 1
1896 elif [[ ${1,,} =~ ^-+update(-?spec(file)?(-?data(base)?)?)?$ ]]; then
1897 updateDatabaseFlag=1
1898 shift 1
1899 else
1900 [[ -f "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST" ]] && [[ -n $(cat "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST") ]] && updateDatabaseFlag=1 || updateDatabaseFlag=0
1901 fi
1902
1903 # load list of SRPM-to-build-into-spec-files filenames (if no input) or assign input as SRPM names to build specfiles for
1904
1905 if (( $updateDatabaseFlag == 1 )) && [[ -f "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST" ]]; then
1906
1907 srpmSpecBuildList=($(cat "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST"))
1908
1909 [[ -f "${RPM_BUILD_DIR%/}/.SRPM-SPEC-FAILED-LIST" ]] && mv -f "${RPM_BUILD_DIR%/}/.SRPM-SPEC-FAILED-LIST" "${RPM_BUILD_DIR%/}/.SRPM-SPEC-FAILED-LIST.old"
1910 [[ -f "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILT-LIST" ]] && mv -f "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILT-LIST" "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILT-LIST.old"
1911 touch "${RPM_BUILD_DIR%/}/.SRPM-SPEC-FAILED-LIST"
1912 touch "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILT-LIST"
1913
1914 elif (( $# > 1 )); then
1915 srpmSpecBuildList=(${@})
1916 else
1917 srpmSpecBuildList=($(find "${RPM_BUILD_DIR%/}/SRPMS" -maxdepth 1 -type f -name "*.src.rpm"))
1918 fi
1919
1920 (( ${#srpmSpecBuildList[@]} == 0 )) && echo "NO SRPMS TO BUILD! EXITING..." >&2 && return
1921
1922 echo -e "\n\nINSTALLING BUILD DEPENDENCIES... \n" >&2
1923 srpmAutoBuild_builddep "${srpmSpecBuildList[@]}"
1924
1925 # Build new specfiles from selected SRPMs
1926
1927 # if building multiple SPECs, list how many
1928 (( ${#srpmSpecBuildList[@]} > 1 )) && echo -e "\n\nNOTICE: ${#srpmSpecBuildList[@]} spec file(s) will now be build from SRPM package(s)." >&2
1929 echo -e "\n" >&2
1930
1931 for srpmCur in "${srpmSpecBuildList[@]}"; do
1932
1933 skipCurFlag=0
1934
1935 (( $forceFlag == 0 )) && nameMatchCur="$(srpmAutoBuild_getInfo -n -v -a $(find {"${RPM_BUILD_DIR%/}/RPMS","${LOCALREPO_DIR%/}/built"} -type f -name "*$(srpmAutoBuild_getInfo -n "${srpmCur}")*.rpm" | grep -v '/cache/'))" && [[ -n "${nameMatchCur}" ]] && [[ -n "$( echo "${nameMatchCur}" | grep -F "$(srpmAutoBuild_getInfo -n -v -a "${srpmCur}")")" ]] && skipCurFlag=1
1936 (( specsForceRebuildFlag == 0 )) && nameMatchCur="$(srpmAutoBuild_getInfo -n -v -a $(find "${RPM_BUILD_DIR%/}/SPECS" -type f -name "*$(srpmAutoBuild_getInfo -n "${srpmCur}")*.spec"))" && [[ -n "${nameMatchCur}" ]] && [[ -n "$( echo "${nameMatchCur}" | grep -F "$(srpmAutoBuild_getInfo -n -v -a "${srpmCur}")")" ]] && skipCurFlag=1
1937
1938 if (( $skipCurFlag == 0 )); then
1939
1940 echo "A SPEC-file will now be built from: ${srpmCur}" >&2
1941
1942 # Build SPEC-file from SRPM using %{prep}
1943 failedPrepFlagCur=0
1944 [[ -f "${srpmCur}" ]] && rpmbuild -rp "${srpmCur}" || dnf builddep --skip-broken $(srpmAutoBuild_getRpmNames "${srpmCur}") "${srpmCur}" && rpmbuild -rp "${srpmCur}" || rpmbuild -rp "${srpmCur}" --nodeps || failedPrepFlagCur=1
1945
1946 (( $updateDatabaseFlag == 1 )) && (( $failedPrepFlagCur == 0 )) && echo "${srpmCur}" >> "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILT-LIST"
1947 (( $updateDatabaseFlag == 1 )) && (( $failedPrepFlagCur == 1 )) && echo "${srpmCur}" >> "${RPM_BUILD_DIR%/}/.SRPM-SPEC-FAILED-LIST"
1948
1949
1950 (( $failedPrepFlagCur == 1 )) && echo -e "\nNOTICE: FAILED TO BUILD SPEC: ${nn} \n\n${nn} was not successfully built into a spec-file, either due to a failure during the execution of %{prep}, or because the input file was not found. \n" >&2
1951
1952 # if successful build of SPECfile: copy source into ${RPM_BUILD_DIR%/}/SRPMS if it isnt already there, and check the name/version of the generated specfile against the SRPM
1953 if (( $failedPrepFlagCur == 0 )); then
1954
1955 # copy SRPM into rpm build tree SRPMS folder
1956 [[ -n "$(find "${RPM_BUILD_DIR%/}/SRPMS/" -maxdepth 1 -type f -wholename "$(realpath "${srpmCur}")")" ]] || \cp -f "${srpmCur}" "${RPM_BUILD_DIR%/}/SRPMS/"
1957
1958 # print status/info to screen
1959 echo -e "\nA SPEC-file was successfully generated from ${srpmCur} \n\nThe code will now automatically confirm that it includes valid/parsable name and version information. \nThis ensures that checks made during the build process to avoid re-building already-build specfiles will return valid results. \n" >&2
1960
1961 # Check Name and Version in specfile. If we cant read/parse some info (in particular version info), hard code it using a static expression (no variable anything) based on the SRPM file's info
1962 srpmAutoBuild_check_SpecSrpm_NameVersion "$(srpmAutoBuild_getInfo -n "${srpmCur}").spec" "${srpmCur}"
1963
1964 fi
1965
1966 else
1967
1968 echo -e "\nAn matching and already-build specfile or rpm ppackage was found for ${srpmCur}, and as such it will not be re-buiult into a specfile. \nUse the '-f' or '--force' flags to override this behavior if it is in error. \n" >&2
1969
1970 fi
1971
1972 done
1973
1974}
1975
1976
1977srpmAutoBuild_builddep() {
1978 # download and install build dependencies for the SRPMS we want to build
1979 # Note: this existsw because `dnf builddep` doesnt work with multiple srpms in the same function call, and since dnf is usually slow to initiate a new connection it is VERY slow to call for each SROm individually. This function uses a vectorized approach that is much faster because it extracts all the requiired dependencies for ALL packagges being built using `rpm` , and then maked a single call to dnf to insttal them all. dnf builddep is still used as a backup in the final build script, in case this approach missed (or couldnt parse) a dependent package that dnf builddep identified.
1980 srpmAutoBuild_rootUserCheck
1981
1982
1983 local srpmBuildList=""
1984 local specBuildList=""
1985 local builddepPkgList=""
1986 local recursionFlag=0
1987
1988 [[ ${1,,} =~ ^-+r(ec(ursion)?)? ]] && recursionFlag=1 && shift 1
1989
1990
1991 # get package names from inputs or, if no inputs, from the SRPMS/SPECS present in the default rpm build tree directories
1992
1993 if (( $# == 0)); then
1994 # no inputs - get packages from SRPMS and SPECS folders, unless "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST" exists and is not empty
1995
1996 if [[ -f "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST" ]] && [[ -n "$(cat "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST")" ]]; then
1997 srpmBuildList="$(cat "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST" | grep -E '.src.rpm')"
1998 specBuildList="$(cat "${RPM_BUILD_DIR%/}/.SRPM-SPEC-BUILD-LIST" | grep -E '.spec')"
1999 else
2000 srpmBuildList="$(find "${RPM_BUILD_DIR%/}/SRPMS" $( (( $recursionFlag == 0 )) && echo '-maxdepth 1') -type f -name "*.src.rpm")"
2001 specBuildList="$(find "${RPM_BUILD_DIR%/}/SPECS" -maxdepth 1 -type f -name "*.spec")"
2002 fi
2003
2004 else
2005 # get packages from function input
2006
2007 srpmBuildList="$(echo "${@}" | sed -zE s/' '/'\n'/g | grep -E '\.src\.rpm[ \t]*$')"
2008 specBuildList="$(echo "${@}" | sed -zE s/' '/'\n'/g | grep -E '\.spec[ \t]*$')"
2009 fi
2010
2011 # get build requirements
2012 builddepPkgList="$(echo "$([[ -n "${srpmBuildList}" ]] && echo "$(rpm -qpR $(echo ${srpmBuildList} | sed -zE s/' '/'\n'/g | grep -E '.src.rpm') | sed -E s/'^(.+)$'/'"\1"'/)" || echo ""; [[ -n "${specBuildList}" ]] && echo "$(cat $(echo ${specBuildList} | sed -zE s/' '/'\n'/g | grep -E '.spec') | grep -E '^(Build)?Requires' | sed -E s/'^[^\:]*\:[ \t]*(.*)$'/'"\1"'/)" || echo "")" | sort -u)"
2013
2014 # try and parse things that didnt originally parse using rpm --eval
2015 builddepPkgList="$(echo "$(echo "${builddepPkgList}" | grep -v -E s/'\%\{.*\}')"; [[ -n $(echo "${builddepPkgList}" | grep -E s/'\%\{.*\}') ]] && echo "$(rpm --eval $(echo "${builddepPkgList}" | grep -E s/'\%\{.*\}'))" | sort -u)"
2016
2017 eval 'dnf install --skip-broken -y '$(echo "${builddepPkgList}")
2018
2019}
2020
2021srpmAutoBuild_getInfo() {
2022 # gets info about the name/version of SPEC-files and RPMs and SRPMs
2023 #
2024 # By default, if no (valid) flags,. you will get a human-readable ()
2025 #
2026 # Use the following flags to instead output a (partial) package name, made up of some compination name/ver/arch
2027 # Output will be constructed using standard RPM naming. Using all 3 flags ('-n -v -a') gives $(name)-$(ver).$(arch)
2028 # '-n' or '--name': include name
2029 # '-v' or '--ver(sion)?': include version
2030 # '-a' or '--arch(itecture)?': include arch
2031 #
2032 # NOTE: for RPMS and SRPMs, the arch returned is what is coded into the [S]RPM.
2033 # The specfiles dont seem to *always* include this, so for specfiles the
2034 # arch returned is the current system architecture (i.e., "$(uname -m)"")
2035
2036 local nn=""
2037 local flagsAll=""
2038
2039 [[ "${*,,}" =~ ^(.+ )?-+n(ames?)?( .+)?$ ]] && flagsAll="${flagsAll} -n"
2040 [[ "${*,,}" =~ ^(.+ )?-+v(er(sions?)?)?( .+)?$ ]] && flagsAll="${flagsAll} -v"
2041 [[ "${*,,}" =~ ^(.+ )?-+a(rch(itecture)?)?( .+)?$ ]] && flagsAll="${flagsAll} -a"
2042 #[[ -z "${flagsAll}" ]] && flagsAll="-n -v -a"
2043 [[ -n "${flagsAll}" ]] && flagsAll="$(echo "${flagsAll}" | sed -E s/' *(.*[^( *$)]) *$'/'\1'/)"
2044
2045 for nn in "${@}"; do
2046 if [[ ! ${nn} =~ ^-+((n(ames?)?)|(v(er(sions?)?)?)|(a(rch(itecture)?)?))$ ]]; then
2047 if [[ -d "${nn}" ]]; then
2048 [[ -n "$(find "${nn}" -maxdepth 1 -type f -name "*.spec")" ]] && srpmAutoBuild_getInfo_fromSPECs ${flagsAll} "${nn}"
2049 [[ -n "$(find "${nn}" -maxdepth 1 -type f -name "*.rpm")" ]] && srpmAutoBuild_getInfo_fromRPMs ${flagsAll} "${nn}"
2050 else
2051 #[[ -z "${flagsAll}" ]] && echo -e "\nchecking \"${nn}\""
2052 if [[ ${nn} == *.spec ]]; then
2053 srpmAutoBuild_getInfo_fromSPECs ${flagsAll} "${nn}"
2054
2055 elif [[ ${nn} == *.rpm ]]; then
2056 srpmAutoBuild_getInfo_fromRPMs ${flagsAll} "${nn}"
2057
2058 elif [[ ${nn} == ${RPM_BUILD_DIR%/}/SPECS/* ]]; then
2059 srpmAutoBuild_getInfo_fromSPECs ${flagsAll} "${nn}"
2060
2061 elif ( [[ ${nn} == ${RPM_BUILD_DIR%/}/SRPMS/* ]] || [[ ${nn} == ${RPM_BUILD_DIR%/}/RPMS/* ]] || [[ ${nn} == ${LOCALREPO_DIR%/}/built/* ]] || [[ ${nn} == ${LOCALREPO_DIR%/}/downloaded/* ]] || [[ ${nn} == ${LOCALREPO_DIR%/}/source/* ]] ); then
2062 srpmAutoBuild_getInfo_fromRPMs ${flagsAll} "${nn}"
2063 fi
2064 fi
2065 fi
2066 done
2067}
2068
2069srpmAutoBuild_getInfo_fromSPECs() {
2070 # this will isolate the main package name, version, and release in the spec-file and print it.
2071 # It is sort of like an `rpm -qiP` except that it works with spec-files and (optionally) filters the output for name/version info
2072 #
2073 # FLAGS
2074 # '-n' or '--name' --> output package name only
2075 # '-v' or '--ver[sion]' --> output package version + release only, in the form {version}-{release}
2076 # if both of the above flags are present, it will output just the package name + version + release in the form '{name}-{version}-{release}'. This format matches standard RPM file naming protocol.
2077 # if neither of the above flags are present, it will output the full unfiltered info header. This is good for information viewing, but not fdor scripting package names/versions
2078
2079 local nn=""
2080 local kk=0
2081 local specInfoCur=""
2082 local outType=0
2083 local tempCur=""
2084 local -a inAll
2085 local -a inAllTemp
2086 local archFlag=0
2087
2088 [[ "${*,,}" =~ ^(.+ )?-+n(ames?)?( .+)?$ ]] && outType=1
2089 [[ "${*,,}" =~ ^(.+ )?-+v(er(sions?)?)?( .+)?$ ]] && outType=$(( $outType + 2 ))
2090 [[ "${*,,}" =~ ^(.+ )?-+a(rch(itecture)?)?( .+)?$ ]] && archFlag=1
2091
2092 for nn in "$@"; do
2093 # case 1: input is a file
2094 [[ -f "${nn}" ]] && [[ ${nn} == *.spec ]] && inAll[$kk]="${nn}" && ((kk++))
2095
2096 # case 2: input is a directory. scan its top level for specfiles
2097 if [[ -d "${nn}" ]]; then
2098 inAllTemp=($(find "${nn}" -maxdepth 1 -type f -name "*.spec"))
2099 for tempCur in "${inAllTemp[@]}"; do
2100 inAll[$kk]="${tempCur}" && ((kk++))
2101 done
2102 fi
2103 done
2104
2105 for nn in "${inAll[@]}"; do
2106
2107 (( $outType == 0 )) && echo -e "\nSPEC FILE NAME: $nn"
2108
2109 specInfoCur="$(rpm --eval "$(echo -n "$(echo -e "\n\n"; cat "$nn")" | grep -E '^((Name)|(Version)|(Release)|(Summary)|(Epoch)|(License)|(URL))\:|^[ \t]*$' | sed -zE s/'^.*(((\n([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Name\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Version\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Release\:[^\n]*\n))([^\n]*[a-zA-Z0-9]+[^\n]*\n)*)|((\n([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Name\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Release\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Version\:[^\n]*\n))([^\n]*[a-zA-Z0-9]+[^\n]*\n)*)|((\n([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Version\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Name\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Release\:[^\n]*\n))([^\n]*[a-zA-Z0-9]+[^\n]*\n)*)|((\n([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Version\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Release\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Name\:[^\n]*\n))([^\n]*[a-zA-Z0-9]+[^\n]*\n)*)|((\n([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Release\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Version\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Name\:[^\n]*\n))([^\n]*[a-zA-Z0-9]+[^\n]*\n)*)|((\n([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Release\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Name\:[^\n]*\n))(([^\n]*[a-zA-Z0-9]+[^\n]*\n)*(Version\:[^\n]*\n))([^\n]*[a-zA-Z0-9]+[^\n]*\n)*)).*$'/'\1'/ | sed -zE s/'\n*(.*[^\n])\n*$'/'\1\n\n'/)";)"
2110
2111 (( $outType == 0 )) && echo "$(echo "${specInfoCur}"; echo "Architecture: $(uname -m) (build system)")"
2112
2113 (( $outType == 1 )) && echo -n "${specInfoCur}" | grep -E '^Name\:' | sed -E s/'^Name\:[ \t]*([^\n]*\n?)$'/'\1'/ | sed -zE s/'(.*)\n$'/'\1'/
2114
2115 (( $outType == 2 )) && echo -n "$(echo "${specInfoCur}" | grep -E '^Version\:'; echo "${specInfoCur}" | grep -E '^Release\:')" | sed -zE s/'^Version\:[ \t]*([^\n]*)\nRelease\:[ \t]*([^\n]*\n?)$'/'\1-\2'/
2116
2117 (( $outType == 3 )) && echo -n "$(echo "${specInfoCur}" | grep -E '^Name\:'; echo "${specInfoCur}" | grep -E '^Version\:'; echo "${specInfoCur}" | grep -E '^Release\:')" | sed -zE s/'^Name\:[ \t]*([^\n]*)\nVersion\:[ \t]*([^\n]*)\nRelease\:[ \t]*([^\n]*\n?)$'/'\1-\2-\3'/
2118
2119 (( $archFlag == 1 )) && echo ".$(uname -m)" || echo ""
2120
2121 (( $outType == 0 )) && echo -e "----------------------------------------------------------------------\n" >&2
2122
2123 done
2124
2125}
2126
2127srpmAutoBuild_getInfo_fromRPMs() {
2128 # this will isolate the main package name, version, and release in the srpmfile and print it.
2129 # This calls `rpm -qiP` and (optionally) filters the output for name/version info --> works with rpoms and srpms
2130 #
2131 # FLAGS
2132 # '-n' or '--name' --> output package name only
2133 # '-v' or '--ver[sion]' --> output package version + release only, in the form {version}-{release}
2134 # '-a' or '--arch[itecture]' --> output package intended architecture
2135 # if more than 1 of the above flags are present, it will output the listed flags in the following order (unlisted flags will haver the corresponding info omitted): '{name}-{version}-{release}.{arch}'. This format matches standard RPM file naming protocol.
2136 # if neither of the above flags are present, it will output the full unfiltered info header. This is good for information viewing, but not fdor scripting package names/versions
2137
2138 local nn=""
2139 local kk=0
2140 local srpmInfoCur=""
2141 local nameCur=""
2142 local verCur=""
2143 local archCur=""
2144 local outNameFlag=0
2145 local outVerFlag=0
2146 local outArchFlag=0
2147 local outType=1
2148 local -a inAll
2149
2150 [[ "${*,,}" =~ ^(.+ )?-+n(ames?)?( .+)?$ ]] && outNameFlag=1
2151 [[ "${*,,}" =~ ^(.+ )?-+v(er(sions?)?)?( .+)?$ ]] && outVerFlag=1
2152 [[ "${*,,}" =~ ^(.+ )?-+a(rch(itecture)?)?( .+)?$ ]] && outArchFlag=1
2153
2154 (( $outNameFlag == 0 )) && (( $outVerFlag == 0 )) && (( $outArchFlag == 0 )) && outType=0
2155
2156 for nn in "$@"; do
2157 # case 1: input is a file
2158 [[ -f "${nn}" ]] && [[ ${nn} =~ ^.*(\.src)?\.rpm$ ]] && inAll[$kk]="${nn}" && ((kk++))
2159
2160 # case 2: input is a directory. scan its top level for [s]rpms
2161 if [[ -d "${nn}" ]]; then
2162 inAllTemp=($(find "${nn}" -maxdepth 1 -type f -name "*.rpm"))
2163 for tempCur in "${inAllTemp[@]}"; do
2164 inAll[$kk]="${tempCur}" && ((kk++))
2165 done
2166 fi
2167 done
2168
2169 for nn in "${inAll[@]}"; do
2170
2171 (( $outType == 0 )) && echo -e "\nSRPM NAME: $nn"
2172
2173 srpmInfoCur="$(rpm --eval "$(rpm -qip "${nn}")")"
2174
2175 if (( $outType == 0 )); then
2176
2177 echo "${srpmInfoCur}"
2178 echo -e "\n--------------------------------------------------------\n" >&2
2179
2180 else
2181
2182 (( $outNameFlag == 1 )) && nameCur="$(echo "${srpmInfoCur}" | grep -E '^Name {8}:' | sed -E s/'^.*\:[ \t]*(.*)$'/'\1'/)" || nameCur=""
2183
2184 (( $outVerFlag == 1 )) && verCur="$([[ -z "${nameCur}" ]] || echo '-')$(echo "$(echo "${srpmInfoCur}" | grep -E '^Version {5}\:'; echo "${srpmInfoCur}" | grep -E '^Release[ \t]+\:')" | sed -z -E s/'^Version {5}\:[ \t]*([^\n]*)\nRelease {5}\: *([^\n]*\n?)$'/'\1-\2\n'/g)" || verCur=""
2185
2186 (( $outArchFlag == 1)) && archCur="$([[ -z "${nameCur}${verCur}" ]] || echo '.')$(echo "${srpmInfoCur}" | grep -E '^Architecture\:' | sed -E s/'^Architecture\:[ \t]*(.*)$'/'\1'/)" || archCur=""
2187
2188 echo "${nameCur}${verCur}${archCur}"
2189
2190 fi
2191
2192 done
2193
2194}
2195
2196
2197srpmAutoBuild_check_SpecSrpm_NameVersion() {
2198 # compares the version of a specfile ($1) and srpm ($2). Inputs should use full file paths.
2199 # If the names are the same and the specfile version is invalid, it will be overwritten with the version of the srpm.
2200 # the utility in this is in avoiding re-building RPM's you have already built. The code will attempt to match up SPEC files to already build RPMs, but will only skip building if there is a perfect name and package match. This sort of match requires the name and version to parse correctly.This usually is the case for SRPM's, but often times the SPEC files use dynamic variable-based names that `rpm` doesnt seem to be able to parse outside of actually building the package, meaning the code wont find a matching RPM unless the dynamic variable names are replaced with static names derived from the SRPM.
2201
2202 #local infoSPEC=""
2203 local nameSPEC=""
2204 local verSPEC=""
2205 local nameSRPM=""
2206 local verSRPM=""
2207 local nameRep=""
2208
2209 # extract names and versions from the SPEC-file and SRPM
2210
2211 # SPEC Info
2212
2213 # get name and version from srpm using `rpm --eval` and the specfile contents. Filter specfile contents to find a grouping with at least 3 of the following fields: Name, Version, Release, Summary. Some specfiles have >1 lines beginning with "Name", but should only contain 1 group like this, and the "Name" field from this group is the one we want.
2214
2215 #infoSPEC="$( cat "${1}" | grep -z -o -P '(\n((Name)|(Version)|(Release)|(Summary))\:[^(\n)]*){3,4}' | sed -E s/'[ \t]+'/' '/g | sed -E s/'^Summary.*$'// | sed -z -E s/'\n+'/'\n'/g | sed -z -E s/'\nRelease\:[ \t]*'/'-'/g)"
2216
2217 #infoSPEC="$(srpmAutoBuild_getInfo_fromSPECs "${1}")"
2218 #nameSPEC="$(rpm --eval "$(echo "${infoSPEC}" | grep -E '^Name\:' | sed -E s/'^Name\:[ \t]*(.*)$'/'\1'/)")"
2219
2220 #erSPEC="$(rpm --eval "$(echo "${infoSPEC}" | grep -E '^Version\:' | sed -E s/'^Version\:[ \t]*(.*)$'/'\1'/)")"
2221
2222 nameSPEC="$(srpmAutoBuild_getInfo_fromSPECs -n "${1}")"
2223 verSPEC="$(srpmAutoBuild_getInfo_fromSPECs -v "${1}")"
2224
2225 # secondary check in case the 1st didnt work. dont filter the specfile, just grab the 1st line starting with Name/Version and use that
2226
2227 [[ -z "${nameSPEC}" ]] && nameSPEC="$(rpm --eval "$(cat "${1}" | grep -E '^Name\:' | head -n 1 | sed -E s/'^.*\:[ \t]*(.*)$'/'\1'/)")"
2228 [[ -z "${nameSPEC}" ]] && nameSPEC="${1%.spec}"
2229
2230 [[ -z "${verSPEC}" ]] && verSPEC="$(rpm --eval "$(cat "${1}" | grep -E '^Version\:' | head -n 1 | sed -E s/'^.*\:[ \t]*(.*)$'/'\1'/)")"
2231
2232 # SRPM Info
2233
2234 # get name and version from srpm using `rpm --eval` and `rpm --qip`
2235
2236 #nameSRPM="$(rpm --eval "$(rpm -qip "${2}" | grep -E '^Name {8}\:' | sed -E s/'^.*\: *(.*)$'/'\1'/)")"
2237 #verSRPM="$(rpm --eval "$(rpm -qip "${2}" | grep -E '^Version {5}\:|^Release {5}\:' | sed -z -E s/'Version[^\:]*\: *([^\n]*)\nRelease[^\:]*\: *([^\n]*)\n'/'\1-\2\n'/g)")"
2238
2239 nameSRPM="$(srpmAutoBuild_getInfo_fromRPMs -n "${2}")"
2240 verSRPM="$(srpmAutoBuild_getInfo_fromRPMs -v "${2}")"
2241
2242 # secondary check in case the 1st didnt work. Get name and/or version direct from the srpm name, not its contents.
2243
2244 [[ -z "${nameSRPM}" ]] && nameSRPM="$(echo "${2##*/}" | sed -E s/'^(.*)-[^-]*-[^\.]*\.[^\.]*\.src\.rpm'/'\1'/)"
2245
2246 [[ -z "${verSRPM}" ]] && verSRPM="$(echo "${2##*/}" | sed -E s/'^.*-([^-]*-[^\.])*\.[^\.]*\.src\.rpm'/'\1'/)"
2247
2248 # fix "Name" in the SPEC file (if needed)
2249
2250 if [[ "${nameSPEC}" != "${nameSRPM}" ]]; then
2251
2252 # determine replacement package name
2253 if [[ ${2} == *"${1%%.spec}"* ]]; then
2254 # use name from specfile filename, since this matches the start of the srpm filename
2255 nameRep="${1%%.spec}"
2256 else
2257 # use name derived from the srpm package
2258 nameRep="${nameSRPM}"
2259 fi
2260
2261 # add name to spec-file
2262 if [[ -n "$(cat ${1} | grep -E '^Name\: ')" ]]; then
2263 # name field exists. overwrite name. In case multiple lines begin with "Name: ", overwrite the 1st one only
2264 echo "$(cat "${1}" | sed -z -i -E s/'\nName\: [^\n]*'/'\nName\: '"$(srpmAutoBuild_escapeRegexChars "${nameRep}")"''/)" > "${1}"
2265 else
2266 # Add "Name: ____" entry to the start (1st line) of spec file
2267 echo "$(echo "Name: ${nameRep}" && cat "${1}")" > "${1}"
2268 fi
2269
2270 fi
2271
2272 # fix "Version" in the SPEC file (if needed)
2273
2274 if [[ -z "${verSPEC}" ]] || ( [[ "${verSPEC}" != "${verSRPM}" ]] && [[ "${2}" != *"${verSPEC}"* ]] && [[ ${verSRPM} =~ ^.+$ ]] ); then
2275
2276 if [[ -n "$(cat ${1} | grep -E '^Name\:')" ]]; then
2277 # name field exists. overwrite name.
2278 echo "$(cat "${1}" | sed -i -E s/'^Version {5}\:.*$'/'Version \: '"$(srpmAutoBuild_escapeRegexChars "${verSRPM}")"''/)" > "${1}"
2279 else
2280 echo "$(echo "$(cat ${1} | grep -E '^Name {8}\:')" && echo "Version : ${verSRPM}" && echo "$(cat "${1}" | grep -v -E '^Name {8}\:')")" > "${1}"
2281 fi
2282
2283 fi
2284
2285}
2286
2287
2288srpmAutoBuild_escapeRegexChars() {
2289 # escape regex characters.
2290 #
2291 # flag: --newline-mod or '-n' --> transform leading newlines into '(^|\n)' and trailing newlines into '(\n|$)' (instead of just '\n')
2292 # flag: --glob-mod or '-g' --> transform '*' into '.*' (instead of '\*')
2293 #
2294 # Intended usage: running `sed [-iz] -E s/"$(srpmAutoBuild_escapeRegexChars "$stringToReplace")"/'<replacementString>'/[g]`.
2295 # This should make `sed -E` match whatever the literal (un-escaped) text in `$stringToReplace` is
2296
2297 local strMod=""
2298 local newlineModFlag=0
2299 local globModFlag=0
2300
2301 (( $# == 0 )) && echo -n "" && return
2302 strMod="${*}"
2303
2304 [[ ${strMod,,} =~ ^(.+ )?-+n((ewline)?(-?m(od)?)?)( .+)?$ ]] && newlineModFlag=1 && strMod="$(echo "${strMod}" | sed -zE s/'^-+[Nn](([Ee][Ww][Ll][Ii][Nn][[Ee])?(-?[Mm][Oo][Dd])?)? ?'//g | sed -zE s/'-+[Nn](([Ee][Ww][Ll][Ii][Nn][[Ee])?(-?[Mm][Oo][Dd])?)? ?'/' '/g)"
2305 [[ ${strMod,,} =~ ^(.+ )?-+g((lob)?(-?m(od)?)?)( .+)?$ ]] && globModFlag=1 && strMod="$(echo "${strMod}" | sed -zE s/'^-+[Gg](([Ll][Oo][[Bb])?(-?[Mm][Oo][Dd])?)? ?'//g | sed -zE s/'-+[Gg](([Ll][Oo][[Bb])?(-?[Mm][Oo][Dd])?)? ?'/' '/g)"
2306
2307
2308 strMod="${strMod//\\/\\\\}"
2309 strMod="${strMod//./\\.}"
2310 strMod="${strMod//\//\\\/}"
2311 strMod="${strMod//\(/\\\(}"
2312 strMod="${strMod//\)/\\\)}"
2313 strMod="${strMod//\[/\\\[}"
2314 strMod="${strMod//\{/\\\{}"
2315 strMod="${strMod//\?/\\\?}"
2316 strMod="${strMod//\+/\\\+}"
2317 strMod="${strMod//\|/\\\|}"
2318 strMod="${strMod//\^/\\\^}"
2319 strMod="${strMod//\$/\\\$}"
2320 strMod="${strMod//\!/\\\!}"
2321 strMod="${strMod//"'"/"'\"'\"'"}"
2322 (( $globModFlag == 1 )) && strMod="${strMod//\*/.\*}" || strMod="${strMod//\*/\\\*}"
2323 strMod="$(echo -n "${strMod}" | sed -zE s/'\t'/'\\t'/g | sed -zE s/'\n'/'\\n'/g)"
2324 (( $newlineModFlag == 1 )) && strMod="$(echo -n "${strMod}" | sed -zE s/'^\\n'/'\(\^\|\\n\)'/ | sed -zE s/'\\n$'/'\(\\n\|\$\)'/)"
2325
2326 echo -n "${strMod}"
2327}
2328
2329
2330srpmAutoBuild_getUniqueDir() {
2331 # Appends a directory name given as function input by increasingly larger numbers until it finds a directory name that doesnt exist
2332 # Default behavior it to create the unique directory as a new, empty directory
2333 # Use flag '-n' or --no-make' or '--no-create' to not make the directory and just return the name instead
2334
2335 local noMakeFlag=0
2336 local uniqueDirName=""
2337
2338 [[ ${1,,} =~ ^-+no?-?((m(ake)?)|(c(reate)?))?$ ]] && noMakeFlag=1 && shift 1
2339
2340 uniqueDirName="$(srpmAutoBuild_getUniqueName -n "${*}")"
2341
2342 (( $noMakeFlag == 0 )) && mkdir --parents "${uniqueDirName}"
2343
2344 echo -n "${uniqueDirName}"
2345}
2346
2347
2348srpmAutoBuild_getUniqueName() {
2349 # appends a name by increasingly larger numbers until it finds a name that doesnt exist (as any object type) in the filesystem
2350 # NOTE: inputs are combined via "${*}" --> multiple inputs are treated as [single] spaces in the object name
2351 # NOTE: order of checking is "${*}", "${*}0", "${*}1", etc.
2352 # This behavior means that if the input ends with '/' it will check if the input exists, then checks for subdirectories under "${*}" that are named "0", "1", etc.
2353 # If "${*}" ends in a '/' and exists but NOT as a directory, the ending '/' will be removed and the result will be a unique directory name "${*}[#]"
2354 #
2355 # Default behavior is to use a trailing newline unless the 1st input is the flag '-n' or '---no-newline'. This is to match the behavior of 'echo <...>' and 'echo -n <...>'.
2356
2357 local nf=""
2358 local uniqueName=""
2359
2360 [[ ${1} =~ ^-+n(o-?newline)?$ ]] && nf='-n' && shift 1
2361 uniqueName="${*}"
2362
2363 [[ -z "${uniqueName}" ]] && echo "WARNING: no input. Returning <null>." >&2 && echo ${nf} "" && return
2364
2365 if [[ -e ${uniqueName} ]]; then
2366 [[ "${uniqueName}" == */ ]] && [[ ! -d "${uniqueName}" ]] && uniqueName="${uniqueName%/}"
2367
2368 local kk=0
2369 while [[ -e "${uniqueName}${kk#/}" ]]; do
2370 ((kk++))
2371 done
2372
2373 uniqueName="${uniqueName}${kk#/}"
2374 fi
2375
2376 echo ${nf} "${uniqueName}"
2377}
2378
2379
2380
2381srpmAutoBuild_fixSpecFile_missingDebugSourceFileList() {
2382 # This fixes the common "Build failed because debugsource file cannot be found" error
2383
2384 \cp -f "${*}" "${*}.old"
2385 sed -i -E s/'^\%global debug_package \%\{nil\}.*\n?$\n?'// "${*}"
2386 sed -i -E s/'^\%prep$'/'%global debug_package %{nil}\n\n%prep'/ "${*}"
2387}
2388
2389
2390srpmAutoBuild_switchSpecFile() {
2391 # switches between the original and modified spec file. (one of them is *.spec, the other is *.spec.old)
2392
2393 \mv -f "${*}" "${*}.old.temp"
2394 \mv -f "${*}.old" "${*}"
2395 \mv -f "${*}.old.temp" "${*}.old"
2396}
2397
2398
2399srpmAutoBuild_printBuildStats() {
2400 # displays current build progress and some rough statistics about successful / failed / skipped builds
2401 # INPUTS: srpmAutoBuild_printBuildStats "${nn}" "${nFailsCur}" "${kk}" "${ff}" "${ss}" "${nSPECS}"
2402
2403 local numSpecsFinished=0
2404
2405 echo -e "\nBUILD ID# $(( $1 + 1 )): $( (( ${14} == 1 )) && echo -n "PRIMARY" || echo -n "SECONDARY" ) BUILD PROCESS \n"
2406
2407 if [[ ! ${2} =~ ^NaN[1-3]$ ]]; then
2408
2409 if (( ${2} > 3 )); then
2410
2411 echo -e "\nSTATUS: FAILED! <=========================================================== \n"
2412 else
2413
2414 echo -e "\nSTATUS: BUILT SUCCESSFULLY! ( BUILD ATTEMPT # $(( ${2} + 1 )) ) \n----> Number of failed initial build attempt(s): ${2} \n"
2415 fi
2416 else
2417 echo -ne "\nSTATUS: SKIPPED! \nREASON: "
2418 (( ${13} == 3)) && echo -n "This specfile is currently being built by the other build process."
2419 (( ${13} == 2 )) && echo -n "A matching RPM with the same package name and version was found in ${RPM_BUILD_DIR%/}/RPMS, suggesting that this SPEC file has already been built. \n\nNOTE: To ignore matching already built RPMS and force (re)building, use 'srpmAutoBuild_buildSA --force'. Note that this will overwrite the existing RPM, should it exist in ${RPM_BUILD_DIR%/}/RPMS."
2420 (( ${13} == 1 )) && echo -n "The input SPEC-file could not be located (and/or read, if insufficient permissions)."
2421 [[ ! ${13} =~ ^[1-3]$ ]] && echo -n "UNKNOWN. INDICATOR VARIABLE 'skipCurFlag' HAS TAKEN AN UNSUPPORTED VALUE"
2422 echo -e "\n"
2423 fi
2424
2425 [[ ! -e "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" ]] && (( ${14} == 2 )) && numSpecsFinished=$(( ${6} - ${1} )) || numSpecsFinished=${1}
2426
2427 echo -e "BREAKDOWN OF BUILDS (BUILD RUN: $( (( ${14} == 1 )) && echo "primary" || echo "secondary")) \n"
2428
2429 echo -e "OVERALL BUILD STATS (This Build Run Only): ${3} Successes | ${4} Failures | ${5} Skipped/Excluded \n"
2430 echo -e "CURRENT OVERALL PROGRESS (All Build Runs): ${numSpecsFinished} of ${6} SPEC-files Processed ----> $((( ( $numSpecsFinished * 100 ) / ${6} )))% Complete\n"
2431
2432 echo -e "BREAKDOWN OF INDIVIDUAL BUILD ATTEMPTS \n\nSuccess on First Attempt: \t\t ${7} \n1 Failure then Success: \t\t ${8}\n2 Failures then Success: \t\t ${9} \n3 Failures then Success: \t\t ${10} \nFailed All 4 Build Attempts: \t ${11} \nBuild was Skipped: \t\t ${12} \n"
2433}
2434
2435
2436srpmAutoBuild_checkBuildStatus() {
2437 # FLAGS:
2438 # '-s' or '--simple' gives number of SPECS done.
2439 # '-a' or '--all' prints the entire detailed status record.
2440 # '-sbs' or '--side-by-side' gives the same output as '-all' but placed in 2 columns using 'diff'
2441 # Optional: use '-sbs=<#>' or '--side=-by-side=<#>' to specify the combined width of both columns.
2442 # Default width is 200. Less than ~190 will start to cut off info from the 2 columns.
2443 # Default is print the detailed status record but from the most recent build only.
2444
2445 local isPresentFlag=0
2446 [[ -f "${RPM_BUILD_DIR%/}/.STATUS_1" ]] && [[ -n $(cat "${RPM_BUILD_DIR%/}/.STATUS_1") ]] && isPresentFlag=$(( $isPresentFlag + 1 ))
2447 [[ -f "${RPM_BUILD_DIR%/}/.STATUS_2" ]] && [[ -n $(cat "${RPM_BUILD_DIR%/}/.STATUS_2") ]] && isPresentFlag=$(( $isPresentFlag + 2 ))
2448
2449 if (( $# > 0 )) && [[ ${1,,} =~ ^-+a(ll)? ]]; then
2450
2451 (( $isPresentFlag == 3 )) && echo -e "\nBUILD RUN #1" || echo ""
2452 ( (( $isPresentFlag == 1 )) | (( $isPresentFlag == 3 )) ) && cat "${RPM_BUILD_DIR%/}/.STATUS_1";
2453
2454 (( $isPresentFlag == 3 )) && echo -e "\n\n-------------------------------------------------------------------------------\n\nBUILD RUN #2" || echo -e ""
2455 ( (( $isPresentFlag == 2 )) | (( $isPresentFlag == 3 )) ) && cat "${RPM_BUILD_DIR%/}/.STATUS_2";
2456
2457 echo -e "\n\n-------------------------------------------------------------------------------\n"
2458
2459 elif (( $# > 0 )) && [[ ${1,,} =~ ^-+s(ide)?-?by?-?s(ide)?(=[0-9]+)?$ ]]; then
2460
2461 (( $isPresentFlag == 1 )) && cat "${RPM_BUILD_DIR%/}/.STATUS_1";
2462 (( $isPresentFlag == 2 )) && cat "${RPM_BUILD_DIR%/}/.STATUS_2";
2463
2464 if (( $isPresentFlag == 3 )); then
2465
2466 local diffWidth
2467 local lineCount1
2468 local lineCount2
2469 local nn=0
2470
2471 lineCount1="$(cat "${RPM_BUILD_DIR%/}/.STATUS_1" | wc -l)"
2472 lineCount2="$(cat "${RPM_BUILD_DIR%/}/.STATUS_2" | wc -l)"
2473
2474 # Transform lineCount{1,2} variables from raw number of lines into the
2475 # number of lines that need to be added to make the files have the same # of lines
2476
2477 if (( $lineCount1 < lineCount2 )); then
2478 lineCount2=$(( $lineCount2 - $lineCount1 ))
2479 lineCount1=0
2480
2481 elif (( $lineCount1 > lineCount2 )); then
2482 lineCount2=$(( $lineCount1 - $lineCount2 ))
2483 lineCount1=0
2484
2485 else # must be equal
2486 lineCount1=0
2487 lineCount2=0
2488 fi
2489
2490 [[ ${1,,} =~ ^-+s(ide)?-?by?-?s(ide)?=[0-9]+$ ]] && diffWidth="${1##*=}" || diffWidth=200
2491
2492 srpmAutoBuild_isMock && echo "TBD" || diff -y --width "${diffWidth}" <(echo -e "$(nn=0 && while (( $nn < $lineCount1 )); do echo -n '\n' && ((nn++)); done )"; echo "$(cat "${RPM_BUILD_DIR%/}/.STATUS_1")") <(echo -e "$(nn=0 && while (( $nn < $lineCount2 )); do echo -n '\n' && ((nn++)); done )"; echo "$(cat "${RPM_BUILD_DIR%/}/.STATUS_2")") #| sed -E s/' [\<\>\|]'/' '/g
2493 fi
2494
2495 echo -e "\n\n-------------------------------------------------------------------------------\n"
2496
2497 elif (( $# == 0 )) || [[ ! ${1,,} =~ ^-+s(imple)?$ ]]; then
2498
2499 (( $isPresentFlag == 3 )) && echo -e "\nBUILD RUN #1 \n\n" || echo -e "\n"
2500 ( (( $isPresentFlag == 1 )) | (( $isPresentFlag == 3 )) ) && cat "${RPM_BUILD_DIR%/}/.STATUS_1" | head -n -2 | sed -zE s'/^.*-{10}\n(.*)$'/'\n\1'/;
2501
2502 (( $isPresentFlag == 3 )) && echo -e "\n\n-------------------------------------------------------------------------------\n\nBUILD RUN #2 \n\n" || echo -e "\n"
2503 ( (( $isPresentFlag == 2 )) | (( $isPresentFlag == 3 )) ) && cat "${RPM_BUILD_DIR%/}/.STATUS_2" | head -n -2 | sed -zE s'/^.*-{10}\n(.*)$'/'\n\1'/;
2504
2505 echo -e "\n\n-------------------------------------------------------------------------------\n"
2506
2507 #[[ -f "${RPM_BUILD_DIR%/}/.STATUS_2" ]] && [[ -n $(cat "${RPM_BUILD_DIR%/}/.STATUS_2" | head -n -2 | sed -zE s'/^.*-{10}\n(.*)$'/'\n\1'/) ]] && ( echo -e "\n\nBUILD RUN #1: \n\n"; cat "${RPM_BUILD_DIR%/}/.STATUS_1" | head -n -2 | sed -zE s'/^.*-{10}\n(.*)$'/'\n\1'/; echo -e "\n\nBUILD RUN #2: \n\n"; cat "${RPM_BUILD_DIR%/}/.STATUS_2" ) || cat "${RPM_BUILD_DIR%/}/.STATUS_1" | head -n -2 | sed -zE s'/^.*-{10}\n(.*)$'/'\n\1'/
2508 fi
2509
2510 if [[ -f "${RPM_BUILD_DIR%/}/.STATS_OVERALL" ]] && [[ -n "$(cat "${RPM_BUILD_DIR%/}/.STATS_OVERALL")" ]]; then
2511 echo -e "\n||---------- OVERALL STATS----------||\n\n"
2512 cat "${RPM_BUILD_DIR%/}/.STATS_OVERALL"
2513 else
2514 local curStatusLine=""
2515 ( [[ -f "${RPM_BUILD_DIR%/}/.STATUS_1" ]] || [[ -f "${RPM_BUILD_DIR%/}/.STATUS_2" ]] ) && curStatusLine="$(cat ${RPM_BUILD_DIR%/}/.STATUS_* | grep -E '^CURRENT OVERALL PROGRESS \(All Build Runs\)\: ' | sort -V | tail -n 1)"
2516 ( [[ -f "${RPM_BUILD_DIR%/}/.STATUS_1" ]] || [[ -f "${RPM_BUILD_DIR%/}/.STATUS_2" ]] ) && curStatusLine="$(cat ${RPM_BUILD_DIR%/}/.STATUS_* | grep -E '^CURRENT PROGRESS\: ' | sort -V | tail -n 1)"
2517
2518 [[ -n "${curStatusLine}" ]] && echo "${curStatusLine}" || echo "CURRENT OVERALL PROGRESS (All Build Runs): $(cat ${RPM_BUILD_DIR%/}/.STATS_OVERALL)"
2519 fi
2520}
2521
2522srpmAutoBuild_setupStatsFiles() {
2523
2524 srpmAutoBuild_setEnvVars
2525 local nn=""
2526
2527 [[ -e "${RPM_BUILD_DIR%/}/.STATS_OVERALL" ]] && chmod 777 "${RPM_BUILD_DIR%/}/.STATS_OVERALL" && \rm -rf "${RPM_BUILD_DIR%/}/.STATS_OVERALL"
2528 touch "${RPM_BUILD_DIR%/}/.STATS_OVERALL" && chmod 777 "${RPM_BUILD_DIR%/}/.STATS_OVERALL"
2529
2530
2531 echo -e "\n||---------- OVERALL BUILD STATISTICS ----------|| \n\n# SPECS PROCESSED: \t\t 0" >> "${RPM_BUILD_DIR%/}/.STATS_OVERALL"
2532 for nn in {'# SUCCESSFUL BUILDS','# FAILED BUILDS','# SKIPPED BUILDS'}; do echo -e "${nn}: \t\t 0 ---> 0%" >> "${RPM_BUILD_DIR%/}/.STATS_OVERALL"; done
2533 echo -e '\n----------------------------------------\n' >> "${RPM_BUILD_DIR%/}/.STATS_OVERALL"
2534 for nn in {'SUCCESS ON 1ST BUILD ATTEMPT','SUCCESS ON 2ND BUILD ATTEMPT','SUCCESS ON 3RD BUILD ATTEMPT','SUCCESS ON 4TH BUILD ATTEMPT'}; do echo -e "${nn}: \t 0 ---> 0%" >> "${RPM_BUILD_DIR%/}/.STATS_OVERALL"; done
2535
2536}
2537
2538srpmAutoBuild_updateStatsFiles() {
2539 # input is nFailsCur from main loop
2540
2541 local keyCur=0
2542 local nn=0
2543 local numFields=0
2544 local -a fieldsCur
2545 local -a valsCur
2546 local -a countLabels=('1ST' '2ND' '3RD' '4TH')
2547
2548 [[ -f "${RPM_BUILD_DIR%/}/.STATS_OVERALL" ]] || echo ".STATS_OVERALL file not found" && return 1
2549 [[ ${1,,} =~ ^[0-4]$ ]] && keyCur=${1} || [[ "${1,,}" == "nan" ]] && keyCur=5 || echo "Invalid Input" && return 2
2550
2551 fieldsCur[0]='# SPECS PROCESSED'
2552
2553 (( $keyCur < 4 )) && fieldsCur[1]='# SUCCESSFUL BUILDS' || (( $keyCur == 4 )) && fieldsCur[1]='# FAILED BUILDS' || (( $keyCur == 5 )) && fieldsCur[1]='# SKIPPED BUILDS'
2554 (( $keyCur < 4 )) && fieldsCur[2]='SUCCESS ON '"${countLabels[$keyCur]}"' BUILD ATTEMPT'
2555
2556 numFields=${#fieldsCur[@]}
2557
2558 for nn in $(seq 0 $(( $numFields - 1 ))); do
2559 valsCur[$nn]=$((( $(cat "${RPM_BUILD_DIR%/}/.STATS_OVERALL" | grep -E '^'"${fieldsCur[$nn]//'#'/'\#'}" | sed -E s/'^[^0-9]*([0-9]*).*$'/'\1'/) + 1 )))
2560
2561 (( $nn == 0 )) && sed -iE s/'^('"${fieldsCur[$nn]//'#'/'\#'}"'[^0-9]*).*$'/'\1'"${valsCur[$nn]}"/ "${RPM_BUILD_DIR%/}/.STATS_OVERALL"
2562 (( $nn == 1 )) && sed -iE s/'^('"${fieldsCur[$nn]//'#'/'\#'}"'[^0-9]*).*$'/'\1'"${valsCur[$nn]} ---> $((( ( 100 * ${valsCur[$nn]} ) / ${valsCur[0]} )))%"/ "${RPM_BUILD_DIR%/}/.STATS_OVERALL"
2563 (( $nn == 2 )) && sed -iE s/'^('"${fieldsCur[$nn]//'#'/'\#'}"'[^0-9]*).*$'/'\1'"${valsCur[$nn]} ---> $((( ( 100 * ${valsCur[$nn]} ) / ${valsCur[0]} )))% (total) | $((( ( 100 * ${valsCur[$nn]} ) / ${valsCur[1]} )))% (of successful builds)"/ "${RPM_BUILD_DIR%/}/.STATS_OVERALL"
2564
2565 done
2566}
2567
2568
2569srpmAutoBuild_fixSpecFile_majorMinorMakedevError() {
2570 # $1 is the path of the specfile to fix
2571 # $2 is the name of the c source code file that caused the error (should be listed in the rpmbuild error message)
2572 # note: this fix is NOT automatically implemented. Manually implementing is easy, it just isnt automated. Just run the following:
2573 # `srpmAutoBuild_fixSpecFile_majorMinorMakedevError <specfile> <c-file>` and then re-try to build the specfile.
2574
2575 local cFile=""
2576 local specFileFull=""
2577
2578 cFile="${2}"
2579 if [[ "${cFile}" == *"/BUILD/"* ]]; then
2580 cFile="${cFile##*/BUILD/}"
2581 cFile="${cFile#*/}"
2582 fi
2583
2584 specFileFull="$(echo "$(cat "${1%.spec}.spec")")"
2585 specFileFull="$(echo "${specFileFull/'%build'/'%build sed -i -z -E s/'"'"'\n#include <'"'"'/'"'"'\n#include <sys\/sysmacros.h>\n#include <'"'"'/ '"${cFile}"}" | sed -z -E s/'\%build sed -i -z -E s'/'\%build\nsed -i -z -E s'/)"
2586
2587 echo "${specFileFull}" > "${1%'.spec'}.spec"
2588}
2589
2590srpmAutoBuild_checkBuildErrorLog() {
2591 # checks the error message log produced by the build to try to smartly auto-fix errors
2592 # $1: buildID
2593 # $2: specNameCur
2594
2595 [[ -f "${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${1}" ]] || return
2596
2597 # fix major/minor/makedev error
2598
2599 [[ -n "$(cat "${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${1}" | grep -E 'undefined reference to .?((major)|(minor)|(makedev))')" ]] && srpmAutoBuild_fixSpecFile_majorMinorMakedevError "${2}" "$(cat "${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${1}" | grep -E 'undefined reference to .?((major)|(minor)|(makedev))' | sed -E s/'^(.+ )?([^ ]*\.c)[\: ].*$'/'\2'/ | sort -u)"
2600
2601}
2602
2603
2604srpmAutoBuild_build() {
2605 # runs full build loop as a stand alone code to be used on either SRPMs or SPEC-files.
2606 #
2607 # input can be a srpm or a specfile. If it is an srpm then a specfile will be built into a specfile prior to the package being built.
2608 # build dependencies will automatically be installed, and many common rpm build errors will be dealt with automatically.
2609 # Basically everything happens automatically without needing additional user input after the function is called.
2610 #
2611 # 3 FLAGS are recognized that change the function behavior. These are not case sensitive, and can be in any input (not limited to first or last inputs)
2612 #
2613 # 1) REVERSEING THE BUILD ORDER. '-r' or '--reverse': reverse the order that the SPECs are built in. This allows for 2 build processes to run simultaneously and not overlap. Alternately, use '-nr' or '--no-reverse' to forse standard (alphabetical order). If not explicitly set, It will be set based on the build run type automatically. Typically, youll want to run the 1st builder on the SRPMS, let it finish installing build dependencies and building SPECs, and then after the 1st builder starts building the RPMs from the SPECS start the 2nd builder using the --reverse Flag (on the just-built spec-files, not the original srpms).
2614 #
2615 # 2) FORCE RE-BUILDING RPMS, EVEN IF ONE OF THE SAME NAME/VERSION/ARCH WAS ALREADY BUILT.'-f' or '--force': The code will by default look for already build RPMs, and if it finds a RPM in a directory indicating it was custom built (i.e., it is somewhere in either ${LOCALREPO_DIR%/}/built or ${RPM_BUILD_DIR%/}/RPMS) with the same name AND the same version, the spec-file isnt built. This Flag forces building the SRPM/SPEC, even if a match has been found indicating that it has already has been built and the RPM currently exists. The code will try to build all the SRPMs that it can, even if they exist already
2616 #
2617 # 3) DISABLING "FUZZY" MATCHING OF INPUTS WITHOUT AN EXACT FILE/DIRECTORY NAME MATCH. '-na' or '--no-auto' or '--no-auto-match': The code will by default try to match up inputs to existing files even if the input isnt a full filename match. Matches are looked for in the pwd and in the RPM build tree SRPM and SPEC directories. Matches in $(pwd) are prioritized. If the file extension is not given, the matching priority is: SPECS in pwd > srpms in pwd > specs in ${RPM_BUILD_DIR%/}/SPECS > srpms in in ${RPM_BUILD_DIR%/}/SRPMS. Enabling this Flag will require an exact filename match (either full or relative path, but exact nonetheless), and anything without an exact match is ignored.
2618 #
2619 # 4) FORCING BUILD RUN TYPE.
2620 # Use '-b1' or '--build(1|main|primary)' to force using build run #1 (primary run). This is the default, UNLESS both the following conditions are met: a) "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" does not exist, and b) both "${RPM_BUILD_DIR%/}/.BUILD_LIST_1" "${RPM_BUILD_DIR%/}/.STATUS_1" exist and are non empty and have PID identifiers different than the current build run. Note that using build run #1 will automatically set --no-reverse', unless '--reverse' is explicitly fgiven as an input.
2621 # Use '-b2' or '--build(2|secondary)' to force using build run #2 (secondary run). Note that using build run #2 will automatically set --reverse', unless '--no-reverse' is explicitly fgiven as an input.
2622 #
2623 # 5) RECURSIVE SEARCHING OF INPUT DIRECTORIES. By default, if any inputs are directories only the top level of that directory is scanned for SPECs and SRPMs. Use flag '-rec' or '--recursive' to include all subdirectories when scanning input directories for SPECs/SRPMs
2624 #
2625 # 6) FORCING THE USE OF SPECFILES
2626 # '-so' or '--specs-only': this will entirely ignore any SRPMs in the input. They will not be built into specs, nor into RPMs
2627 # '-sfr' or '--specs-force-rebuild': this will cause SRPMs to be rebuilt into specs, even if a specfile with the same name/version already exists in ${RPM_BUILD_DIR%/}/SPECS. The default behavior is to not rebuild SPECs, so long as both packasge name AND package version match between the SRPM and the SPEC-file.
2628 #
2629 # Note: the FLAGS actually recognized are slightly more general than what is shown here. example: you can add omit some (though not all) '-' characters (the 1st character must always be a '-' though)
2630
2631 # setup environment variables
2632 srpmAutoBuild_setEnvVars
2633
2634 local -a name_SPECS
2635 local -a name_SPECS_short
2636 local -a name_SRPMS
2637 local -a name_INPUT
2638 local -a nFailsAll
2639 local foundMatchCur=""
2640 local reverseOrderFlag
2641 local forceFlag=0
2642 local noAutoMatchFlag=0
2643 local recursiveDirSearchFlag=0
2644 local buildID=0
2645 local nn=0
2646 local nn2=""
2647 local kk=0
2648 local ff=0
2649 local ss=0
2650 local skipCurFlag=0
2651 local nSPECS=0
2652 local nameTemp=""
2653 local name_SPECS_builtFromSRPMS=""
2654 local built_dir=""
2655 local failed_dir=""
2656 local skipped_dir=""
2657 local rpmTempDir=""
2658 local buildID=0
2659 local specsOnlyFlag=0
2660 local specsForceRebuildFlag=0
2661
2662 rpmTempDir="$(srpmAutoBuild_getUniqueDir "${RPM_BUILD_DIR%/}/TEMP")"
2663
2664 while (( $# > 0 )); do
2665 if [[ ${1,,} =~ ^-+r(everse)?$ ]]; then
2666 reverseOrderFlag=1
2667 elif [[ ${1,,} =~ ^-+no?-?r(everse)?$ ]]; then
2668 reverseOrderFlag=0
2669 elif [[ ${1,,} =~ ^-+f(orce)?$ ]]; then
2670 forceFlag=$(( $forceFlag + 1 ))
2671 elif [[ ${1,,} =~ ^-+n(a|(o-?a(uto(-?match)?)?))$ ]]; then
2672 noAutoMatchFlag=$(( $noAutoMatchFlag + 1 ))
2673 elif [[ ${1,,} =~ ^-+b(1|(uild-?((main)|(primary)|1)))$ ]]; then
2674 buildID=1
2675 elif [[ ${1,,} =~ ^-+b(2|(uild-?((secondary)|2)))$ ]]; then
2676 buildID=2
2677 elif [[ ${1,,} =~ ^-+rec(ursive)?$ ]]; then
2678 recursiveDirSearchFlag=1
2679 elif [[ ${1,,} =~ ^-+s(pecs)?-?o(nly)?$ ]]; then
2680 specsOnlyFlag=1
2681 elif [[ ${1,,} =~ ^-+s(pecs)?-?f(orce)?-?r(ebuild)?$ ]]; then
2682 specsForceRebuildFlag=1
2683 else
2684 if [[ ${1} =~ ^[^\ \t\n]+$ ]] && [[ "$(realpath "${1}")" =~ ^[^\ \t\n]+$ ]]; then
2685 name_INPUT+=("$(realpath "${1}")")
2686 elif [[ ${1} =~ ^[\ \t\n]*$ ]]; then
2687 # input is empty
2688 continue
2689 else
2690 echo -e "\n\nWARNING: input \"${1}\" contains at least 1 space/tab/newline in its file path. This will break srpmAutoBuild in many ways."
2691
2692 [[ ! -e "${1}" ]] && echo -e "There is not an exact file/directory match for this input. \nAs such, it will be ignored. No \"fuzzy matching\" will be attempted." >&2 & continue
2693
2694 echo "\nAs such, the specified file will be moved to \"${rpmTempDir}\" and renamed without spaces/tabs/newlines prior to being utilized by srpmAutoBuild. \n" >&2
2695
2696 # move file. Remove any spaces present in filename aswell
2697 name_INPUT+=($(echo "${rpmTempDir%/}/${1##*/}" | sed -zE s/' '/'__SPACE__'/g | sed -zE s/'\t'/'__TAB__'/g | sed -zE s/'\n'/'__NEWLINE__'/g)")")
2698 \mv -f "${1}" "${name_INPUT[$nn]}"
2699
2700 fi
2701 [[ -n "${name_INPUT[$nn]}" ]] && ((nn++))
2702 fi
2703 shift 1
2704 done
2705
2706 ### set default for empty input
2707 if (( $nn == 0 )) || [[ -z "${name_INPUT[*]}" ]]; then
2708 name_INPUT=("${name_INPUT[@]}")
2709 name_INPUT[0]="${RPM_BUILD_DIR%/}/SPECS"
2710 (( $specsOnlyFlag == 0 )) && name_INPUT[1]="${RPM_BUILD_DIR%/}/SRPMS"
2711 fi
2712
2713 echo "nn = ${nn}" >&2
2714 echo "name_INPUT = ${name_INPUT[*]}" >&2
2715
2716 # remove temp dir if unused
2717 [[ -z "$(find "${rpmTempDir}" -maxdepth 1 -type f)" ]] && \rm -rf "${rpmTempDir}" && rpmTempDir=""
2718
2719 # if running in automatic mode, make the primary build run write an indicator to "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock". NO means it is currently building SPECS from SRPMS, and any positive numeric integer means all SPECS have been generated and have begun to be built into RPMS, empty/missing means 1st build run isnt active. 2nd build run always uses --reverse, so do not let the function be in control of the indicator is it uses rhe --reverse flag.
2720
2721 [[ -z "${BASHPID}" ]] && BASHPID="$(echo $$)"
2722
2723 #if ( [[ -z ${buildID} ]] || (( $buildID == 0 )) ); then
2724 # ( [[ ! -e "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" ]] && ( [[ -e "${RPM_BUILD_DIR%/}/.BUILD_LIST_1" ]] && [[ -n "$(cat "${RPM_BUILD_DIR%/}/.BUILD_LIST_1")" ]] && [[ "$(echo "$(cat "${RPM_BUILD_DIR%/}/.BUILD_LIST_1" | head -n 1)")" != "${BASHPID}" ]] ) && ( [[ -e "${RPM_BUILD_DIR%/}/.STATUS_1" ]] && [[ -n "$(cat "${RPM_BUILD_DIR%/}/.STATUS_1")" ]] && [[ "$(echo "$(cat "${RPM_BUILD_DIR%/}/.STATUS_1" | head -n 1)")" != "${BASHPID}" ]] ) && ( [[ -e "${RPM_BUILD_DIR%/}/.STATS_OVERALL" ]] && [[ -n "$(cat "${RPM_BUILD_DIR%/}/.STATS_OVERALL")" ]] ) ) && buildID=2 || buildID=1
2725 #fi
2726
2727 ( (( $buildID == 1 )) || (( $buildID == 2 )) ) || buildID=1
2728 [[ -z ${reverseOrderFlag} ]] && reverseOrderFlag="$(( $buildID - 1 ))"
2729
2730 if (( $buildID == 1 )); then
2731 srpmAutoBuild_setupStatsFiles
2732 [[ -d "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" ]] && chmod 777 -R "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" && \mv -f "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" "$(srpmAutoBuild_getUniqueDir -n "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock.old")"
2733 [[ -f "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" ]] || touch "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" && chmod 777 "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock"
2734 fi
2735
2736 echo -ne "\n\nbuildID = ${buildID} ----> " >&2; (( $buildID == 1 )) && echo "PRIMARY BUILD RUN STARTED" >&2 || echo "SECONDARY BUILD RUN STARTED" >&2
2737
2738 [[ -e "${RPM_BUILD_DIR%/}/.BUILD_LIST_${buildID}" ]] && chmod 777 "${RPM_BUILD_DIR%/}/.BUILD_LIST_${buildID}" && \rm -rf "${RPM_BUILD_DIR%/}/.BUILD_LIST_${buildID}"
2739 [[ -e "${RPM_BUILD_DIR%/}/.STATUS_${buildID}" ]] && chmod 777 "${RPM_BUILD_DIR%/}/.STATUS_${buildID}" && \rm -rf "${RPM_BUILD_DIR%/}/.STATUS_${buildID}"
2740 echo -ne "\nBUILD PROCESS PID: "; echo "${BASHPID}" | tee "${RPM_BUILD_DIR%/}/.BUILD_LIST_${buildID}" "${RPM_BUILD_DIR%/}/.STATUS_${buildID}"
2741
2742 (( $specsOnlyFlag == 0 )) && echo -e "\n\nBuilding SRPM's into SPEC-files and prepping for main package building phase..." >&2 || echo -e "\n\nONLY EXISTING SPEC-FILES WILL BE USED. SRPM's will not be built into SPEC's." >&2
2743
2744 nINPUT=${#name_INPUT[@]}
2745 echo "nINPUT (orig): $nINPUT" >&2
2746
2747 # expand files to full paths and call `realpath` (again). if any directories were passed as inputs, find any *.spec or *.src.rpm files in the top level of said directories, and add those to the build list.
2748
2749 for nn in $(seq 0 $(( $nINPUT - 1 ))); do
2750
2751 name_INPUT[$nn]="$(realpath "${name_INPUT[$nn]}")"
2752
2753 nameTemp=""
2754
2755 if [[ -d "${name_INPUT[$nn]}" ]]; then
2756
2757 name_INPUT[$nn]="$(echo "$(find "${name_INPUT[$nn]}" $( (( $recursiveDirSearchFlag == 0 )) && echo '-maxdepth 1') -type f -name "*.spec")"; echo "$(find "${name_INPUT[$nn]}" $( (( $recursiveDirSearchFlag == 0 )) && echo '-maxdepth 1') -type f -name "*.src.rpm")")"
2758
2759 elif ! [[ -f "${name_INPUT[$nn]}" ]] && (( noAutoMatchFlag == 0 )); then
2760
2761 nameTemp="$(find "${name_INPUT[$nn]%/*}" $( (( $recursiveDirSearchFlag == 0 )) && echo '-maxdepth 1') -type d -name "${nameTemp##*/}")"
2762
2763 if [[ -n "${nameTemp}" ]]; then
2764
2765 nameTemp2=($(echo "${nameTemp}"))
2766 nameTemp=""
2767
2768 for nn2 in "${nameTemp2[@]}"; do
2769 nameTemp="$(echo "${nameTemp}"; echo "$(find "${nn2}" $( (( $recursiveDirSearchFlag == 0 )) && echo '-maxdepth 1') -type f -name "*.spec")"; echo "$(find "${nn2}" $( (( $recursiveDirSearchFlag == 0 )) && echo '-maxdepth 1') -type f -name "*.src.rpm")")"
2770
2771 done
2772 fi
2773
2774 if [[ -z "${nameTemp}" ]] && (( $recursiveDirSearchFlag > 0 )); then
2775
2776 nameTemp="$(find "/" -type f -name "*${name_INPUT[$nn]}*")"
2777
2778 [[ -n "${nameTemp}" ]] && nameTemp="$(echo "$(echo "${nameTemp}" | grep -E '\.spec$' | sort -V; echo "${nameTemp}" | grep -E '\.src\.rpm$' | sort -V; echo "${nameTemp}" | grep -v -E '((\.spec)|(\.src\.rpm))$' | sort -V)")"
2779
2780 fi
2781
2782 [[ -n "${nameTemp// /}" ]] && name_INPUT[$nn]="${nameTemp}" || name_INPUT[$nn]=""
2783
2784 fi
2785
2786 done
2787
2788 name_INPUT=("${name_INPUT[@]}")
2789 name_INPUT=($(echo "${name_INPUT[@]}" | sed -zE s/' '/'\n'/g | sort -u))
2790
2791 nINPUT=${#name_INPUT[@]}
2792 echo "nINPUT: $nINPUT" >&2
2793
2794 [[ -n "${name_INPUT[*]}" ]] && eval $( echo "${name_INPUT[@]}" | sed -E s/'^(.*)$'/'\[\[ -e "\1" \]\] \|\| '/ | sed -zE s/'\n'// | sed -zE s/'^(.*) \|\|[^a-zA-Z0-9]*$'/'\1'/ ) && chmod 777 "${name_INPUT[@]}"
2795
2796 # Try to match each input individually with an existing file and determine if the input is a specfile or srpm.
2797
2798 for nn in $(seq 0 $(( $nINPUT - 1 ))); do
2799
2800 name_INPUT[$nn]="$(realpath "${name_INPUT[$nn]}")"
2801
2802 # set initial matching flag state
2803 if ! [[ -f "${name_INPUT[$nn]}" ]]; then
2804 foundMatchCur=0
2805 elif [[ ${name_INPUT[$nn]} == *.spec ]]; then
2806 foundMatchCur=1
2807 name_SPECS+=("${name_INPUT[$nn]}")
2808 elif [[ ${name_INPUT[$nn]} == *.src.rpm ]]; then
2809 (( $specsOnlyFlag == 1 )) && echo -e "NOTICE: skipping SRPM ${name_INPUT[$nn]} because the '--specs-only' flag is in use. \nIt will NOT be built, unless an already-generated SPOEC-file is included in the build queue." >&2 && continue
2810 foundMatchCur=2
2811 name_SRPMS+=("${name_INPUT[$nn]}")
2812 else
2813 foundMatchCur=0
2814 fi
2815
2816 if (( $foundMatchCur == 0 )) && (( $noAutoMatchFlag == 0 )); then
2817 # attempt smart matching to find a close match, since there wasnt an exact file match with correct file extension to the input
2818
2819 if [[ ${name_INPUT[$nn]} == *.spec ]]; then
2820 # definitely have a specfile. Check $(pwd) then check ${RPM_BUILD_DIR%/}/SPECS
2821
2822 if [[ -f "$(pwd)/${name_INPUT[$nn]##*/}" ]]; then
2823 name_SPECS+=("$(find "$(pwd)" -type f -wholename "${name_INPUT[$nn]##*/}")")
2824 [[ -z "${name_SPECS[$nn]}" ]] && name_SPECS+=("$(find "$(pwd)" -type f -name "${name_INPUT[$nn]##*/}")")
2825
2826 elif [[ -f "${RPM_BUILD_DIR%/}/SPECS/${name_INPUT[$nn]##*/}" ]]; then
2827 name_SPECS+=("$(find "${RPM_BUILD_DIR%/}/SPECS" -type f -name "${name_INPUT[$nn]##*/}")")
2828
2829 else
2830 name_SPECS+=("$(find / -type f -wholename "*${name_INPUT[$nn]}")")
2831 fi
2832
2833 [[ -n $(echo "${name_SPECS[$nn]}") ]] && foundMatchCur=1
2834
2835 elif (( $specsOnlyFlag == 0 )) && [[ ${name_INPUT[$nn]} == *.src.rpm ]]; then
2836 # definitely have a srpm. Check $(pwd) then check ${RPM_BUILD_DIR%/}/SRPMS
2837
2838 if [[ -f "$(pwd)/${name_INPUT[$nn]##*/}" ]]; then
2839 name_SRPMS+=("$(find "$(pwd)" -type f -wholename "${name_INPUT[$nn]}")")
2840 [[ -z "${name_SRPMS[$nn]}" ]] && name_SRPMS+=("$(find "$(pwd)" -type f -name "${name_INPUT[$nn]##*/}")")
2841
2842 elif [[ -f "${RPM_BUILD_DIR%/}/SRPMS/${name_INPUT[$nn]##*/}" ]]; then
2843 name_SRPMS+=("$(find "${RPM_BUILD_DIR%/}/SRPMS" -type f -name "${name_INPUT[$nn]##*/}")")
2844
2845 else
2846 name_SRPMS+=("$(find / -type f -wholename "*${name_INPUT[$nn]}")" )
2847 fi
2848
2849 [[ -n $(echo "${name_SRPMS[$nn]}") ]] && foundMatchCur=2
2850 fi
2851
2852 if (( $foundMatchCur == 0 )); then
2853 # no matches treating it as a filename with proper extension. Repeat matching search (first in $(pwd), then in ${RPM_BUILD_DIR%/}/<...>, but this time try adding either '.spec' or '.src.rpm' to the end of the given input.
2854
2855 if [[ -f "$(pwd)/${name_INPUT[$nn]##*/}.spec" ]]; then
2856 name_SPECS+=("$(find "$(pwd)" -type f -wholename "${name_INPUT[$nn]}.spec")")
2857 [[ -z "${name_SPECS[$nn]}" ]] && name_SPECS+=("$(find "$(pwd)" -type f -name "${name_INPUT[$nn]##*/}.spec")")
2858 [[ -n "${name_SPECS[$nn]}" ]] && foundMatchCur=1
2859
2860 elif (( $specsOnlyFlag == 0 )) && [[ -n "$(find "$(pwd)" -type f -name "${name_INPUT[$nn]##*/}*.src.rpm")" ]]; then
2861 name_SRPMS+=("$(find "$(pwd)" -type f -wholename "${name_INPUT[$nn]}.src.rpm")")
2862 [[ -z "${name_SRPMS[$nn]}" ]] && name_SRPMS+=("$(find "$(pwd)" -type f -name "${name_INPUT[$nn]##*/}.src.rpm")")
2863 [[ -n "${name_SRPMS[$nn]}" ]] && foundMatchCur=2
2864
2865 elif [[ -f "${RPM_BUILD_DIR%/}/SPECS/${name_INPUT[$nn]##*/}.spec" ]]; then
2866 name_SPECS+=("$(find "${RPM_BUILD_DIR%/}/SPECS" -type f -name "${name_INPUT[$nn]##*/}.spec")")
2867 [[ -n "${name_SPECS[$nn]}" ]] && foundMatchCur=1
2868
2869 elif (( $specsOnlyFlag == 0 )) && [[ -n "$(find "${RPM_BUILD_DIR%/}/SRPMS" -type f -name "${name_INPUT[$nn]##*/}*.src.rpm")" ]]; then
2870 name_SRPMS+=("$(find "${RPM_BUILD_DIR%/}/SRPMS" -type f -name "${name_INPUT[$nn]##*/}*.src.rpm")")
2871 [[ -n "${name_SRPMS[$nn]}" ]] && foundMatchCur=2
2872 fi
2873
2874 fi
2875
2876 fi
2877
2878 # if current file is not a spec-file, remove it from name_SPECS. If it, however, a srpm, add it to name_SRPMS. If it is neither drop it all together.
2879
2880 (( $foundMatchCur == 0 )) && echo "WARNING: ${name_INPUT[$nn]} could not be found as either a SPEC-file nor a SRPM package. It will NOT be built." >&2
2881
2882 (( $foundMatchCur == 1 )) && echo "NOTICE: ${name_INPUT[$nn]} was identified as a SPEC-file (${name_SPECS[$nn]##*/}). It will be built into a RPM." >&2
2883
2884 (( $foundMatchCur == 2 )) && echo "NOTICE: ${name_INPUT[$nn]} was identified as a SRPM (${name_SRPMS[$nn]##*/}). It will be built into a SPEC-file, and then built into a RPM." >&2
2885
2886 done
2887
2888 echo -e "\nDONE ANALYSING INPUT FILES \n ${#name_SPECS[@]} SPEC-files Identified \n ${#name_SRPMS[@]} SRPMS Identified\n" >&2 && sleep 2
2889
2890 (( $specsOnlyFlag == 1 )) && name_SRPMS=($(echo -n ""))
2891
2892 (( ( ${#name_SRPMS[@]} + ${#name_SPECS[@]} ) == 0 )) && echo "NOTHING TO BUILD! EXITING" >&2 && return
2893
2894
2895 (( ${#name_SPECS[@]} > 0 )) && for nn in $(seq 0 $(( ${#name_SPECS[@]} - 1 ))); do
2896 [[ ${name_SPECS[$nn]} == ${RPM_BUILD_DIR%/}/SPECS/* ]] || \mv -f "${name_SPECS[$nn]}" "${RPM_BUILD_DIR%/}/SPECS/${name_SPECS[$nn]##*/}" && name_SPECS[$nn]="${RPM_BUILD_DIR%/}/SPECS/${name_SPECS[$nn]##*/}"
2897 done
2898
2899 (( ${#name_SRPMS[@]} > 0 )) && for nn in $(seq 0 $(( ${#name_SRPMS[@]} - 1 ))); do
2900 [[ ${name_SRPMS[$nn]} == ${RPM_BUILD_DIR%/}/SRPMS/* ]] || \mv -f "${name_SRPMS[$nn]}" "${RPM_BUILD_DIR%/}/SRPMS/${name_SRPMS[$nn]##*/}" && name_SRPMS[$nn]="${RPM_BUILD_DIR%/}/SRPMS/${name_SRPMS[$nn]##*/}"
2901 done
2902
2903 # apply fix for weird naming issue
2904 #for nn in "${RPM_BUILD_DIR%/}/SPECS/"''$'\n'*; do
2905 # mv "${nn}" $(echo "${nn}" | sed -zE s/'SPECS\/\n'/'SPECS\/'/g)
2906 #done
2907
2908 if (( $specsOnlyFlag == 0 )) && (( ${#name_SRPMS[@]} > 0 )); then
2909 echo "STARTING TO BUILD SRPMS INTO SPECS..." >&2
2910 echo "Determining and installing package dependencies for all SRPMS..." >&2 && sleep 2
2911
2912 # empty out ${RPM_BUILD_DIR%/}/SPECS directory
2913 rpmTempDir=""
2914 if [[ -n $(find "${RPM_BUILD_DIR%/}/SPECS" -maxdepth 1 -type f -name "*.spec") ]]; then
2915 rpmTempDir="$(srpmAutoBuild_getUniqueDir "${RPM_BUILD_DIR%/}/SPECS/.temp")"
2916 mv ${RPM_BUILD_DIR%/}/SPECS/*.spec "${rpmTempDir}"
2917 fi
2918
2919 # download/install build dependencies for all srpms
2920 #srpmAutoBuild_builddep "${name_SRPMS[@]}"
2921
2922
2923 # build SPEC-files from all the input SRPMs
2924 echo "Build dependencies downloaded. Starting to build SRPMs into SPEC-files" >&2 && sleep 2
2925 srpmAutoBuild_build_SRPM_SPEC "-f$((( ( 2 * $forceFlag ) + $specsForceRebuildFlag )))" "${name_SRPMS[@]}"
2926
2927 # apply fix for weird naming issue
2928 #for nn in "${RPM_BUILD_DIR%/}/SPECS/"''$'\n'*; do
2929 # mv "${nn}" $(echo "${nn}" | sed -zE s/'SPECS\/\n'/'SPECS\/'/g)
2930 #done
2931
2932 name_SPECS_builtFromSRPMS="$(find "${RPM_BUILD_DIR%/}/SPECS" -maxdepth 1 -type f -name "*.spec")"
2933
2934 # add newly build SPEC-file names to list
2935 name_SPECS=($(echo "$(echo "${name_SPECS[@]}" | sed -zE s/' +'/'\n'/g | sed -zE s/'\n+'/'\n'/g | sed -zE s/'^(.*[^\n])\n*$'/'\1'/ ; echo "${name_SPECS_builtFromSRPMS}")" | sort -u))
2936
2937 # if stuff was initially moved out of ${RPM_BUILD_DIR%/}/SPECS, put it back. Dont overwrite the newer spec's if there are any matching ones
2938 if [[ -n "${rpmTempDir}" ]]; then
2939 \mv -n ${rpmTempDir%/}/*.spec "${RPM_BUILD_DIR%/}/SPECS/"
2940 \rm -rf "${rpmTempDir:?}/"
2941 rpmTempDir=""
2942 fi
2943
2944 fi
2945
2946 # download/install build dependencies for all specfiles
2947 srpmAutoBuild_builddep "${name_SPECS[@]}"
2948
2949 # short name: no file path, no '.spec', just the package name.
2950 name_SPECS_short=($(echo "${name_SPECS[@]}" | sed -zE s/' +'/'\n'/g | sed -zE s/'\n+'/'\n'/g | sed -zE s/'^(.*[^\n])\n*$'/'\1'/ | sed -E s/'^.*\/([^\/]*)\.spec(\.old)?$'/'\1'/))
2951
2952 nSPECS=${#name_SPECS[@]}
2953 echo "# specfiles (final): $nSPECS" >&2
2954
2955 # Setup BUILT and FAILED directories to move specs into after they are finished being processed.
2956 # If these directories exist from previous builds, enumerate them and place them in directories BUILT_OLD and FAILED_OLD
2957
2958 [[ -d "${RPM_BUILD_DIR}" ]] || mkdir "${RPM_BUILD_DIR}"
2959 chmod 777 $(find "${RPM_BUILD_DIR}" -maxdepth 1 -type d)
2960
2961 built_dir="${RPM_BUILD_DIR%/}/SPECS/BUILT"
2962 failed_dir="${RPM_BUILD_DIR%/}/SPECS/FAILED"
2963 skipped_dir="${RPM_BUILD_DIR%/}/SPECS/SKIPPED"
2964 rpmTempDir=""
2965
2966 if [[ -d "${built_dir}" ]]; then
2967 [[ -d "${built_dir}_OLD" ]] || mkdir "${built_dir}_OLD"
2968 \mv -f "${built_dir}" "$(srpmAutoBuild_getUniqueDir -n "${built_dir}_OLD/")"
2969 fi
2970 [[ -d "${built_dir}" ]] || mkdir --parents "${built_dir}"
2971
2972
2973 if [[ -d "${failed_dir}" ]]; then
2974 [[ -d "${failed_dir}_OLD" ]] || mkdir "${failed_dir}_OLD"
2975 \mv -f "${failed_dir}" "$(srpmAutoBuild_getUniqueDir -n "${failed_dir}_OLD/")"
2976 fi
2977 [[ -d "${failed_dir}" ]] || mkdir --parents "${failed_dir}"
2978
2979 if [[ -d "${skipped_dir}" ]]; then
2980 [[ -d "${skipped_dir}_OLD" ]] || mkdir "${skipped_dir}_OLD"
2981 \mv -f "${skipped_dir}" "$(srpmAutoBuild_getUniqueDir -n "${skipped_dir}_OLD/")"
2982 fi
2983 [[ -d "${skipped_dir}" ]] || mkdir --parents "${skipped_dir}"
2984
2985
2986 (( $buildID == 1 )) && [[ -f "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" ]] && chmod 777 "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock" && \rm -f "${RPM_BUILD_DIR%/}/.SECONDARY_BUILD.lock"
2987
2988 nFailsAll=(0 0 0 0 0 0)
2989
2990 echo -e "\n\nMAIN BUILD LOOP IS NOW STARTING \n\n" >&2
2991
2992 [[ -z "${forceFlag}" ]] && forceFlag=0
2993 (( $forceFlag == 1 )) || forceFlag=0
2994
2995 for nn in $( seq 0 $(( $nSPECS - 1 )) | ( (( $reverseOrderFlag == 1 )) && sort -nr || tee ) ); do
2996
2997 # get current spec name and reset failed build count.
2998 nameSpecCur="${name_SPECS[$nn]}"
2999 nFailsCur=0
3000 skipCurFlag=0
3001 nameRpmCur=""
3002
3003 # Check that another build run isnt already building nthis specfile
3004 [[ "${nameSpecCur}" == "$(echo -n "$(cat "${RPM_BUILD_DIR%/}/.BUILD_LIST_$(( 3 - $buildID ))" | tail -n 1)")" ]] && skipCurFlag=3 || echo "${nameSpecCur}" >> "${RPM_BUILD_DIR%/}/.BUILD_LIST_${buildID}"
3005
3006 # check that the specfile exists
3007 (( $skipCurFlag == 0 )) && ( [[ -z "${nameSpecCur}" ]] || [[ ! -f "${nameSpecCur}" ]] ) && skipCurFlag=2
3008
3009 # check for matching rpm packages with the same name+version (unless using '--force' flag)
3010 if (( $skipCurFlag == 0 )) && (( $forceFlag == 0 )); then
3011 nameRpmCur="$(srpmAutoBuild_getInfo -n -v -a ${nameSpecCur})"
3012 nameRpmMatch="$(srpmAutoBuild_getInfo -n -v -a "$(find {"${RPM_BUILD_DIR%/}/RPMS","${LOCALREPO_DIR%/}/built"} -type f -name "*$(srpmAutoBuild_getInfo -n "${nameSpecCur}")*.rpm" | grep -v '/cache/')")"
3013 [[ -n "${nameRpmMatch}" ]] && echo "${nameRpmCur}" | grep -q -F "${nameRpmMatch}" && skipCurFlag=1
3014 fi
3015
3016 echo -e "\n\nDEBUG INFO: \n\nnameSpecCur=${nameSpecCur} \nnameRpmCur=${nameRpmCur} \nskipCurFlag=${skipCurFlag} \n\n" >&2
3017
3018 if (( $skipCurFlag <= $forceFlag )); then
3019
3020 # print status
3021 echo -e "\n\nBEGINNING BUILD # $(( $nn + 1 )) of ${nSPECS}: ${name_SPECS_short[$nn]}.spec \n\n" >&2
3022
3023 # check for missing builddeps, with erasing allowed. This is usually very quick as long as it isnt missing any dependencies, which should be the case for most packages.
3024 dnf builddep --skip-broken --allowerasing -y "${name_SPECS_short[$nn]}"
3025
3026 # Set environment variables to default, in case they were changed
3027 srpmAutoBuild_setEnvVars
3028
3029 [[ -f "${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${buildID} " ]] && chmod 777 "${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${buildID}" && \rm -f "${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${buildID}"
3030 touch "${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${buildID}"
3031
3032 # initial build attempt: try to force generation of debuginfo
3033 nFailsCur=0
3034 QA_RPATHS=$(( 0x0001|0x0010 )) rpmbuild --rpmfcdebug -bb "${nameSpecCur}" 2>${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${buildID} || nFailsCur=1 && srpmAutoBuild_checkBuildErrorLog "${buildID}" "${nameSpecCur}"
3035
3036 if (( $nFailsCur == 1 )); then
3037 # 2nd try: modify spec file to not throw an error in debug source file list is missing. Save orig as *.spec.old
3038 srpmAutoBuild_fixSpecFile_missingDebugSourceFileList "${nameSpecCur}"
3039 QA_RPATHS=$(( 0x0001|0x0010 )) rpmbuild -bb "${nameSpecCur}" 2>${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${buildID} || nFailsCur=2 && srpmAutoBuild_checkBuildErrorLog "${buildID}" "${nameSpecCur}"
3040 fi
3041
3042 if (( $nFailsCur == 2 )); then
3043 # 3rd try: switch back to original spec file. Add '-Wno-error' Flag to CFlag/CXXFlag/CPPFlag env variables. allow build to proceed in cases where there are unpackaged files or missing documentation.
3044 srpmAutoBuild_setEnvVars '-Wno-error'
3045 srpmAutoBuild_switchSpecFile "${nameSpecCur}"
3046 QA_RPATHS=$(( 0x0001|0x0010 )) rpmbuild -bb --define=" _unpackaged_files_terminate_build 0" --define=" _missing_doc_files_terminate_build 0" "${nameSpecCur}" 2>${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${buildID} || nFailsCur=3 && srpmAutoBuild_checkBuildErrorLog "${buildID}" "${nameSpecCur}"
3047 fi
3048
3049 if (( $nFailsCur == 3 )); then
3050 # 4th try: (last try) same as 3rd try, but with the modifies specfile that allows missing debug source list
3051 srpmAutoBuild_switchSpecFile "${nameSpecCur}"
3052 QA_RPATHS=$(( 0x0001|0x0010 )) rpmbuild -bb --define=" _unpackaged_files_terminate_build 0" --define=" _missing_doc_files_terminate_build 0" "${nameSpecCur}" 2>${RPM_BUILD_DIR%/}/.BUILD_ERROR_LOG_${buildID} || nFailsCur=4 && srpmAutoBuild_checkBuildErrorLog "${buildID}" "${nameSpecCur}"
3053 fi
3054
3055 if (( $nFailsCur == 4 )); then
3056 # all tries failed. Add 1 to failed count, switch the specfile back to the original, and move the orig + modded spec files into "FAILED" directory
3057 ((ff++))
3058 srpmAutoBuild_switchSpecFile "${nameSpecCur}"
3059 mv "${nameSpecCur}" "${nameSpecCur}.old" "${failed_dir}"
3060 else
3061 # build succeeded. Add 1 to success count and move specfile + modded spec file (if it exists) into "BUILT" directory
3062 ((kk++))
3063 mv "${nameSpecCur}" "${built_dir}"
3064 [[ -f "${nameSpecCur}.old" ]] && mv "${nameSpecCur}.old" "${built_dir}"
3065 fi
3066
3067 # reset environment variables
3068 srpmAutoBuild_setEnvVars
3069
3070
3071 # update total failure type stats array
3072 nFailsAll[$nFailsCur]=$(( ${nFailsAll[$nFailsCur]} + 1 ))
3073
3074 else
3075
3076 # print message saying spec file was skipped and why it wasnt built
3077 echo -e "\n\nNOTICE: ${nameSpecCur} was excluded from being built. It was skipped for the following reasons: \n" >&2
3078 (( $skipCurFlag == 3)) && echo -e "\n\n----> This specfile is currently being built by the other build process. \n\n" >&2
3079 (( $skipCurFlag == 2 )) && echo -e "\n\n----> A matching RPM with the same package name and version was found in ${RPM_BUILD_DIR%/}/RPMS, suggesting that this SPEC file has already been built. \n\nNOTE: To ignore matching already built RPMS and force (re)building, use 'srpmAutoBuild_buildSA --force'. Note that this will overwrite the existing RPM, should it exist in ${RPM_BUILD_DIR%/}/RPMS. \n\n" >&2
3080 (( $skipCurFlag == 1 )) && echo -e "\n\n----> The input SPEC-file could not be located (and/or read, if insufficient permissions). \n\n" >&2
3081
3082 # add 1 to skipped count and set # current run failures to NaN
3083 ((ss++))
3084 nFailsCur="NaN${skipCurFlag}"
3085 nFailsAll[5]=$(( ${nFailsAll[5]} + 1 ))
3086 mv "${nameSpecCur}" "${skipped_dir}"
3087
3088 fi
3089
3090 # Print info about the result of the current run and stats for all runs completed so far
3091 srpmAutoBuild_updateStatsFiles "${nFailsCur}"
3092 echo -e "\n\n-------------------------------------------------------------------------------\n\nCURRENT BUILD OPERATION HAS FINISHED! BUILD STATS: \n\nSPECFILE NAME: \"${name_SPECS_short[$nn]}\" ( ID# $(( $nn + 1 )) / ${nSPECS} ) $(srpmAutoBuild_printBuildStats "${nn}" "${nFailsCur}" "${kk}" "${ff}" "${ss}" "${nSPECS}" ${nFailsAll[@]} "${skipCurFlag}" "${buildID}") \n\n-------------------------------------------------------------------------------\n" | tee -a "${RPM_BUILD_DIR%/}/.STATUS_${buildID}" >&2
3093
3094
3095 done
3096
3097
3098}
3099
3100
3101# # # # # # # # # # EXTRA FUNCTIONS FOR MANAGING A LOCAL REPOSITORY # # # # # # # # # #
3102
3103# run `localrepo_updateDatabase` to have everything done automatically for you. The rest of the functions are supporting functions for localrepo_updateDatabase
3104# exception: localrepo_showFileTree shows the file tree,, and is for informational purposes only. Other than showing the filetree it doesnt do anything.
3105#
3106# the following environment variables will be used, if they exist:
3107# LOCALREPO_DIR: path to main localrepo dir. Default is '/localrepo'
3108# LOCALREPO_NAME: name of the main localrepo. Default is 'localrepo'
3109# VALID_ARCH_LIST: space separated lists of valid architectures. Default is "noarch x86_64 i686"
3110# LOCALREPO_BACKUP_DIR: directory to store backup in. If /DATA/${LOCALREPO_DIR#/}, exists, it will be used unless LOCALREPO_BACKUP_DIR is defined otherwise. If neither LOCALREPO_BACKUP_DIR nor /DATA/${LOCALREPO_DIR#/} the repo wont automatically make a backup copy
3111# FEDORA_COMPS_FILE_PATH: path to the fedora comps file, needed to use groups in dnf. Default location is ${LOCALREPO_DIR%/}/fedora-comps/comps-f29.xml". If this doesnt exist the code will set it up automatically
3112
3113
3114localrepo_dnf() {
3115 # runs `dnf` with only localrepo as the only active repository active
3116 # use flag '-name' as the 1st input to change 'localrepo' to 'localrepo-name'.
3117 # with default localrepo settings this shiould be '-build', '-source', or '-downloaded'.
3118 # ---> restrict packages to thoise in 'localrepo-[built|source|download]' instead of the full localrepo
3119
3120 # change this (or set env variable LOCALREPO_NAME if your local repo isnt called 'localrepo'
3121 local localrepoName=""
3122 [[ -n "${LOCALREPO_NAME}" ]] && localrepoName="${LOCALREPO_NAME}" || localrepoName='localrepo'
3123
3124 [[ ${1,,} =~ ^-+.+$ ]] && localrepoName="${localrepoName}-${1//'-'/''}" && echo "using repo: ${localrepoName}" && shift 1
3125
3126 dnf --refresh --skip-broken --disablerepo=[a-zA-Z0-9]* --enablerepo="${localrepoName}" ${@}
3127
3128}
3129
3130localrepo_setEnvVars() {
3131
3132 local LOCALREPO_DIR_orig="${LOCALREPO_DIR}"
3133 local LOCALREPO_BACKUP_DIR_orig="${LOCALREPO_BACKUP_DIR}"
3134
3135 # setup LOCALREPO_DIR
3136 ( [[ -z "${LOCALREPO_DIR}" ]] || [[ ${1} =~ ^-+c(lea[nr])?$ ]] ) && LOCALREPO_DIR="/localrepo"
3137 [[ "${LOCALREPO_DIR}" != "${LOCALREPO_DIR%/}" ]] && LOCALREPO_DIR="${LOCALREPO_DIR%/}"
3138 [[ "${LOCALREPO_DIR}" != "${LOCALREPO_DIR_orig}" ]] && echo -e "LOCALREPO_DIR set to: '${LOCALREPO_DIR}'" >&2 && export LOCALREPO_DIR
3139
3140 # setup LOCALREPO_BACKUP_DIR
3141 ( [[ -z "${LOCALREPO_BACKUP_DIR}" ]] || [[ ${1} =~ ^-+c(lea[nr])?$ ]] ) && LOCALREPO_BACKUP_DIR="/localrepo"
3142 [[ "${LOCALREPO_BACKUP_DIR}" != "${LOCALREPO_BACKUP_DIR%/}" ]] && LOCALREPO_BACKUP_DIR="${LOCALREPO_BACKUP_DIR%/}"
3143 [[ "${LOCALREPO_BACKUP_DIR}" != "${LOCALREPO_BACKUP_DIR_orig}" ]] && echo -e "LOCALREPO_BACKUP_DIR set to: '${LOCALREPO_BACKUP_DIR}'" >&2 && export LOCALREPO_BACKUP_DIR
3144
3145 # setup VALID_ARCH_LIST
3146 [[ -z "${VALID_ARCH_LIST}" ]] && VALID_ARCH_LIST="$(echo "noarch"; uname -pmi | sed -zE s/' '/'\n'/g | sort -u; [[ "$(uname -pmi | sed -zE s/' '/'\n'/g | sort -u)" == "x86_64" ]] && echo "i686" )" && export VALID_ARCH_LIST
3147
3148 # setup FEDORA_COMPS_FILE_PATH
3149 [[ -z "${FEDORA_COMPS_FILE_PATH}" ]] && FEDORA_COMPS_FILE_PATH="${LOCALREPO_DIR%/}/fedora-comps/comps-f$(uname -r | sed -E s/'^.*\.fc([0-9]*)\..*$'/'\1'/).xml" && export FEDORA_COMPS_FILE_PATH
3150}
3151
3152localrepo_makeFileTree() {
3153 # makes all the directories in ${LOCALREPO_DIR} that are required by the localrepo_* functions but do not yet exist
3154
3155 # define local repo path and list valid architectures
3156 localrepo_setEnvVars
3157
3158 local -a vaArray
3159 [[ -n "${VALID_ARCH_LIST}" ]] && vaArray=(${VALID_ARCH_LIST}) || vaArray=($(echo "noarch"; uname -pmi | sed -zE s/' '/'\n'/g | sort -u; [[ "$(uname -pmi | sed -zE s/' '/'\n'/g | sort -u)" == "x86_64" ]] && echo "i686" ))
3160
3161 [[ -d "${LOCALREPO_DIR}" ]] || mkdir --parents "${LOCALREPO_DIR}"
3162 [[ -d "${LOCALREPO_DIR%/}/cache" ]] || mkdir "${LOCALREPO_DIR%/}/cache"
3163 [[ -d "${LOCALREPO_DIR%/}/.MISC" ]] || mkdir "${LOCALREPO_DIR%/}/.MISC"
3164 [[ -d "${LOCALREPO_DIR%/}/.REMOVED" ]] || mkdir "${LOCALREPO_DIR%/}/.REMOVED"
3165
3166 for ll in {'source/','built/','downloaded/','built/debuginfo/','downloaded/debuginfo/'}; do
3167 for mm in {"","${vaArray[@]}"}; do
3168
3169 if ( [[ "${ll}" == "source/" ]] && [[ -z "${mm}" ]] ) || ( [[ "${ll}" != "source/" ]] && [[ -n "${mm}" ]] ); then
3170
3171 for nn in {a..z} {0..9}; do
3172 [[ -d "${LOCALREPO_DIR%/}/${ll%/}/${mm}packages/${nn}" ]] || mkdir --parents "${LOCALREPO_DIR%/}/${ll%/}/${mm%/}/packages/${nn}"
3173 done
3174
3175 [[ -d "${LOCALREPO_DIR%/}/${ll%/}/${mm%/}/cache" ]] || mkdir --parents "${LOCALREPO_DIR%/}/${ll%/}/${m%/}/cache"
3176
3177 fi
3178
3179 if [[ "${ll}" != *'debuginfo' ]]; then
3180
3181 [[ -d "${LOCALREPO_DIR%/}/${ll%/}/NEW" ]] || mkdir --parents "${LOCALREPO_DIR%/}/${ll%/}/NEW"
3182 [[ -d "${LOCALREPO_DIR%/}/.REMOVED/${ll}" ]] || mkdir --parents "${LOCALREPO_DIR%/}/.REMOVED/${ll}"
3183
3184 fi
3185
3186 done
3187 done
3188
3189}
3190
3191
3192localrepo_importBuiltRPMs() {
3193 # transfers RPMs from paths used by default by rpmbuild and srpmAutoBuild (~/rpmbuild and /builddir./build) into the local repo's ${LOCALREPO_DIR%/}/*/NEW folders
3194
3195 # define local repo and rpmbuild path
3196 localrepo_setEnvVars
3197
3198 local uu=""
3199
3200 # copy (S)RPMs from user rpmbuild trees into NEW directories
3201 for uu in {/root,/home/*}; do
3202 [[ -d "${uu%/}/rpmbuild/RPMS/" ]] && [[ -n $(find "${uu%/}/rpmbuild/RPMS/" -type f -name "*.rpm") ]] && chmod -R 775 ${uu%/}/rpmbuild/RPMS/*.rpm && \cp -u $(find "${uu%/}/rpmbuild/RPMS/" -type f -name "*.rpm") "${LOCALREPO_DIR%/}/built/NEW"
3203 [[ -d "${uu%/}/rpmbuild/SRPMS/" ]] && [[ -n $(find "${uu%/}/rpmbuild/SRPMS/" -type f -name "*.src.rpm") ]] && chmod -R 775 ${uu%/}/rpmbuild/SRPMS/*.rpm && \cp -u $(find "${uu%/}/rpmbuild/SRPMS/" -type f -name "*.src.rpm") "${LOCALREPO_DIR%/}/source/NEW"
3204 done
3205
3206 # copy (S)RPMs from srpmAutoBuild's RPM_BUILD_DIR into NEW directories
3207 if [[ -n "${RPM_BUILD_DIR}" ]] && [[ -d "${RPM_BUILD_DIR}" ]]; then
3208 [[ -n $(find "${RPM_BUILD_DIR%/}/RPMS/" -type f -name "*.rpm") ]] && \cp -u $(find "${RPM_BUILD_DIR%/}/RPMS/" -type f -name "*.rpm") "${LOCALREPO_DIR%/}/built/NEW"
3209 [[ -n $(find "${RPM_BUILD_DIR%/}/SRPMS/" -type f -name "*.src.rpm") ]] && \cp -u $(find "${RPM_BUILD_DIR%/}/SRPMS/" -type f -name "*src.rpm") "${LOCALREPO_DIR%/}/source/NEW"
3210 fi
3211
3212 # copy (S)RPMs from the mock build dir used by srpmAutoBuild into NEW directories
3213 if [[ -n "${MOCK_ROOT_DIR}" ]] && [[ -d "${MOCK_ROOT_DIR%/}/builddir/build" ]] && [[ "${RPM_BUILD_DIR}" != "${MOCK_ROOT_DIR%/}/builddir/build" ]]; then
3214 [[ -n $(find "${RPM_BUILD_DIR%/}/RPMS/" -type f -name "*.rpm") ]] && \cp -u $(find "${MOCK_ROOT_DIR%/}/builddir/build/RPMS/" -type f -name "*.rpm") "${LOCALREPO_DIR%/}/built/NEW"
3215 [[ -n $(find "${RPM_BUILD_DIR%/}/SRPMS/" -type f -name "*.src.rpm") ]] && \cp -u $(find "${MOCK_ROOT_DIR%/}/builddir/build/SRPMS/" -type f -name "*src.rpm") "${LOCALREPO_DIR%/}/source/NEW"
3216 fi
3217}
3218
3219
3220localrepo_downloadMissingRPMs() {
3221 # download any installed RPMS that are not ye(yet) built
3222 # this was originally intended to allow for re-creating a image of the system (via lorax) with the online repos completely disabled and all packages being sourced from this local repo
3223
3224 # define local repo path
3225 localrepo_setEnvVars
3226
3227 local missingRpmList=""
3228
3229 # find rpms not in built or downloaded and download to "${LOCALREPO_DIR%/}/downloaded/NEW"
3230
3231 missingRpmList="$(diff -ywd --tabsize=1 --width=512 --suppress-common-lines <(rpm -qa | sort -u) <(find ${LOCALREPO_DIR%/}/{built,downloaded} -type f -name "*.rpm" | sed -E s/'^.*\/([^\/]*)\.rpm$'/'\1'/ | sort -u) | grep -v -E '\>' | grep -E '[\<\|]' | sed -E s/'^([^\<\|]*)[\<\|].*$'/'\1'/ | sort -u)"
3232
3233 [[ -n "${missingRpmList}" ]] && cd "${LOCALREPO_DIR%/}/downloaded/NEW" && dnf download --skip-broken ${missingRpmList} && cd "${OLDPWD}"
3234
3235}
3236
3237
3238localrepo_sortNewRPMs() {
3239 # looks in user's rpmbuild trees for new RPMs and moves them into */NEW, then sorts all the RPMs int eh */NEW directories into the proper package directories
3240
3241 # define local repo path and list valid architectures
3242 localrepo_setEnvVars
3243
3244 local -a vaArray
3245 [[ -n "${VALID_ARCH_LIST}" ]] && vaArray=(${VALID_ARCH_LIST}) || vaArray=($(echo "noarch"; uname -pmi | sed -zE s/' '/'\n'/g | sort -u; [[ "$(uname -pmi | sed -zE s/' '/'\n'/g | sort -u)" == "x86_64" ]] && echo "i686" ))
3246
3247 local ll=""
3248 local mm=""
3249 local nn=""
3250
3251 # set user:group to root:wheel if we can
3252 [[ "${USER}" == "root" ]] && chown -R root:wheel ${LOCALREPO_DIR%/}/{source,built,downloaded}/NEW && chmod -R 775 ${LOCALREPO_DIR%/}/{source,built,downloaded}/NEW
3253
3254 for nn in {0..9} {a..z} {A..Z}; do
3255
3256 # sort source srpms into source/packages/* folders
3257 [[ -n "$(find "${LOCALREPO_DIR%/}/source/NEW" -type f -name "${nn}*.src.rpm")" ]] && \mv -f $(find "${LOCALREPO_DIR%/}/source/NEW" -type f -name "${nn}*.src.rpm") "${LOCALREPO_DIR%/}/source/packages/${nn,,}"
3258
3259 done
3260
3261 for ll in {built,downloaded}; do
3262 for mm in "${vaArray[@]}"; do
3263 for nn in {0..9} {a..z} {A..Z}; do
3264
3265 # sort {built,downloaded} rpms into {built,downloaded}/packages/* folders
3266 [[ -n "$(find "${LOCALREPO_DIR%/}/${ll%/}/NEW" -type f -name "${nn}*.${mm}.rpm" | grep -v -E 'debug(source|info)')" ]] && \mv -f $(find "${LOCALREPO_DIR%/}/${ll%/}/NEW" -type f -name "${nn}*.${mm}.rpm" | grep -v -E 'debug(source|info)') "${LOCALREPO_DIR%/}/${ll%/}/${mm%/}/packages/${nn,,}"
3267
3268 # sort debug info for {built,downloaded} rpms into {built,downloaded}/debuginfo/packages/* folders
3269 [[ -n "$(find "${LOCALREPO_DIR%/}/${ll%/}/NEW" -type f -name "${nn}*.${mm}.rpm" | grep -E 'debug(source|info)')" ]] && \mv -f $(find "${LOCALREPO_DIR%/}/${ll%/}/NEW" -type f -name "${nn}*.${mm}.rpm" | grep -E 'debug(source|info)') "${LOCALREPO_DIR%/}/${ll%/}/debuginfo/${mm%/}/packages/${nn,,}"
3270
3271 done
3272 done
3273 done
3274
3275}
3276
3277
3278localrepo_fixSorting_debuginfo() {
3279 # move debug packages into debuginfo dirs, and move any packages that arent debuginfo out of debuginfo dirs
3280 # localrepo_sortNewRPMs *should* sort everything correctly, but this function runs very fast so running it is worthwhile
3281
3282 # define local repo path
3283 localrepo_setEnvVars
3284
3285 # move mis-sorted debug packages in standard folders into debuginfo folders.
3286 # If duplicates already exists in debuginfo folder: overwrite if the other is newer, otherwise move the other one to the REMOVED folder
3287 if [[ -n "$(find ${LOCALREPO_DIR%/}/{built,downloaded}/*/packages -type f -name "*debug*.rpm" | grep -E '^.*\/[^\/]*-debug(source|info)-[^\/]*$')" ]]; then
3288
3289 eval $(find ${LOCALREPO_DIR%/}/{built,downloaded}/*/packages -type f -name "*debug*.rpm" | grep -E '^.*\/[^\/]*-debug(source|info)-[^\/]*$' | sed -E s/'^(.*)\/(built|downloaded)\/(.*)$'/'\\mv -u "\1\/\2\/\3" "\1\/\2\/debuginfo\/\3\";'/)
3290 eval $(find ${LOCALREPO_DIR%/}/{built,downloaded}/*/packages -type f -name "*debug*.rpm" | grep -E '^.*\/[^\/]*-debug(source|info)-[^\/]*$' | sed -E s/'^(.*)\/(built|downloaded)\/(.*)$'/'\\mv -f "\1\/\3" "\1\/\.REMOVED\/\2";'/)
3291
3292 fi
3293
3294 # move mis-sorted standard packages in debuginfo folders into standard folders.
3295 # If duplicates already exists in standard folder: overwrite if the other is newer, otherwise move the other one to the REMOVED folder
3296 if [[ -n "$(find ${LOCALREPO_DIR%/}/{built,downloaded}/debuginfo/*/packages -type f -name "*.rpm" | grep -v -E '^.*\/[^\/]*-debug(source|info)-[^\/]*$')" ]]; then
3297
3298 eval $(find ${LOCALREPO_DIR%/}/{built,downloaded}/debuginfo/*/packages -type f -name "*.rpm" | grep -v -E '^.*\/[^\/]*-debug(source|info)-[^\/]*$' | sed -E s/'^(.*)\/(built|downloaded)\/debuginfo\/(.*)$'/'\\mv -u "\1\/\2\/debuginfo\/\3" "\1\/\2\/\3\";'/)
3299 eval $(find ${LOCALREPO_DIR%/}/{built,downloaded}/debuginfo/*/packages -type f -name "*.rpm" | grep -v -E '^.*\/[^\/]*-debug(source|info)-[^\/]*$' | sed -E s/'^(.*)\/(built|downloaded)\/debuginfo\/(.*)$'/'\\mv -f "\1\/\2\/debuginfo\/\3" "\1\/\.REMOVED\/\2";'/)
3300
3301 fi
3302
3303}
3304
3305
3306localrepo_setupFedoraComps() {
3307
3308 # define local repo path
3309 localrepo_setEnvVars
3310
3311 local fedoraCompsBasePath=""
3312 local dirOrig=""
3313
3314 if ! ( [[ -n $(rpm -qa | grep 'intltool') ]] || sudo dnf install intltool -y || sudo dnf install intltool -y --enablerepo=[a-zA-Z0-9]* ); then
3315 echo -e "\nUnable to install intltools, which is required to [re]make 'fedora-comps'. 'fedora-comps' will not be [re]made. \nTo automatically [re]make fedora-comps, manually install the 'intltool' package and then re-run 'localrepo_setupFedoraComps' \n" >&2
3316 return
3317 fi
3318
3319 echo "Fedora-comps will now be [re]made" >&2
3320
3321 dirOrig="$(pwd)"
3322
3323 [[ -n "${FEDORA_COMPS_FILE_PATH}" ]] && fedoraCompsBasePath="${FEDORA_COMPS_FILE_PATH%/fedora-comps/*}" || fedoraCompsBasePath="${LOCALREPO_DIR%/}" && FEDORA_COMPS_FILE_PATH="${fedoraCompsBasePath%/}/fedora-comps/comps-f$(uname -r | sed -E s/'^.*\.fc([0-9]*)\..*$'/'\1'/).xml" && export FEDORA_COMPS_FILE_PATH
3324
3325 cd "${fedoraCompsBasePath}"
3326
3327 [[ -d "${fedoraCompsBasePath%/}/fedora-comps" ]] && [[ -f "${fedoraCompsBasePath%/}/fedora-comps/Makefile" ]] && cd "${fedoraCompsBasePath%/}/fedora-comps" && make clean || ( [[ ! -d "${fedoraCompsBasePath%/}/fedora-comps" ]] || \mv -f "${fedoraCompsBasePath%/}/fedora-comps" "${fedoraCompsBasePath%/}/fedora-comps.old" ) && git clone 'http://git@pagure.io/fedora-comps.git' && cd "${fedoraCompsBasePath%/}/fedora-comps"
3328
3329 make all && make validate
3330
3331 chmod -R 775 "${fedoraCompsBasePath%/}/fedora-comps"
3332 chown -R root:wheel "${fedoraCompsBasePath%/}/fedora-comps"
3333
3334 cd "${dirOrig}"
3335
3336}
3337
3338
3339localrepo_repoBackup() {
3340 # backs up the local repo using rsync if either:
3341 # a) LOCALREPO_BACKUP_DIR is defined and not equal to the string "NONE"(this is the priority)
3342 # b) /DATA/${LOCALREPO_DIR#/} exists (to not use this by default, define and export LOCALREPO_BACKUP_DIR)
3343 #
3344 # To not backup the repo ever (including not using /DATA/${LOCALREPO_DIR#/}, even if it exists), define/export LOCALREPO_BACKUP_DIR="NONE"
3345
3346 # see if "${LOCALREPO_BACKUP_DIR} or "/DATA/${LOCALREPO_DIR#/}" exists
3347 localrepo_setEnvVars
3348
3349 # If we have a backup location, run rsync to updaate the repo
3350 if [[ -n "${LOCALREPO_BACKUP_DIR}" ]] && [[ "${LOCALREPO_BACKUP_DIR}" != "NONE" ]]; then
3351
3352 [[ -d "${LOCALREPO_BACKUP_DIR}" ]] || mkdir --parents "${LOCALREPO_BACKUP_DIR}"
3353
3354 rsync -avP "${LOCALREPO_DIR%/}/" "${LOCALREPO_BACKUP_DIR%/}/"
3355
3356 fi
3357
3358}
3359
3360localrepo_cleanDatabase() {
3361 # deletes all repo data (NOT packages, just the stuff createrepo generates)
3362 # use this to refresh the repo and regenerate all the repo data from scratch
3363
3364 echo "local repository database cleaning will begin in 5 seconds..." >&2 && sleep 5
3365
3366 dnf clean all
3367
3368 # define local repo path and list valid architectures
3369 localrepo_setEnvVars
3370
3371 local globstarState=""
3372 globstarState="$(shopt globstar)"
3373 globstarState="${globstarState##* }"
3374
3375 [[ "${globstarState}" == "off" ]] && shopt -s globstar
3376
3377 # clean repodata
3378
3379 LOCALREPO_DIR="${LOCALREPO_DIR%/}"
3380
3381 chmod 777 ${LOCALREPO_DIR:?}/**/.repodata ${LOCALREPO_DIR:?}/.repodata ${LOCALREPO_DIR:?}/**/repodata ${LOCALREPO_DIR:?}/repodata ${LOCALREPO_DIR:?}/**/drpms ${LOCALREPO_DIR:?}/drpms ${LOCALREPO_DIR:?}/**/cache ${LOCALREPO_DIR:?}/cache
3382
3383 \rm -rf ${LOCALREPO_DIR:?}/**/.repodata ${LOCALREPO_DIR:?}/.repodata ${LOCALREPO_DIR:?}/**/repodata ${LOCALREPO_DIR:?}/repodata ${LOCALREPO_DIR:?}/**/drpms ${LOCALREPO_DIR:?}/drpms ${LOCALREPO_DIR:?}/**/cache ${LOCALREPO_DIR:?}/cache
3384
3385 [[ "${globstarState}" == "off" ]] && shopt -u globstar
3386
3387 # remake repo files
3388 localrepo_setupDNF
3389
3390}
3391
3392
3393localrepo_updateDatabase() {
3394 # generates the file tree structure (if needed), adds + sorts new packages, and calls "create repo" on each sub-tree in the local repo
3395 # repos are generated with a cache and with delta-rpm info
3396 #
3397 # NOTE: you will need to manually
3398 #
3399 # note: repos are generated for each level in ${LOCALREPO_DIR}. The top level repo contains all packages from its subrepos. e.g.,
3400 # localrepo/repodata/repomd.xml has everything (top-level repo)
3401 # localrepo/built/repodata/repomd.xml has all built rpms (mid-level repo)
3402 # localrepo/built/x86_64/repodata/repomd.xml has all non-debuginfo/debugsource built rpms with x86_64 architecture packages (bottom-level repo)
3403
3404 # define local repo path and list valid architectures
3405 localrepo_setEnvVars
3406
3407 local -a vaArray
3408 [[ -n "${VALID_ARCH_LIST}" ]] && vaArray=(${VALID_ARCH_LIST}) || vaArray=($(echo "noarch"; uname -pmi | sed -zE s/' '/'\n'/g | sort -u; [[ "$(uname -pmi | sed -zE s/' '/'\n'/g | sort -u)" == "x86_64" ]] && echo "i686" ))
3409
3410 local fedoraCompsFileCmd=""
3411 local localrepoBaseName="${LOCALREPO_DIR##*/}"
3412 localrepoBaseName=${localrepoBaseName%/}
3413
3414 [[ -f "${FEDORA_COMPS_FILE_PATH}" ]] && fedoraCompsFileCmd="-g ${FEDORA_COMPS_FILE_PATH} "
3415
3416 # ensure valid permissions
3417 [[ "${USER}" == "root" ]] && chown -R root:wheel ${LOCALREPO_DIR%/}/{source,built,downloaded} && chmod -R 775 ${LOCALREPO_DIR%/}/{source,built,downloaded}
3418
3419 # add + sort all new packages into the local repo
3420 [[ ${1,,} =~ ^-+c((lean)?((-?repo)?(-?data)?)?)? ]] && echo "cleaning RPM database..." >&2 && sleep 2 && localrepo_cleanDatabase
3421 localrepo_makeFileTree
3422 localrepo_importBuiltRPMs
3423 localrepo_downloadMissingRPMs
3424 localrepo_sortNewRPMs
3425 localrepo_fixSorting_debuginfo
3426
3427
3428 # make dnf cache directory (if needed)
3429 [[ -d "/var/cache/dnf/${localrepoBaseName}" ]] || mkdir --parents "/var/cache/dnf/${localrepoBaseName}"
3430
3431 # make sure we have the createrepo function
3432 [[ -z $(rpm -qa | grep 'createrepo') ]] && sudo dnf install createrepo_c -y
3433
3434 # make source repo
3435 createrepo_c --workers $((( $(nproc) / 2 ))) ${fedoraCompsFileCmd} -c "${LOCALREPO_DIR%/}/source/cache/" --deltas "${LOCALREPO_DIR%/}/source"
3436
3437 for ll in {built,downloaded,built/debuginfo,downloaded/debuginfo}; do
3438 for mm in "${vaArray[@]}"; do
3439 # make the bottom-level repos
3440 createrepo_c --workers $((( $(nproc) / 2 ))) ${fedoraCompsFileCmd} -c "${LOCALREPO_DIR%/}/${ll%/}/${mm%/}/cache/" --deltas "${LOCALREPO_DIR%/}/${ll%/}/${mm%/}/"
3441 done
3442
3443 # create repos for mid-level parent repos
3444 createrepo_c --workers $((( $(nproc) / 2 ))) ${fedoraCompsFileCmd} -c "${LOCALREPO_DIR%/}/${ll%/}/cache/" --deltas "${LOCALREPO_DIR%/}/${ll}"
3445
3446 done
3447
3448 # create main top-level parent repo
3449 #createrepo_c --workers $((( $(nproc) / 2 ))) ${fedoraCompsFileCmd} -c "${LOCALREPO_DIR%/}/cache/" $(eval echo $(ls -A1 ${LOCALREPO_DIR} | grep -v -E 'built|downloaded|source' | sed -E s/'^(.*)$'/'-x \$\(realpath \$\{LOCALREPO_DIR}\/\1\)'"'"'*'"'"''/)) --deltas "${LOCALREPO_DIR}"
3450
3451 createrepo_c --workers $((( $(nproc) / 2 ))) ${fedoraCompsFileCmd} -c "${LOCALREPO_DIR%/}/cache/" $(echo "$(find ${LOCALREPO_DIR} -maxdepth 1 -type d | grep -v -E '((built)|(downloaded)|(source)|(fedora-comps)|(drpms)|(repodata)|(cache)|(localmirror))' | sed -E s/'^'"$(srpmAutoBuild_escapeRegexChars "${LOCALREPO_DIR}")"'\/?(.*)$'/'\1'/ | grep -E '^.+$' | sed -E s/'^(.*)$'/'--excludes=\1\* '/)") --deltas "${LOCALREPO_DIR}"
3452
3453
3454
3455 # make symlinks to dnf cache directory
3456 ( [[ -d "/var/cache/dnf/${localrepoBaseName#/}/cache" ]] && echo "y" || echo "" ) | ln -s "${LOCALREPO_DIR%/}/cache/" "/var/cache/dnf/${localrepoBaseName#/}/cache"
3457 ( [[ -d "/var/cache/dnf/${localrepoBaseName#/}/repodata" ]] && echo "y" || echo "" ) | ln -s "${LOCALREPO_DIR%/}/repodata/" "/var/cache/dnf/${localrepoBaseName#/}/repodata"
3458
3459 sudo dnf --refresh --enablerepo=${localrepoBaseName%/}* makecache
3460
3461 localrepo_repoBackup
3462
3463}
3464
3465
3466localrepo_showFileTree() {
3467 # shows a generic filetree to screen showing the localrepo layout
3468 # note: this layout assumes x86_64. It is not dynamically generated. on other architectrures you will
3469 # have different options than "x86_64" and "i686", though the "noarch" option should apply to all.
3470
3471cat << EOF
3472|____localrepo
3473| |____{cache,repodata,drpms}
3474| |
3475| |
3476| |
3477| |____source
3478| | |____{cache,repodata,drpms}
3479| | |____packages
3480| | |____{0..9,a..z}
3481| |
3482| |
3483| |
3484| |____built
3485| | |____{cache,repodata,drpms}
3486| | |
3487| | |____x86_64
3488| | | |____{cache,repodata,drpms}
3489| | | |____packages
3490| | | |____{0..9,a..z}
3491| | |
3492| | |____noarch
3493| | | |____{cache,repodata,drpms}
3494| | | |____packages
3495| | | |____{0..9,a..z}
3496| | |
3497| | |___i686
3498| | | |____{cache,repodata,drpms}
3499| | | |____packages
3500| | | |____{0..9,a..z}
3501| | |
3502| | |____debuginfo
3503| | | |____{cache,repodata,drpms}
3504| | | |
3505| | | |____x86_64
3506| | | | |____{cache,repodata,drpms}
3507| | | | |____packages
3508| | | | |____{0..9,a..z}
3509| | | |
3510| | | |____noarch
3511| | | | |____{cache,repodata,drpms}
3512| | | | |____packages
3513| | | | |____{0..9,a..z}
3514| | | |
3515| | | |___i686
3516| | | | |____{cache,repodata,drpms}
3517| | | | |____packages
3518| | | | |____{0..9,a..z}
3519| |
3520| |
3521| |
3522| |____downloaded
3523| | |____{cache,repodata,drpms}
3524| | |
3525| | |____x86_64
3526| | | |____{cache,repodata,drpms}
3527| | | |____packages
3528| | | |____{0..9,a..z}
3529| | |
3530| | |____noarch
3531| | | |____{cache,repodata,drpms}
3532| | | |____packages
3533| | | |____{0..9,a..z}
3534| | |
3535| | |___i686
3536| | | |____{cache,repodata,drpms}
3537| | | |____packages
3538| | | |____{0..9,a..z}
3539| | |
3540| | |____debuginfo
3541| | | |____{cache,repodata,drpms}
3542| | | |
3543| | | |____x86_64
3544| | | | |____{cache,repodata,drpms}
3545| | | | |____packages
3546| | | | |____{0..9,a..z}
3547| | | |
3548| | | |____noarch
3549| | | | |____{cache,repodata,drpms}
3550| | | | |____packages
3551| | | | |____{0..9,a..z}
3552| | | |
3553| | | |___i686
3554| | | | |____{cache,repodata,drpms}
3555| | | | |____packages
3556| | | | |____{0..9,a..z}| |
3557EOF
3558
3559}
3560
3561localrepo_setupDNF() {
3562 # this will setup dnf to use the localrepo. All sub-repos will be added, though most are not initially enabled.
3563 # Note: someof the mirrors here probablyh wont work for local system access. You can remove the ones that dont work manually if your like
3564
3565 # define local repo path and list valid architectures
3566 localrepo_setEnvVars
3567
3568 local nameCur=""
3569 local nameCur2=""
3570 local enabledCur=""
3571 local skipCur=""
3572 local costCur=""
3573 local -a vaArray
3574
3575 [[ -n "${VALID_ARCH_LIST}" ]] && vaArray=(${VALID_ARCH_LIST}) || vaArray=($(echo "noarch"; uname -pmi | sed -zE s/' '/'\n'/g | sort -u; [[ "$(uname -pmi | sed -zE s/' '/'\n'/g | sort -u)" == "x86_64" ]] && echo "i686" ))
3576
3577 echo -n "Ensuring localrepo directory tree exists at ${LOCALREPO_DIR}..." >&2
3578 localrepo_makeFileTree
3579 echo "done" >&2
3580
3581 if ( [[ -n $(rpm -qa | grep 'intltool') ]] || sudo dnf install intltool -y || sudo dnf install intltool -y --enablerepo=[a-zA-Z0-9]* ); then
3582 echo -n "Preparing to [re]make he fedora-comps files that provides group install info..." >&2
3583 localrepo_setupFedoraComps
3584 else
3585 echo -e "\nUnable to install intltools, which is required to [re]make 'fedora-comps'. 'fedora-comps' will not be [re]made. \nTo automatically [re]make fedora-comps, manually install the 'intltool' package and then run 'localrepo_setupFedoraComps' \n" >&2
3586 fi
3587
3588 echo "Beginning setup of the localrepo '*.repo' files and mirrorlists..." >&2
3589
3590 [[ -f "/etc/yum.repos.d/${LOCALREPO_DIR##*/}.repo" ]] && ( chmod 775 "/etc/yum.repos.d/${LOCALREPO_DIR##*/}.repo" || (( 1 == 1 )) ) && \mv -f "/etc/yum.repos.d/${LOCALREPO_DIR##*/}.repo" "/etc/yum.repos.d/${LOCALREPO_DIR##*/}.repo.old"
3591
3592 [[ -d "${LOCALREPO_DIR%/}/localmirror" ]] && ( [[ -d "${LOCALREPO_DIR%/}/localmirror/.old" ]] && \rm -rf "${LOCALREPO_DIR%/}/localmirror/.old" ) && mkdir "${LOCALREPO_DIR%/}/localmirror/.old" && \mv -f ${LOCALREPO_DIR%/}/localmirror/mirror-* "${LOCALREPO_DIR%/}/localmirror/.old" || mkdir --parents "${LOCALREPO_DIR%/}/localmirror"
3593
3594 [[ "${USER}" == "root" ]] && echo "$(echo "$(cat "/etc/dnf/dnf.conf" | grep -v -E '^fastestmirror=')" && echo "fastestmirror=true")" > "/etc/dnf/dnf.conf"
3595
3596 LOCALREPO_DIR="${LOCALREPO_DIR%/}"
3597
3598############################################################
3599cat << EOF > "/etc/yum.repos.d/${LOCALREPO_DIR##*/}.repo"
3600[localrepo]
3601name=localrepo - Fedora \$releasever - ALL
3602mirrorlist=file:///${LOCALREPO_DIR#/}/localmirror/mirror-localrepo-all
3603enabled=1
3604metadata_expire=1d
3605repo_gpgcheck=0
3606type=rpm
3607gpgcheck=0
3608gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-\$releasever-\$basearch
3609skip_if_unavailable=False
3610cost=20
3611
3612EOF
3613############################################################
3614
3615#setup mirrorlist for base localrepo. This is used as a template for the rest of the mirrorlists.
3616############################################################
3617cat << EOF > "${LOCALREPO_DIR}/localmirror/mirror-localrepo-all"
3618file:///${LOCALREPO_DIR#/}
3619localhost/${LOCALREPO_DIR#/}
3620localhost:22/${LOCALREPO_DIR#/}
3621localhost:80/${LOCALREPO_DIR#/}
3622localhost:8080/${LOCALREPO_DIR#/}
3623http://127.0.0.1/${LOCALREPO_DIR#/}
3624http://127.0.0.1:22/${LOCALREPO_DIR#/}
3625http://127.0.0.1:80/${LOCALREPO_DIR#/}
3626http://127.0.0.1:8080/${LOCALREPO_DIR#/}
3627https://127.0.0.1/${LOCALREPO_DIR#/}
3628https://127.0.0.1:22/${LOCALREPO_DIR#/}
3629https://127.0.0.1:80/${LOCALREPO_DIR#/}
3630https://127.0.0.1:8080/${LOCALREPO_DIR#/}
3631http://[::1]/${LOCALREPO_DIR#/}
3632http://[::1]:22/${LOCALREPO_DIR#/}
3633http://[::1]:80/${LOCALREPO_DIR#/}
3634http://[::1]:8080/${LOCALREPO_DIR#/}
3635https://[::1]/${LOCALREPO_DIR#/}
3636https://[::1]:22/${LOCALREPO_DIR#/}
3637https://[::1]:80/${LOCALREPO_DIR#/}
3638https://[::1]:8080/${LOCALREPO_DIR#/}
3639EOF
3640############################################################
3641
3642 # setup mirrorlists for "source" and "built" and "downloaded" + all sub-repos under "built" and "downloaded"
3643 for ll in {source,built,downloaded,built/debuginfo,downloaded/debuginfo}; do
3644
3645 for mm in {"","${vaArray[@]}"}; do
3646
3647 [[ "${ll}" == "source" ]] && [[ -n "${mm}" ]] && continue
3648
3649 nameCur="localrepo-${ll//'/'/'-'}"
3650 nameCur2="${ll^^}"
3651
3652 [[ -n ${mm} ]] && nameCur="${nameCur}-${mm}" && nameCur2="${nameCur2}-${mm}"
3653
3654 [[ -z ${mm} ]] && [[ "${ll}" != */debuginfo ]] && enabledCur="1" || enabledCur="0"
3655
3656 ( [[ -z ${mm} ]] && [[ "${ll}" != "downloaded" ]] ) && skipCur="False" || skipCur="True"
3657
3658 costCur=0
3659 [[ "${ll}" == "downloaded" ]] && costCur=10
3660 [[ "${ll}" == */debuginfo ]] && costCur=$(( $costCur + 2 ))
3661 [[ -z "${mm}" ]] || costCur=$(( $costCur + 1 ))
3662 if [[ -n "$(echo "${vaArray[@]}" | grep 'x86_64')" ]]; then
3663 [[ "${mm}" = "i686" ]] && costCur=$(( $costCur + 6 ))
3664 [[ "${mm}" = "noarch" ]] && costCur=$(( $costCur + 3 ))
3665 fi
3666
3667 [[ -f "${LOCALREPO_DIR%/}/localmirror/mirror-${nameCur}" ]] && chmod 775 "${LOCALREPO_DIR%/}/localmirror/mirror-${nameCur}" || touch "${LOCALREPO_DIR%/}/localmirror/mirror-${nameCur}"
3668 echo "$(cat "${LOCALREPO_DIR%/}/localmirror/mirror-localrepo-all" | sed -E s/'^(.*)$'/'\1\/'"${ll//'/'/'\/'}"'\/'"${mm}"/ | sed -E s/'^(.*)\/$'/'\1'/)" > "${LOCALREPO_DIR%/}/localmirror/mirror-${nameCur}"
3669
3670############################################################
3671cat << EOF >> "/etc/yum.repos.d/${LOCALREPO_DIR##*/}.repo"
3672[${nameCur}]
3673name=localrepo - Fedora \$releasever - ${nameCur2}
3674mirrorlist=file:///${LOCALREPO_DIR#/}/localmirror/mirror-${nameCur}
3675enabled=${enabledCur}
3676metadata_expire=1d
3677repo_gpgcheck=0
3678type=rpm
3679gpgcheck=0
3680gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-\$releasever-\$basearch
3681skip_if_unavailable=${skipCur}
3682cost=${costCur}
3683
3684EOF
3685############################################################
3686
3687 done
3688
3689 done
3690
3691 chmod 775 "/etc/yum.repos.d/${LOCALREPO_DIR##*/}.repo"
3692 chmod -R 775 "${LOCALREPO_DIR%/}/localmirror"
3693
3694 sync
3695
3696 echo -e "\n*.repo files and local mirrorlists for ${LOCALREPO_NAME} have been generated! \nThe packages contained in ${LOCALREPO_NAME} should now be accessable via DNF. \n" >&2
3697
3698}
3699
3700
3701#!/bin/bash
3702
3703UEFIDracutUpdate() {
3704 # MAIN FUNCTION TO CREATE / UPDATE BOOTABLE EFI FILES
3705 #
3706 # Inputs are kernel versions to update the bootable efi files for (same format as $(uname -r))
3707 # If no (non-flag) inputs, all kernel versions will be updated
3708 #
3709 # This can be called with no arguments and should** figure them all out for you using information from current mounts.
3710 # ** It works well for me, but has only tested on configurations ive had on my system. This means:
3711 #
3712 # FIlesystems: ext4 and ZFS (on root) have been tested. XFS will probably work too.
3713 # brtfs probably wont work without a little modification (though maybe it will, idk)
3714 #
3715 # GPU: tested with nvidia gpu using nvidia (not nouveau) drivers. integrated graphics probably works too.
3716 # no special cases have been setup for AMD gpus.
3717 #
3718 # Other: LUKS should be handled appropriately. LVM and DM/MD RAID support has not been explicitly added.
3719 #
3720 # Fedora 29 is the only Fedora version tested. I imagine it works with others, but idk for sure.
3721 #
3722 # Including files in the initramfs: 3 directories will be automatically added to the initramfs (if they exist and contain files):
3723 #
3724 # /etc/systemd/personal - this is intended to be used for custom systemd services.
3725 # *.service files in /etc/systemd/personal are included and installed. Files in the other 2 dirs are only included.
3726 #
3727 # /usr/local/bin/my-services - this is intended for files that support the custom systemd services
3728 #
3729 # /usr/local/bin/my-services - this is intended for general scripts, including functions you might find
3730 # useful should you end up in the dracut emergency shell for whatever reason.
3731 #
3732 # NOTE: because this sets up everything in the kernel commandline, the devices need not be listed in /etc/{fs,crypt}tab
3733 # if you do have them listed there is can, in some instances, lead to issues
3734 # # example: it might ask you a 2nd time for a password to decrypt an already-decrypted drive
3735 #
3736 # NOTE: unless you use either pf the flags '-na' or '--no-ask', you will be asked for
3737 # confirmation that the parameters it has determined automatically are correct.
3738 # if it is getting something wrong, it *should* accept any manual hardcoded entries of the following parameters:
3739 # ${luksUUID} ${bootDisk} ${rootDisk} ${rootFSType} ${rootFlags} ${usrDisk} ${usrFSType} ${usrFlags}
3740 #
3741 # IMPORTANT NOTE: the variable 'kernelCmdline_static' is for all the "extra" kernel command line parameters you want to add.
3742 # I left what Im using in there, as an example, though this wont be ideal for most systems. You should set this manually,
3743 # or remove it / comment it out it entirely if you arent sure how to set up.
3744 #
3745 # NOTE: these codes probably require root privileges to run, though doesnt call sudo in case someone without root access wants to try it.
3746 # I recommend, if possible, to run this as the root user (e.g., call 'su' then run it)
3747
3748 # set local variables
3749
3750 local rootDisk="";
3751 local bootDisk="";
3752 local luksUUID="";
3753 local rootFSType="";
3754 local rootFlags="";
3755 local userResponse="";
3756 local noAskFlag=0;
3757 local kernelCmdline_static="";
3758 local dracutArgsExtra=""
3759 local nn=""
3760 local usrDisk=""
3761 local usrFSType=""
3762 local usrFlags=""
3763 local usrMountFlag=0
3764 local kernelCmdline_spectreMeltdownMitigations=""
3765
3766 local useHardcodedZFSInfoFlag=0
3767
3768 # disable selinux when running from a live os
3769 [[ -n "$(findmnt / | grep '/dev/mapper/live')" ]] && setenforce 0 && dnf upgrade -y *dracut* *systemd*
3770
3771 kernelCmdline_static='rd.driver.pre=tpm rd.timeout=60 rd.locale.LANG=en_US.UTF-8 rd.udev.log-priority=info rd.lvm=0 rd.lvm.conf=0 rd.md=0 rd.md.conf=0 rd.dm=0 rd.dm.conf=0 systemd.unified_cgroup_hierarchy gpt intel_pstate=hwp_only zswap.enabled=1 zswap.compressor=lz4 transparent_hugepages=always panic=60'
3772
3773 kernelCmdline_spectreMeltdownMitigations='spec_store_bypass_disable=prctl noibrs noibpb spectre_v2=auto pti=auto'
3774
3775 [[ ${*,,} =~ ^(.+\ )?-+no?-?a(sk)?(\ .+)?$ ]] && noAskFlag=1
3776
3777 mount "$(myFindEFIDev)" 2>&1 | grep -v 'already mounted' >&2
3778
3779 # set parameters for root /ot / usr / luks disk information
3780
3781 # example or manually set parameters. Note that the leading '[param]=' part is auto added, and doesnt need to be included (though can be)
3782
3783 if (( ${useHardcodedZFSInfoFlag} == 1 )); then
3784 rootDisk='ZFS=FEDORA/ROOT'
3785 rootFSType='zfs'
3786 rootFlags='zfsutil,rw,relatime,xattr,posixacl'
3787 luksUUID="luks-$(cryptsetup luksUUID /dev/disk/by-id/nvme-Samsung_SSD_970_PRO_1TB_S462NF0K403461K-part2)"
3788 bootDisk='/dev/disk/by-id/nvme-Samsung_SSD_970_PRO_1TB_S462NF0K403461K-part1'
3789 #usrDisk='ZFS=FEDORA/ROOT/USR'
3790 #usrFSType='zfs'
3791 #usrFlags='zfsutil,rw,relatime,xattr,posixacl'
3792 fi
3793
3794 #bootDisk='/dev/disk/by-id/nvme-INTEL_MEMPEK1W032GA_PHBT8146015X032E-part3'
3795 #rootDisk='/dev/disk/by-id/nvme-INTEL_MEMPEK1W032GA_PHBT8146015X032E-part4'
3796 #bootDisk="$(find /dev/disk/by-id/ -name "nvme-I*601*-part3")"
3797 #rootDisk="$(find /dev/disk/by-id/ -name "nvme-I*601*-part4")"
3798
3799 #rootDisk="/dev/mapper/luks-$(cryptsetup luksUUID /dev/disk/by-id/nvme-INTEL_MEMPEK1W032GA_PHBT814600LW032E-part5)"
3800 #bootDisk='/dev/disk/by-id/nvme-INTEL_MEMPEK1W032GA_PHBT814600LW032E-part3'
3801 #luksUUID="luks-$(cryptsetup luksUUID /dev/disk/by-id/nvme-INTEL_MEMPEK1W032GA_PHBT814600LW032E-part5)"
3802 #rootFSTye='ext4'
3803 #rootFlags='rw,relatime'
3804
3805 # automatically find parameters for root, boot and luks if they are empty (i.e., not hard-coded)
3806
3807 [[ -z "${rootDisk}" ]] && [[ -n "$(mount -l | grep 'on / type' | sed -E s/'^(.*) on \/ type .*$'/'\1'/)" ]] && rootDisk="$(mount -l | grep 'on / type' | sed -E s/'^(.*) on \/ type .*$'/'\1'/)";
3808
3809 [[ -z "${bootDisk}" ]] && bootDisk="$(myFindEFIDev)"
3810
3811 [[ -z "${luksUUID}" ]] && luksUUID="$(myDevToID -u "$(echo "$(for nn in /dev/mapper/*; do [[ $(cryptsetup status "$nn" 2>&1) != *"not found" ]] && cryptsetup status "$nn" 2>/dev/null; done)" | grep 'device: ' | sed -E s/'^.*(\/dev\/.*)$'/'\1'/)" | sed -E s/'^UUID='/'luks-'/ | grep -vE '^luks-$')"
3812 (( $(echo "${luksUUID}" | wc -l) > 1 )) && (( ${useHardcodedZFSInfoFlag} == 0 )) && luksUUID="$(echo "${luksUUID}" | while read -r nn; do [[ -n "$(dmsetup table "${nn}" | grep 'logon')" ]] && echo "${nn}"; done)"
3813
3814 [[ -z "${rootFSType}" ]] && [[ -n "$(mount -l | grep 'on / type' | sed -E s/'^.* on \/ type ([^ ]*) .*$'/'\1'/)" ]] && rootFSType="$(mount -l | grep 'on / type' | sed -E s/'^.* on \/ type ([^ ]*) .*$'/'\1'/)";
3815 [[ "${rootDisk}" == "ZFS="* ]] && rootFSType='zfs'
3816 [[ ${rootFSType#*=} =~ ^[Zz][Ff][Ss]$ ]] && rootFSype="zfs" && [[ -n "${rootDisk}" ]] && rootDisk="ZFS=$(echo "${rootDisk}" | sed -E s/'^[Zz][Ff][Ss]=(.*)'/'\1'/)"
3817
3818 [[ -z "${rootFlags}" ]] && [[ -n "$(mount -l | grep 'on / type' | sed -E s/'^.* on \/ type [^ ]* \(([^\)]*)\).*$'/'\1'/)" ]] && rootFlags="$(mount -l | grep 'on / type' | sed -E s/'^.* on \/ type [^ ]* \(([^\)]*)\).*$'/'\1'/)";
3819 [[ ${rootFSType#*=} =~ ^[Zz][Ff][Ss]$ ]] && rootFlags="${rootFlags//'seclabel'/}" && [[ ! ${rootFlags#'rootFlags='} =~ ^(.+,)?zfsutil(,.+)?$ ]] && rootFlags="zfsutil,${rootFlags#'rootFlags='}"
3820 [[ -n "${rootFlags}" ]] && rootFlags="${rootFlags//,,/,}"
3821
3822 # add in leading '[param]='
3823 #luksUUID=""
3824
3825 [[ -n "${rootDisk}" ]] && rootDisk="root=$(myDevToID "${rootDisk#'root='}") rw";
3826 [[ -n "${bootDisk}" ]] && bootDisk="boot=$(myDevToID "${bootDisk#'boot='}")";
3827 [[ -n "${luksUUID}" ]] && luksUUID="${luksUUID,,}" && luksUUID="${luksUUID#'*luks.uuid='}" && luksUUID="luks-${luksUUID#'luks-'}" && luksUUID="rd.luks.uuid=${luksUUID#'*luks.uuid='}" # && [[ "${luksUUID}" == "rd.luks.uuid=UUID" ]] && luksUUID="";
3828 [[ -n "${rootFSType}" ]] && rootFSType="rootfstype=${rootFSType#'rootfstype='}";
3829 [[ -n "${rootFlags}" ]] && rootFlags="rootflags=${rootFlags#'rootflags='}";
3830
3831 # same steps as above, but for a separate /usr mount (if it exists)
3832
3833 ( [[ -n "$(cat /etc/mtab | grep ' /usr ')" ]] || [[ -n "${usrDisk}${usrFSType}${usrFlags}" ]] ) && usrMountFlag=1
3834
3835 usrMountFlag=0
3836
3837 if (( $usrMountFlag == 1 )); then
3838
3839 [[ -z "${usrDisk}" ]] && [[ -n "$(mount -l | grep 'on /usr type' | sed -E s/'^(.*) on \/usr type .*$'/'\1'/)" ]] && usrDisk="$(mount -l | grep 'on /usr type' | sed -E s/'^(.*) on \/usr type .*$'/'\1'/)";
3840
3841 [[ -z "${usrFSType}" ]] && [[ -n "$(mount -l | grep 'on /usr type' | sed -E s/'^.* on \/usr type ([^ ]*) .*$'/'\1'/)" ]] && usrFSType="$(mount -l | grep 'on /usr type' | sed -E s/'^.* on \/usr type ([^ ]*) .*$'/'\1'/)";
3842 [[ "${usrDisk}" == 'ZFS='* ]] && usrFSType='zfs'
3843 [[ ${usrFSType#*=} =~ ^[Zz][Ff][Ss]$ ]] && usrFSype="zfs" && [[ -n "${usrDisk}" ]] && usrDisk="ZFS=$(echo "${usrDisk}" | sed -E s/'^[Zz][Ff][Ss]=(.*)'/'\1'/)"
3844
3845 [[ -z "${usrFlags}" ]] && [[ -n "$(mount -l | grep 'on /usr type' | sed -E s/'^.* on \/usr type [^ ]* \(([^\)]*)\).*$'/'\1'/)" ]] && usrFlags="$(mount -l | grep 'on /usr type' | sed -E s/'^.* on \/usr type [^ ]* \(([^\)]*)\).*$'/'\1'/)";
3846 [[ ${usrFSType#*=} =~ ^[Zz][Ff][Ss]$ ]] && [[ ! ${usrFlags#'mount.usrflags='} =~ ^(.+,)?zfsutil(,.+)?$ ]] && usrFlags="zfsutil,${usrFlags#'mount.usrflags='}"
3847
3848 [[ -n "${usrDisk}" ]] && usrDisk="mount.usr=$(myDevToID "${usrDisk#'mount.usr='}")";
3849 [[ -n "${usrFSType}" ]] && usrFSType="mount.usrfstype=${usrFSType#'mount.usrfstype='}";
3850 [[ -n "${usrFlags}" ]] && usrFlags="mount.usrflags=${usrFlags#'mount.usrflags='}";
3851 fi
3852
3853 # automatically make additions to the command line that are specific to using a nvidia gpu, using LUKS, and using ZFS
3854
3855 [[ -n "$(rpm -qa | grep 'nvidia')" ]] && kernelCmdline_static="${kernelCmdline_static} rd.driver.blacklist=nouveau rd.modprobe.blacklist=nouveau rd.driver.pre=nvidia rd.driver.pre=nvidia_uvm rd.driver.pre=nvidia_drm rd.driver.pre=drm driver.blacklist=nouveau modprobe.blacklist=nouveau driver.pre=nvidia driver.pre=nvidia_uvm driver.pre=nvidia_drm driver.pre=drm nvidia-drm.modeset=1"
3856 [[ -n "${luksUUID}" ]] && kernelCmdline_static="${kernelCmdline_static} rd.driver.pre=dm_crypt driver.pre=dm_crypt rd.luks.allow-discards rd.luks.timeout=60"
3857 [[ -n "$(rpm -qa | grep 'zfs')" ]] && kernelCmdline_static="${kernelCmdline_static} zfs.zfs_flags=0x1D8 zfs_ignorecache=1"
3858 [[ ${rootFSType#*=} =~ ^[Zz][Ff][Ss]$ ]] && kernelCmdline_static="${kernelCmdline_static} rd.driver.pre=zfs driver.pre=zfs zfs_force=1"
3859
3860 kernelCmdline_systemdUnits='systemd.show_status'
3861# for nn in /etc/systemd/personal/*.service; do
3862# [[ "${nn##*/}" != 'my-zfs-'* ]] && kernelCmdline_systemdUnits="${kernelCmdline_systemdUnits} "'rd.systemd.mask="'"${nn##*/}"'"'
3863# done
3864 #[[ -f "/etc/systemd/personal/zfsSwitchServices.sh" ]] && kernelCmdline_systemdUnits="${kernelCmdline_systemdUnits} "'rd.systemd.run="/bin/chmod 777 /etc/systemd/personal/zfsSwitchServices.sh" systemd.run="/bin/bash -c '"'"'/etc/systemd/personal/zfsSwitchServices.sh'"'"'"'
3865 # systemd.run_success_action=none systemd.run_failure_action=none'
3866 #[[ ${rootFSType#*=} =~ ^[Zz][Ff][Ss]$ ]] && kernelCmdline_systemdUnits="${kernelCmdline_systemdUnits} "'rd.systemd.units="my-zfs-import.service" rd.systemd.units="my-zfs-mount.service"'
3867
3868 #if [[ ${rootFSType#*=} =~ ^[Zz][Ff][Ss]$ ]]; then
3869 #...
3870 #else
3871 # for nn in /etc/systemd/personal/*.service; do
3872 # [[ ${nn} =~ ^my-zfs-.*\.service$ ]]] && kernelCmdline_systemdUnits='${kernelCmdline_systemdUnits} systemd.mask="'"${nn##*/}"'"'
3873 # done
3874 #fi
3875
3876 kernelCmdline="${luksUUID} ${bootDisk} ${rootDisk} ${rootFSType} ${rootFlags} ${usrDisk} ${usrFSType} ${usrFlags} ${kernelCmdline_spectreMeltdownMitigations} ${kernelCmdline_systemdUnits} ${kernelCmdline_static} rd.info rd.shell rd.driver.pre=vfat rhgb";
3877 kernelCmdline="$(echo "${kernelCmdline}" | sed -E s/'^[ \t]*([^ \t].*[^ \t])[ \t]*$'/'\1'/ | sed -E s/'[ \t]+'/' '/g)";
3878
3879 # Setup additional (non-kernel-commandline) dracut arguments.
3880 # You may want to customize the initial 'dracutArgsExtra' variable, though this isnt as important as custom setting 'kernelCmdline_static' is
3881
3882 dracutArgsExtra='--persistent-policy "by-id" --no-hostonly-i18n --no-hostonly --nostrip --hostonly-cmdline --early-microcode --nohardlink --install /bin/vim --install /bin/tee --install /bin/seq --install /bin/find --install /bin/wc --install /bin/tail --install /bin/head --force-add crypt --force-add dm --force-add zfs --force-add bash --force-add dracut-systemd --force-add systemd --force-add uefi-lib --force-add kernel-modules --force-add kernel-modules-extra --add plymouth --include /etc/iscsi/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi --include /run/cryptsetup /run/cryptsetup --include /lib/modules/'"$(uname -r)"'/extra /lib/modules/'"$(uname -r)"'/extra'
3883
3884 # include items from /usr/local/my-{scripts,services}
3885 for nn in '/etc/systemd/personal/' /usr/local/bin/my-{scripts,services}/ /usr/local/bin/my-{scripts,services}/*.sh /etc/systemd/personal/*{.sh,.service}; do
3886 dracutArgsExtra="${dracutArgsExtra} --include ${nn} ${nn}"
3887 done
3888
3889 # include + install items from /etc/systemd/personal into both /etc/systemd/personal and /etc/systemd/system in the initrd
3890 if [[ -d "/etc/systemd/personal" ]]; then
3891 for nn in /etc/systemd/personal/*{.sh,.service}; do
3892 [[ "${nn}" == *.service ]] && chmod -x "${nn}" || chmod +x "${nn}"
3893 \cp -f "${nn}" "/usr/lib/systemd/system/";
3894
3895 dracutArgsExtra="${dracutArgsExtra} --include ${nn} ${nn//\/personal\//\/system\/}";
3896 dracutArgsExtra="${dracutArgsExtra} --include ${nn} ${nn//\/personal\//\/user\/}";
3897
3898 #dracutArgsExtra="${dracutArgsExtra} --install ${nn}";
3899 #[[ -e "${nn//\/personal\//\/system\/}" ]] && dracutArgsExtra="${dracutArgsExtra} --install ${nn//\/personal\//\/system\/}";
3900 #[[ -e "${nn//\/personal\//\/user\/}" ]] && dracutArgsExtra="${dracutArgsExtra} --install ${nn//\/personal\//\/user\/}";
3901 done
3902 fi
3903
3904 # manually specify boot stub location
3905 [[ -e "/usr/lib/systemd/boot/efi/linuxx64.efi.stub" ]] && dracutArgsExtra="${dracutArgsExtra} --uefi-stub /usr/lib/systemd/boot/efi/linuxx64.efi.stub"
3906
3907 # Print info to screen about the parsed parameters.
3908 # If '--no-ask' flag is set, pause for 10 seconds then continue.
3909 # Otherwise, pause for a minute and request user feedback.
3910 # Note: if no feedbback is received in 1 minute, the code will continue running.
3911
3912 echo -e "\n\nTHE FOLLOWING SETTINGS HAVE BEEN DYNAMICALLY SET (UNLESS OVERWRITTEN BY HARD-CODED DEFAULTS) \n"
3913 (( $noAskFlag == 0 )) && echo -e "Do these look correct? \n----> An empty/null response or a response of y[es] will be taken as \"yes\" \n----> Any other non-empty response will be taken as \"no\" \n----> Timeout is 60 seconds. Default response upon timeout is \"yes\" \n"
3914 echo -e " ${rootDisk} $( [[ -n "${rootDisk}" ]] && echo '\n ' )${rootFSType}$( [[ -n "${rootFSType}" ]] && echo '\n ' )${rootFlags}$( [[ -n "${rootFlags}" ]] && echo '\n ' )${bootDisk}$( [[ -n "${bootDisk}" ]] && echo '\n ' )${luksUUID}$( [[ -n "${luksUUID}" ]] && echo '\n ' )${usrDisk}$( [[ -n "${usrDisk}" ]] && echo '\n ' )${usrFSType}$( [[ -n "${usrFSType}" ]] && echo '\n ' )${usrFlags}$( [[ -n "${usrFlags}" ]] && echo '\n' ) \nAdditional Dracut parameters: -fvM --uefi ${dracutArgsExtra} \n\nFULL KERNEL COMMAND LINE: \n\n${kernelCmdline} \n";
3915
3916 (( $noAskFlag == 0 )) && read -iE -t 60 -p "Response ( <null>/y[es] --> yes | anything else --> no ): " userResponse && [[ -n "${userResponse}" ]] && [[ ! ${userResponse,,} =~ ^y(es)?$ ]] && [[ ! ${userResponse} =~ ^[\ \t]*$ ]] && return 1;
3917 (( $noAskFlag == 1 )) && echo "The code will proceed in 10 seconds..." && sleep 10;
3918
3919 # ensure a few extra modules have prerequisites met
3920
3921 [[ -n "$(for nn in {biosdevname,nbd,gpg,clevis,stratis,busybox,udisks2-iscsi}; do [[ -n "$(rpm -qa | grep "$nn")" ]] || echo '1'; done)" ]] && dnf install -y biosdevname nbd gpg *clevis* stratis* busybox udisks2-iscsi
3922
3923 # shift efi files and ensure systemd is up to date systemd
3924
3925 #UEFIBootUpdate --shift-efi;
3926
3927 #systemctl enable clevis-luks-askpass.path
3928 systemctl set-default graphical.target --global --user;
3929 systemctl set-default graphical.target --global --system;
3930 systemctl daemon-reload;
3931 systemctl daemon-reload --global --system;
3932 systemctl daemon-reexec --global --system;
3933
3934 # run dracut --uefi, either for specific kernels or for all kernels
3935
3936 if (( $# == 0 )) || [[ ${*,,} =~ ^(.+\ )?-+a(ll)?(\ .+)?$ ]]; then
3937 dracut -fvM --uefi --kernel-cmdline "${kernelCmdline}" --regenerate-all ${dracutArgsExtra};
3938 else
3939 for nn in "${@}"; do
3940 [[ -e "/lib/modules/${nn}" ]] && dracut -fvM --uefi --kernel-cmdline "${kernelCmdline}" --kver "${nn}" ${dracutArgsExtra};
3941 done;
3942 fi;
3943
3944 UEFIBootOrderList -v
3945}
3946
3947
3948myFindEFIDev() {
3949 # attempts to automatically find the block device the system EFI partition is on
3950 # scans /etc/fstab and /etc/mtab for any vfat filesystem mounts on /boot, /boot/efi, or /efi
3951
3952 local -a EFIdev
3953 local nn=0
3954
3955 EFIdev=($(echo "$(cat /etc/{m,fs}tab | grep -E '[ \t](((\/[Bb][Oo][Oo][Tt])?\/[Ee][Ff][Ii])|\/[Bb][Oo][Oo][Tt])[ \t]' | sed -E s/'^[ \t]*([^ \t]*)[ \t].*$'/'\1'/)"))
3956
3957 for nn in $(seq 0 $((( ${#EFIdev[@]} - 1 )))); do
3958
3959 [[ ${EFIdev[$nn]^^} =~ ^UUID=[0-9A-Z-]+$ ]] && EFIdev[$nn]="$(findmnt ${EFIdev[$nn]} | tail -n $((( $(findmnt ${EFIdev[$nn]} | wc -l) - 1 ))) | grep -E '(((\/[Bb][Oo][Oo][Tt])?\/[Ee][Ff][Ii])|\/[Bb][Oo][Oo][Tt])[ \t]' | sed -E s/'^[^ \t]+[ \t]+([^ \t]*)[ \t].*$'/'\1'/)"
3960
3961 [[ ${EFIdev[$nn]} =~ ^\/dev\/disk\/by-id\/.+$ ]] && EFIdev[$nn]="$(echo "/dev/$(ls -l1 /dev/disk/by-id | grep -F "/${1##*/}" | head -n 1 | sed -E s/'^.* -> \.\.\/\.\.\/(.*)$'/'\1'/)")"
3962
3963 done
3964
3965 echo "$(local nn=""; for nn in "${EFIdev[@]}"; do [[ -n "$(findmnt "${nn}" | grep 'vfat' | grep -E '^\/boot(\/efi)?[ \t]')" ]] && echo "${nn}"; done)" | sort -u
3966}
3967
3968myDevToID() {
3969 # find a unique block device name from /dev/disk/by-id or a unique uuid for the device
3970 # input is block device ( /dev/<...> )
3971 # output is the (full path of the) matching entry in /dev/disk/by-id/<...>, UNLESS using uuid flag
3972 # if flag '-u' or '--uuid' is used as 1st input, output will instead be 'UUID=<deviceUUID>'
3973 # if flag --type=<...> is used, where <...>=[by-]{partuuid,partlabel,path,id,label,uuid}; then the corresponding folder in /dec/disk will be used. Note that using 'uuid' here outputs the path in /dev/disk/uuid, NOT 'UUID=<deviceUUID>'
3974
3975 local uuidFlag=0
3976 local matchType=""
3977 local -a inAll0
3978 local inAll=""
3979 local nn=""
3980
3981 inAll0=("${@}")
3982
3983 for nn in $(seq 0 $((( ${#inAll0[@]} - 1 )))); do
3984
3985 if [[ ${inAll0[$nn],,} =~ ^-+u(uid)?$ ]]; then
3986 uuidFlag=1 && matchType='uuid' && inAll0[$nn]=""
3987
3988 elif [[ ${inAll0[$nn],,} =~ ^-+type=(by-)?(id|uuid|partuuid|partlabel|label|path)$ ]]; then
3989 [[ "${matchType}" != 'uuid' ]] && matchType="$(echo "${inAll0[$nn],,}" | sed -E s/'^-+type=["'"'"']?(by-)?(id|uuid|partuuid|partlabel|label|path)["'"'"']?$'/'\2'/)" && inAll0[$nn]=""
3990
3991 else
3992 inAll="$(cat <(echo "${inAll}") <(echo "${inAll0[$nn]}"))"
3993 fi
3994 done
3995
3996 inAll="$(echo "${inAll}" | grep -vE '^$')"
3997
3998 [[ -z "${matchType}" ]] && matchType='id'
3999
4000 if (( $(echo "${inAll}" | wc -l) > 1 )); then
4001
4002 (( $uuidFlag == 1 )) && matchType='-u' || matchType='type=by-'"${matchType}"
4003
4004 echo "${inAll}" | while read -r nn; do
4005 [[ -n "${nn}" ]] && myDevToID ${matchType} "${nn}"
4006 done
4007
4008 else
4009
4010 [[ "${inAll}" == '/dev/mapper/'* ]] && echo "${*}" && return
4011
4012 [[ "${inAll^^}" =~ ^ZFS=.+$ ]] && echo "ZFS=${*##*=}" && return
4013
4014 (( $uuidFlag == 1 )) && [[ "${inAll}" == /dev/disk/by-uuid/* ]] && [[ -e "${inAll}" ]] && ( [[ -z "${*##*/}" ]] && echo "" || echo "UUID=${*##*/}" ) && return
4015 (( $uuidFlag == 0 )) && [[ "${inAll}" == /dev/disk/by-${matchType}/* ]] && [[ -e "${inAll}" ]] && echo "${inAll}" && return
4016
4017 (( $uuidFlag == 0 )) && [[ "${inAll}" == /dev/disk/* ]] && [[ ! "${inAll}" == /dev/disk/by-${matchType}/* ]] && inAll="$(realpath "${inAll%/*}/$(ls -l1 ${inAll%/*} | grep -vE '(^nvme-eui|^nvme-nvme|^wwn)' | grep -F "${inAll##*/}" | sed -E s/'^.* [^ ]* -> (.*)$'/'\1'/ | sort -u | head -n 1)")"
4018
4019 (( $uuidFlag == 1 )) && echo "UUID=$(ls -l1 /dev/disk/by-uuid | grep -F "/${inAll##*/}" | head -n 1 | sed -E s/'^.* ([^ ]*) -> .*$'/'\1'/)"
4020 (( $uuidFlag == 0 )) && echo "/dev/disk/by-${matchType}/$(ls -l1 /dev/disk/by-${matchType} | grep -v -E '(nvme\-eui|nvme\-nvme|wwn)' | grep -F "/${inAll##*/}" | head -n 1 | sed -E s/'^.* ([^ ]*) -> .*$'/'\1'/)"
4021
4022 fi
4023}
4024
4025UEFIBootUpdate() {
4026 # Generates new EFI boot menu entries for new .efi files detected in <EFI_DEV>/EFI/Linux/linux-*.efi
4027 #
4028 # NOTES: 1) Old entries are not auto deleted. YOull have to do this manually with efibootmgr
4029 # 2) It determines "new" entries mt matching the loader menu name and the efi filename.
4030 # If there are 2 efi files with the same loader name (perhaps on different disks),
4031 # it wont automatically recognize/create the 2nd one. Basically, ensure the names are unique.
4032 #
4033 # ALT BEHAVIOR: use flag '--shift-efi' to instead rotate the current efi files into "_OLD" versions.
4034 # existing "_OLD" versions will be overwritten. This by default gives 1 backup copy, though
4035 # manually setting a filename to "*_WORKING" is also accepted,
4036 #
4037 # 3 efi name types will be considered when determining whether to make a efi boot file:
4038 # the original dracut output, and names are parsed like so:
4039 #
4040 # linux-$(uname -r)[_OLD|_WORKING]-<machineID>.efi (examples below)
4041 #
4042 # linux-4.18.18-300.fc29.x86_64_OLD-48c20436d5fd44b485482ed7dbea0a3f.efi
4043 # linux-4.19.12-301.fc29.x86_64_WORKING-48c20436d5fd44b485482ed7dbea0a3f.efi
4044 # linux-4.19.15-300.fc29.x86_64-48c20436d5fd44b485482ed7dbea0a3f.efi
4045 #
4046 # ( NOTE: menu entries will be named using everything between the 2 '-' characters - e.g. '4.19.12-301.fc29.x86_64_WORKING')
4047 #
4048 # The standard names automatically replace the "_OLD" names before each every update, and thus are always remade
4049 # and the "WORKING" names are left as is, and if they dont exist the current efi file will be made into the "_WORKING" efi file
4050
4051 local nn=0;
4052 local EFIcurmenu="";
4053 local -a kverEFI;
4054 local EFIbasedir="";
4055 local EFIdev0="";
4056 local EFIdev="";
4057 local EFIpart="";
4058 local EFIpartuuid=""
4059 local kverEFI="";
4060 local kverEFItemp="";
4061 local kverEFIWorking="";
4062 local -a kverEFINew;
4063
4064 # find base dir for efi device. should be /boot, /boot/efi, or /efi, depending of the system setup
4065
4066 if (( $# > 0 )) && [[ -d "${1}" ]]; then
4067 EFIbasedir="${1}";
4068 else
4069 EFIbasedir="$(findmnt $(myFindEFIDev) | grep -E '(((\/[Bb][Oo][Oo][Tt])?\/[Ee][Ff][Ii])|\/[Bb][Oo][Oo][Tt])[ \t]' | sed -E s/'^([^ \t]*).*$'/'\1'/)"
4070 if [[ ! -d "${EFIbasedir}" ]]; then
4071 if [[ -d "/boot/efi/EFI" ]] &&
4072 [[ -z "$(mountpoint "/boot/efi" | grep 'not')" ]]; then
4073 EFIbasedir="/boot/efi";
4074 elif [[ -d "/boot/EFI" ]] && [[ -z "$(mountpoint "/boot" | grep 'not')" ]]; then
4075 EFIbasedir="/boot";
4076 elif [[ -d "/efi/EFI" ]] && [[ -z "$(mountpoint "/efi" | grep 'not')" ]]; then
4077 EFIbasedir="/boot";
4078 elif [[ -d "/boot/efi" ]]; then
4079 EFIbasedir="/booti/efi";
4080 elif [[ -d "/EFI" ]]; then
4081 EFIIbasedir="/";
4082 elif [[ -d "/efi" ]]; then
4083 EFIbasedir="/efi";
4084 else
4085 EFIbasedir="/boot/efi";
4086 fi
4087 fi
4088 fi
4089
4090 # break into device + partition
4091
4092 #EFIdev="$(mount -l | grep -F "${EFIbasedir}" | sed -E s/'^([^ ]*) .*$'/'\1'/ | sort -u)";
4093 EFIdev0="$(myDevToID "$(myFindEFIDev)")"
4094 EFIpart="$(echo -n "${EFIdev0}" | sed -E s/'^.*[^0-9]([0-9]+)$'/'\1'/)";
4095 EFIdev="$(echo -n "${EFIdev0}" | sed -E s/'^(.*)-part[0-9]*$'/'\1'/)";
4096 EFIpartUUID="$(myDevToID --type=partuuid "${EFIdev0}")"
4097 EFIpartUUID="${EFIpartUUID#'/dev/disk/by-partuuid/'}"
4098
4099 [[ -n "$(echo "${EFIdev}" | grep 'nvme')" ]] && EFIdev="${EFIdev%p}";
4100
4101 echo -e "\nThe following properties have been identified for the EFI system partition: \n Mount Point: \t ${EFIbasedir} \n Device Name: \t ${EFIdev} \n Partition: \t ${EFIpart} \n";
4102 sleep 5;
4103
4104 # get list of current menu entries and kernel versions of items to add
4105
4106 EFIcurmenu="$(efibootmgr -v 2>&1)";
4107
4108 kverEFI="$(find "${EFIbasedir}/EFI/Linux/" -maxdepth 1 -type f -name "linux-*.efi" | sort -V)";
4109 kverEFI="$(echo "$kverEFI" | grep -F "$(uname -m)_OLD-"; echo "$kverEFI" | grep -F "$(uname -m)_WORKING-"; echo "$kverEFI" | grep -F "$(uname -m)-")"
4110
4111 # check if *_WORKING efi boot file exists, if not copy current efi boot file into *_WORKING efi boot file
4112
4113 echo "$kverEFI" | grep -v -E '_(OLD|WORKING)-' | sort -u | while read -r nn; do [[ ! -f "${nn//$(uname -m)/$(uname -m)_WORKING}" ]] && cp "${nn}" "${nn//$(uname -m)/$(uname -m)_WORKING}" && echo -e "\nSince no ${nn%$(uname -m)*}_WORKING efi file exists, \nthe current efi boot file ${nn%$(uname -m)*} has been saved as a working backup. \nNote that this is not auto updated - you will have to manually update this file from now on (should you want to). \n" >&2; done
4114
4115 # get updated list of current menu entries and kernel versions of items to add
4116
4117 kverEFI="$(find "${EFIbasedir}/EFI/Linux/" -maxdepth 1 -type f -name "linux-*.efi" | sort -V)";
4118 kverEFI="$(echo "$kverEFI" | grep -F "$(uname -m)_OLD-"; echo "$kverEFI" | grep -F "$(uname -m)_WORKING-"; echo "$kverEFI" | grep -F "$(uname -m)-")"
4119
4120 # update efi boot order or (if --shift-efi flag set) shift the on-disk efi files
4121
4122 [[ -n "${kverEFI}" ]] && echo "${kverEFI}" | while read -r nn; do
4123 if [[ ${1,,} =~ ^-+s(hift)?-?e(fi)?$ ]]; then
4124 \mv -f "$(echo -n "${nn}")" "$(echo -n "${nn%$(uname -m)*}$(uname -m)_OLD-${kverEFI[$nn]##*-}")";
4125 else
4126 kverEFItemp="${nn,,}"
4127 [[ -z "$(echo "${EFIcurmenu,,}" | grep -F "$(echo -n "${kverEFItemp##*linux-}")" | grep -vF "${EFIpartuuid}")" ]] && efibootmgr -c -d "${EFIdev}" -p ${EFIpart} -l "$(echo -n "${nn##"$EFIbasedir"}")" -L "Fedora-EFI_$(echo -n "${nn##*linux-}" | sed -E s/'^([^-]*-[^-]*)-.*$'/'\1'/)" 1>/dev/null;
4128 fi
4129 done
4130
4131
4132 # print new boot order (unless using --shift-efi)
4133 [[ ${1,,} =~ ^-+s(hift)?-?e(fi)?$ ]] || UEFIBootOrderList -v
4134}
4135
4136UEFIBootOrderList() {
4137 # prints a "nice" list of active and inactive boot entries. Basically, a poretty alternative to the output of efibootmgr
4138 #
4139 # FLAGS
4140 #
4141 # use flag '-v' or '--verbose' to give additional output (including info on what disk/partition/file the boot entry represents)
4142 #
4143 # use flag '-m' or '--mod[ify]' to reorder the default boot list order
4144 # This will cause the boot list to be displayed, after which you will be interactively asked to choose entries to:
4145 # a) deactivate b) send to the top of the active list
4146 #
4147 # use flag '-nd' or '--no-dedup' to NOT de-deplicate the boot order list.
4148 # The default behavior is to automatically "fix" the boot order by removing duplicate entries from the boot order list
4149 # Note: this is NOT reffering to duplicates of the actual efi entries returned by 'efibootmgr',
4150 # but rather to any repeated (HEX x4) values in the boot order listing that is set via 'efibootmgr -o'
4151
4152 local nn="";
4153 local EFImenu="";
4154 local -a bootOrderVal;
4155 local -a bootOrderIsActive;
4156 local -a bootOrderInd;
4157 local -a bootOrderReMap;
4158 local activeIndList=""
4159 local inactiveIndList=""
4160 local bootCurTemp=""
4161 local indCurTemp=""
4162 local kk=0;
4163 local kk1=0;
4164
4165 bootOrderInd=($(echo -n "$(efibootmgr | grep -E '^BootOrder\:' | sed -E s/'^BootOrder\: (.*)$'/'\1'/ | myuniq | sed -zE s/'\n'/' '/g)"));
4166 [[ ${*,,} =~ ^(.+ )?-+no?-?d(edup)?( .+)?$ ]] || efibootmgr -o $(echo ${bootOrderInd[@]} | sed -E s/' '/','/g) 2>&1 1>/dev/null
4167 EFImenu="$(efibootmgr $( [[ ${*,,} =~ ^(.+ )?-+v(erbose)?( .+)?$ ]] && echo '-v' ) | tail -n +4)";
4168
4169 kk=0
4170 for nn in "${bootOrderInd[@]}"; do
4171 bootCurTemp="$(echo "${EFImenu}" | grep --color=auto -E '^Boot'"${nn}"'[\* ] ')"
4172 bootOrderVal[$kk]="$(echo "${bootCurTemp}" | sed -E s/'^Boot[^\* ]*[\* ] (.*)$'/'\1'/)";
4173 [[ "${bootCurTemp%% *}" == *\* ]] && bootOrderIsActive[$kk]=1 && activeIndList="${activeIndList} ${kk}"
4174 [[ ! "${bootCurTemp%% *}" == *\* ]] && bootOrderIsActive[$kk]=0 && inactiveIndList="${inactiveIndList} ${kk}"
4175 ((kk++))
4176 done
4177
4178 echo -e "\n||----------------------------------------------------------||\n||-------------------- EFI BOOT ENTRIES --------------------||\n||----------------------------------------------------------||\n";
4179 echo -e "\n||------------------------- ACTIVE -------------------------||\n";
4180
4181 kk1=0
4182 for kk in ${activeIndList}; do
4183 echo "(${kk1}) ${bootOrderVal[$kk]}"
4184 bootOrderReMap[$kk1]=${kk}
4185 ((kk1++))
4186 done
4187
4188 echo -e "\n\nNOTE: The above list is ordered by boot priority. The 1st listing is the \"default\" boot entry. \n The default behavior is to try these in order until a valid/working boot image is found.";
4189
4190 echo -e "\n\n||------------------------ INACTIVE ------------------------||\n";
4191
4192 for kk in ${inactiveIndList}; do
4193 echo "(${kk1}) ${bootOrderVal[$kk]}"
4194 bootOrderReMap[$kk1]=${kk}
4195 ((kk1++))
4196 done;
4197 echo -e "\n\nNOTE: To activate/deactivate/reorder efi boot menu entries, run 'UEFIBootOrderList -m [-v]'\n\n"
4198
4199 if [[ ${*,,} =~ ^(.+ )?-+m(od(ify)?)?( .+)?$ ]]; then
4200 local userResponse=""
4201
4202 echo -e "\nRespond to the following questions with a {space,comma,newline}-seperated list of indicies from the above listing. \nThe index is the number shown in (#) at the start of each line. \nNote: Non-numeric characters (except for spaces, commas and newlines) will be filtered out of the response and ignored. \n\nTimeout is 30 seconds\n"
4203
4204 read -ie -t 30 -p "Select boot entries to deactivate: " userResponse
4205
4206 userResponse="$(echo "${userResponse}" | sed -E s/'[ \n]'/' '/g | sed -E s/'[^0-9 ]'//g | sed -E s/' +'/' '/g | sed -E s/'^ $'//)"
4207
4208 if [[ -n "${userResponse}" ]]; then
4209 for kk in ${userResponse}; do
4210 (( $kk < ${#bootOrderReMap[@]} )) && efibootmgr -A -b "${bootOrderInd[${bootOrderReMap[$kk]}]}" 2>&1 1>/dev/null
4211 done
4212 fi
4213
4214 userResponse=""
4215 read -ie -t 30 -p "Select boot entries to place at the top of the \"active\" list: " userResponse
4216
4217 userResponse="$(echo "${userResponse}" | sed -E s/'[ \n]'/' '/g | sed -E s/'[^0-9 ]'//g | sed -E s/' +'/' '/g | sed -E s/'^ $'//)"
4218
4219 if [[ -n "${userResponse}" ]]; then
4220 local bootOrderNew=""
4221 local -a bootOrderNewTemp
4222 bootOrderNewTemp=("${bootOrderInd[@]}")
4223 for kk in ${userResponse}; do
4224 if (( $kk < ${#bootOrderReMap[@]} )); then
4225 efibootmgr -a -b ${bootOrderInd[${bootOrderReMap[$kk]}]} #2>/dev/null
4226 bootOrderNew="${bootOrderNew} ${bootOrderInd[${bootOrderReMap[$kk]}]}"
4227 bootOrderNewTemp[${bootOrderReMap[$kk]}]=""
4228 fi
4229 done
4230
4231 bootOrderNew="$(echo "${bootOrderNew} ${bootOrderNewTemp[@]}" | sed -E s/'[ \t\n\,]+'/' '/g | sed -E s/'^ *([^ ].*[^ ]) *$'/'\1'/ | myuniq | sed -zE s/'\n'/','/g | sed -E s/'^(.*[^.]),*$'/'\1\n'/)"
4232 efibootmgr -o "${bootOrderNew%,}" #2>&1 1>/dev/null
4233 fi
4234
4235 echo -e "\n\n||----------------- NEW BOOT MENU ORDERING -----------------|| \n\n"
4236 UEFIBootOrderList $( [[ ${*,,} =~ ^(.+ )?-+v(erbose)?( .+)?$ ]] && echo '-v' )
4237 fi
4238}
4239
4240myuniq() {
4241 # returns unique elements in a list
4242 # replacement for 'uniq', which is straight broken on my system
4243 # input should be list separated by newlines/spaces/tabs/commas
4244 # output is newline-separated list
4245
4246 local inAll=""
4247 local outAll=""
4248
4249 (( $# > 0 )) && inAll="${@}" || inAll="$(cat <&0)"
4250 inAll="$(echo -n "${inAll}" | sed -zE s/'[ ,\t]'/'\n'/g | sed -zE s/'\n+'/'\n'/g)"
4251 while [[ -n "${inAll}" ]]; do
4252 outAll="$(echo "${outAll}"; echo "${inAll}" | head -n 1)"
4253 inAll="$(echo -n "${inAll}" | grep -v -F "$(echo "${inAll}" | head -n 1)")"
4254 done
4255
4256 outAll="$(echo "${outAll}" | grep -E '.+')"
4257 echo "${outAll}"
4258}
4259
4260UEFIKernelPostInstallSetup() {
4261 # setup kernel post install script to automatically re-make the bootable efi files after a kernel update
4262 # untested, but i think it should work. Change '/usr/local/bin/my-scripts/dracut-UEFI-boot.sh' to wherever this file is actually saved.
4263
4264 cat << EOF > "/etc/kernel/postinst.d/dracut-EFI_postinst"
4265#!/bin/bash
4266
4267source /usr/local/bin/my-scripts/dracut-UEFI-boot.sh
4268
4269(( \$# > 0 )) && zfsDracutUpdate "\${@}" || zfsDracutUpdate
4270
4271[[ -d "/boot" ]] && [[ -n "\$(echo \$(rpm -qa | grep 'zfs'))" ]] && [[ -n "\$(zfs list | grep 'FEDORA/ROOT/BOOT')" ]] && zfsBackupBoot
4272
4273EOF
4274
4275 chmod 755 "/etc/kernel/postinst.d/dracut-EFI_postinst"
4276
4277}
4278
4279
4280myGetUserInput(){
4281 # this is intended as a user input request function, but apparently i never ended up using it....
4282
4283 local aCur=""
4284 local userResponse=""
4285 local aindSelect=0
4286 local -a arrayIn
4287 local kk=0
4288
4289 #readarray arrayIn < <(echo "${1}" | sort -u)
4290 echo "${1}" | sort -u | read -a arrayIn
4291
4292 if (( ${#arrayIn[@]} > 1 )); then
4293
4294 echo -e "\nUnable to determine the \"${2}\" device path. Please select one of the following. \nTimeout is 30 seconds, after which choice 0 will be used by default. \n\n"
4295
4296 kk=0
4297 for aCur in "${arrayIn[@]}"; do
4298 echo "(${kk}): ${aCur}"
4299 ((kk++))
4300 done
4301
4302 echo "(${kk}}: Manually enter boot device path"
4303 read -ie -t 30 -p "Choose a response [0-${kk}]: " userResponse
4304
4305 [[ ${userResponse} =~ ^[0-9]+$ ]] && (( $userResponse >= 0 )) && (( $userResponse <= $kk )) || userResponse=0
4306 (( $userResponse == $kk )) && read -ie -t 120 -p "Please enter the \"${2}\" device path: " aindSelect && [[ ! -e "${aindSelect}" ]] && echo "INPUT BLOCK DEVICE DOES NOT EXIST! THE CODE WILL NOW ABORT!" && exit 1
4307 (( $userResponse < $kk )) && aindSelect="${arrayIn[$userResponse]}"
4308
4309 echo "${userResponse}"
4310
4311 else
4312
4313 echo "${1}"
4314
4315 fi
4316}
4317
4318
4319zfsBackupBoot() {
4320
4321 local -a fileChanged;
4322 local -a fileRemoved;
4323 local mountBOOTFlag=0;
4324 local nn="";
4325 local BOOTMountPoint=""
4326
4327 [[ -z "$(find /boot | grep -v -E '^\/boot$')" ]] && return
4328 [[ -z "$(find /BOOT | grep -v -E '^\/BOOT$')" ]] && mountBOOTFlag=1 && zfs mount FEDORA/ROOT/BOOT;
4329 BOOTMountPoint="$(zfs get mountpoint -r -t filesystem | grep -E 'mountpoint[ \t]+\/BOOT[ \t]' | sed -E s/'^([^ ]*) .*$'/'\1'/)"
4330 [[ -z "$(find ${BOOTMountPoint} | grep -v -E '^'"${BOOTMountPoint}"'$')" ]] && return
4331
4332 /bin/bash -c "mapfile -t fileChanged < <(rsync -avPAXEWH --super -n /boot/ ${BOOTMountPoint%/}/ | grep -v -E '\/$' | grep -v 'sending incremental file list');"
4333
4334 if (( ${#fileChanged[@]} > 0 )); then
4335 for nn in "${fileChanged[@]}"; do
4336 [[ -f "${BOOTMountPoint}/${nn}" ]] && mv -i -f "${BOOTMountPoint}/${nn}" "${BOOTMountPoint}/OLD/${nn}";
4337 done;
4338 fi;
4339
4340 rsync -aAXEPW --super /boot/ ${BOOTMountPoint}/;
4341
4342 /bin/bash -c "readarray fileRemoved < <(echo -n \"$(diff -dy --width=512 <(find \"${BOOTMountPoint}\" | sed -E s/'^'\"${BOOTMountPoint%/}\"'\/(.*)$'/'\1'/ | grep -v -E '^OLD' | sort -V) <(find \"/boot\" | sed -E s/'^\/boot\/(.*)$'/'\1'/ | sort -V))\" | grep '<' | sed -E s/'^(.+[^ \t])[ \t]*<.*$'/'\1'/);"
4343
4344 if (( ${#fileRemoved[@]} > 0 )); then
4345 for nn in "${fileRemoved[@]}";
4346 do
4347 [[ -d "${BOOTMountPoint}/OLD/$(echo -n "${nn%/*}/")" ]] || mkdir --parents "${BOOTMountPoint}/OLD/$(echo -n "${nn%/*}/")";
4348 mv -i -f "${BOOTMountPoint}/$(echo -n "${nn}")" "${BOOTMountPoint}/OLD/$(echo -n "${nn%/*}/")";
4349 done;
4350 fi;
4351
4352 (( ${mountBOOTFlag} == 1 )) && zfs umount FEDORA/ROOT/BOOT
4353
4354}
4355
4356zfs-modprobe() {
4357
4358 local nn="";
4359 zfs-depmod;
4360
4361 if (( $# == 0 )); then
4362 for nn in /lib/modules/*; do
4363 modprobe zfs -S "${nn##*/}";
4364 done;
4365 else
4366 for nn in "$@"; do
4367 [[ -f "/var/lib/${nn}" ]] && ( modprobe zfs -S "$nn" || echo "WARNING: ZFS MODULE FAILED TO LOAD FOR KERNEL \"${nn}\"" && (( 1 == 1 )) ) || [[ ${nn,,} =~ ^-+cur(rent)?$ ]] && ( modprobe zfs || echo "WARNING: ZFS MODULE FAILED TO LOAD FOR THE CURRENT KERNEL (\"${nn}\")" && (( 1 == 1 )) ) || echo "WARNING: Input not recognized as an installed kernel version [in \$(uname -r) format]. This input has been skipped.";
4368 done;
4369 fi
4370
4371}
4372
4373zfs-depmod() {
4374
4375 local nn="";
4376 local mm="";
4377
4378 for nn in /lib/modules/*; do
4379 if [[ -z "$(find "${nn}" -type f -name "zfs.ko*")" ]] && [[ -n "$(find /var/lib/dkms/zfs/ -type d -name "${nn##*/}")" ]] && [[ -n "$(find "$(find /var/lib/dkms/zfs/ -type d -name "${nn##*/}" | sort -V | tail -n 1)" -type f -name "zfs.ko*" | grep -E '\/'"$(uname -m)"'\/')" ]]; then
4380
4381 [[ -d "${nn}/extra" ]] || mkdir --parents "${nn}/extra";
4382
4383 if [[ ! -e "${nn}/extra/zfs" ]] || [[ ${1,,} =~ ^-+f(orce)?$ ]]; then
4384 echo "$(find "$(find /var/lib/dkms/zfs/ -type d -name "${nn##*/}" | sort -V | tail -n 1)" -type d -name "$(uname -m)")"
4385 ln -fs "$(find "$(find /var/lib/dkms/zfs/ -type d -name "${nn##*/}" | sort -V | tail -n 1)" -type d -name "$(uname -m)")" "${nn}/extra/zfs";
4386 fi
4387
4388 for mm in ${nn}/extra/zfs/module/*; do
4389 chmod +x "${mm}"
4390 if [[ -e "${nn}/extra/${mm##*/}" ]] || [[ ${1,,} =~ ^-+f(orce)?$ ]]; then
4391 echo "${mm}" "${nn}/extra/${mm##*/}";
4392 ln -fs "${mm}" "${nn}/extra/${mm##*/}";
4393 fi
4394 done;
4395 fi;
4396 done;
4397 depmod -a
4398}
4399# [[ "${rootDisk}" == /dev/mapper/* ]] && [[ -n "$(cryptsetup status "${rootDisk##*/}" | grep 'device:')" ]] && rootDisk="$(cryptsetup status "${rootDisk##*/}" | grep 'device:' | sed -E s/'^[ \t]*device\:[ \t]*(.*)$'/'\1'/)"
4400 # [[ -z "${bootDisk}" ]] && [[ -d "/boot" ]] && [[ -n "$(mount -l | grep 'on /boot type' | sed -E s/'^(.*) on \/boot type .*$'/'\1'/)" ]] && bootDisk="$(mount -l | grep 'on /boot type' | sed -E s/'^(.*) on \/boot type .*$'/'\1'/)";
4401 # [[ -z "${bootDisk}" ]] && [[ -d "/boot/efi" ]] && [[ -n "$(mount -l | grep 'on /boot/efi type' | sed -E s/'^(.*) on \/boot\/efi type .*$'/'\1'/)" ]] && bootDisk="$(mount -l | grep 'on /boot/efi type' | sed -E s/'^(.*) on \/boot\/efi type .*$'/'\1'/)";
4402 # [[ -z "${bootDisk}" ]] && [[ -d "/efi" ]] && [[ -n "$(mount -l | grep 'on /efi type' | sed -E s/'^(.*) on \/efi type .*$'/'\1'/)" ]] && bootDisk="$(mount -l | grep 'on /efi type' | sed -E s/'^(.*) on \/efi type .*$'/'\1'/)";
4403
4404zfsGetMountingOrder() {
4405 # returns a mounting order such that everything under the specified filesystem is mounted such that a parent directory mount point always is mounted before any mounts to one of its sub-directories
4406 # i.e., mounting zfs datasets to `/`, `/a`, `/b`, and `/a/c` will always have `/` go first, and will always have `a` go before `c`
4407
4408 local aa
4409 local bb
4410 local kk
4411
4412 aa="$(/sbin/zfs get mountpoint -r "${*}" -t filesystem -H -o name,value | grep -v 'none' | sed -E s/'\t'/' '/g)"
4413 bb="$(/sbin/zfs get mountpoint -r "${*}" -t filesystem -H -o value | grep -v 'none' | sed -E s/'^(.*)$'/'\1'/)"
4414
4415 eval "$(declare aa="" && aa="$(/sbin/zfs get mountpoint -r "${*}" -t filesystem -H -o name,value | grep -v 'none' | sed -E s/'\t'/' '/g)" && declare bb="" && bb="$(/sbin/zfs get mountpoint -r "${*}" -t filesystem -H -o value | grep -v 'none' | sed -E s/'^(.*)$'/'\1'/)" && echo "$(eval echo $(declare bb="" && bb="$(/sbin/zfs get mountpoint -r "${*}" -t filesystem -H -o value | grep -v 'none' | sed -E s/'^(.*)$'/'\1'/)" && eval echo $(declare bb="" && bb="$(/sbin/zfs get mountpoint -r "${*}" -t filesystem -H -o value | grep -v 'none' | sed -E s/'^(.*)$'/'\/\1'/)" && declare kk && echo $(for kk in $(my-seq 2 $(eval $(echo "${bb}" | sed -E s/'[^\/]'//g | sed -E s/'^(.*)$'/'echo '"'"'\1'"'"' \| wc -m; '/) | sort -g | tail -n 1)); do echo '{'; echo "${bb}" | sed -E s/'^\/([^\/]*)\/.*$'/'\/\1'/ | sort -u; echo '}'; bb="$(echo "${bb}" | sed -E s/'^\/[^\/]*\/?(.*)$'/'\/\1'/)"; done) | sed -E s/'\/'// | sed -E s/'\} \{'/'\}\/\{'/g | sed -E s/'\{ '/'\{'/g | sed -E s/' \}'/'\}'/g | sed -E s/' '/','/g | sed -E s/'([^\}])\/'/'\1'/g) | sed -E s/'[\{\}]'//g | sed -zE s/' '/'\n'/g | sed -E s/'^(.*)\/\/.*$'/'\1'/ | my-uniq | sed -E s/'^(.+[^\/])\/?$'/'\[\[ -n "\$\(echo "\$\{bb\}" \| grep -Fx '"'"'\1'"'"'\)" \]\] \&\& echo '"'"'\1'"'"'; '/) | my-uniq)" | sed -E s/'^(.*)$'/'echo "\$\{aa\}" \| grep '"'"'\.\*\1\$'"'"'; '/)" | sed -E s/'^([^ ]*) .*$'/'\1'/
4416
4417}
4418
4419
4420
4421zfsOrderedMount() {
4422 # Implements mounting in the order specified by zfsGetMountingOrder. All ZFS filesystems under the input filesystem will be [u]mounted
4423 #
4424 # If the given name doesnt exist as a dataset/pool name, it will automatically try to import it
4425 # use flag '-u' or '--umount' to instead unmount. This is done in the opposite order as mounting is done in.
4426 #
4427 # syntax: zfsOrderedMount [-u] $(topLevelZFSDatasetName)
4428
4429 local nn
4430
4431 (( $# > 1 )) && echo "$(for nn in ${@}; do zfsOrderedMount "${nn}"; done)" && return
4432
4433 local -a mountOrder
4434 local mountOrder=""
4435 local umountFlag=""
4436
4437 [[ ${1,,} =~ ^-+u(m(ount)?)?$ ]] && umountFlag="u" && shift 1
4438
4439 [[ -n "$(zfs list -H -o name | grep -F "${*}")" ]] || [[ -n "$(zpool list -H -o name | grep -F "${*}")" ]] || zpool import -N "${*}"
4440
4441 sleep 1
4442
4443 zfsGetMountOrder "${@}" | tee >&2 >&1 | mountOrder0="$(cat -)"
4444
4445# mountOrder0="$(zfsGetMountingOrder "${@}")"
4446# /bin/bash -c 'mapfile -t mountOrder < <(echo "${mountOrder0}")'
4447
4448 sleep 1
4449
4450 (( ${#mountOrder[@]} == 0 )) && return
4451
4452 for nn in $( my-seq $( [[ -z "${umountFlag}" ]] && echo '0') $((( ${#mountOrder[@]} - 1 ))) $( [[ -n "${umountFlag}" ]] && echo '-1 0 ') ); do
4453 [[ -n "$(/sbin/zfs get -H -o value mounted "${nn}" | grep -F "$( [[ -n "${umountFlag}" ]] && echo 'yes' || echo 'no')")" ]] || /sbin/zfs ${umountFlag}mount $( [[ -n "${umountFlag}" ]] && echo -n '-f ' || echo -n '-O ' && [[ -n "$(/sbin/zfs get -H -o value keystatus "${mountOrder[$nn]}" 2>/dev/null | grep -xF 'unavailable')" ]] && echo -n '-l ' ) "${mountOrder[$nn]}"
4454 done
4455}
4456
4457
4458my-seq() {
4459
4460 eval echo "{${1}..${2}$( (( $# > 2 )) && echo -n "..${3}")}"
4461}
4462
4463
4464my-wc() {
4465
4466 local -a inAll
4467 local inFlags=""
4468
4469 [[ ${1} =~ ^-[ml]$ ]] && inFlags="${1#-}" && shift 1
4470 [[ ${1} =~ ^-[ml]$ ]] && inFlags="${inFlags}${1#-}" && shift 1
4471
4472 [[ -z "${inFlags}" ]] && inFlags='m'
4473
4474 mapfile -t inAll < <( (( $# == 0 )) && cat <&0 || echo "${*}" )
4475
4476 [[ "${inFlags}" != "${inFlags//m/}" ]] && eval echo "\$((( $(echo "${inAll[*]}" | sed -zE s/'.'/'1'/g | sed -E s/'1'/' 1 + '/g) 0 )))"
4477 [[ "${inFlags}" != "${inFlags//l/}" ]] && eval echo "\$((( $(echo "$(local nn="" && for nn in "${inAll[@]}"; do echo "${nn}"; done)" | sed -E s/'^.*$'/' 1 + '/g | sed -zE s/'\n'//g) 0 )))"
4478}
4479
4480my-tail() {
4481
4482 local nLines
4483 local negFlag
4484 local inAll
4485
4486 [[ "${1}" == "-n" ]] && shift 1
4487 [[ ${1} =~ ^[0-9]+$ ]] && nLines=${1} && negFlag=2
4488 [[ ${1} =~ ^\+[0-9]+$ ]] && nLines=${1#'+'} && negFlag=2
4489 [[ ${1} =~ ^-[0-9]+$ ]] && nLines=${1#'-'} && negFlag=1
4490
4491 (( $# > 0 )) && inAll="${*}" || inAll="$(cat <&0)"
4492
4493 [[ -z "${nLines}" ]] && echo "insufficient input...must provide the number of lines" >&2 && return
4494
4495 echo -n "${inAll}" | sed -zE s/'^(.*)((\n[^\n]*){'"${nLines}"'})$'/'\'"${negFlag}"''/
4496}
4497
4498my-uniq() {
4499 # returns unique elements in a list
4500 # replacement for 'uniq', which is straight broken on my system
4501 # input should be list separated by newlines/spaces/tabs/commas
4502 # output is newline-separated list
4503
4504 local inAll=""
4505 local outAll=""
4506
4507 (( $# > 0 )) && inAll="${*}" || inAll="$(cat <&0)"
4508 inAll="$( echo -n "${inAll}" | sed -zE s/'[\ \,\t]'/'\n'/g | sed -zE s/'\n+'/'\n'/g )"
4509
4510 while [[ -n "${inAll}" ]]; do
4511 outAll="$( echo "${outAll}" && echo "${inAll}" | head -n 1 )"
4512 inAll="$( echo -n "${inAll}" | grep -v -F "$(echo -n "${inAll}" | head -n 1)" )"
4513 done
4514
4515 outAll="$(echo "${outAll}" | grep -E '^.+$')"
4516 echo "${outAll}"
4517}
4518
4519
4520#!/bin/bash
4521
4522zfsMountServiceFEDORA() {
4523
4524 local rootD=""
4525 [[ -n "${root}" ]] && rootD="$(echo "${root}" | sed -E s/'^[Zz][Ff][Ss][\=\:](.*)$'/'\1'/)" || rootD='FEDORA/ROOT'
4526
4527 if [[ -n "$(/sbin/zfs get mounted -H -o value "${rootD}" | grep -v 'yes')" ]]; then
4528 return 0
4529 else
4530 local nn=""
4531 local mm=""
4532 for nn in {'FEDORA/ROOT/VAR','FEDORA/ROOT/USR','FEDORA/ROOT/SRV','FEDORA/ROOT/LOCALREPO','FEDORA/ROOT/HOME','FEDORA/ROOT/BOOT','FEDORA/ROOT/OPT','FEDORA/ROOT/USR_LOCAL','FEDORA/ROOT/MOCK'}; do
4533 if [[ "$(/sbin/zfs get -H -o value mounted "${nn}")" != "yes" ]]; then
4534 mm="$( echo "${nn}" | zfsConvertLegacyMount $( [[ "${nn}" == *'/BOOT' ]] && echo '-p' ) "${rootD}" )"
4535 [[ -n "${mm}" ]] && /sbin/zfs set mountpoint="${mm}" "${nn}"
4536 /sbin/zfs mount "${nn}"
4537 fi
4538 done
4539 fi
4540}
4541
4542zfsImportMount() {
4543
4544 local nn=""
4545 local umountFlag=0
4546 local exportFlag=0
4547 local ALTROOT=""
4548 local altrootFlag=0
4549 local prefixFlag=0
4550 local -a mountDirs
4551 local mountDirs1=""
4552 local -a mountDirs2
4553 local -a mountPools
4554 local numInitialPools=0
4555 local numInitialMapped=0
4556 local kk=0
4557
4558 #[[ -e /dev/mapper/luks-$(cryptsetup luksUUID "/dev/disk/by-id/nvme-Samsung_SSD_970_PRO_1TB_S462NF0K403461K-part2") ]] || clevis luks unlock "/dev/disk/by-id/nvme-Samsung_SSD_970_PRO_1TB_S462NF0K403461K-part2"
4559
4560 kk=0
4561 for nn in "${@}"; do
4562 if [[ ${nn,,} =~ ^-+u(mount)?-?e?(xport)?$ ]]; then
4563 umountFlag=1
4564 [[ ${nn,,} =~ ^-+u(mount)?-?e(xport)?$ ]] && exportFlag=1
4565 elif [[ ${nn^^} =~ ^-+ALTROOT=.*$ ]]; then
4566 ALTROOT="$(echo "${nn##*=}")" # | sed -E s/'^["'"'"']?(.*)["'"'"']?$'/'\1'/)"
4567 altrootFlag=1
4568 echo -e "\nALTROOT set to '${ALTROOT}' \n" >&2
4569 elif [[ ${nn^^} =~ ^-+PREFIX=.*$ ]]; then
4570 PREFIX="$(echo "${nn##*=}")" # | sed -E s/'^["'"'"']?(.*)["'"'"']?$'/'\1'/)"
4571 prefixFlag=1
4572 echo -e "\PREFIX '${PREFIX}' will be appended to the start of all mountpoints \n" >&2
4573 else
4574 mountDirs[$kk]="${nn}"
4575 mountPools[$kk]="${nn%%/*}"
4576 ((kk++))
4577 fi
4578 done
4579
4580 [[ -n "${root}" ]] && ROOT_DATASET="$( echo "${root}" | sed -E s/'^[Zz][Ff][Ss][\=\:](.*)$'/'\1'/ )"
4581
4582 [[ -z "${ROOT_DATASET}" ]] && ROOT_DATASET='FEDORA/ROOT'
4583
4584 export ROOT_DATASET
4585
4586 if ( ( [[ -n "$(findmnt '/')" ]] && [[ "$(findmnt '/' | grep 'zfs' | sed -E s/'^\/[ \t]*([^ \t]*)[ \t].*$'/'\1'/)" != "${ROOT_DATASET}" ]] ) || ( [[ "$(echo "${root}" | sed -E s/'^[Zz][Ff][Ss][\=\:](.*)$'/'\1'/)" != "${ROOT_DATASET}" ]] ) ) && (( $altrootFlag == 0 )) && (( $prefixFlag == 0 )); then
4587 if [[ ! -e "/sysroot" ]] || [[ -z "$(find "/sysroot" -maxdepth 1 | grep -vE '\/sysroot')" ]]; then
4588 ALTROOT='/sysroot'
4589 echo -e "\nALTROOT automatically set to '${ALTROOT}' \n" >&2
4590 else
4591 kk=0
4592 while [[ -e "/sysroot${kk}" ]] && [[ -n "$(find "/sysroot${kk}" -maxdepth 1 | grep -vE '\/sysroot'"${kk}")" ]]; do ((kk++)); done
4593 ALTROOT="/sysroot${kk}"
4594 echo -e "\nALTROOT automatically set to '${ALTROOT}' \n" >&2
4595 fi
4596 fi
4597
4598 mountDirs=("${mountDirsi[@]}")
4599 mountPools=("${mountPools[@]}")
4600
4601 export ALTROOT
4602 export PREFIX
4603
4604 for nn in {'ROOT_DATASET','ALTROOT','altrootFlag','PREFIX','prefixFlag'}; do
4605 echo "${nn}=$(eval echo "\$${nn}")" >&2
4606 done
4607 echo "# ZFS Pools: ${#mountPools[@]} ( ${mountPools[*]} )" >&2
4608 echo "# Datasets: ${#mountDirs[@]} ( ${mountDirs[*]} )" >&2
4609
4610 sleep 2
4611
4612 numInitialPools="$(zpool list -H -o name | wc -l)"
4613 echo "number of initial pools: ${numInitialPools}"
4614
4615 if (( ${umountFlag} == 0 )); then
4616
4617 [[ -e "/etc/zfs/zpool.cache" ]] && rm -rf "/etc/zfs/zpool.cache"
4618
4619 if [[ -z "${mountPools[@]}" ]]; then
4620
4621 echo -ne "\nAttempting to import all available ZFS pools..." >&2
4622
4623 /sbin/zpool import -a -N -o cachefile=none $( (( $altrootFlag == 0 )) && [[ -n "${ALTROOT}" ]] && echo -n '-o altroot='"${ALTROOT}" || echo -n "" )
4624 (( $(zpool list -H -o name | wc -l) <= $numInitialPools )) && /sbin/zpool import -a -N -f -o cachefile=none $( (( $altrootFlag == 0 )) && [[ -n "${ALTROOT}" ]] && echo -n '-o altroot='"${ALTROOT}" || echo -n "" )
4625
4626 if (( $(zpool list -H -o name | wc -l) <= $numInitialPools )); then
4627 numInitialMapped="$(find /dev/mapper -maxdepth 1 -type b | wc -l)"
4628 myLuksOpen
4629
4630 (( $(find /dev/mapper -maxdepth 1 -type b | wc -l) > $numInitialMapped )) || /sbin/zpool import -a -N -o cachefile=none $( (( $altrootFlag == 0 )) && [[ -n "${ALTROOT}" ]] && echo -n '-o altroot='"${ALTROOT}" || echo -n "" ) "${nn}"
4631 (( $(zpool list -H -o name | wc -l) <= $numInitialPools )) && /sbin/zpool import -a -N -f -o cachefile=none $( (( $altrootFlag == 0 )) && [[ -n "${ALTROOT}" ]] && echo -n '-o altroot='"${ALTROOT}" || echo -n "" ) "${nn}"
4632 fi
4633
4634 (( $(zpool list -H -o name | wc -l) > $numInitialPools )) && echo -n "At least 1 ZFS pool was found and imported!" >&2 || echo -n "FAILED TO IMPORT ANY POOLS!" >&2
4635
4636 else
4637
4638 for nn in "${mountPools[@]}"; do
4639 if [[ -z "$(/sbin/zpool list -H -o name | grep "${nn}")" ]]; then
4640
4641 echo -ne "\nAttempting to import pool ${nn}..." >&2
4642
4643 /sbin/zpool import -N -o cachefile=none $( (( $altrootFlag == 0 )) && [[ -n "${ALTROOT}" ]] && echo -n '-o altroot='"${ALTROOT}" || echo -n "" ) "${nn}"
4644 (( $(zpool list -H -o name | wc -l) <= $numInitialPools )) && /sbin/zpool import -N -f -o cachefile=none $( (( $altrootFlag == 0 )) && [[ -n "${ALTROOT}" ]] && echo -n '-o altroot='"${ALTROOT}" || echo -n "" ) "${nn}"
4645
4646 if (( $(zpool list -H -o name | wc -l) <= $numInitialPools )); then
4647 numInitialMapped="$(find /dev/mapper -maxdepth 1 -type b | wc -l)"
4648 myLuksOpen
4649
4650 (( $(find /dev/mapper -maxdepth 1 -type b | wc -l) > $numInitialMapped )) || /sbin/zpool import -N -o cachefile=none $( (( $altrootFlag == 0 )) && [[ -n "${ALTROOT}" ]] && echo -n '-o altroot='"${ALTROOT}" || echo -n "" ) "${nn}"
4651 (( $(zpool list -H -o name | wc -l) <= $numInitialPools )) && /sbin/zpool import -N -f -o cachefile=none $( (( $altrootFlag == 0 )) && [[ -n "${ALTROOT}" ]] && echo -n '-o altroot='"${ALTROOT}" || echo -n "" ) "${nn}"
4652 fi
4653
4654 (( $(zpool list -H -o name | wc -l) > $numInitialPools )) && numInitialPools="$(zpool list -H -o name | wc -l)" && echo -n "Pool imported!" >&2 || echo -n "FAILED TO IMPORT POOL!" >&2
4655
4656 fi
4657 done
4658 fi
4659
4660 mountDirs1="$(for nn in "${mountDirs[@]}"; do
4661 [[ -n "$(zfs list -t filesystem -H -o name "${mountDirs[$kk]}")" ]] && echo "${mountDirs[$kk]}"
4662 done)"
4663 unset mountDirs && local -a mountDirs
4664 echo "${mountDirs1}"
4665 mapfile -t mountDirs < <(echo -n "${mountDirs1}")
4666 mountPools=("${mountPools[@]}")
4667
4668 nameLegacy="$(zfs get -H -o name,value mountpoint ${mountDirs[@]} | grep -E '^FEDORA\/.*legacy$' | sed -E s/'^(.+)\t.+$'/'\1'/)"
4669 mountLegacyNew="$(echo -n "${nameLegacy}" | zfsConvertLegacyMount | grep -E '^.+$')"
4670
4671 if (( $(echo "${nameLegacy}" | wc -l) == $(echo "${mountLegacyNew}" | wc -l) )); then
4672 echo "${nameLegacy}" | while read -r nn; do
4673 zfs set mountpoint="$(echo "${mountLegacyNew}" | head -n 1)" "${nn}"
4674 mountLegacyNew="$(echo "${mountLegacyNew}" | head -n -1)"
4675 done
4676 fi
4677
4678 mountDirs2=($( ( ( [[ -n "${mountDirs[@]}" ]] && zfsFindMountOrder "${mountDirs[@]}" ) || ( [[ -n "$(/sbin/zpool list -H -o name)" ]] && zfsFindMountOrder $(/sbin/zpool list -H -o name) ) || echo "" ) | while read -r nn; do [[ -n "${nn}" ]] && echo "$nn"; done ) )
4679
4680 [[ -z "${mountDirs2[@]}" ]] && return
4681
4682 for nn in "${mountDirs2[@]}"; do
4683
4684 if zfsIsEncrypted "${nn}" && ( ( [[ "$(/sbin/zfs get -H -o value keylocation "${nn}")" != "prompt" ]] && [[ "$(/sbin/zfs get -H -o value encryptionroot "${nn}")" == "${nn}" ]] ) || ( [[ "$(/sbin/zfs get -H -o value keylocation "${nn}")" == "prompt" ]] && ( [[ "${nn}" == "${nn%%/*}" ]] || ( [[ -n "${root}" ]] && [[ "${nn}" == "${root#ZFS=}" ]] ) ) ) || [[ "${nn}" == "${ROOT_DATASET}" ]] ); then
4685
4686 echo "Attempting to load key for '${nn}'..." >&2
4687 /sbin/zfs load-key "${nn}" && echo "key loaded!" >&2 || echo "KEY WAS NOT LOADED" >&2
4688 fi
4689
4690 [[ -n "${PREFIX}" ]] && [[ "$(/sbin/zfs get -H -o value mountpoint "${nn}")" != ${PREFIX}* ]] && sbin/zfs set mountpoint="${PREFIX%/}$(/sbin/zfs get -H -o value mountpoint "${nn}")" "${nn}"
4691
4692 if [[ "$(/sbin/zfs get -H -o value mounted "${nn}")" != "yes" ]] || ! zfsIsEncrypted "${nn}"; then
4693
4694 /sbin/zfs mount "${nn}" && echo "Dataset '${nn}' mounted!" >&2 || echo "DATASET '${nn}' FAILED TO MOUNT!" >&2
4695 fi
4696 done
4697
4698 else
4699
4700 [[ -z "${mountDirs[@]}" ]] && mountDirs=($(/sbin/zpool list -H -o name))
4701
4702 if [[ -n "$(findmnt '/' | grep zfs)" ]]; then
4703 rootPool="$(fintmnt '/' | sed -E s/'^\/ ([^ ]*)/*$'/'\1'/)"
4704 mountDirs=("$(for nn in "${mountDirs[@]}"; do echo "${nn}" | sed -E s/'^'"${rootPool}"'(\/.+)?$'//; done)")
4705 mountPools="${mountPools//"${rootPool}"/}"
4706 fi
4707
4708 [[ -n "${mountDirs[@]}" ]] && while read -r nn; do
4709 if [[ "$(/sbin/zfs get -H -o value mounted "${nn}")" != "no" ]]; then
4710 /sbin/zfs umount -f "${nn}" && echo "Dataset '${nn}' unmounted!" >&2 || echo "DATASET '${nn}' FAILED TO UNMOUNT!" >&2;
4711 fi;
4712 done < <(zfsFindMountOrder -u "${mountDirs[@]}")
4713
4714 if (( $exportFlag == 1 )); then
4715 if [[ -z "${mountPools[@]}" ]]; then
4716 /sbin/zpool export -a && echo "All pools exported!" >&2 || echo "ONE OR MORE POOLS FAILED TO EXPORT!" >&2;
4717 else
4718 for nn in "${mountPools[@]}"; do
4719 /sbin/zpool export "${nn}" && echo "Pool '${nn}' exported!" >&2 || echo "POOL '${nn}' FAILED TO EXPORT!" >&2;
4720 done
4721 fi
4722 fi
4723
4724 fi
4725
4726 unset ROOT_DATASET
4727 unset ALTROOT
4728 unset PREFIX
4729
4730}
4731
4732zfsFindMountOrder() {
4733
4734 local zfsList=""
4735 local zfsMount=""
4736 local zfsMount0=""
4737 local zfsMount1=""
4738 local zfsMountOrder=""
4739 local ROOT_DATASET=""
4740 local -a zfsMountSplitU
4741 local kk=0
4742 local nn=""
4743 local umountFlag=""
4744
4745 [[ "${*,,}" =~ ^(.+\ )?-+u(mount)?(\ .+)?$ ]] && umountFlag='-u'
4746
4747 if (( $# > ( ${#umountFlag} / 2 ) )); then
4748 ROOT_DATASET="$( zfsFindCommonRoot "$( for nn in "${@}"; do [[ "${nn,,}" =~ ^-+u(mount)?$ ]] || echo "${nn}"; done )" )"
4749 elif [ -n "${root}" ]]; then
4750 ROOT_DATASET="$( echo "${root}" | sed -E s/'^[Zz][Ff][Ss][\=\:]'// )"
4751 fi
4752 #echo "ROOT_DATASET: $ROOT_DATASET"
4753
4754 [[ ! -t 0 ]] && echo "stdin detected" >&2 && ROOT_DATASET="$(echo "$(echo "${ROOT_DATASET}"; cat <&0)")"
4755
4756 [[ -z "${ROOT_DATASET}" ]] && ROOT_DATASET="$(/sbin/zpool list -H -o name)"
4757
4758 [[ -n "${ROOT_DATASET}" ]] && ROOT_DATASET="$(echo "$(zfs list -H -o name -r ${ROOT_DATASET} -t filesystem)" | while read -r nn; do [[ "$(/sbin/zfs get -H -o value canmount "${nn}")" == "on" ]] && echo "${nn}"; done)"
4759
4760 [[ -z "${ROOT_DATASET}" ]] && return
4761 #echo "ROOT_DATASET: $ROOT_DATASET"
4762
4763 zfsList="$( /sbin/zfs get -H -o name,value mountpoint ${ROOT_DATASET} | grep -vE '(none$|legacy$)')"
4764 zfsMount="$( /sbin/zfs get -H -o value mountpoint ${ROOT_DATASET} | grep -vE '(none$|legacy$)' ; echo "$(/sbin/zfs get -H -o name,value mountpoint ${ROOT_DATASET} | grep -E 'legacy$' | sed -E s/'^(.*)\tlegacy$'/'\1'/)" | zfsConvertLegacyMount)"
4765 zfsMount0="${zfsMount}"
4766
4767 #echo "zfsList: ${zfsList}"
4768 echo "zfsMount: ${zfsMount}"
4769
4770 #kk=0
4771 while [[ -n "${zfsMount0}" ]]; do
4772 zfsMountSplitU+="$( echo "${zfsMount0}" | sed -E s/'^(\/[^\/]*)\/?.*$'/'\1'/ | grep -vE '(none$|legacy$)' | sort -u )"
4773 #((kk++))
4774 #echo "kk=$kk: ${zfsMountSplitU[@]}"
4775
4776 zfsMount0="$( echo "${zfsMount0}" | sed -E s/'^\/[^\/]*(\/?.*)$'/'\1'/ | grep -vE '(none$|legacy$)' | grep -E '^[^\ \t]+$' )"
4777 echo "zfsMount0: ${zfsMount0}"
4778 done
4779
4780 zfsMount1="$( echo "${zfsMount}" | while read -r nn; do kk=0; echo -n "${nn}"; for kk in $( myseq 0 $((( ${#zfsMountSplitU[@]} - $( echo "${nn}" | sed -E s/'[^\/]'//g | wc -m ) ))) ); do echo -n '/.'; done; echo -ne "\n"; done )"
4781 #echo "zfsMount1: ${zfsMount1}"
4782
4783
4784 while [[ -n "${zfsMount1}" ]]; do
4785 zfsMountOrder="$( cat <( echo "${zfsMount1}" | grep -vE '\/\.$' ) <( echo "${zfsMountOrder}" ) )"
4786 zfsMount1="$( echo "${zfsMount1}" | grep -E '\/\.$' | sed -E s/'^(.*)\/\.$'/'\1'/ )"
4787 done
4788
4789 zfsMountOrder="$(echo "${zfsMountOrder}" | grep -E '^.+$' | while read -r nn; do echo "${zfsList}" | grep -E "${nn//\//\\\/}"'$' | sed -E s/'^([^\t]*)\t.*$'/'\1'/; done)"
4790
4791 if [[ "${umountFlag}" == '-u' ]]; then
4792 echo "${zfsMountOrder}" | zfsFlipInput
4793 else
4794 echo "${zfsMountOrder}"
4795 fi
4796}
4797
4798zfsConvertLegacyMount() {
4799
4800 local inAll=""
4801 local commonRoot=""
4802 local commonMount=""
4803 local nn=""
4804 local preserveCaseFlag=0
4805
4806 [[ "${*,,}" =~ ^(.+\ )?-+p((reserve)?-?(c(ase)?)?)?(\ .+)?$ ]] && preserveCaseFlag=1
4807
4808 inAll="$(for nn in "${@}"; do [[ "${nn,,}" =~ ^-+p((reserve)?-?(c(ase)?)?)?$ ]] || echo "${nn}"; done)"
4809
4810 if [[ ! -t 0 ]]; then
4811 if (( "$( echo "${inAll}" | wc -l)" == 1 )); then
4812 commonRoot="${inAll}"
4813 inAll="$(cat <&0)"
4814 else
4815 inAll="$(echo "$(cat <&0; echo "${inAll}")")"
4816 fi
4817 fi
4818
4819 [[ -z "${inAll}" ]] && return 1
4820
4821 [[ -z "${commonRoot}" ]] && commonRoot="$(echo "${inAll}" | zfsFindCommonRoot)"
4822
4823 [[ -z "${commonRoot}" ]] && return 2
4824
4825 commonMount="$(/sbin/zfs get -H -o value mountpoint "${commonRoot}")"
4826
4827 [[ -z "${commonMount}" ]] && return 4
4828
4829 while [[ "${commonMount}" == "legacy" ]]; do
4830 commonRoot="${commonRoot%/*}"
4831 [[ -z "${commonRoot}" ]] && break
4832 commonMount="$(/sbin/zfs get -H -o value mountpoint "${commonRoot}")"
4833 done
4834
4835 ( [[ -z "${commonMount}" ]] || [[ "${commonMount}" == "legacy" ]] ) && return 8
4836
4837 (( $preserveCaseFlag == 0 )) && inAll="${inAll,,}" && commonRoot="${commonRoot,,}";
4838 inAll="${inAll//usr_local/usr\/local}";
4839 inAll="${inAll//mock/var\/lib\/mock}";
4840 inAll="${inAll//"${commonRoot}"/"${commonMount}"}";
4841
4842 [[ -n "${ALTROOT}" ]] && inAll="${inAll##"${ALTROOT}"}"
4843 [[ -n "${PREFIX}" ]] && [[ "${inAll}" != "${inAll##"${PREFIX}"}" ]] && inAll="${PREFIX%/}/${inAll#/}"
4844
4845 echo "$inAll"
4846}
4847
4848zfsFindCommonRoot() {
4849
4850 local inAll=""
4851 local inTemp=""
4852 local nn=""
4853
4854 inAll="$(for nn in "${@}"; do echo "${nn}"; done)"
4855 [[ ! -t 0 ]] && inAll="$(echo "$(cat <&0; "${inAll}")")"
4856
4857 while (( 1 == 1 )) && [[ -n "${inAll}" ]]; do
4858 inTemp="$(echo "${inAll}" | sed -E s/'^(\/?[^\/]+)(\/.*)?$'/'\1'/ | sort -u)"
4859 (( $(echo "${inTemp}" | wc -l) == 1 )) && echo -n "${inTemp}" || break
4860 inAll="${inAll//"${inTemp}"/}"
4861 done
4862
4863}
4864
4865zfsFlipInput() {
4866 local -a inAll
4867 local nn=""
4868 local mm=""
4869 kk=0
4870
4871 (( $# > 0 )) && inAll=("${@}") || inAll[0]="$(cat <&0)"
4872
4873 for nn in "${inAll[@]}"; do
4874 kk=0
4875 echo -n "${nn}" | grep -E '^.+$' | while read -r mm; do echo "${kk} ${mm}" && ((kk++)); done | sort -nr | sed -E s/'^[0-9]* (.*)$'/'\1'/
4876 done
4877}
4878
4879zfsIsEncrypted() {
4880 [[ "$(/sbin/zfs get -H -o value mounted "${*}")" != "yes" ]] && [[ -n "$(/sbin/zpool get all -H "${*%%/*}" | grep 'feature@encryption')" ]] && [[ "$(/sbin/zpool get feature@encryption -H -o value "${*%%/*}")" == 'active' ]] && [[ "$(/sbin/zfs get keystatus -H -o value "${*}")" == 'unavailable' ]] && return 0 || return 1
4881}
4882
4883
4884myseq() {
4885 (( $# == 1)) && echo "${1}" && return
4886 (( $# == 2 )) && eval echo '{'"${1}"'..'"${2}"'}' | sed -zE s/' '/'\n'/g && return
4887 eval echo '{'"${1}"'..'"${3}"'..'"${2}"'}'| sed -zE s/' '/'\n'/g
4888}
4889
4890mytee() {
4891 [ -t 0 ] && return
4892
4893 local inA="$(cat <&0)"
4894 local kk=0
4895 local aStr=""
4896
4897 echo "${inA}" >&2
4898 echo "${inA}" ;
4899
4900 [[ "${1}" == '-a' ]] && aStr='>' && shift 1
4901
4902 for kk in $( myseq 1 $# ); do
4903 eval echo '"${inA}" >'"${aStr} \$${kk}"
4904 done
4905}
4906
4907
4908myLuksOpen() {
4909 # Searches for luks devices and prompts you to decrypt any found via a password prompt.
4910 # Accepts globs, and by default does "fuzzy" matching (i.e., adds globs to either end of the input).
4911 # This is done progressively and stopped once a match is found to avoid unintentional matches.
4912 # If any inputs are directories, they will be resursively searched for block devices contained within.
4913 # To make this also check stdin, set the 1st input as '-si' or '--std-in'
4914 # You will be prompted for a password on any matching LUKS device. Already decrypted devices are skipped.
4915 # If a input is given, ANY device within the /dev subsystem with a matching (partial) name will be checked for LUKS.
4916 # If no input is given, ALL devices and '/dev' will be queried.
4917
4918 # SET LOCAL VARIABLES
4919 local -a cryptDev0
4920 local -a cryptDev
4921 local cryptDevTemp=""
4922 local nn=""
4923 local mm=""
4924
4925 # PARSE INPUTS
4926 # If no input then search all of '/dev' for LUKS devices
4927 if (( $# >= 1 )) && [[ ${1,,} =~ ^-+s(td)?-?in?$ ]]; then
4928 shift 1
4929 mapfile -t cryptDev0 < <(echo "$(cat <&0)"; echo "${*}")
4930 else
4931 (( $# > 0 )) && cryptDev0=("${@}")
4932 fi
4933 (( ${#cryptDev0[@]} == 0 )) && cryptDev0=('/dev')
4934
4935 # SEARCH FOR MATCHING BLOCK DEVICES USING "FUZZY" SEARCHING
4936 cryptDevTemp="$( for nn in "${cryptDev0[@]}"; do
4937 if [[ -e "${nn}" ]]; then
4938 echo "${nn}"
4939 else
4940 echo "$(find /dev -wholename "${nn}")" | read -r mm && [[ -n "${mm}" ]] && echo "${mm}" && continue
4941 echo "$(find /dev -wholename "${nn}*")" | read -r mm && [[ -n "${mm}" ]] && echo "${mm}" && continue
4942 echo "$(find /dev -wholename "*${nn}")" | read -r mm && [[ -n "${mm}" ]] && echo "${mm}" && continue
4943 echo "$(find /dev -wholename "*${nn}*")" | read -r mm && [[ -n "${mm}" ]] && echo "${mm}" && continue
4944 echo "$(find /dev -wholename "**/${nn}*")" | read -r mm && [[ -n "${mm}" ]] && echo "${mm}" && continue
4945 echo "$(find /dev -wholename "**/*${nn}")" | read -r mm && [[ -n "${mm}" ]] && echo "${mm}" && continue
4946 echo "$(find /dev -wholename "**/*${nn}*")"
4947 fi
4948 done | grep -E '^.+$' )"
4949
4950 # SEARCH FOR ALL BLOCK DEVICES WITHIN ANY DIRECTORIES PASSED AS INPUT
4951 [[ -n "${cryptDevTemp}" ]] && cryptDevTemp="$(echo "${cryptDevTemp}" | while read -r nn; do [[ -d "${cryptDevTemp}" ]] && echo "$(find "${nn}" -type b)" || echo "${nn}"; done | grep -vE '^\/dev\/?$' | sort -u)"
4952
4953 # REMOVE DEVICES THAT ARENT LUKS
4954 [[ -n "${cryptDevTemp}" ]] && cryptDevTemp="$(echo "${cryptDevTemp}" | while read -r nn; do cryptsetup isLuks "${nn}" && echo "${nn}"; done)"
4955
4956 # EARLY EXIT IF NO MATCHES
4957 [[ -z "${cryptDevTemp}" ]] && echo "No [locked] LUKS devices found" >&2 && return
4958
4959 # LOOP THROUGH MATCHES AND TRY TO DECRYPT EACH ONE
4960 mapfile -t cryptDev < <(echo "${cryptDevTemp}")
4961 for nn in "${cryptDev[@]}"; do
4962 ( [[ -n "${nn}" ]] && cryptsetup isLuks "${nn}" && [[ ! -e "/dev/mapper/luks-$(cryptsetup luksUUID "${nn}")" ]] ) || continue
4963
4964 echo -en "\nNow attempting to decrypt ${nn}... \n" >&2
4965 ( [[ -e "/bin/clevis-luks-unlock" ]] && clevis luks unlock -d "${nn}" ) || cryptsetup open "${nn}" "luks-$(cryptsetup luksUUID "${nn}")"
4966 done
4967}
4968
4969
4970
4971
4972lineLengthSort() {
4973
4974 local -a inStr
4975 local nn=""
4976
4977 (( $# > 0 )) && inStr=("${@}") || inStr[0]="$(cat <&0)"
4978
4979 for nn in "${inStr[@]}"; do
4980 eval $(echo -n "${nn}" | sed -E s/'^(.*)$'/'echo -n '"'"'\1'"'"' | wc -m | sed -zE s\/'"'"'\\n\$'"'"'\/\/ \&\& echo '"'"' \1'"'"'\; '/) | sort -g | sed -E s/'^[0-9]+ (.*)$'/'\1'/
4981 done
4982}