blob: 6528a7bebe6fd0b6f1c212a2a1f4bc879160af3e [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:fxtest/fxtest.dart';
import 'package:meta/meta.dart';
/// Deconstructed Fuchsia Package Url used to precisely target URL components.
class PackageUrl {
/// Root chunk of the Package URL.
///
/// ```
/// fuchsia.com
/// ```
///
/// from
///
/// ```
/// fuchsia-pkg://fuchsia.com/pkg-name/variant?hash=1234#meta/component-name.cmx
/// ```
final String host;
/// First chunk from the URI.
///
/// ```
/// pkg-name
/// ```
///
/// from
///
/// ```
/// fuchsia-pkg://fuchsia.com/pkg-name/variant?hash=1234#meta/component-name.cmx
/// ```
final String packageName;
/// Optional. Second chunk in the URI.
///
/// ```
/// variant
/// ```
///
/// from
///
/// ```
/// fuchsia-pkg://fuchsia.com/pkg-name/variant?hash=1234#meta/component-name.cmx
/// ```
final String packageVariant;
/// Optional. Value for "hash" querystring value.
///
/// ```
/// 1234
/// ```
///
/// from
///
/// ```
/// fuchsia-pkg://fuchsia.com/pkg-name/variant?hash=1234#meta/component-name.cmx
/// ```
final String hash;
/// Component name with the extension.
///
/// ```
/// component-name.cmx
/// ```
///
/// from
///
/// ```
/// fuchsia-pkg://fuchsia.com/pkg-name/variant?hash=1234#meta/component-name.cmx
/// ```
final String fullComponentName;
/// Component name without the extension.
///
/// ```
/// component-name
/// ```
///
/// from
///
/// ```
/// fuchsia-pkg://fuchsia.com/pkg-name/variant?hash=1234#meta/component-name.cmx
/// ```
final String componentName;
String _stringifed;
PackageUrl({
@required this.host,
@required this.packageName,
@required this.packageVariant,
@required this.hash,
@required this.fullComponentName,
@required this.componentName,
});
PackageUrl.copyWithHash({
@required PackageUrl other,
@required this.hash,
}) : host = other.host,
packageName = other.packageName,
packageVariant = other.packageVariant,
fullComponentName = other.fullComponentName,
componentName = other.componentName;
/// Breaks out a canonical Fuchsia URL into its constituent parts.
///
/// Parses something like
/// `fuchsia-pkg://host/package_name/variant?hash=1234#PATH.cmx` into:
///
/// ```dart
/// PackageUrl(
/// 'host': 'host',
/// 'packageName': 'package_name',
/// 'packageVariant': 'variant',
/// 'hash': '1234',
/// 'fullComponentName': 'PATH.cmx',
/// 'componentName': 'PATH',
/// );
/// ```
factory PackageUrl.fromString(String packageUrl) {
Uri parsedUri = Uri.parse(packageUrl);
if (parsedUri.scheme != 'fuchsia-pkg') {
throw MalformedFuchsiaUrlException(packageUrl);
}
return PackageUrl(
host: parsedUri.host,
packageName:
parsedUri.pathSegments.isNotEmpty ? parsedUri.pathSegments[0] : null,
packageVariant:
parsedUri.pathSegments.length > 1 ? parsedUri.pathSegments[1] : null,
hash: parsedUri.queryParameters['hash'],
fullComponentName: PackageUrl._removeMetaPrefix(parsedUri.fragment),
componentName: PackageUrl._removeMetaPrefix(
PackageUrl._removeExtension(parsedUri.fragment),
),
);
}
/// Returns something like
/// `fuchsia-pkg://host/package_name/variant?hash=1234#PATH.cmx`
@override
String toString() {
if (_stringifed == null) {
var path = [packageName];
if (packageVariant != null) path.add(packageVariant);
_stringifed = Uri(
scheme: 'fuchsia-pkg',
host: host,
pathSegments: path,
fragment: fullComponentName == null ? null : 'meta/$fullComponentName',
queryParameters: hash == null ? null : {'hash': hash},
).toString();
}
return _stringifed;
}
static String _removeMetaPrefix(String fullComponentName) {
const token = 'meta/';
return fullComponentName.startsWith(token)
? fullComponentName.substring(token.length)
: fullComponentName;
}
static String _removeExtension(String fullComponentName) {
// Guard against uninteresting edge cases
if (fullComponentName == null || !fullComponentName.contains('.')) {
return fullComponentName ?? '';
}
return fullComponentName.substring(0, fullComponentName.lastIndexOf('.'));
}
}