Skip to content

Commit 52a0344

Browse files
[path_provider] Restore 2.8 compatibility on Android and iOS (flutter#6039)
Adds a new repo tooling command that removes dev_dependencies, which aren't needed to consume a package, only for development. Also adds a --lib-only flag to analyze to analyze only the client-facing code. This is intended for use in the legacy analyze CI steps, primarily to solve the problem that currently plugins that use Pigeon can't support a version of Flutter older than the version supported by Pigeon, because otherwise the legacy analysis CI steps fail. Adds this new command to the legacy analysis CI step, and restores the recently-removed 2.8/2.10 compatibility to path_provider.
1 parent 946e9b7 commit 52a0344

File tree

12 files changed

+260
-14
lines changed

12 files changed

+260
-14
lines changed

.cirrus.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,14 @@ task:
163163
matrix:
164164
CHANNEL: "2.10.5"
165165
CHANNEL: "2.8.1"
166+
package_prep_script:
167+
# Allow analyzing plugins that use a Pigeon version with a higher
168+
# minimum Flutter/Dart version than the plugin itself.
169+
- ./script/tool_runner.sh remove-dev-dependencies
166170
analyze_script:
167-
- ./script/tool_runner.sh analyze --skip-if-not-supporting-flutter-version="$CHANNEL" --custom-analysis=script/configs/custom_analysis.yaml
171+
# Only analyze lib/; non-client code doesn't need to work on
172+
# all supported legacy version.
173+
- ./script/tool_runner.sh analyze --lib-only --skip-if-not-supporting-flutter-version="$CHANNEL" --custom-analysis=script/configs/custom_analysis.yaml
168174
- name: readme_excerpts
169175
env:
170176
CIRRUS_CLONE_SUBMODULES: true

packages/path_provider/path_provider_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.0.17
2+
3+
* Lower minimim version back to 2.8.1.
4+
15
## 2.0.16
26

37
* Fixes bug with `getExternalStoragePaths(null)`.

packages/path_provider/path_provider_android/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ name: path_provider_android
22
description: Android implementation of the path_provider plugin.
33
repository: https://github.com/flutter/plugins/tree/main/packages/path_provider/path_provider_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
5-
version: 2.0.16
5+
version: 2.0.17
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"
9-
flutter: ">=3.0.0"
9+
flutter: ">=2.8.1"
1010

1111
flutter:
1212
plugin:

packages/path_provider/path_provider_ios/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.0.11
2+
3+
* Lower minimim version back to 2.8.
4+
15
## 2.0.10
26

37
* Switches backend to pigeon.

packages/path_provider/path_provider_ios/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ name: path_provider_ios
22
description: iOS implementation of the path_provider plugin.
33
repository: https://github.com/flutter/plugins/tree/main/packages/path_provider/path_provider_ios
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+path_provider%22
5-
version: 2.0.10
5+
version: 2.0.11
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"
9-
flutter: ">=3.0.0"
9+
flutter: ">=2.8.0"
1010

1111
flutter:
1212
plugin:

script/tool/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 0.8.10
2+
3+
- Adds a new `remove-dev-dependencies` command to remove `dev_dependencies`
4+
entries to make legacy version analysis possible in more cases.
5+
- Adds a `--lib-only` option to `analyze` to allow only analyzing the client
6+
parts of a library for legacy verison compatibility.
7+
18
## 0.8.9
29

310
- Includes `dev_dependencies` when overridding dependencies using

script/tool/lib/src/analyze_command.dart

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,13 @@ class AnalyzeCommand extends PackageLoopingCommand {
3232
valueHelp: 'dart-sdk',
3333
help: 'An optional path to a Dart SDK; this is used to override the '
3434
'SDK used to provide analysis.');
35+
argParser.addFlag(_libOnlyFlag,
36+
help: 'Only analyze the lib/ directory of the main package, not the '
37+
'entire package.');
3538
}
3639

3740
static const String _customAnalysisFlag = 'custom-analysis';
38-
41+
static const String _libOnlyFlag = 'lib-only';
3942
static const String _analysisSdk = 'analysis-sdk';
4043

4144
late String _dartBinaryPath;
@@ -104,13 +107,20 @@ class AnalyzeCommand extends PackageLoopingCommand {
104107

105108
@override
106109
Future<PackageResult> runForPackage(RepositoryPackage package) async {
107-
// Analysis runs over the package and all subpackages, so all of them need
108-
// `flutter pub get` run before analyzing. `example` packages can be
109-
// skipped since 'flutter packages get' automatically runs `pub get` in
110-
// examples as part of handling the parent directory.
110+
final bool libOnly = getBoolArg(_libOnlyFlag);
111+
112+
if (libOnly && !package.libDirectory.existsSync()) {
113+
return PackageResult.skip('No lib/ directory.');
114+
}
115+
116+
// Analysis runs over the package and all subpackages (unless only lib/ is
117+
// being analyzed), so all of them need `flutter pub get` run before
118+
// analyzing. `example` packages can be skipped since 'flutter packages get'
119+
// automatically runs `pub get` in examples as part of handling the parent
120+
// directory.
111121
final List<RepositoryPackage> packagesToGet = <RepositoryPackage>[
112122
package,
113-
...await getSubpackages(package).toList(),
123+
if (!libOnly) ...await getSubpackages(package).toList(),
114124
];
115125
for (final RepositoryPackage packageToGet in packagesToGet) {
116126
if (packageToGet.directory.basename != 'example' ||
@@ -129,8 +139,8 @@ class AnalyzeCommand extends PackageLoopingCommand {
129139
if (_hasUnexpecetdAnalysisOptions(package)) {
130140
return PackageResult.fail(<String>['Unexpected local analysis options']);
131141
}
132-
final int exitCode = await processRunner.runAndStream(
133-
_dartBinaryPath, <String>['analyze', '--fatal-infos'],
142+
final int exitCode = await processRunner.runAndStream(_dartBinaryPath,
143+
<String>['analyze', '--fatal-infos', if (libOnly) 'lib'],
134144
workingDir: package.directory);
135145
if (exitCode != 0) {
136146
return PackageResult.fail();

script/tool/lib/src/main.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import 'publish_check_command.dart';
2828
import 'publish_plugin_command.dart';
2929
import 'pubspec_check_command.dart';
3030
import 'readme_check_command.dart';
31+
import 'remove_dev_dependencies.dart';
3132
import 'test_command.dart';
3233
import 'update_excerpts_command.dart';
3334
import 'update_release_info_command.dart';
@@ -71,6 +72,7 @@ void main(List<String> args) {
7172
..addCommand(PublishPluginCommand(packagesDir))
7273
..addCommand(PubspecCheckCommand(packagesDir))
7374
..addCommand(ReadmeCheckCommand(packagesDir))
75+
..addCommand(RemoveDevDependenciesCommand(packagesDir))
7476
..addCommand(TestCommand(packagesDir))
7577
..addCommand(UpdateExcerptsCommand(packagesDir))
7678
..addCommand(UpdateReleaseInfoCommand(packagesDir))
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:file/file.dart';
6+
import 'package:yaml/yaml.dart';
7+
import 'package:yaml_edit/yaml_edit.dart';
8+
9+
import 'common/package_looping_command.dart';
10+
import 'common/repository_package.dart';
11+
12+
/// A command to remove dev_dependencies, which are not used by package clients.
13+
///
14+
/// This is intended for use with legacy Flutter version testing, to allow
15+
/// running analysis (with --lib-only) with versions that are supported for
16+
/// clients of the library, but not for development of the library.
17+
class RemoveDevDependenciesCommand extends PackageLoopingCommand {
18+
/// Creates a publish metadata updater command instance.
19+
RemoveDevDependenciesCommand(Directory packagesDir) : super(packagesDir);
20+
21+
@override
22+
final String name = 'remove-dev-dependencies';
23+
24+
@override
25+
final String description = 'Removes any dev_dependencies section from a '
26+
'package, to allow more legacy testing.';
27+
28+
@override
29+
bool get hasLongOutput => false;
30+
31+
@override
32+
PackageLoopingType get packageLoopingType =>
33+
PackageLoopingType.includeAllSubpackages;
34+
35+
@override
36+
Future<PackageResult> runForPackage(RepositoryPackage package) async {
37+
bool changed = false;
38+
final YamlEditor editablePubspec =
39+
YamlEditor(package.pubspecFile.readAsStringSync());
40+
const String devDependenciesKey = 'dev_dependencies';
41+
final YamlNode root = editablePubspec.parseAt(<String>[]);
42+
final YamlMap? devDependencies =
43+
(root as YamlMap)[devDependenciesKey] as YamlMap?;
44+
if (devDependencies != null) {
45+
changed = true;
46+
print('${indentation}Removed dev_dependencies');
47+
editablePubspec.remove(<String>[devDependenciesKey]);
48+
}
49+
50+
if (changed) {
51+
package.pubspecFile.writeAsStringSync(editablePubspec.toString());
52+
}
53+
54+
return changed
55+
? PackageResult.success()
56+
: PackageResult.skip('Nothing to remove.');
57+
}
58+
}

script/tool/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: flutter_plugin_tools
22
description: Productivity utils for flutter/plugins and flutter/packages
33
repository: https://github.com/flutter/plugins/tree/main/script/tool
4-
version: 0.8.9
4+
version: 0.8.10
55

66
dependencies:
77
args: ^2.1.0

script/tool/test/analyze_command_test.dart

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,59 @@ void main() {
9393
]));
9494
});
9595

96+
test('passes lib/ directory with --lib-only', () async {
97+
final RepositoryPackage package =
98+
createFakePackage('a_package', packagesDir);
99+
100+
await runCapturingPrint(runner, <String>['analyze', '--lib-only']);
101+
102+
expect(
103+
processRunner.recordedCalls,
104+
orderedEquals(<ProcessCall>[
105+
ProcessCall('flutter', const <String>['pub', 'get'], package.path),
106+
ProcessCall('dart', const <String>['analyze', '--fatal-infos', 'lib'],
107+
package.path),
108+
]));
109+
});
110+
111+
test('skips when missing lib/ directory with --lib-only', () async {
112+
final RepositoryPackage package =
113+
createFakePackage('a_package', packagesDir);
114+
package.libDirectory.deleteSync();
115+
116+
final List<String> output =
117+
await runCapturingPrint(runner, <String>['analyze', '--lib-only']);
118+
119+
expect(processRunner.recordedCalls, isEmpty);
120+
expect(
121+
output,
122+
containsAllInOrder(<Matcher>[
123+
contains('SKIPPING: No lib/ directory'),
124+
]),
125+
);
126+
});
127+
128+
test(
129+
'does not run flutter pub get for non-example subpackages with --lib-only',
130+
() async {
131+
final RepositoryPackage mainPackage = createFakePackage('a', packagesDir);
132+
final Directory otherPackagesDir =
133+
mainPackage.directory.childDirectory('other_packages');
134+
createFakePackage('subpackage1', otherPackagesDir);
135+
createFakePackage('subpackage2', otherPackagesDir);
136+
137+
await runCapturingPrint(runner, <String>['analyze', '--lib-only']);
138+
139+
expect(
140+
processRunner.recordedCalls,
141+
orderedEquals(<ProcessCall>[
142+
ProcessCall(
143+
'flutter', const <String>['pub', 'get'], mainPackage.path),
144+
ProcessCall('dart', const <String>['analyze', '--fatal-infos', 'lib'],
145+
mainPackage.path),
146+
]));
147+
});
148+
96149
test("don't elide a non-contained example package", () async {
97150
final RepositoryPackage plugin1 = createFakePlugin('a', packagesDir);
98151
final RepositoryPackage plugin2 = createFakePlugin('example', packagesDir);
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:args/command_runner.dart';
6+
import 'package:file/file.dart';
7+
import 'package:file/memory.dart';
8+
import 'package:flutter_plugin_tools/src/remove_dev_dependencies.dart';
9+
import 'package:test/test.dart';
10+
11+
import 'util.dart';
12+
13+
void main() {
14+
late FileSystem fileSystem;
15+
late Directory packagesDir;
16+
late CommandRunner<void> runner;
17+
18+
setUp(() {
19+
fileSystem = MemoryFileSystem();
20+
packagesDir = createPackagesDirectory(fileSystem: fileSystem);
21+
22+
final RemoveDevDependenciesCommand command = RemoveDevDependenciesCommand(
23+
packagesDir,
24+
);
25+
runner = CommandRunner<void>('trim_dev_dependencies_command',
26+
'Test for trim_dev_dependencies_command');
27+
runner.addCommand(command);
28+
});
29+
30+
void _addToPubspec(RepositoryPackage package, String addition) {
31+
final String originalContent = package.pubspecFile.readAsStringSync();
32+
package.pubspecFile.writeAsStringSync('''
33+
$originalContent
34+
$addition
35+
''');
36+
}
37+
38+
test('skips if nothing is removed', () async {
39+
createFakePackage('a_package', packagesDir, version: '1.0.0');
40+
41+
final List<String> output =
42+
await runCapturingPrint(runner, <String>['remove-dev-dependencies']);
43+
44+
expect(
45+
output,
46+
containsAllInOrder(<Matcher>[
47+
contains('SKIPPING: Nothing to remove.'),
48+
]),
49+
);
50+
});
51+
52+
test('removes dev_dependencies', () async {
53+
final RepositoryPackage package =
54+
createFakePackage('a_package', packagesDir, version: '1.0.0');
55+
56+
_addToPubspec(package, '''
57+
dev_dependencies:
58+
some_dependency: ^2.1.8
59+
another_dependency: ^1.0.0
60+
''');
61+
62+
final List<String> output =
63+
await runCapturingPrint(runner, <String>['remove-dev-dependencies']);
64+
65+
expect(
66+
output,
67+
containsAllInOrder(<Matcher>[
68+
contains('Removed dev_dependencies'),
69+
]),
70+
);
71+
expect(package.pubspecFile.readAsStringSync(),
72+
isNot(contains('some_dependency:')));
73+
expect(package.pubspecFile.readAsStringSync(),
74+
isNot(contains('another_dependency:')));
75+
});
76+
77+
test('removes from examples', () async {
78+
final RepositoryPackage package =
79+
createFakePackage('a_package', packagesDir, version: '1.0.0');
80+
81+
final RepositoryPackage example = package.getExamples().first;
82+
_addToPubspec(example, '''
83+
dev_dependencies:
84+
some_dependency: ^2.1.8
85+
another_dependency: ^1.0.0
86+
''');
87+
88+
final List<String> output =
89+
await runCapturingPrint(runner, <String>['remove-dev-dependencies']);
90+
91+
expect(
92+
output,
93+
containsAllInOrder(<Matcher>[
94+
contains('Removed dev_dependencies'),
95+
]),
96+
);
97+
expect(package.pubspecFile.readAsStringSync(),
98+
isNot(contains('some_dependency:')));
99+
expect(package.pubspecFile.readAsStringSync(),
100+
isNot(contains('another_dependency:')));
101+
});
102+
}

0 commit comments

Comments
 (0)