-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 22eb354
Showing
32 changed files
with
2,814 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# https://dart.dev/guides/libraries/private-files | ||
# Created by `dart pub` | ||
.dart_tool/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## 0.0.1 | ||
|
||
- Initial version. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
BSD 3-Clause License | ||
|
||
Copyright (c) 2024, Serverpod | ||
|
||
Redistribution and use in source and binary forms, with or without | ||
modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this | ||
list of conditions and the following disclaimer. | ||
|
||
2. Redistributions in binary form must reproduce the above copyright notice, | ||
this list of conditions and the following disclaimer in the documentation | ||
and/or other materials provided with the distribution. | ||
|
||
3. Neither the name of the copyright holder nor the names of its | ||
contributors may be used to endorse or promote products derived from | ||
this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
 | ||
|
||
# CLI Tools | ||
|
||
This package contains tools for building great command line interfaces. These tools were developed for the Serverpod CLI but can be used in any Dart project. | ||
|
||
## Contributing to the Project | ||
|
||
We are happy to accept contributions. To contribute, please do the following: | ||
|
||
1. Fork the repository | ||
2. Create a feature branch | ||
3. Commit your changes | ||
4. Push to the branch | ||
5. Create a pull request | ||
6. Discuss and modify the pull request as necessary | ||
7. The pull request will be accepted and merged by the repository owner | ||
|
||
Tests are required to accept any pull requests. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include: package:serverpod_lints/cli.yaml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import 'package:cli_tools/cli_tools.dart'; | ||
|
||
void main() async { | ||
/// Simple example of using the [StdOutLogger] class. | ||
var logger = StdOutLogger(LogLevel.info); | ||
|
||
logger.info('An info message'); | ||
logger.error('An error message'); | ||
logger.debug( | ||
'A debug message that will not be shown because log level is info', | ||
); | ||
await logger.progress( | ||
'A progress message', | ||
() async => Future.delayed( | ||
const Duration(seconds: 3), | ||
() => true, | ||
), | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
library analytics; | ||
|
||
export 'src/analytics/analytics.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
library better_command_runner; | ||
|
||
export 'src/better_command_runner/better_command_runner.dart'; | ||
export 'src/better_command_runner/exit_exception.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
library cli_tools; | ||
|
||
export 'analytics.dart'; | ||
export 'better_command_runner.dart'; | ||
export 'local_storage_manager.dart'; | ||
export 'logger.dart'; | ||
export 'package_version.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
library local_storage_manager; | ||
|
||
export 'src/local_storage_manager/local_storage_manager.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
library logger; | ||
|
||
export 'src/logger/logger.dart'; | ||
export 'src/logger/loggers/std_out_logger.dart'; | ||
export 'src/logger/loggers/void_logger.dart'; | ||
export 'src/logger/helpers/ansi_style.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
library package_version; | ||
|
||
export 'src/package_version/package_version.dart'; | ||
export 'src/package_version/pub_api_client.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import 'dart:convert'; | ||
import 'dart:io'; | ||
|
||
import 'package:ci/ci.dart' as ci; | ||
import 'package:http/http.dart' as http; | ||
|
||
/// Interface for analytics services. | ||
abstract interface class Analytics { | ||
/// Clean up resources. | ||
void cleanUp(); | ||
|
||
/// Track an event. | ||
void track({ | ||
required String event, | ||
}); | ||
} | ||
|
||
/// Analytics service for MixPanel. | ||
class MixPanelAnalytics implements Analytics { | ||
final String _uniqueUserId; | ||
final String _endpoint = 'https://api.mixpanel.com/track'; | ||
final String _projectToken; | ||
final String _version; | ||
|
||
MixPanelAnalytics({ | ||
required String uniqueUserId, | ||
required String projectToken, | ||
required String version, | ||
}) : _uniqueUserId = uniqueUserId, | ||
_projectToken = projectToken, | ||
_version = version; | ||
|
||
@override | ||
void cleanUp() {} | ||
|
||
@override | ||
void track({ | ||
required String event, | ||
}) { | ||
var payload = jsonEncode({ | ||
'event': event, | ||
'properties': { | ||
'distinct_id': _uniqueUserId, | ||
'token': _projectToken, | ||
'platform': _getPlatform(), | ||
'dart_version': Platform.version, | ||
'is_ci': ci.isCI, | ||
'version': _version, | ||
} | ||
}); | ||
|
||
_quietPost(payload); | ||
} | ||
|
||
String _getPlatform() { | ||
if (Platform.isMacOS) { | ||
return 'MacOS'; | ||
} else if (Platform.isWindows) { | ||
return 'Windows'; | ||
} else if (Platform.isLinux) { | ||
return 'Linux'; | ||
} else { | ||
return 'Unknown'; | ||
} | ||
} | ||
|
||
Future<void> _quietPost(String payload) async { | ||
try { | ||
await http.post( | ||
Uri.parse(_endpoint), | ||
body: 'data=$payload', | ||
headers: { | ||
'Accept': 'text/plain', | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
}, | ||
).timeout(const Duration(seconds: 2)); | ||
} catch (e) { | ||
return; | ||
} | ||
} | ||
} |
181 changes: 181 additions & 0 deletions
181
lib/src/better_command_runner/better_command_runner.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import 'package:args/args.dart'; | ||
import 'package:args/command_runner.dart'; | ||
import 'package:cli_tools/src/better_command_runner/exit_exception.dart'; | ||
|
||
/// A function type for executing code before running a command. | ||
typedef OnBeforeRunCommand = Future<void> Function( | ||
BetterCommandRunner runner, | ||
); | ||
|
||
/// A function type for passing log messages. | ||
typedef PassMessage = void Function(String message); | ||
|
||
/// A function type for setting the log level. | ||
/// The [logLevel] is the log level to set. | ||
/// The [commandName] is the name of the command if custom rules for log | ||
/// levels are needed. | ||
typedef SetLogLevel = void Function({ | ||
required CommandRunnerLogLevel parsedLogLevel, | ||
String? commandName, | ||
}); | ||
|
||
/// A function type for tracking events. | ||
typedef OnAnalyticsEvent = void Function(String event); | ||
|
||
/// A custom implementation of [CommandRunner] with additional features. | ||
/// | ||
/// This class extends the [CommandRunner] class from the `args` package and adds | ||
/// additional functionality such as logging, setting log levels, tracking events, | ||
/// and handling analytics. | ||
/// | ||
/// The [BetterCommandRunner] class provides a more enhanced command line interface | ||
/// for running commands and handling command line arguments. | ||
class BetterCommandRunner extends CommandRunner { | ||
final PassMessage? _logError; | ||
final PassMessage? _logInfo; | ||
final SetLogLevel? _setLogLevel; | ||
final OnBeforeRunCommand? _onBeforeRunCommand; | ||
OnAnalyticsEvent? _onAnalyticsEvent; | ||
|
||
final ArgParser _argParser; | ||
|
||
/// Creates a new instance of [BetterCommandRunner]. | ||
/// | ||
/// The [executableName] is the name of the executable for the command line interface. | ||
/// The [description] is a description of the command line interface. | ||
/// The [logError] function is used to pass error log messages. | ||
/// The [logInfo] function is used to pass informational log messages. | ||
/// The [setLogLevel] function is used to set the log level. | ||
/// The [onBeforeRunCommand] function is executed before running a command. | ||
/// The [onAnalyticsEvent] function is used to track events. | ||
/// The [wrapTextColumn] is the column width for wrapping text in the command line interface. | ||
BetterCommandRunner( | ||
super.executableName, | ||
super.description, { | ||
PassMessage? logError, | ||
PassMessage? logInfo, | ||
SetLogLevel? setLogLevel, | ||
OnBeforeRunCommand? onBeforeRunCommand, | ||
OnAnalyticsEvent? onAnalyticsEvent, | ||
int? wrapTextColumn, | ||
}) : _logError = logError, | ||
_logInfo = logInfo, | ||
_onBeforeRunCommand = onBeforeRunCommand, | ||
_setLogLevel = setLogLevel, | ||
_onAnalyticsEvent = onAnalyticsEvent, | ||
_argParser = ArgParser(usageLineLength: wrapTextColumn) { | ||
argParser.addFlag( | ||
BetterCommandRunnerFlags.quiet, | ||
abbr: BetterCommandRunnerFlags.quietAbbr, | ||
defaultsTo: false, | ||
negatable: false, | ||
help: 'Suppress all cli output. Is overridden by ' | ||
' -${BetterCommandRunnerFlags.verboseAbbr}, --${BetterCommandRunnerFlags.verbose}.', | ||
); | ||
|
||
argParser.addFlag( | ||
BetterCommandRunnerFlags.verbose, | ||
abbr: BetterCommandRunnerFlags.verboseAbbr, | ||
defaultsTo: false, | ||
negatable: false, | ||
help: 'Prints additional information useful for development. ' | ||
'Overrides --${BetterCommandRunnerFlags.quietAbbr}, --${BetterCommandRunnerFlags.quiet}.', | ||
); | ||
|
||
if (_onAnalyticsEvent != null) { | ||
argParser.addFlag( | ||
BetterCommandRunnerFlags.analytics, | ||
abbr: BetterCommandRunnerFlags.analyticsAbbr, | ||
defaultsTo: true, | ||
negatable: true, | ||
help: 'Toggles if analytics data is sent. ', | ||
); | ||
} | ||
} | ||
|
||
@override | ||
ArgParser get argParser => _argParser; | ||
|
||
/// Adds a list of commands to the command runner. | ||
void addCommands(List<Command> commands) { | ||
for (var command in commands) { | ||
addCommand(command); | ||
} | ||
} | ||
|
||
/// Checks if analytics is enabled. | ||
bool analyticsEnabled() => _onAnalyticsEvent != null; | ||
|
||
@override | ||
ArgResults parse(Iterable<String> args) { | ||
try { | ||
return super.parse(args); | ||
} on UsageException catch (e) { | ||
_onAnalyticsEvent?.call(BetterCommandRunnerAnalyticsEvents.invalid); | ||
_logError?.call(e.toString()); | ||
throw ExitException(ExitCodeType.commandNotFound); | ||
} | ||
} | ||
|
||
@override | ||
void printUsage() { | ||
_logInfo?.call(usage); | ||
} | ||
|
||
@override | ||
Future<void> runCommand(ArgResults topLevelResults) async { | ||
_setLogLevel?.call( | ||
parsedLogLevel: _parseLogLevel(topLevelResults), | ||
commandName: topLevelResults.command?.name, | ||
); | ||
|
||
if (argParser.options.containsKey(BetterCommandRunnerFlags.analytics) && | ||
!topLevelResults[BetterCommandRunnerFlags.analytics]) { | ||
_onAnalyticsEvent = null; | ||
} | ||
|
||
await _onBeforeRunCommand?.call(this); | ||
|
||
try { | ||
await super.runCommand(topLevelResults); | ||
if (topLevelResults.command == null) { | ||
_onAnalyticsEvent?.call(BetterCommandRunnerAnalyticsEvents.help); | ||
} else { | ||
_onAnalyticsEvent?.call(topLevelResults.command!.name!); | ||
} | ||
} on UsageException catch (e) { | ||
_logError?.call(e.toString()); | ||
_onAnalyticsEvent?.call(BetterCommandRunnerAnalyticsEvents.invalid); | ||
throw ExitException(ExitCodeType.commandNotFound); | ||
} | ||
} | ||
|
||
CommandRunnerLogLevel _parseLogLevel(ArgResults topLevelResults) { | ||
if (topLevelResults[BetterCommandRunnerFlags.verbose]) { | ||
return CommandRunnerLogLevel.verbose; | ||
} else if (topLevelResults[BetterCommandRunnerFlags.quiet]) { | ||
return CommandRunnerLogLevel.quiet; | ||
} | ||
|
||
return CommandRunnerLogLevel.normal; | ||
} | ||
} | ||
|
||
/// Constants for the command runner flags. | ||
abstract class BetterCommandRunnerFlags { | ||
static const quiet = 'quiet'; | ||
static const quietAbbr = 'q'; | ||
static const verbose = 'verbose'; | ||
static const verboseAbbr = 'v'; | ||
static const analytics = 'analytics'; | ||
static const analyticsAbbr = 'a'; | ||
} | ||
|
||
/// Constants for the command runner analytics events. | ||
abstract class BetterCommandRunnerAnalyticsEvents { | ||
static const help = 'help'; | ||
static const invalid = 'invalid'; | ||
} | ||
|
||
/// An enum for the command runner log levels. | ||
enum CommandRunnerLogLevel { quiet, verbose, normal } |
Oops, something went wrong.