diff --git a/sqlite3/lib/src/hook/compile/description.dart b/sqlite3/lib/src/hook/compile/description.dart index 21b66f82..045acab5 100644 --- a/sqlite3/lib/src/hook/compile/description.dart +++ b/sqlite3/lib/src/hook/compile/description.dart @@ -17,6 +17,7 @@ import '../utils.dart'; sealed class SqliteBinary { static SqliteBinary forBuild(BuildInput input) { final userDefines = input.userDefines; + final userDefinesBase = _userDefinesBase(input); PrecompiledFromGithubAssets fromGitHub(LibraryType type) { final pattern = @@ -26,6 +27,20 @@ sealed class SqliteBinary { return PrecompiledFromGithubAssets(type, urlPattern: pattern); } + List resolvedPaths(String key) { + final List entries = + (userDefines[key] as List?)?.cast() ?? const []; + if (userDefinesBase == null) return entries; + + return [ + for (final entry in entries) + if (p.isAbsolute(entry)) + entry + else + userDefinesBase.resolve(entry).toFilePath(), + ]; + } + switch (userDefines['source']) { case null: case 'sqlite3': @@ -58,13 +73,12 @@ sealed class SqliteBinary { userDefines, input.config.code.targetOS, ), - additionalIncludes: - (userDefines['additional_includes'] as List?)?.cast() ?? const [], + additionalIncludes: resolvedPaths('additional_includes'), additionalFlags: (userDefines['additional_flags'] as List?)?.cast() ?? const [], - additionalLibraryDirectories: - (userDefines['additional_lib_directories'] as List?)?.cast() ?? - const [], + additionalLibraryDirectories: resolvedPaths( + 'additional_lib_directories', + ), additionalLibraries: (userDefines['additional_libraries'] as List?)?.cast() ?? const [], @@ -78,6 +92,22 @@ sealed class SqliteBinary { ); } } + + /// The `pubspec.yaml` the user-defines were read from. + /// + /// Relative paths are resolved against this file, matching what + /// [HookInputUserDefines.path] does for `path`. That method only resolves a + /// single string, so list-valued options need the base itself. + static Uri? _userDefinesBase(BuildInput input) { + final userDefines = input.json['user_defines']; + if (userDefines is! Map) return null; + + final source = userDefines['workspace_pubspec']; + if (source is! Map) return null; + + final basePath = source['base_path']; + return basePath is String ? Uri.file(basePath) : null; + } } /// A [SqliteBinary] not built or downloaded by the hook. diff --git a/sqlite3/test/hook/description_test.dart b/sqlite3/test/hook/description_test.dart index f8e090b4..dcef884e 100644 --- a/sqlite3/test/hook/description_test.dart +++ b/sqlite3/test/hook/description_test.dart @@ -3,6 +3,7 @@ library; import 'package:code_assets/code_assets.dart'; import 'package:hooks/hooks.dart'; +import 'package:path/path.dart' as p; import 'package:sqlite3/src/hook/asset_hashes.dart'; import 'package:sqlite3/src/hook/compile/description.dart'; import 'package:test/test.dart'; @@ -39,6 +40,45 @@ void main() { ); }); + test('resolves relative paths against the pubspec', () async { + await testBuildHook( + userDefines: PackageUserDefines( + workspacePubspec: PackageUserDefinesSource( + defines: { + 'source': 'source', + 'path': 'native/sqlite3.c', + 'additional_includes': ['native/include', '/absolute/include'], + 'additional_lib_directories': ['native/lib'], + }, + basePath: Uri.file(p.join(d.sandbox, 'pubspec.yaml')), + ), + ), + mainMethod: (args) { + return build(args, (input, outputs) async { + final config = SqliteBinary.forBuild(input) as CompileSqlite; + + expect(config.sourceFile, p.join(d.sandbox, 'native', 'sqlite3.c')); + expect(config.additionalIncludes, [ + p.join(d.sandbox, 'native', 'include'), + '/absolute/include', + ]); + expect(config.additionalLibraryDirectories, [ + p.join(d.sandbox, 'native', 'lib'), + ]); + }); + }, + check: (_, _) {}, + extensions: [ + CodeAssetExtension( + targetArchitecture: Architecture.arm64, + targetOS: OS.macOS, + linkModePreference: LinkModePreference.dynamic, + macOS: MacOSCodeConfig(targetVersion: 13), + ), + ], + ); + }); + test('can use custom download url', () async { await testBuildHook( mainMethod: (args) {