Commit 1c2747ce authored by Matt Perry's avatar Matt Perry

Merge pull request #2269 from mpcomplete/rm.updater

Remove unused updater package.
parents ed345073 eaee8915
...@@ -15,9 +15,5 @@ ...@@ -15,9 +15,5 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<service
android:name="org.domokit.sky.shell.UpdateService"
android:exported="false"
android:process=":remote"/>
</application> </application>
</manifest> </manifest>
// Copyright 2015 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 'dart:io';
import 'package:mojo/core.dart';
import 'package:flutter/http.dart' as http;
import 'package:flutter/services.dart';
import 'package:flx/bundle.dart';
import 'package:sky_services/updater/update_service.mojom.dart';
import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart' as yaml;
import 'pipe_to_file.dart';
import 'version.dart';
const String kManifestFile = 'flutter.yaml';
const String kBundleFile = 'app.flx';
UpdateServiceProxy _initUpdateService() {
UpdateServiceProxy updateService = new UpdateServiceProxy.unbound();
shell.connectToService(null, updateService);
return updateService;
}
final UpdateServiceProxy _updateService = _initUpdateService();
String cachedDataDir = null;
Future<String> getDataDir() async {
if (cachedDataDir == null)
cachedDataDir = await getAppDataDir();
return cachedDataDir;
}
class UpdateFailure extends Error {
UpdateFailure(this._message);
String _message;
String toString() => _message;
}
class UpdateTask {
UpdateTask();
Future run() async {
try {
await _runImpl();
} on UpdateFailure catch (e) {
print('Update failed: $e');
} catch (e, stackTrace) {
print('Update failed: $e');
print('Stack: $stackTrace');
} finally {
_updateService.ptr.notifyUpdateCheckComplete();
}
}
Future _runImpl() async {
_dataDir = await getDataDir();
await _readLocalManifest();
yaml.YamlMap remoteManifest = await _fetchManifest();
if (!_shouldUpdate(remoteManifest)) {
print('Update skipped. No new version.');
return;
}
await _fetchBundle();
await _validateBundle();
await _replaceBundle();
print('Update success.');
}
Map _currentManifest;
String _dataDir;
String _tempPath;
Future _readLocalManifest() async {
String bundlePath = path.join(_dataDir, kBundleFile);
Bundle bundle = await Bundle.readHeader(bundlePath);
_currentManifest = bundle.manifest;
}
Future<yaml.YamlMap> _fetchManifest() async {
String manifestUrl = _currentManifest['update-url'] + '/' + kManifestFile;
String manifestData = (await http.get(manifestUrl)).body;
return yaml.loadYaml(manifestData, sourceUrl: manifestUrl);
}
bool _shouldUpdate(yaml.YamlMap remoteManifest) {
Version currentVersion = new Version(_currentManifest['version']);
Version remoteVersion = new Version(remoteManifest['version']);
return (currentVersion < remoteVersion);
}
Future _fetchBundle() async {
// TODO(mpcomplete): Use the cache dir. We need an equivalent of mkstemp().
_tempPath = path.join(_dataDir, 'tmp.skyx');
String bundleUrl = _currentManifest['update-url'] + '/' + kBundleFile;
UrlResponse response = await fetchUrl(bundleUrl);
int result = await PipeToFile.copyToFile(response.body, _tempPath);
if (result != MojoResult.kOk)
throw new UpdateFailure('Failure fetching new package: ${response.statusLine}');
}
Future _validateBundle() async {
Bundle bundle = await Bundle.readHeader(_tempPath);
if (bundle == null)
throw new UpdateFailure('Remote package not a valid FLX file.');
if (bundle.manifest['key'] != _currentManifest['key'])
throw new UpdateFailure('Remote package key does not match.');
if (!await bundle.verifyContent())
throw new UpdateFailure('Invalid package signature or hash. This package has been tampered with.');
}
Future _replaceBundle() async {
String bundlePath = path.join(_dataDir, kBundleFile);
await new File(_tempPath).rename(bundlePath);
}
}
void main() {
UpdateTask task = new UpdateTask();
task.run();
}
// Copyright 2015 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 'dart:io';
import 'dart:typed_data';
import 'package:mojo/core.dart';
// Helper class to drain the contents of a mojo data pipe to a file.
class PipeToFile {
MojoDataPipeConsumer _consumer;
MojoEventSubscription _events;
IOSink _outputStream;
PipeToFile(this._consumer, String outputPath) {
_events = new MojoEventSubscription(_consumer.handle);
_outputStream = new File(outputPath).openWrite();
}
Future<int> _doRead() async {
ByteData thisRead = _consumer.beginRead();
if (thisRead == null) {
throw 'Data pipe beginRead failed: ${_consumer.status}';
}
// TODO(mpcomplete): Should I worry about the _eventStream listen callback
// being invoked again before this completes?
await _outputStream.add(thisRead.buffer.asUint8List());
return _consumer.endRead(thisRead.lengthInBytes);
}
Future<int> drain() {
Completer<int> completer = new Completer();
_events.subscribe((int signal) {
(() async {
if (MojoHandleSignals.isReadable(signal)) {
int result = await _doRead();
if (result != MojoResult.kOk) {
_events.close();
_events = null;
_outputStream.close();
completer.complete(result);
} else {
_events.enableReadEvents();
}
} else if (MojoHandleSignals.isPeerClosed(signal)) {
_events.close();
_events = null;
_outputStream.close();
completer.complete(MojoResult.kOk);
} else {
throw 'Unexpected handle event: ${MojoHandleSignals.string(signal)}';
}
})();
});
return completer.future;
}
static Future<int> copyToFile(MojoDataPipeConsumer consumer, String outputPath) {
PipeToFile drainer = new PipeToFile(consumer, outputPath);
return drainer.drain();
}
}
// Copyright 2015 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:math';
// This class represents a dot-separated version string. Used for comparing
// versions.
// Usage: assert(new Version('1.1.0') < new Version('1.2.1'));
class Version {
Version(String versionStr) :
_parts = versionStr.split('.').map((String val) => int.parse(val)).toList();
List<int> _parts;
bool operator<(Version other) => _compare(other) < 0;
bool operator==(dynamic other) => other is Version && _compare(other) == 0;
bool operator>(Version other) => _compare(other) > 0;
int _compare(Version other) {
int length = min(_parts.length, other._parts.length);
for (int i = 0; i < length; ++i) {
if (_parts[i] < other._parts[i])
return -1;
if (_parts[i] > other._parts[i])
return 1;
}
return _parts.length - other._parts.length; // results in 1.0 < 1.0.0
}
int get hashCode => _parts.fold(373, (int acc, int part) => 37*acc + part);
}
name: updater
author: Flutter Authors <flutter-dev@googlegroups.com>
description: An autoupdater for Flutter
homepage: http://flutter.io
dependencies:
path: ^1.3.0
yaml: ^2.1.3
# TODO(abarth): Updater should not depend on flutter
flutter:
path: ../flutter
flx:
path: ../flx
environment:
sdk: '>=1.12.0 <2.0.0'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment