The future is now: opkg vs apk

Yeah, needs a bunch of caveats, though.

If you run ext4, then /rom is empty.

If you did ASU upgrade, then /rom world now includes all the packages that were present in pre-upgrade /overlay version of world.

When I first read that thread, which was asking, "How does one determine which packages were "user-installed"?", I dismissed the grep commands as not very useful in that context. They certainly won't answer that specific question accurately; better to use owut list, which was implemented to give an exact answer to that question and includes all the removals, too.

Perhaps I wasn't clear enough. Let me provide a concrete example:

opkg workflow:
grep "^Size:" /var/opkg-lists/base | awk '{sum+=$2}'

Done. Simple one-liner.

apk workflow:
for pkg in $(apk list -I); do apk info --size $pkg; done

Requires iterating thousands of packages.

I assumed this difference was obvious to anyone working with package management at scale. If my English explanation was inadequate, I apologize.

Or format yaml if that suits your workflow better:

$ apk --installed query --fields name,installed-size,file-size --format json '*'
[
  {
    "name": "adblock",
    "installed-size": 87368,
    "file-size": 22363
  }, {
    "name": "addrwatch",
    "installed-size": 53161,
    "file-size": 23367
  }, {
    "name": "apcupsd",
    "installed-size": 579553,
    "file-size": 242557
  }, {
    "name": "apk-mbedtls",
    "installed-size": 232023,
    "file-size": 123142
  }, {
    "name": "atop",
    "installed-size": 304031,
...

Currently, APK's index.json only contains package names and versions:

{
  "packages": {
    "luci": "24.339.76330~d0000e1",
    "kmod-usb-storage": "6.12.66-1"
  }
}

Feature Request: Include package size information in index.json, similar to opkg's Packages format:
Package: luci
Version: 24.339.76330~d0000e1
Size: 104857
Installed-Size: 524288

Use case:
Web-based package selectors need to display package sizes without making individual HEAD requests for hundreds of packages.

Proposed solution:
Add size and installed_size fields to index.json:

{
  "packages": {
    "luci": {
      "version": "24.339.76330~d0000e1",
      "size": 104857,
      "installed_size": 524288
    }
  }
}

This data already exists in the APKv3 database - it just needs to be exported to index.json.

P.S. While apk query --format json works locally on the router, I need this data in the hosted index.json for remote access.

Right, I wrote that to specifically support the ASU server, which is the only user and it needs those files as compact/fast as possible. Why don't you just download packages.adb instead if you need the full database and use host apk on your server? No need to modify our special purpose, OpenWrt-only json files...

1 Like

@efahl

I understand now, thank you for the explanation!

I'm building a custom firmware selector that hooks into the official OpenWrt interface:

I was struggling because Cloudflare Workers (my hosting platform) can't execute APK commands to parse packages.adb.

But your explanation clarified the design policy - I'll handle package size display on my side instead of requesting changes to index.json.

Thanks again!

Oh, I forgot to mention that index.json is probably inappropriate for your use anyhow, as it contains mangled package names. Since ASU operates in the "ABI Free Zone", any packages with an ABI suffix in their name (libubox20260213) will have that stripped (libubox) in that particular file, and recovering it is quite a chore (requires the contents of several fields in packages.adb). It's easier to just start with packages.adb.

Re: Package Size Information via ASU API

Thank you @efahl for the suggestion about using packages.adb via ASU server.

I investigated the ASU API documentation and tested the available endpoints:

  • /api/v1/overview - Returns version/target/architecture information only
  • /api/v1/stats - Returns build queue length only
  • /api/v1/build - Accepts build requests but doesn't return package size information
  • /json/v1/overview.json - Same as above

Conclusion: While the ASU server internally uses APK and packages.adb for dependency resolution during image builds, this functionality is not exposed via any external API endpoint. There is no API that returns individual package size information.

Therefore, I will continue using the current approach:

  1. Fetch package names/versions from index.json
  2. Send HEAD requests to individual .apk files
  3. Extract size from Content-Length headers

This remains the only practical browser-based solution for obtaining package sizes.

Thank you for the discussion—it helped clarify what's actually available via the ASU API.

I created the original script that ends up generating ipk files for those packages. Glad to read it’s working well for you!
I was hoping I could just let the script generate packages for apk similarly.

I intend to try this soon and will let it know if there are any problems.

PS: Regarding the licensing, never say never. I can’t say Devolo is ignoring us.

1 Like

How are you building the .ipk files? If you're using the buildroot stuff, then the transition should be pretty simple, just turn on CONFIG_USE_APK=y.

If you're "hand constructing" them, then you might take a look at https://github.com/openwrt/openwrt/blob/main/include/package-pack.mk#L593. Should be able to find host apk-tools v3 for a number of distros (I see v 3.0.3 on Fedora), or failing that use containerized Alpine ( podman run -it docker.io/library/alpine:latest).

1 Like

By calling the ipk-build script that’s included with OpenWrt is the short answer.

I created a script that accepts an existing OpenWrt image file and reconstructs all the packages that are installed inside using the data from /usr/lib/opkg/info using ipk-build. (Then I added a list to just construct the needed G.hn packages plus some patching.)

This is great! I was indeed looking for an example on how to call apkg mkpkg although I hadn’t looked too much into it just yet. (I saw a suggestion on the forum to look at Alpine’s docs.)

As Devolo’s images will not move beyond OpenWrt 15.05, the first part logic can stay. It is only be a matter of calling apkg mkpkg with the right arguments. I saw that there was an apk host binary in my OpenWrt build tree with the mkpkg command. With the example you pointed me to, I guess it should not be too hard to implement this. Many thanks!!

In case anybody here is interested, I put the script here recently:

Yup, I use staging_dir/host/bin/apk adbdump ... quite often to see what's inside various packages and indexes.

I forgot to mention that the device apk is the tiny version, with several "applets" removed, most importantly for your use case apk mkpkg, but also apk mkindx, so the host version is the way to go for this job. (I've taken a poke at creating a device apk-full... package that includes everything, but haven't gotten anywhere on it.)

1 Like

I did not do too much testing, but it seems to be working now:

(1/9) Installing delos-base-files (1.0-r7)
  Installing file to etc/config/delos.apk-new
(2/9) Installing delos-device-name (0.0_p20230906)
(3/9) Installing devolo-shared-configlayer (2.34.1)
(4/9) Installing dlan2-fw-flashless-2400-ac (001-r4)
(5/9) Installing dlan2-tools (0.0_p20230906)
(6/9) Installing ghn-flashless (001-r4)
  Installing file to etc/init.d/ghn-host.apk-new
(7/9) Installing ghn-host (0.0_p20230906)
(8/9) Installing libssp (5.2.0-r1)
(9/9) Installing posix-timezone-db (2021a-r2)
OK: 24.3 MiB in 189 packages

I created an apk-build script which essentially takes the same input as the original ipkg-build script which calls apk mkpkg to build the packages. Two things I had to drop/alter:

  1. Version information, it seems apk is much stricter and some ipk versions were things like Git hashes which seem to get rejected.
  2. Dependency information, it seems packages like base-files, libc, libubox, etc. are not there with the same names? Maybe I could rewrite/fix dependencies at some point. I’m not sure whats going on there, but it was complaining so I just removed the dependencies for now.

@xize, maybe you can test the new version? It should give you APK packages now. https://codeberg.org/jschwart/devolo-extract-ghn-packages

1 Like

I will have a look later this week :slight_smile: thank you very much!

1 Like

Yeah, version checking is a bit different. You can embed hashes in the version, it just needs to be separated from the version parts by a tilde, like owut-2026.01.13~2526d84b-r1. You can test with apk version --check to see if things are correct:

$ apk version --check '1.2.3-bort-r1' && echo 'Looks good!'
1.2.3-bort-r1

$ apk version --check '1.2.3~abcd-r1' && echo 'Looks good!'
Looks good!

The dependencies should be substantially the same. Maybe an issue with ABI names for things like libubox? Should use one of the provides values for that:

$ apk --installed query --fields name,package,provides,reverse-depends --format yaml libubox20260213
# 1 items
- package: libubox20260213-2026.02.13~1aa36ee7-r1
  name: libubox20260213
  provides: # 2 items
    - libubox
    - libubox-any
  reverse-depends:
    - rpcd
    - netifd
    - libustream-openssl20201210
...

But picking one of those "dependees" shows it's defined against the ABI-versioned names:

$ apk --installed query --fields name,package,provides,depends --format yaml rpcd
# 1 items
- package: rpcd-2025.12.03~ffb9961c-r1
  name: rpcd
  depends: # 6 items
    - libblobmsg-json20260213
    - libc
    - libjson-c5
    - libubox20260213
    - libubus20251202
    - libuci20250120
  provides: # 1 items
    - rpcd-any

Ah that’s good to know. But can there just a be hash and no date as well? For instance one ipk version is fdb2dee-1, another version is cdee4af640bdcf3299490ea16f256ad2ebaa06cc-1.

Hmm, I was getting these errors:

WARNING: opening from cache https://downloads.openwrt.org/snapshots/targets/ipq40xx/generic/packages/packages.adb: No such file or directory
WARNING: opening from cache https://downloads.openwrt.org/snapshots/packages/arm_cortex-a7_neon-vfpv4/base/packages.adb: No such file or directory
WARNING: opening from cache https://downloads.openwrt.org/snapshots/packages/arm_cortex-a7_neon-vfpv4/luci/packages.adb: No such file or directory
WARNING: opening from cache https://downloads.openwrt.org/snapshots/packages/arm_cortex-a7_neon-vfpv4/packages/packages.adb: No such file or directory
WARNING: opening from cache https://downloads.openwrt.org/snapshots/packages/arm_cortex-a7_neon-vfpv4/routing/packages.adb: No such file or directory
WARNING: opening from cache https://downloads.openwrt.org/snapshots/packages/arm_cortex-a7_neon-vfpv4/telephony/packages.adb: No such file or directory
WARNING: opening from cache https://downloads.openwrt.org/snapshots/packages/arm_cortex-a7_neon-vfpv4/video/packages.adb: No such file or directory
ERROR: unable to select packages:
  base-files, (no such package):
    required by: delos-base-files-1.0-r7[base-files,]
  delos-device-name, (no such package):
    required by: delos-base-files-1.0-r7[delos-device-name,]
  libc, (no such package):
    required by: delos-base-files-1.0-r7[libc,] delos-device-name-0.0_p20230906[libc,] devolo-shared-configlayer-2.34.1[libc,] dlan2-fw-flashless-2400-ac-001-r4[libc,]
                 dlan2-tools-0.0_p20230906[libc,] ghn-flashless-001-r4[libc,] ghn-host-0.0_p20230906[libc,] posix-timezone-db-2021a-r2[libc,]
  libssp, (no such package):
    required by: delos-base-files-1.0-r7[libssp,] devolo-shared-configlayer-2.34.1[libssp,] dlan2-fw-flashless-2400-ac-001-r4[libssp,]
                 dlan2-tools-0.0_p20230906[libssp,] ghn-flashless-001-r4[libssp,] ghn-host-0.0_p20230906[libssp,]
  posix-timezone-db, (no such package):
    required by: delos-base-files-1.0-r7[posix-timezone-db,]
  uci, (no such package):
    required by: delos-base-files-1.0-r7[uci,]
  libpthread, (no such package):
    required by: dlan2-tools-0.0_p20230906[libpthread,] ghn-host-0.0_p20230906[libpthread,]
  ghn-flashless, (no such package):
    required by: dlan2-fw-flashless-2400-ac-001-r4[ghn-flashless,]
  dlan2-tools, (no such package):
    required by: ghn-flashless-001-r4[dlan2-tools,]
  ghn-host, (no such package):
    required by: ghn-flashless-001-r4[ghn-host,]
  libblobmsg-json, (no such package):
    required by: ghn-host-0.0_p20230906[libblobmsg-json,]
  libubox, (no such package):
    required by: ghn-host-0.0_p20230906[libubox,]
  libubus, (no such package):
    required by: ghn-host-0.0_p20230906[libubus,]
  libuci, (no such package):
    required by: ghn-host-0.0_p20230906[libuci,]

It could also be my unclean environment though (I had used opkg before) or maybe some odd character sneaking in with the conversion?

To get around the library version in the filename, the script runs patchelf to patch all library references to point to the right library versions. (In the Devolo firmware the libraries have no versions in their filename.)

Unfortunately this only works for the ARM (next) version of the device. There is an older MIPS (v1) version and its firmware is based on uClibc while OpenWrt uses musl instead. To get those binaries to run the script also creates packages for all the uClibc library dependencies when targeting that device…
(Getting G.hn itself going needs more work though, probably a DSA port…)

I think those would both need a fake version number prefixing the hash, and the rev has to start with r, so

0~cdee4af640bdcf3299490ea16f256ad2ebaa06cc-r1

The dependency requirements are still not real clear to me, as I just haven't experimented with them enough. I thought that the name was sufficient, but maybe it needs to be something from the provides list... @Dante just did a major rework of all this a few months back, so maybe he could make an observation here.

$ apk query --fields name,package,provides --format yaml libc base-files
# 2 items
- package: base-files-1683~8b994ed397
  name: base-files
  provides: # 1 items
    - base-files-any

- package: libc-1.2.5-r5
  name: libc
  provides: # 1 items
    - libc-any
1 Like

Yes, this indeed works!! I just pushed a commit that follows this pattern and now things are quite close to the original ipk versions:

delos-base-files_1.0-r7_arm_cortex-a7_neon-vfpv4.apk
delos-device-name_0~fdb2dee-r1_arm_cortex-a7_neon-vfpv4.apk
devolo-shared-configlayer_2.34.1_arm_cortex-a7_neon-vfpv4.apk
dlan2-fw-flashless-2400-ac_001-r4_arm_cortex-a7_neon-vfpv4.apk
dlan2-tools_0~cdee4af640bdcf3299490ea16f256ad2ebaa06cc-r1_arm_cortex-a7_neon-vfpv4.apk
ghn-flashless_001-r4_arm_cortex-a7_neon-vfpv4.apk
ghn-host_0~fdb2dee-r1_arm_cortex-a7_neon-vfpv4.apk
libssp_5.2.0-r1_arm_cortex-a7_neon-vfpv4.apk
posix-timezone-db_2021a-r2_arm_cortex-a7_neon-vfpv4.apk

(The filenames are formed this way, not sure it’s standard: --output ${dest_dir}/${name}_${version}_${arch}.apk)

I’ll keep an eye on this topic for anything related to dependencies :slight_smile:

1 Like

Hello,

I have tried using the new scripts but I have some problems.

when I'm in the root folder of my imagebuilder and use ./scripts/devolo-extract-ghn-packages devolo.bin ghn it will not work I get Invalid arguments! but when I use a direct path: ./scripts/devolo-extract-ghn-packages ~/openwrt/devolo.bin ghn it works, ghn will be extracted in the root directory as expected.

Then I came to a other issue it cannot find apk bin file and talks about:

OpenWrt in /home/developer/openwrt/ghn/devolo-extract-ghn-packages.728070/openwrt-root/_devolo.bin.extracted/squashfs-root uses apk!
This script requires apk to generate packages for this version of OpenWrt!
If you have an OpenWrt build tree, try including its "staging_dir/host/bin" in your PATH.
Possibly your distribution packages apk.

the image and toolchain is all build, the APK bin does exist in staging_dir but the script cannot locate it, I'm using Ubuntu on WSL.

APK is the mbtls version.

thank you :slight_smile: