← Back to issue list

expand-extensions fails to process advanced grammar in parts/part/prime

View original Github issue

Metadata

Project
snapcraft
Number
#5583
Type
issue
State
open
Author
tsteven4
Labels
Status: Triaged Type: Bug
Created
Updated
Closed

Current evaluation

expand-extensions crashes with AttributeError when a part's prime keyword uses advanced grammar (on amd64). Grammar is only processed for a fixed key list, not prime. Triaged, minimal reproducer provided, internal ticket SNAPCRAFT-1184 opened.

Suggested action: keep open

Reason: A maintainer (mr-cal) triaged this, confirmed it as a real bug, and provided a minimal reproducer; an internal Jira ticket (SNAPCRAFT-1184) was created. The root cause is visible in code: snapcraft/parts/grammar.py only processes a fixed _KEYS list (source, build-environment, build-packages, stage-packages, build-snaps, stage-snaps) and omits prime/stage, so the grammar dict reaches craft_parts validation unprocessed. It is a valid, scoped bug that should remain open until fixed.

Impact: 50 Quick Win: 30.0 Staleness: 45 Complexity: 40 Confidence: 70 Support Request: 5

Issue body

### Bug Description A little debugging shows the problem is with passing a dictionary: ```{'on amd64': ['usr/lib/*/libvpl.so.*']}``` when a string is expected. If the corresponding two lines in snapcraft.yaml are deleted expand-extensions completes without error. ### To Reproduce ``` git clone https://github.com/canonical/firefox-snap.git cd firefox-snap git checkout 68729cec83fb64bd123b178aecfd18e36e1e0a9e $ snapcraft expand-extensions --verbosity trace 2025-06-25 18:10:00.797 Starting snapcraft, version 8.9.4 2025-06-25 18:10:00.798 Logging execution to '/home/tsteven4/.local/state/snapcraft/log/snapcraft-20250625-181000.722229.log' 2025-06-25 18:10:00.798 Raw pre-parsed sysargs: args={'help': False, 'verbose': False, 'quiet': False, 'verbosity': <EmitterMode.TRACE: 5>, 'version': False} filtered=['expand-extensions'] 2025-06-25 18:10:00.799 General parsed sysargs: command='expand-extensions' args=[] 2025-06-25 18:10:00.799 Configuring application... 2025-06-25 18:10:00.801 Command parsed sysargs: Namespace() 2025-06-25 18:10:00.802 Setting up ConfigService 2025-06-25 18:10:00.882 Build plan: platform=None, build_for=None 2025-06-25 18:10:00.884 Running snapcraft expand-extensions on host 2025-06-25 18:10:01.007 snapcraft internal error: AttributeError("'dict' object has no attribute 'startswith'") 2025-06-25 18:10:01.028 Traceback (most recent call last): 2025-06-25 18:10:01.028 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_application/application.py", line 615, in run 2025-06-25 18:10:01.028 return_code = self._run_inner() 2025-06-25 18:10:01.029 ^^^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.029 File "/snap/snapcraft/15082/lib/python3.12/site-packages/snapcraft/application.py", line 173, in _run_inner 2025-06-25 18:10:01.030 return_code = super()._run_inner() 2025-06-25 18:10:01.030 ^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.030 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_application/application.py", line 594, in _run_inner 2025-06-25 18:10:01.031 return_code = dispatcher.run() or os.EX_OK 2025-06-25 18:10:01.031 ^^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.031 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_cli/dispatcher.py", line 528, in run 2025-06-25 18:10:01.032 return self._loaded_command.run(self._parsed_command_args) 2025-06-25 18:10:01.032 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.032 File "/snap/snapcraft/15082/lib/python3.12/site-packages/snapcraft/commands/extensions.py", line 138, in run 2025-06-25 18:10:01.033 project_data = models.Project.unmarshal(yaml_data_for_arch) 2025-06-25 18:10:01.033 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.033 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_application/models/base.py", line 62, in unmarshal 2025-06-25 18:10:01.034 return cls.model_validate(data) 2025-06-25 18:10:01.034 ^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.035 File "/snap/snapcraft/15082/lib/python3.12/site-packages/pydantic/main.py", line 703, in model_validate 2025-06-25 18:10:01.035 return cls.__pydantic_validator__.validate_python( 2025-06-25 18:10:01.035 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.036 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_application/models/project.py", line 107, in _validate_part 2025-06-25 18:10:01.036 craft_parts.validate_part(part) 2025-06-25 18:10:01.036 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_parts/parts.py", line 707, in validate_part 2025-06-25 18:10:01.037 _get_part_spec(data) 2025-06-25 18:10:01.037 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_parts/parts.py", line 758, in _get_part_spec 2025-06-25 18:10:01.037 return PartSpec(**part_spec) 2025-06-25 18:10:01.038 ^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.038 File "/snap/snapcraft/15082/lib/python3.12/site-packages/pydantic/main.py", line 253, in __init__ 2025-06-25 18:10:01.038 validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self) 2025-06-25 18:10:01.038 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.039 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_parts/constraints.py", line 44, in _validate_relative_path_str 2025-06-25 18:10:01.040 if path.startswith("/"): 2025-06-25 18:10:01.040 ^^^^^^^^^^^^^^^ 2025-06-25 18:10:01.040 AttributeError: 'dict' object has no attribute 'startswith' 2025-06-25 18:10:01.041 Full execution log: '/home/tsteven4/.local/state/snapcraft/log/snapcraft-20250625-181000.722229.log' ``` ### Environment Running snapcraft on Windows 11 WSL2 instance of ubuntu 24.04 ### snapcraft.yaml ```yaml # Copyright (C) 2021 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. name: firefox version: "140.0-1" summary: Mozilla Firefox web browser description: Firefox is a powerful, extensible web browser with support for modern web application technologies. confinement: strict grade: stable base: core24 source-code: https://github.com/canonical/firefox-snap assumes: - snapd2.54 # for mount-control compression: lzo apps: firefox: command: firefox.launcher desktop: firefox.desktop extensions: [gnome] environment: # See below and also the 'snap/hooks/post-refresh' file for # more details about our hunspell setup. DICPATH: "$SNAP_COMMON/snap-hunspell" GTK_USE_PORTAL: 1 HOME: "$SNAP_USER_COMMON" PIPEWIRE_CONFIG_NAME: "$SNAP/usr/share/pipewire/pipewire.conf" PIPEWIRE_MODULE_DIR: "$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/pipewire-0.3" SPA_PLUGIN_DIR: "$SNAP/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/spa-0.2" SPEECHD_ADDRESS: "unix_socket:/run/user/$SNAP_UID/speech-dispatcher/speechd.sock" MOZ_APP_REMOTINGNAME: "firefox_firefox" slots: - dbus-daemon - mpris plugs: - alsa - audio-playback - audio-record - avahi-observe - browser-sandbox - camera - cups-control - gsettings - hardware-observe - home - host-hunspell - host-usr-share-hunspell - joystick - login-session-observe - mount-observe - network - network-observe - opengl - pcscd - removable-media - screen-inhibit-control - system-packages-doc - u2f-devices - unity7 - upower-observe geckodriver: command: usr/lib/firefox/geckodriver extensions: [gnome] plugs: - network-bind # + all the plugs required by firefox, so that when geckodriver # executes firefox it inherits the correct set of permissions - audio-playback - audio-record - avahi-observe - browser-sandbox - camera - cups-control - gsettings - hardware-observe - home - host-hunspell - host-usr-share-hunspell - joystick - login-session-observe - network - network-observe - opengl - pcscd - removable-media - screen-inhibit-control - system-packages-doc - u2f-devices - unity7 - upower-observe slots: - dbus-daemon - mpris plugs: browser-sandbox: interface: browser-support allow-sandbox: true dot-mozilla-firefox: interface: personal-files read: [$HOME/.mozilla/firefox] etc-firefox: interface: system-files read: [/etc/firefox] host-hunspell: interface: mount-control mount: - what: /usr/share/hunspell where: $SNAP_COMMON/host-hunspell persistent: true options: [ro, bind, noatime, noexec] host-usr-share-hunspell: interface: system-files read: - /var/lib/snapd/hostfs/usr/share/hunspell layout: /usr/share/libdrm: bind: $SNAP/gnome-platform/usr/share/libdrm /usr/share/alsa: bind: $SNAP/usr/share/alsa /usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/opensc-pkcs11.so: bind-file: $SNAP/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/opensc-pkcs11.so parts: rust: plugin: nil build-packages: - wget override-pull: | # Do not use rustup to work around https://forum.snapcraft.io/t/armhf-builds-on-launchpad-timing-out/31008 REQUIRED_RUST_VERSION=1.82.0 ROOT=https://static.rust-lang.org/dist/rust-$REQUIRED_RUST_VERSION if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ]; then BINARIES_SUFFIX=x86_64-unknown-linux-gnu elif [ $CRAFT_ARCH_BUILD_FOR = "armhf" ]; then BINARIES_SUFFIX=armv7-unknown-linux-gnueabihf elif [ $CRAFT_ARCH_BUILD_FOR = "arm64" ]; then BINARIES_SUFFIX=aarch64-unknown-linux-gnu elif [ $CRAFT_ARCH_BUILD_FOR = "riscv64" ]; then BINARIES_SUFFIX=riscv64gc-unknown-linux-gnu fi wget -O - $ROOT-$BINARIES_SUFFIX.tar.gz | tar -x -z --strip-components=1 ./install.sh --prefix=/usr --destdir=$CRAFT_STAGE override-prime: '' cbindgen: plugin: nil after: - rust override-build: | craftctl default cargo install cbindgen override-prime: '' clang: plugin: nil build-packages: - binutils-dev - cmake - libncurses-dev - make - wget build-environment: - LLVM_RELEASE: "16.0.4" override-pull: | ROOT=https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_RELEASE # Download the binaries BINARIES_BASENAME=clang+llvm-$LLVM_RELEASE if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ]; then BINARIES_SUFFIX=x86_64-linux-gnu-ubuntu-22.04.tar.xz elif [ $CRAFT_ARCH_BUILD_FOR = "armhf" ]; then BINARIES_SUFFIX=armv7a-linux-gnueabihf.tar.xz elif [ $CRAFT_ARCH_BUILD_FOR = "arm64" ]; then BINARIES_SUFFIX=aarch64-linux-gnu.tar.xz fi wget -O - $ROOT/$BINARIES_BASENAME-$BINARIES_SUFFIX | tar -x --xz # And cmake-$LLVM_RELEASE.src needed on LLVM >= 15.0.0 wget -O - $ROOT/cmake-$LLVM_RELEASE.src.tar.xz | tar -x --xz mv cmake-$LLVM_RELEASE.src cmake if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ]; then # And the sources to build LLVMgold.so, which isn't distributed in a binary form wget -O - $ROOT/llvm-$LLVM_RELEASE.src.tar.xz | tar -x --xz fi override-build: | craftctl default if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ]; then cd llvm-$LLVM_RELEASE.src mkdir build cd build cmake -DLLVM_BINUTILS_INCDIR=/usr/include -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$CRAFT_PART_INSTALL/usr .. # TODO: use $CRAFT_PARALLEL_BUILD_COUNT again once https://github.com/canonical/snapcraft/issues/4785 is fixed make -j8 install-LLVMgold-stripped fi override-stage: | craftctl default mkdir -p usr cp -R $CRAFT_PART_SRC/clang+llvm-$LLVM_RELEASE-*/* usr/ override-prime: '' dump-syms: plugin: nil after: - rust build-packages: - curl - git - jq - python3-yaml override-pull: | if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ] || [ $CRAFT_ARCH_BUILD_FOR = "arm64" ]; then VERSION=$(craftctl get version | cut -d- -f1) BUILD=$(craftctl get version | cut -d- -f2 | cut -d. -f1) FFINFO=$(curl -s https://ftp.mozilla.org/pub/firefox/candidates/$VERSION-candidates/build$BUILD/linux-x86_64/en-US/firefox-$VERSION.json) MOZ_SOURCE_REPO=$(echo $FFINFO | jq -r .moz_source_repo) MOZ_SOURCE_STAMP=$(echo $FFINFO | jq -r .moz_source_stamp) FETCHES=$MOZ_SOURCE_REPO/raw-file/$MOZ_SOURCE_STAMP/taskcluster/kinds/fetch/toolchains.yml TOOLCHAINS=$(curl -sSL "${FETCHES}") unset PYTHONPATH REPO=$(echo "${TOOLCHAINS}" | /usr/bin/python3 -c 'import yaml, sys; fetches = yaml.safe_load(sys.stdin); print("{}".format(fetches["dump-syms"]["fetch"]["repo"]))') SHA1=$(echo "${TOOLCHAINS}" | /usr/bin/python3 -c 'import yaml, sys; fetches = yaml.safe_load(sys.stdin); print("{}".format(fetches["dump-syms"]["fetch"]["revision"]))') git clone "${REPO}" . && git checkout "${SHA1}" fi override-build: | craftctl default if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ] || [ $CRAFT_ARCH_BUILD_FOR = "arm64" ]; then cargo build --release cp target/release/dump_syms $CRAFT_STAGE/usr/bin/ fi # This is a temporary workaround to including the hunspell content # snap, which would cause breakage in the Ubuntu desktop image build # because of the Ubuntu policy. See: # https://bugzilla.mozilla.org/show_bug.cgi?id=1792006 # # The definition of this part is essentially a copy of the # corresponding part in hunspell-dictionaries-1-7-2004 by # Buo-ren, Lin. hunspell: plugin: nil override-build: | craftctl default set -eu apt download $(apt-cache search '^hunspell-.*$' | awk '!/myspell|dbgsym|tools|transitional|dependency/{printf "%s ", $1}') find . -name "*.deb" -exec dpkg-deb -x {} "$CRAFT_PART_INSTALL" \; prime: - usr/share/hunspell # We use the amd64 binary for all architectures since the used files are said # to be arch-independent. wasi-sdk: plugin: nil after: - clang build-packages: - wget build-environment: - WASI_BRANCH: "15" - WASI_RELEASE: "15.0" override-pull: | ROOT=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_BRANCH wget $ROOT/wasi-sysroot-$WASI_RELEASE.tar.gz wget $ROOT/libclang_rt.builtins-wasm32-wasi-$WASI_RELEASE.tar.gz override-build: | craftctl default tar -C $CRAFT_STAGE -xf wasi-sysroot-$WASI_RELEASE.tar.gz tar -C $CRAFT_STAGE/usr/lib/clang/* -xf libclang_rt.builtins-wasm32-wasi-$WASI_RELEASE.tar.gz override-prime: '' nodejs: plugin: nil build-packages: - wget build-environment: - NODEJS_RELEASE: "v16.18.1" override-pull: | ROOT=https://nodejs.org/dist/$NODEJS_RELEASE/node-$NODEJS_RELEASE-linux- if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ]; then SUFFIX=x64.tar.xz elif [ $CRAFT_ARCH_BUILD_FOR = "armhf" ]; then SUFFIX=armv7l.tar.xz elif [ $CRAFT_ARCH_BUILD_FOR = "arm64" ]; then SUFFIX=arm64.tar.xz fi wget -O - $ROOT$SUFFIX | tar -x --xz override-build: | craftctl default cp -R node-$NODEJS_RELEASE-linux-*/ $CRAFT_PART_INSTALL/usr/ override-prime: '' mozconfig: plugin: nil override-stage: | cp $CRAFT_PROJECT_DIR/mozconfig.in $CRAFT_STAGE/mozconfig override-prime: '' # Launchpad builders have a timeout for how long they are allowed to access # the internet (through a proxy) starting from the start of the build. # Since the firefox part takes a long time to build, we need to ensure # that all other parts that need to access the internet (to e.g. fetch build # or stage packages) are built before it (before the proxy authentication is # revoked). firefox: plugin: nil after: - apikeys - cbindgen - clang - distribution - dump-syms - ffmpeg - firefox-langpacks - hunspell - mozconfig - nodejs - rust - wasi-sdk build-packages: - cmake - coreutils - file - git - libasound2-dev - libdbus-glib-1-dev - libgtk2.0-dev - libpython3-dev - libx11-xcb-dev - libxt-dev - m4 - make - nasm - quilt - unzip - wget - xvfb - zip override-pull: | VERSION=$(craftctl get version | cut -d- -f1) BUILD=$(craftctl get version | cut -d- -f2 | cut -d. -f1) ROOT=https://ftp.mozilla.org/pub/firefox/candidates/$VERSION-candidates/build$BUILD wget -O - $ROOT/source/firefox-$VERSION.source.tar.xz | tar -x --xz --strip-components=1 mkdir -p $CRAFT_STAGE/debug-symbols cp toolkit/crashreporter/tools/upload_symbols.py $CRAFT_STAGE/debug-symbols/ override-build: | craftctl default QUILT_PATCHES=$CRAFT_PROJECT_DIR/patches quilt push -a BUILD_DBGSYMS=false if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ] || [ $CRAFT_ARCH_BUILD_FOR = "arm64" ]; then # Build and publish debug symbols for amd64 and arm64 only, # because Launchpad builders for armhf choke (OOM) when # building with debug symbols enabled, even with # patches/mozilla-reduce-rust-debuginfo.patch applied, # at least as of 2023-06-25. BUILD_DBGSYMS=true fi # GitHub Actions is limited to 2 CPUs and 7GB RAM, and # too much debug info from Rust will make gkrust linkage fail. # Same goes for arm64 builds on Launchpad. It seems we can't # detect $GITHUB_WORKSPACE, so we assume presence of the file # "symbols-upload-token" means we are running on GitHub. if [ -f "$CRAFT_PROJECT_DIR/symbols-upload-token"] || [ $CRAFT_ARCH_BUILD_FOR = "arm64" ] || [ $CRAFT_ARCH_BUILD_FOR = "armhf" ]; then patch -p1 < $CRAFT_PROJECT_DIR/patches/mozilla-reduce-rust-debuginfo.patch fi # Hardware is too limited on Launchpad armhf and amd64 builders, # so use thin rather than fat LTO. You can attempt to drop this when # amd64 builders have at least 32 GB of memory as per # https://help.launchpad.net/Packaging/BuilderSpecs if [ $CRAFT_ARCH_BUILD_FOR != "arm64" ]; then patch -p1 < $CRAFT_PROJECT_DIR/patches/thin-lto.patch fi export MOZCONFIG="$CRAFT_STAGE/mozconfig" if [ $BUILD_DBGSYMS = "true" ]; then echo "ac_add_options --enable-debug-symbols" >> $MOZCONFIG else echo "ac_add_options --disable-debug-symbols" >> $MOZCONFIG fi if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ]; then # Enable LTO and PGO (https://firefox-source-docs.mozilla.org/build/buildsystem/pgo.html) only on amd64 for now. # Linking with gold fails on armhf (error: undefined reference to '__aeabi_uldivmod') and would need to be # investigated further, and running PGO on arm64 takes forever (> 4 days in the Launchpad build environment!). echo "ac_add_options --enable-linker=lld" >> $MOZCONFIG echo "ac_add_options MOZ_PGO=1" >> $MOZCONFIG fi if [ $CRAFT_ARCH_BUILD_FOR != "armhf" ]; then echo "ac_add_options --enable-rust-simd" >> $MOZCONFIG fi echo "ac_add_options --prefix=$CRAFT_PART_INSTALL/usr" >> $MOZCONFIG GNOME_SDK_SNAP=/snap/gnome-46-2404-sdk/current if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ]; then # "clang -dumpmachine" returns "x86_64-unknown-linux-gnu" on # amd64 (at least the binaries they distribute), but what we # really need is "x86_64-pc-linux-gnu"; so let's hard-code it. export TARGET_TRIPLET="x86_64-pc-linux-gnu" else export TARGET_TRIPLET=$(clang -dumpmachine) fi export LDFLAGS="-Wl,-rpath-link=$GNOME_SDK_SNAP/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR -Wl,-rpath-link=$GNOME_SDK_SNAP/usr/lib" export LDFLAGS="-Wl,-rpath-link=$CRAFT_PART_BUILD/obj-$TARGET_TRIPLET/dist/bin${LDFLAGS:+ $LDFLAGS}" export LD_LIBRARY_PATH="$CRAFT_PART_BUILD/obj-$TARGET_TRIPLET/dist/bin${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" export WASI_SYSROOT=$CRAFT_STAGE/wasi-sysroot export MOZBUILD_STATE_PATH=$CRAFT_PART_BUILD/.mozbuild unset PYTHONPATH if [ $CRAFT_ARCH_BUILD_FOR = "amd64" ]; then # Needed for PGO-enabled builds that execute the built binaries. This should mirror the link paths in $LDFLAGS. export LD_LIBRARY_PATH="$GNOME_SDK_SNAP/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:$GNOME_SDK_SNAP/usr/lib" # Ensure the instrumented binary is run against the right version of libssl3.so and libnss3.so # (locally-built versions are more recent than the ones in the gnome platform snap) export LD_LIBRARY_PATH="$CRAFT_PART_BUILD/obj-$TARGET_TRIPLET/instrumented/dist/bin${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" fi MACH="/usr/bin/python3 ./mach" $MACH repackage desktop-file --output $CRAFT_PART_INSTALL/firefox.desktop --flavor snap --release-product "firefox" --release-type release --wmclass firefox_firefox if [ $CRAFT_TARGET_ARCH = "amd64" ]; then # xvfb is only needed when doing a PGO-enabled build # TODO: use $CRAFT_PARALLEL_BUILD_COUNT again once https://github.com/canonical/snapcraft/issues/4785 is fixed xvfb-run '--server-args=-screen 0 1920x1080x24' $MACH build -j8 else # TODO: use $CRAFT_PARALLEL_BUILD_COUNT again once https://github.com/canonical/snapcraft/issues/4785 is fixed $MACH build -j8 fi if [ $BUILD_DBGSYMS = "true" ]; then DUMP_SYMS=$CRAFT_STAGE/usr/bin/dump_syms $MACH buildsymbols fi $MACH install cp obj-*/dist/host/bin/geckodriver $CRAFT_PART_INSTALL/usr/lib/firefox/ DISTRIBUTION=$CRAFT_PART_INSTALL/usr/lib/firefox/distribution mkdir -p $DISTRIBUTION/extensions cp browser/branding/official/default256.png $CRAFT_PART_INSTALL/ if [ $BUILD_DBGSYMS = "true" ]; then cp obj-*/dist/firefox-*.crashreporter-symbols.zip $CRAFT_STAGE/debug-symbols/ fi # update the path to the vulkan drivers for the snap environment sed -i 's#/usr/lib/#/snap/firefox/current/usr/lib/#' $CRAFT_PART_INSTALL/usr/share/vulkan/icd.d/*.json override-stage: | # Workaround for LP: #2016358: create mount points for the gnome # content interface, while a proper fix is implemented in snapd. # Thanks to James Henstridge. mkdir $CRAFT_PART_INSTALL/{gnome-platform,data-dir,data-dir/{icons,sounds,themes}} craftctl default stage-packages: - libasound2t64 - libcurl4t64 - libpci3 - libpipewire-0.3-0t64 - libpipewire-0.3-modules - libspa-0.2-modules - libspeechd2 - libvulkan1 - libxt6t64 - mesa-vulkan-drivers - pipewire-bin - pipewire-pulse - opensc-pkcs11 prime: - default256.png - firefox.desktop - usr/lib/firefox - usr/lib/*/opensc-pkcs11.so - usr/lib/*/pkcs11/opensc-pkcs11.so - usr/lib/*/libasn1.so.* - usr/lib/*/libcurl.so.* - usr/lib/*/libgssapi.so.* - usr/lib/*/libhcrypto.so.* - usr/lib/*/libheimbase.so.* - usr/lib/*/libheimntlm.so.* - usr/lib/*/libhogweed.so.* - usr/lib/*/libhx509.so.* - usr/lib/*/libkrb5.so.* - usr/lib/*/liblber-2.4.so.* - usr/lib/*/libldap_r-2.4.so.* - usr/lib/*/libnettle.so.* - usr/lib/*/libnghttp2.so.* - usr/lib/*/libpci.so.* - usr/lib/*/libpipewire*.so* - usr/lib/*/libroken.so.* - usr/lib/*/librtmp.so.* - usr/lib/*/libsasl2.so.* - usr/lib/*/libspeechd.so.* - usr/lib/*/libssh.so.* - usr/lib/*/libssl.so.* - usr/lib/*/libvulkan* - usr/lib/*/libVkLayer* - usr/lib/*/libwind.so.* - usr/lib/*/libXt.so.* - usr/lib/*/pipewire-* - usr/lib/*/spa-* - usr/share/alsa - usr/share/pipewire - usr/share/vulkan # Workaround for LP: #2016358 (see the 'override-stage' above). - gnome-platform - data-dir/icons - data-dir/sounds - data-dir/themes firefox-langpacks: plugin: nil build-packages: - coreutils - sed - wget override-pull: | VERSION=$(craftctl get version | cut -d- -f1) BUILD=$(craftctl get version | cut -d- -f2 | cut -d. -f1) SERVER=https://ftp.mozilla.org ROOT=$SERVER/pub/firefox/candidates/$VERSION-candidates/build$BUILD XPIS=$(wget -O - $ROOT/linux-x86_64/xpi/ | sed -n 's/.* href="\(.*\.xpi\)".*/\1/p') for XPI in $XPIS; do wget $SERVER$XPI done override-prime: | INSTALLDIR=$CRAFT_PRIME/usr/lib/firefox/distribution/extensions mkdir -p $INSTALLDIR for XPI in $(ls $CRAFT_PART_SRC/*.xpi); do LANGCODE=$(basename $XPI .xpi) mkdir $INSTALLDIR/locale-$LANGCODE cp $XPI $INSTALLDIR/locale-$LANGCODE/langpack-$LANGCODE@firefox.mozilla.org.xpi done launcher: plugin: nil override-prime: | cp "$CRAFT_PROJECT_DIR/firefox.launcher" "$CRAFT_PRIME/" cp "$CRAFT_PROJECT_DIR/patch-default-profile.py" "$CRAFT_PRIME/" distribution: plugin: nil source: https://github.com/mozilla-partners/canonical.git override-prime: | mkdir -p $CRAFT_PRIME/usr/lib/firefox cp -R $CRAFT_PART_SRC/desktop/ubuntu/distribution $CRAFT_PRIME/usr/lib/firefox/ ffmpeg: plugin: nil # Not using the ffmpeg snap (which might provide a more recent version) # because it is currently built on core18 stage-packages: - libavcodec60 - libhwy1t64 - libsvtav1enc1d1 - libjxl0.7 - librav1e0 # the package is intel specific - on amd64: - libvpl2 prime: - usr/lib/*/libaom.so.* - usr/lib/*/libavcodec.so.* - usr/lib/*/libavutil.so.* - usr/lib/*/libcodec2.so.* - usr/lib/*/libdav1d.so.* - usr/lib/*/libgsm.so.* - usr/lib/*/libhwy.so.* - usr/lib/*/libjxl.so.* - usr/lib/*/libjxl_threads.so.* - usr/lib/*/libmd.so.* - usr/lib/*/libmfx.so.* - usr/lib/*/libmp3lame.so.* - usr/lib/*/libnuma.so.* - usr/lib/*/libOpenCL.so.* - usr/lib/*/libopus.so.* - usr/lib/*/librav1e.so.* - usr/lib/*/libshine.so.* - usr/lib/*/libsnappy.so.* - usr/lib/*/libsoxr.so.* - usr/lib/*/libspeex.so.* - usr/lib/*/libSvtAv1Enc.so.* - usr/lib/*/libswresample.so.* - usr/lib/*/libtheoradec.so.* - usr/lib/*/libtheoraenc.so.* - usr/lib/*/libtwolame.so.* - usr/lib/*/libvdpau.so.* - usr/lib/*/libvpx.so.* - usr/lib/*/libwavpack.so.* - usr/lib/*/libwebpmux.so.* - usr/lib/*/libwebp.so.* - usr/lib/*/libx264.so.* - usr/lib/*/libx265.so.* - usr/lib/*/libxvidcore.so.* - usr/lib/*/libzvbi.so.* # the package is intel specific - on amd64: - usr/lib/*/libvpl.so.* apikeys: plugin: nil after: - mozconfig build-packages: - coreutils - gpg - jq override-build: | craftctl default MOZCONFIG="$CRAFT_STAGE/mozconfig" gpg -d --batch --passphrase "$(base64 -d $CRAFT_PROJECT_DIR/.passphrase)" -o apikeys $CRAFT_PROJECT_DIR/.apikeys cat apikeys | jq .MOZ_GOOGLE_LOCATION_SERVICE_API_KEY | tr -d '"' > $CRAFT_PART_INSTALL/gls-gapi.data echo "ac_add_options --with-google-location-service-api-keyfile=$CRAFT_STAGE/gls-gapi.data" >> $MOZCONFIG cat apikeys | jq .MOZ_GOOGLE_SAFEBROWSING_API_KEY | tr -d '"' > $CRAFT_PART_INSTALL/sb-gapi.data echo "ac_add_options --with-google-safebrowsing-api-keyfile=$CRAFT_STAGE/sb-gapi.data" >> $MOZCONFIG override-prime: '' debug-symbols: plugin: nil build-packages: - python3 - python3-virtualenv after: - firefox override-build: | export SYMBOLS_ARCHIVE=$(find $CRAFT_STAGE/debug-symbols/ -type f -name "firefox-*.crashreporter-symbols.zip") if [ -f "$SYMBOLS_ARCHIVE" ]; then if [ -f "$CRAFT_PROJECT_DIR/symbols-upload-token" ]; then virtualenv venv/ source venv/bin/activate venv/bin/pip3 install redo requests argparse SOCORRO_SYMBOL_UPLOAD_URL=https://symbols.stage.mozaws.net/upload/ SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE="$CRAFT_PROJECT_DIR/symbols-upload-token" venv/bin/python3 $CRAFT_STAGE/debug-symbols/upload_symbols.py $SYMBOLS_ARCHIVE rm "$CRAFT_PROJECT_DIR/symbols-upload-token" deactivate else cp $SYMBOLS_ARCHIVE $CRAFT_PROJECT_DIR/$CRAFT_PROJECT_NAME_$(craftctl get version)_$CRAFT_ARCH_BUILD_FOR.debug fi fi slots: dbus-daemon: interface: dbus bus: session name: org.mozilla.firefox hooks: post-refresh: plugs: [host-usr-share-hunspell] ``` ### Relevant log output ```shell 2025-06-25 18:13:57.414 Starting snapcraft, version 8.9.4 2025-06-25 18:13:57.414 Log verbosity level set to BRIEF 2025-06-25 18:13:57.414 Setting up Project 2025-06-25 18:13:57.415 Project file found at '/home/tsteven4/work/firefox-expandextensions/snapcraft.yaml' 2025-06-25 18:13:57.415 Loading project file 'snapcraft.yaml 2025-06-25 18:13:57.489 Preparing application... 2025-06-25 18:13:57.490 Merging commands for group 'Lifecycle': 2025-06-25 18:13:57.490 - using application command for 'clean'. 2025-06-25 18:13:57.490 - using application command for 'pull'. 2025-06-25 18:13:57.490 - using application command for 'build'. 2025-06-25 18:13:57.490 - using application command for 'stage'. 2025-06-25 18:13:57.490 - using application command for 'prime'. 2025-06-25 18:13:57.490 - using application command for 'pack'. 2025-06-25 18:13:57.490 Merging commands for group 'Other': 2025-06-25 18:13:57.491 Raw pre-parsed sysargs: args={'help': False, 'verbose': False, 'quiet': False, 'verbosity': <EmitterMode.TRACE: 5>, 'version': False} filtered=['expand-extensions'] 2025-06-25 18:13:57.491 General parsed sysargs: command='expand-extensions' args=[] 2025-06-25 18:13:57.492 Configuring application... 2025-06-25 18:13:57.494 Command parsed sysargs: Namespace() 2025-06-25 18:13:57.494 Setting up ConfigService 2025-06-25 18:13:57.575 Build plan: platform=None, build_for=None 2025-06-25 18:13:57.576 Running snapcraft expand-extensions on host 2025-06-25 18:13:57.711 snapcraft internal error: AttributeError("'dict' object has no attribute 'startswith'") 2025-06-25 18:13:57.735 Traceback (most recent call last): 2025-06-25 18:13:57.736 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_application/application.py", line 615, in run 2025-06-25 18:13:57.736 return_code = self._run_inner() 2025-06-25 18:13:57.737 ^^^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.737 File "/snap/snapcraft/15082/lib/python3.12/site-packages/snapcraft/application.py", line 173, in _run_inner 2025-06-25 18:13:57.737 return_code = super()._run_inner() 2025-06-25 18:13:57.737 ^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.738 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_application/application.py", line 594, in _run_inner 2025-06-25 18:13:57.738 return_code = dispatcher.run() or os.EX_OK 2025-06-25 18:13:57.738 ^^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.738 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_cli/dispatcher.py", line 528, in run 2025-06-25 18:13:57.738 return self._loaded_command.run(self._parsed_command_args) 2025-06-25 18:13:57.738 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.739 File "/snap/snapcraft/15082/lib/python3.12/site-packages/snapcraft/commands/extensions.py", line 138, in run 2025-06-25 18:13:57.739 project_data = models.Project.unmarshal(yaml_data_for_arch) 2025-06-25 18:13:57.739 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.739 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_application/models/base.py", line 62, in unmarshal 2025-06-25 18:13:57.740 return cls.model_validate(data) 2025-06-25 18:13:57.740 ^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.740 File "/snap/snapcraft/15082/lib/python3.12/site-packages/pydantic/main.py", line 703, in model_validate 2025-06-25 18:13:57.741 return cls.__pydantic_validator__.validate_python( 2025-06-25 18:13:57.741 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.741 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_application/models/project.py", line 107, in _validate_part 2025-06-25 18:13:57.742 craft_parts.validate_part(part) 2025-06-25 18:13:57.743 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_parts/parts.py", line 707, in validate_part 2025-06-25 18:13:57.743 _get_part_spec(data) 2025-06-25 18:13:57.744 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_parts/parts.py", line 758, in _get_part_spec 2025-06-25 18:13:57.744 return PartSpec(**part_spec) 2025-06-25 18:13:57.744 ^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.745 File "/snap/snapcraft/15082/lib/python3.12/site-packages/pydantic/main.py", line 253, in __init__ 2025-06-25 18:13:57.745 validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self) 2025-06-25 18:13:57.746 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.746 File "/snap/snapcraft/15082/lib/python3.12/site-packages/craft_parts/constraints.py", line 44, in _validate_relative_path_str 2025-06-25 18:13:57.747 if path.startswith("/"): 2025-06-25 18:13:57.747 ^^^^^^^^^^^^^^^ 2025-06-25 18:13:57.748 AttributeError: 'dict' object has no attribute 'startswith' 2025-06-25 18:13:57.749 Full execution log: '/home/tsteven4/.local/state/snapcraft/log/snapcraft-20250625-181357.409022.log' ``` ### Additional context _No response_

Evaluation history

Date Model Scores Action Summary
qwen/qwen3.8-27b
Impact: 50
Quick Win: 30.0
Staleness: 45
Complexity: 40
Confidence: 70
Support Request: 5
keep open expand-extensions crashes with AttributeError when a part's prime keyword uses advanced grammar (on amd64). Grammar is only processed for a fixed key list, not prime. Triaged, minimal reproducer provided, internal ticket SNAPCRAFT-1184 opened.
qwen/qwen3.6-35b-a3b
Staleness: 75
Complexity: 65
Confidence: 85
Support Request: 10
keep open snapcraft expand-extensions crashes with AttributeError when parsing architecture-specific overrides in the prime keyword. Triaged, Jira ticket created, awaiting fix.
qwen3.6-35b-a3b-mtp-q6
Staleness: 75
Complexity: 60
Confidence: 85
Support Request: 10
keep open Bug in snapcraft expand-extensions causing AttributeError when parsing architecture-specific grammar in the prime keyword. Triaged, internal ticket created, but inactive for over a year.
qwen3.6-35b-a3b-mtp-q6
Staleness: 80
Complexity: 25
Confidence: 90
Support Request: 0
keep open snapcraft expand-extensions crashes parsing architecture-specific dictionary grammar in the prime section. The bug is triaged and confirmed. An internal ticket exists, but the issue remains waiting to be assigned.

Update history

No update history recorded yet.

Related issues

Issue Project State Summary Similarity
#874 Craft-parts cannot parse advanced grammar in `stage` and `prime` fields craft-parts open craft-parts crashes with AttributeError when stage/prime entries use advanced grammar. Maintainer triaged: root cause is snapcraft's expand-extensions not processing grammar for prime (snapcraft#5583, open). No activity for ~18 months.
81%