diff --git a/bin/kradle.dart b/bin/kradle.dart index 263efd6..961999a 100644 --- a/bin/kradle.dart +++ b/bin/kradle.dart @@ -64,8 +64,8 @@ Future interactiveMode() async { final prompt = Select(prompt: "choose task", options: tasks).interact(); final selection = tasks[prompt]; if (selection == addLibrary) { - final name = interact.Input(prompt: "library name").interact(); - await runTaskWithSpinner(TaskName.add, {TaskOption.name: name}); + final lib = interact.Input(prompt: "library name").interact(); + await runTaskWithSpinner(TaskName.add, {TaskOption.lib: lib}); } else if (selection == getFlutter) { final version = askForFlutterVersion(); final overwrite = askConfirmation("overwrite existing distribution?"); @@ -106,7 +106,7 @@ Future interactiveMode() async { final flutterVersion = askForFlutterVersion(); await runTaskWithSpinner(TaskName.init, { TaskOption.flutter: flutterVersion, - TaskOption.klutter: gradleVersion, + TaskOption.bom: gradleVersion, }); } else if (selection == quit) { return; diff --git a/lib/src/cli/task_build.dart b/lib/src/cli/task_build.dart index 6e842bb..01de8b7 100644 --- a/lib/src/cli/task_build.dart +++ b/lib/src/cli/task_build.dart @@ -51,7 +51,7 @@ class BuildProject extends Task { Context context, Map options) async { final workingDirectory = Directory(findPathToRoot(context, options)); // ignore: avoid_print - print("building platform module"); + print("building platform module..."); _executor ..workingDirectory = workingDirectory ..arguments = ["clean", "build", "-p", "platform"] diff --git a/lib/src/cli/task_project_init.dart b/lib/src/cli/task_project_init.dart index e5ac015..14ca41c 100644 --- a/lib/src/cli/task_project_init.dart +++ b/lib/src/cli/task_project_init.dart @@ -34,6 +34,9 @@ import "../producer/project.dart"; import "cli.dart"; import "context.dart"; +const _resourceZipUrl = + "https://github.com/buijs-dev/klutter-dart/raw/develop/resources.zip"; + /// Task to prepare a flutter project for using klutter plugins. /// /// {@category consumer} @@ -89,7 +92,9 @@ void _consumerInit(String pathToRoot) { Future _producerInit( String pathToRoot, String bom, VerifiedFlutterVersion flutter) async { + final resources = await _downloadResourcesZipOrThrow(); final producer = _Producer( + resourcesDirectory: resources, pathToRoot: pathToRoot, bomVersion: bom, flutterVersion: flutter.version.prettyPrint); @@ -103,12 +108,37 @@ Future _producerInit( ..setupExample; } +/// Download [_resourceZipUrl] and return the unzipped directory. +Future _downloadResourcesZipOrThrow() async { + final zip = Directory.systemTemp.resolveFile("resources.zip") + ..maybeDelete + ..createSync(recursive: true); + + final target = Directory.systemTemp.resolveFolder("resources_unpacked") + ..maybeDelete + ..createSync(recursive: true); + + await download(_resourceZipUrl, zip); + if (zip.existsSync()) { + await unzip(zip, target); + zip.deleteSync(); + } + + if (!target.existsSync()) { + throw const KlutterException("Failed to download resources"); + } + + return target; +} + class _Producer { _Producer( - {required this.bomVersion, + {required this.resourcesDirectory, + required this.bomVersion, required this.flutterVersion, required this.pathToRoot}); + final Directory resourcesDirectory; final String bomVersion; final String flutterVersion; final String pathToRoot; @@ -201,7 +231,7 @@ extension on _Producer { } Future get addGradle async { - final gradle = Gradle(pathToRoot); + final gradle = Gradle(pathToRoot, resourcesDirectory); await Future.wait([ gradle.copyToRoot, gradle.copyToAndroid, @@ -209,6 +239,6 @@ extension on _Producer { } Future get addKradle async { - await Future.wait([Kradle(pathToRoot).copyToRoot]); + await Future.wait([Kradle(pathToRoot, resourcesDirectory).copyToRoot]); } } diff --git a/lib/src/producer/gradle.dart b/lib/src/producer/gradle.dart index 40c6806..d0b3f4c 100644 --- a/lib/src/producer/gradle.dart +++ b/lib/src/producer/gradle.dart @@ -36,12 +36,39 @@ import "resource.dart"; /// {@category gradle} class Gradle { /// Create a Gradle instance based of the Flutter project root folder. - Gradle(this.pathToRoot); + Gradle(this.pathToRoot, this.resourcesDirectory) { + _gradlew = LocalResource( + pathToSource: resourcesDirectory.resolveFile("gradlew").absolutePath, + filename: "gradlew", + targetRelativeToRoot: ""); + _gradlewBat = LocalResource( + pathToSource: + resourcesDirectory.resolveFile("gradlew.bat").absolutePath, + filename: "gradlew.bat", + targetRelativeToRoot: ""); + _gradlewJar = LocalResource( + pathToSource: + resourcesDirectory.resolveFile("gradle-wrapper.jar").absolutePath, + filename: "gradle-wrapper.jar", + targetRelativeToRoot: "gradle/wrapper".normalize); + _gradlewProperties = LocalResource( + pathToSource: resourcesDirectory + .resolveFile("gradle-wrapper.properties") + .absolutePath, + filename: "gradle-wrapper.properties", + targetRelativeToRoot: "gradle/wrapper".normalize); + _gradleProperties = LocalResource( + pathToSource: + resourcesDirectory.resolveFile("gradle.properties").absolutePath, + filename: "gradle.properties", + targetRelativeToRoot: ""); + } /// The Flutter project root folder. final String pathToRoot; - final bool _isWindows = Platform.isWindows; + /// The directory containing the gradle-wrapper files. + final Directory resourcesDirectory; late final LocalResource _gradlew; late final LocalResource _gradlewBat; @@ -49,65 +76,6 @@ class Gradle { late final LocalResource _gradlewProperties; late final LocalResource _gradleProperties; - late final Future _isInitialized = - Future.wait([_init]).then((_) => true); - - /// Read all resources from the klutter package lib/res folder. - Future get _init async { - await Future.wait([ - _loadGradlew, - _loadGradlewBat, - _loadGradlewJar, - _loadGradlewProperties, - _loadGradleProperties, - ]); - } - - Future get _loadGradlew async { - _gradlew = await loadResource( - uri: "package:klutter/res/gradlew".toUri, - targetRelativeToRoot: "", - filename: "gradlew", - isWindows: _isWindows, - ); - } - - Future get _loadGradlewBat async { - _gradlewBat = await loadResource( - uri: "package:klutter/res/gradlew.bat".toUri, - targetRelativeToRoot: "", - filename: "gradlew.bat", - isWindows: _isWindows, - ); - } - - Future get _loadGradlewJar async { - _gradlewJar = await loadResource( - uri: "package:klutter/res/gradle-wrapper.jar".toUri, - targetRelativeToRoot: "gradle/wrapper".normalize, - filename: "gradle-wrapper.jar", - isWindows: _isWindows, - ); - } - - Future get _loadGradlewProperties async { - _gradlewProperties = await loadResource( - uri: "package:klutter/res/gradle-wrapper.properties".toUri, - targetRelativeToRoot: "gradle/wrapper".normalize, - filename: "gradle-wrapper.properties", - isWindows: _isWindows, - ); - } - - Future get _loadGradleProperties async { - _gradleProperties = await loadResource( - uri: "package:klutter/res/gradle.properties".toUri, - targetRelativeToRoot: "", - filename: "gradle.properties", - isWindows: _isWindows, - ); - } - /// Copy Gradle files to the project root folder. /// /// Copies the following files: @@ -117,13 +85,12 @@ class Gradle { /// - gradle/wrapper/gradle-wrapper.jar /// - gradle/wrapper/gradle-wrapper.properties Future get copyToRoot async { - await _isInitialized; pathToRoot.verifyExists.rootFolder.copyFiles([ - _gradlewBat, _gradlew, - _gradleProperties, + _gradlewBat, _gradlewJar, - _gradlewProperties, + _gradleProperties, + _gradlewProperties ]); } @@ -136,7 +103,6 @@ class Gradle { /// - gradle/wrapper/gradle-wrapper.jar /// - gradle/wrapper/gradle-wrapper.properties Future get copyToAndroid async { - await _isInitialized; pathToRoot.verifyExists.androidFolder.copyFiles([ _gradlewBat, _gradlew, @@ -148,8 +114,6 @@ class Gradle { } extension on String { - Uri get toUri => Uri.parse(this); - Directory get rootFolder => Directory(this); Directory get androidFolder => diff --git a/lib/src/producer/kradle.dart b/lib/src/producer/kradle.dart index cddc586..b4f924a 100644 --- a/lib/src/producer/kradle.dart +++ b/lib/src/producer/kradle.dart @@ -35,56 +35,34 @@ import "resource.dart"; /// {@category producer} class Kradle { /// Create a Kradle instance based of the Flutter project root folder. - Kradle(this.pathToRoot); + Kradle(this.pathToRoot, this.resourcesDirectory) { + _kradleEnv = LocalResource( + pathToSource: resourcesDirectory.resolveFile("kradle.env").absolutePath, + filename: "kradle.env", + targetRelativeToRoot: ""); + _kradleYaml = LocalResource( + pathToSource: + resourcesDirectory.resolveFile("kradle.yaml").absolutePath, + filename: "kradle.yaml", + targetRelativeToRoot: ""); + } /// The Flutter project root folder. final String pathToRoot; - final bool _isWindows = Platform.isWindows; + /// The directory containing the kradle files. + final Directory resourcesDirectory; late final LocalResource _kradleEnv; late final LocalResource _kradleYaml; - late final Future _isInitialized = - Future.wait([_init]).then((_) => true); - - /// Read all resources from the klutter package lib/res folder. - Future get _init async { - await Future.wait([ - _loadKradleEnv, - _loadKradleYaml, - ]); - } - - Future get _loadKradleEnv async { - _kradleEnv = await loadResource( - uri: "package:klutter/res/kradle.env".toUri, - targetRelativeToRoot: "".normalize, - filename: "kradle.env", - isWindows: _isWindows, - ); - } - - Future get _loadKradleYaml async { - _kradleYaml = await loadResource( - uri: "package:klutter/res/kradle.yaml".toUri, - targetRelativeToRoot: "".normalize, - filename: "kradle.yaml", - isWindows: _isWindows, - ); - } - - /// Copy Kradlew files to the project root folder. + /// Copy Kradle files to the project root folder. /// /// Copies the following files: /// - kradle.yaml - /// - kradlew - /// - kradlew.bat /// - kradle.env - /// - kradle/kradle-wrapper.jar Future get copyToRoot async { - await _isInitialized; pathToRoot.verifyExists.rootFolder.copyFiles([ _kradleYaml, _kradleEnv, @@ -93,7 +71,5 @@ class Kradle { } extension on String { - Uri get toUri => Uri.parse(this); - Directory get rootFolder => Directory(this); } diff --git a/lib/src/producer/resource.dart b/lib/src/producer/resource.dart index 576dc94..a54a4e0 100644 --- a/lib/src/producer/resource.dart +++ b/lib/src/producer/resource.dart @@ -19,7 +19,6 @@ // SOFTWARE. import "dart:io"; -import "dart:isolate"; import "../common/utilities.dart"; @@ -58,20 +57,3 @@ class LocalResource { /// Path to the source File. final String pathToSource; } - -/// Load resource files from lib/res folder. -Future loadResource({ - required Uri uri, - required String filename, - required String targetRelativeToRoot, - required bool isWindows, -}) => - Isolate.resolvePackageUri(uri).then((pathToSource) { - return LocalResource( - pathToSource: isWindows - ? pathToSource!.path.replaceFirst("/", "") - : pathToSource!.path, - filename: filename, - targetRelativeToRoot: targetRelativeToRoot, - ); - }); diff --git a/test/src/producer/gradle_test.dart b/test/src/producer/gradle_test.dart index 214ac16..2fa3daa 100644 --- a/test/src/producer/gradle_test.dart +++ b/test/src/producer/gradle_test.dart @@ -29,7 +29,7 @@ void main() { test("Verify exception is thrown if root does not exist", () { expect( - () => Gradle("fake").copyToRoot, + () => Gradle("fake", Directory.systemTemp).copyToRoot, throwsA(predicate((e) => e is KlutterException && e.cause.startsWith("Path does not exist:") && @@ -39,8 +39,16 @@ void main() { test("Verify Gradle files are copied to the root folder", () async { final root = Directory("${Directory.systemTemp.path}${s}gradle10") ..createSync(recursive: true); + final resources = + Directory("${Directory.systemTemp.path}${s}gradle10resources") + ..createSync(recursive: true); + resources.resolveFile("gradle.properties").createSync(); + resources.resolveFile("gradle-wrapper.jar").createSync(); + resources.resolveFile("gradle-wrapper.properties").createSync(); + resources.resolveFile("gradlew").createSync(); + resources.resolveFile("gradlew.bat").createSync(); - await Gradle(root.normalizeToDirectory.absolutePath).copyToRoot; + await Gradle(root.normalizeToDirectory.absolutePath, resources).copyToRoot; final properties = File("${root.path}/gradle.properties").normalizeToFile; final wrapperJar = @@ -50,22 +58,23 @@ void main() { .normalizeToFile; final wrapperSh = File("${root.path}/gradlew").normalizeToFile; final wrapperBat = File("${root.path}/gradlew.bat").normalizeToFile; - expect(properties.existsSync(), true, reason: "gradle.properties should exist"); expect(wrapperJar.existsSync(), true, reason: "gradle-wrapper.jar should exist"); expect(wrapperProperties.existsSync(), true, - reason: "gradle-wrapper.properties should exist"); - expect(wrapperSh.existsSync(), true, reason: "gradlew should exist"); - expect(wrapperBat.existsSync(), true, reason: "gradlew.bat should exist"); + reason: "${wrapperProperties.absolutePath} should exist"); + expect(wrapperSh.existsSync(), true, + reason: "${wrapperSh.absolutePath} should exist"); + expect(wrapperBat.existsSync(), true, + reason: "${wrapperBat.absolutePath} should exist"); root.deleteSync(recursive: true); }); test("Verify exception is thrown if root does not exist", () { expect( - () => Gradle("fake").copyToAndroid, + () => Gradle("fake", Directory.systemTemp).copyToAndroid, throwsA(predicate((e) => e is KlutterException && e.cause.startsWith("Path does not exist:") && @@ -77,7 +86,7 @@ void main() { ..createSync(recursive: true); expect( - () => Gradle(root.path).copyToAndroid, + () => Gradle(root.path, Directory.systemTemp).copyToAndroid, throwsA(predicate((e) => e is KlutterException && e.cause.startsWith("Path does not exist:")))); @@ -91,8 +100,15 @@ void main() { final android = Directory("${root.path}/android".normalize) ..createSync(recursive: true); - - await Gradle(root.path).copyToAndroid; + final resources = + Directory("${Directory.systemTemp.path}${s}gradle30resources") + ..createSync(recursive: true); + resources.resolveFile("gradle.properties").createSync(); + resources.resolveFile("gradle-wrapper.jar").createSync(); + resources.resolveFile("gradle-wrapper.properties").createSync(); + resources.resolveFile("gradlew").createSync(); + resources.resolveFile("gradlew.bat").createSync(); + await Gradle(root.path, resources).copyToAndroid; final properties = File("${android.path}/gradle.properties").normalizeToFile; diff --git a/test/src/producer/kradle_test.dart b/test/src/producer/kradle_test.dart index 6587e2a..b63fb15 100644 --- a/test/src/producer/kradle_test.dart +++ b/test/src/producer/kradle_test.dart @@ -29,7 +29,7 @@ void main() { test("Verify exception is thrown if root does not exist", () { expect( - () => Kradle("fake").copyToRoot, + () => Kradle("fake", Directory.systemTemp).copyToRoot, throwsA(predicate((e) => e is KlutterException && e.cause.startsWith("Path does not exist:") && @@ -39,15 +39,16 @@ void main() { test("Verify Kradle files are copied to the root folder", () async { final root = Directory("${Directory.systemTemp.path}${s}kradle10") ..createSync(recursive: true); - - await Kradle(root.normalizeToDirectory.absolutePath).copyToRoot; - + final resources = + Directory("${Directory.systemTemp.path}${s}kradle10resources") + ..createSync(recursive: true); + resources.resolveFile("kradle.env").createSync(); + resources.resolveFile("kradle.yaml").createSync(); + await Kradle(root.normalizeToDirectory.absolutePath, resources).copyToRoot; final env = File("${root.path}/kradle.env").normalizeToFile; final yaml = File("${root.path}/kradle.yaml").normalizeToFile; - expect(env.existsSync(), true, reason: "kradle.env should exist"); expect(yaml.existsSync(), true, reason: "kradle.yaml should exist"); - root.deleteSync(recursive: true); }); } diff --git a/test/src/producer/resource_test.dart b/test/src/producer/resource_test.dart deleted file mode 100644 index 89b5162..0000000 --- a/test/src/producer/resource_test.dart +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2021 - 2023 Buijs Software -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import "package:klutter/src/producer/resource.dart"; -import "package:test/test.dart"; - -void main() { - test( - "When Platform is windows then first '/' character of a resource path is removed", - () async { - final resource = await loadResource( - uri: Uri.parse("package:klutter/res/gradlew.bat"), - targetRelativeToRoot: "", - filename: "gradlew.bat", - isWindows: true, - ); - - expect(resource.pathToSource.startsWith("/"), false); - }); - - test( - "When Platform is NOT windows then first '/' character of a resource path is NOT removed", - () async { - final resource = await loadResource( - uri: Uri.parse("package:klutter/res/gradlew.bat"), - targetRelativeToRoot: "", - filename: "gradlew.bat", - isWindows: false, - ); - - expect(resource.pathToSource.startsWith("/"), true); - }); -}