diff options
Diffstat (limited to 'src/cpt-lib.in')
-rw-r--r-- | src/cpt-lib.in | 287 |
1 files changed, 174 insertions, 113 deletions
diff --git a/src/cpt-lib.in b/src/cpt-lib.in index d6fa0a4..328149e 100644 --- a/src/cpt-lib.in +++ b/src/cpt-lib.in @@ -892,11 +892,19 @@ pkg_strip() { done 2>/dev/null ||: } +pkg_fix_deps_fullpath() { + # Return the canonical path of libraries extracted by readelf. + while read -r dep _ rslv _; do + [ "$dep" = "$1" ] || continue + printf '%s\n' "$rslv" + done +} + pkg_fix_deps() { # Dynamically look for missing runtime dependencies by checking each binary # and library with either 'ldd' or 'readelf'. This catches any extra # libraries and or dependencies pulled in by the package's build suite. - log "$1" "Checking for missing dependencies" + log "$1" "Checking for missing dependencies (using ${elf_prog##*/})" # Go to the directory containing the built package to # simplify path building. @@ -921,9 +929,15 @@ pkg_fix_deps() { find "$pkg_dir/$pkg_name/" -type f 2>/dev/null | while read -r file; do + # We call ldd regardless here, because we also use it to retrieve the + # fullpath of a library when using readelf. Best use we have here is + # saving it in a buffer, so we don't use the dynamic loader everytime we + # need to reference it. + lddbuf=$(ldd -- "$file" 2>/dev/null) ||: + case ${elf_prog:-ldd} in *readelf) "$elf_prog" -d "$file" 2>/dev/null ;; - *) ldd "$file" 2>/dev/null ;; + *) pirntf '%s\n' "$lddbuf" ;; esac | while read -r dep; do # Skip lines containing 'ldd'. @@ -935,6 +949,12 @@ pkg_fix_deps() { dep=${dep##*\[} dep=${dep%%\]*} + # Retrieve the fullpath of the library from our ldd buffer. + case $elf_prog in + *readelf) line=$(printf '%s\n' "$lddbuf" | + pkg_fix_deps_fullpath "$line") + esac + # ldd output: # libc.so => /lib/ld-musl-x86_64.so.1 dep=${dep#* => } @@ -1653,138 +1673,179 @@ pkg_install() { log "$pkg_name" "Installed successfully" } -pkg_fetch() { - log "Updating repositories" - - run_hook pre-fetch +pkg_vcs_pull_fossil() { + # Pull function for Fossil. + [ "$(fossil remote 2>/dev/null)" != off ] || { + log "$repo" " " + printf '%s\n' "No remote, skipping." + return 0 + } - # Create a list of all repositories. - # See [1] at top of script. - # shellcheck disable=2046,2086 - { IFS=:; set -- $CPT_PATH; IFS=$old_ifs ;} + # Ensure we have proper permissions to do the pull operation. + if [ -w "$PWD" ] && [ "$uid" != 0 ]; then + fossil update + else + pkg_vcs_as_root "fossil update" + fi +} - # Update each repository in '$CPT_PATH'. It is assumed that - # each repository is 'git' tracked. - for repo; do - # Go to the root of the repository (if it exists). - cd "$repo" - cd "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || - cd "$(hg root 2>/dev/null)" 2>/dev/null ||: +pkg_vcs_pull_git() { + # Pull function for Git. + [ "$(git remote 2>/dev/null)" ] || { + log "$repo" " " + printf '%s\n' "No remote, skipping." + return 0 + } - if [ -d .git ]; then + # Display a message if signing is enabled for this repository. + case $(git config merge.verifySignatures) in + true) log "$PWD" "[signed] " ;; + *) log "$PWD" " " ;; + esac - [ "$(git remote 2>/dev/null)" ] || { - log "$repo" " " - printf '%s\n' "No remote, skipping." - continue - } + # Ensure we have proper permissions to do the pull operation. + if [ -w "$PWD" ] && [ "$uid" != 0 ]; then + git fetch + git merge + git submodule update --remote --init -f + else + pkg_vcs_as_root \ + "git fetch && git merge && git submodule update --remote --init -f" + fi +} - contains "$repos" "$PWD" || { - repos="$repos $PWD " +pkg_vcs_pull_hg() { + # Pull function for Mercurial. + [ "$(hg showconfig paths 2>/dev/null)" ] || { + log "$repo" " " + printf '%s\n' "No remote, skipping." + return 0 + } - # Display a tick if signing is enabled for this - # repository. - case $(git config merge.verifySignatures) in - true) log "$PWD" "[signed] " ;; - *) log "$PWD" " " ;; - esac + if [ -w "$PWD" ] && [ "$uid" != 0 ]; then + hg pull + hg update + else + pkg_vcs_as_root "hg pull && hg update" + fi +} - if [ -w "$PWD" ] && [ "$uid" != 0 ]; then - git fetch - git merge - git submodule update --remote --init -f +pkg_vcs_pull_rsync() { + # Pull function for rsync repositories. The details of our rsync + # repositories are explained in the user manual. - else - [ "$uid" = 0 ] || log "$PWD" "Need root to update" - - # Find out the owner of the repository and spawn - # git as this user below. - # - # This prevents 'git' from changing the original - # ownership of files and directories in the rare - # case that the repository is owned by a 3rd user. - ( - user=$(_stat "$PWD") + # Read remote repository address from the '.rsync' file. + read -r remote < .rsync + if [ -w "$PWD" ] && [ "$uid" != 0 ]; then + rsync -acvzzC --include=core --delete "$remote/" "$PWD" + else + pkg_vcs_as_root "rsync -acvzzC --include=core --delete \"$remote/\" \"$PWD\"" + fi +} - [ "$user" = root ] || - log "Dropping permissions to $user for pull" +pkg_vcs_pull_local() { + # Local repository. We don't do a "pull" here, we just notify the user that + # this is the case. + log "$repo" " " + printf '%s\n' "Not a remote repository, skipping." +} - git_cmd="git fetch && git merge && git submodule update --remote --init -f" - case $su in *su) git_cmd="'$git_cmd'"; esac +pkg_vcs_as_root() ( + # Helper function for pkg_vcs_pull* functions used for proper + # privilege escalation. + [ "$uid" = 0 ] || log "$PWD" "Need root to update" - # Spawn a subshell to run multiple commands as - # root at once. This makes things easier on users - # who aren't using persist/timestamps for auth - # caching. - user=$user as_root sh -c "$git_cmd" - ) - fi - } - elif [ -d .hg ]; then + # Find out the owner of the repository and spawn the operation as the user + # below. + # + # This prevents the VCS from changing the original ownership of files and + # directories in the rare case that the repository is owned by a third user. + user=$(_stat "$PWD") - [ "$(hg showconfig paths 2>/dev/null)" ] || { - log "$repo" " " - printf '%s\n' "No remote, skipping." - continue - } + [ "$user" = root ] || log "Dropping permissions to $user for pull" + case ${su##*/} in su) set -- "'$1'"; esac - contains "$repos $PWD" || { - repos="$repos $PWD" + # Spawn a subhsell to run multiple commands as root at once. This makes + # things easier on users who aren't using persist/timestamps for auth + # caching. + as_root sh -c "$@" +) - if [ -w "$PWD" ] && [ "$uid" != 0 ]; then - hg pull - hg update - else - [ "$uid" ] || log "$PWD" "Need root to update" +pkg_vcs_info() { + # Finds and returns repository information for the current directory. It + # will return current directory, repository root, and the type of repository + # in a colon separated format. - # We are going to do the same operation as above, to - # find the owner of the repository. - ( - user=$(_stat "$PWD") + : "${repo_file:=$cac_dir/repository-cache}" + set -- - [ "$user" = root ] || - log "Dropping permissions to $user for pull" + if [ "$CPT_REPO_CACHE" != 0 ] && information=$(grep "^$PWD:" "$repo_file" 2>/dev/null); then + # Repository information is already cached. + printf '%s\n' "$information" | sed 1q + return + elif rootdir=$(git rev-parse --show-toplevel 2>/dev/null); then + # Git repository + backend=git + elif rootdir=$(hg root 2>/dev/null); then + # Mercurial repository + backend=hg + elif rootdir=$(fossil info 2>/dev/null | grep ^local-root:); then + # Fossil repository + backend=fossil + + # We want to remove the initial spacing before the root directory, and + # the leading dash on the root directory. + rootdir=$(printf '%s\n' "$rootdir" | cut -d ' ' -f2-) + rootdir=${rootdir%/} + elif [ -f .rsync ]; then + backend=rsync + rootdir=$PWD + + # If an .rsync_root file exists, we check that the repository root + # exists. If it does, we change to that directory to do the fetch. + # This way, we allow for partial repositories while making sure that + # we can fetch the repository in a single operation. + [ -f .rsync_root ] && { + read -r rsync_root < .rsync_root + [ -f "$rsync_root/.rsync" ] && rootdir=$(_readlinkf "$rsync_root") + } + else + # Local repository + backend=local + rootdir=$PWD + fi - hg_cmd="hg pull && hg update" + # We cache all these information, so that we don't have to spend much time + # looking these up the next time we are doing it. If CPT_REPO_CACHE is set + # to 0, we will not write this cache. + [ "$CPT_REPO_CACHE" = 0 ] || set -- "$repo_file" + printf '%s:%s:%s\n' "$PWD" "$rootdir" "$backend" | tee -a "$@" +} - case $su in *su) hg_cmd="'$hg_cmd'"; esac - user=$user as_root sh -c "$hg_cmd" - ) - fi - } - elif [ -f .rsync ]; then - # If an .rsync_root file exists, we check that the repository root - # exists. If it does, we change to that directory to do the fetch. - # This way, we allow for partial repositories while making sure that - # we can fetch the repository in a single operation. - [ -f .rsync_root ] && { - read -r rsync_root < .rsync_root - [ -f "$rsync_root/.rsync" ] && cd "$rsync_root" - } - contains "$repos" "$PWD" || { - repos="$repos $PWD" - read -r remote < .rsync - if [ -w "$PWD" ] && [ "$uid" != 0 ]; then - rsync -acvzzC --include=core --delete "$remote/" "$PWD" - else - [ "$uid" = 0 ] || log "$PWD" "Need root to update" +pkg_fetch() { + log "Updating repositories" - # Similar to the git update, we find the owner of - # the repository and spawn rsync as that user. - ( - user=$(_stat "$PWD") + run_hook pre-fetch - [ "$user" = root ] || - log "Dropping permissions to $user for pull" + # Create a list of all repositories. + # See [1] at top of script. + # shellcheck disable=2046,2086 + { IFS=:; set -- $CPT_PATH; IFS=$old_ifs ;} - user=$user as_root rsync -acvzzC --include=core --delete "$remote/" "$PWD" - ) - fi - } - else - log "$repo" " " - printf '%s\n' "Not a remote repository, skipping." - fi + # Update each repository in '$CPT_PATH'. It is assumed that + # each repository is 'git' tracked. + for repo; do + # Go to the root of the repository. + cd "$repo" + repo_type=$(pkg_vcs_info) + repo_root=${repo_type#$PWD:} + repo_type=${repo_type##*:} repo_root=${repo_root%:*} + contains "$repos" "$repo_root" || { + repos="$repos $repo_root " + cd "$repo_root" + + "pkg_vcs_pull_$repo_type" + } done run_hook post-fetch |