Skip to content

Commit 4adfbc1

Browse files
committed
Share dowload script
1 parent 40a24cc commit 4adfbc1

File tree

8 files changed

+201
-182
lines changed

8 files changed

+201
-182
lines changed

packages/powersync/bin/setup_web.dart

Lines changed: 3 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -1,176 +1,4 @@
1-
import 'dart:convert';
2-
import 'dart:io';
3-
import 'package:collection/collection.dart';
4-
import 'package:pub_semver/pub_semver.dart';
5-
import 'package:pubspec_parse/pubspec_parse.dart';
6-
import 'package:args/args.dart';
1+
// ignore: implementation_imports
2+
import 'package:powersync_core/src/setup_web.dart';
73

8-
void main(List<String> arguments) async {
9-
var parser = ArgParser();
10-
// Add a flag to enable/disable the download of worker (defaults to true)
11-
// Pass the --no-worker argument to disable the download of the worker
12-
// dart run powersync:setup_web --no-worker
13-
parser.addFlag('worker', defaultsTo: true);
14-
// Add a option to specify the output directory (defaults to web)
15-
// Pass the --output-dir argument to specify the output directory
16-
// dart run powersync:setup_web --output-dir assets
17-
parser.addOption('output-dir', abbr: 'o', defaultsTo: 'web');
18-
var results = parser.parse(arguments);
19-
bool downloadWorker = results.flag('worker');
20-
String outputDir = results.option('output-dir')!;
21-
22-
final root = Directory.current.uri;
23-
print('Project root: ${root.toFilePath()}');
24-
25-
final wasmPath = '${root.toFilePath()}$outputDir/sqlite3.wasm';
26-
27-
final workerPath = '${root.toFilePath()}$outputDir/powersync_db.worker.js';
28-
final syncWorkerPath =
29-
'${root.toFilePath()}$outputDir/powersync_sync.worker.js';
30-
31-
final packageConfigFile = File.fromUri(
32-
root.resolve('.dart_tool/package_config.json'),
33-
);
34-
dynamic packageConfig;
35-
try {
36-
packageConfig = json.decode(await packageConfigFile.readAsString());
37-
} on FileSystemException {
38-
print('Missing .dart_tool/package_config.json');
39-
print('Run `flutter pub get` first.');
40-
exit(1);
41-
} on FormatException {
42-
print('Invalid .dart_tool/package_config.json');
43-
print('Run `flutter pub get` first.');
44-
exit(1);
45-
}
46-
47-
try {
48-
final httpClient = HttpClient();
49-
50-
final powersyncPackageName = 'powersync';
51-
52-
if (downloadWorker) {
53-
final powersyncPkg =
54-
getPackageFromConfig(packageConfig, powersyncPackageName);
55-
56-
final powersyncVersion = getPubspecVersion(
57-
packageConfigFile, powersyncPkg, powersyncPackageName);
58-
59-
final workerUrl =
60-
'https://github.com/powersync-ja/powersync.dart/releases/download/powersync-v$powersyncVersion/powersync_db.worker.js';
61-
62-
final syncWorkerUrl =
63-
'https://github.com/powersync-ja/powersync.dart/releases/download/powersync-v$powersyncVersion/powersync_sync.worker.js';
64-
65-
await downloadFile(httpClient, workerUrl, workerPath);
66-
await downloadFile(httpClient, syncWorkerUrl, syncWorkerPath);
67-
}
68-
69-
final sqlitePackageName = 'sqlite3';
70-
71-
final sqlite3Pkg = getPackageFromConfig(packageConfig, sqlitePackageName);
72-
73-
String sqlite3Version =
74-
"v${getPubspecVersion(packageConfigFile, sqlite3Pkg, sqlitePackageName)}";
75-
76-
List<String> tags = await getLatestTagsFromRelease(httpClient);
77-
String? matchTag = tags.firstWhereOrNull((element) =>
78-
element.contains(sqlite3Version) && coreVersionIsInRange(element));
79-
if (matchTag != null) {
80-
sqlite3Version = matchTag;
81-
} else {
82-
throw Exception(
83-
"""No compatible powersync core version found for sqlite3 version $sqlite3Version
84-
Latest supported sqlite3 versions: ${tags.take(3).map((tag) => tag.split('-')[0]).join(', ')}.
85-
You can view the full list of releases at https://github.com/powersync-ja/sqlite3.dart/releases""");
86-
}
87-
88-
final sqliteUrl =
89-
'https://github.com/powersync-ja/sqlite3.dart/releases/download/$sqlite3Version/sqlite3.wasm';
90-
91-
await downloadFile(httpClient, sqliteUrl, wasmPath);
92-
} catch (e) {
93-
print(e);
94-
exit(1);
95-
}
96-
}
97-
98-
bool coreVersionIsInRange(String tag) {
99-
// Sets the range of powersync core version that is compatible with the sqlite3 version
100-
// We're a little more selective in the versions chosen here than the range
101-
// we're compatible with.
102-
VersionConstraint constraint = VersionConstraint.parse('>=0.3.0 <0.4.0');
103-
List<String> parts = tag.split('-');
104-
String powersyncPart = parts[1];
105-
106-
List<String> versionParts = powersyncPart.split('.');
107-
String extractedVersion =
108-
versionParts.sublist(versionParts.length - 3).join('.');
109-
final coreVersion = Version.parse(extractedVersion);
110-
if (constraint.allows(coreVersion)) {
111-
return true;
112-
}
113-
return false;
114-
}
115-
116-
dynamic getPackageFromConfig(dynamic packageConfig, String packageName) {
117-
final pkg = (packageConfig['packages'] ?? []).firstWhere(
118-
(e) => e['name'] == packageName,
119-
orElse: () => null,
120-
);
121-
if (pkg == null) {
122-
throw Exception('Dependency on package:$packageName is required');
123-
}
124-
return pkg;
125-
}
126-
127-
String getPubspecVersion(
128-
File packageConfigFile, dynamic package, String packageName) {
129-
final rootUri = packageConfigFile.uri.resolve(package['rootUri'] ?? '');
130-
print('Using package:$packageName from ${rootUri.toFilePath()}');
131-
132-
String pubspec =
133-
File('${rootUri.toFilePath()}/pubspec.yaml').readAsStringSync();
134-
Pubspec parsed = Pubspec.parse(pubspec);
135-
final version = parsed.version?.toString();
136-
if (version == null) {
137-
throw Exception(
138-
"${capitalize(packageName)} version not found. Run `flutter pub get` first.");
139-
}
140-
return version;
141-
}
142-
143-
String capitalize(String s) => s[0].toUpperCase() + s.substring(1);
144-
145-
Future<List<String>> getLatestTagsFromRelease(HttpClient httpClient) async {
146-
var request = await httpClient.getUrl(Uri.parse(
147-
"https://api.github.com/repos/powersync-ja/sqlite3.dart/releases"));
148-
var response = await request.close();
149-
if (response.statusCode == HttpStatus.ok) {
150-
var res = await response.transform(utf8.decoder).join();
151-
List<dynamic> jsonObj = json.decode(res);
152-
List<String> tags = [];
153-
for (dynamic obj in jsonObj) {
154-
final tagName = obj['tag_name'] as String;
155-
if (!tagName.contains("-powersync")) continue;
156-
tags.add(tagName);
157-
}
158-
return tags;
159-
} else {
160-
throw Exception("Failed to fetch GitHub releases and tags");
161-
}
162-
}
163-
164-
Future<void> downloadFile(
165-
HttpClient httpClient, String url, String savePath) async {
166-
print('Downloading: $url');
167-
var request = await httpClient.getUrl(Uri.parse(url));
168-
var response = await request.close();
169-
if (response.statusCode == HttpStatus.ok) {
170-
var file = File(savePath);
171-
await response.pipe(file.openWrite());
172-
} else {
173-
throw Exception(
174-
'Failed to download file: ${response.statusCode} ${response.reasonPhrase}');
175-
}
176-
}
4+
void main(List<String> args) => downloadWebAssets(args);

packages/powersync/pubspec.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ dependencies:
1515
powersync_core: ^1.1.1
1616
powersync_flutter_libs: ^0.4.4
1717
collection: ^1.17.0
18-
pubspec_parse: ^1.3.0
19-
args: ^2.5.0
20-
pub_semver: ^2.1.4
2118

2219
dev_dependencies:
2320
lints: ^5.1.0

packages/powersync_core/lib/src/open_factory.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
// To conditionally export an implementation for either web or "native" platforms
33
// The sqlite library uses dart:ffi which is not supported on web
44

5-
export 'open_factory/abstract_powersync_open_factory.dart'
6-
show powerSyncDefaultSqliteOptions;
7-
85
export 'open_factory/open_factory_stub.dart'
96
// ignore: uri_does_not_exist
107
if (dart.library.io) 'open_factory/native/native_open_factory.dart'
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import 'dart:convert';
2+
import 'dart:io';
3+
import 'package:collection/collection.dart';
4+
import 'package:pub_semver/pub_semver.dart';
5+
import 'package:pubspec_parse/pubspec_parse.dart';
6+
import 'package:args/args.dart';
7+
8+
Future<void> downloadWebAssets(List<String> arguments,
9+
{bool encryption = false}) async {
10+
var parser = ArgParser();
11+
// Add a flag to enable/disable the download of worker (defaults to true)
12+
// Pass the --no-worker argument to disable the download of the worker
13+
// dart run powersync:setup_web --no-worker
14+
parser.addFlag('worker', defaultsTo: true);
15+
// Add a option to specify the output directory (defaults to web)
16+
// Pass the --output-dir argument to specify the output directory
17+
// dart run powersync:setup_web --output-dir assets
18+
parser.addOption('output-dir', abbr: 'o', defaultsTo: 'web');
19+
var results = parser.parse(arguments);
20+
bool downloadWorker = results.flag('worker');
21+
String outputDir = results.option('output-dir')!;
22+
23+
final root = Directory.current.uri;
24+
print('Project root: ${root.toFilePath()}');
25+
26+
final wasmPath = '${root.toFilePath()}$outputDir/sqlite3.wasm';
27+
28+
final workerPath = '${root.toFilePath()}$outputDir/powersync_db.worker.js';
29+
final syncWorkerPath =
30+
'${root.toFilePath()}$outputDir/powersync_sync.worker.js';
31+
32+
final packageConfigFile = File.fromUri(
33+
root.resolve('.dart_tool/package_config.json'),
34+
);
35+
dynamic packageConfig;
36+
try {
37+
packageConfig = json.decode(await packageConfigFile.readAsString());
38+
} on FileSystemException {
39+
print('Missing .dart_tool/package_config.json');
40+
print('Run `flutter pub get` first.');
41+
exit(1);
42+
} on FormatException {
43+
print('Invalid .dart_tool/package_config.json');
44+
print('Run `flutter pub get` first.');
45+
exit(1);
46+
}
47+
48+
try {
49+
final httpClient = HttpClient();
50+
51+
final powersyncPackageName = 'powersync';
52+
53+
if (downloadWorker) {
54+
final powersyncPkg =
55+
getPackageFromConfig(packageConfig, powersyncPackageName);
56+
57+
final powersyncVersion = getPubspecVersion(
58+
packageConfigFile, powersyncPkg, powersyncPackageName);
59+
60+
final workerUrl =
61+
'https://github.com/powersync-ja/powersync.dart/releases/download/powersync-v$powersyncVersion/powersync_db.worker.js';
62+
63+
final syncWorkerUrl =
64+
'https://github.com/powersync-ja/powersync.dart/releases/download/powersync-v$powersyncVersion/powersync_sync.worker.js';
65+
66+
await downloadFile(httpClient, workerUrl, workerPath);
67+
await downloadFile(httpClient, syncWorkerUrl, syncWorkerPath);
68+
}
69+
70+
final sqlitePackageName = 'sqlite3';
71+
72+
final sqlite3Pkg = getPackageFromConfig(packageConfig, sqlitePackageName);
73+
74+
String sqlite3Version =
75+
"v${getPubspecVersion(packageConfigFile, sqlite3Pkg, sqlitePackageName)}";
76+
77+
List<String> tags = await getLatestTagsFromRelease(httpClient);
78+
String? matchTag = tags.firstWhereOrNull((element) =>
79+
element.contains(sqlite3Version) && coreVersionIsInRange(element));
80+
if (matchTag != null) {
81+
sqlite3Version = matchTag;
82+
} else {
83+
throw Exception(
84+
"""No compatible powersync core version found for sqlite3 version $sqlite3Version
85+
Latest supported sqlite3 versions: ${tags.take(3).map((tag) => tag.split('-')[0]).join(', ')}.
86+
You can view the full list of releases at https://github.com/powersync-ja/sqlite3.dart/releases""");
87+
}
88+
89+
final filename = encryption ? 'sqlite3mc.wasm' : 'sqlite3.wasm';
90+
final sqliteUrl =
91+
'https://github.com/powersync-ja/sqlite3.dart/releases/download/$sqlite3Version/$filename';
92+
93+
await downloadFile(httpClient, sqliteUrl, wasmPath);
94+
} catch (e) {
95+
print(e);
96+
exit(1);
97+
}
98+
}
99+
100+
bool coreVersionIsInRange(String tag) {
101+
// Sets the range of powersync core version that is compatible with the sqlite3 version
102+
// We're a little more selective in the versions chosen here than the range
103+
// we're compatible with.
104+
VersionConstraint constraint = VersionConstraint.parse('>=0.3.0 <0.4.0');
105+
List<String> parts = tag.split('-');
106+
String powersyncPart = parts[1];
107+
108+
List<String> versionParts = powersyncPart.split('.');
109+
String extractedVersion =
110+
versionParts.sublist(versionParts.length - 3).join('.');
111+
final coreVersion = Version.parse(extractedVersion);
112+
if (constraint.allows(coreVersion)) {
113+
return true;
114+
}
115+
return false;
116+
}
117+
118+
dynamic getPackageFromConfig(dynamic packageConfig, String packageName) {
119+
final pkg = (packageConfig['packages'] ?? []).firstWhere(
120+
(e) => e['name'] == packageName,
121+
orElse: () => null,
122+
);
123+
if (pkg == null) {
124+
throw Exception('Dependency on package:$packageName is required');
125+
}
126+
return pkg;
127+
}
128+
129+
String getPubspecVersion(
130+
File packageConfigFile, dynamic package, String packageName) {
131+
final rootUri = packageConfigFile.uri.resolve(package['rootUri'] ?? '');
132+
print('Using package:$packageName from ${rootUri.toFilePath()}');
133+
134+
String pubspec =
135+
File('${rootUri.toFilePath()}/pubspec.yaml').readAsStringSync();
136+
Pubspec parsed = Pubspec.parse(pubspec);
137+
final version = parsed.version?.toString();
138+
if (version == null) {
139+
throw Exception(
140+
"${capitalize(packageName)} version not found. Run `flutter pub get` first.");
141+
}
142+
return version;
143+
}
144+
145+
String capitalize(String s) => s[0].toUpperCase() + s.substring(1);
146+
147+
Future<List<String>> getLatestTagsFromRelease(HttpClient httpClient) async {
148+
var request = await httpClient.getUrl(Uri.parse(
149+
"https://api.github.com/repos/powersync-ja/sqlite3.dart/releases"));
150+
var response = await request.close();
151+
if (response.statusCode == HttpStatus.ok) {
152+
var res = await response.transform(utf8.decoder).join();
153+
List<dynamic> jsonObj = json.decode(res);
154+
List<String> tags = [];
155+
for (dynamic obj in jsonObj) {
156+
final tagName = obj['tag_name'] as String;
157+
if (!tagName.contains("-powersync")) continue;
158+
tags.add(tagName);
159+
}
160+
return tags;
161+
} else {
162+
throw Exception("Failed to fetch GitHub releases and tags");
163+
}
164+
}
165+
166+
Future<void> downloadFile(
167+
HttpClient httpClient, String url, String savePath) async {
168+
print('Downloading: $url');
169+
var request = await httpClient.getUrl(Uri.parse(url));
170+
var response = await request.close();
171+
if (response.statusCode == HttpStatus.ok) {
172+
var file = File(savePath);
173+
await response.pipe(file.openWrite());
174+
} else {
175+
throw Exception(
176+
'Failed to download file: ${response.statusCode} ${response.reasonPhrase}');
177+
}
178+
}

packages/powersync_core/pubspec.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ dependencies:
2424
fetch_client: ^1.1.2
2525
web: ^1.0.0
2626

27+
# Only used internally to download WASM / worker files.
28+
args: ^2.6.0
29+
pub_semver: ^2.0.0
30+
pubspec_parse: ^1.3.0
31+
2732
dev_dependencies:
2833
lints: ^5.1.1
2934
test: ^1.25.0

0 commit comments

Comments
 (0)