| # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| # @ECLASS: cros-workon.eclass |
| # @MAINTAINER: |
| # ChromiumOS Build Team |
| # @BUGREPORTS: |
| # Please report bugs via http://crbug.com/new (with label Build) |
| # @VCSURL: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/master/eclass/@ECLASS@ |
| # @BLURB: helper eclass for building ChromiumOS packages from git |
| # @DESCRIPTION: |
| # A lot of ChromiumOS packages (src/platform/ and src/third_party/) are |
| # managed in the same way. You've got a git tree and you want to build |
| # it. This automates a lot of that common stuff in one place. |
| |
| inherit cros-constants cros-credentials |
| |
| # Default slotting for cros-workon packages. |
| # |
| # Gentoo Slotting Guide: |
| # https://devmanual.gentoo.org/general-concepts/slotting/index.html |
| # |
| # By default, cros-workon packages do not support having multiple versions |
| # of the same package installed at the same time. The top level slot |
| # of "0" expresses this requirement, as Portage will not allow multiple |
| # packages with the same name and slot to be installed. The subslot is set to |
| # ${PVR} by default. ${PVR} expands to the package version and revision number, |
| # e.g. "0.0.1-r307" or "9999". This means that a package being uprevved (or a |
| # user installing the unstable version of a package) will trigger subslot |
| # rebuilds in every package that DEPENDs on the original package and uses the |
| # subslot operator ':='. |
| # |
| # Packages should only override this value in specific cases: |
| # 1. The package does not provide any artifacts that can be consumed at build |
| # time by another package. An example would be if a package only installs |
| # a program and provides no headers or shared libraries. In this case, the |
| # package should override SLOT to be "0/0", indicating that changes in that |
| # package do not need to trigger recompilations in dependent packages. |
| # |
| # 2. The package genuinely supports having multiple versions installed at the |
| # same time. In this case, the package should define the slots and subslots |
| # in a manner consistent with the Gentoo Slotting Guide. All usages in this |
| # manner require sign-off from the Chromium OS build team. |
| # |
| # In either case, the SLOT variable must be overridden *after* inheriting from |
| # this eclass. |
| SLOT="0/${PVR}" |
| |
| # Array variables. All of the following variables can contain multiple items |
| # with the restriction being that all of them have to have either: |
| # - the same number of items globally |
| # - one item as default for all |
| # - no items as the cros-workon default |
| # The exceptions are: |
| # - CROS_WORKON_PROJECT has to have all items specified. |
| # - CROS_WORKON_TREE is not listed here because it may not have the same number |
| # of items as other array variables when CROS_WORKON_SUBTREE is used. |
| # See the variable description below for more details. |
| ARRAY_VARIABLES=( |
| CROS_WORKON_{SUBTREE,REPO,PROJECT,LOCALNAME,DESTDIR,COMMIT,SRCPATH,EGIT_BRANCH,OPTIONAL_CHECKOUT} ) |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_SUBTREE |
| # @DESCRIPTION: |
| # Subpaths of the source checkout to be used in the build, separated by |
| # whitespace. Normally this will be set to directories, but files are also |
| # allowed if necessary. |
| # Default value is an empty string, meaning the whole source checkout is used. |
| # It is strongly recommended to set this variable if the source checkout |
| # contains multiple packages (e.g. platform2) to avoid unnecessary uprev when |
| # unrelated files in the repository are modified. |
| # Access to files outside of these subpaths will be denied. |
| : ${CROS_WORKON_SUBTREE:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_REPO |
| # @DESCRIPTION: |
| # The base git URL to locate the remote repository. This is usually the root of |
| # the GoB server. It could be any git server, but for infra reliability, our |
| # policy is to only refer to servers we maintain (e.g. googlesource.com). |
| # It is combined with CROS_WORKON_PROJECT to form the full URL. |
| # Look at the cros-constants eclass for common values. |
| : ${CROS_WORKON_REPO:=${CROS_GIT_HOST_URL}} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_PROJECT |
| # @DESCRIPTION: |
| # The path on the remote server (beneath CROS_WORKON_REPO) to find the git repo. |
| # This has no relationship to where the source is checked out locally in the |
| # manifest. If looking at a manifest.xml, this is the "name" attribute of the |
| # "project" tag. |
| : ${CROS_WORKON_PROJECT:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_LOCALNAME |
| # @DESCRIPTION: |
| # The relative path in the local manifest checkout to find the local git |
| # checkout. The exact path it is relative to depends on the CATEGORY of the |
| # ebuild. For chromeos-base packages, this is relative to src/. For all other |
| # packages, it is relative to src/third_party/. This applies to all ebuilds |
| # regardless of the overlay they live in. |
| # If looking at a manifest.xml, this is related to the "path" attribute of the |
| # "project" tag (although that path is relative to the root of the manifest). |
| # |
| # *** WARNING *** |
| # Do NOT rely on this default value, it will go away. |
| # Instead override this to the desired value. |
| # TODO(https://crbug.com/916471): Remove the default value. |
| : ${CROS_WORKON_LOCALNAME:=${PN}} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_DESTDIR |
| # @DESCRIPTION: |
| # Destination directory in ${WORKDIR} for checkout. It must be under ${S}. |
| # Note that the default is ${S}, but is only referenced in src_unpack for |
| # ebuilds that would like to override it. |
| : ${CROS_WORKON_DESTDIR:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_COMMIT |
| # @DESCRIPTION: |
| # Git commit hashes of the source repositories. |
| # It is guaranteed that files identified by tree hashes in CROS_WORKON_TREE |
| # can be found in the commit. |
| # CROW_WORKON_COMMIT is updated only when CROS_WORKON_TREE below is updated, |
| # so it does not necessarily point to HEAD in the source repository. |
| : "${CROS_WORKON_COMMIT:=}" |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_TREE |
| # @DESCRIPTION: |
| # Git tree hashes of the contents of the source repositories. |
| # If CROS_WORKON_SUBTREE is set, tree hashes are taken from specified subpaths; |
| # otherwise, they are taken from the root directories of the source |
| # repositories. Therefore note that CROS_WORKON_TREE may have different number |
| # of entries than CROS_WORKON_COMMIT if multiple subpaths are specified in |
| # CROS_WORKON_SUBTREE. |
| # This is used for verifying the correctness of prebuilts. Unlike the commit |
| # hash, this hash is unaffected by the history of the repository, or by |
| # commit messages. |
| : ${CROS_WORKON_TREE:=} |
| |
| # Scalar variables. These variables modify the behaviour of the eclass. |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_SUBDIRS_TO_COPY |
| # @DESCRIPTION: |
| # Make cros-workon operate exclusively with the subtrees given by this array. |
| # NOTE: This only speeds up local_cp builds. Inplace/local_git builds are unaffected. |
| # It will also be disabled by using project arrays, rather than a single project. |
| : ${CROS_WORKON_SUBDIRS_TO_COPY:=/} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_SUBDIRS_TO_REV |
| # @DESCRIPTION: |
| # Array of directories in the source tree. If defined, this causes this ebuild |
| # to only uprev if there are changes within the specified subdirectories. |
| : ${CROS_WORKON_SUBDIRS_TO_REV:=/} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_SRCROOT |
| # @DESCRIPTION: |
| # Root of the manifest checkout. The src/platform/ and src/third_party/ and |
| # related trees all live here. It is extremely uncommon for any package to |
| # want to access this path, so please think twice (or consult with someone) |
| # before doing so. All source code that an ebuild needs should be listed in |
| # its CROS_WORKON_PROJECT settings (so changes can be properly tracked). |
| : ${CROS_WORKON_SRCROOT:="${CHROOT_SOURCE_ROOT}"} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_INPLACE |
| # @DESCRIPTION: |
| # Build the sources in place. Don't copy them to a temp dir. No ebuild should |
| # set this itself as it is meant for other tools (e.g. cros_workon_make). |
| : ${CROS_WORKON_INPLACE:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_USE_VCSID |
| # @DESCRIPTION: |
| # Export VCSID into the project. This may contain information like the git |
| # commit of the project's checkout as well as the current package version. |
| # Most packages do not use this, so unless you're sure you do, do not set it. |
| : ${CROS_WORKON_USE_VCSID:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_OUTOFTREE_BUILD |
| # @DESCRIPTION: |
| # Do not copy the source tree to $S; instead set $S to the |
| # source tree and store compiled objects and build state |
| # in $WORKDIR. The ebuild is responsible for ensuring |
| # the build output goes to $WORKDIR, e.g. setting |
| # O=${WORKDIR}/${P}/build/${board} when compiling the kernel. |
| : ${CROS_WORKON_OUTOFTREE_BUILD:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_INCREMENTAL_BUILD |
| # @DESCRIPTION: |
| # If set to "1", store output objects in a location that is not wiped |
| # between emerges. If disabled, objects will be written to ${WORKDIR} |
| # like normal. |
| : ${CROS_WORKON_INCREMENTAL_BUILD:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_MANUAL_UPREV |
| # @DESCRIPTION: |
| # If set to "1", the cros-workon uprev system on the bots will not automatically |
| # revbump your package when changes are made. This is useful if you want more |
| # direct control over when updates to the source git repo make it into the |
| # ebuild, or if the git repo you're using is not part of the official manifest. |
| # e.g. If you set CROS_WORKON_REPO or EGIT_REPO_URI to an external (to Google) |
| # site, set this to "1". |
| # Note that you must specify the CROS_WORKON_MANUAL_UPREV="1" line in both the |
| # unstable (i.e. 9999) and stable (e.g. 0.0.1-r) ebuild files. |
| : "${CROS_WORKON_MANUAL_UPREV:=}" |
| if [[ -n ${CROS_WORKON_BLACKLIST} ]]; then |
| die "CROS_WORKON_BLACKLIST has been renamed to CROS_WORKON_MANUAL_UPREV" |
| fi |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_MAKE_COMPILE_ARGS |
| # @DESCRIPTION: |
| # Args to pass to `make` when running src_compile. Not intended for ebuilds |
| # to set, just to respect. Used by `cros_workon_make` and friends. |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_EGIT_BRANCH |
| # @DESCRIPTION: |
| # This branch is used as EGIT_BRANCH when falling back to git-2. Leaving this |
| # as the default value of space will cause git-2 to fetch all branches with |
| # the special refspec ":". Since we don't know which branch CROS_WORKON_COMMIT |
| # is in, fetching all branches is a safe bet. However, if the git branch being |
| # updated can't be fast-forwarded (e.g. linux-next master), the branch needs to |
| # be specified because the special refspec excludes non-FF branches in fetches. |
| : ${CROS_WORKON_EGIT_BRANCH:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_ALWAYS_LIVE |
| # @DESCRIPTION: |
| # If set to "1", don't try to do a local fetch for 9999 ebuilds. |
| : ${CROS_WORKON_ALWAYS_LIVE:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_SRCPATH |
| # @DESCRIPTION: |
| # Location of the source directory relative to the brick source root. This is |
| # used for locally sourced packages and, if defined, takes precedence over |
| # Chrome OS specific source locations. |
| : ${CROS_WORKON_SRCPATH:=} |
| |
| # @ECLASS-VARIABLE: CROS_WORKON_OPTIONAL_CHECKOUT |
| # @DESCRIPTION: |
| # Command to determine whether the corresponding CROS_WORKON_PROJECT is |
| # included. More precisely, CROS_WORKON_PROJECT[i] is included iff |
| # CROS_WORKON_OPTIONAL_CHECKOUT[i] returns 0. |
| # |
| # A common pattern is using these commands to evaluate USE flags, for example, |
| # |
| # CROS_WORKON_PROJECT=(a b c) |
| # CROS_WORKON_OPTIONAL_CHECKOUT=("true" "use checkoutb" "use checkoutc") |
| # |
| # would always checkout project a, and checkout projects b and c if the |
| # checkoutb and checkout c USE flags were set, respectively. |
| # |
| # The default value is "true" meaning all projects are checked out. |
| : ${CROS_WORKON_OPTIONAL_CHECKOUT:="true"} |
| |
| # Join the tree commits to produce a unique identifier |
| CROS_WORKON_TREE_COMPOSITE=$(IFS="_"; echo "${CROS_WORKON_TREE[*]}") |
| IUSE="cros_host cros_workon_tree_$CROS_WORKON_TREE_COMPOSITE" |
| |
| inherit flag-o-matic toolchain-funcs |
| |
| # We need git-2 only for packages that define CROS_WORKON_PROJECT. Otherwise, |
| # there's no dependence on git and we don't want it pulled in. |
| if [[ -n "${CROS_WORKON_PROJECT[*]}" ]]; then |
| inherit git-2 |
| # Add this sentinel value because array_vars_autocomplete later mutates the array. |
| EMPTY_PROJECT=0 |
| else |
| EMPTY_PROJECT=1 |
| fi |
| |
| # Block deprecated vars. |
| if [[ ${CROS_WORKON_SUBDIR+set} == "set" ]]; then |
| die "CROS_WORKON_SUBDIR is no longer supported. Please use CROS_WORKON_LOCALNAME instead." |
| fi |
| |
| # Sanitize all variables, autocomplete where necessary. |
| # This function possibly modifies all CROS_WORKON_ variables inplace. It also |
| # provides a global project_count variable which contains the number of |
| # projects. |
| array_vars_autocomplete() { |
| # CROS_WORKON_{PROJECT,SRCPATH} must have all values explicitly filled in. |
| # They have to be of the same length, or one may be undefined (length <= 1 |
| # and empty). |
| project_count=${#CROS_WORKON_PROJECT[@]} |
| local srcpath_count=${#CROS_WORKON_SRCPATH[@]} |
| if [[ ${project_count} -lt ${srcpath_count} ]]; then |
| if [[ ${project_count} -gt 1 ]] || [[ -n "${CROS_WORKON_PROJECT[@]}" ]]; then |
| die "CROS_WORKON_PROJECT has fewer values than _SRCPATH" |
| fi |
| project_count=${srcpath_count} |
| elif [[ ${project_count} -gt ${srcpath_count} ]]; then |
| if [[ ${srcpath_count} -gt 1 ]] || [[ -n "${CROS_WORKON_SRCPATH[@]}" ]]; then |
| die "CROS_WORKON_SRCPATH has fewer values than _PROJECT" |
| fi |
| fi |
| |
| # No project_count is really bad. |
| if [[ ${project_count} -eq 0 ]]; then |
| die "Must have at least one value in CROS_WORKON_{PROJECT,SRCPATH}" |
| fi |
| # For one value, defaults will suffice, unless it's blank (likely undefined). |
| if [[ ${project_count} -eq 1 ]]; then |
| if [[ -z "${CROS_WORKON_SRCPATH[@]}" ]] && [[ -z "${CROS_WORKON_PROJECT[@]}" ]]; then |
| die "Undefined CROS_WORKON_{PROJECT,SRCPATH}" |
| fi |
| return |
| fi |
| |
| [[ ${CROS_WORKON_OUTOFTREE_BUILD} == "1" ]] && die "Out of Tree Build not compatible with multi-project ebuilds" |
| |
| local count var |
| for var in "${ARRAY_VARIABLES[@]}"; do |
| eval count=\${#${var}\[@\]} |
| if [[ ${count} -ne ${project_count} ]] && [[ ${count} -ne 1 ]]; then |
| die "${var} has ${count} projects. ${project_count} or one default expected." |
| fi |
| # Invariably, ${project_count} is at least 2 here. All variables also either |
| # have all items or the first serves as default (or isn't needed if |
| # empty). By looking at the second item, determine if we need to |
| # autocomplete. |
| local i |
| if [[ ${count} -ne ${project_count} ]]; then |
| for (( i = 1; i < project_count; ++i )); do |
| eval ${var}\[i\]=\${${var}\[0\]} |
| done |
| fi |
| eval einfo "${var}: \${${var}[@]}" |
| done |
| } |
| |
| # Filter ARRAY_VARIABLES based on CROS_WORKON_OPTIONAL_CHECKOUT. This function |
| # possibly modifies all of ARRAY_VARIABLES and project_count inplace. |
| filter_optional_projects() { |
| local kept_indices=() |
| local i |
| for (( i = 0; i < project_count; ++i )); do |
| local cmd=${CROS_WORKON_OPTIONAL_CHECKOUT[i]} |
| if eval "${cmd}"; then |
| kept_indices+=( "${i}" ) |
| else |
| einfo "Filtering out project ${CROS_WORKON_PROJECT[i]}: '${cmd}' returned false" |
| fi |
| done |
| |
| if [[ "${#kept_indices[@]}" -eq "${project_count}" ]]; then |
| return |
| fi |
| |
| if [[ "${#kept_indices[@]}" -eq 0 ]]; then |
| die "Must have at least one value of CROS_WORKON_OPTIONAL_CHECKOUT be true." |
| fi |
| |
| local var |
| for var in "${ARRAY_VARIABLES[@]}"; do |
| local filtered_var=() |
| for i in "${kept_indices[@]}"; do |
| local value |
| eval "value=\"\${${var}[i]}\"" |
| filtered_var+=( "${value}" ) |
| done |
| |
| eval "${var}"='( "${filtered_var[@]}" )' |
| done |
| |
| project_count=${#kept_indices[@]} |
| } |
| |
| # Calculate path where code should be checked out. |
| # Result passed through global variable "path" to preserve proper array quoting. |
| get_paths() { |
| local pathbase srcbase |
| pathbase="${CROS_WORKON_SRCROOT}" |
| |
| if [[ "${CATEGORY}" == "chromeos-base" || |
| "${CATEGORY}" == "brillo-base" ]] ; then |
| pathbase+=/src |
| else |
| pathbase+=/src/third_party |
| fi |
| |
| srcbase="$(dirname "$(dirname "$(dirname "$(dirname "${EBUILD}")")")")/src" |
| |
| path=() |
| local pathelement i |
| for (( i = 0; i < project_count; ++i )); do |
| if [[ -n "${CROS_WORKON_SRCPATH[i]}" ]]; then |
| pathelement="${CROS_WORKON_SRCROOT}/${CROS_WORKON_SRCPATH[i]}" |
| else |
| pathelement="${pathbase}/${CROS_WORKON_LOCALNAME[i]}" |
| if [[ ! -d "${pathelement}" ]]; then |
| ewarn "Could not find \"${pathelement}\"." |
| ewarn "The CROS_WORKON_LOCALNAME for this ebuild should be updated" |
| ewarn "to be relative to \"${pathbase}\"." |
| pathelement="${pathbase}/platform/${CROS_WORKON_LOCALNAME[i]}" |
| fi |
| fi |
| path+=( "${pathelement}" ) |
| done |
| } |
| |
| local_copy_cp() { |
| local src="${1}" |
| local dst="${2}" |
| einfo "Copying sources from ${src}" |
| local blacklist=( |
| # Python compiled objects are a pain. |
| "--exclude=*.py[co]" |
| # Assume any dir named ".git" is an actual git dir. We don't copy them |
| # as the ones created by `repo` are full of symlinks which are skipped |
| # due to --safe-links below which makes the git dir useless. |
| "--exclude=.git/" |
| ) |
| |
| local sl |
| for sl in "${CROS_WORKON_SUBDIRS_TO_COPY[@]}"; do |
| if [[ -d "${src}/${sl}" ]]; then |
| mkdir -p "${dst}/${sl}" |
| rsync -a --safe-links \ |
| --exclude-from=<( |
| cd "${src}/${sl}" || \ |
| die "cd ${src}/${sl}" |
| git ls-files --others --ignored --exclude-standard --directory 2>/dev/null | \ |
| sed 's:^:/:' |
| ) "${blacklist[@]}" "${src}/${sl}/" "${dst}/${sl}/" || \ |
| die "rsync -a --safe-links --exclude-from=<(...) ${blacklist[*]} ${src}/${sl}/ ${dst}/${sl}/" |
| fi |
| done |
| } |
| |
| symlink_in_place() { |
| local src="${1}" |
| local dst="${2}" |
| einfo "Using experimental inplace build in ${src}." |
| |
| SBOX_TMP=":${SANDBOX_WRITE}:" |
| |
| if [ "${SBOX_TMP/:$CROS_WORKON_SRCROOT://}" == "${SBOX_TMP}" ]; then |
| ewarn "For inplace build you need to modify the sandbox" |
| ewarn "Set SANDBOX_WRITE=${CROS_WORKON_SRCROOT} in your env." |
| fi |
| mkdir -p "${dst%/*}" |
| |
| if [[ "$(realpath "${src}")" != "$(realpath "${dst}")" ]]; then |
| ln -sfT "${src}" "${dst}" || die "ln -sfT ${src} ${dst}" |
| fi |
| } |
| |
| local_copy() { |
| # Local vars used by all called functions. |
| local src="${1}" |
| local dst="${2}" |
| |
| # If we want to use git, and the source actually is a git repo |
| if [ "${CROS_WORKON_INPLACE}" == "1" ]; then |
| symlink_in_place "${src}" "${dst}" |
| else |
| local_copy_cp "${src}" "${dst}" |
| fi |
| } |
| |
| set_vcsid() { |
| export VCSID="${PVR}-${1}" |
| |
| if [ "${CROS_WORKON_USE_VCSID}" = "1" ]; then |
| append-cppflags -DVCSID=\'\"${VCSID}\"\' |
| MAKEOPTS+=" VCSID=${VCSID}" |
| # When working with multiple projects, keep from adding the same |
| # flags many many times. |
| CROS_WORKON_USE_VCSID="2" |
| fi |
| } |
| |
| get_rev() { |
| GIT_DIR="$1" git rev-parse HEAD |
| } |
| |
| cros-workon_src_unpack() { |
| local fetch_method # local|git |
| |
| # Sanity check. We cannot have S set to WORKDIR because if/when we try |
| # to check out repos, git will die if it tries to check out into a dir |
| # that already exists. Some packages might try this when out-of-tree |
| # builds are enabled, and they'll work fine most of the time because |
| # they'll be using a full manifest and will just re-use the existing |
| # checkout in src/platform/*. But if the code detects that it has to |
| # make its own checkout, things fall apart. For out-of-tree builds, |
| # the initial $S doesn't even matter because it resets it below to the |
| # repo in src/platform/. |
| if [[ ${S} == "${WORKDIR}" ]]; then |
| die "Sorry, but \$S cannot be set to \$WORKDIR" |
| fi |
| |
| # Set the default of CROS_WORKON_DESTDIR. This is done here because S is |
| # sometimes overridden in ebuilds and we cannot rely on the global state |
| # (and therefore ordering of eclass inherits and local ebuild overrides). |
| : ${CROS_WORKON_DESTDIR:=${S}} |
| |
| # Fix array variables |
| array_vars_autocomplete |
| |
| filter_optional_projects |
| |
| # Make sure all CROS_WORKON_DESTDIR are under S. |
| local p r i |
| for p in "${CROS_WORKON_DESTDIR[@]}"; do |
| if [[ "${p}" != "${S}" && "${p}" != "${S}"/* ]]; then |
| die "CROS_WORKON_DESTDIR=${p} must be under S=${S}" |
| fi |
| done |
| |
| # Verify CROS_WORKON_COMMIT settings. |
| for (( i = 0; i < project_count; ++i )); do |
| r="${CROS_WORKON_COMMIT[i]}" |
| local tree="${CROS_WORKON_TREE[i]}" |
| if [[ "${PV}" == "9999" ]]; then |
| # Setting CROS_WORKON_COMMIT in 9999 ebuilds doesn't make sense nor is |
| # supported, so reject it up front. |
| if [[ -n "${tree}" ]]; then |
| die "9999 ebuilds must not set CROS_WORKON_COMMIT or CROS_WORKON_TREE" |
| fi |
| else |
| # Enforce that a full commit id is used to avoid possible collisions |
| # in the future. This comes up with hand edited ebuilds sometimes. |
| if [[ "${r}" == refs/tags/* ]]; then |
| # Allow tags when the ebuild is not auto-uprevving. |
| if [[ "${CROS_WORKON_MANUAL_UPREV}" != "1" ]]; then |
| die "CROS_WORKON_COMMIT may use git tags only with CROS_WORKON_MANUAL_UPREV=1" |
| fi |
| elif ! echo "${r}" | grep -Eq '^[0-9a-f]{40}$'; then |
| die "CROS_WORKON_COMMIT must be a full commit id to avoid collisions, not '${r}'" |
| fi |
| if [[ -n "${tree}" ]] && ! echo "${tree}" | grep -Eq '^[0-9a-f]{40}$'; then |
| die "CROS_WORKON_TREE must be a full commit id to avoid collisions, not '${tree}'" |
| fi |
| fi |
| done |
| |
| for (( i = 0; i < project_count; ++i )); do |
| p="${CROS_WORKON_PROJECT[$i]}" |
| r="${CROS_WORKON_REPO[$i]}" |
| if [[ "${p}" == /* ]]; then |
| die "CROS_WORKON_PROJECT: ${p}: paths should not be absolute" |
| elif [[ "${p}" == ../* ]]; then |
| die "CROS_WORKON_PROJECT: ${p}: paths should be relative to the root of the server" |
| fi |
| |
| # Catch a few semi-common mistakes with project source. https://crbug.com/1008106 |
| if [[ "${p}" == chromeos/* ]]; then |
| if [[ "${r}" == "${CROS_GIT_HOST_URL}" ]]; then |
| die "CROS_WORKON_PROJECT: ${p}: chromeos/ projects should have CROS_WORKON_REPO=\${CROS_GIT_INT_HOST_URL}" |
| fi |
| elif [[ "${p}" == chromium/* ]]; then |
| if [[ "${r}" == "${CROS_GIT_INT_HOST_URL}" ]]; then |
| die "CROS_WORKON_PROJECT: ${p}: chromiumos/ projects should have CROS_WORKON_REPO=\${CROS_GIT_HOST_URL}" |
| fi |
| fi |
| done |
| |
| if [[ "${PV}" == "9999" && "${CROS_WORKON_ALWAYS_LIVE}" != "1" ]] || [[ "${EMPTY_PROJECT}" == "1" ]]; then |
| # Live / non-repo packages |
| fetch_method=local |
| elif [[ "${PV}" != "9999" && "${CROS_WORKON_ALWAYS_LIVE}" == "1" ]]; then |
| die "CROS_WORKON_ALWAYS_LIVE is set for non-9999 ebuild" |
| else |
| fetch_method=git |
| fi |
| |
| local repo=( "${CROS_WORKON_REPO[@]}" ) |
| local project=( "${CROS_WORKON_PROJECT[@]}" ) |
| local destdir=( "${CROS_WORKON_DESTDIR[@]}" ) |
| local branch=( "${CROS_WORKON_EGIT_BRANCH[@]}" ) |
| get_paths |
| |
| # Automatically build out-of-tree for common.mk packages. |
| # TODO(vapier): Enable this once all common.mk packages have converted. |
| #if [[ -e ${path}/common.mk ]] ; then |
| # : ${CROS_WORKON_OUTOFTREE_BUILD:=1} |
| #fi |
| |
| if [[ ${fetch_method} == "git" && ${CROS_WORKON_OUTOFTREE_BUILD} == "1" ]] ; then |
| # See if the local repo exists, is unmodified, and is checked out to |
| # the right rev. This will be the common case, so support it to make |
| # builds a bit faster. |
| if [[ -d ${path} ]] ; then |
| if [[ ${CROS_WORKON_COMMIT} == "$(get_rev "${path}/.git")" ]] ; then |
| local changes=$( |
| cd "${path}" |
| # Needed as `git status` likes to grab a repo lock. |
| addpredict "${PWD}:${CHROOT_SOURCE_ROOT}/.repo" |
| # Ignore untracked files as they (should) be ignored by the build too. |
| git status --porcelain | grep -v '^[?][?]' |
| ) |
| if [[ -z ${changes} ]] ; then |
| fetch_method=local |
| else |
| # Assume that if the dev has changes, they want it that way. |
| : #ewarn "${path} contains changes" |
| fi |
| else |
| echo "Local checkout '${path}' is not at rev ${CROS_WORKON_COMMIT}." |
| echo "Will manually git clone to get the pinned state." |
| fi |
| else |
| # This will hit minilayout users a lot, and rarely non-minilayout |
| # users. So don't bother warning here. |
| : #ewarn "${path} does not exist" |
| fi |
| fi |
| |
| if [[ "${fetch_method}" == "git" ]] ; then |
| all_local() { |
| local p |
| for p in "${path[@]}"; do |
| [[ -d ${p} ]] || return 1 |
| done |
| return 0 |
| } |
| |
| local fetched=0 |
| if all_local; then |
| for (( i = 0; i < project_count; ++i )); do |
| # Looks like we already have a local copy of all repositories. |
| # Let's use these and checkout ${CROS_WORKON_COMMIT}. |
| # -s: For speed, share objects between ${path} and ${S}. |
| # -n: Don't checkout any files from the repository yet. We'll |
| # checkout the source separately. |
| # |
| # We don't use git clone to checkout the source because the -b |
| # option for clone defaults to HEAD if it can't find the |
| # revision you requested. On the other hand, git checkout fails |
| # if it can't find the revision you requested, so we use that |
| # instead. |
| |
| # Destination directory. If we have one project, it's simply |
| # ${CROS_WORKON_DESTDIR}. More projects either specify an array or go to |
| # ${S}/${project}. |
| |
| if [[ "${CROS_WORKON_COMMIT[i]}" == "master" ]]; then |
| # Since we don't have a CROS_WORKON_COMMIT revision specified, |
| # we don't know what revision the ebuild wants. Let's take the |
| # version of the code that the user has checked out. |
| # |
| # This almost replicates the pre-cros-workon behavior, where |
| # the code you had in your source tree was used to build |
| # things. One difference here, however, is that only committed |
| # changes are included. |
| # |
| # TODO(davidjames): We should fix the preflight buildbot to |
| # specify CROS_WORKON_COMMIT for all ebuilds, and update this |
| # code path to fail and explain the problem. |
| git clone -s "${path[i]}" "${destdir[i]}" || \ |
| die "Can't clone ${path[i]}." |
| : $(( ++fetched )) |
| else |
| git clone -sn "${path[i]}" "${destdir[i]}" || \ |
| die "Can't clone ${path[i]}." |
| if ! ( cd ${destdir[i]} && git checkout -q ${CROS_WORKON_COMMIT[i]} ) ; then |
| ewarn "Cannot run git checkout ${CROS_WORKON_COMMIT[i]} in ${destdir[i]}." |
| ewarn "Is ${path[i]} up to date? Try running repo sync." |
| rm -rf "${destdir[i]}/.git" |
| else |
| : $(( ++fetched )) |
| fi |
| fi |
| done |
| if [[ ${fetched} -eq ${project_count} ]]; then |
| # TODO: Id of all repos? |
| # We should run get_rev in destdir[0] because CROS_WORKON_COMMIT |
| # is only checked out there. Also, we can't use |
| # CROS_WORKON_COMMIT directly because it could be a named or |
| # abbreviated ref. |
| set_vcsid "$(get_rev "${destdir[0]}/.git")" |
| cros-workon_enforce_subtrees |
| return |
| else |
| ewarn "Falling back to git.eclass..." |
| fi |
| fi |
| |
| # We have to pull from git, maybe a private repo. |
| cros-credentials_setup |
| |
| |
| # Always pull all branches, if we are pulling source via git. |
| EGIT_ALL_BRANCH="1" |
| |
| for (( i = 0; i < project_count; ++i )); do |
| EGIT_BRANCH="${branch[i]}" |
| EGIT_REPO_URI="${repo[i]}/${project[i]}.git" |
| EGIT_PROJECT="${project[i]}" |
| EGIT_SOURCEDIR="${destdir[i]}" |
| EGIT_COMMIT="${CROS_WORKON_COMMIT[i]}" |
| # If the logic above checked out the repo (only one failed), then skip it. |
| if [[ -d "${EGIT_SOURCEDIR}/.git" ]]; then |
| einfo "Skipping existing checkout of ${EGIT_PROJECT} in ${EGIT_SOURCEDIR}" |
| continue |
| fi |
| # Clones to /var, copies src tree to the /build/<board>/tmp. |
| # Make sure git-2 does not run `unpack` for us automatically. |
| # The normal cros-workon flow above doesn't do it, so don't |
| # let git-2 do it either. http://crosbug.com/38342 |
| EGIT_NOUNPACK=true git-2_src_unpack |
| # TODO(zbehan): Support multiple projects for vcsid? |
| done |
| set_vcsid "${CROS_WORKON_COMMIT[0]}" |
| cros-workon_enforce_subtrees |
| return |
| fi |
| |
| einfo "Using local source dir(s): ${path[*]}" |
| |
| # Clone from the git host + repository path specified by |
| # CROS_WORKON_REPO + CROS_WORKON_PROJECT. Checkout source from |
| # the branch specified by CROS_WORKON_COMMIT into the workspace path. |
| # If the repository exists just punt and let it be copied off for build. |
| if [[ "${fetch_method}" == "local" && ! -d ${path} ]] ; then |
| ewarn "Sources are missing in ${path}" |
| ewarn "You need to cros_workon and repo sync your project. For example if you are working on the crash-reporter package:" |
| ewarn "cros_workon --board=amd64-generic start crash-reporter" |
| ewarn "repo sync" |
| fi |
| |
| einfo "path: ${path[*]}" |
| einfo "destdir: ${destdir[*]}" |
| |
| # Out of tree builds don't need to copy the source, but can use it |
| # directly. |
| if [[ ${CROS_WORKON_OUTOFTREE_BUILD} -eq 1 ]]; then |
| S="${path[0]}" |
| else |
| # Copy source tree to /build/<board>/tmp for building |
| for (( i = 0; i < project_count; ++i )); do |
| local_copy "${path[i]}" "${destdir[i]}" || \ |
| die "Cannot create a local copy" |
| done |
| fi |
| if [[ "${EMPTY_PROJECT}" == "0" ]]; then |
| set_vcsid "$(get_rev "${path[0]}/.git")" |
| fi |
| cros-workon_enforce_subtrees |
| } |
| |
| # Enforces subtree restrictions specified by CROS_WORKON_SUBTREE. |
| cros-workon_enforce_subtrees() { |
| local i j p q |
| |
| local destdir=( "${CROS_WORKON_DESTDIR[@]}" ) |
| |
| # If CROS_WORKON_OUTOFTREE_BUILD is enabled, CROS_WORKON_DESTDIR |
| # can be outdated. In that case, S has been set to path[0] at this |
| # point. |
| if [[ "${CROS_WORKON_OUTOFTREE_BUILD}" == 1 ]]; then |
| destdir=( "${S}" ) |
| fi |
| |
| # Gather the subtrees specified by CROS_WORKON_SUBTREE. All directories |
| # and files under those subtrees are not blacklisted. |
| local keep_dirs=() |
| for (( i = 0; i < project_count; ++i )); do |
| if [[ -z "${CROS_WORKON_SUBTREE[i]}" ]]; then |
| keep_dirs+=( "${destdir[i]}" ) |
| else |
| for p in ${CROS_WORKON_SUBTREE[i]}; do |
| keep_dirs+=( "${destdir[i]}/${p}" ) |
| done |
| fi |
| done |
| |
| keep_dirs=( $(IFS=$'\n'; LC_ALL=C sort -u <<<"${keep_dirs[*]}") ) |
| |
| # Ignore overlapping subtrees. |
| for (( i = 0; i < ${#keep_dirs[@]}; ++i )); do |
| p="${keep_dirs[i]}" |
| : $(( j = i + 1 )) |
| while (( j < ${#keep_dirs[@]} )); do |
| q="${keep_dirs[j]}" |
| if [[ "${q}" == "${p}"/* ]]; then |
| einfo "Ignoring overlapping CROS_WORKON_SUBTREE: ${q} is under ${p}" |
| keep_dirs=( "${keep_dirs[@]:0:j}" "${keep_dirs[@]:$(( j + 1 ))}" ) |
| else |
| : $(( ++j )) |
| fi |
| done |
| done |
| |
| # If the directory to keep is $S only, then there is nothing we need to do. |
| if [[ "${#keep_dirs[@]}" == 1 && "${keep_dirs}" == "${S}" ]]; then |
| return |
| fi |
| |
| # It is an error to specify a missing file in CROS_WORKON_SUBTREE. |
| for p in "${keep_dirs[@]}"; do |
| if [[ ! -e "${p}" ]]; then |
| die "File specified in CROS_WORKON_SUBTREE is missing: ${p}" |
| fi |
| done |
| |
| # Gather the parent directories of subtrees to use. |
| # Those directories are exempted from blacklist because we need them to |
| # reach subtrees. |
| local keep_parents=() |
| for p in "${keep_dirs[@]}"; do |
| if [[ "${p}" == "${S}" ]]; then |
| continue |
| fi |
| q="${p%/*}" |
| while [[ "${q}" != "${S}" ]]; do |
| keep_parents+=( "${q}" ) |
| q="${q%/*}" |
| done |
| done |
| |
| keep_parents=( $(IFS=$'\n'; LC_ALL=C sort -u <<<"${keep_parents[*]}") ) |
| |
| # Construct arguments to pass to find(1) to list directories/files to |
| # blacklist. |
| # |
| # The command line built here is tricky, but it does the following |
| # during traversal of the filesystem by depth-first order: |
| # |
| # 1. Do nothing about the root directory ($S). Note that we should not |
| # reach here if there is nothing to blacklist. |
| # 2. If the visiting file is a parent directory of a subtree (i.e. in |
| # $keep_parents[@]), then recurse into its contents. |
| # 3. If the visiting file is the top directory of a subtree (i.e. in |
| # $keep_dirs[@]), then do not recurse into its contents. |
| # 4. Otherwise, blacklist the visiting file, and if it is a directory, |
| # do not recursive into its contents. |
| # |
| local find_args=( "${S}" -mindepth 1 ) |
| for p in "${keep_parents[@]}"; do |
| find_args+=( ! -path "${p}" ) |
| done |
| find_args+=( -prune ) |
| for p in "${keep_dirs[@]}"; do |
| find_args+=( ! -path "${p}" ) |
| done |
| |
| if [[ "${S}" == "${WORKDIR}"/* ]]; then |
| # $S is writable, so just remove blacklisted files. |
| find "${find_args[@]}" -exec rm -rf {} + |
| else |
| # $S is read-only, so use portage sandbox. |
| local deny_paths="$(find "${find_args[@]}" -printf '%p:')" |
| deny_paths="${deny_paths%:}" |
| if [[ -n "${deny_paths}" ]]; then |
| adddeny "${deny_paths}" |
| fi |
| fi |
| } |
| |
| cros-workon_get_build_dir() { |
| local dir |
| if [[ ${CROS_WORKON_INCREMENTAL_BUILD} == "1" ]]; then |
| dir="${SYSROOT}/var/cache/portage/${CATEGORY}/${PN}" |
| local stripped_slot="${SLOT%%/*}" |
| # We don't use the colon when adding in SLOTs because some tools |
| # such as protoc interpret it as a special character in some |
| # flags... |
| [[ ${stripped_slot:-0} != "0" ]] && dir+="__${stripped_slot}" |
| else |
| dir="${WORKDIR}/build" |
| fi |
| echo "${dir}" |
| } |
| |
| cros-workon_pkg_setup() { |
| if [[ ${MERGE_TYPE} != "binary" && ${CROS_WORKON_INCREMENTAL_BUILD} == "1" ]]; then |
| local out=$(cros-workon_get_build_dir) |
| addwrite "${out}" |
| mkdir -p -m 755 "${out}" |
| chown ${PORTAGE_USERNAME}:${PORTAGE_GRPNAME} "${out}" "${out%/*}" |
| fi |
| } |
| |
| cros-workon_pkg_info() { |
| print_quoted_array() { printf '"%s"\n' "$@"; } |
| |
| array_vars_autocomplete > /dev/null |
| get_paths |
| CROS_WORKON_SRCDIR=("${path[@]}") |
| |
| local val var |
| for var in CROS_WORKON_SRCDIR CROS_WORKON_PROJECT ; do |
| eval val=(\"\${${var}\[@\]}\") |
| echo ${var}=\($(print_quoted_array "${val[@]}")\) |
| done |
| } |
| |
| EXPORT_FUNCTIONS pkg_setup src_unpack pkg_info |