Skip to content

Commit e23332c

Browse files
authored
androidenv: fix 'latest' where SDK level is not an int (NixOS#470569)
2 parents 9792f74 + dcac273 commit e23332c

File tree

3 files changed

+62
-15
lines changed

3 files changed

+62
-15
lines changed

pkgs/development/mobile/androidenv/compose-android-packages.nix

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ let
1414
# Coerces a string to an int.
1515
coerceInt = val: if lib.isInt val then val else lib.toIntBase10 val;
1616

17-
coerceIntVersion = v: coerceInt (lib.versions.major v);
17+
coerceIntVersion = v: coerceInt (lib.versions.major (toString v));
1818

1919
# Parses a single version, substituting "latest" with the latest version.
2020
parseVersion =
@@ -144,7 +144,7 @@ in
144144

145145
let
146146
# Resolve all the platform versions.
147-
platformVersions' = map coerceInt (parseVersions repo "platforms" platformVersions);
147+
platformVersions' = map coerceIntVersion (parseVersions repo "platforms" platformVersions);
148148

149149
# Determine the Android os identifier from Nix's system identifier
150150
os =
@@ -220,6 +220,28 @@ let
220220
extras = fetchArchives repo.extras;
221221
};
222222

223+
# Latest packages that are typically keyed by the API level.
224+
archivesByApiLevel =
225+
let
226+
# Transforms the given attrset mapping API levels (with possible suffixes and minor versions)
227+
# into the latest API level for each major version.
228+
mkLatestByApiLevel =
229+
packages:
230+
lib.filterAttrs (_: value: value != null) (
231+
lib.mapAttrs (
232+
_: value:
233+
(lib.findFirst (x: x.name == lib.versions.majorMinor x.name) { value = null; } (
234+
lib.lists.sort (x: y: lib.strings.versionOlder y.name x.name) value
235+
)).value
236+
) (lib.groupBy (x: lib.versions.major x.name) (lib.attrsToList packages))
237+
);
238+
in
239+
{
240+
platforms = mkLatestByApiLevel allArchives.packages.platforms;
241+
sources = mkLatestByApiLevel allArchives.packages.sources;
242+
system-images = mkLatestByApiLevel allArchives.system-images;
243+
};
244+
223245
# Lift the archives to the package level for easy search,
224246
# and add recurseIntoAttrs to all of them.
225247
allPackages =
@@ -284,17 +306,28 @@ let
284306
lib.hasAttrByPath [ package (toString version) ] packages;
285307

286308
# Displays a nice error message that includes the available options if a version doesn't exist.
309+
# Note that allPackages can be a list of package sets, or a single package set. Pass a list if
310+
# you want to prioritize elements to the left (e.g. for passing a platform major version).
287311
checkVersion =
288-
packages: package: version:
289-
if hasVersion packages package version then
290-
packages.${package}.${toString version}
291-
else
312+
allPackages: package: version:
313+
let
314+
# Convert the package sets to a list.
315+
allPackages' = if lib.isList allPackages then allPackages else lib.singleton allPackages;
316+
317+
# Pick the first package set where we have the version.
318+
packageSet = lib.findFirst (packages: hasVersion packages package version) null allPackages';
319+
in
320+
if packageSet == null then
292321
throw ''
293322
The version ${toString version} is missing in package ${package}.
294323
The only available versions are ${
295-
builtins.concatStringsSep ", " (builtins.attrNames packages.${package})
324+
lib.concatStringsSep ", " (
325+
lib.attrNames (lib.foldl (s: x: s // (x.${package} or { })) { } allPackages')
326+
)
296327
}.
297-
'';
328+
''
329+
else
330+
packageSet.${package}.${toString version};
298331

299332
# Returns true if we should link the specified plugins.
300333
shouldLink =
@@ -508,19 +541,23 @@ lib.recurseIntoAttrs rec {
508541
'';
509542
};
510543

544+
# This is a list of the chosen API levels, as integers.
511545
platformVersions = platformVersions';
512546

513547
platforms = map (
514548
version:
515549
deployAndroidPackage {
516-
package = checkVersion allArchives.packages "platforms" version;
550+
package = checkVersion [ archivesByApiLevel allArchives.packages ] "platforms" version;
517551
}
518552
) platformVersions';
519553

554+
# This exposes the version strings (e.g. "36.1" for API 36).
555+
platformVersionStrings = map (platform: platform.version) platforms;
556+
520557
sources = map (
521558
version:
522559
deployAndroidPackage {
523-
package = checkVersion allArchives.packages "sources" version;
560+
package = checkVersion [ archivesByApiLevel allArchives.packages ] "sources" version;
524561
}
525562
) platformVersions';
526563

@@ -539,14 +576,19 @@ lib.recurseIntoAttrs rec {
539576
# ```
540577
let
541578
availablePackages =
542-
map (abiVersion: allArchives.system-images.${toString apiVersion}.${type}.${abiVersion})
579+
map
580+
(
581+
abiVersion:
582+
archivesByApiLevel.system-images.${toString apiVersion}.${type}.${abiVersion}
583+
or allArchives.system-images.${toString apiVersion}.${type}.${abiVersion}
584+
)
543585
(
544586
builtins.filter (
545587
abiVersion: lib.hasAttrByPath [ (toString apiVersion) type abiVersion ] allArchives.system-images
546588
) abiVersions
547589
);
548590

549-
instructions = builtins.listToAttrs (
591+
instructions = lib.listToAttrs (
550592
map (package: {
551593
name = package.name;
552594
value = lib.optionalString (lib.hasPrefix "google_apis" type) ''

pkgs/development/mobile/androidenv/examples/shell-with-emulator.nix

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ let
7878
androidSdk = androidComposition.androidsdk;
7979
platformTools = androidComposition.platform-tools;
8080
latestSdk = pkgs.lib.foldl' pkgs.lib.max 0 androidComposition.platformVersions;
81+
latestSdkVersion = pkgs.lib.foldl' (
82+
s: x: if pkgs.lib.strings.compareVersions x s > 0 then x else s
83+
) "0" androidComposition.platformVersionStrings;
8184
jdk = pkgs.jdk;
8285
in
8386
pkgs.mkShell rec {
@@ -123,8 +126,8 @@ pkgs.mkShell rec {
123126
124127
packages=(
125128
"build-tools" "cmdline-tools" \
126-
"platform-tools" "platforms;android-${toString latestSdk}" \
127-
"system-images;android-${toString latestSdk};google_apis;x86_64"
129+
"platform-tools" "platforms;android-${toString latestSdkVersion}" \
130+
"system-images;android-${toString latestSdkVersion};google_apis;x86_64"
128131
)
129132
${pkgs.lib.optionalString emulatorSupported ''packages+=("emulator")''}
130133
@@ -184,7 +187,7 @@ pkgs.mkShell rec {
184187
mkdir -p $ANDROID_USER_HOME
185188
186189
avdmanager delete avd -n testAVD || true
187-
echo "" | avdmanager create avd --force --name testAVD --package 'system-images;android-${toString latestSdk};google_apis;x86_64'
190+
echo "" | avdmanager create avd --force --name testAVD --package 'system-images;android-${toString latestSdkVersion};google_apis;x86_64'
188191
result=$(avdmanager list avd)
189192
190193
if [[ ! $result =~ "Name: testAVD" ]]; then

pkgs/development/mobile/androidenv/examples/shell-without-emulator.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ let
4848
includeSystemImages = false;
4949
includeEmulator = false;
5050

51+
platformVersions = [ "latest" ];
52+
5153
# Accepting more licenses declaratively:
5254
extraLicenses = [
5355
# Already accepted for you with the global accept_license = true or

0 commit comments

Comments
 (0)