Skip to content

Commit 67deafd

Browse files
authored
latestPreview* fields in model and updates in backend (#4425)
* latestPreview* fields in model and updates in backend * Prevent NPE * Fix NPE in test * Remove versions.sort()
1 parent 5b28958 commit 67deafd

File tree

9 files changed

+411
-104
lines changed

9 files changed

+411
-104
lines changed

app/bin/tools/backfill_package_fields.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:pool/pool.dart';
99
import 'package:pub_dev/package/models.dart';
1010
import 'package:pub_dev/service/entrypoint/tools.dart';
1111
import 'package:pub_dev/shared/datastore.dart';
12+
import 'package:pub_dev/tool/utils/dart_sdk_version.dart';
1213

1314
final _argParser = ArgParser()
1415
..addOption('concurrency',
@@ -26,6 +27,7 @@ Future main(List<String> args) async {
2627
print('Ensures Package.assignedTags is a list.');
2728
print('Ensures Package.latestPublished is a DateTime.');
2829
print('Ensures Package.latestPrereleasePublished is a DateTime.');
30+
print('Ensures Package.lastVersionPublished is a DateTime.');
2931
print(_argParser.usage);
3032
return;
3133
}
@@ -54,10 +56,12 @@ Future<void> _backfillPackageFields(Package p) async {
5456
p.isWithheld != null &&
5557
p.assignedTags != null &&
5658
p.latestPublished != null &&
57-
p.latestPrereleasePublished != null) {
59+
p.latestPrereleasePublished != null &&
60+
p.lastVersionPublished != null) {
5861
return;
5962
}
6063
print('Backfilling properties on package ${p.name}');
64+
final currentDartSdk = await getDartSdkVersion();
6165
final latestVersion =
6266
await dbService.lookupValue<PackageVersion>(p.latestVersionKey);
6367
final latestPrereleaseVersion =
@@ -73,8 +77,13 @@ Future<void> _backfillPackageFields(Package p) async {
7377
package.isUnlisted ??= false;
7478
package.isWithheld ??= false;
7579
package.assignedTags ??= [];
76-
package.latestPublished = latestVersion.created;
77-
package.latestPrereleasePublished = latestPrereleaseVersion.created;
80+
package.latestPublished ??= latestVersion.created;
81+
package.latestPrereleasePublished ??= latestPrereleaseVersion.created;
82+
// updates lastVersionPublished
83+
package.updateVersion(latestVersion,
84+
dartSdkVersion: currentDartSdk.semanticVersion);
85+
package.updateVersion(latestPrereleaseVersion,
86+
dartSdkVersion: currentDartSdk.semanticVersion);
7887
tx.insert(package);
7988
});
8089
print('Updated properties on package ${p.name}.');

app/lib/admin/backend.dart

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import '../shared/configuration.dart';
2525
import '../shared/datastore.dart';
2626
import '../shared/exceptions.dart';
2727
import '../shared/tags.dart';
28+
import '../tool/utils/dart_sdk_version.dart';
2829

2930
final _logger = Logger('pub.admin.backend');
3031
final _continuationCodec = utf8.fuse(hex);
@@ -381,6 +382,7 @@ class AdminBackend {
381382
_logger.info('${caller.userId} (${caller.email}) initiated the delete '
382383
'of package $packageName $version');
383384

385+
final currentDartSdk = await getDartSdkVersion();
384386
await withRetryTransaction(_db, (tx) async {
385387
final Key packageKey = _db.emptyKey.append(Package, id: packageName);
386388
final package = (await tx.lookup([packageKey])).first as Package;
@@ -405,16 +407,22 @@ class AdminBackend {
405407
bool updatePackage = false;
406408
if (package != null && package.latestVersion == version) {
407409
package.latestVersionKey = null;
410+
package.latestPublished = null;
408411
updatePackage = true;
409412
}
410413
if (package != null && package.latestPrereleaseVersion == version) {
411414
package.latestPrereleaseVersionKey = null;
415+
package.latestPrereleasePublished = null;
412416
updatePackage = true;
413417
}
418+
if (package != null && package.latestPreviewVersion == version) {
419+
package.latestPreviewVersionKey = null;
420+
package.latestPreviewPublished = null;
421+
}
414422
if (updatePackage) {
415-
versions
416-
.where((v) => v.version != version)
417-
.forEach(package.updateVersion);
423+
package.lastVersionPublished = null;
424+
versions.where((v) => v.version != version).forEach((v) => package
425+
.updateVersion(v, dartSdkVersion: currentDartSdk.semanticVersion));
418426
package.updated = DateTime.now().toUtc();
419427
tx.insert(package);
420428
}

app/lib/package/backend.dart

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import 'package:logging/logging.dart';
1515
import 'package:meta/meta.dart';
1616
import 'package:pana/pana.dart' show runProc;
1717
import 'package:path/path.dart' as p;
18-
import 'package:pub_dev/package/overrides.dart';
1918
import 'package:pub_package_reader/pub_package_reader.dart';
19+
import 'package:pub_semver/pub_semver.dart';
2020

2121
import '../account/backend.dart';
2222
import '../account/consent_backend.dart';
@@ -38,9 +38,11 @@ import '../shared/redis_cache.dart' show cache;
3838
import '../shared/storage.dart';
3939
import '../shared/urls.dart' as urls;
4040
import '../shared/utils.dart';
41+
import '../tool/utils/dart_sdk_version.dart';
4142
import 'model_properties.dart';
4243
import 'models.dart';
4344
import 'name_tracker.dart';
45+
import 'overrides.dart';
4446
import 'upload_signer_service.dart';
4547

4648
// The maximum stored length of `README.md` and other user-provided file content
@@ -249,6 +251,79 @@ class PackageBackend {
249251
return _storage.downloadUrl(package, version);
250252
}
251253

254+
/// Updates the stable, prerelease and preview versions of [package].
255+
///
256+
/// Returns true if the values did change.
257+
Future<bool> updatePackageVersions(
258+
String package, {
259+
Version dartSdkVersion,
260+
}) async {
261+
final pkgKey = db.emptyKey.append(Package, id: package);
262+
dartSdkVersion ??= (await getDartSdkVersion()).semanticVersion;
263+
264+
// ordered version list by publish date
265+
final versions =
266+
await db.query<PackageVersion>(ancestorKey: pkgKey).run().toList();
267+
268+
return await withRetryTransaction(db, (tx) async {
269+
final p = await tx.lookupOrNull<Package>(pkgKey);
270+
if (p == null) {
271+
throw NotFoundException.resource('package "$package"');
272+
}
273+
274+
final oldStableVersion = p.latestSemanticVersion;
275+
final oldPrereleaseVersion = p.latestPrereleaseSemanticVersion;
276+
final oldPreviewVersion = p.latestPreviewSemanticVersion;
277+
278+
// reset field values
279+
p.latestVersionKey = null;
280+
p.latestPrereleaseVersionKey = null;
281+
p.latestPreviewVersionKey = null;
282+
283+
// update fields
284+
for (final pv in versions) {
285+
p.updateVersion(pv, dartSdkVersion: dartSdkVersion);
286+
}
287+
288+
// shortcut if there was no change
289+
final unchanged = oldStableVersion == p.latestSemanticVersion &&
290+
oldPrereleaseVersion == p.latestPrereleaseSemanticVersion &&
291+
oldPreviewVersion == p.latestPreviewSemanticVersion;
292+
if (unchanged) {
293+
return false;
294+
}
295+
296+
// sanity check changes
297+
if (oldStableVersion.compareTo(p.latestSemanticVersion) > 0 ||
298+
oldPrereleaseVersion.compareTo(p.latestPrereleaseSemanticVersion) >
299+
0 ||
300+
oldPreviewVersion.compareTo(p.latestPreviewSemanticVersion) > 0) {
301+
_logger.severe(
302+
'Version update sanity check failed for package "$package": '
303+
'$oldStableVersion -> ${p.latestVersion} / '
304+
'$oldPrereleaseVersion -> ${p.latestPrereleaseVersion} / '
305+
'$oldPreviewVersion -> ${p.latestPreviewVersion}');
306+
return false;
307+
}
308+
309+
tx.insert(p);
310+
return true;
311+
});
312+
}
313+
314+
/// Updates the stable, prerelase and preview versions of all package.
315+
///
316+
/// Return the number of updated packages.
317+
Future<int> updateAllPackageVersions({Version dartSdkVersion}) async {
318+
var count = 0;
319+
await for (final p in db.query<Package>().run()) {
320+
final updated =
321+
await updatePackageVersions(p.name, dartSdkVersion: dartSdkVersion);
322+
if (updated) count++;
323+
}
324+
return count;
325+
}
326+
252327
/// Updates [options] on [package].
253328
Future<void> updateOptions(String package, api.PkgOptions options) async {
254329
final user = await requireAuthenticatedUser();
@@ -596,6 +671,8 @@ class PackageBackend {
596671
newVersion.package, _maxVersionsPerPackage);
597672
}
598673

674+
final currentDartSdk = await getDartSdkVersion();
675+
599676
Package package;
600677
String prevLatestStableVersion;
601678
String prevLatestPrereleaseVersion;
@@ -648,7 +725,8 @@ class PackageBackend {
648725
newVersion.publisherId = package.publisherId;
649726

650727
// Keep the latest version in the package object up-to-date.
651-
package.updateVersion(newVersion);
728+
package.updateVersion(newVersion,
729+
dartSdkVersion: currentDartSdk.semanticVersion);
652730
package.updated = DateTime.now().toUtc();
653731

654732
_logger.info(

app/lib/package/model_properties.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class Pubspec {
3939
pubspek.Pubspec.parse(yamlString, lenient: true),
4040
json.encode(_loadYaml(yamlString)));
4141

42+
factory Pubspec.fromJson(Map<String, dynamic> map) =>
43+
Pubspec._(pubspek.Pubspec.fromJson(map, lenient: true), json.encode(map));
44+
4245
Map<String, dynamic> get asJson {
4346
_load();
4447
return _json;

app/lib/package/models.dart

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ class Package extends db.ExpandoModel<String> {
6060
@db.IntProperty(required: true)
6161
int likes;
6262

63+
/// [DateTime] when the most recently uploaded [PackageVersion] was published.
64+
/// TODO: set required: true after backfill was done.
65+
@db.DateTimeProperty(required: false)
66+
DateTime lastVersionPublished;
67+
6368
/// Key referencing the [PackageVersion] for the latest version of this package, ordered by priority order of
6469
/// semantic versioning, hence, deprioritizing prereleases.
6570
@db.ModelKeyProperty(propertyName: 'latest_version', required: true)
@@ -81,6 +86,18 @@ class Package extends db.ExpandoModel<String> {
8186
@db.DateTimeProperty()
8287
DateTime latestPrereleasePublished;
8388

89+
/// Reference to latest version of this package ordered by semantic versioning,
90+
/// filtered for versions that depend on an SDK that will be published in the
91+
/// future.
92+
///
93+
/// Note: the version may be stable or prerelease.
94+
@db.ModelKeyProperty()
95+
db.Key latestPreviewVersionKey;
96+
97+
/// DateTime at which point the `PackageVersion` referenced in [latestPreviewVersionKey] was published.
98+
@db.DateTimeProperty()
99+
DateTime latestPreviewPublished;
100+
84101
/// The publisher id (null, if the package does not have a publisher).
85102
@db.StringProperty()
86103
String publisherId;
@@ -144,14 +161,27 @@ class Package extends db.ExpandoModel<String> {
144161
String get latestPrereleaseVersion =>
145162
latestPrereleaseVersionKey?.id as String;
146163

164+
String get latestPreviewVersion => latestPreviewVersionKey?.id as String;
165+
147166
Version get latestPrereleaseSemanticVersion =>
148167
latestPrereleaseVersionKey == null
149168
? null
150169
: Version.parse(latestPrereleaseVersion);
151170

171+
Version get latestPreviewSemanticVersion => latestPreviewVersionKey == null
172+
? null
173+
: Version.parse(latestPreviewVersion);
174+
152175
bool get showPrereleaseVersion {
153176
if (latestPrereleaseVersion == null) return false;
154-
return latestSemanticVersion < latestPrereleaseSemanticVersion;
177+
return latestSemanticVersion < latestPrereleaseSemanticVersion &&
178+
(latestPreviewSemanticVersion == null ||
179+
latestPreviewSemanticVersion < latestPrereleaseSemanticVersion);
180+
}
181+
182+
bool get showPreviewVersion {
183+
if (latestPreviewVersion == null) return false;
184+
return latestSemanticVersion < latestPreviewSemanticVersion;
155185
}
156186

157187
String get shortLatestPrereleasePublished {
@@ -185,22 +215,38 @@ class Package extends db.ExpandoModel<String> {
185215
uploaders.remove(userId);
186216
}
187217

188-
/// Updates latest stable and dev version keys with the new version.
189-
void updateVersion(PackageVersion pv) {
190-
final Version newVersion = pv.semanticVersion;
218+
/// Updates latest stable, prerelease and preview versions and published
219+
/// timestamp with the new version.
220+
void updateVersion(
221+
PackageVersion pv, {
222+
@required Version dartSdkVersion,
223+
}) {
224+
final newVersion = pv.semanticVersion;
191225

192226
if (latestVersionKey == null ||
193-
isNewer(latestSemanticVersion, newVersion, pubSorted: true)) {
227+
(isNewer(latestSemanticVersion, newVersion, pubSorted: true) &&
228+
!pv.pubspec.isPreviewForCurrentSdk(dartSdkVersion))) {
194229
latestVersionKey = pv.key;
195230
latestPublished = pv.created;
196231
}
197232

233+
if (latestPreviewVersionKey == null ||
234+
isNewer(latestPreviewSemanticVersion, newVersion, pubSorted: true)) {
235+
latestPreviewVersionKey = pv.key;
236+
latestPreviewPublished = pv.created;
237+
}
238+
198239
if (latestPrereleaseVersionKey == null ||
199240
isNewer(latestPrereleaseSemanticVersion, newVersion,
200241
pubSorted: false)) {
201242
latestPrereleaseVersionKey = pv.key;
202243
latestPrereleasePublished = pv.created;
203244
}
245+
246+
if (lastVersionPublished == null ||
247+
lastVersionPublished.isBefore(pv.created)) {
248+
lastVersionPublished = pv.created;
249+
}
204250
}
205251

206252
bool isNewPackage() => created.difference(DateTime.now()).abs().inDays <= 30;

app/lib/tool/test_profile/import_source.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class _AutoGeneratedImportSource implements ImportSource {
111111

112112
@override
113113
Future<List<int>> getArchiveBytes(String package, String version) async {
114-
final archive = _ArchiveBuilder();
114+
final archive = ArchiveBuilder();
115115

116116
final isFlutter = package.startsWith('flutter_');
117117
final pubspec = json.encode({
@@ -138,7 +138,8 @@ class _AutoGeneratedImportSource implements ImportSource {
138138
Future<void> close() async {}
139139
}
140140

141-
class _ArchiveBuilder {
141+
@visibleForTesting
142+
class ArchiveBuilder {
142143
final archive = Archive();
143144

144145
void addFile(String path, String content) {

0 commit comments

Comments
 (0)