| // Copyright 2024, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:convert'; |
| import 'dart:io' as io; |
| |
| import 'package:crypto/crypto.dart'; |
| import 'package:file/file.dart'; |
| |
| import 'command.dart'; |
| import 'package.dart'; |
| import 'provenance.dart'; |
| |
| /// A [Package] whose artifacts are uploaded to "go/cipd". |
| /// |
| /// The [upload] method uploads the files in the artifacts directory to a CIPD |
| /// package. The [name] becomes the packages CIPD path. |
| /// In [dryRun] mode, the [upload] method merely prints the 1st level contents |
| /// instead of uploading them. |
| abstract class CipdPackage extends Package { |
| final String version; |
| |
| CipdPackage(String name, Uri source, this.version) : super(name, source); |
| |
| /// Upload the files in the [artifacts] directory to go/cipd. |
| @override |
| Future<void> upload(Directory artifacts, bool provenance) async { |
| if (await isAlreadyUploaded()) { |
| throw StateError('Attempted to re-upload existing CIPD version'); |
| } |
| final zip = artifacts.parent.childFile('${artifacts.basename}.zip'); |
| final jsonOutput = artifacts.parent.childFile('${artifacts.basename}.json'); |
| final buildArguments = [ |
| 'pkg-build', |
| '-name', |
| name, |
| '-in', |
| artifacts.path, |
| '-install-mode', |
| 'copy', |
| '-out', |
| zip.path, |
| '-json-output', |
| jsonOutput.path, |
| ]; |
| log.info('Running cipd ${buildArguments.join(' ')}...'); |
| final buildResult = await Command('cipd', buildArguments).run(raise: true); |
| final instanceId = |
| jsonDecode(await jsonOutput.readAsString())['result']['instance_id']; |
| final digest = sha256.convert(await zip.readAsBytes()).toString(); |
| final registerArguments = [ |
| 'pkg-register', |
| zip.path, |
| '-ref', |
| 'latest', |
| '-tag', |
| 'version:$version', |
| ]; |
| log.info('Produced $name instance $instanceId with digest $digest'); |
| log.info('Running cipd ${registerArguments.join(' ')}...'); |
| if (isDryRun) { |
| final files = await artifacts.list(recursive: true).toList(); |
| log.info("Files that would've been included:\n $files"); |
| } else { |
| final result = await Command('cipd', registerArguments).run(raise: true); |
| if (provenance) { |
| provenanceReportCipd(name, digest, instanceId); |
| } |
| } |
| log.info('Finished running cipd create for $name.'); |
| } |
| |
| Future<bool> isAlreadyUploaded() async { |
| final arguments = [ |
| 'resolve', |
| '-version', |
| 'version:$version', |
| name, |
| ]; |
| log.info('Running cipd ${arguments.join(' ')}...'); |
| final result = await Command('cipd', arguments).run(); |
| return result.exitCode == 0; |
| } |
| } |