Avoid reloading credentials file on each getter access (#4344)
* Avoid reloading credentials file on each getter access
* Check for tokensfile when attempting mutation
diff --git a/lib/src/authentication/credential.dart b/lib/src/authentication/credential.dart
index 7e03a4d..232ca5c 100644
--- a/lib/src/authentication/credential.dart
+++ b/lib/src/authentication/credential.dart
@@ -8,12 +8,15 @@
import '../source/hosted.dart';
import '../utils.dart';
-/// Token is a structure for storing authentication credentials for third-party
-/// pub registries. A token holds registry [url], credential [kind] and [token]
-/// itself.
+/// [Credential] is a structure for storing authentication credentials for
+/// third-party pub registries.
///
-/// Token could be serialized into and from JSON format structured like
-/// this:
+/// A [Credential] holds a registry [url], and either the [token] itself or the
+/// name of an environment variable [env] for looking up the token when
+/// authenticating.
+///
+/// For storing in the pub-tokens.json configuration, a [Credential] can be
+/// serialized into and from JSON format structured like this:
///
/// ```json
/// {
@@ -21,6 +24,17 @@
/// "token": "gjrjo7Tm2F0u64cTsECDq4jBNZYhco"
/// }
/// ```
+///
+/// or
+///
+/// /// ```json
+/// {
+/// "url": "https://example.com/",
+/// "env": "TOKEN_ENV_VAR"
+/// }
+/// ```
+///
+/// Unknown JSON properties will be preserved when reencoding.
class Credential {
/// Internal constructor that's only used by [Credential.fromJson].
Credential._internal({
diff --git a/lib/src/authentication/token_store.dart b/lib/src/authentication/token_store.dart
index 104dbd1..d11f63c 100644
--- a/lib/src/authentication/token_store.dart
+++ b/lib/src/authentication/token_store.dart
@@ -19,11 +19,13 @@
/// Cache directory.
final String? configDir;
- /// List of saved authentication tokens.
+ /// Enumeration of saved authentication tokens.
///
- /// Modifying this field will not write changes to the disk. You have to call
- /// [flush] to save changes.
- Iterable<Credential> get credentials => _loadCredentials();
+ /// Call [addCredential] and [removeCredential] to update the credentials
+ /// while saving changes to disk.
+ Iterable<Credential> get credentials => _credentials;
+
+ late final List<Credential> _credentials = _loadCredentials();
/// Reads "pub-tokens.json" and parses / deserializes it into list of
/// [Credential].
@@ -103,7 +105,7 @@
void _saveCredentials(List<Credential> credentials) {
final tokensFile = this.tokensFile;
if (tokensFile == null) {
- missingConfigDir();
+ throw AssertionError('Bad state');
}
ensureDir(p.dirname(tokensFile));
writeTextFile(
@@ -117,6 +119,9 @@
/// Adds [token] into store and writes into disk.
void addCredential(Credential token) {
+ if (tokensFile == null) {
+ missingConfigDir();
+ }
final credentials = _loadCredentials();
// Remove duplicate tokens
@@ -128,20 +133,23 @@
/// Removes tokens with matching [hostedUrl] from store. Returns whether or
/// not there's a stored token with matching url.
bool removeCredential(Uri hostedUrl) {
- final credentials = _loadCredentials();
-
+ if (tokensFile == null) {
+ missingConfigDir();
+ }
var i = 0;
var found = false;
- while (i < credentials.length) {
- if (credentials[i].url == hostedUrl) {
- credentials.removeAt(i);
+ while (i < _credentials.length) {
+ if (_credentials[i].url == hostedUrl) {
+ _credentials.removeAt(i);
found = true;
} else {
i++;
}
}
- _saveCredentials(credentials);
+ if (found) {
+ _saveCredentials(_credentials);
+ }
return found;
}
@@ -150,7 +158,7 @@
/// matching credential is found.
Credential? findCredential(Uri hostedUrl) {
Credential? matchedCredential;
- for (final credential in credentials) {
+ for (final credential in _credentials) {
if (credential.url == hostedUrl && credential.isValid()) {
if (matchedCredential == null) {
matchedCredential = credential;
@@ -170,7 +178,7 @@
/// Returns whether or not store contains a token that could be used for
/// authenticating given [url].
bool hasCredential(Uri url) {
- return credentials.any((it) => it.url == url && it.isValid());
+ return _credentials.any((it) => it.url == url && it.isValid());
}
/// Deletes pub-tokens.json file from the disk.