Skip to content

Commit 35681b0

Browse files
authored
Analytics (#2778)
1 parent 9c65d31 commit 35681b0

18 files changed

+314
-62
lines changed

lib/pub.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@ import 'src/command_runner.dart';
99
import 'src/pub_embeddable_command.dart';
1010
export 'src/executable.dart'
1111
show getExecutableForCommand, CommandResolutionFailedException;
12+
export 'src/pub_embeddable_command.dart' show PubAnalytics;
1213

1314
/// Returns a [Command] for pub functionality that can be used by an embedding
1415
/// CommandRunner.
15-
Command<int> pubCommand() => PubEmbeddableCommand();
16+
///
17+
/// If [analytics] is given, pub will use that analytics instance to send
18+
/// statistics about resolutions.
19+
Command<int> pubCommand({PubAnalytics analytics}) =>
20+
PubEmbeddableCommand(analytics);
1621

1722
/// Support for the `pub` toplevel command.
1823
@Deprecated('Use [pubCommand] instead.')

lib/src/command.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ abstract class PubCommand extends Command<int> {
117117
return _pubEmbeddableCommand ?? (runner as PubCommandRunner);
118118
}
119119

120+
PubAnalytics get analytics => _pubEmbeddableCommand?.analytics;
121+
120122
@override
121123
String get invocation {
122124
var command = this;

lib/src/command/add.dart

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,10 @@ class AddCommand extends PubCommand {
150150
// TODO(jonasfj): Stop abusing Entrypoint.global for dry-run output
151151
await Entrypoint.global(newRoot, entrypoint.lockFile, cache,
152152
solveResult: solveResult)
153-
.acquireDependencies(
154-
SolveType.GET,
155-
dryRun: true,
156-
precompile: argResults['precompile'],
157-
);
153+
.acquireDependencies(SolveType.GET,
154+
dryRun: true,
155+
precompile: argResults['precompile'],
156+
analytics: analytics);
158157
} else {
159158
/// Update the `pubspec.yaml` before calling [acquireDependencies] to
160159
/// ensure that the modification timestamp on `pubspec.lock` and
@@ -165,14 +164,18 @@ class AddCommand extends PubCommand {
165164
/// Create a new [Entrypoint] since we have to reprocess the updated
166165
/// pubspec file.
167166
final updatedEntrypoint = Entrypoint(directory, cache);
168-
await updatedEntrypoint.acquireDependencies(SolveType.GET,
169-
precompile: argResults['precompile']);
167+
await updatedEntrypoint.acquireDependencies(
168+
SolveType.GET,
169+
precompile: argResults['precompile'],
170+
analytics: analytics,
171+
);
170172

171173
if (argResults['example'] && entrypoint.example != null) {
172174
await entrypoint.example.acquireDependencies(
173175
SolveType.GET,
174176
precompile: argResults['precompile'],
175177
onlyReportSuccessOrFailure: true,
178+
analytics: analytics,
176179
);
177180
}
178181
}

lib/src/command/downgrade.dart

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,21 @@ class DowngradeCommand extends PubCommand {
5353
'The --packages-dir flag is no longer used and does nothing.'));
5454
}
5555
var dryRun = argResults['dry-run'];
56+
5657
await entrypoint.acquireDependencies(
5758
SolveType.DOWNGRADE,
5859
unlock: argResults.rest,
5960
dryRun: dryRun,
61+
analytics: analytics,
6062
);
6163
if (argResults['example'] && entrypoint.example != null) {
62-
await entrypoint.example.acquireDependencies(SolveType.GET,
63-
unlock: argResults.rest,
64-
dryRun: dryRun,
65-
onlyReportSuccessOrFailure: true);
64+
await entrypoint.example.acquireDependencies(
65+
SolveType.GET,
66+
unlock: argResults.rest,
67+
dryRun: dryRun,
68+
onlyReportSuccessOrFailure: true,
69+
analytics: analytics,
70+
);
6671
}
6772

6873
if (isOffline) {

lib/src/command/get.dart

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,21 @@ class GetCommand extends PubCommand {
5151
log.warning(log.yellow(
5252
'The --packages-dir flag is no longer used and does nothing.'));
5353
}
54-
await entrypoint.acquireDependencies(SolveType.GET,
55-
dryRun: argResults['dry-run'], precompile: argResults['precompile']);
54+
await entrypoint.acquireDependencies(
55+
SolveType.GET,
56+
dryRun: argResults['dry-run'],
57+
precompile: argResults['precompile'],
58+
analytics: analytics,
59+
);
5660

5761
if (argResults['example'] && entrypoint.example != null) {
58-
await entrypoint.example.acquireDependencies(SolveType.GET,
59-
dryRun: argResults['dry-run'],
60-
precompile: argResults['precompile'],
61-
onlyReportSuccessOrFailure: true);
62+
await entrypoint.example.acquireDependencies(
63+
SolveType.GET,
64+
dryRun: argResults['dry-run'],
65+
precompile: argResults['precompile'],
66+
onlyReportSuccessOrFailure: true,
67+
analytics: analytics,
68+
);
6269
}
6370
}
6471
}

lib/src/command/global_activate.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,12 @@ class GlobalActivateCommand extends PubCommand {
139139

140140
var path = readArg('No package to activate given.');
141141
validateNoExtraArgs();
142-
return globals.activatePath(path, executables,
143-
overwriteBinStubs: overwrite);
142+
return globals.activatePath(
143+
path,
144+
executables,
145+
overwriteBinStubs: overwrite,
146+
analytics: analytics,
147+
);
144148
}
145149

146150
throw StateError('unreachable');

lib/src/command/remove.dart

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,25 +68,30 @@ class RemoveCommand extends PubCommand {
6868
final newRoot = Package.inMemory(newPubspec);
6969

7070
await Entrypoint.global(newRoot, entrypoint.lockFile, cache)
71-
.acquireDependencies(
72-
SolveType.GET,
73-
precompile: argResults['precompile'],
74-
dryRun: true,
75-
);
71+
.acquireDependencies(SolveType.GET,
72+
precompile: argResults['precompile'],
73+
dryRun: true,
74+
analytics: null);
7675
} else {
7776
/// Update the pubspec.
7877
_writeRemovalToPubspec(packages);
7978

8079
/// Create a new [Entrypoint] since we have to reprocess the updated
8180
/// pubspec file.
8281
final updatedEntrypoint = Entrypoint(directory, cache);
83-
await updatedEntrypoint.acquireDependencies(SolveType.GET,
84-
precompile: argResults['precompile']);
82+
await updatedEntrypoint.acquireDependencies(
83+
SolveType.GET,
84+
precompile: argResults['precompile'],
85+
analytics: analytics,
86+
);
8587

8688
if (argResults['example'] && entrypoint.example != null) {
87-
await entrypoint.example.acquireDependencies(SolveType.GET,
88-
precompile: argResults['precompile'],
89-
onlyReportSuccessOrFailure: true);
89+
await entrypoint.example.acquireDependencies(
90+
SolveType.GET,
91+
precompile: argResults['precompile'],
92+
onlyReportSuccessOrFailure: true,
93+
analytics: analytics,
94+
);
9095
}
9196
}
9297
}

lib/src/command/upgrade.dart

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,14 @@ class UpgradeCommand extends PubCommand {
122122
}
123123

124124
Future<void> _runUpgrade(Entrypoint e, {bool onlySummary = false}) async {
125-
await e.acquireDependencies(SolveType.UPGRADE,
126-
unlock: argResults.rest,
127-
dryRun: _dryRun,
128-
precompile: _precompile,
129-
onlyReportSuccessOrFailure: onlySummary);
125+
await e.acquireDependencies(
126+
SolveType.UPGRADE,
127+
unlock: argResults.rest,
128+
dryRun: _dryRun,
129+
precompile: _precompile,
130+
onlyReportSuccessOrFailure: onlySummary,
131+
analytics: analytics,
132+
);
130133

131134
_showOfflineWarning();
132135
}
@@ -233,6 +236,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not:
233236
SolveType.UPGRADE,
234237
dryRun: true,
235238
precompile: _precompile,
239+
analytics: null, // No analytics for dry-run
236240
);
237241
} else {
238242
await _updatePubspec(changes);
@@ -243,6 +247,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not:
243247
await Entrypoint(directory, cache).acquireDependencies(
244248
SolveType.UPGRADE,
245249
precompile: _precompile,
250+
analytics: analytics,
246251
);
247252
}
248253

@@ -326,6 +331,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not:
326331
SolveType.UPGRADE,
327332
dryRun: true,
328333
precompile: _precompile,
334+
analytics: null,
329335
);
330336
} else {
331337
await _updatePubspec(changes);
@@ -336,6 +342,7 @@ be direct 'dependencies' or 'dev_dependencies', following packages are not:
336342
await Entrypoint(directory, cache).acquireDependencies(
337343
SolveType.UPGRADE,
338344
precompile: _precompile,
345+
analytics: analytics,
339346
);
340347
}
341348

lib/src/entrypoint.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import 'package_config.dart' show PackageConfig;
2828
import 'package_graph.dart';
2929
import 'package_name.dart';
3030
import 'packages_file.dart' as packages_file;
31+
import 'pub_embeddable_command.dart';
3132
import 'pubspec.dart';
3233
import 'sdk.dart';
3334
import 'solver.dart';
@@ -247,6 +248,7 @@ class Entrypoint {
247248
Iterable<String> unlock,
248249
bool dryRun = false,
249250
bool precompile = false,
251+
@required PubAnalytics analytics,
250252
bool onlyReportSuccessOrFailure = false,
251253
}) async {
252254
final suffix = root.dir == null || root.dir == '.' ? '' : ' in ${root.dir}';
@@ -307,6 +309,10 @@ class Entrypoint {
307309
}
308310

309311
if (!dryRun) {
312+
if (analytics != null) {
313+
result.sendAnalytics(analytics);
314+
}
315+
310316
/// Build a package graph from the version solver results so we don't
311317
/// have to reload and reparse all the pubspecs.
312318
_packageGraph = PackageGraph.fromSolveResult(this, result);

lib/src/executable.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import 'io.dart';
1919
import 'isolate.dart' as isolate;
2020
import 'log.dart' as log;
2121
import 'log.dart';
22+
import 'pub_embeddable_command.dart';
2223
import 'solver/type.dart';
2324
import 'system_cache.dart';
2425
import 'utils.dart';
@@ -236,7 +237,9 @@ Future<int> _runDartProgram(
236237
/// [CommandResolutionFailedException].
237238
///
238239
/// * Otherwise if the current package resolution is outdated do an implicit
239-
/// `pub get`, if that fails, throw a [CommandResolutionFailedException].
240+
/// `pub get`, if that fails, throw a [CommandResolutionFailedException].
241+
///
242+
/// This pub get will send analytics events to [analytics] if provided.
240243
///
241244
/// * Otherwise let `<current>` be the name of the package at [root], and
242245
/// interpret [descriptor] as `[<package>][:<command>]`.
@@ -269,6 +272,7 @@ Future<String> getExecutableForCommand(
269272
bool allowSnapshot = true,
270273
String root,
271274
String pubCacheDir,
275+
PubAnalytics analytics,
272276
}) async {
273277
root ??= p.current;
274278
var asPath = descriptor;
@@ -294,7 +298,11 @@ Future<String> getExecutableForCommand(
294298
entrypoint.assertUpToDate();
295299
} on DataException {
296300
await warningsOnlyUnlessTerminal(
297-
() => entrypoint.acquireDependencies(SolveType.GET));
301+
() => entrypoint.acquireDependencies(
302+
SolveType.GET,
303+
analytics: analytics,
304+
),
305+
);
298306
}
299307

300308
String command;

lib/src/global_packages.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import 'lock_file.dart';
2121
import 'log.dart' as log;
2222
import 'package.dart';
2323
import 'package_name.dart';
24+
import 'pub_embeddable_command.dart';
2425
import 'pubspec.dart';
2526
import 'sdk.dart';
2627
import 'solver.dart';
@@ -144,11 +145,11 @@ class GlobalPackages {
144145
/// existing binstubs in other packages will be overwritten by this one's.
145146
/// Otherwise, the previous ones will be preserved.
146147
Future<void> activatePath(String path, List<String> executables,
147-
{bool overwriteBinStubs}) async {
148+
{bool overwriteBinStubs, @required PubAnalytics analytics}) async {
148149
var entrypoint = Entrypoint(path, cache);
149150

150151
// Get the package's dependencies.
151-
await entrypoint.acquireDependencies(SolveType.GET);
152+
await entrypoint.acquireDependencies(SolveType.GET, analytics: analytics);
152153
var name = entrypoint.root.name;
153154

154155
try {

lib/src/pub_embeddable_command.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
// @dart=2.10
6+
import 'package:meta/meta.dart';
7+
import 'package:usage/usage.dart';
68

9+
import 'command.dart' show PubCommand, PubTopLevel;
710
import 'command.dart';
811
import 'command/add.dart';
912
import 'command/build.dart';
@@ -24,6 +27,16 @@ import 'command/uploader.dart';
2427
import 'log.dart' as log;
2528
import 'log.dart';
2629

30+
/// The information needed for the embedded pub command to send analytics.
31+
@sealed
32+
class PubAnalytics {
33+
/// Name of the custom dimension of the dependency kind.
34+
final String dependencyKindCustomDimensionName;
35+
final Analytics analytics;
36+
PubAnalytics(this.analytics,
37+
{@required this.dependencyKindCustomDimensionName});
38+
}
39+
2740
/// Exposes the `pub` commands as a command to be embedded in another command
2841
/// runner such as `dart pub`.
2942
class PubEmbeddableCommand extends PubCommand implements PubTopLevel {
@@ -34,10 +47,13 @@ class PubEmbeddableCommand extends PubCommand implements PubTopLevel {
3447
@override
3548
String get docUrl => 'https://dart.dev/tools/pub/cmd/pub-global';
3649

50+
@override
51+
final PubAnalytics analytics;
52+
3753
@override
3854
String get directory => argResults['directory'];
3955

40-
PubEmbeddableCommand() : super() {
56+
PubEmbeddableCommand(this.analytics) : super() {
4157
argParser.addFlag('trace',
4258
help: 'Print debugging information when an error occurs.');
4359
argParser.addFlag('verbose',

0 commit comments

Comments
 (0)