| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library pub_dartlang_org.handlers; | 5 library pub_dartlang_org.handlers; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:math'; | 8 import 'dart:math'; |
| 9 import 'dart:convert'; | 9 import 'dart:convert'; |
| 10 | 10 |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 if (responseAsJson) { | 221 if (responseAsJson) { |
| 222 return packageShowHandlerJson(request, Uri.decodeComponent(path)); | 222 return packageShowHandlerJson(request, Uri.decodeComponent(path)); |
| 223 } else { | 223 } else { |
| 224 return packageShowHandlerHtml(request, Uri.decodeComponent(path)); | 224 return packageShowHandlerHtml(request, Uri.decodeComponent(path)); |
| 225 } | 225 } |
| 226 } | 226 } |
| 227 | 227 |
| 228 var package = Uri.decodeComponent(path.substring(0, slash)); | 228 var package = Uri.decodeComponent(path.substring(0, slash)); |
| 229 if (path.substring(slash).startsWith('/versions')) { | 229 if (path.substring(slash).startsWith('/versions')) { |
| 230 path = path.substring(slash + '/versions'.length); | 230 path = path.substring(slash + '/versions'.length); |
| 231 if (path.startsWith('/') && path.endsWith('.yaml')) { | 231 if (path.startsWith('/')) { |
| 232 path = path.substring(1, path.length - '.yaml'.length); | 232 if (path.endsWith('.yaml')) { |
| 233 String version = Uri.decodeComponent(path); | 233 path = path.substring(1, path.length - '.yaml'.length); |
| 234 return packageVersionHandlerYaml(request, package, version); | 234 String version = Uri.decodeComponent(path); |
| 235 return packageVersionHandlerYaml(request, package, version); |
| 236 } else { |
| 237 path = path.substring(1); |
| 238 String version = Uri.decodeComponent(path); |
| 239 return packageVersionHandlerHtml(request, package, version); |
| 240 } |
| 235 } else { | 241 } else { |
| 236 return packageVersionsHandler(request, package); | 242 return packageVersionsHandler(request, package); |
| 237 } | 243 } |
| 238 } | 244 } |
| 239 return _notFoundHandler(request); | 245 return _notFoundHandler(request); |
| 240 } | 246 } |
| 241 | 247 |
| 242 /// Handles requests for /packages/<package> - JSON | 248 /// Handles requests for /packages/<package> - JSON |
| 243 packageShowHandlerJson(shelf.Request request, String packageName) async { | 249 packageShowHandlerJson(shelf.Request request, String packageName) async { |
| 244 Package package = await backend.lookupPackage(packageName); | 250 Package package = await backend.lookupPackage(packageName); |
| 245 if (package == null) return _notFoundHandler(request); | 251 if (package == null) return _notFoundHandler(request); |
| 246 | 252 |
| 247 var versions = await backend.versionsOfPackage(packageName); | 253 var versions = await backend.versionsOfPackage(packageName); |
| 248 _sortVersionsDesc(versions, decreasing: false); | 254 _sortVersionsDesc(versions, decreasing: false); |
| 249 | 255 |
| 250 var json = { | 256 var json = { |
| 251 'name' : package.name, | 257 'name' : package.name, |
| 252 'uploaders': package.uploaderEmails, | 258 'uploaders': package.uploaderEmails, |
| 253 'versions': | 259 'versions': |
| 254 versions.map((packageVersion) => packageVersion.version).toList(), | 260 versions.map((packageVersion) => packageVersion.version).toList(), |
| 255 }; | 261 }; |
| 256 return _jsonResponse(json); | 262 return _jsonResponse(json); |
| 257 } | 263 } |
| 258 | 264 |
| 259 /// Handles requests for /packages/<package> - HTML | 265 /// Handles requests for /packages/<package> - HTML |
| 260 packageShowHandlerHtml(shelf.Request request, String packageName) async { | 266 packageShowHandlerHtml(shelf.Request request, String packageName) async { |
| 267 return packageVersionHandlerHtml(request, packageName, null); |
| 268 } |
| 269 |
| 270 /// Handles requests for /packages/<package>/versions |
| 271 packageVersionsHandler(shelf.Request request, String packageName) async { |
| 272 var versions = await backend.versionsOfPackage(packageName); |
| 273 if (versions.isEmpty) return _notFoundHandler(request); |
| 274 |
| 275 _sortVersionsDesc(versions); |
| 276 |
| 277 var versionDownloadUrls = await Future.wait( |
| 278 versions.map((PackageVersion version) { |
| 279 return backend.downloadUrl(packageName, version.version); |
| 280 }).toList()); |
| 281 |
| 282 return _htmlResponse(templateService.renderPkgVersionsPage( |
| 283 packageName, versions, versionDownloadUrls)); |
| 284 } |
| 285 |
| 286 /// Handles requests for /packages/<package>/versions/<version> |
| 287 packageVersionHandlerHtml(request, |
| 288 String packageName, |
| 289 String versionName) async { |
| 261 String cachedPage; | 290 String cachedPage; |
| 262 if (backend.uiPackageCache != null) { | 291 if (backend.uiPackageCache != null) { |
| 263 cachedPage = await backend.uiPackageCache.getUIPackagePage(packageName); | 292 cachedPage = await backend.uiPackageCache.getUIPackagePage( |
| 293 packageName, versionName); |
| 264 } | 294 } |
| 265 | 295 |
| 266 if (cachedPage == null) { | 296 if (cachedPage == null) { |
| 267 Package package = await backend.lookupPackage(packageName); | 297 Package package = await backend.lookupPackage(packageName); |
| 268 if (package == null) return _notFoundHandler(request); | 298 if (package == null) return _notFoundHandler(request); |
| 269 | 299 |
| 270 var versions = await backend.versionsOfPackage(packageName); | 300 var versions = await backend.versionsOfPackage(packageName); |
| 271 _sortVersionsDesc(versions); | |
| 272 | 301 |
| 273 var latestVersion = versions.where( | 302 _sortVersionsDesc(versions, decreasing: true, pubSorting: true); |
| 274 (version) => version.key == package.latestVersionKey).first; | 303 var latestStable = versions[0]; |
| 304 var first10Versions = versions.take(10).toList(); |
| 275 | 305 |
| 276 var first10Versions = versions.take(10).toList(); | 306 _sortVersionsDesc(versions, decreasing: true, pubSorting: false); |
| 307 var latestDev = versions[0]; |
| 308 |
| 309 var selectedVersion; |
| 310 if (versionName != null) { |
| 311 for (var v in versions) { |
| 312 if (v.version == versionName) selectedVersion = v; |
| 313 } |
| 314 // TODO: cache error? |
| 315 if (selectedVersion == null) { |
| 316 return _notFoundHandler(request); |
| 317 } |
| 318 } else { |
| 319 if (selectedVersion == null) { |
| 320 selectedVersion = latestStable; |
| 321 } |
| 322 } |
| 277 | 323 |
| 278 var versionDownloadUrls = await Future.wait( | 324 var versionDownloadUrls = await Future.wait( |
| 279 first10Versions.map((PackageVersion version) { | 325 first10Versions.map((PackageVersion version) { |
| 280 return backend.downloadUrl(packageName, version.version); | 326 return backend.downloadUrl(packageName, version.version); |
| 281 }).toList()); | 327 }).toList()); |
| 282 | 328 |
| 283 cachedPage = templateService.renderPkgShowPage( | 329 cachedPage = templateService.renderPkgShowPage( |
| 284 package, first10Versions, versionDownloadUrls, latestVersion, | 330 package, first10Versions, versionDownloadUrls, selectedVersion, |
| 285 versions.length); | 331 latestStable, latestDev, versions.length); |
| 286 if (backend.uiPackageCache != null) { | 332 if (backend.uiPackageCache != null) { |
| 287 await backend.uiPackageCache.setUIPackagePage(packageName, cachedPage); | 333 await backend.uiPackageCache.setUIPackagePage( |
| 334 packageName, versionName, cachedPage); |
| 288 } | 335 } |
| 289 } | 336 } |
| 290 | 337 |
| 291 return _htmlResponse(cachedPage); | 338 return _htmlResponse(cachedPage); |
| 292 } | 339 } |
| 293 | 340 |
| 294 /// Handles requests for /packages/<package>/versions | |
| 295 packageVersionsHandler(shelf.Request request, String packageName) async { | |
| 296 var versions = await backend.versionsOfPackage(packageName); | |
| 297 if (versions.isEmpty) return _notFoundHandler(request); | |
| 298 | |
| 299 _sortVersionsDesc(versions); | |
| 300 | |
| 301 var versionDownloadUrls = await Future.wait( | |
| 302 versions.map((PackageVersion version) { | |
| 303 return backend.downloadUrl(packageName, version.version); | |
| 304 }).toList()); | |
| 305 | |
| 306 return _htmlResponse(templateService.renderPkgVersionsPage( | |
| 307 packageName, versions, versionDownloadUrls)); | |
| 308 } | |
| 309 | |
| 310 /// Handles requests for /packages/<package>/versions/<version>.yaml | 341 /// Handles requests for /packages/<package>/versions/<version>.yaml |
| 311 packageVersionHandlerYaml(request, String package, String version) async { | 342 packageVersionHandlerYaml(request, String package, String version) async { |
| 312 var packageVersion = await backend.lookupPackageVersion(package, version); | 343 var packageVersion = await backend.lookupPackageVersion(package, version); |
| 313 if (packageVersion == null) { | 344 if (packageVersion == null) { |
| 314 return _notFoundHandler(request); | 345 return _notFoundHandler(request); |
| 315 } else { | 346 } else { |
| 316 return _yamlResponse(packageVersion.pubspec.jsonString); | 347 return _yamlResponse(packageVersion.pubspec.jsonString); |
| 317 } | 348 } |
| 318 } | 349 } |
| 319 | 350 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 body: content, | 463 body: content, |
| 433 headers: {'content-type' : 'application/atom+xml; charset="utf-8"'}); | 464 headers: {'content-type' : 'application/atom+xml; charset="utf-8"'}); |
| 434 } | 465 } |
| 435 | 466 |
| 436 shelf.Response _redirectResponse(url) { | 467 shelf.Response _redirectResponse(url) { |
| 437 return new shelf.Response.seeOther(url); | 468 return new shelf.Response.seeOther(url); |
| 438 } | 469 } |
| 439 | 470 |
| 440 | 471 |
| 441 /// Sorts [versions] according to the semantic versioning specification. | 472 /// Sorts [versions] according to the semantic versioning specification. |
| 442 void _sortVersionsDesc(List<PackageVersion> versions, {bool decreasing: true}) { | 473 /// |
| 474 /// If [pubSorting] is `true` then pub's priorization ordering is used, which |
| 475 /// will rang pre-release versions lower than stable versions (e.g. it will |
| 476 /// order "0.9.0-dev.1 < 0.8.0"). Otherwise it will use semantic version |
| 477 /// sorting (e.g. it will order "0.8.0 < 0.9.0-dev.1"). |
| 478 void _sortVersionsDesc(List<PackageVersion> versions, |
| 479 {bool decreasing: true, bool pubSorting: true}) { |
| 443 versions.sort((PackageVersion a, PackageVersion b) { | 480 versions.sort((PackageVersion a, PackageVersion b) { |
| 444 if (decreasing) { | 481 if (pubSorting) { |
| 445 return semver.Version.prioritize(b.semanticVersion, a.semanticVersion); | 482 if (decreasing) { |
| 483 return semver.Version.prioritize(b.semanticVersion, a.semanticVersion); |
| 484 } else { |
| 485 return semver.Version.prioritize(a.semanticVersion, b.semanticVersion); |
| 486 } |
| 446 } else { | 487 } else { |
| 447 return semver.Version.prioritize(a.semanticVersion, b.semanticVersion); | 488 if (decreasing) { |
| 489 return b.semanticVersion.compareTo(a.semanticVersion); |
| 490 } else { |
| 491 return a.semanticVersion.compareTo(b.semanticVersion); |
| 492 } |
| 448 } | 493 } |
| 449 }); | 494 }); |
| 450 } | 495 } |
| 451 | 496 |
| 452 | 497 |
| 453 /// Extracts the 'page' query parameter from [url]. | 498 /// Extracts the 'page' query parameter from [url]. |
| 454 /// | 499 /// |
| 455 /// Returns a valid positive integer. If [maxPages] is given, the result is | 500 /// Returns a valid positive integer. If [maxPages] is given, the result is |
| 456 /// clamped to [maxPages]. | 501 /// clamped to [maxPages]. |
| 457 int _pageFromUrl(Uri url, {int maxPages}) { | 502 int _pageFromUrl(Uri url, {int maxPages}) { |
| 458 var pageAsString = url.queryParameters['page']; | 503 var pageAsString = url.queryParameters['page']; |
| 459 int pageAsInt = 1; | 504 int pageAsInt = 1; |
| 460 if (pageAsString != null) { | 505 if (pageAsString != null) { |
| 461 try { | 506 try { |
| 462 pageAsInt = max(int.parse(pageAsString), 1); | 507 pageAsInt = max(int.parse(pageAsString), 1); |
| 463 } catch (_, __) { } | 508 } catch (_, __) { } |
| 464 } | 509 } |
| 465 | 510 |
| 466 if (maxPages != null && pageAsInt > maxPages) pageAsInt = maxPages; | 511 if (maxPages != null && pageAsInt > maxPages) pageAsInt = maxPages; |
| 467 return pageAsInt; | 512 return pageAsInt; |
| 468 } | 513 } |
| OLD | NEW |