Skip to content

Commit

Permalink
Serialize AssetGraph to/from List<int> (#873)
Browse files Browse the repository at this point in the history
Helpful for #41

Centralizes all references to `JSON` within the serialization so that we
can update a single place to experiment with other serialization
formats.
  • Loading branch information
natebosch authored Jan 19, 2018
1 parent 6bb54ad commit 843231f
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 58 deletions.
4 changes: 1 addition & 3 deletions build_runner/bin/create_merged_dir.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:args/args.dart';
Expand Down Expand Up @@ -52,8 +51,7 @@ Future main(List<String> args) async {

await logTimedAsync(logger, 'Loading asset graph at ${assetGraphFile.path}',
() async {
assetGraph = new AssetGraph.deserialize(
JSON.decode(await assetGraphFile.readAsString()) as Map);
assetGraph = new AssetGraph.deserialize(await assetGraphFile.readAsBytes());
});

packageGraph = new PackageGraph.forThisPackage();
Expand Down
4 changes: 1 addition & 3 deletions build_runner/bin/graph_inspector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:args/command_runner.dart';
Expand Down Expand Up @@ -43,8 +42,7 @@ Future main(List<String> args) async {
}
stdout.writeln('Loading asset graph at ${assetGraphFile.path}...');

assetGraph = new AssetGraph.deserialize(
JSON.decode(assetGraphFile.readAsStringSync()) as Map);
assetGraph = new AssetGraph.deserialize(assetGraphFile.readAsBytesSync());
packageGraph = new PackageGraph.forThisPackage();

var commandRunner = new CommandRunner(
Expand Down
5 changes: 2 additions & 3 deletions build_runner/lib/src/asset_graph/graph.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class AssetGraph {
AssetGraph._(this.buildActionsDigest);

/// Deserializes this graph.
factory AssetGraph.deserialize(Map serializedGraph) =>
factory AssetGraph.deserialize(List<int> serializedGraph) =>
new _AssetGraphDeserializer(serializedGraph).deserialize();

static Future<AssetGraph> build(
Expand All @@ -58,8 +58,7 @@ class AssetGraph {
return graph;
}

Map<String, dynamic> serialize() =>
new _AssetGraphSerializer(this).serialize();
List<int> serialize() => new _AssetGraphSerializer(this).serialize();

/// Checks if [id] exists in the graph.
bool contains(AssetId id) =>
Expand Down
7 changes: 4 additions & 3 deletions build_runner/lib/src/asset_graph/serialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class _AssetGraphDeserializer {
final _idToAssetId = <int, AssetId>{};
final Map _serializedGraph;

_AssetGraphDeserializer(this._serializedGraph);
_AssetGraphDeserializer(List<int> bytes)
: _serializedGraph = JSON.decode(UTF8.decode(bytes)) as Map;

/// Perform the deserialization, should only be called once.
AssetGraph deserialize() {
Expand Down Expand Up @@ -129,7 +130,7 @@ class _AssetGraphSerializer {
_AssetGraphSerializer(this._graph);

/// Perform the serialization, should only be called once.
Map<String, dynamic> serialize() {
List<int> serialize() {
/// Compute numeric identifiers for all asset ids.
var next = 0;
for (var node in _graph.allNodes) {
Expand All @@ -152,7 +153,7 @@ class _AssetGraphSerializer {
});
result['serializedAssetIds'] = serializedAssetIds;

return result;
return UTF8.encode(JSON.encode(result));
}

List _serializeNode(AssetNode node) {
Expand Down
4 changes: 1 addition & 3 deletions build_runner/lib/src/generate/build_definition.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:build/build.dart';
Expand Down Expand Up @@ -186,8 +185,7 @@ class _Loader {
return logTimedAsync(_logger, 'Reading cached asset graph', () async {
try {
var cachedGraph = new AssetGraph.deserialize(
JSON.decode(await _environment.reader.readAsString(assetGraphId))
as Map);
await _environment.reader.readAsBytes(assetGraphId));
if (computeBuildActionsDigest(_buildActions) !=
cachedGraph.buildActionsDigest) {
_logger.warning(
Expand Down
5 changes: 2 additions & 3 deletions build_runner/lib/src/generate/build_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// for details. 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 'dart:convert';
import 'dart:io';

import 'package:build/build.dart';
Expand Down Expand Up @@ -200,9 +199,9 @@ class BuildImpl {
// Write out the dependency graph file.
await logTimedAsync(_logger, 'Caching finalized dependency graph',
() async {
await _writer.writeAsString(
await _writer.writeAsBytes(
new AssetId(_packageGraph.root.name, assetGraphPath),
JSON.encode(_assetGraph.serialize()));
_assetGraph.serialize());
});

done.complete(result);
Expand Down
11 changes: 6 additions & 5 deletions build_runner/test/asset_graph/graph_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,17 @@ void main() {
}
}

var encoded = JSON.encode(graph.serialize());
var decoded = new AssetGraph.deserialize(JSON.decode(encoded) as Map);
var encoded = graph.serialize();
var decoded = new AssetGraph.deserialize(encoded);
expect(graph, equalsAssetGraph(decoded));
});

test('Throws an AssetGraphVersionError if versions dont match up', () {
var serialized = graph.serialize();
var bytes = graph.serialize();
var serialized = JSON.decode(UTF8.decode(bytes));
serialized['version'] = -1;
var encoded = JSON.encode(serialized);
expect(() => new AssetGraph.deserialize(JSON.decode(encoded) as Map),
var encoded = UTF8.encode(JSON.encode(serialized));
expect(() => new AssetGraph.deserialize(encoded),
throwsA(assetGraphVersionException));
});
});
Expand Down
35 changes: 15 additions & 20 deletions build_runner/test/generate/build_definition_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// for details. 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 'dart:convert';
import 'dart:io';

import 'package:build/build.dart';
Expand Down Expand Up @@ -36,11 +35,15 @@ main() {
BuildEnvironment environment;
String pkgARoot;

Future<Null> createFile(String path, String contents) async {
Future<Null> createFile(String path, dynamic contents) async {
var file = new File(p.join(pkgARoot, path));
expect(await file.exists(), isFalse);
await file.create(recursive: true);
await file.writeAsString(contents);
if (contents is String) {
await file.writeAsString(contents);
} else {
await file.writeAsBytes(contents as List<int>);
}
addTearDown(() async => await file.exists() ? await file.delete() : null);
}

Expand Down Expand Up @@ -103,8 +106,7 @@ main() {
generatedANode.wasOutput = true;
generatedANode.needsUpdate = false;

await createFile(
assetGraphPath, JSON.encode(originalAssetGraph.serialize()));
await createFile(assetGraphPath, originalAssetGraph.serialize());

await deleteFile(p.join('lib', 'b.txt'));
var buildDefinition = await BuildDefinition.prepareWorkspace(
Expand All @@ -128,8 +130,7 @@ main() {
var originalAssetGraph = await AssetGraph.build(buildActions,
<AssetId>[].toSet(), new Set(), aPackageGraph, environment.reader);

await createFile(
assetGraphPath, JSON.encode(originalAssetGraph.serialize()));
await createFile(assetGraphPath, originalAssetGraph.serialize());

await createFile(p.join('lib', 'a.txt'), 'a');
var buildDefinition = await BuildDefinition.prepareWorkspace(
Expand Down Expand Up @@ -157,8 +158,7 @@ main() {
aPackageGraph,
environment.reader);

await createFile(
assetGraphPath, JSON.encode(originalAssetGraph.serialize()));
await createFile(assetGraphPath, originalAssetGraph.serialize());

await modifyFile(p.join('lib', 'a.txt'), 'b');
var buildDefinition = await BuildDefinition.prepareWorkspace(
Expand Down Expand Up @@ -189,8 +189,7 @@ main() {
originalAssetGraph.get(generatedSrcId) as GeneratedAssetNode;
generatedNode.wasOutput = false;

await createFile(
assetGraphPath, JSON.encode(originalAssetGraph.serialize()));
await createFile(assetGraphPath, originalAssetGraph.serialize());

var buildDefinition = await BuildDefinition.prepareWorkspace(
environment, options, buildActions);
Expand Down Expand Up @@ -221,8 +220,7 @@ main() {
node.needsUpdate = false;
}

await createFile(
assetGraphPath, JSON.encode(originalAssetGraph.serialize()));
await createFile(assetGraphPath, originalAssetGraph.serialize());

// Same as before, but change the `BuilderOptions` for the first action.
var newBuildActions = [
Expand Down Expand Up @@ -272,7 +270,7 @@ main() {
expect(assetGraph.allNodes.map((node) => node.id),
unorderedEquals(expectedIds));

await createFile(assetGraphPath, JSON.encode(assetGraph.serialize()));
await createFile(assetGraphPath, assetGraph.serialize());

var buildDefinition = await BuildDefinition.prepareWorkspace(
environment, options, buildActions);
Expand Down Expand Up @@ -321,8 +319,7 @@ main() {
var originalAssetGraph = await AssetGraph.build(buildActions,
<AssetId>[].toSet(), new Set(), aPackageGraph, environment.reader);

await createFile(
assetGraphPath, JSON.encode(originalAssetGraph.serialize()));
await createFile(assetGraphPath, originalAssetGraph.serialize());

buildActions.add(new BuildAction(new TestBuilder(), 'a',
targetSources: const InputSet(include: const ['.copy']),
Expand Down Expand Up @@ -365,8 +362,7 @@ main() {
var originalAssetGraph = await AssetGraph.build(buildActions,
<AssetId>[].toSet(), new Set(), aPackageGraph, environment.reader);

await createFile(
assetGraphPath, JSON.encode(originalAssetGraph.serialize()));
await createFile(assetGraphPath, originalAssetGraph.serialize());

buildActions = [
new BuildAction(new TestBuilder(), 'a',
Expand Down Expand Up @@ -416,8 +412,7 @@ main() {
(originalAssetGraph.get(aTxtCopy) as GeneratedAssetNode).wasOutput = true;
await createFile(aTxtCopy.path, 'hello');

await createFile(
assetGraphPath, JSON.encode(originalAssetGraph.serialize()));
await createFile(assetGraphPath, originalAssetGraph.serialize());

buildActions.add(new BuildAction(new TestBuilder(), 'a',
targetSources: const InputSet(include: const ['.copy']),
Expand Down
16 changes: 6 additions & 10 deletions build_runner/test/generate/build_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// for details. 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 'dart:convert';

import 'package:build/build.dart';
import 'package:glob/glob.dart';
Expand Down Expand Up @@ -252,8 +251,7 @@ void main() {

var graphId = makeAssetId('a|$assetGraphPath');
expect(writer.assets, contains(graphId));
var cachedGraph = new AssetGraph.deserialize(
JSON.decode(UTF8.decode(writer.assets[graphId])) as Map);
var cachedGraph = new AssetGraph.deserialize(writer.assets[graphId]);
expect(
cachedGraph.allNodes.map((node) => node.id),
unorderedEquals([
Expand Down Expand Up @@ -577,8 +575,7 @@ void main() {

var graphId = makeAssetId('a|$assetGraphPath');
expect(writer.assets, contains(graphId));
var cachedGraph = new AssetGraph.deserialize(
JSON.decode(UTF8.decode(writer.assets[graphId])) as Map);
var cachedGraph = new AssetGraph.deserialize(writer.assets[graphId]);

var expectedGraph = await AssetGraph.build([], new Set(), new Set(),
buildPackageGraph({rootPackage('a'): []}), null);
Expand Down Expand Up @@ -731,9 +728,8 @@ void main() {
writer: writer);

/// Should be deleted using the writer, and removed from the new graph.
var serialized = JSON.decode(
UTF8.decode(writer.assets[makeAssetId('a|$assetGraphPath')])) as Map;
var newGraph = new AssetGraph.deserialize(serialized);
var newGraph = new AssetGraph.deserialize(
writer.assets[makeAssetId('a|$assetGraphPath')]);
var aNodeId = makeAssetId('a|lib/a.txt');
var aCopyNodeId = makeAssetId('a|lib/a.txt.copy');
var aCloneNodeId = makeAssetId('a|lib/a.txt.copy.clone');
Expand Down Expand Up @@ -821,8 +817,8 @@ void main() {
}, writer: writer);

// Read cached graph and validate.
var graph = new AssetGraph.deserialize(JSON.decode(
UTF8.decode(writer.assets[makeAssetId('a|$assetGraphPath')])) as Map);
var graph = new AssetGraph.deserialize(
writer.assets[makeAssetId('a|$assetGraphPath')]);
var outputNode =
graph.get(makeAssetId('a|lib/file.a.copy')) as GeneratedAssetNode;
var fileANode = graph.get(makeAssetId('a|lib/file.a'));
Expand Down
7 changes: 2 additions & 5 deletions build_runner/test/generate/watch_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// for details. 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 'dart:convert';

import 'package:async/async.dart';
import 'package:build/build.dart';
Expand Down Expand Up @@ -242,10 +241,8 @@ a:file://fake/pkg/path
outputs: {'a|web/b.txt.copy': 'b2', 'a|web/c.txt.copy': 'c'},
writer: writer);

var serialized = JSON.decode(
UTF8.decode(writer.assets[makeAssetId('a|$assetGraphPath')]))
as Map;
var cachedGraph = new AssetGraph.deserialize(serialized);
var cachedGraph = new AssetGraph.deserialize(
writer.assets[makeAssetId('a|$assetGraphPath')]);

var expectedGraph = await AssetGraph.build([], new Set(), new Set(),
buildPackageGraph({rootPackage('a'): []}), null);
Expand Down

0 comments on commit 843231f

Please sign in to comment.