mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
fix checkLockAcquired: support re-entrant locking (#9272)
* fix checkLockAcquired: support re-entrant locking * add test; address comments * add comment
This commit is contained in:
parent
33997bb7bb
commit
361afef305
@ -4,6 +4,8 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'base/context.dart';
|
||||
import 'base/file_system.dart';
|
||||
import 'base/logger.dart';
|
||||
@ -33,10 +35,19 @@ class Cache {
|
||||
///
|
||||
/// This is used by the tests since they run simultaneously and all in one
|
||||
/// process and so it would be a mess if they had to use the lock.
|
||||
@visibleForTesting
|
||||
static void disableLocking() {
|
||||
_lockEnabled = false;
|
||||
}
|
||||
|
||||
/// Turn on the [lock]/[releaseLockEarly] mechanism.
|
||||
///
|
||||
/// This is used by the tests.
|
||||
@visibleForTesting
|
||||
static void enableLocking() {
|
||||
_lockEnabled = true;
|
||||
}
|
||||
|
||||
/// Lock the cache directory.
|
||||
///
|
||||
/// This happens automatically on startup (see [FlutterCommandRunner.runCommand]).
|
||||
@ -48,7 +59,7 @@ class Cache {
|
||||
if (!_lockEnabled)
|
||||
return null;
|
||||
assert(_lock == null);
|
||||
_lock = fs.file(fs.path.join(flutterRoot, 'bin', 'cache', 'lockfile')).openSync(mode: FileMode.WRITE);
|
||||
_lock = await fs.file(fs.path.join(flutterRoot, 'bin', 'cache', 'lockfile')).open(mode: FileMode.WRITE);
|
||||
bool locked = false;
|
||||
bool printed = false;
|
||||
while (!locked) {
|
||||
@ -77,7 +88,7 @@ class Cache {
|
||||
/// Checks if the current process owns the lock for the cache directory at
|
||||
/// this very moment; throws a [StateError] if it doesn't.
|
||||
static void checkLockAcquired() {
|
||||
if (_lockEnabled && _lock == null) {
|
||||
if (_lockEnabled && _lock == null && platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') {
|
||||
throw new StateError(
|
||||
'The current process does not own the lock for the cache directory. This is a bug in Flutter CLI tools.',
|
||||
);
|
||||
|
67
packages/flutter_tools/test/src/cache_test.dart
Normal file
67
packages/flutter_tools/test/src/cache_test.dart
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright 2016 The Chromium 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 'dart:async';
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
|
||||
import 'context.dart';
|
||||
|
||||
void main() {
|
||||
group('$Cache.checkLockAcquired', () {
|
||||
setUp(() {
|
||||
Cache.enableLocking();
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
// Restore locking to prevent potential side-effects in
|
||||
// tests outside this group (this option is globally shared).
|
||||
Cache.enableLocking();
|
||||
});
|
||||
|
||||
test('should throw when locking is not acquired', () {
|
||||
expect(() => Cache.checkLockAcquired(), throwsStateError);
|
||||
});
|
||||
|
||||
test('should not throw when locking is disabled', () {
|
||||
Cache.disableLocking();
|
||||
Cache.checkLockAcquired();
|
||||
});
|
||||
|
||||
testUsingContext('should not throw when lock is acquired', () async {
|
||||
await Cache.lock();
|
||||
Cache.checkLockAcquired();
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => new MockFileSystem(),
|
||||
});
|
||||
|
||||
testUsingContext('should not throw when FLUTTER_ALREADY_LOCKED is set', () async {
|
||||
Cache.checkLockAcquired();
|
||||
}, overrides: <Type, Generator>{
|
||||
Platform: () => new FakePlatform()..environment = <String, String>{'FLUTTER_ALREADY_LOCKED': 'true'},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class MockFileSystem extends MemoryFileSystem {
|
||||
@override
|
||||
File file(dynamic path) {
|
||||
return new MockFile();
|
||||
}
|
||||
}
|
||||
|
||||
class MockFile extends Mock implements File {
|
||||
@override
|
||||
Future<RandomAccessFile> open({FileMode mode: FileMode.READ}) async {
|
||||
return new MockRandomAccessFile();
|
||||
}
|
||||
}
|
||||
|
||||
class MockRandomAccessFile extends Mock implements RandomAccessFile {}
|
Loading…
Reference in New Issue
Block a user