summaryrefslogtreecommitdiff
path: root/pkgs/development/mobile/androidenv/deploy-androidpackages.nix
blob: 21d30bc45e8452469c8cf7793a239590a179adf7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
{
  stdenv,
  lib,
  unzip,
  mkLicenses,
  os,
  arch,
  meta,
}:
{
  packages,
  nativeBuildInputs ? [ ],
  buildInputs ? [ ],
  patchesInstructions ? { },
  ...
}@args:

let
  extraParams = removeAttrs args [
    "packages"
    "os"
    "buildInputs"
    "nativeBuildInputs"
    "patchesInstructions"
  ];
  sortedPackages = builtins.sort (x: y: builtins.lessThan x.name y.name) packages;

  mkXmlAttrs =
    attrs: lib.concatStrings (lib.mapAttrsToList (name: value: " ${name}=\"${value}\"") attrs);
  mkXmlValues =
    attrs:
    lib.concatStrings (
      lib.mapAttrsToList (
        name: value:
        let
          tag = builtins.head (builtins.match "([^:]+).*" name);
        in
        if builtins.typeOf value == "string" then "<${tag}>${value}</${tag}>" else mkXmlDoc name value
      ) attrs
    );
  mkXmlDoc =
    name: doc:
    let
      tag = builtins.head (builtins.match "([^:]+).*" name);
      hasXmlAttrs = builtins.hasAttr "element-attributes" doc;
      xmlValues = removeAttrs doc [ "element-attributes" ];
      hasXmlValues = builtins.length (builtins.attrNames xmlValues) > 0;
    in
    if hasXmlAttrs && hasXmlValues then
      "<${tag}${mkXmlAttrs doc.element-attributes}>${mkXmlValues xmlValues}</${tag}>"
    else if hasXmlAttrs && !hasXmlValues then
      "<${tag}${mkXmlAttrs doc.element-attributes}/>"
    else if !hasXmlAttrs && hasXmlValues then
      "<${tag}>${mkXmlValues xmlValues}</${tag}>"
    else
      "<${tag}/>";
  mkXmlPackage = package: ''
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <ns2:repository
      xmlns:ns2="http://schemas.android.com/repository/android/common/02"
      xmlns:ns3="http://schemas.android.com/repository/android/common/01"
      xmlns:ns4="http://schemas.android.com/repository/android/generic/01"
      xmlns:ns5="http://schemas.android.com/repository/android/generic/02"
      xmlns:ns6="http://schemas.android.com/sdk/android/repo/addon2/01"
      xmlns:ns7="http://schemas.android.com/sdk/android/repo/addon2/02"
      xmlns:ns8="http://schemas.android.com/sdk/android/repo/addon2/03"
      xmlns:ns9="http://schemas.android.com/sdk/android/repo/repository2/01"
      xmlns:ns10="http://schemas.android.com/sdk/android/repo/repository2/02"
      xmlns:ns11="http://schemas.android.com/sdk/android/repo/repository2/03"
      xmlns:ns12="http://schemas.android.com/sdk/android/repo/sys-img2/03"
      xmlns:ns13="http://schemas.android.com/sdk/android/repo/sys-img2/02"
      xmlns:ns14="http://schemas.android.com/sdk/android/repo/sys-img2/01"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <license id="${package.license}" type="text">${lib.concatStringsSep "---" (mkLicenses package.license)}</license>
      <localPackage path="${builtins.replaceStrings [ "/" ] [ ";" ] package.path}" obsolete="${
        if (lib.hasAttrByPath [ "obsolete" ] package) then package.obsolete else "false"
      }">
        ${mkXmlDoc "type-details" package.type-details}
        ${mkXmlDoc "revision" package.revision-details}
        ${lib.optionalString (lib.hasAttrByPath [ "dependencies" ] package) (
          mkXmlDoc "dependencies" package.dependencies
        )}
        <display-name>${package.displayName}</display-name>
        <uses-license ref="${package.license}"/>
      </localPackage>
    </ns2:repository>
  '';
in
stdenv.mkDerivation (
  {
    inherit buildInputs;
    pname = "android-sdk-${lib.concatMapStringsSep "-" (package: package.name) sortedPackages}";
    version = lib.concatMapStringsSep "-" (package: package.revision) sortedPackages;
    src = lib.flatten (map (package: package.archives) packages);
    inherit os arch;
    nativeBuildInputs = [ unzip ] ++ nativeBuildInputs;
    preferLocalBuild = true;

    unpackPhase = ''
      runHook preUnpack
      if [ -z "$src" ]; then
        echo "$pname did not have any sources available for os=$os, arch=$arch." >&2
        echo "Are packages available for this architecture?" >&2
        exit 1
      fi
      buildDir=$PWD
      i=0
      for srcArchive in $src; do
        extractedZip="extractedzip-$i"
        i=$((i+1))
        cd "$buildDir"
        mkdir "$extractedZip"
        cd "$extractedZip"
        unpackFile "$srcArchive"
      done
      runHook postUnpack
    '';

    installPhase = ''
      runHook preInstall
    ''
    + lib.concatStrings (
      lib.imap0 (i: package: ''
        cd $buildDir/extractedzip-${toString i}

        # Most Android Zip packages have a root folder, but some don't. We unpack
        # the zip file in a folder and we try to discover whether it has a single root
        # folder. If this is the case, we adjust the current working folder.
        if [ "$(find . -mindepth 1 -maxdepth 1 -type d | wc -l)" -eq 1 ]; then
            cd "$(find . -mindepth 1 -maxdepth 1 -type d)"
        fi
        extractedZip="$PWD"

        packageBaseDir=$out/libexec/android-sdk/${package.path}
        mkdir -p $packageBaseDir
        cd $packageBaseDir
        cp -a $extractedZip/* .
        ${patchesInstructions.${package.name}}

        if [ ! -f $packageBaseDir/package.xml ]; then
          cat << EOF > $packageBaseDir/package.xml
        ${mkXmlPackage package}
        EOF
        fi
      '') packages
    )
    + ''
      runHook postInstall
    '';

    # Some executables that have been patched with patchelf may not work any longer after they have been stripped.
    dontStrip = true;
    dontPatchELF = true;
    dontAutoPatchelf = true;

    inherit meta;
  }
  // extraParams
)