upload method

  1. @Route.post('/api/packages/versions/newUpload')
Future<Response> upload(
  1. Request req
)

Implementation

@Route.post('/api/packages/versions/newUpload')
Future<shelf.Response> upload(shelf.Request req) async {
  try {
    var uploader = await _getUploaderEmail(req);

    var contentType = req.headers['content-type'];
    if (contentType == null) throw 'invalid content type';

    var mediaType = MediaType.parse(contentType);
    var boundary = mediaType.parameters['boundary'];
    if (boundary == null) throw 'invalid boundary';

    var transformer = MimeMultipartTransformer(boundary);
    MimeMultipart? fileData;

    // The map below makes the runtime type checker happy.
    // https://github.com/dart-lang/pub-dev/blob/19033f8154ca1f597ef5495acbc84a2bb368f16d/app/lib/fake/server/fake_storage_server.dart#L74
    final stream = req.read().map((a) => a).transform(transformer);
    await for (var part in stream) {
      if (fileData != null) continue;
      fileData = part;
    }

    var bb = await fileData!.fold(
        BytesBuilder(), (BytesBuilder byteBuilder, d) => byteBuilder..add(d));
    var tarballBytes = bb.takeBytes();
    var tarBytes = GZipDecoder().decodeBytes(tarballBytes);
    var archive = TarDecoder().decodeBytes(tarBytes);
    ArchiveFile? pubspecArchiveFile;
    ArchiveFile? readmeFile;
    ArchiveFile? changelogFile;

    for (var file in archive.files) {
      if (file.name == 'pubspec.yaml') {
        pubspecArchiveFile = file;
        continue;
      }
      if (file.name.toLowerCase() == 'readme.md') {
        readmeFile = file;
        continue;
      }
      if (file.name.toLowerCase() == 'changelog.md') {
        changelogFile = file;
        continue;
      }
    }

    if (pubspecArchiveFile == null) {
      throw 'Did not find any pubspec.yaml file in upload. Aborting.';
    }

    var pubspecYaml = utf8.decode(pubspecArchiveFile.content);
    var pubspec = loadYamlAsMap(pubspecYaml)!;

    if (uploadValidator != null) {
      await uploadValidator!(pubspec, uploader);
    }

    // TODO: null
    var name = pubspec['name'] as String;
    var version = pubspec['version'] as String;

    var package = await metaStore.queryPackage(name);

    // Package already exists
    if (package != null) {
      if (package.private == false) {
        throw '$name is not a private package. Please upload it to https://pub.dev';
      }

      // Check uploaders
      if (package.uploaders?.contains(uploader) == false) {
        throw '$uploader is not an uploader of $name';
      }

      // Check duplicated version
      var duplicated = package.versions
          .firstWhereOrNull((item) => version == item.version);
      if (duplicated != null) {
        throw 'version invalid: $name@$version already exists.';
      }
    }

    // Upload package tarball to storage
    await packageStore.upload(name, version, tarballBytes);

    String? readme;
    String? changelog;
    if (readmeFile != null) {
      readme = utf8.decode(readmeFile.content);
    }
    if (changelogFile != null) {
      changelog = utf8.decode(changelogFile.content);
    }

    // Write package meta to database
    var unpubVersion = UnpubVersion(
      version,
      pubspec,
      pubspecYaml,
      uploader,
      readme,
      changelog,
      DateTime.now(),
    );
    await metaStore.addVersion(name, unpubVersion);

    // TODO: Upload docs
    return shelf.Response.found(
        _resolveUrl(req, '/api/packages/versions/newUploadFinish'));
  } catch (err) {
    return shelf.Response.found(_resolveUrl(
        req, '/api/packages/versions/newUploadFinish?error=$err'));
  }
}