summaryrefslogtreecommitdiffstats
path: root/pkgs/development/compilers/flutter/update/update.py
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/development/compilers/flutter/update/update.py')
-rwxr-xr-xpkgs/development/compilers/flutter/update/update.py339
1 files changed, 339 insertions, 0 deletions
diff --git a/pkgs/development/compilers/flutter/update/update.py b/pkgs/development/compilers/flutter/update/update.py
new file mode 100755
index 000000000000..c622487cf9dc
--- /dev/null
+++ b/pkgs/development/compilers/flutter/update/update.py
@@ -0,0 +1,339 @@
+#! /usr/bin/env nix-shell
+#! nix-shell -i python3 -p python3Packages.pyyaml
+
+import shutil
+import json
+import urllib.request
+import tempfile
+from sys import exit
+import os
+import subprocess
+import re
+import json
+import argparse
+import yaml
+import json
+
+
+NIXPKGS_ROOT = subprocess.Popen(['git',
+ 'rev-parse',
+ '--show-toplevel'],
+ stdout=subprocess.PIPE,
+ text=True).communicate()[0].strip()
+
+
+def load_code(name, **kwargs):
+ with open(f"{NIXPKGS_ROOT}/pkgs/development/compilers/flutter/update/{name}", 'r') as f:
+ code = f.read()
+
+ for (key, value) in kwargs.items():
+ code = code.replace(f"@{key}@", value)
+
+ return code
+
+
+# Return out paths
+def nix_build(code):
+ temp = tempfile.NamedTemporaryFile(mode='w')
+ temp.write(code)
+ temp.flush()
+ os.fsync(temp.fileno())
+
+ process = subprocess.Popen(
+ [
+ "nix-build",
+ "--impure",
+ "--no-out-link",
+ "--expr",
+ f"with import {NIXPKGS_ROOT} {{}}; callPackage {temp.name} {{}}"],
+ stdout=subprocess.PIPE,
+ text=True)
+
+ process.wait()
+ temp.close()
+ return process.stdout.read().strip().splitlines()[0]
+
+
+# Return errors
+def nix_build_to_fail(code):
+ temp = tempfile.NamedTemporaryFile(mode='w')
+ temp.write(code)
+ temp.flush()
+ os.fsync(temp.fileno())
+
+ process = subprocess.Popen(
+ [
+ "nix-build",
+ "--impure",
+ "--keep-going",
+ "--no-link",
+ "--expr",
+ f"with import {NIXPKGS_ROOT} {{}}; callPackage {temp.name} {{}}"],
+ stderr=subprocess.PIPE,
+ text=True)
+
+ stderr = ""
+ while True:
+ line = process.stderr.readline()
+ if not line:
+ break
+ stderr += line
+ print(line.strip())
+
+ process.wait()
+ temp.close()
+ return stderr
+
+
+def get_artifact_hashes(flutter_compact_version):
+ code = load_code("get-artifact-hashes.nix",
+ nixpkgs_root=NIXPKGS_ROOT,
+ flutter_compact_version=flutter_compact_version)
+
+ stderr = nix_build_to_fail(code)
+
+ pattern = re.compile(
+ r"/nix/store/.*-flutter-artifacts-(.+?)-(.+?).drv':\n\s+specified: .*\n\s+got:\s+(.+?)\n")
+ matches = pattern.findall(stderr)
+ result_dict = {}
+
+ for match in matches:
+ flutter_platform, architecture, got = match
+ result_dict.setdefault(flutter_platform, {})[architecture] = got
+
+ def sort_dict_recursive(d):
+ return {
+ k: sort_dict_recursive(v) if isinstance(
+ v, dict) else v for k, v in sorted(
+ d.items())}
+ result_dict = sort_dict_recursive(result_dict)
+
+ return result_dict
+
+
+def get_dart_hashes(dart_version):
+ platforms = [
+ "x86_64-linux",
+ "aarch64-linux",
+ "x86_64-darwin",
+ "aarch64-darwin"]
+ result_dict = {}
+ for platform in platforms:
+ code = load_code(
+ "get-dart-hashes.nix",
+ dart_version=dart_version,
+ platform=platform)
+ stderr = nix_build_to_fail(code)
+
+ pattern = re.compile(r"got:\s+(.+?)\n")
+ result_dict[platform] = pattern.findall(stderr)[0]
+
+ return result_dict
+
+
+def get_flutter_hash_and_src(flutter_version):
+ code = load_code(
+ "get-flutter.nix",
+ flutter_version=flutter_version,
+ hash="")
+
+ stderr = nix_build_to_fail(code)
+ pattern = re.compile(r"got:\s+(.+?)\n")
+ hash = pattern.findall(stderr)[0]
+
+ code = load_code(
+ "get-flutter.nix",
+ flutter_version=flutter_version,
+ hash=hash)
+
+ return (hash, nix_build(code))
+
+
+def get_pubspec_lock(flutter_compact_version, flutter_src):
+ code = load_code(
+ "get-pubspec-lock.nix",
+ flutter_compact_version=flutter_compact_version,
+ flutter_src=flutter_src,
+ hash="")
+
+ stderr = nix_build_to_fail(code)
+ pattern = re.compile(r"got:\s+(.+?)\n")
+ hash = pattern.findall(stderr)[0]
+
+ code = load_code(
+ "get-pubspec-lock.nix",
+ flutter_compact_version=flutter_compact_version,
+ flutter_src=flutter_src,
+ hash=hash)
+
+ pubspec_lock_file = nix_build(code)
+
+ with open(pubspec_lock_file, 'r') as f:
+ pubspec_lock_yaml = f.read()
+
+ return yaml.safe_load(pubspec_lock_yaml)
+
+
+def write_data(
+ nixpkgs_flutter_version_directory,
+ flutter_version,
+ engine_hash,
+ dart_version,
+ dart_hash,
+ flutter_hash,
+ artifact_hashes,
+ pubspec_lock):
+ with open(f"{nixpkgs_flutter_version_directory}/data.json", "w") as f:
+ f.write(json.dumps({
+ "version": flutter_version,
+ "engineVersion": engine_hash,
+ "dartVersion": dart_version,
+ "dartHash": dart_hash,
+ "flutterHash": flutter_hash,
+ "artifactHashes": artifact_hashes,
+ "pubspecLock": pubspec_lock,
+ }, indent=2).strip() + "\n")
+
+
+def update_all_packages():
+ versions_directory = f"{NIXPKGS_ROOT}/pkgs/development/compilers/flutter/versions"
+ versions = [directory for directory in os.listdir(versions_directory)]
+ versions = sorted(versions, key=lambda x: (
+ int(x.split('_')[0]), int(x.split('_')[1])), reverse=True)
+
+ new_content = [
+ "flutterPackages = recurseIntoAttrs (callPackage ../development/compilers/flutter { });",
+ "flutter = flutterPackages.stable;",
+ ] + [f"flutter{version.replace('_', '')} = flutterPackages.v{version};" for version in versions]
+
+ with open(f"{NIXPKGS_ROOT}/pkgs/top-level/all-packages.nix", 'r') as file:
+ lines = file.read().splitlines(keepends=True)
+
+ start = -1
+ end = -1
+ for i, line in enumerate(lines):
+ if "flutterPackages = recurseIntoAttrs (callPackage ../development/compilers/flutter { });" in line:
+ start = i
+ if start != -1 and len(line.strip()) == 0:
+ end = i
+ break
+
+ if start != -1 and end != -1:
+ del lines[start:end]
+ lines[start:start] = [f" {l}\n" for l in new_content]
+
+ with open(f"{NIXPKGS_ROOT}/pkgs/top-level/all-packages.nix", 'w') as file:
+ file.write("".join(lines))
+
+
+# Finds Flutter version, Dart version, and Engine hash.
+# If the Flutter version is given, it uses that. Otherwise finds the
+# latest stable Flutter version.
+def find_versions(flutter_version=None):
+ engine_hash = None
+ dart_version = None
+
+ releases = json.load(urllib.request.urlopen(
+ "https://storage.googleapis.com/flutter_infra_release/releases/releases_linux.json"))
+
+ if not flutter_version:
+ stable_hash = releases['current_release']['stable']
+ release = next(
+ filter(
+ lambda release: release['hash'] == stable_hash,
+ releases['releases']))
+ flutter_version = release['version']
+
+ tags = subprocess.Popen(['git',
+ 'ls-remote',
+ '--tags',
+ 'https://github.com/flutter/engine.git'],
+ stdout=subprocess.PIPE,
+ text=True).communicate()[0].strip()
+
+ try:
+ engine_hash = next(
+ filter(
+ lambda line: line.endswith(f'refs/tags/{flutter_version}'),
+ tags.splitlines())).split('refs')[0].strip()
+ except StopIteration:
+ exit(
+ f"Couldn't find Engine hash for Flutter version: {flutter_version}")
+
+ try:
+ dart_version = next(
+ filter(
+ lambda release: release['version'] == flutter_version,
+ releases['releases']))['dart_sdk_version']
+ except StopIteration:
+ exit(
+ f"Couldn't find Dart version for Flutter version: {flutter_version}")
+
+ return (flutter_version, engine_hash, dart_version)
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Update Flutter in Nixpkgs')
+ parser.add_argument('--version', type=str, help='Specify Flutter version')
+ parser.add_argument('--artifact-hashes', action='store_true',
+ help='Whether to get artifact hashes')
+ args = parser.parse_args()
+
+ (flutter_version, engine_hash, dart_version) = find_versions(args.version)
+
+ flutter_compact_version = '_'.join(flutter_version.split('.')[:2])
+
+ if args.artifact_hashes:
+ print(
+ json.dumps(
+ get_artifact_hashes(flutter_compact_version),
+ indent=2).strip() +
+ "\n")
+ return
+
+ print(f"Flutter version: {flutter_version} ({flutter_compact_version})")
+ print(f"Engine hash: {engine_hash}")
+ print(f"Dart version: {dart_version}")
+
+ dart_hash = get_dart_hashes(dart_version)
+ (flutter_hash, flutter_src) = get_flutter_hash_and_src(flutter_version)
+
+ nixpkgs_flutter_version_directory = f"{NIXPKGS_ROOT}/pkgs/development/compilers/flutter/versions/{flutter_compact_version}"
+
+ if os.path.exists(f"{nixpkgs_flutter_version_directory}/data.json"):
+ os.remove(f"{nixpkgs_flutter_version_directory}/data.json")
+ os.makedirs(nixpkgs_flutter_version_directory, exist_ok=True)
+
+ update_all_packages()
+
+ common_data_args = {
+ "nixpkgs_flutter_version_directory": nixpkgs_flutter_version_directory,
+ "flutter_version": flutter_version,
+ "dart_version": dart_version,
+ "engine_hash": engine_hash,
+ "flutter_hash": flutter_hash,
+ "dart_hash": dart_hash,
+ }
+
+ write_data(
+ pubspec_lock={},
+ artifact_hashes={},
+ **common_data_args)
+
+ pubspec_lock = get_pubspec_lock(flutter_compact_version, flutter_src)
+
+ write_data(
+ pubspec_lock=pubspec_lock,
+ artifact_hashes={},
+ **common_data_args)
+
+ artifact_hashes = get_artifact_hashes(flutter_compact_version)
+
+ write_data(
+ pubspec_lock=pubspec_lock,
+ artifact_hashes=artifact_hashes,
+ **common_data_args)
+
+
+if __name__ == "__main__":
+ main()