├── .gitattributes ├── .github └── FUNDING.yml ├── .mailmap ├── README.md ├── functions ├── index_vars ├── README.txt ├── macosx_10_i386 ├── macosx_11_i386 ├── macosx_12_i386 ├── macosx_13_i386 ├── macosx_14_i386 ├── macosx_15_i386 ├── macosx_16_i386 ├── macosx_17_i386 ├── macosx_18_i386 ├── macosx_19_i386 ├── macosx_20_arm ├── macosx_20_i386 ├── macosx_21_arm ├── macosx_21_i386 ├── macosx_22_arm ├── macosx_22_i386 ├── macosx_23_arm ├── macosx_23_i386 ├── macosx_24_arm ├── macosx_24_i386 ├── macosx_9_i386 └── macosx_9_powerpc ├── mpbb ├── mpbb-checkout ├── mpbb-cleanup ├── mpbb-gather-archives ├── mpbb-help ├── mpbb-install-dependencies ├── mpbb-install-port ├── mpbb-list-subports ├── mpbb-mirror-distfiles ├── mpbb-print-info ├── mpbb-selfupdate ├── mpbb-show-config-logs ├── mpbb-test-port └── tools ├── archive-path.tcl ├── canonical-variants.tcl ├── dependencies.tcl ├── failcache-cleanup.tcl ├── failcache.tcl ├── gather-archives.tcl ├── mirror-multi.tcl ├── mirrordb.tcl ├── noisy-delete.tcl ├── portgroups.tcl ├── reclaim-space.tcl ├── sort-with-subports.tcl ├── supported-archs.tcl ├── uninstall-unneeded-ports.tcl ├── update-mirrordb.tcl └── wait-for-mirror.tcl /.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize EOLs by default, to avoid falling back on committers' 2 | # "core.autocrlf" settings. 3 | * text=auto 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | open_collective: macports 2 | github: macports 3 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MacPorts Buildbot Scripts # 2 | 3 | This is a collection of scripts that will be run by the MacPorts 4 | Project's Buildbot buildslaves for continuous integration and 5 | precompilation of binary archives. 6 | 7 | 8 | ## General Structure ## 9 | 10 | The `mpbb` ("MacPorts Buildbot") driver script defines a subcommand for 11 | each step of a build. These subcommands are implemented as separate 12 | scripts named `mpbb-SUBCOMMAND`, but they are not intended to be 13 | standalone programs and should not be executed as such. Build steps 14 | should only be run using the `mpbb` driver. 15 | 16 | The defined build steps are: 17 | 18 | 1. Update base without updating the portindex. 19 | 20 | mpbb --prefix /opt/local selfupdate 21 | 22 | 2. Checkout ports tree and update the portindex. 23 | 24 | mpbb --prefix /opt/local --work-dir /tmp/scratch \ 25 | checkout \ 26 | [--ports-url https://github.com/macports/macports-ports.git] \ 27 | [--ports-commit 40c3ce0a26abc0d778754ecde9660bead94a2ffd] 28 | 29 | 3. Print one or more ports' subports to standard output. 30 | 31 | mpbb --prefix /opt/local list-subports php cmake llvm-3.8 [...] 32 | 33 | 4. For each subport listed in step 3: 34 | 35 | a. Install dependencies. 36 | 37 | mpbb --prefix /opt/local install-dependencies php71 38 | 39 | b. Install the subport itself. 40 | 41 | mpbb --prefix /opt/local install-port php71 42 | 43 | c. Gather archives. 44 | 45 | mpbb --prefix /opt/local --work-dir /tmp/scratch \ 46 | gather-archives \ 47 | --archive-site https://packages.macports.org \ 48 | --staging-dir /tmp/scratch/staging 49 | 50 | d. Upload. Must be implemented in the buildmaster. 51 | 52 | e. Deploy. Must be implemented in the buildmaster. 53 | 54 | f. Clean up. This must always be run, even if a previous step 55 | failed. 56 | 57 | mpbb --prefix /opt/local cleanup 58 | 59 | 60 | ## Subcommand API ## 61 | 62 | Subcommand scripts are sourced by the `mpbb` driver. A script named 63 | `mpbb-SUBCOMMAND` must define these two shell functions: 64 | 65 | - `SUBCOMMAND()`: 66 | Perform the subcommand's work and return zero on success and 67 | nonzero on failure. 68 | - `SUBCOMMAND-usage()`: 69 | Print to standard out a usage summary, a description of the 70 | subcommand's purpose, and the subcommand's options, but do not 71 | `exit`. The output is passed through `fmt(1)`, so single newlines 72 | are not preserved. 73 | 74 | Scripts may define additional functions as desired. For example, the 75 | `mpbb-list-subports` script defines the required `list-subports` and 76 | `list-subports-usage` functions, as well as a `print-subports` helper. 77 | 78 | Subcommand scripts may use but not modify these global shell parameters: 79 | 80 | - `$command`: 81 | The name of the subcommand. 82 | - `$option_prefix`: 83 | The prefix of the MacPorts installation. 84 | - `$option_jobs_dir`: 85 | The path to a local copy of the 86 | [jobs tools](https://github.com/macports/macports-infrastructure/tree/master/jobs). 87 | - `$option_log_dir`: 88 | A directory for storing build logs. 89 | - `$option_work_dir`: 90 | A directory for storing temporary data. It is guaranteed to 91 | persist for the duration of an `mpbb` run, so it may be used to 92 | share ancillary files (e.g., a Subversion checkout of the ports 93 | tree) between builds of different ports. 94 | - `$option_failcache_dir`: 95 | A directory for storing information about previously failed builds which 96 | saves time because builds that are known to fail will not be attempted. 97 | - `$option_license_db_dir`: 98 | A directory for storing information about port licenses used by the 99 | port_binary_distributable.tcl script. 100 | 101 | 102 | ## Runtime Requirements ## 103 | 104 | - `mpbb` is written in [bash](https://www.gnu.org/software/bash) and 105 | is known to be compatible with 3.2.17 through 3.2.57. 106 | - Library functions 107 | - `compute_failcache_hash` requires an 108 | [OpenSSL](https://www.openssl.org) that can generate SHA256 digests. 109 | - `parseopt` requires [Frodo Looijaard's enhanced 110 | `getopt(1)`](http://frodo.looijaard.name/project/getopt), 111 | which is available from the `getopt` port. 112 | - Subcommands 113 | - Any subcommand involving ports requires MacPorts, obviously. 114 | - `mpbb checkout` requires one or both of the 115 | [Git](https://git-scm.com) and 116 | [Subversion](http://subversion.apache.org) clients. 117 | - `mpbb help` requires 118 | [`fmt(1)`](https://en.wikipedia.org/wiki/Fmt_(Unix)). 119 | - `mpbb gather-archives` requires [curl](https://curl.haxx.se). 120 | - `mpbb selfupdate` requires Make. 121 | 122 | ## Development Setup ## 123 | 124 | For development of `mpbb`, we recommend the following setup: 125 | 126 | - Install a separate copy of MacPorts, e.g. in `/opt/mports`. See 127 | [Install Multiple MacPorts Copies](https://guide.macports.org/#installing.macports.source.multiple). 128 | It is not recommended to use your normal copy of MacPorts, since `mpbb` will 129 | do cleanup after installation and deactivate all active ports. 130 | - Call `mpbb` with `--prefix=/opt/mports` to use your custom prefix. You may 131 | also want to set `--work-dir`. 132 | -------------------------------------------------------------------------------- /functions: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Helper functions for mpbb 5 | 6 | # Print $0 and arguments to standard error. 7 | # Unset IFS to ensure "$*" uses spaces as separators. 8 | msg() (unset IFS; printf >&2 '%s: %s\n' "$0" "$*") 9 | err() { msg error: "$@"; } 10 | warn() { msg warning: "$@"; } 11 | 12 | unset GETOPT_COMPATIBLE 13 | if getopt -T >/dev/null; then 14 | # http://frodo.looijaard.name/project/getopt 15 | err "Cannot find an enhanced getopt(1)" 16 | return 3 17 | fi 18 | 19 | # TODO Documentation, obviously :) 20 | parseopt() { 21 | # Be stricter about this than getopt(1) is. 22 | if ! [[ ${1-} =~ ^[[:alnum:]-]+:{0,2}(,[[:alnum:]-]+:{0,2})*$ ]]; then 23 | err 'Invalid argument given to parseopt' 24 | return 3 25 | fi 26 | 27 | # Use "--options +" to prevent arguments from being rearranged. 28 | local opts 29 | opts=$(getopt --name "$0" --opt + --longopt "$1" -- "${@:2}") 30 | case $? in 31 | 0) 32 | ;; 33 | 1) 34 | # getopt(1) will print the bad argument to standard error. 35 | echo >&2 "Try \`$0 help' for more information." 36 | return 2 37 | ;; 38 | *) 39 | err 'getopt encountered an internal error' 40 | return 3 41 | ;; 42 | esac 43 | readonly opts 44 | 45 | local -a validopts 46 | IFS=, read -ra validopts <<<"$1" 47 | readonly validopts=("${validopts[@]/#/--}") 48 | 49 | eval set -- "$opts" 50 | 51 | local opt validopt 52 | # getopt(1) ensures that the options are always terminated with "--". 53 | while [[ $1 != -- ]]; do 54 | opt=$1 55 | shift 56 | # XXX Do NOT touch anything below unless you know exactly what 57 | # you're doing (http://mywiki.wooledge.org/BashFAQ/006#eval). 58 | for validopt in "${validopts[@]}"; do 59 | if [[ $validopt == "$opt:" || $validopt == "$opt::" ]]; then 60 | opt=${opt#--} 61 | # $1 is null for omitted optional arguments. 62 | eval option_"${opt//-/_}"'=$1' 63 | shift 64 | continue 2 65 | fi 66 | if [[ $validopt == "$opt" ]]; then 67 | opt=${opt#--} 68 | eval option_"${opt//-/_}"'=1' 69 | continue 2 70 | fi 71 | done 72 | # Unreachable unless there is a bug in this function or in getopt(1). 73 | err 'parseopt encountered an internal error' 74 | return 3 75 | done 76 | # shellcheck disable=SC2034 77 | args=("${@:2}") 78 | } 79 | 80 | ## Compute a failcache hash for the given port 81 | # 82 | # Computes and prints a hash uniquely identifying a specific state of a port's 83 | # definition files, including the Portfile's hash as well as the port's 84 | # patchfiles. To build the hash, this function executes the following 85 | # algorithm: 86 | # - For the Portfile, and each file in files/ (if any), calculate a SHA256 87 | # hash 88 | # - Sort the hash values alphabetically 89 | # - Hash the result using SHA256 90 | # This means a failcache entry will not match if a patchfile changes. A common 91 | # case where this is the desired behavior is a port committed without 92 | # a required patchfile. 93 | # 94 | # Valid arguments are all arguments accepted by "port dir". 95 | compute_failcache_hash() { 96 | local portdir 97 | local -a filelist 98 | 99 | portdir=$("${option_prefix}/bin/port" dir "$@") 100 | if [ $? -ne 0 ] || [ -z "$portdir" ]; then 101 | err "Could not compute failcache hash: port dir" "$@" "failed" 102 | return 1 103 | fi 104 | 105 | if [ ! -d "$portdir" ]; then 106 | err "Port directory $portdir does not exist" 107 | return 2 108 | fi 109 | 110 | filelist=("$portdir/Portfile") 111 | if [ -d "$portdir/files" ]; then 112 | filelist+=("$portdir/files") 113 | fi 114 | 115 | find "${filelist[@]}" -type f -exec openssl dgst -sha256 {} \; |\ 116 | cut -d' ' -f2 |\ 117 | sort |\ 118 | openssl dgst -sha256 |\ 119 | cut -d' ' -f2 120 | } 121 | 122 | ## Compute a key that uniquely identifies a (port, variants, portfile-hash) tuple 123 | # 124 | # Valid arguments are a port name, optionally followed by a variant 125 | # specification. Invokes "port dir" to find the Portfile and patchfiles and 126 | # computes a checksum of these files that will become part of the hash. 127 | failcache_key() { 128 | local port=$1 129 | if [ -z "$port" ]; then 130 | err "failcache_key expects a port argument, but none was given." 131 | return 1 132 | fi 133 | 134 | local checksum 135 | checksum=$(compute_failcache_hash "$port") 136 | if [ $? -ne 0 ]; then 137 | err "compute_failcache_hash $port failed" 138 | return 2 139 | fi 140 | 141 | local canonical_variants 142 | canonical_variants=$("${option_prefix}/bin/port-tclsh" "${thisdir}/tools/canonical-variants.tcl" "$@") 143 | if [ $? -ne 0 ]; then 144 | err "tools/canonical-variants.tcl" "$@" "failed" 145 | return 4 146 | fi 147 | 148 | echo "$port $canonical_variants $checksum" 149 | } 150 | 151 | ## Delete stale failcache entries for a given port 152 | # 153 | # Valid arguments are the first and last parts of a key generated by 154 | # failcache_key in order, i.e. portname and checksum. 155 | # Returns 1 if there were no entries for the given port, 0 otherwise. 156 | failcache_cleanup() { 157 | if ! compgen -G "${option_failcache_dir}/${1} *" > /dev/null; then 158 | return 1 159 | fi 160 | for f in "${option_failcache_dir}/${1} "*; do 161 | if [ "$(basename "$f" | cut -d ' ' -f3)" != "${2}" ]; then 162 | rm -f "${f}" 163 | fi 164 | done 165 | return 0 166 | } 167 | 168 | ## Test whether a given port with variants has previously failed. 169 | # 170 | # Valid arguments are a port name, optionally followed by a variant 171 | # specification. Succeeds if the port did not previously fail to build, 172 | # fails if the port is known to fail. 173 | failcache_test() { 174 | local key 175 | key=$(failcache_key "$@") 176 | if [ $? -ne 0 ]; then 177 | err "Could not determine failcache key for" "$@" 178 | return 1 179 | fi 180 | 181 | # check that it doesn't exceed NAME_MAX 182 | if [ "$(echo "$key" | wc -c)" -gt 255 ]; then 183 | printf "failcache key too long: %s\n" "${key}" 184 | return 0 185 | fi 186 | 187 | if [ -f "${option_failcache_dir}/${key}" ]; then 188 | printf "port %s previously failed in build %s\n" "${key}" "$(<"${option_failcache_dir}/${key}")" 189 | return 1 190 | else 191 | return 0 192 | fi 193 | } 194 | 195 | ## Mark a build of a given port with variants as successful. 196 | # 197 | # Valid arguments are a port name, optionally followed by a variant 198 | # specification. Removes any database entries that marked a port as failed. 199 | failcache_success() { 200 | local key 201 | key=$(failcache_key "$@") 202 | if [ $? -ne 0 ]; then 203 | err "Could not determine failcache key for" "$@" 204 | return 1 205 | fi 206 | 207 | if [ "$(echo "$key" | wc -c)" -gt 255 ]; then 208 | printf "failcache key too long: %s\n" "${key}" 209 | return 0 210 | fi 211 | 212 | # Only remove the entry for the successful configuration, leaving 213 | # other entries in case they are explicitly requested later. These 214 | # can be removed manually if desired. 215 | rm -f "${option_failcache_dir}/${key}" 216 | } 217 | 218 | ## Mark a build of a given port with variants as failed. 219 | # 220 | # Valid arguments are a port name, optionally followed by a variant 221 | # specification. Creates or updates the timestamp of a database entry that 222 | # marks a port as failed. 223 | failcache_failure() { 224 | local key 225 | key=$(failcache_key "$@") 226 | if [ $? -ne 0 ]; then 227 | err "Could not determine failcache key for" "$@" 228 | return 1 229 | fi 230 | 231 | if [ "$(echo "$key" | wc -c)" -gt 255 ]; then 232 | printf "failcache key too long: %s\n" "${key}" 233 | return 0 234 | fi 235 | 236 | mkdir -p "${option_failcache_dir}" 237 | echo "${BUILDBOT_BUILDURL:-unknown}" > "${option_failcache_dir}/${key}" 238 | } 239 | 240 | get-maintainers() { 241 | # 'username@macports.org github_username' => 'username@macports.org' 242 | # $option_prefix is set in mpbb 243 | # shellcheck disable=SC2154 244 | "${option_prefix}/bin/port" info --index --maintainers --line "$@" \ 245 | | tr ', ' '\n' | fgrep '@' | tr '\n' ',' | sed 's/,$//' 246 | } 247 | -------------------------------------------------------------------------------- /index_vars/README.txt: -------------------------------------------------------------------------------- 1 | These files are intended to be used with portindex(1)'s -p option. They 2 | contain pairs of variable names and values, where the values are what 3 | could be set for each variable on the platform described in the file 4 | name. This allows the generated index to more accurately resemble what 5 | would be generated if portindex were actually run on that platform. 6 | 7 | Example usage: 8 | 9 | portindex -p file:./index_vars/macosx_24_arm 10 | -------------------------------------------------------------------------------- /index_vars/macosx_10_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 10 os_version 10.0.0 macos_version 10.6.0 macos_version_major 10.6 macosx_version 10.6 macosx_sdk_version 10.6 macosx_deployment_target 10.6 os_arch i386 build_arch x86_64 universal_archs {i386 x86_64} cxx_stdlib libc++ xcodeversion 3.2.6 xcodecltversion none developer_dir /Developer compiler_version_cache {versions {/Developer {/usr/bin/clang 77 /usr/bin/gcc-4.0 5494 /usr/bin/gcc-4.2 5666 /usr/bin/llvm-gcc-4.2 2335.6}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_11_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 11 os_version 11.0.0 macos_version 10.7.0 macos_version_major 10.7 macosx_version 10.7 macosx_sdk_version 10.7 macosx_deployment_target 10.7 os_arch i386 build_arch x86_64 universal_archs {i386 x86_64} cxx_stdlib libc++ xcodeversion 4.6.3 xcodecltversion none developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 425.0.28 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 2336.11.00}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_12_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 12 os_version 12.0.0 macos_version 10.8.0 macos_version_major 10.8 macosx_version 10.8 macosx_sdk_version 10.8 macosx_deployment_target 10.8 os_arch i386 build_arch x86_64 universal_archs {i386 x86_64} cxx_stdlib libc++ xcodeversion 5.1.1 xcodecltversion none developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 503.0.40 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_13_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 13 os_version 13.0.0 macos_version 10.9.0 macos_version_major 10.9 macosx_version 10.9 macosx_sdk_version 10.9 macosx_deployment_target 10.9 os_arch i386 build_arch x86_64 universal_archs {i386 x86_64} cxx_stdlib libc++ xcodeversion 6.2 xcodecltversion 6.2.0.0.1.1424975374 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 600.0.57 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}} {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 600.0.57 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_14_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 14 os_version 14.0.0 macos_version 10.10.0 macos_version_major 10.10 macosx_version 10.10 macosx_sdk_version 10.10 macosx_deployment_target 10.10 os_arch i386 build_arch x86_64 universal_archs {i386 x86_64} cxx_stdlib libc++ xcodeversion 7.0.1 xcodecltversion 7.2.0.0.1.1447826929 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 700.1.81 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}} {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 700.0.72 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_15_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 15 os_version 15.0.0 macos_version 10.11.0 macos_version_major 10.11 macosx_version 10.11 macosx_sdk_version 10.11 macosx_deployment_target 10.11 os_arch i386 build_arch x86_64 universal_archs {i386 x86_64} cxx_stdlib libc++ xcodeversion 8.2.1 xcodecltversion 8.2.0.0.1.1480973914 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 800.0.42.1 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}} {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 800.0.42.1 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_16_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 16 os_version 16.0.0 macos_version 10.12.0 macos_version_major 10.12 macosx_version 10.12 macosx_sdk_version 10.12 macosx_deployment_target 10.12 os_arch i386 build_arch x86_64 universal_archs {i386 x86_64} cxx_stdlib libc++ xcodeversion 9.2 xcodecltversion 9.2.0.0.1.1510905681 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 900.0.39.2 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}} {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 900.0.39.2 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_17_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 17 os_version 17.0.0 macos_version 10.13.0 macos_version_major 10.13 macosx_version 10.13 macosx_sdk_version 10.13 macosx_deployment_target 10.13 os_arch i386 build_arch x86_64 universal_archs {i386 x86_64} cxx_stdlib libc++ xcodeversion 10.1 xcodecltversion 10.1.0.0.1.1539992718 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1000.10.44.4 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}} {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1000.11.45.5 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_18_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 18 os_version 18.0.0 macos_version 10.14.0 macos_version_major 10.14 macosx_version 10.14 macosx_sdk_version 10.14 macosx_deployment_target 10.14 os_arch i386 build_arch x86_64 universal_archs x86_64 cxx_stdlib libc++ xcodeversion 11.3.1 xcodecltversion 10.3.0.0.1.1562985497 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1001.0.46.4 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}} {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1100.0.33.17 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_19_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 19 os_version 19.0.0 macos_version 10.15.0 macos_version_major 10.15 macosx_version 10.15 macosx_sdk_version 10.15 macosx_deployment_target 10.15 os_arch i386 build_arch x86_64 universal_archs x86_64 cxx_stdlib libc++ xcodeversion 12.4 xcodecltversion 12.4.0.0.1.1610135815 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1200.0.32.29 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}} {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1200.0.32.29 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_20_arm: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 20 os_version 20.0.0 macos_version 11.0.0 macos_version_major 11 macosx_version 11 macosx_sdk_version 11 macosx_deployment_target 11.0 os_arch arm build_arch arm64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 13.2.1 xcodecltversion 13.2.0.0.1.1638488800 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1300.0.29.30 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}} {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1300.0.29.30 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_20_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 20 os_version 20.0.0 macos_version 11.0.0 macos_version_major 11 macosx_version 11 macosx_sdk_version 11 macosx_deployment_target 11.0 os_arch i386 build_arch x86_64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 13.2.1 xcodecltversion 13.2.0.0.1.1638488800 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1300.0.29.30 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}} {/Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1300.0.29.30 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_21_arm: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 21 os_version 21.0.0 macos_version 12.0 macos_version_major 12 macosx_version 12 macosx_sdk_version 12 macosx_deployment_target 12.0 os_arch arm build_arch arm64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 14.2 xcodecltversion 14.2.0.0.1.1668646533 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1400.0.29.202 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}} /Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1400.0.29.202 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_21_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 21 os_version 21.0.0 macos_version 12.0 macos_version_major 12 macosx_version 12 macosx_sdk_version 12 macosx_deployment_target 12.0 os_arch i386 build_arch x86_64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 14.2 xcodecltversion 14.2.0.0.1.1668646533 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1400.0.29.202 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}} /Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1400.0.29.202 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_22_arm: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 22 os_version 22.0.0 macos_version 13.0 macos_version_major 13 macosx_version 13 macosx_sdk_version 13 macosx_deployment_target 13.0 os_arch arm build_arch arm64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 14.3.1 xcodecltversion 14.3.1.0.1.1683849156 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1403.0.22.14.1 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}} /Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1403.0.22.14.1 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_22_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 22 os_version 22.0.0 macos_version 13.0 macos_version_major 13 macosx_version 13 macosx_sdk_version 13 macosx_deployment_target 13.0 os_arch i386 build_arch x86_64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 14.3.1 xcodecltversion 14.3.1.0.1.1683849156 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1403.0.22.14.1 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}} /Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1403.0.22.14.1 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_23_arm: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 23 os_version 23.0.0 macos_version 14.0 macos_version_major 14 macosx_version 14 macosx_sdk_version 14 macosx_deployment_target 14.0 os_arch arm build_arch arm64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 15.4 xcodecltversion 16.2.0.0.1.1733547573 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1600.0.26.6 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}} /Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1500.3.9.4 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_23_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 23 os_version 23.0.0 macos_version 14.0 macos_version_major 14 macosx_version 14 macosx_sdk_version 14 macosx_deployment_target 14.0 os_arch i386 build_arch x86_64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 15.4 xcodecltversion 16.2.0.0.1.1733547573 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1600.0.26.6 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}} /Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1500.3.9.4 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_24_arm: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 24 os_version 24.0.0 macos_version 15.0 macos_version_major 15 macosx_version 15 macosx_sdk_version 15 macosx_deployment_target 15.0 os_arch arm build_arch arm64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 16.3 xcodecltversion 16.3.0.0.1.1742442376 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1700.0.13.3 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}} /Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1700.0.13.3 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_24_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 24 os_version 24.0.0 macos_version 15.0 macos_version_major 15 macosx_version 15 macosx_sdk_version 15 macosx_deployment_target 15.0 os_arch i386 build_arch x86_64 universal_archs {arm64 x86_64} cxx_stdlib libc++ xcodeversion 16.3 xcodecltversion 16.3.0.0.1.1742442376 developer_dir /Applications/Xcode.app/Contents/Developer compiler_version_cache {versions {/Library/Developer/CommandLineTools {/usr/bin/clang 1700.0.13.3 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}} /Applications/Xcode.app/Contents/Developer {/usr/bin/clang 1700.0.13.3 /usr/bin/gcc-4.0 {} /usr/bin/gcc-4.2 {} /usr/bin/llvm-gcc-4.2 {}}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_9_i386: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 9 os_version 9.0.0 macos_version 10.5.0 macos_version_major 10.5 macosx_version 10.5 macosx_sdk_version 10.5 macosx_deployment_target 10.5 os_arch i386 build_arch i386 universal_archs {i386 ppc} cxx_stdlib libstdc++ xcodeversion 3.1.4 xcodecltversion none developer_dir /Developer compiler_version_cache {versions {/Developer {/usr/bin/clang {} /usr/bin/gcc-4.0 5493 /usr/bin/gcc-4.2 5577 /Developer/usr/bin/llvm-gcc-4.2 2064.3}}} 2 | -------------------------------------------------------------------------------- /index_vars/macosx_9_powerpc: -------------------------------------------------------------------------------- 1 | os_platform darwin os_subplatform macosx os_major 9 os_version 9.0.0 macos_version 10.5.0 macos_version_major 10.5 macosx_version 10.5 macosx_sdk_version 10.5 macosx_deployment_target 10.5 os_arch powerpc build_arch ppc universal_archs {i386 ppc} cxx_stdlib libstdc++ xcodeversion 3.1.4 xcodecltversion none developer_dir /Developer compiler_version_cache {versions {/Developer {/usr/bin/clang {} /usr/bin/gcc-4.0 5493 /usr/bin/gcc-4.2 5577 /Developer/usr/bin/llvm-gcc-4.2 2064.3}}} 2 | -------------------------------------------------------------------------------- /mpbb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Abort on undefined variables. 5 | set -u 6 | 7 | # shellcheck disable=SC2154 8 | # Don't inherit any option variables from the calling environment. 9 | unset "${!option_@}" 10 | 11 | # Load function library 12 | thisdir=$(cd "$(dirname "$0")" && pwd) 13 | # shellcheck source=functions 14 | . "$thisdir/functions" || exit 15 | 16 | mpbb-usage() { 17 | # "prog" is defined in mpbb-help. 18 | # shellcheck disable=SC2154 19 | cat <] [] 21 | 22 | Build MacPorts ports in a continuous integration environment. 23 | 24 | Global options: 25 | 26 | --prefix= 27 | The prefix of the MacPorts installation that will be used for 28 | building ports. Defaults to \`/opt/local'. 29 | 30 | --work-dir= 31 | A working directory to be used for storing temporary files, 32 | accessible by the MacPorts installation specified with \`--prefix'. 33 | The directory should persist between runs of \`mpbb'. Defaults to 34 | the value of \$PWD or \`/tmp/mpbb'. 35 | 36 | Available commands: 37 | 38 | ${cmds[0]}$(printf ', %s' "${cmds[@]:1}") 39 | 40 | Run \`$prog help ' for per-command help. 41 | EOF 42 | } 43 | 44 | # Process options. 45 | parseopt prefix:,work-dir: "$@" || exit 46 | 47 | # Use sensible defaults for options that weren't set on the command line. 48 | # shellcheck disable=SC2154 49 | { 50 | : "${option_prefix=/opt/local}" 51 | : "${option_work_dir=${PWD:-/tmp/mpbb}}" 52 | } 53 | 54 | # shellcheck disable=SC2034 55 | # Not really options, but pretend they are because they're global. 56 | { 57 | option_jobs_dir=${option_work_dir}/infrastructure/jobs 58 | option_log_dir=${option_work_dir}/logs 59 | } 60 | option_failcache_dir=${option_work_dir}/failcache 61 | option_license_db_dir=${option_work_dir}/license_db 62 | option_mirrordb_url="" 63 | option_mirrordb_credentials="" 64 | 65 | # Inform the user if old repositories are still present. 66 | if [[ -d ${option_work_dir}/tools/.svn ]]; then 67 | msg "\`${option_work_dir}/tools' is no longer used for the jobs" \ 68 | 'tools and may be deleted' 69 | fi 70 | if [[ -d ${option_work_dir}/dports/.svn ]]; then 71 | msg "\`${option_work_dir}/dports' is no longer used for the ports" \ 72 | 'tree and may be deleted' 73 | fi 74 | 75 | # shellcheck disable=SC2086 76 | # Set up the positional arguments for the subcommand. With "set -u" 77 | # enabled, "${foo[@]}" doesn't work if foo is empty. 78 | set -- ${args+"${args[@]}"} 79 | 80 | # Load the subcommand implementations. Each sourced script "mpbb-FOO" 81 | # must define functions "FOO" and "FOO-usage". 82 | cmds=() 83 | usages=(mpbb-usage) 84 | for cmdfile in "$thisdir/mpbb-"*; do 85 | # Unfortunately ShellCheck does not currently support following multiple 86 | # files, so we'll just disable the warning. 87 | # shellcheck disable=SC1090 88 | if . "$cmdfile"; then 89 | cmd=${cmdfile##*/mpbb-} 90 | cmds+=("$cmd") 91 | usages+=("${cmd}-usage") 92 | else 93 | err "failed to load subcommand script \`$cmdfile'" 94 | exit 3 95 | fi 96 | done 97 | 98 | if (( $# < 1 )); then 99 | err "No command specified" 100 | echo >&2 "Try \`$0 help' for more information." 101 | exit 2 102 | fi 103 | 104 | subcmd=$1 105 | shift 106 | 107 | # This loop exits with 0 if cmds contains subcmd or is empty. 108 | for cmd in "${cmds[@]}"; do 109 | [[ $cmd == "$subcmd" ]] && break 110 | done 111 | # shellcheck disable=SC2181 112 | if (( $? != 0 || ${#cmds[@]} == 0 )); then 113 | err "Unknown command \`$subcmd'" 114 | echo >&2 "Try \`$0 help' for more information." 115 | exit 2 116 | fi 117 | 118 | ## Otherwise, run the command and deal with errors 119 | PORTSRC=${option_work_dir}/macports.conf "$subcmd" "$@" 120 | readonly rc=$? 121 | case $rc in 122 | 0) 123 | ;; 124 | *) 125 | err "\`$subcmd' failed to run successfully" 126 | ;; 127 | esac 128 | exit $rc 129 | -------------------------------------------------------------------------------- /mpbb-checkout: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | checkout-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] checkout [] 13 | 14 | Obtain a working copy of the jobs tools and ports tree and configure 15 | MacPorts to use the latter as a port source. 16 | 17 | Options: 18 | 19 | --archive-sites= 20 | Space-separated list of additional URLs to check for preexisting 21 | archives. Defaults to \`https://packages-private.macports.org'. 22 | 23 | --binpath= 24 | Colon-separated list of paths where MacPorts will look for 25 | programs. Defaults to 26 | \`/bin:/sbin:/bin:/sbin:/usr/bin:/usr/sbin'. 27 | 28 | --git[=] 29 | Use Git to obtain the jobs tools and ports tree; this is the default 30 | behavior. The path to a Git client may be provided explicitly, 31 | otherwise \`git' is used. Cannot be specified together with --svn. 32 | 33 | --jobs-url= 34 | URL to a repository containing the jobs tools. Only used when 35 | checking out a new working copy. Defaults to 36 | \`https://github.com/macports/macports-infrastructure.git' for Git 37 | and 38 | \`https://github.com/macports/macports-infrastructure.git/trunk/jobs' 39 | for Subversion. 40 | 41 | --ports-branch= 42 | The branch of the remote repository from which the ports tree will 43 | be checked out. Only used with Git; defaults to \`master'. 44 | 45 | --ports-commit= 46 | A commit or revision at which the ports tree will be checked out. 47 | Any specifier understood by the version-control client may be used. 48 | Defaults to \`FETCH_HEAD' for Git and \`HEAD' for Subversion. 49 | 50 | --ports-url= 51 | URL to a repository containing the ports tree. Only used when 52 | checking out a new working copy. Defaults to 53 | \`https://github.com/macports/macports-ports.git' for Git and 54 | \`https://github.com/macports/macports-ports.git/trunk' for 55 | Subversion. 56 | 57 | --svn[=] 58 | Use Subversion to obtain the jobs tools and ports tree. The path to 59 | a Subversion client may be provided explicitly, otherwise \`svn' is 60 | used. Cannot be specified together with --git. 61 | 62 | Run \`$prog help' for global options and a list of other subcommands. 63 | EOF 64 | } 65 | 66 | is-empty() { 67 | if [[ $# -ne 1 || -z $1 ]]; then 68 | err 'is-empty requires a single non-null argument' 69 | return 2 70 | fi 71 | (shopt -s dotglob nullglob; f=("$1"/*); (( ! ${#f[@]} ))) 72 | } 73 | 74 | git-checkout() { 75 | if (( $# < 2 )); then 76 | err 'git-checkout requires at least two arguments' 77 | return 2 78 | fi 79 | 80 | local -r dst=$1 src=$2 commitish=${3-FETCH_HEAD} branch=${4-master} 81 | 82 | # top is null unless dst exists somewhere in a Git working tree. 83 | local -r top=$({ cd "$dst" && "$git" rev-parse --show-toplevel; } 2>/dev/null) 84 | if ! { [[ -z $top ]] && is-empty "$dst" || [[ $top -ef $dst ]]; }; then 85 | err "\`$dst' is not an empty directory or" \ 86 | 'the top level of a Git working tree' 87 | return 1 88 | fi 89 | 90 | printf "\n---> Updating Git repository from \`%s' branch of \`%s'\n" \ 91 | "$branch" "$src" 92 | ( 93 | # "git init" creates the intermediate directories and is safe to 94 | # run in an existing repository. 95 | "$git" init "$dst" || exit 96 | 97 | # Change directories explicitly because Lion's Git (1.7.12.4) is 98 | # too old to understand "git -C" (requires 1.8.5). 99 | cd "$dst" || exit 100 | 101 | # Fetch directly from the URL to avoid fussing with remotes and 102 | # to allow switching sources easily. 103 | "$git" fetch --tags "$src" "$branch" || exit 104 | 105 | # Maintain master to prevent Git from garbage-collecting the 106 | # fetched objects. 107 | "$git" update-ref -m "mpbb checkout $(date -u +%Y-%m-%dT%TZ)" \ 108 | refs/heads/master FETCH_HEAD || exit 109 | 110 | # Only update the working tree here, at the very end. 111 | "$git" checkout --detach "$commitish" 112 | ) 113 | } 114 | 115 | svn-checkout() { 116 | if (( $# < 2 )); then 117 | err 'svn-checkout requires at least two arguments' 118 | return 2 119 | fi 120 | 121 | local -r dst=$1 src=$2 rev=${3-HEAD} 122 | local -r svn=("$svn" --non-interactive) 123 | local -r root=$("${svn[@]}" info --show-item wc-root "$dst" 2>/dev/null) 124 | 125 | if [[ -z $root ]] && is-empty "$dst"; then 126 | printf "\n---> Checking out Subversion repository from \`%s'\n" "$src" 127 | # "svn checkout" creates the intermediate directories. 128 | "${svn[@]}" checkout --revision "$rev" "$src" "$dst" 129 | elif [[ $root -ef $dst ]]; then 130 | # TODO Allow switching the Subversion server. 131 | printf "\n---> Updating Subversion repository from \`%s'\n" \ 132 | "$("${svn[@]}" info --show-item url "$dst")" 133 | "${svn[@]}" cleanup "$dst" \ 134 | && "${svn[@]}" update --revision "$rev" "$dst" 135 | else 136 | err "\`$dst' is not an empty directory or" \ 137 | 'the root of a Subversion working copy' 138 | return 1 139 | fi 140 | } 141 | 142 | checkout() { 143 | local args 144 | parseopt archive-sites:,binpath:,git::,jobs-url:,ports-branch:,ports-commit:,ports-url:,svn::,svn-url: "$@" \ 145 | || return 146 | # shellcheck disable=SC2086 147 | set -- ${args+"${args[@]}"} 148 | 149 | # shellcheck disable=SC2154 150 | # To maintain backwards compatibility, --svn-url implies --svn. 151 | if [[ -n ${option_svn_url+_} ]]; then 152 | : "${option_svn=}" 153 | fi 154 | 155 | # shellcheck disable=SC2154 156 | local -r ports_dir=${option_work_dir}/ports 157 | 158 | # $option_archive_sites is set by parseopt 159 | # shellcheck disable=SC2154 160 | : "${option_archive_sites=https://packages-private.macports.org}" 161 | 162 | # $option_archive_sites isn't quoted on purpose 163 | # shellcheck disable=SC2086 164 | archive_site_local=$(printf '%s/:tbz2 ' ${option_archive_sites}) 165 | 166 | # $option_binpath is set by parseopt 167 | # $option_prefix is set in mpbb 168 | # shellcheck disable=SC2154 169 | : "${option_binpath=${option_prefix}/bin:${option_prefix}/sbin:/bin:/sbin:/usr/bin:/usr/sbin}" 170 | 171 | local checkout git jobs_dir svn 172 | # shellcheck disable=SC2100 disable=SC2154 173 | if [[ -z ${option_svn+_} ]] && git=${option_git:-$(command -v git)}; then 174 | checkout=git-checkout 175 | # Checking out "jobs_url" should create a "jobs" subdirectory. 176 | jobs_dir=$(dirname "${option_jobs_dir}") 177 | : "${option_jobs_url=https://github.com/macports/macports-infrastructure.git}" 178 | : "${option_ports_url=https://github.com/macports/macports-ports.git}" 179 | elif [[ -z ${option_git+_} ]] && svn=${option_svn:-$(command -v svn)}; then 180 | checkout=svn-checkout 181 | jobs_dir=${option_jobs_dir} 182 | if [[ -n ${option_svn_url+_} ]]; then 183 | : "${option_jobs_url=${option_svn_url}/base/portmgr/jobs}" 184 | : "${option_ports_url=${option_svn_url}/dports}" 185 | else 186 | : "${option_jobs_url=https://github.com/macports/macports-infrastructure.git/trunk/jobs}" 187 | : "${option_ports_url=https://github.com/macports/macports-ports.git/trunk}" 188 | fi 189 | else 190 | case ${option_git+_},${option_svn+_} in 191 | _,_) err 'cannot use both Git and Subversion'; return 2 ;; 192 | _,) err 'cannot find a Git client' ;; 193 | ,_) err 'cannot find a Subversion client' ;; 194 | ,) err 'cannot find any Git or Subversion clients' ;; 195 | esac 196 | return 1 197 | fi 198 | readonly checkout git jobs_dir svn 199 | 200 | $checkout "${jobs_dir}" "${option_jobs_url}" || return 201 | # shellcheck disable=SC2086 disable=SC2154 202 | $checkout "${ports_dir}" "${option_ports_url}" \ 203 | ${option_ports_commit+"${option_ports_commit}"} \ 204 | ${option_ports_branch+"${option_ports_branch}"} || return 205 | 206 | # $option_prefix is set in mpbb 207 | # shellcheck disable=SC2154 208 | (cd "${ports_dir}" && "${option_prefix}/bin/portindex") || return 209 | 210 | cat > "${option_work_dir}/macports.conf" <> "${option_work_dir}/macports.conf" < "${option_work_dir}/sources.conf" <] cleanup 13 | 14 | Clean up after a build. 15 | 16 | Run \`$prog help' for global options and a list of other subcommands. 17 | EOF 18 | } 19 | 20 | format_size() { 21 | size="${1#-}" 22 | if [ "$1" == "$size" ]; then 23 | sign= 24 | else 25 | sign=- 26 | fi 27 | units=KiB 28 | if [ "$size" -ge 1024 ]; then 29 | size=$(((size + 512) / 1024)) 30 | units=MiB 31 | if [ "$size" -ge 1024 ]; then 32 | size=$(((size + 512) / 1024)) 33 | units=GiB 34 | fi 35 | fi 36 | echo "$sign$size$units" 37 | } 38 | 39 | disk_free() { 40 | df -k "$1" | awk 'NR==2 {print $4}' 41 | } 42 | 43 | cleanup() { 44 | # if this is the very first build, selfupdate did not install port yet 45 | # $option_prefix is set in mpbb 46 | # shellcheck disable=SC2154 47 | if [ ! -e "${option_prefix}/bin/port" ]; then 48 | echo "---> Skipping cleanup" 49 | echo "port not installed at ${option_prefix}/bin/port" 50 | return 51 | fi 52 | 53 | # Provide a way to pause builds to deal with situations like 54 | # https://trac.macports.org/ticket/53587 55 | if [[ ${BUILDBOT_BUILDERNAME:-unknown} == *-watcher ]]; then 56 | # $option_work_dir is set in mpbb 57 | # shellcheck disable=SC2154 58 | waitfile="$option_work_dir/wait" 59 | if [ -f "$waitfile" ]; then 60 | echo "----> Waiting" 61 | waitcount=0 62 | while [ -f "$waitfile" ]; do 63 | if [ "$waitcount" -eq 0 ]; then 64 | echo "waiting while $waitfile exists" 65 | waitcount=100 66 | else 67 | waitcount=$((waitcount - 1)) 68 | fi 69 | sleep 6 70 | done 71 | echo 72 | fi 73 | fi 74 | 75 | # $option_prefix is set in mpbb 76 | # shellcheck disable=SC2154 77 | disk_free_before=$(disk_free "$option_prefix") 78 | echo "----> Free disk space before cleanup: $(format_size "$disk_free_before")" 79 | echo 80 | # Do extra cleanup if free space is less than this (in KiB) 81 | DISK_FREE_THRESHOLD=15000000 82 | 83 | if [[ ${BUILDBOT_BUILDERNAME:-unknown} == *-watcher || "$disk_free_before" -lt "$DISK_FREE_THRESHOLD" ]]; then 84 | if [[ ${BUILDBOT_BUILDERNAME:-unknown} == *-watcher ]]; then 85 | echo 86 | echo "----> Uninstalling unneeded ports" 87 | # $thisdir is set by mpbb and points to the directory in which this script resides 88 | # shellcheck disable=SC2154 89 | "${option_prefix}/bin/port-tclsh" "${thisdir}/tools/uninstall-unneeded-ports.tcl" 90 | fi 91 | if [ ! -L "${option_prefix}/var/macports/distfiles" ]; then 92 | echo 93 | echo "----> Deleting distfiles" 94 | find "${option_prefix}/var/macports/distfiles" -type f \! -newerat "4 hours ago" -print -delete | sed -E 's/^/Deleting distfile /' 95 | find "${option_prefix}/var/macports/distfiles" -type d -mindepth 1 -empty -print -delete | sed -E 's/^/Deleting directory /' 96 | fi 97 | # clean out failcache at most once every week 98 | timestamp="${option_work_dir}/failcache-cleanup.timestamp" 99 | if [[ ! -f "$timestamp" || $(($(date +%s) - $(stat -f %m "$timestamp"))) -gt 604800 ]]; then 100 | echo 101 | echo "----> Deleting unneeded failcache entries" 102 | "${option_prefix}/bin/port-tclsh" "${thisdir}/tools/failcache-cleanup.tcl" --failcache_dir "${option_failcache_dir}" 103 | touch "$timestamp" 104 | fi 105 | fi 106 | echo 107 | for dir in build logs; do 108 | echo "----> Deleting ${dir}" 109 | ports="$(find "${option_prefix}/var/macports/${dir}" -name '.*' -prune -o -depth 2 -type d -print | sed 's,^.*/,,' | sort -fu)" 110 | for port in ${ports}; do 111 | echo "Deleting ${dir} for ${port}" 112 | "${option_prefix}/bin/port-tclsh" "${thisdir}/tools/noisy-delete.tcl" "${option_prefix}/var/macports/${dir}"/*/"${port}" 113 | done 114 | rm -rf "${option_prefix}/var/macports/${dir}"/* 115 | echo 116 | done 117 | 118 | # $option_prefix is set in mpbb 119 | # shellcheck disable=SC2154 120 | disk_free_after=$(disk_free "$option_prefix") 121 | echo "----> Free disk space after cleanup: $(format_size "$disk_free_after")" 122 | 123 | if [[ "$disk_free_after" -lt "$DISK_FREE_THRESHOLD" ]]; then 124 | echo "----> Trying to free more disk space" 125 | # $thisdir is set by mpbb and points to the directory in which this script resides 126 | # shellcheck disable=SC2154 127 | "${option_prefix}/bin/port-tclsh" "${thisdir}/tools/reclaim-space.tcl" "$disk_free_after" "$DISK_FREE_THRESHOLD" 128 | # $option_prefix is set in mpbb 129 | # shellcheck disable=SC2154 130 | disk_free_after=$(disk_free "$option_prefix") 131 | echo "----> Free disk space after extra cleanup: $(format_size "$disk_free_after")" 132 | fi 133 | 134 | echo "----> Disk space saved by cleanup: $(format_size $((disk_free_after - disk_free_before)))" 135 | } 136 | -------------------------------------------------------------------------------- /mpbb-gather-archives: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | gather-archives-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] gather-archives [] 13 | 14 | Copy unpublished, distributable archives of active ports into a staging 15 | directory for uploading. 16 | 17 | Options: 18 | 19 | --archive-site= 20 | URL to check for preexisting public archives. Defaults to 21 | \`https://packages.macports.org'. 22 | 23 | --archive-site-private= 24 | URL to check for preexisting private archives. Defaults to 25 | \`https://packages-private.macports.org'. 26 | 27 | --staging-dir= 28 | A directory for storing archives before deployment. Defaults to the 29 | \`archive-staging' subdirectory of the \`--work-dir' working directory. 30 | 31 | Run \`$prog help' for global options and a list of other subcommands. 32 | EOF 33 | } 34 | 35 | device-of-path() { 36 | df -P -- "$1" | awk 'NR==2 {print $1}' 37 | } 38 | 39 | gather-archives() { 40 | local args 41 | parseopt archive-site:,archive-site-private:,staging-dir: "$@" || return 42 | # $option_archive_site is set by parseopt 43 | # shellcheck disable=SC2154 44 | : "${option_archive_site=https://packages.macports.org}" 45 | # $option_archive_site_private is set by parseopt 46 | # shellcheck disable=SC2154 47 | : "${option_archive_site_private=https://packages-private.macports.org}" 48 | # $option_staging_dir is set by parseopt 49 | # shellcheck disable=SC2154 50 | : "${option_staging_dir=${option_work_dir}/archive-staging}" 51 | # shellcheck disable=SC2086 52 | set -- ${args+"${args[@]}"} 53 | 54 | # $option_prefix is set in mpbb 55 | # shellcheck disable=SC2154 56 | tclsh="${option_prefix}/bin/port-tclsh" 57 | 58 | if [ -d "${option_staging_dir}" ]; then 59 | find "${option_staging_dir}" -type f -delete -print | sed -E -e "s|^.*/||" -e 's/^/Deleting previously staged archive: /' 60 | rm -rf "${option_staging_dir}" 61 | echo 62 | fi 63 | 64 | mkdir -p "${option_staging_dir}"/public "${option_staging_dir}"/private || return 65 | chmod -R a+rX "${option_staging_dir}" 66 | 67 | # $thisdir is set in mpbb 68 | # shellcheck disable=SC2154 69 | "${tclsh}" "${thisdir}/tools/gather-archives.tcl" --archive_site_private "${option_archive_site_private}" \ 70 | --archive_site_public "${option_archive_site}" --jobs_dir "${option_jobs_dir}" \ 71 | --license_db_dir "${option_license_db_dir}" --staging_dir "${option_staging_dir}" \ 72 | "${option_work_dir}/requested_port" 73 | return $? 74 | } 75 | -------------------------------------------------------------------------------- /mpbb-help: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | help-usage() { 9 | cat <] 11 | 12 | Show usage information for \`$prog' or a specific \`$prog' subcommand. 13 | 14 | Run \`$prog help' for global options and a list of other subcommands. 15 | EOF 16 | } 17 | 18 | help() { 19 | local cols helpfunc prog 20 | cols=$(tput cols) || cols=80 21 | # The main program should define "mpbb-usage", which is called if 22 | # "mpbb help" is invoked without any arguments. 23 | helpfunc=${1-mpbb}-usage 24 | prog=$(basename "$0") 25 | readonly cols helpfunc prog 26 | 27 | # This loop exits with 0 if usages contains helpfunc or is empty. 28 | for usage in "${usages[@]}"; do 29 | [[ $usage == "$helpfunc" ]] && break 30 | done 31 | if (( $? != 0 || ${#usages[@]} == 0 )); then 32 | err "No help available for subcommand \`${helpfunc%-usage}'" 33 | return 2 34 | fi 35 | 36 | "$helpfunc" | fmt -w $((cols - 8)) >&2 37 | } 38 | -------------------------------------------------------------------------------- /mpbb-install-dependencies: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | install-dependencies-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] install-dependencies 13 | 14 | Build and install the dependencies of the given port. 15 | 16 | Run \`$prog help' for global options and a list of other subcommands. 17 | EOF 18 | } 19 | 20 | install-dependencies() { 21 | local port=${1-} 22 | if [[ -z $port ]]; then 23 | err "Must specify a port" 24 | return 1 25 | fi 26 | local log_subports_progress="${option_log_dir}/ports-progress.txt" 27 | local result 28 | 29 | # Script attempts to get to a state where all dependencies (and 30 | # only dependencies) of the port are active 31 | # $option_prefix and $thisdir are set in mpbb 32 | # shellcheck disable=SC2154 33 | "${option_prefix}/bin/port-tclsh" "${thisdir}/tools/dependencies.tcl" --failcache_dir "${option_failcache_dir}" \ 34 | --logs_dir "${option_log_dir}" "$@" 35 | result=$? 36 | if [ $result -ne 0 ]; then 37 | echo "Processing dependencies for '$port' failed, aborting." >&2 38 | if [ $result -eq 2 ]; then 39 | echo "Building '$port' ... [ERROR] (failed to activate dependencies) maintainers: $(get-maintainers "$port")." >> "$log_subports_progress" 40 | fi 41 | return 1 42 | fi 43 | } 44 | -------------------------------------------------------------------------------- /mpbb-install-port: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | install-port-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] install-port [--source] 13 | 14 | Build and install the given port. 15 | 16 | Options: 17 | 18 | --source 19 | Build the port from source, ignoring binary archives. 20 | 21 | Run \`$prog help' for global options and a list of other subcommands. 22 | EOF 23 | } 24 | 25 | install-port() { 26 | local args 27 | parseopt source "$@" || return 28 | # $option_source is set by parseopt 29 | # shellcheck disable=SC2154 30 | : "${option_source=0}" 31 | set -- ${args+"${args[@]}"} 32 | local source_flag 33 | [[ "${option_source}" -eq 1 ]] && source_flag=s 34 | local port=${1-} 35 | if [[ -z "$port" ]]; then 36 | err "Must specify a port" 37 | return 1 38 | fi 39 | # $option_log_dir is set in mpbb 40 | # shellcheck disable=SC2154 41 | local log_port_contents="${option_log_dir}/port-contents.txt" 42 | local log_port_stats="${option_log_dir}/port-statistics.txt" 43 | local log_port_main="${option_log_dir}/main.log" 44 | local log_subports_progress="${option_log_dir}/ports-progress.txt" 45 | 46 | # prepare the log files and make sure to start with empty ones 47 | mkdir -p "${option_log_dir}" 48 | #> "$log_port_contents" 49 | > "$log_port_stats" 50 | 51 | rm -f "${option_work_dir}/requested_port" 52 | 53 | # $option_prefix and $thisdir are set in mpbb 54 | # shellcheck disable=SC2154 55 | local imagepath=$("${option_prefix}/bin/port-tclsh" "${thisdir}/tools/archive-path.tcl" "$@") 56 | if [[ -f "$imagepath" || -d "${imagepath%.*}" ]]; then 57 | echo "$* already installed, nothing to do" 58 | # log: summary for the portwatcher 59 | echo "Building '$port' ... [OK]" >> "$log_subports_progress" 60 | echo "$@" >> "${option_work_dir}/requested_port" 61 | return 0 62 | elif [[ -n "$("${option_prefix}/bin/port" -q installed "$@")" ]]; then 63 | # archive name differs, supported_archs probably changed 64 | "${option_prefix}/bin/port" -fv uninstall "$@" 65 | fi 66 | 67 | local time_start 68 | local time_stop 69 | time_start=$(date +%s) 70 | FETCHFAILED=0 71 | # $option_prefix is set in mpbb 72 | # shellcheck disable=SC2154 73 | if ! "${option_prefix}/bin/port" -d fetch "$@"; then 74 | echo "Fetch of '$port' failed." 75 | if [ -n "$option_mirrordb_url" ]; then 76 | echo "Waiting for '$port' to be mirrored." 77 | if "${option_prefix}/bin/port-tclsh" "${thisdir}/tools/wait-for-mirror.tcl" \ 78 | "$option_mirrordb_url" "$option_mirrordb_credentials" "$port"; then 79 | echo "Mirroring of '$port' done. Retrying fetch." 80 | if ! "${option_prefix}/bin/port" -d fetch "$@"; then 81 | echo "Second fetch of '$port' failed." 82 | FETCHFAILED=1 83 | fi 84 | else 85 | echo "Timed out waiting for '$port' to be mirrored." 86 | FETCHFAILED=1 87 | fi 88 | else 89 | FETCHFAILED=1 90 | fi 91 | if [ "$FETCHFAILED" -eq 1 ]; then 92 | # log: summary for the portwatcher 93 | echo "Fetching '$port' ... [ERROR] maintainers: $(get-maintainers "$port")." >> "$log_subports_progress" 94 | # Do not add to failcache. This could be a temporary problem that will 95 | # be resolved once the file appears on mirrors. 96 | return 1 97 | fi 98 | fi 99 | # $option_prefix is set in mpbb 100 | # shellcheck disable=SC2154 101 | if ! "${option_prefix}/bin/port" -d checksum "$@"; then 102 | echo "Checksum of '$port' failed." 103 | # log: summary for the portwatcher 104 | echo "Checksum '$port' ... [ERROR] maintainers: $(get-maintainers "$port")." >> "$log_subports_progress" 105 | # Do not add to failcache. This could be a temporary network or server problem. 106 | # Delete the files so they will be re-fetched next time (hopefully correctly). 107 | "${option_prefix}/bin/port" -d clean --dist "$@" 108 | return 1 109 | fi 110 | # $option_prefix is set in mpbb 111 | # shellcheck disable=SC2154 112 | if "${option_prefix}/bin/port" "-dkn${source_flag}" install --unrequested "$@"; then 113 | # Remove failcache if it exists 114 | failcache_success "$@" 115 | if [ $? -ne 0 ]; then 116 | err "failcache_success" "$@" "failed." 117 | return 1 118 | fi 119 | else 120 | echo "Build of '$port' failed." 121 | # log: summary for the portwatcher 122 | echo "Building '$port' ... [ERROR] maintainers: $(get-maintainers "$port")." >> "$log_subports_progress" 123 | # update failcache 124 | failcache_failure "$@" 125 | if [ $? -ne 0 ]; then 126 | err "failcache_failure" "$@" "failed." 127 | return 1 128 | fi 129 | return 1 130 | fi 131 | time_stop=$(date +%s) 132 | 133 | # log: summary for the portwatcher 134 | echo "Building '$port' ... [OK]" >> "$log_subports_progress" 135 | 136 | # log: contents 137 | "${option_prefix}/bin/port" -q contents "$port" > "$log_port_contents" 138 | 139 | # log: statistics 140 | echo "time: $((time_stop - time_start))s" >> "$log_port_stats" 141 | 142 | local port_workdir 143 | local port_workdir_size="" 144 | local port_destdir_size="" 145 | local print_arg_workdir="ERROR" 146 | local print_arg_destdir="ERROR" 147 | # First, compute port_workdir_size and port_destdir_size 148 | port_workdir=$("${option_prefix}/bin/port" work "$port") 149 | if [ -n "$port_workdir" ]; then 150 | port_workdir_size=$(du -ks "$port_workdir" | sed 's/^ *//' | tr '\t' '\n' | head -n 1) 151 | if [ $? -eq 0 ] && [ -n "$port_workdir_size" ]; then 152 | print_arg_workdir="${port_workdir_size}k" 153 | fi 154 | 155 | local port_destdir="$port_workdir/destroot" 156 | # if we arrive here, 'port work $port' was successful, so we're 157 | # at least going to print 'destdir: -' 158 | print_arg_destdir="-" 159 | if [ -d "$port_destdir" ]; then 160 | port_destdir_size=$(du -ks "$port_destdir" | sed 's/^ *//' | tr '\t' '\n' | head -n 1) 161 | if [ $? -eq 0 ] && [ -n "$port_destdir_size" ]; then 162 | print_arg_destdir="${port_destdir_size}k" 163 | fi 164 | fi 165 | fi 166 | # Then print them, or on error (or if destdir doesn't exist), print the 167 | # appropriate message 168 | echo "workdir: $print_arg_workdir" >> "$log_port_stats" 169 | echo "destdir: $print_arg_destdir" >> "$log_port_stats" 170 | 171 | # log: main.log 172 | local port_mainlog 173 | port_mainlog=$("${option_prefix}/bin/port" logfile "$port") 174 | if [ $? -eq 0 ] && [ -f "$port_mainlog" ]; then 175 | cp -f "$port_mainlog" "$log_port_main" 176 | fi 177 | 178 | echo "$@" >> "${option_work_dir}/requested_port" 179 | } 180 | -------------------------------------------------------------------------------- /mpbb-list-subports: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | list-subports-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] list-subports [] [ [...]] 13 | 14 | Print the name and subports of each given port to standard output. 15 | 16 | Options: 17 | 18 | --archive-site= 19 | URL to check for preexisting public archives. Defaults to 20 | \`https://packages.macports.org'. 21 | 22 | --archive-site-private= 23 | URL to check for preexisting private archives. Defaults to 24 | \`https://packages-private.macports.org'. 25 | 26 | Run \`$prog help' for global options and a list of other subcommands. 27 | EOF 28 | } 29 | 30 | print-subports() { 31 | local archive_site_public=$1 32 | local archive_site_private=$2 33 | local include_deps=$3 34 | local portnames=$4 35 | 36 | # $option_prefix is set in mpbb 37 | # shellcheck disable=SC2154 38 | tclsh="${option_prefix}/bin/port-tclsh" 39 | # $option_prefix is set in mpbb 40 | # shellcheck disable=SC2154 41 | if [ "${include_deps}" = "yes" ]; then 42 | include_deps=--include_deps 43 | else 44 | include_deps= 45 | fi 46 | "${tclsh}" "${thisdir}/tools/sort-with-subports.tcl" --jobs_dir "${option_jobs_dir}" \ 47 | --license_db_dir "${option_license_db_dir}" --failcache_dir "${option_failcache_dir}" \ 48 | --archive_site_public "${archive_site_public}" \ 49 | --archive_site_private "${archive_site_private}" ${include_deps} \ 50 | ${portnames} || return 51 | } 52 | 53 | list-subports() { 54 | # $option_log_dir is set in mpbb 55 | # shellcheck disable=SC2154 56 | local log_subports_progress="${option_log_dir}/ports-progress.txt" 57 | 58 | local args 59 | parseopt archive-site:,archive-site-private:,include-deps: "$@" || return 60 | # $option_archive_site is set by parseopt 61 | # shellcheck disable=SC2154 62 | : "${option_archive_site=https://packages.macports.org}" 63 | # $option_archive_site_private is set by parseopt 64 | # shellcheck disable=SC2154 65 | : "${option_archive_site_private=https://packages-private.macports.org}" 66 | # $option_include_deps is set by parseopt 67 | # shellcheck disable=SC2154 68 | : "${option_include_deps=yes}" 69 | set -- ${args+"${args[@]}"} 70 | 71 | if [ $# -le 0 ]; then 72 | err "Must specify at least one port" 73 | return 1 74 | fi 75 | 76 | success=0 77 | 78 | # prepare the log file and make sure to start with an empty one 79 | mkdir -p "$option_log_dir" 80 | > "$log_subports_progress" 81 | 82 | print-subports "${option_archive_site}" "${option_archive_site_private}" "${option_include_deps}" "$*" && success=1 83 | 84 | if [ $success -eq 0 ]; then 85 | err "None of the specified ports were found in the port index." 86 | return 1 87 | fi 88 | } 89 | -------------------------------------------------------------------------------- /mpbb-mirror-distfiles: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | mirror-distfiles-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] mirror-distfiles [ [...]] 13 | 14 | Mirror the distfiles of each given port and their recursive dependencies. 15 | 16 | Options: 17 | 18 | --distfiles-dir= 19 | A directory for storing the distfiles. Defaults to the 20 | \`var/macports/distfiles' subdirectory of the \`--prefix' directory. If 21 | changed, deletes the \`var/macports/distfiles' directory and replaces it 22 | with a symlink to the specified directory. 23 | 24 | Run \`$prog help' for global options and a list of other subcommands. 25 | EOF 26 | } 27 | 28 | mirror-distfiles() { 29 | local args 30 | parseopt distfiles-dir: "$@" || return 31 | default_distfiles_dir="${option_prefix}"/var/macports/distfiles 32 | : "${option_distfiles_dir=${default_distfiles_dir}}" 33 | set -- ${args+"${args[@]}"} 34 | 35 | if [ ! -d "${option_distfiles_dir}" ]; then 36 | err "Distfiles directory \`${option_distfiles_dir}' does not exist" 37 | return 1 38 | fi 39 | 40 | if [ $# -le 0 ]; then 41 | err "Must specify at least one port" 42 | return 1 43 | fi 44 | 45 | if [ "${option_distfiles_dir}" = "${default_distfiles_dir}" ]; then 46 | if [ -L "${default_distfiles_dir}" ]; then 47 | msg "Removing symlink \`${default_distfiles_dir}' and creating directory" 48 | rm -f "${default_distfiles_dir}" 49 | mkdir "${default_distfiles_dir}" || return 50 | fi 51 | else 52 | make_symlink=0 53 | if [ -L "${default_distfiles_dir}" ]; then 54 | distfiles_link_target="$(readlink -n "${default_distfiles_dir}")" 55 | if [ "${distfiles_link_target}" != "${option_distfiles_dir}" ]; then 56 | msg "Changing \`${default_distfiles_dir}' symlink from \`${distfiles_link_target}' to \`${option_distfiles_dir}'" 57 | rm -f "${default_distfiles_dir}" 58 | make_symlink=1 59 | fi 60 | elif [ -d "${default_distfiles_dir}" ]; then 61 | msg "Removing directory \`${default_distfiles_dir}' and replacing it with a symlink to \`${option_distfiles_dir}'" 62 | rm -rvf "${default_distfiles_dir}" | sed 's/^/Deleting /' 63 | make_symlink=1 64 | else 65 | msg "Making \`${default_distfiles_dir}' a symlink to \`${option_distfiles_dir}'" 66 | make_symlink=1 67 | fi 68 | if [ ${make_symlink} -eq 1 ]; then 69 | ln -s "${option_distfiles_dir}" "${default_distfiles_dir}" || return 70 | fi 71 | fi 72 | 73 | # Mirror the distfiles. 74 | # $option_prefix is set by mpbb 75 | # shellcheck disable=SC2154 76 | "${option_prefix}/bin/port-tclsh" "${thisdir}/tools/mirror-multi.tcl" -c "${option_work_dir}/mirrorcache" "$@" 77 | #"${option_prefix}/bin/port" -p mirror "$@" $("${option_prefix}/bin/port" -pq rdeps --index "$@" | sed -E -e '/^--$/d' -e 's/^[[:space:]]+//' | sort -u) 78 | } 79 | -------------------------------------------------------------------------------- /mpbb-print-info: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | print-info-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] print-info [] 13 | 14 | Prints the macOS and Xcode versions and the version, revision, variants, 15 | and last modified commit of the port if given. 16 | 17 | Run \`$prog help' for global options and a list of other subcommands. 18 | EOF 19 | } 20 | 21 | print-info() { 22 | local port=${1-} 23 | if [[ -n $port ]]; then 24 | local portversion portrevision portvariants portdir portcommit 25 | 26 | # $option_prefix is set in mpbb 27 | # shellcheck disable=SC2154 28 | if portversion=$("${option_prefix}/bin/port" info --index --line --version "$port"); then 29 | printf "portversion=%s\n" "$portversion" 30 | fi 31 | 32 | # $option_prefix is set in mpbb 33 | # shellcheck disable=SC2154 34 | if portrevision=$("${option_prefix}/bin/port" info --index --line --revision "$port"); then 35 | printf "portrevision=%s\n" "$portrevision" 36 | fi 37 | 38 | # $option_prefix is set in mpbb 39 | # shellcheck disable=SC2154 40 | if portvariants=$("${option_prefix}/bin/port-tclsh" tools/canonical-variants.tcl "$port"); then 41 | printf "portvariants=%s\n" "$portvariants" 42 | fi 43 | 44 | # $option_prefix is set in mpbb 45 | # shellcheck disable=SC2154 46 | if portdir=$("${option_prefix}/bin/port" dir "$port"); then 47 | if portcommit=$(git -C "$portdir" log -n 1 --pretty=format:%H .); then 48 | printf "portcommit=%s\n" "$portcommit" 49 | fi 50 | fi 51 | fi 52 | 53 | if command -v sw_vers >/dev/null; then 54 | local macosversion macosbuild 55 | 56 | if macosversion=$(sw_vers -productVersion); then 57 | if macosbuild=$(sw_vers -buildVersion); then 58 | printf "macosversion=%s (%s)\n" "$macosversion" "$macosbuild" 59 | else 60 | printf "macosversion=%s\n" "$macosversion" 61 | fi 62 | fi 63 | fi 64 | 65 | if command -v xcodebuild >/dev/null; then 66 | local xcodeversion xcodebuild 67 | 68 | if xcodeversion=$(xcodebuild -version | sed -En 's,^Xcode (.*)$,\1,p'); then 69 | if xcodebuild=$(xcodebuild -version | sed -En 's,^Build ?[Vv]ersion:? (.*)$,\1,p'); then 70 | printf "xcodeversion=%s (%s)\n" "$xcodeversion" "$xcodebuild" 71 | else 72 | printf "xcodeversion=%s\n" "$xcodeversion" 73 | fi 74 | fi 75 | fi 76 | } 77 | -------------------------------------------------------------------------------- /mpbb-selfupdate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | selfupdate-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] selfupdate 13 | 14 | Install or update the auxiliary MacPorts base installation. (To reindex 15 | port sources, use \`$prog checkout'.) 16 | 17 | Run \`$prog help' for global options and a list of other subcommands. 18 | EOF 19 | } 20 | 21 | selfupdate() { 22 | # $option_prefix is set in mpbb 23 | # shellcheck disable=SC2154 24 | if [ ! -f "${option_prefix}/bin/port" ]; then 25 | macports_version=2.10.5 26 | macports_distname=MacPorts-${macports_version} 27 | macports_distfile=${macports_distname}.tar.bz2 28 | if [ ! -d ${macports_distname} ]; then 29 | if [ ! -f ${macports_distfile} ]; then 30 | curl -fsLO https://distfiles.macports.org/MacPorts/${macports_distfile} || return 31 | fi 32 | tar -xjf ${macports_distfile} || return 33 | fi 34 | cd ${macports_distname} || return 35 | if [ "${option_prefix}" != "/opt/local" ]; then 36 | applications_dir_flag="--with-applications-dir=${option_prefix}/Applications/MacPorts" 37 | fi 38 | : "${applications_dir_flag=}" 39 | if [ "$(id -u)" -ne 0 ]; then 40 | install_user_and_group_flags="--with-install-user=$(id -un) --with-install-group=$(id -gn)" 41 | fi 42 | : "${install_user_and_group_flags=}" 43 | PATH=/usr/bin:/bin:/usr/sbin:/sbin ./configure \ 44 | --prefix="${option_prefix}" \ 45 | ${applications_dir_flag} \ 46 | ${install_user_and_group_flags} \ 47 | --enable-readline || return 48 | make -j"$(sysctl -n hw.activecpu)" || return 49 | make install || return 50 | cd .. || return 51 | rm -rf ${macports_distfile} ${macports_distname} || return 52 | fi 53 | 54 | # selfupdate at most once every 12 hours 55 | if [[ ! -f selfupdate.timestamp || $(($(date +%s) - $(stat -f %m selfupdate.timestamp))) -gt 43200 ]]; then 56 | "${option_prefix}/bin/port" -d selfupdate --no-sync || return 57 | touch selfupdate.timestamp 58 | fi 59 | } 60 | -------------------------------------------------------------------------------- /mpbb-show-config-logs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | show-config-logs-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] port-show-config-logs 13 | 14 | Show the config.log files of the given port. 15 | 16 | Run \`$prog help' for global options and a list of other subcommands. 17 | EOF 18 | } 19 | 20 | show-config-logs() { 21 | local port=${1-} 22 | if [[ -z $port ]]; then 23 | err "Must specify a port" 24 | return 1 25 | fi 26 | 27 | # $option_prefix is set in mpbb 28 | # shellcheck disable=SC2154 29 | workpath=$("${option_prefix}/bin/port" work "$port") || return 30 | if [[ -n $workpath ]]; then 31 | cd "$workpath" 32 | find -s . -name config.log -print0 \ 33 | | xargs -0 -n 1 -I @ sh -c \ 34 | 'printf -- "%s:\n" "@" 1>&2; \ 35 | cat "@"; \ 36 | printf "\n"' 37 | fi 38 | } 39 | -------------------------------------------------------------------------------- /mpbb-test-port: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- coding: utf-8; mode: sh; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=sh:et:sw=4:ts=4:sts=4 3 | 4 | # Note: 5 | # This script is sourced by the mpbb wrapper script. 6 | # Do not execute this directly! 7 | 8 | test-port-usage() { 9 | # "prog" is defined in mpbb-help. 10 | # shellcheck disable=SC2154 11 | cat <] test-port 13 | 14 | Run tests for the given port. 15 | 16 | Options: 17 | 18 | --builtin-only 19 | Run only built-in tests, skipping those defined in the Portfile. 20 | 21 | Run \`$prog help' for global options and a list of other subcommands. 22 | EOF 23 | } 24 | 25 | test-port() { 26 | local args 27 | parseopt builtin-only "$@" || return 28 | # $option_builtin_only is set by parseopt 29 | # shellcheck disable=SC2154 30 | : "${option_builtin_only=0}" 31 | set -- ${args+"${args[@]}"} 32 | local test_run_flag 33 | [[ "${option_builtin_only}" -eq 1 ]] && test_run_flag="test.run=no depends_test=''" 34 | local port=${1-} 35 | if [[ -z "$port" ]]; then 36 | err "Must specify a port" 37 | return 1 38 | fi 39 | # $option_log_dir is set in mpbb 40 | # shellcheck disable=SC2154 41 | #local log_subports_progress="${option_log_dir}/ports-progress.txt" 42 | 43 | # prepare the log files and make sure to start with empty ones 44 | mkdir -p "${option_log_dir}" 45 | 46 | # $option_prefix is set in mpbb 47 | # shellcheck disable=SC2154 48 | if ! "${option_prefix}/bin/port" -dkn test "$@" ${test_run_flag}; then 49 | echo "Testing '$port' failed." 50 | # log: summary for the portwatcher 51 | #echo "Testing '$port' ... [FAIL] maintainers: $(get-maintainers "$port")." >> "$log_subports_progress" 52 | return 1 53 | fi 54 | 55 | # log: summary for the portwatcher 56 | #echo "Testing '$port' ... [OK]" >> "$log_subports_progress" 57 | } 58 | -------------------------------------------------------------------------------- /tools/archive-path.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # 3 | # Prints the archive filename for the given port with the given variants. 4 | # 5 | # Copyright © 2013, 2016 The MacPorts Project. 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions 9 | # are met: 10 | # 1. Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # 2. Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # 3. Neither the name of the MacPorts project, nor the names of any contributors 17 | # may be used to endorse or promote products derived from this software 18 | # without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 21 | # AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 24 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 | # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 29 | # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 30 | # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | proc split_variants {variants} { 33 | set result [dict create] 34 | set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants] 35 | foreach { match sign variant } $l { 36 | dict set result $variant $sign 37 | } 38 | return $result 39 | } 40 | 41 | package require macports 42 | 43 | if {[catch {mportinit "" "" ""} result]} { 44 | ui_error "$errorInfo" 45 | ui_error "Failed to initialize ports system: $result" 46 | exit 1 47 | } 48 | 49 | set portname [lindex $::argv 0] 50 | if {[llength $::argv] > 1} { 51 | set variations [split_variants [lindex $::argv 1]] 52 | } else { 53 | set variations "" 54 | } 55 | 56 | if {[catch {set one_result [mportlookup $portname]}] || [llength $one_result] < 2} { 57 | # just print whatever, mpbb will notice the missing port itself 58 | puts "nonexistent" 59 | exit 0 60 | } 61 | 62 | lassign $one_result portname portinfo 63 | if {[dict exists $portinfo porturl]} { 64 | if {[catch {set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variations]}]} { 65 | ui_warn "failed to open port: $portname" 66 | puts "nonexistent" 67 | exit 0 68 | } else { 69 | set workername [ditem_key $mport workername] 70 | puts [$workername eval get_portimage_path] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tools/canonical-variants.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 3 | # 4 | # Writes the canonical list of variants as it appears in binary archive names 5 | # to stdout. 6 | # 7 | # Copyright (c) 2016 The MacPorts Project. 8 | # Copyright (c) 2016 Clemens Lang 9 | # 10 | # Redistribution and use in source and binary forms, with or without 11 | # modification, are permitted provided that the following conditions 12 | # are met: 13 | # 1. Redistributions of source code must retain the above copyright 14 | # notice, this list of conditions and the following disclaimer. 15 | # 2. Redistributions in binary form must reproduce the above copyright 16 | # notice, this list of conditions and the following disclaimer in 17 | # the documentation and/or other materials provided with the 18 | # distribution. 19 | # 3. Neither the name of the MacPorts project, nor the names of any contributors 20 | # may be used to endorse or promote products derived from this software 21 | # without specific prior written permission. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 24 | # AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 27 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 30 | # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 32 | # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 33 | # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | 35 | package require macports 36 | 37 | if {[llength $::argv] == 0} { 38 | puts stderr "Usage: $argv0 \[(+|-)variant...\]" 39 | exit 1 40 | } 41 | 42 | # initialize macports 43 | if {[catch {mportinit "" "" ""} result]} { 44 | ui_error "$errorInfo" 45 | ui_error "Failed to initialize ports sytem: $result" 46 | exit 1 47 | } 48 | 49 | # look up the path of the Portfile for the given port 50 | set portname [lindex $::argv 0] 51 | #try -pass_signal {...} 52 | try { 53 | set result [mportlookup $portname] 54 | if {[llength $result] < 2} { 55 | ui_error "No such port: $portname" 56 | exit 1 57 | } 58 | } on error {eMessage} { 59 | ui_error "mportlookup $portname failed: $eMessage" 60 | exit 1 61 | } 62 | 63 | # parse the given variants from the command line 64 | set variants [dict create] 65 | foreach item [lrange $::argv 1 end] { 66 | foreach {_ sign variant} [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $item] { 67 | dict set variants $variant $sign 68 | } 69 | } 70 | 71 | # open the port to get its active variants 72 | lassign $result portname portinfo 73 | #try -pass_signal {...} 74 | try { 75 | set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variants] 76 | } on error {eMessage} { 77 | ui_error "mportopen $portname from [dict get $portinfo porturl] failed: $eMessage" 78 | exit 1 79 | } 80 | 81 | set portinfo [mportinfo $mport] 82 | puts [dict get $portinfo canonical_active_variants] 83 | -------------------------------------------------------------------------------- /tools/dependencies.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 3 | # 4 | # Ensure that all dependencies needed to install a given port are active. 5 | # 6 | # Copyright (c) 2016 The MacPorts Project. 7 | # Copyright (c) 2016 Clemens Lang 8 | # 9 | # Redistribution and use in source and binary forms, with or without 10 | # modification, are permitted provided that the following conditions 11 | # are met: 12 | # 1. Redistributions of source code must retain the above copyright 13 | # notice, this list of conditions and the following disclaimer. 14 | # 2. Redistributions in binary form must reproduce the above copyright 15 | # notice, this list of conditions and the following disclaimer in 16 | # the documentation and/or other materials provided with the 17 | # distribution. 18 | # 3. Neither the name of the MacPorts project, nor the names of any contributors 19 | # may be used to endorse or promote products derived from this software 20 | # without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 23 | # AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 26 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 29 | # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 32 | # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | set start_time [clock seconds] 35 | 36 | package require macports 37 | package require registry2 38 | 39 | source [file join [file dirname [info script]] failcache.tcl] 40 | 41 | set failcache_dir "" 42 | set logs_dir "" 43 | while {[string range [lindex $argv 0] 0 1] eq "--"} { 44 | switch -- [lindex $argv 0] { 45 | --failcache_dir { 46 | set failcache_dir [lindex $argv 1] 47 | set argv [lreplace $argv 0 0] 48 | } 49 | --logs_dir { 50 | set logs_dir [lindex $argv 1] 51 | set argv [lreplace $argv 0 0] 52 | } 53 | default { 54 | ui_error "unknown option: [lindex $argv 0]" 55 | exit 2 56 | } 57 | } 58 | set argv [lreplace $argv 0 0] 59 | } 60 | 61 | if {$logs_dir ne ""} { 62 | set log_status_dependencies [open ${logs_dir}/dependencies-progress.txt w] 63 | set log_subports_progress [open ${logs_dir}/ports-progress.txt a] 64 | } else { 65 | set log_status_dependencies [open /dev/null a] 66 | set log_subports_progress $log_status_dependencies 67 | } 68 | 69 | if {[llength $argv] == 0} { 70 | puts stderr "Usage: $argv0 \[(+|-)variant...\]" 71 | exit 2 72 | } 73 | 74 | # initialize macports 75 | set my_global_options(ports_nodeps) yes 76 | if {[catch {mportinit "" my_global_options ""} result]} { 77 | ui_error "$errorInfo" 78 | ui_error "Failed to initialize ports system: $result" 79 | exit 2 80 | } 81 | 82 | # look up the path of the Portfile for the given port 83 | set portname [lindex $argv 0] 84 | #try -pass_signal {...} 85 | try { 86 | set result [mportlookup $portname] 87 | if {[llength $result] < 2} { 88 | ui_error "No such port: $portname" 89 | exit 1 90 | } 91 | } on error {eMessage} { 92 | ui_error "mportlookup $portname failed: $eMessage" 93 | exit 2 94 | } 95 | 96 | # parse the given variants from the command line 97 | set variants [dict create] 98 | foreach item [lrange $argv 1 end] { 99 | foreach {_ sign variant} [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $item] { 100 | dict set variants $variant $sign 101 | } 102 | } 103 | 104 | # open the port so we can run dependency calculation 105 | lassign $result portname portinfo 106 | #try -pass_signal {...} 107 | try { 108 | set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variants] 109 | } on error {eMessage} { 110 | ui_error "mportopen of $portname from [dict get $portinfo porturl] failed: $eMessage" 111 | exit 2 112 | } 113 | 114 | set portinfo [dict merge $portinfo [mportinfo $mport]] 115 | # Also checking for matching archive, in case supported_archs changed 116 | if {[registry::entry imaged $portname [dict get $portinfo version] [dict get $portinfo revision] [dict get $portinfo canonical_active_variants]] ne "" 117 | && [[ditem_key $mport workername] eval [list _archive_available]]} { 118 | puts "$argv already installed, not installing or activating dependencies" 119 | exit 0 120 | } 121 | # Ensure build-time deps are always included for the top-level port, 122 | # because CI will do a build of all ports affected by a commit even if 123 | # the version hasn't changed and an archive is available. This 124 | # shouldn't result in unnecessary installations, because the check 125 | # above will skip installing deps for already installed ports, and the 126 | # buildbot will exclude ports that have an archive deployed. 127 | [ditem_key $mport workername] eval [list set portutil::archive_available_result 0] 128 | 129 | foreach p [split $env(PATH) :] { 130 | if {![string match ${macports::prefix}* $p]} { 131 | lappend bin_search_path $p 132 | } 133 | } 134 | 135 | # check if depspec is fulfilled by a port, and if so, append its 136 | # name to the variable named by retvar 137 | proc check_dep_needs_port {depspec retvar} { 138 | upvar $retvar ret 139 | set splitlist [split $depspec :] 140 | set portname [lindex $splitlist end] 141 | set depregex [lindex $splitlist 1] 142 | switch [lindex $splitlist 0] { 143 | bin { 144 | global bin_search_path 145 | set depregex \^$depregex\$ 146 | set search_path $bin_search_path 147 | set executable 1 148 | } 149 | lib { 150 | set search_path {/Library/Frameworks /System/Library/Frameworks /lib /usr/lib} 151 | set i [string first . $depregex] 152 | if {$i < 0} {set i [string length $depregex]} 153 | set depname [string range $depregex 0 ${i}-1] 154 | set depversion [string range $depregex $i end] 155 | regsub {\.} $depversion {\.} depversion 156 | set depregex \^${depname}${depversion}\\.dylib\$ 157 | set executable 0 158 | } 159 | path { 160 | # separate directory from regex 161 | set fullname $depregex 162 | regexp {^(.*)/(.*?)$} $fullname match search_path depregex 163 | if {[string index $search_path 0] ne "/" 164 | || [string match ${macports::prefix}* $search_path]} { 165 | # Path in prefix, can be assumed to be from a port 166 | lappend ret $portname 167 | return 168 | } 169 | set depregex \^$depregex\$ 170 | set executable 0 171 | } 172 | port { 173 | lappend ret $portname 174 | return 175 | } 176 | } 177 | if {![_mportsearchpath $depregex $search_path $executable]} { 178 | lappend ret $portname 179 | } 180 | } 181 | 182 | # Get the ports needed by a given port. 183 | proc collect_deps {portinfo retvar} { 184 | upvar $retvar ret 185 | # Recursive deps are not being built, so only their runtime deps are needed. 186 | foreach deptype {depends_lib depends_run} { 187 | if {[dict exists $portinfo $deptype]} { 188 | foreach depspec [dict get $portinfo $deptype] { 189 | check_dep_needs_port $depspec ret 190 | } 191 | } 192 | } 193 | } 194 | 195 | # return maintainer email addresses for the given port names 196 | proc get_maintainers {args} { 197 | set retlist [list] 198 | foreach portname $args { 199 | try { 200 | set result [mportlookup $portname] 201 | if {[llength $result] < 2} { 202 | continue 203 | } 204 | } on error {eMessage} { 205 | ui_error "mportlookup $portname failed: $eMessage" 206 | continue 207 | } 208 | set portinfo [lindex $result 1] 209 | foreach maintainer [macports::unobscure_maintainers [dict get $portinfo maintainers]] { 210 | if {[dict exists $maintainer email]} { 211 | lappend retlist [dict get $maintainer email] 212 | } 213 | } 214 | } 215 | return [join $retlist ,] 216 | } 217 | 218 | proc open_port {portname {variations {}}} { 219 | try { 220 | set result [mportlookup $portname] 221 | if {[llength $result] < 2} { 222 | ui_error "No such port: $portname" 223 | puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (unknown dependency '$portname') maintainers: [get_maintainers $::portname]." 224 | exit 1 225 | } 226 | } on error {eMessage} { 227 | ui_error "mportlookup $portname failed: $eMessage" 228 | exit 2 229 | } 230 | lassign $result portname portinfo 231 | try { 232 | set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variations] 233 | } on error {eMessage} { 234 | ui_error "mportopen $portname from [dict get $portinfo porturl] failed: $eMessage" 235 | exit 2 236 | } 237 | 238 | set portinfo [dict merge $portinfo [mportinfo $mport]] 239 | dict set portinfo requested_variations $variations 240 | global mportinfo_array 241 | if {![dict exists $mportinfo_array $mport]} { 242 | dict set mportinfo_array $mport $portinfo 243 | } 244 | return [list $mport $portinfo] 245 | } 246 | 247 | # Deactivate the given port, first deactivating any active dependents 248 | # it has. 249 | proc deactivate_with_dependents {e} { 250 | if {[$e state] ne "installed"} { 251 | return 252 | } 253 | foreach dependent [$e dependents] { 254 | deactivate_with_dependents $dependent 255 | } 256 | set options [dict create ports_nodepcheck 1] 257 | if {![registry::run_target $e deactivate $options] 258 | && [catch {portimage::deactivate [$e name] [$e version] [$e revision] [$e variants] $options} result]} { 259 | puts stderr $::errorInfo 260 | puts stderr "Deactivating [$e name] @[$e version]_[$e revision][$e variants] failed: $result" 261 | exit 2 262 | } 263 | } 264 | 265 | proc deactivate_unneeded {portinfo} { 266 | global mportinfo_array 267 | # Unfortunately mportdepends doesn't have quite the right semantics 268 | # to be useful here. It's concerned with what is needed and not 269 | # present, whereas here we're concerned with removing what we can do 270 | # without. Future API opportunity? 271 | set deplist [list] 272 | # The top level port is being built, so all build time and run time deps are needed. 273 | foreach deptype {depends_fetch depends_extract depends_patch depends_build depends_lib depends_run} { 274 | if {[dict exists $portinfo $deptype]} { 275 | foreach depspec [dict get $portinfo $deptype] { 276 | check_dep_needs_port $depspec deplist 277 | } 278 | } 279 | } 280 | set needed_array [dict create] 281 | set mports_array [dict create] 282 | while {$deplist ne ""} { 283 | set dep [lindex $deplist end] 284 | set deplist [lreplace ${deplist}[set deplist {}] end end] 285 | if {![dict exists $needed_array $dep]} { 286 | dict set needed_array $dep 1 287 | set needed [list] 288 | lassign [open_port $dep] mport depportinfo 289 | dict set mports_array $dep $mport 290 | collect_deps $depportinfo needed 291 | foreach newdep $needed { 292 | if {![dict exists $needed_array $newdep]} { 293 | lappend deplist $newdep 294 | } 295 | } 296 | } 297 | } 298 | 299 | set dependents_check_list [list] 300 | puts "Deactivating unneeded ports:" 301 | foreach e [registry::entry installed] { 302 | # Deactivate everything we don't need and also ports we do need that 303 | # are active with an old version or non-default variants. The 304 | # latter will reduce performance for universal installations a 305 | # bit, but those are much less common and this ensures 306 | # consistent behaviour. 307 | if {![dict exists $needed_array [$e name]]} { 308 | deactivate_with_dependents $e 309 | } else { 310 | set entryinfo [dict get $mportinfo_array [dict get $mports_array [$e name]]] 311 | if {[dict get $entryinfo version] ne [$e version] 312 | || [dict get $entryinfo revision] != [$e revision] 313 | || [dict get $entryinfo canonical_active_variants] ne [$e variants]} { 314 | lappend dependents_check_list $e 315 | puts stderr "[$e name] installed version @[$e version]_[$e revision][$e variants] doesn't match tree version [dict get $entryinfo version]_[dict get $entryinfo revision][dict get $entryinfo canonical_active_variants]" 316 | } 317 | } 318 | } 319 | # also deactivate dependents of any needed deactivated ports 320 | if {$dependents_check_list ne ""} { 321 | puts "Deactivating ports with outdated versions/variants and their dependents:" 322 | } 323 | foreach e $dependents_check_list { 324 | deactivate_with_dependents $e 325 | } 326 | # For ports that remain active, close the mport that was opened 327 | # earlier - it most likely won't be used again (and will be 328 | # reopened in the uncommon case that it is needed.) 329 | foreach e [registry::entry installed] { 330 | mportclose [dict get $mports_array [$e name]] 331 | } 332 | } 333 | 334 | puts stderr "init took [expr {[clock seconds] - $start_time}] seconds" 335 | set start_time [clock seconds] 336 | 337 | set mportinfo_array [dict create] 338 | if {[catch {deactivate_unneeded $portinfo} result]} { 339 | ui_error $::errorInfo 340 | ui_error "deactivate_unneeded failed: $result" 341 | exit 2 342 | } 343 | 344 | puts stderr "deactivating unneeded ports took [expr {[clock seconds] - $start_time}] seconds" 345 | set start_time [clock seconds] 346 | 347 | # gather a list of dependencies with the correct variants (+universal is dealt 348 | # with in specific ways) 349 | set dlist [list] 350 | if {[catch {mportdepends $mport "activate" 1 1 0 dlist} result]} { 351 | ui_error $::errorInfo 352 | ui_error "mportdepends $portname activate failed: $result" 353 | exit 2 354 | } elseif {$result != 0} { 355 | ui_error "mportdepends $portname activate failed: $result" 356 | exit 2 357 | } 358 | 359 | 360 | proc append_it {ditem} { 361 | global dlist_sorted mportinfo_array 362 | lappend dlist_sorted $ditem 363 | set this_portinfo [mportinfo $ditem] 364 | dict set this_portinfo requested_variations [ditem_key $ditem variations] 365 | dict set mportinfo_array $ditem $this_portinfo 366 | return 0 367 | } 368 | try { 369 | # produce a list of deps in sorted order 370 | set dlist_sorted [list] 371 | dlist_eval $dlist {} [list append_it] 372 | unset dlist 373 | } on error {eMessage} { 374 | ui_error "sorting dlist failed: $eMessage" 375 | exit 2 376 | } 377 | 378 | puts stderr "calculating deps took [expr {[clock seconds] - $start_time}] seconds" 379 | set start_time [clock seconds] 380 | 381 | # print a message to two channels 382 | proc tee {msg ch1 ch2} { 383 | puts $ch1 $msg 384 | puts $ch2 $msg 385 | } 386 | 387 | set dependencies_count [llength $dlist_sorted] 388 | tee "Installing $dependencies_count dependencies of $portname:" $log_status_dependencies stdout 389 | foreach ditem $dlist_sorted { 390 | tee "[ditem_key $ditem provides] [_mportkey $ditem PortInfo(canonical_active_variants)]" $log_status_dependencies stdout 391 | } 392 | puts $log_status_dependencies "" 393 | 394 | ## ensure dependencies are installed and active 395 | proc checkdep_failcache {ditem} { 396 | global mportinfo_array 397 | set depinfo [dict get $mportinfo_array $ditem] 398 | 399 | if {[check_failcache [dict get $depinfo name] [ditem_key $ditem porturl] [dict get $depinfo canonical_active_variants]]} { 400 | tee "Dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' has previously failed and is required." $::log_status_dependencies stderr 401 | puts "Port [dict get $depinfo name] previously failed in build [check_failcache [dict get $depinfo name] [ditem_key $ditem porturl] [dict get $depinfo canonical_active_variants] yes]" 402 | puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to install dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]." 403 | # could keep going to report all deps in the failcache, but failing fast seems better 404 | exit 1 405 | } 406 | } 407 | 408 | if {$failcache_dir ne ""} { 409 | try { 410 | foreach ditem $dlist_sorted { 411 | checkdep_failcache $ditem 412 | } 413 | } on error {eMessage} { 414 | ui_error "checkdep_failcache failed: $eMessage" 415 | exit 2 416 | } 417 | puts stderr "checking failcache took [expr {[clock seconds] - $start_time}] seconds" 418 | set start_time [clock seconds] 419 | } 420 | 421 | # clean up any work directories left over from earlier 422 | # (avoids possible errors with different variants in the statefile) 423 | proc clean_workdirs {} { 424 | global macports::portdbpath 425 | set build_dir [file join $portdbpath build] 426 | foreach dir [glob -nocomplain -directory $build_dir *] { 427 | file delete -force -- $dir 428 | } 429 | } 430 | 431 | # Returns 0 if dep is installed, 1 if not 432 | proc install_dep_archive {ditem} { 433 | global mportinfo_array dependencies_counter dependencies_count \ 434 | log_status_dependencies 435 | set depinfo [dict get $mportinfo_array $ditem] 436 | incr dependencies_counter 437 | set msg "Installing dependency ($dependencies_counter of $dependencies_count) '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]'" 438 | puts -nonewline $log_status_dependencies "$msg ... " 439 | puts "----> ${msg}" 440 | if {[registry::entry imaged [dict get $depinfo name] [dict get $depinfo version] [dict get $depinfo revision] [dict get $depinfo canonical_active_variants]] ne ""} { 441 | puts "Already installed, nothing to do" 442 | puts $log_status_dependencies {[OK]} 443 | return 0 444 | } 445 | clean_workdirs 446 | set fail 0 447 | set workername [ditem_key $ditem workername] 448 | 449 | # First fetch the archive 450 | if {[catch {mportexec $ditem archivefetch} result]} { 451 | puts stderr $::errorInfo 452 | ui_error "Archivefetch failed: $result" 453 | set fail 1 454 | } 455 | if {$fail || $result > 0 || [$workername eval [list find_portarchive_path]] eq ""} { 456 | # The known_fail case should normally be caught before now, but 457 | # it's quick and easy to check and may save a build. 458 | if {[dict exists $depinfo known_fail] && [string is true -strict [dict get $depinfo known_fail]]} { 459 | puts stderr "Dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' is known to fail, aborting." 460 | puts $log_status_dependencies {[FAIL] (known_fail)} 461 | puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (dependency '[dict get $depinfo name]' known to fail) maintainers: [get_maintainers $::portname [dict get $depinfo name]]." 462 | exit 1 463 | } 464 | # This dep will have to be built, not just installed 465 | puts stderr "Fetching archive for dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed." 466 | puts $log_status_dependencies {[MISSING]} 467 | return 1 468 | } 469 | # Now install it 470 | if {[catch {$workername eval [list eval_targets install]} result]} { 471 | puts stderr $::errorInfo 472 | ui_error "Install failed: $result" 473 | set fail 1 474 | } 475 | if {$fail || $result > 0} { 476 | puts stderr "Installing from archive for dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting." 477 | puts $log_status_dependencies {[FAIL]} 478 | puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to install dependency '[dict get $depinfo name]')." 479 | exit 1 480 | } 481 | 482 | puts $log_status_dependencies {[OK]} 483 | return 0 484 | } 485 | 486 | # mportexec uses this global variable, so we have to clean up between 487 | # doing operations (that require deps) on different ports. 488 | proc close_open_mports {} { 489 | global macports::open_mports 490 | foreach mport $open_mports { 491 | catch {ditem_key $mport refcnt 1} 492 | catch {mportclose $mport} 493 | } 494 | set open_mports [list] 495 | } 496 | 497 | proc install_dep_source {depinfo} { 498 | global build_counter build_count log_status_dependencies \ 499 | mportinfo_array failcache_dir 500 | incr build_counter 501 | set msg "Building dependency ($build_counter of $build_count) '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]'" 502 | puts -nonewline $log_status_dependencies "$msg ... " 503 | puts "----> ${msg}" 504 | 505 | # Be quiet during the prep operations 506 | set macports::channels(debug) {} 507 | set macports::channels(info) {} 508 | close_open_mports 509 | clean_workdirs 510 | set mportinfo_array [dict create] 511 | set requested_variations [expr {[dict exists $depinfo requested_variations] ? [dict get $depinfo requested_variations] : {}}] 512 | set ditem [lindex [open_port [dict get $depinfo name] $requested_variations] 0] 513 | # Ensure archivefetch is not attempted at all 514 | set workername [ditem_key $ditem workername] 515 | $workername eval [list set portutil::archive_available_result 0] 516 | $workername eval [list archive_sites] 517 | 518 | # deactivate ports not needed for this dep 519 | if {[catch {deactivate_unneeded $depinfo} result]} { 520 | ui_error $::errorInfo 521 | ui_error "deactivate_unneeded failed: $result" 522 | exit 2 523 | } 524 | 525 | # Show all output for the installation 526 | set macports::channels(debug) stderr 527 | set macports::channels(info) stdout 528 | 529 | set fail 0 530 | # Fetch and checksum the distfiles 531 | if {[catch {mportexec $ditem fetch} result]} { 532 | puts stderr $::errorInfo 533 | ui_error "Fetch failed: $result" 534 | set fail 1 535 | } 536 | if {$fail || $result > 0} { 537 | puts stderr "Fetch of dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting." 538 | puts $log_status_dependencies {[FAIL] (fetch)} 539 | puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to fetch dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]." 540 | exit 1 541 | } 542 | if {[catch {mportexec $ditem checksum} result]} { 543 | puts stderr $::errorInfo 544 | ui_error "Checksum failed: $result" 545 | set fail 1 546 | } 547 | if {$fail || $result > 0} { 548 | puts stderr "Checksum of dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting." 549 | puts $log_status_dependencies {[FAIL] (checksum)} 550 | puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to checksum dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]." 551 | exit 1 552 | } 553 | 554 | # Now install 555 | if {[catch {mportexec $ditem install} result]} { 556 | puts stderr $::errorInfo 557 | ui_error "Install failed: $result" 558 | set fail 1 559 | } 560 | if {$fail || $result > 0} { 561 | puts stderr "Build of dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting." 562 | puts $log_status_dependencies {[FAIL]} 563 | puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to install dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]." 564 | 565 | if {$failcache_dir ne ""} { 566 | failcache_update [dict get $depinfo name] [ditem_key $ditem porturl] [dict get $depinfo canonical_active_variants] 1 567 | } 568 | #ui_debug "Open mports:" 569 | #foreach mport $macports::open_mports { 570 | # ui_debug [ditem_key $ditem] 571 | #} 572 | exit 1 573 | } 574 | 575 | # Success. Clear any failcache entry. 576 | if {$failcache_dir ne ""} { 577 | failcache_update [dict get $depinfo name] [ditem_key $ditem porturl] [dict get $depinfo canonical_active_variants] 0 578 | } 579 | puts $log_status_dependencies {[OK]} 580 | } 581 | 582 | # Show all output for anything that gets installed 583 | set macports::channels(debug) stderr 584 | set macports::channels(info) stdout 585 | set dependencies_counter 0 586 | set missing_deps [list] 587 | try { 588 | foreach ditem $dlist_sorted { 589 | if {[install_dep_archive $ditem]} { 590 | lappend missing_deps [dict get $mportinfo_array $ditem] 591 | } 592 | } 593 | } on error {eMessage} { 594 | ui_error "install_dep_archive failed: $eMessage" 595 | exit 2 596 | } 597 | 598 | puts stderr "installing deps took [expr {[clock seconds] - $start_time}] seconds" 599 | set start_time [clock seconds] 600 | 601 | set build_count [llength $missing_deps] 602 | if {$build_count > 0} { 603 | # Some deps are neither installed nor able to be fetched as an archive. 604 | # This should ideally never happen since each dep should have had 605 | # its own build previously, but failures and out-of-order builds 606 | # do happen sometimes for various reasons. 607 | tee "Building $build_count dependencies of $portname:" $log_status_dependencies stdout 608 | set build_counter 0 609 | foreach missing_dep $missing_deps { 610 | install_dep_source $missing_dep 611 | } 612 | 613 | puts stderr "building missing deps took [expr {[clock seconds] - $start_time}] seconds" 614 | set start_time [clock seconds] 615 | 616 | # Now effectively start again for the main port. 617 | 618 | # Go back to being quiet 619 | set macports::channels(debug) {} 620 | set macports::channels(info) {} 621 | close_open_mports 622 | set mportinfo_array [dict create] 623 | try { 624 | set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variants] 625 | } on error {eMessage} { 626 | ui_error "mportopen $portname from [dict get $portinfo porturl] failed: $eMessage" 627 | exit 2 628 | } 629 | [ditem_key $mport workername] eval [list set portutil::archive_available_result 0] 630 | if {[catch {deactivate_unneeded $portinfo} result]} { 631 | ui_error $::errorInfo 632 | ui_error "deactivate_unneeded failed: $result" 633 | exit 2 634 | } 635 | 636 | puts stderr "deactivating unneeded ports (again) took [expr {[clock seconds] - $start_time}] seconds" 637 | set start_time [clock seconds] 638 | 639 | # gather a list of dependencies with the correct variants (+universal is dealt 640 | # with in specific ways) 641 | set dlist [list] 642 | if {[catch {mportdepends $mport "activate" 1 1 0 dlist} result]} { 643 | ui_error $::errorInfo 644 | ui_error "mportdepends $portname activate failed: $result" 645 | exit 2 646 | } elseif {$result != 0} { 647 | ui_error "mportdepends $portname activate failed: $result" 648 | exit 2 649 | } 650 | 651 | try { 652 | # produce a list of deps in sorted order 653 | set dlist_sorted [list] 654 | dlist_eval $dlist {} [list append_it] 655 | unset dlist 656 | } on error {eMessage} { 657 | ui_error "sorting dlist failed: $eMessage" 658 | exit 2 659 | } 660 | 661 | puts stderr "calculating deps (again) took [expr {[clock seconds] - $start_time}] seconds" 662 | set start_time [clock seconds] 663 | } else { 664 | # Go back to being quiet 665 | set macports::channels(debug) {} 666 | set macports::channels(info) {} 667 | } 668 | 669 | proc activate_dep {ditem} { 670 | set workername [ditem_key $ditem workername] 671 | set fail 0 672 | if {[catch {$workername eval [list eval_targets activate]} result]} { 673 | puts stderr $::errorInfo 674 | ui_error "Activate failed: $result" 675 | set fail 1 676 | } 677 | if {$fail || $result > 0} { 678 | set depinfo [dict get $::mportinfo_array $ditem] 679 | puts stderr "Activation of dependency '[dict get $depinfo name]' with variants '[dict get $depinfo canonical_active_variants]' failed, aborting." 680 | puts $::log_subports_progress "Building '$::portname' ... \[FAIL\] (failed to activate dependency '[dict get $depinfo name]') maintainers: [get_maintainers $::portname [dict get $depinfo name]]." 681 | exit 1 682 | } 683 | } 684 | 685 | puts "Activating all dependencies..." 686 | try { 687 | foreach ditem $dlist_sorted { 688 | activate_dep $ditem 689 | } 690 | } on error {eMessage} { 691 | ui_error "activate_dep failed: $eMessage" 692 | exit 2 693 | } 694 | 695 | puts stderr "activating deps took [expr {[clock seconds] - $start_time}] seconds" 696 | 697 | puts "Done." 698 | exit 0 699 | -------------------------------------------------------------------------------- /tools/failcache-cleanup.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # 3 | # clear out stale entries and entries for deleted ports from the failcache 4 | 5 | package require macports 6 | mportinit 7 | 8 | source [file join [file dirname [info script]] failcache.tcl] 9 | 10 | set failcache_dir "" 11 | while {[string range [lindex $::argv 0] 0 1] eq "--"} { 12 | switch -- [lindex $::argv 0] { 13 | --failcache_dir { 14 | set failcache_dir [lindex $::argv 1] 15 | set ::argv [lrange $::argv 1 end] 16 | } 17 | default { 18 | error "unknown option: [lindex $::argv 0]" 19 | } 20 | } 21 | set ::argv [lrange $::argv 1 end] 22 | } 23 | 24 | if {$failcache_dir eq ""} { 25 | error "must specify --failcache_dir" 26 | } 27 | 28 | foreach f [glob -directory $failcache_dir -nocomplain -tails *] { 29 | lassign [split $f " "] entry_portname entry_variants entry_hash 30 | set result [mportlookup $entry_portname] 31 | if {[llength $result] < 2} { 32 | puts "Port '$entry_portname' no longer exists; removing failcache entry $f" 33 | file delete -force [file join $failcache_dir $f] 34 | continue 35 | } 36 | set portinfo [lindex $result 1] 37 | set hash [port_files_checksum [dict get $portinfo porturl]] 38 | if {$entry_hash ne $hash} { 39 | puts "Removing stale failcache entry: $f" 40 | file delete -force [file join $failcache_dir $f] 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /tools/failcache.tcl: -------------------------------------------------------------------------------- 1 | # common code for operating on the failcache 2 | 3 | package require sha256 4 | 5 | # save in case env gets cleared 6 | if {[info exists ::env(BUILDBOT_BUILDURL)]} { 7 | set failcache_buildurl $::env(BUILDBOT_BUILDURL) 8 | } 9 | 10 | # slightly odd method as per mpbb's compute_failcache_hash 11 | proc port_files_checksum {porturl} { 12 | set portdir [macports::getportdir $porturl] 13 | lappend hashlist [::sha2::sha256 -hex -file ${portdir}/Portfile] 14 | if {[file exists ${portdir}/files]} { 15 | fs-traverse f [list ${portdir}/files] { 16 | if {[file type $f] eq "file"} { 17 | lappend hashlist [::sha2::sha256 -hex -file $f] 18 | } 19 | } 20 | } 21 | foreach hash [lsort $hashlist] { 22 | append compound_hash "${hash}\n" 23 | } 24 | return [::sha2::sha256 -hex $compound_hash] 25 | } 26 | 27 | proc check_failcache {portname porturl canonical_variants {return_contents no}} { 28 | global failcache_dir 29 | set hash [port_files_checksum $porturl] 30 | set key "$portname $canonical_variants $hash" 31 | set ret 0 32 | foreach f [glob -directory $failcache_dir -nocomplain -tails "${portname} *"] { 33 | if {$f eq $key} { 34 | if {$return_contents} { 35 | set fd [open [file join $failcache_dir $f] r] 36 | set line [gets $fd] 37 | close $fd 38 | return $line 39 | } 40 | set ret 1 41 | } elseif {[lindex [split $f " "] end] ne $hash} { 42 | puts stderr "removing stale failcache entry: $f" 43 | file delete -force [file join $failcache_dir $f] 44 | } 45 | } 46 | return $ret 47 | } 48 | 49 | proc failcache_update {portname porturl canonical_variants failed} { 50 | global failcache_dir 51 | set hash [port_files_checksum $porturl] 52 | set entry_path [file join $failcache_dir "$portname $canonical_variants $hash"] 53 | if {$failed} { 54 | global env failcache_buildurl 55 | file mkdir $failcache_dir 56 | set fd [open $entry_path w] 57 | if {[info exists env(BUILDBOT_BUILDURL)]} { 58 | puts $fd $env(BUILDBOT_BUILDURL) 59 | } elseif {[info exists failcache_buildurl]} { 60 | puts $fd $failcache_buildurl 61 | } else { 62 | puts $fd "unknown" 63 | } 64 | close $fd 65 | } else { 66 | file delete -force $entry_path 67 | } 68 | } 69 | 70 | # clear all entries for portname 71 | proc failcache_clear_all {portname} { 72 | global failcache_dir 73 | foreach f [glob -directory $failcache_dir -nocomplain "${portname} *"] { 74 | puts stderr "clearing failcache entry: [file tail $f]" 75 | file delete -force $f 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tools/gather-archives.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | 3 | package require macports 4 | package require registry2 5 | package require fetch_common 6 | 7 | set archive_site_private https://packages-private.macports.org 8 | set archive_site_public https://packages.macports.org 9 | set jobs_dir "" 10 | set license_db_dir "" 11 | set staging_dir "" 12 | while {[string range [lindex $::argv 0] 0 1] eq "--"} { 13 | switch -- [lindex $::argv 0] { 14 | --archive_site_private { 15 | set archive_site_private [lindex $::argv 1] 16 | set ::argv [lreplace $::argv 0 0] 17 | } 18 | --archive_site_public { 19 | set archive_site_public [lindex $::argv 1] 20 | set ::argv [lreplace $::argv 0 0] 21 | } 22 | --jobs_dir { 23 | set jobs_dir [file normalize [lindex $::argv 1]] 24 | set ::argv [lreplace $::argv 0 0] 25 | } 26 | --license_db_dir { 27 | set license_db_dir [file normalize [lindex $::argv 1]] 28 | set ::argv [lreplace $::argv 0 0] 29 | } 30 | --staging_dir { 31 | set staging_dir [file normalize [lindex $::argv 1]] 32 | set ::argv [lreplace $::argv 0 0] 33 | } 34 | default { 35 | error "unknown option: [lindex $::argv 0]" 36 | } 37 | } 38 | set ::argv [lreplace $::argv 0 0] 39 | } 40 | 41 | if {$staging_dir eq ""} { 42 | error "must specify --staging_dir" 43 | } 44 | if {$jobs_dir eq ""} { 45 | error "must specify --jobs_dir" 46 | } 47 | if {[llength $::argv] == 0} { 48 | error "must specify an input file" 49 | } 50 | 51 | if {[catch {mportinit "" "" ""} result]} { 52 | puts stderr "$errorInfo" 53 | error "Failed to initialize ports system: $result" 54 | } 55 | 56 | source ${jobs_dir}/distributable_lib.tcl 57 | if {$license_db_dir ne ""} { 58 | init_license_db $license_db_dir 59 | } 60 | 61 | set tarcmd "$macports::autoconf::tar_path [macports::get_tar_flags .${macports::portarchivetype}]cvf" 62 | 63 | file stat $staging_dir stat_array 64 | set staging_device $stat_array(dev) 65 | 66 | set infd [open [lindex $::argv 0] r] 67 | while {[gets $infd line] >= 0} { 68 | set portname [lindex [split $line] 0] 69 | if {[catch {mportlookup $portname} result]} { 70 | puts stderr "$errorInfo" 71 | puts stderr "Failed to look up port '$portname': $result" 72 | continue 73 | } elseif {[llength $result] < 2} { 74 | puts stderr "port $portname not found in the index" 75 | continue 76 | } 77 | 78 | lassign $result portname portinfo 79 | 80 | foreach e [registry::entry imaged $portname] { 81 | if {[$e version] ne [dict get $portinfo version] || [$e revision] != [dict get $portinfo revision]} { 82 | puts "Skipping [$e name] @[$e version]_[$e revision][$e variants] (not current)" 83 | continue 84 | } 85 | set requested_variations [split_variants [$e requested_variants]] 86 | 87 | lassign [check_licenses [$e name] $requested_variations] license_result license_reason 88 | puts $license_reason 89 | if {$license_result == 0} { 90 | set archive_type public 91 | set archive_site $archive_site_public 92 | } else { 93 | set archive_type private 94 | set archive_site $archive_site_private 95 | } 96 | set portimage_path [$e location] 97 | # Port image may sometimes be a directory 98 | if {[file isfile $portimage_path]} { 99 | set archive_path $portimage_path 100 | set staging_operation copy 101 | } else { 102 | set archive_path ${portimage_path}.${macports::portarchivetype} 103 | # Check if an archive also exists 104 | if {[file isfile $archive_path]} { 105 | # The archive is not the image, so it can be safely 106 | # deleted after staging. 107 | set staging_operation move 108 | } elseif {[file isdirectory $portimage_path]} { 109 | # The archive was either somehow never created, or 110 | # has since been deleted. Recreate it if needed. 111 | set staging_operation create 112 | } else { 113 | # No portimage at all 114 | puts "Image for [$e name] @[$e version]_[$e revision][$e variants] seems to be missing" 115 | continue 116 | } 117 | } 118 | set archive_basename [file tail $archive_path] 119 | set archive_name_encoded [portfetch::percent_encode $archive_basename] 120 | if {![catch {curl getsize ${archive_site}/[$e name]/${archive_name_encoded}} size] && $size > 0} { 121 | puts "Already uploaded ${archive_type} archive: ${archive_basename}" 122 | continue 123 | } 124 | 125 | puts "Staging ${archive_type} archive for upload: ${archive_basename}" 126 | set archive_staging_dir [file join ${staging_dir} ${archive_type} [$e name]] 127 | file mkdir $archive_staging_dir 128 | switch $staging_operation { 129 | copy { 130 | file stat $archive_path stat_array 131 | if {$stat_array(dev) == $staging_device} { 132 | puts "creating hardlink to $archive_path in $archive_staging_dir" 133 | file link -hard [file join $archive_staging_dir $archive_basename] $archive_path 134 | } else { 135 | puts "copying $archive_path to $archive_staging_dir" 136 | file copy -force -- $archive_path $archive_staging_dir 137 | } 138 | } 139 | create { 140 | puts "creating $archive_basename from $portimage_path" 141 | system -W $portimage_path "$tarcmd [file join $archive_staging_dir $archive_basename] ." 142 | } 143 | move { 144 | puts "moving $archive_path to $archive_staging_dir" 145 | file rename -force -- $archive_path $archive_staging_dir 146 | } 147 | } 148 | } 149 | } 150 | 151 | if {$license_db_dir ne ""} { 152 | write_license_db $license_db_dir 153 | } 154 | 155 | exit 0 156 | -------------------------------------------------------------------------------- /tools/mirror-multi.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 3 | # 4 | # Mirrors the distfiles for the given ports, for each possible variant 5 | # and supported platform. Skips those that have already been mirrored 6 | # by comparing the Portfile's hash against the hash recorded previously. 7 | # 8 | # Copyright (c) 2018 The MacPorts Project. 9 | # 10 | # Redistribution and use in source and binary forms, with or without 11 | # modification, are permitted provided that the following conditions 12 | # are met: 13 | # 1. Redistributions of source code must retain the above copyright 14 | # notice, this list of conditions and the following disclaimer. 15 | # 2. Redistributions in binary form must reproduce the above copyright 16 | # notice, this list of conditions and the following disclaimer in 17 | # the documentation and/or other materials provided with the 18 | # distribution. 19 | # 3. Neither the name of the MacPorts project, nor the names of any contributors 20 | # may be used to endorse or promote products derived from this software 21 | # without specific prior written permission. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 24 | # AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 27 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 30 | # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 32 | # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 33 | # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | 35 | package require macports 36 | package require fetch_common 37 | 38 | source [file join [file dirname [info script]] mirrordb.tcl] 39 | 40 | set ui_options(ports_verbose) yes 41 | if {[catch {mportinit ui_options "" ""} result]} { 42 | ui_error "$errorInfo" 43 | ui_error "Failed to initialize ports system: $result" 44 | exit 1 45 | } 46 | 47 | set platforms [list 8 powerpc 8 i386 9 powerpc 9 i386] 48 | foreach vers {10 11 12 13 14 15 16 17 18 19} { 49 | if {${macports::os_major} != $vers} { 50 | lappend platforms $vers i386 51 | } 52 | } 53 | foreach vers {20 21 22 23 24} { 54 | if {${macports::os_major} != $vers} { 55 | lappend platforms $vers arm $vers i386 56 | } elseif {${macports::os_arch} eq "i386"} { 57 | lappend platforms $vers arm 58 | } else { 59 | lappend platforms $vers i386 60 | } 61 | } 62 | set deptypes [list depends_fetch depends_extract depends_patch depends_build depends_lib depends_run depends_test] 63 | 64 | set processed [dict create] 65 | set mirror_done [dict create] 66 | set distfiles_results [dict create] 67 | 68 | proc check_mirror_done_local {portname} { 69 | global mirror_done 70 | if {[dict exists $mirror_done $portname]} { 71 | return [dict get $mirror_done $portname] 72 | } 73 | global mirrorcache_dir 74 | set cache_entry [file join $mirrorcache_dir [string toupper [string index $portname 0]] $portname] 75 | if {[file isfile $cache_entry]} { 76 | set portfile_hash [get_portfile_hash $portname] 77 | if {$portfile_hash eq {}} { 78 | return 0 79 | } 80 | set fd [open $cache_entry] 81 | set entry_hash [gets $fd] 82 | set partial [gets $fd] 83 | close $fd 84 | if {$portfile_hash eq $entry_hash} { 85 | if {$partial eq ""} { 86 | dict set mirror_done $portname 1 87 | return 1 88 | } else { 89 | dict set mirror_done $portname $partial 90 | return $partial 91 | } 92 | } else { 93 | file delete -force $cache_entry 94 | dict set mirror_done $portname 0 95 | } 96 | } else { 97 | dict set mirror_done $portname 0 98 | } 99 | return 0 100 | } 101 | 102 | proc check_mirror_done_remote {portname} { 103 | global mirror_done 104 | if {[dict exists $mirror_done $portname]} { 105 | return [dict get $mirror_done $portname] 106 | } 107 | if {[get_remote_db_value mirror.sha256.${portname}] eq [get_portfile_hash $portname]} { 108 | set result [get_remote_db_value mirror.status.${portname}] 109 | if {$result ne {}} { 110 | dict set mirror_done $portname $result 111 | return $result 112 | } 113 | } else { 114 | dict set mirror_done $portname 0 115 | } 116 | return 0 117 | } 118 | 119 | 120 | proc set_mirror_done_remote {portname value} { 121 | # We actually need to upload the files before updating their 122 | # status in the remote db, so just update the dict here. 123 | global mirror_done 124 | if {![dict exists $mirror_done $portname] || [dict get $mirror_done $portname] != 1} { 125 | dict set mirror_done $portname $value 126 | } 127 | } 128 | 129 | # Write out info needed to update the remote db. 130 | proc write_status_dicts {} { 131 | foreach d {mirror_done portfile_hash_cache portname_portfile_map} { 132 | global $d 133 | set fd [open $d w] 134 | puts -nonewline $fd [set $d] 135 | close $fd 136 | } 137 | } 138 | 139 | 140 | proc set_mirror_done_local {portname value} { 141 | global mirror_done 142 | if {![dict exists $mirror_done $portname] || [dict get $mirror_done $portname] != 1} { 143 | global mirrorcache_dir 144 | set portfile_hash [get_portfile_hash $portname] 145 | 146 | set cache_dir [file join $mirrorcache_dir [string toupper [string index $portname 0]]] 147 | file mkdir $cache_dir 148 | set cache_entry [file join $cache_dir $portname] 149 | set fd [open $cache_entry w] 150 | puts $fd $portfile_hash 151 | if {$value != 1} { 152 | puts $fd $value 153 | } 154 | close $fd 155 | dict set mirror_done $portname 1 156 | } 157 | } 158 | 159 | proc get_dep_list {portinfo} { 160 | global deptypes 161 | set deps [dict create] 162 | foreach deptype $deptypes { 163 | if {[dict exists $portinfo $deptype]} { 164 | foreach dep [dict get $portinfo $deptype] { 165 | dict set deps [lindex [split $dep :] end] 1 166 | } 167 | } 168 | } 169 | return $deps 170 | } 171 | 172 | proc get_variants {portinfo} { 173 | if {![dict exists $portinfo vinfo]} { 174 | return {} 175 | } 176 | set variants {} 177 | dict for {vname variant} [dict get $portinfo vinfo] { 178 | if {![dict exists $variant is_default] || [dict get $variant is_default] ne "+"} { 179 | lappend variants $vname 180 | } 181 | } 182 | return $variants 183 | } 184 | 185 | # Remember that the distfiles have been tried already 186 | # (same distfiles can be shared by multiple ports) 187 | proc save_distfiles_results {mport succeeded} { 188 | if {[catch {_mportkey $mport all_dist_files} all_dist_files]} { 189 | # no distfiles, no problem 190 | return 191 | } 192 | global distfiles_results 193 | set distpath [_mportkey $mport distpath] 194 | foreach distfile $all_dist_files { 195 | set filepath [file join $distpath $distfile] 196 | dict set distfiles_results $filepath $succeeded 197 | } 198 | } 199 | 200 | # Given a distribution file name, return the name without an attached tag 201 | # Example : getdistname distfile.tar.gz:tag1 returns "distfile.tar.gz" 202 | # / isn't included in the regexp, thus allowing port specification in URLs. 203 | proc getdistname {name} { 204 | regexp {(.+):[0-9A-Za-z_-]+$} $name match name 205 | return $name 206 | } 207 | 208 | # check if mirroring should be skipped due to all distfiles having 209 | # previously been successfully mirrored, or any distfile previously 210 | # having a checksum mismatch 211 | # Returns: 212 | # 0 - mirror needed 213 | # 1 - mirror not needed 214 | # 2 - mirror already failed for at least one distfile 215 | proc skip_mirror {mport identifier} { 216 | if {([catch {_mportkey $mport distfiles} distfiles] || $distfiles eq "") 217 | && ([catch {_mportkey $mport patchfiles} patchfiles] || $patchfiles eq "")} { 218 | # no distfiles, no need to mirror 219 | return 1 220 | } 221 | global distfiles_results check_distfiles_url 222 | if {![info exists distfiles]} { 223 | set distfiles [list] 224 | } 225 | if {![info exists patchfiles]} { 226 | set patchfiles [list] 227 | } 228 | if {$check_distfiles_url} { 229 | set dist_subdir [_mportkey $mport dist_subdir] 230 | global distfiles_url distfiles_url_results 231 | } 232 | set distpath [_mportkey $mport distpath] 233 | set filespath [_mportkey $mport filespath] 234 | set any_unmirrored 0 235 | foreach distfile [concat $distfiles $patchfiles] { 236 | if {[file exists [file join $filespath $distfile]]} { 237 | continue 238 | } 239 | set distfile [getdistname $distfile] 240 | if {$check_distfiles_url} { 241 | if {[dict exists $distfiles_url_results ${dist_subdir}/${distfile}]} { 242 | set url_result [dict get $distfiles_url_results ${dist_subdir}/${distfile}] 243 | } else { 244 | set distfile_url ${distfiles_url}${dist_subdir}/[portfetch::percent_encode $distfile] 245 | set url_result [expr {![catch {curl getsize $distfile_url} size] && $size > 0}] 246 | dict set distfiles_url_results ${dist_subdir}/${distfile} $url_result 247 | } 248 | if {$url_result} { 249 | continue 250 | } 251 | } 252 | set filepath [file join $distpath $distfile] 253 | if {![dict exists $distfiles_results $filepath]} { 254 | set any_unmirrored 1 255 | } elseif {[dict get $distfiles_results $filepath] == 0} { 256 | ui_msg "Skipping ${identifier}: $distfile already failed checksum" 257 | return 2 258 | } 259 | } 260 | if {$any_unmirrored == 0} { 261 | #ui_msg "Skipping ${identifier}: all distfiles already mirrored" 262 | return 1 263 | } 264 | return 0 265 | } 266 | 267 | 268 | proc mirror_port {portinfo} { 269 | global processed platforms 270 | set portname [dict get $portinfo name] 271 | set porturl [dict get $portinfo porturl] 272 | dict set processed $portname 1 273 | set do_mirror 1 274 | set attempted 0 275 | set succeeded 0 276 | if {[lsearch -exact -nocase [dict get $portinfo license] "nomirror"] >= 0} { 277 | ui_msg "Not mirroring $portname due to license" 278 | set do_mirror 0 279 | } 280 | if {[catch {mportopen $porturl [dict create subport $portname] {}} mport]} { 281 | ui_error "mportopen $porturl failed: $mport" 282 | return 1 283 | } 284 | set portinfo [mportinfo $mport] 285 | 286 | set skip_result [skip_mirror $mport $portname] 287 | if {$do_mirror && $skip_result == 0} { 288 | incr attempted 289 | mportexec $mport clean 290 | if {[mportexec $mport mirror] == 0} { 291 | save_distfiles_results $mport 1 292 | incr succeeded 293 | } else { 294 | save_distfiles_results $mport 0 295 | } 296 | } elseif {$skip_result == 2} { 297 | # count as a failure 298 | incr attempted 299 | } 300 | mportclose $mport 301 | 302 | set deps [get_dep_list $portinfo] 303 | set variants [get_variants $portinfo] 304 | 305 | foreach variant $variants { 306 | ui_msg "$portname +${variant}" 307 | if {[catch {mportopen $porturl [dict create subport $portname] [dict create $variant +]} mport]} { 308 | ui_error "mportopen $porturl failed: $mport" 309 | continue 310 | } 311 | set portinfo [mportinfo $mport] 312 | set deps [dict merge [get_dep_list $portinfo] $deps] 313 | set skip_result [skip_mirror $mport "$portname +${variant}"] 314 | if {$do_mirror && $skip_result == 0} { 315 | incr attempted 316 | mportexec $mport clean 317 | if {[mportexec $mport mirror] == 0} { 318 | save_distfiles_results $mport 1 319 | incr succeeded 320 | } else { 321 | save_distfiles_results $mport 0 322 | } 323 | } elseif {$skip_result == 2} { 324 | incr attempted 325 | } 326 | mportclose $mport 327 | } 328 | 329 | foreach {os_major os_arch} $platforms { 330 | ui_msg "$portname with platform 'darwin $os_major $os_arch'" 331 | if {[catch {mportopen $porturl [dict create subport $portname os_major $os_major os_arch $os_arch] {}} mport]} { 332 | ui_error "mportopen $porturl failed: $mport" 333 | continue 334 | } 335 | set portinfo [mportinfo $mport] 336 | set deps [dict merge [get_dep_list $portinfo] $deps] 337 | set skip_result [skip_mirror $mport "$portname darwin $os_major $os_arch"] 338 | if {$do_mirror && $skip_result == 0} { 339 | incr attempted 340 | mportexec $mport clean 341 | if {[mportexec $mport mirror] == 0} { 342 | save_distfiles_results $mport 1 343 | incr succeeded 344 | } else { 345 | save_distfiles_results $mport 0 346 | } 347 | } elseif {$skip_result == 2} { 348 | incr attempted 349 | } 350 | mportclose $mport 351 | } 352 | 353 | set dep_failed 0 354 | foreach dep [dict keys $deps] { 355 | if {![dict exists $processed $dep] && [check_mirror_done $dep] == 0} { 356 | set result [mportlookup $dep] 357 | if {[llength $result] < 2} { 358 | ui_error "No such port: $dep" 359 | set dep_failed 1 360 | continue 361 | } 362 | if {[mirror_port [lindex $result 1]] != 0} { 363 | set dep_failed 1 364 | } 365 | } 366 | } 367 | 368 | if {$dep_failed == 0 && ($attempted == 0 || $succeeded > 0)} { 369 | if {$succeeded == $attempted} { 370 | set_mirror_done $portname 1 371 | } else { 372 | set_mirror_done $portname 0.5 373 | } 374 | return 0 375 | } 376 | return 1 377 | } 378 | 379 | set mirrorcache_dir /tmp/mirrorcache 380 | set use_cachedir yes 381 | set include_subports no 382 | set use_remotedb no 383 | set check_distfiles_url no 384 | while {[string match -* [lindex $argv 0]]} { 385 | switch -- [lindex $argv 0] { 386 | -c { 387 | set use_cachedir yes 388 | set mirrorcache_dir [lindex $argv 1] 389 | set argv [lrange $argv 1 end] 390 | } 391 | -d { 392 | set check_distfiles_url yes 393 | set distfiles_url_results [dict create] 394 | set distfiles_url [lindex $argv 1] 395 | set argv [lrange $argv 1 end] 396 | } 397 | -s { 398 | set include_subports yes 399 | } 400 | -r { 401 | set use_remotedb yes 402 | set use_cachedir no 403 | set mirrorcache_baseurl [lindex $argv 1] 404 | set mirrorcache_credentials [lindex $argv 2] 405 | set argv [lrange $argv 2 end] 406 | } 407 | default { 408 | ui_error "Unknown option [lindex $argv 0]" 409 | } 410 | } 411 | set argv [lrange $argv 1 end] 412 | } 413 | if {$use_cachedir} { 414 | rename check_mirror_done_local check_mirror_done 415 | rename set_mirror_done_local set_mirror_done 416 | } elseif {$use_remotedb} { 417 | rename check_mirror_done_remote check_mirror_done 418 | rename set_mirror_done_remote set_mirror_done 419 | } 420 | 421 | proc process_port {portname} { 422 | global processed 423 | if {[dict exists $processed $portname]} { 424 | ui_msg "skipping ${portname}, already processed" 425 | return 426 | } 427 | if {[check_mirror_done $portname] == 1} { 428 | ui_msg "skipping ${portname}, previously mirrored" 429 | return 430 | } 431 | 432 | global exitval 433 | set result [mportlookup $portname] 434 | if {[llength $result] < 2} { 435 | ui_error "No such port: $portname" 436 | set exitval 1 437 | return 438 | } 439 | set portinfo [lindex $result 1] 440 | if {[mirror_port $portinfo] != 0} { 441 | set exitval 1 442 | } 443 | 444 | global include_subports 445 | if {$include_subports} { 446 | set subports [expr {[dict exists $portinfo subports] ? [dict get $portinfo subports] : {}}] 447 | foreach subport $subports { 448 | process_port $subport 449 | } 450 | } 451 | } 452 | 453 | set exitval 0 454 | foreach portname $argv { 455 | process_port $portname 456 | } 457 | 458 | if {$use_remotedb} { 459 | write_status_dicts 460 | } 461 | 462 | exit $exitval 463 | -------------------------------------------------------------------------------- /tools/mirrordb.tcl: -------------------------------------------------------------------------------- 1 | # common code for mirror database 2 | 3 | set portfile_hash_cache [dict create] 4 | set portname_portfile_map [dict create] 5 | 6 | proc get_portfile_hash {portname} { 7 | global portfile_hash_cache portname_portfile_map 8 | if {[dict exists $portname_portfile_map $portname]} { 9 | set portfile [dict get $portname_portfile_map $portname] 10 | } else { 11 | set result [mportlookup $portname] 12 | if {[llength $result] < 2} { 13 | return {} 14 | } 15 | set portinfo [lindex $result 1] 16 | set portfile [file join [macports::getportdir [dict get $portinfo porturl]] Portfile] 17 | dict set portname_portfile_map $portname $portfile 18 | } 19 | if {[dict exists $portfile_hash_cache $portfile]} { 20 | return [dict get $portfile_hash_cache $portfile] 21 | } elseif {[file isfile $portfile]} { 22 | set portfile_hash [sha256 file $portfile] 23 | dict set portfile_hash_cache $portfile $portfile_hash 24 | return $portfile_hash 25 | } 26 | return {} 27 | } 28 | 29 | proc get_remote_db_value {key} { 30 | global mirrorcache_baseurl mirrorcache_credentials 31 | set fullurl ${mirrorcache_baseurl}GET/${key}?type=txt 32 | try { 33 | curl fetch -u $mirrorcache_credentials $fullurl mirror_db_response 34 | set fd [open mirror_db_response r] 35 | gets $fd result 36 | close $fd 37 | } on error {} { 38 | set result {} 39 | } finally { 40 | file delete mirror_db_response 41 | } 42 | return $result 43 | } 44 | -------------------------------------------------------------------------------- /tools/noisy-delete.tcl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env port-tclsh 2 | 3 | # Delete files while producing output often enough that buildbot won't 4 | # cancel the build due to timeout. 5 | 6 | package require Thread 7 | 8 | set noisemaker { 9 | while {1} { 10 | # Every 5 minutes 11 | after 300000 12 | puts "Still deleting..." 13 | } 14 | } 15 | 16 | thread::create $noisemaker 17 | 18 | file delete -force {*}$::argv 19 | -------------------------------------------------------------------------------- /tools/portgroups.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 3 | # 4 | # Writes a list of included PortGroups for a given port to stdout. 5 | # 6 | # Copyright (c) 2016 The MacPorts Project. 7 | # Copyright (c) 2016 Clemens Lang 8 | # 9 | # Redistribution and use in source and binary forms, with or without 10 | # modification, are permitted provided that the following conditions 11 | # are met: 12 | # 1. Redistributions of source code must retain the above copyright 13 | # notice, this list of conditions and the following disclaimer. 14 | # 2. Redistributions in binary form must reproduce the above copyright 15 | # notice, this list of conditions and the following disclaimer in 16 | # the documentation and/or other materials provided with the 17 | # distribution. 18 | # 3. Neither the name of the MacPorts project, nor the names of any contributors 19 | # may be used to endorse or promote products derived from this software 20 | # without specific prior written permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 23 | # AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 26 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 29 | # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 31 | # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 32 | # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | proc split_variants {variants} { 35 | set result [dict create] 36 | set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants] 37 | foreach { match sign variant } $l { 38 | dict set result $variant $sign 39 | } 40 | return $result 41 | } 42 | 43 | package require macports 44 | 45 | if {[llength $::argv] == 0} { 46 | puts stderr "Usage: $argv0 " 47 | exit 1 48 | } 49 | 50 | # initialize macports 51 | if {[catch {mportinit "" "" ""} result]} { 52 | ui_error "$errorInfo" 53 | ui_error "Failed to initialize ports sytem: $result" 54 | exit 1 55 | } 56 | 57 | # look up the path of the Portfile for the given port 58 | set portname [lindex $::argv 0] 59 | if {[llength $::argv] > 1} { 60 | set variations [split_variants [lindex $::argv 1]] 61 | } else { 62 | set variations "" 63 | } 64 | #try -pass_signal {...} 65 | try { 66 | set result [mportlookup $portname] 67 | if {[llength $result] < 2} { 68 | ui_error "No such port: $portname" 69 | exit 1 70 | } 71 | } on error {eMessage} { 72 | ui_error "mportlookup $portname failed: $eMessage" 73 | exit 1 74 | } 75 | 76 | # open the port so we can run dependency calculation 77 | lassign $result portname portinfo 78 | #try -pass_signal {...} 79 | try { 80 | set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variations] 81 | } on error {eMessage} { 82 | ui_error "mportopen for $portname with url [dict get $portinfo porturl] failed: $eMessage" 83 | exit 1 84 | } 85 | 86 | # obtain PortInfo array for this port and print the list of included 87 | # PortGroups 88 | set portinfo [mportinfo $mport] 89 | # only ports that include at least one PortGroup have portinfo(portgroups) set 90 | if {[dict exists $portinfo portgroups]} { 91 | foreach portgroup [dict get $portinfo portgroups] { 92 | lassign $portgroup group version 93 | puts "$group-$version" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tools/reclaim-space.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 3 | 4 | if {[llength $::argv] < 2 || ([lindex $::argv 0] eq "-y" && [llength $::argv] < 3)} { 5 | puts stderr "Usage: $::argv0 \[-y\] cur_free target" 6 | exit 1 7 | } 8 | set dryrun no 9 | if {[lindex $::argv 0] eq "-y"} { 10 | set dryrun yes 11 | } 12 | # given in KiB, convert to bytes 13 | set cur_free [expr {[lindex $::argv end-1] * 1024}] 14 | set target [expr {[lindex $::argv end] * 1024}] 15 | 16 | package require macports 17 | # for random 18 | package require Tclx 19 | mportinit 20 | 21 | random seed 22 | set candidates [dict create] 23 | 24 | fs-traverse -ignoreErrors -- f [list ${macports::portdbpath}/distfiles] { 25 | if {[file type $f] eq "file"} { 26 | # 0 for distfile, 1 for port 27 | dict set candidates $f 0 28 | } 29 | } 30 | 31 | foreach port [registry::entry imaged] { 32 | if {[$port dependents] eq ""} { 33 | dict set candidates $port 1 34 | } 35 | } 36 | 37 | proc active_files_size {port} { 38 | set total 0 39 | foreach f [$port files] { 40 | if {![catch {file type $f} type] && $type eq "file"} { 41 | incr total [file size $f] 42 | } 43 | } 44 | return $total 45 | } 46 | 47 | set candidate_list [dict keys $candidates] 48 | # It is tempting to sort by size and delete the largest things first, 49 | # but picking randomly greatly reduces the chance that we will just 50 | # uninstall one huge port that will immediately be reinstalled as a 51 | # dependency of whatever we build next. 52 | while {$cur_free < $target && [llength $candidate_list] > 0} { 53 | set i [random [llength $candidate_list]] 54 | set chosen [lindex $candidate_list $i] 55 | set candidate_list [lreplace ${candidate_list}[set candidate_list {}] $i $i] 56 | if {[dict get $candidates $chosen] == 0} { 57 | set size [file size $chosen] 58 | incr cur_free $size 59 | puts "Deleting $chosen ($size bytes)" 60 | if {!$dryrun} { 61 | file delete -force $chosen 62 | } 63 | } else { 64 | set size [file size [$chosen location]] 65 | if {[$chosen state] eq "installed"} { 66 | incr size [active_files_size $chosen] 67 | } 68 | incr cur_free $size 69 | set deps [$chosen dependencies] 70 | puts "Uninstalling [$chosen name] @[$chosen version]_[$chosen revision][$chosen variants] ($size bytes)" 71 | if {!$dryrun} { 72 | if {![registry::run_target $chosen uninstall ""]} { 73 | # Portfile failed, use the registry directly 74 | registry_uninstall::uninstall [$chosen name] [$chosen version] [$chosen revision] [$chosen variants] "" 75 | } 76 | } 77 | foreach dep $deps { 78 | if {![dict exists $candidates $dep] && [$dep dependents] eq ""} { 79 | dict set candidates $dep 1 80 | lappend candidate_list $dep 81 | } 82 | } 83 | } 84 | } 85 | 86 | mportshutdown 87 | exit 0 88 | -------------------------------------------------------------------------------- /tools/sort-with-subports.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # 3 | # Generates a list of ports where a port is only listed after all of its 4 | # dependencies (sans variants) have already been listed. Includes all 5 | # sub-ports of the specified ports. 6 | # 7 | # Copyright (c) 2006,2008 Bryan L Blackburn. All rights reserved. 8 | # Copyright (c) 2018-2019 The MacPorts Project 9 | # 10 | # Redistribution and use in source and binary forms, with or without 11 | # modification, are permitted provided that the following conditions 12 | # are met: 13 | # 1. Redistributions of source code must retain the above copyright 14 | # notice, this list of conditions and the following disclaimer. 15 | # 2. Redistributions in binary form must reproduce the above copyright 16 | # notice, this list of conditions and the following disclaimer in 17 | # the documentation and/or other materials provided with the 18 | # distribution. 19 | # 3. Neither the name Bryan L Blackburn, nor the names of any contributors 20 | # may be used to endorse or promote products derived from this software 21 | # without specific prior written permission. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 24 | # AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 27 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 30 | # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 32 | # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 33 | # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | # 35 | 36 | package require macports 37 | package require fetch_common 38 | 39 | 40 | proc ui_prefix {priority} { 41 | return "OUT: " 42 | } 43 | 44 | 45 | proc ui_channels {priority} { 46 | return {} 47 | } 48 | 49 | 50 | proc process_port_deps {portname} { 51 | global portdepinfo portsoftdeps portlist 52 | set deplist [dict get $portdepinfo $portname] 53 | dict unset portdepinfo $portname 54 | if {[dict exists $portsoftdeps $portname]} { 55 | lappend deplist {*}[dict get $portsoftdeps $portname] 56 | dict unset portsoftdeps $portname 57 | } 58 | foreach portdep $deplist { 59 | if {[dict exists $portdepinfo $portdep]} { 60 | process_port_deps $portdep 61 | } 62 | } 63 | lappend portlist $portname 64 | } 65 | 66 | proc check_failing_deps {portname} { 67 | global failingports portdepinfo outputports requestedports \ 68 | canonicalnames 69 | if {[dict exists $failingports $portname]} { 70 | return [dict get $failingports $portname] 71 | } 72 | # Protect against dependency cycles 73 | dict set failingports $portname [list 3 $portname] 74 | foreach portdep [dict get $portdepinfo $portname] { 75 | set dep_ret [check_failing_deps $portdep] 76 | # 0 = ok, 1 = known_fail, 2 = failcache, 3 = dep cycle 77 | set status [lindex $dep_ret 0] 78 | if {$status != 0} { 79 | set failed_dep [lindex $dep_ret 1] 80 | if {[dict get $outputports $portname] == 1} { 81 | if {$status == 1} { 82 | if {[dict exists $requestedports $portname]} { 83 | puts stderr "Excluding [dict get $canonicalnames $portname] because its dependency '$failed_dep' is known to fail" 84 | } 85 | dict set outputports $portname 0 86 | } elseif {$status == 2 && ![dict exists $requestedports $portname]} { 87 | # Exclude deps that will fail due to their own dep being in the failcache. 88 | # But still output requested ports so the failure will be reported. 89 | dict set outputports $portname 0 90 | } elseif {$status == 3} { 91 | if {[dict exists $requestedports $portname]} { 92 | puts stderr "Warning: [dict get $canonicalnames $portname] appears to have a cyclic dependency involving '$portdep'" 93 | } 94 | # Some cycles involving depends_test exist, which don't cause 95 | # problems yet only because we don't run tests. 96 | #dict set outputports $portname 0 97 | } 98 | } 99 | # keep processing other deps for now if there was a dep cycle 100 | if {$status != 3} { 101 | dict set failingports $portname [list $status $failed_dep] 102 | return [dict get $failingports $portname] 103 | } 104 | } 105 | } 106 | dict set failingports $portname [list 0 ""] 107 | return [dict get $failingports $portname] 108 | } 109 | 110 | source [file join [file dirname [info script]] failcache.tcl] 111 | 112 | if {[catch {mportinit "" "" ""} result]} { 113 | puts stderr "$errorInfo" 114 | error "Failed to initialize ports system: $result" 115 | } 116 | 117 | set archive_site_private "" 118 | set archive_site_public "" 119 | set failcache_dir "" 120 | set jobs_dir "" 121 | set license_db_dir "" 122 | set include_deps no 123 | while {[string range [lindex $::argv 0] 0 1] eq "--"} { 124 | switch -- [lindex $::argv 0] { 125 | --archive_site_private { 126 | set archive_site_private [lindex $::argv 1] 127 | set ::argv [lrange $::argv 1 end] 128 | } 129 | --archive_site_public { 130 | set archive_site_public [lindex $::argv 1] 131 | set ::argv [lrange $::argv 1 end] 132 | } 133 | --failcache_dir { 134 | set failcache_dir [lindex $::argv 1] 135 | set ::argv [lrange $::argv 1 end] 136 | } 137 | --jobs_dir { 138 | set jobs_dir [lindex $::argv 1] 139 | set ::argv [lrange $::argv 1 end] 140 | } 141 | --license_db_dir { 142 | set license_db_dir [lindex $::argv 1] 143 | set ::argv [lrange $::argv 1 end] 144 | } 145 | --include_deps { 146 | set include_deps yes 147 | } 148 | default { 149 | error "unknown option: [lindex $::argv 0]" 150 | } 151 | } 152 | set ::argv [lrange $::argv 1 end] 153 | } 154 | 155 | if {$jobs_dir ne "" && $archive_site_public ne "" && $archive_site_private ne ""} { 156 | source ${jobs_dir}/distributable_lib.tcl 157 | if {$license_db_dir ne ""} { 158 | init_license_db $license_db_dir 159 | } 160 | } 161 | 162 | set is_64bit_capable [sysctl hw.cpu64bit_capable] 163 | 164 | set portdepinfo [dict create] 165 | set portsoftdeps [dict create] 166 | set canonicalnames [dict create] 167 | set failingports [dict create] 168 | set todo [list] 169 | if {[lindex $argv 0] eq "-"} { 170 | while {[gets stdin line] >= 0} { 171 | lappend todo [string tolower [string trim $line]] 172 | } 173 | } else { 174 | foreach p $argv { 175 | lappend todo [string tolower $p] 176 | } 177 | } 178 | # save the ones that the user actually wants to know about 179 | set inputports [dict create] 180 | set outputports [dict create] 181 | set requestedports [dict create] 182 | foreach p $todo { 183 | dict set inputports $p 1 184 | dict set outputports $p 1 185 | dict set requestedports $p 1 186 | } 187 | set archive_ext .tbz2 188 | # process all recursive deps 189 | set depstypes [list depends_fetch depends_extract depends_patch depends_build depends_lib depends_run] 190 | while {[llength $todo] > 0} { 191 | set p [lindex $todo 0] 192 | set todo [lreplace ${todo}[set todo {}] 0 0] 193 | 194 | if {![dict exists $portdepinfo $p]} { 195 | if {[catch {mportlookup $p} result]} { 196 | puts stderr "$errorInfo" 197 | error "Failed to find port '$p': $result" 198 | } 199 | if {[llength $result] < 2} { 200 | puts stderr "port $p not found in the index" 201 | dict set portdepinfo $p "" 202 | dict set outputports $p 0 203 | continue 204 | } 205 | 206 | set portinfo [lindex $result 1] 207 | 208 | if {[dict exists $inputports $p]} { 209 | if {$failcache_dir ne ""} { 210 | failcache_clear_all [dict get $portinfo name] 211 | } 212 | if {[dict exists $portinfo subports]} { 213 | foreach subport [dict get $portinfo subports] { 214 | set splower [string tolower $subport] 215 | if {![dict exists $portdepinfo $splower]} { 216 | lappend todo $splower 217 | } 218 | if {![dict exists $requestedports $splower]} { 219 | dict set outputports $splower 1 220 | dict set requestedports $splower 1 221 | } 222 | } 223 | } 224 | } 225 | 226 | set opened 0 227 | if {[dict get $outputports $p] == 1} { 228 | if {[dict exists $portinfo replaced_by]} { 229 | if {[dict exists $requestedports $p]} { 230 | puts stderr "Excluding [dict get $portinfo name] because it is replaced by [dict get $portinfo replaced_by]" 231 | } 232 | dict set outputports $p 0 233 | } elseif {[dict exists $portinfo known_fail] && [string is true -strict [dict get $portinfo known_fail]]} { 234 | if {[dict exists $requestedports $p]} { 235 | puts stderr "Excluding [dict get $portinfo name] because it is known to fail" 236 | } 237 | dict set outputports $p 0 238 | dict set failingports $p [list 1 [dict get $portinfo name]] 239 | } elseif {$failcache_dir ne "" && ![dict exists $requestedports $p]} { 240 | # exclude dependencies with a failcache entry 241 | if {![catch {mportopen [dict get $portinfo porturl] [dict create subport [dict get $portinfo name]] ""} result]} { 242 | set opened 1 243 | set mport $result 244 | set portinfo [dict merge $portinfo [mportinfo $mport]] 245 | if {![dict exists $portinfo canonical_active_variants]} { 246 | puts stderr "Warning: [dict get $portinfo name] has no canonical_active_variants" 247 | dict set outputports $p 0 248 | } elseif {[check_failcache [dict get $portinfo name] [dict get $portinfo porturl] [dict get $portinfo canonical_active_variants]] != 0} { 249 | dict set outputports $p 0 250 | dict set failingports $p [list 2 [dict get $portinfo name]] 251 | } 252 | } else { 253 | dict set outputports $p 0 254 | } 255 | } 256 | if {$archive_site_public ne "" && [dict get $outputports $p] == 1} { 257 | # FIXME: support non-default variants 258 | if {$opened == 1 || ![catch {mportopen [dict get $portinfo porturl] [dict create subport [dict get $portinfo name]] ""} result]} { 259 | if {$opened != 1} { 260 | set opened 1 261 | set mport $result 262 | set portinfo [dict merge $portinfo [mportinfo $mport]] 263 | } 264 | set workername [ditem_key $mport workername] 265 | set archive_name [$workername eval {get_portimage_name}] 266 | set archive_name_encoded [portfetch::percent_encode $archive_name] 267 | if {![catch {curl getsize ${archive_site_public}/[dict get $portinfo name]/${archive_name_encoded}} size] && $size > 0} { 268 | # Check for other installed variants that might not have been uploaded 269 | set archives_prefix ${macports::portdbpath}/software/[dict get $portinfo name]/[dict get $portinfo name]-[dict get $portinfo version]_[dict get $portinfo revision] 270 | set any_archive_missing 0 271 | foreach installed_archive [glob -nocomplain -tails -path ${archives_prefix} *] { 272 | if {[file extension $installed_archive] ne $archive_ext} { 273 | set installed_archive ${installed_archive}${archive_ext} 274 | } 275 | if {$installed_archive ne $archive_name} { 276 | set installed_archive_encoded [portfetch::percent_encode $installed_archive] 277 | if {[catch {curl getsize ${archive_site_public}/[dict get $portinfo name]/${installed_archive_encoded}} size] || $size <= 0} { 278 | set any_archive_missing 1 279 | puts stderr "$installed_archive installed but not uploaded" 280 | break 281 | } 282 | } 283 | } 284 | if {!$any_archive_missing} { 285 | if {[dict exists $requestedports $p]} { 286 | puts stderr "Excluding [dict get $portinfo name] because it has already been built and uploaded to the public server" 287 | } 288 | dict set outputports $p 0 289 | } 290 | } 291 | } else { 292 | if {[dict exists $requestedports $p]} { 293 | puts stderr "Excluding [dict get $portinfo name] because it failed to open: $result" 294 | } 295 | dict set outputports $p 0 296 | } 297 | if {[dict get $outputports $p] == 1 && $archive_site_private ne "" && $jobs_dir ne ""} { 298 | # FIXME: support non-default variants 299 | set results [check_licenses [dict get $portinfo name] [list]] 300 | if {[lindex $results 0] == 1 && ![catch {curl getsize ${archive_site_private}/[dict get $portinfo name]/${archive_name_encoded}} size] && $size > 0} { 301 | if {[dict exists $requestedports $p]} { 302 | puts stderr "Excluding [dict get $portinfo name] because it is not distributable and it has already been built and uploaded to the private server" 303 | } 304 | dict set outputports $p 0 305 | } 306 | } 307 | } 308 | if {[dict get $outputports $p] == 1 && 309 | ($::macports::os_major <= 10 || $::macports::os_major >= 18)} { 310 | if {$opened == 1 || ![catch {mportopen [dict get $portinfo porturl] [dict create subport [dict get $portinfo name]] ""} result]} { 311 | if {$opened != 1} { 312 | set opened 1 313 | set mport $result 314 | set portinfo [dict merge $portinfo [mportinfo $mport]] 315 | } 316 | set supported_archs [_mportkey $mport supported_archs] 317 | switch $::macports::os_arch { 318 | arm { 319 | if {$supported_archs ne "" && $supported_archs ne "noarch" && "arm64" ni $supported_archs} { 320 | if {[dict exists $requestedports $p]} { 321 | puts stderr "Excluding [dict get $portinfo name] because it does not support the arm64 arch" 322 | } 323 | dict set outputports $p 0 324 | } 325 | } 326 | i386 { 327 | if {${is_64bit_capable}} { 328 | if {$::macports::os_major >= 18 && $supported_archs ne "" && $supported_archs ne "noarch" && "x86_64" ni $supported_archs} { 329 | if {[dict exists $requestedports $p]} { 330 | puts stderr "Excluding [dict get $portinfo name] because it does not support the x86_64 arch" 331 | } 332 | dict set outputports $p 0 333 | } 334 | } elseif {$supported_archs ne "" && $supported_archs ne "noarch" && ("x86_64" ni $supported_archs || "i386" ni $supported_archs)} { 335 | if {[dict exists $requestedports $p]} { 336 | puts stderr "Excluding [dict get $portinfo name] because the ${::macports::macosx_version}_x86_64 builder will build it" 337 | } 338 | dict set outputports $p 0 339 | } 340 | } 341 | powerpc { 342 | if {$supported_archs ne "" && $supported_archs ne "noarch" && "ppc" ni $supported_archs} { 343 | if {[dict exists $requestedports $p]} { 344 | puts stderr "Excluding [dict get $portinfo name] because it does not support the ppc arch" 345 | } 346 | dict set outputports $p 0 347 | } 348 | } 349 | default {} 350 | } 351 | } else { 352 | puts stderr "Excluding [dict get $portinfo name] because it failed to open: $result" 353 | dict set outputports $p 0 354 | } 355 | } 356 | } 357 | 358 | if {$opened} { 359 | mportclose $mport 360 | } 361 | 362 | if {[dict get $outputports $p] == 1} { 363 | dict set canonicalnames $p [dict get $portinfo name] 364 | } 365 | 366 | # If $requestedports($p) == 0, we're seeing the port again as a dependency of 367 | # something else and thus need to follow its deps even if it was excluded. 368 | if {[dict get $outputports $p] == 1 || ![dict exists $requestedports $p] || [dict get $requestedports $p] == 0} { 369 | dict set portdepinfo $p [list] 370 | foreach depstype $depstypes { 371 | if {[dict exists $portinfo $depstype] && [dict get $portinfo $depstype] ne ""} { 372 | foreach onedep [dict get $portinfo $depstype] { 373 | set depname [string tolower [lindex [split [lindex $onedep 0] :] end]] 374 | if {[string match port:* $onedep]} { 375 | dict lappend portdepinfo $p $depname 376 | } else { 377 | # soft deps are installed before their dependents, but 378 | # don't cause exclusion if they are failing 379 | # real problematic example: bin:xattr:xattr 380 | dict lappend portsoftdeps $p $depname 381 | } 382 | if {![dict exists $outputports $depname]} { 383 | lappend todo $depname 384 | if {$include_deps} { 385 | dict set outputports $depname 1 386 | } else { 387 | dict set outputports $depname 0 388 | } 389 | } elseif {[dict exists $requestedports $depname] && ![dict exists $portdepinfo $depname]} { 390 | # may or may not have been checked for exclusion yet 391 | lappend todo $depname 392 | } 393 | } 394 | } 395 | } 396 | } 397 | 398 | # Mark as having been processed at least once. 399 | if {[dict exists $requestedports $p]} { 400 | dict set requestedports $p 0 401 | } 402 | } 403 | } 404 | 405 | if {$jobs_dir ne "" && $license_db_dir ne "" && $archive_site_public ne "" && $archive_site_private ne ""} { 406 | write_license_db $license_db_dir 407 | } 408 | 409 | set sorted_portnames [lsort -dictionary [dict keys $portdepinfo]] 410 | foreach portname $sorted_portnames { 411 | check_failing_deps $portname 412 | } 413 | 414 | set portlist [list] 415 | foreach portname $sorted_portnames { 416 | if {[dict exists $portdepinfo $portname]} { 417 | process_port_deps $portname 418 | } 419 | } 420 | 421 | foreach portname $portlist { 422 | if {[dict get $outputports $portname] == 1} { 423 | puts [dict get $canonicalnames $portname] 424 | } 425 | } 426 | -------------------------------------------------------------------------------- /tools/supported-archs.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 3 | # 4 | # Generates a list of supported architectures for the given port. 5 | # 6 | # Copyright (c) 2016 The MacPorts Project. 7 | # 8 | # Redistribution and use in source and binary forms, with or without 9 | # modification, are permitted provided that the following conditions 10 | # are met: 11 | # 1. Redistributions of source code must retain the above copyright 12 | # notice, this list of conditions and the following disclaimer. 13 | # 2. Redistributions in binary form must reproduce the above copyright 14 | # notice, this list of conditions and the following disclaimer in 15 | # the documentation and/or other materials provided with the 16 | # distribution. 17 | # 3. Neither the name of the MacPorts project, nor the names of any contributors 18 | # may be used to endorse or promote products derived from this software 19 | # without specific prior written permission. 20 | # 21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 22 | # AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 25 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28 | # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 30 | # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 31 | # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | proc split_variants {variants} { 34 | set result [dict create] 35 | set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants] 36 | foreach { match sign variant } $l { 37 | dict set result $variant $sign 38 | } 39 | return $result 40 | } 41 | 42 | if {[llength $::argv] == 0} { 43 | puts stderr "Usage: $argv0 " 44 | exit 1 45 | } 46 | 47 | package require macports 48 | 49 | if {[catch {mportinit "" "" ""} result]} { 50 | ui_error "$errorInfo" 51 | ui_error "Failed to initialize ports system: $result" 52 | exit 1 53 | } 54 | 55 | set portname [lindex $::argv 0] 56 | if {[llength $::argv] > 1} { 57 | set variations [split_variants [lindex $::argv 1]] 58 | } else { 59 | set variations "" 60 | } 61 | 62 | if {[catch {set one_result [mportlookup $portname]}] || [llength $one_result] < 2} { 63 | ui_error "No port named ${portname} could be found in the port index" 64 | exit 1 65 | } 66 | 67 | lassign $one_result portname portinfo 68 | 69 | if {[dict exists $portinfo porturl]} { 70 | if {[catch {set mport [mportopen [dict get $portinfo porturl] [dict create subport $portname] $variations]}]} { 71 | ui_warn "failed to open port: $portname" 72 | } else { 73 | set archs [_mportkey $mport supported_archs] 74 | puts [expr {$archs ne "" ? $archs : "arm64 i386 ppc ppc64 x86_64"}] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tools/uninstall-unneeded-ports.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4 3 | 4 | proc printUsage {} { 5 | puts "Usage: $::argv0 \[-hV\]" 6 | puts " -h This help" 7 | puts " -V show version and MacPorts version being used" 8 | } 9 | 10 | set MY_VERSION 0.2 11 | 12 | set showVersion 0 13 | 14 | set origArgv $::argv 15 | while {[string index [lindex $::argv 0] 0] == "-" } { 16 | switch [string range [lindex $::argv 0] 1 end] { 17 | h { 18 | printUsage 19 | exit 0 20 | } 21 | V { 22 | set showVersion 1 23 | } 24 | default { 25 | puts "Unknown option [lindex $::argv 0]" 26 | printUsage 27 | exit 2 28 | } 29 | } 30 | set ::argv [lrange $::argv 1 end] 31 | } 32 | 33 | package require macports 34 | mportinit 35 | 36 | if {$showVersion} { 37 | puts "uninstall-unneeded-ports.tcl version $MY_VERSION" 38 | puts "MacPorts version [macports::version]" 39 | exit 0 40 | } 41 | 42 | # Create a lookup table for determining whether a port has dependents 43 | # (regardless of whether or not those dependents are currently installed) 44 | set dependents [dict create] 45 | set a_dependency [dict create] 46 | foreach source $macports::sources { 47 | set source [lindex $source 0] 48 | macports_try -pass_signal { 49 | set fd [open [macports::getindex $source] r] 50 | 51 | macports_try -pass_signal { 52 | while {[gets $fd line] >= 0} { 53 | lassign $line name len 54 | set portinfo [read $fd $len] 55 | 56 | # depends_test is not included because mpbb doesn't run `port test' 57 | foreach field {depends_build depends_extract depends_fetch depends_lib depends_patch depends_run} { 58 | if {[dict exists $portinfo $field]} { 59 | foreach dependency [dict get $portinfo $field] { 60 | set lowercase_dependency_name [string tolower [lindex [split $dependency :] end]] 61 | dict incr dependents $lowercase_dependency_name 62 | dict set a_dependency $lowercase_dependency_name $name 63 | } 64 | } 65 | } 66 | } 67 | } on error {} { 68 | ui_warn "It looks like your PortIndex file for $source may be corrupt." 69 | throw 70 | } finally { 71 | close $fd 72 | } 73 | } on error {} { 74 | ui_warn "Can't open index file for source: $source" 75 | } 76 | } 77 | 78 | proc removal_reason {installed_name} { 79 | global dependents a_dependency 80 | set reason "" 81 | set lowercase_name [string tolower $installed_name] 82 | if {![dict exists $dependents $lowercase_name]} { 83 | set reason "no port in the PortIndex depends on $installed_name" 84 | } elseif {[dict get $dependents $lowercase_name] == 1} { 85 | set dependency_reason [removal_reason [dict get $a_dependency $lowercase_name]] 86 | if {$dependency_reason ne ""} { 87 | set reason "only [dict get $a_dependency $lowercase_name] depends on $installed_name and $dependency_reason" 88 | } 89 | } 90 | return $reason 91 | } 92 | 93 | # Deactivate the given port, first deactivating any active dependents 94 | # it has. 95 | proc deactivate_with_dependents {e} { 96 | if {[$e state] ne "installed"} { 97 | return 98 | } 99 | foreach dependent [$e dependents] { 100 | deactivate_with_dependents $dependent 101 | } 102 | set options [dict create ports_nodepcheck 1] 103 | if {![registry::run_target $e deactivate $options] 104 | && [catch {portimage::deactivate [$e name] [$e version] [$e revision] [$e variants] $options} result]} { 105 | puts stderr $::errorInfo 106 | puts stderr "Deactivating [$e name] @[$e version]_[$e revision][$e variants] failed: $result" 107 | } 108 | } 109 | 110 | set uninstall_options [dict create ports_force 1] 111 | foreach port [registry::entry imaged] { 112 | # Set to yes if a port should be uninstalled 113 | set uninstall no 114 | 115 | set installed_name [$port name] 116 | set installed_version [$port version] 117 | set installed_revision [$port revision] 118 | set installed_variants [$port variants] 119 | 120 | set portindex_match [mportlookup $installed_name] 121 | if {[llength $portindex_match] < 2} { 122 | # Not found in index 123 | ui_msg "Removing ${installed_name} @${installed_version}_${installed_revision}${installed_variants} because it is no longer in the PortIndex" 124 | set uninstall yes 125 | } else { 126 | set portinfo [lindex $portindex_match 1] 127 | 128 | set portspec "$installed_name @${installed_version}_$installed_revision$installed_variants" 129 | if {[dict get $portinfo version] ne $installed_version || [dict get $portinfo revision] != $installed_revision} { 130 | # The version in the index is different than the installed one 131 | ui_msg "Removing $portspec because there is a newer version in the PortIndex" 132 | set uninstall yes 133 | } else { 134 | set reason [removal_reason $installed_name] 135 | if {$reason ne ""} { 136 | set uninstall yes 137 | ui_msg "Removing $portspec because $reason" 138 | } else { 139 | set uninstall no 140 | if {no} { 141 | set lowercase_name [string tolower $installed_name] 142 | ui_msg "Not removing $portspec because it has [dict get $dependents $lowercase_name] dependents" 143 | } 144 | } 145 | } 146 | } 147 | if {$uninstall} { 148 | # Deactivate any active dependents first 149 | foreach dependent [$port dependents] { 150 | deactivate_with_dependents $dependent 151 | } 152 | # Try to run the target via the portfile first, so pre/post code runs 153 | if {![registry::run_target $port uninstall $uninstall_options]} { 154 | # Portfile failed, use the registry directly 155 | registry_uninstall::uninstall $installed_name $installed_version $installed_revision $installed_variants $uninstall_options 156 | } 157 | } 158 | } 159 | 160 | # Deactivate anything with inactive dependencies 161 | # (can happen with non-port: deps) 162 | # https://trac.macports.org/ticket/68662 163 | 164 | # Track if each port has any version active 165 | # (ports may have multiple installed variants, e.g. universal) 166 | set has_active [dict create] 167 | foreach port [registry::entry installed] { 168 | foreach dep [$port dependencies] { 169 | if {![dict exists $has_active [$dep name]]} { 170 | dict set has_active [$dep name] [expr {[registry::entry installed [$dep name]] ne ""}] 171 | } 172 | if {![dict get $has_active [$dep name]]} { 173 | ui_msg "Deactivating [$port name] because its dependency [$dep name] is not active" 174 | deactivate_with_dependents $port 175 | break 176 | } 177 | } 178 | } 179 | 180 | mportshutdown 181 | exit 0 182 | -------------------------------------------------------------------------------- /tools/update-mirrordb.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | 3 | # args: 4 | # mirrorcache_baseurl mirrorcache_credentials 5 | # then paths to three files containing tcl dicts: 6 | # mirror_done portfile_hash_cache portname_portfile_map 7 | 8 | package require Pextlib 9 | 10 | lassign $argv mirrorcache_baseurl mirrorcache_credentials mirror_done_p portfile_hash_cache_p portname_portfile_map_p 11 | foreach var {mirror_done portfile_hash_cache portname_portfile_map} { 12 | set fd [open [set ${var}_p] r] 13 | set $var [gets $fd] 14 | close $fd 15 | } 16 | 17 | dict for {portname status} $mirror_done { 18 | if {![dict exists $portname_portfile_map $portname]} { 19 | puts stderr "$portname not found in portname_portfile_map" 20 | continue 21 | } 22 | set portfile [dict get $portname_portfile_map $portname] 23 | set hash [dict get $portfile_hash_cache $portfile] 24 | set hashurl ${mirrorcache_baseurl}SET/mirror.sha256.${portname}/${hash} 25 | set statusurl ${mirrorcache_baseurl}SET/mirror.status.${portname}/${status} 26 | curl fetch -u $mirrorcache_credentials $hashurl /dev/null 27 | curl fetch -u $mirrorcache_credentials $statusurl /dev/null 28 | } 29 | -------------------------------------------------------------------------------- /tools/wait-for-mirror.tcl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env port-tclsh 2 | 3 | # Check a remote database to see if mirroring has been attempted for 4 | # the current version of the given port, and if not, wait and check 5 | # periodically until it has been, or timeout is reached. 6 | 7 | if {$argc != 3} { 8 | error "Usage: wait-for-mirror.tcl mirrorcache_baseurl mirrorcache_credentials portname" 9 | } 10 | 11 | lassign $argv mirrorcache_baseurl mirrorcache_credentials portname 12 | 13 | package require macports 14 | source [file join [file dirname [info script]] mirrordb.tcl] 15 | 16 | set ui_options(ports_verbose) yes 17 | if {[catch {mportinit ui_options "" ""} result]} { 18 | ui_error "$errorInfo" 19 | ui_error "Failed to initialize ports system: $result" 20 | exit 1 21 | } 22 | 23 | proc main {portname} { 24 | set portfile_hash [get_portfile_hash $portname] 25 | set key mirror.sha256.${portname} 26 | set start [clock seconds] 27 | while {[get_remote_db_value $key] ne $portfile_hash} { 28 | # 1h timeout 29 | if {[clock seconds] - $start >= 3600} { 30 | return 1 31 | } 32 | # 10s delay between queries 33 | after 10000 34 | } 35 | return 0 36 | } 37 | 38 | main $portname 39 | --------------------------------------------------------------------------------