From f47fe99199fdca6fd77da698e3cf8c2bc998fc5f Mon Sep 17 00:00:00 2001 From: Alexandre Roux Date: Thu, 20 Oct 2022 11:49:17 +0200 Subject: [PATCH 1/4] feat: add version display supports. --- README.md | 1 + bin/dhttpd.dart | 6 ++++++ lib/src/options.dart | 4 ++++ lib/src/options.g.dart | 6 ++++++ lib/src/version.dart | 2 ++ pubspec.yaml | 1 + test/readme_test.dart | 1 + 7 files changed, 21 insertions(+) create mode 100644 lib/src/version.dart diff --git a/README.md b/README.md index 1bf30ff..41f2a31 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ $ dhttpd --help --host= The hostname to listen on. (defaults to "localhost") -h, --help Displays the help. + --version Prints the version of dhttpd. ``` [path]: https://dart.dev/tools/pub/cmd/pub-global#running-a-script-from-your-path diff --git a/bin/dhttpd.dart b/bin/dhttpd.dart index aad82fb..d449477 100644 --- a/bin/dhttpd.dart +++ b/bin/dhttpd.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:dhttpd/dhttpd.dart'; import 'package:dhttpd/src/options.dart'; +import 'package:dhttpd/src/version.dart'; Future main(List args) async { Options options; @@ -19,6 +20,11 @@ Future main(List args) async { return; } + if (options.version) { + print(packageVersion); + return; + } + await Dhttpd.start( path: options.path, port: options.port, diff --git a/lib/src/options.dart b/lib/src/options.dart index 98957fc..b723932 100644 --- a/lib/src/options.dart +++ b/lib/src/options.dart @@ -31,10 +31,14 @@ class Options { @CliOption(abbr: 'h', negatable: false, help: 'Displays the help.') final bool help; + @CliOption(negatable: false, help: 'Prints the version of dhttpd.') + final bool version; + Options({ required this.port, this.path, required this.host, required this.help, + required this.version, }); } diff --git a/lib/src/options.g.dart b/lib/src/options.g.dart index d0ad260..daf91bf 100644 --- a/lib/src/options.g.dart +++ b/lib/src/options.g.dart @@ -25,6 +25,7 @@ Options _$parseOptionsResult(ArgResults result) => Options( path: result['path'] as String?, host: result['host'] as String, help: result['help'] as bool, + version: result['version'] as bool, ); ArgParser _$populateOptionsParser(ArgParser parser) => parser @@ -51,6 +52,11 @@ ArgParser _$populateOptionsParser(ArgParser parser) => parser abbr: 'h', help: 'Displays the help.', negatable: false, + ) + ..addFlag( + 'version', + help: 'Prints the version of dhttpd.', + negatable: false, ); final _$parserForOptions = _$populateOptionsParser(ArgParser()); diff --git a/lib/src/version.dart b/lib/src/version.dart new file mode 100644 index 0000000..072cbf4 --- /dev/null +++ b/lib/src/version.dart @@ -0,0 +1,2 @@ +// Generated code. Do not modify. +const packageVersion = '4.0.2-dev'; diff --git a/pubspec.yaml b/pubspec.yaml index e2771a0..9c9ccc1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,6 +17,7 @@ dev_dependencies: build_cli: ^2.0.2 build_runner: ^2.0.0 build_verify: '>=2.0.0 <4.0.0' + build_version: ^2.1.1 lints: ^1.0.0 path: ^1.6.1 test: ^1.3.0 diff --git a/test/readme_test.dart b/test/readme_test.dart index ae3f36e..4622d08 100644 --- a/test/readme_test.dart +++ b/test/readme_test.dart @@ -29,6 +29,7 @@ $ dhttpd --help --host= The hostname to listen on. (defaults to "localhost") -h, --help Displays the help. + --version Prints the version of dhttpd. ```'''); expect(readme.readAsStringSync(), contains(expected)); From c4a3fa0d279dc2862f4588bc42705960e899cc94 Mon Sep 17 00:00:00 2001 From: kevmoo Date: Sun, 15 Mar 2026 14:58:50 -0700 Subject: [PATCH 2/4] changelog tweaks --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc5431b..9118de2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,10 @@ - Support multiple `--headers` flags and more robust header value parsing. For example: `--headers="header1=value1;header2=value2"` or `--headers="header1=value1" --headers="header2=value2"` -- Add `--list-files` flag to show a directory listing when no `index.html` is +- Added `--list-files` flag to show a directory listing when no `index.html` is present. -- Add clickable link to serve output. +- Added `--version` flag. +- Added clickable link to serve output. - Require `sdk: ^3.10.0`. ## 4.1.0 From fcc2605fb434176dd1bc3d8e8a4dcedce5e95c41 Mon Sep 17 00:00:00 2001 From: kevmoo Date: Sun, 15 Mar 2026 15:00:34 -0700 Subject: [PATCH 3/4] test: add test for version flag and ensure false default --- lib/src/options.dart | 2 +- test/command_test.dart | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/src/options.dart b/lib/src/options.dart index 9ce96d1..b74c0f9 100644 --- a/lib/src/options.dart +++ b/lib/src/options.dart @@ -82,6 +82,6 @@ class Options { this.sslkeypassword, required this.help, this.listFiles = false, - required this.version, + this.version = false, }); } diff --git a/test/command_test.dart b/test/command_test.dart index 7d16681..d017063 100644 --- a/test/command_test.dart +++ b/test/command_test.dart @@ -9,12 +9,20 @@ import 'package:test_descriptor/test_descriptor.dart' as d; import 'package:test_process/test_process.dart'; void main() { + test('prints version', () => _versionCheck()); test('prints help', () => _readmeCheck(['--help'])); test('serves on specified port', _outputCheck); test('handles custom headers', _headersCheck); test('rejects invalid headers', _invalidHeadersCheck); } +Future _versionCheck() async { + final process = await _runApp(['--version']); + final output = (await process.stdoutStream().join('\n')).trim(); + await process.shouldExit(0); + expect(output, matches(RegExp(r'^\d+\.\d+\.\d+'))); +} + Future _readmeCheck(List args) async { final process = await _runApp(args); final output = (await process.stdoutStream().join('\n')).trim(); From 09733f90aea080367a86e18aa6813d3fe4e0b122 Mon Sep 17 00:00:00 2001 From: kevmoo Date: Sun, 15 Mar 2026 15:07:30 -0700 Subject: [PATCH 4/4] more cleanup --- README.md | 10 ++++---- lib/src/options.dart | 52 +++++++++++++++++++++--------------------- lib/src/options.g.dart | 44 +++++++++++++++++------------------ test/command_test.dart | 15 ++++++------ 4 files changed, 61 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 9ac3a7c..44c3a79 100644 --- a/README.md +++ b/README.md @@ -54,17 +54,17 @@ See the Dart documentation of [SecurityContext.usePrivateKey](https://api.dart.d ```console $ dhttpd --help --p, --port= The port to listen on. Provide `0` to use a random port. - (defaults to "8080") - --path= The path to serve. If not set, the current directory is used. - --headers= HTTP headers to apply to each response. Can be used multiple times. Format: header=value;header2=value +--headers= HTTP headers to apply to each response. Can be used multiple times. Format: header=value;header2=value --host= The hostname to listen on. (defaults to "localhost") +-l, --list-files List the files in the directory if no index.html is present. + --path= The path to serve. If not set, the current directory is used. +-p, --port= The port to listen on. Provide `0` to use a random port. + (defaults to "8080") --sslcert= The SSL certificate to use. Also requires sslkey --sslkey= The key of the SSL certificate to use. Also requires sslcert --sslkeypassword= The password for the key of the SSL certificate to use. -h, --help Displays the help. --l, --list-files List the files in the directory if no index.html is present. --version Prints the version of dhttpd. ``` diff --git a/lib/src/options.dart b/lib/src/options.dart index b74c0f9..61bf126 100644 --- a/lib/src/options.dart +++ b/lib/src/options.dart @@ -9,22 +9,6 @@ const String defaultHost = 'localhost'; @CliOptions() class Options { - @CliOption( - abbr: 'p', - valueHelp: 'port', - defaultsTo: defaultPort, - help: 'The port to listen on. Provide `0` to use a random port.', - ) - final int port; - - @CliOption( - valueHelp: 'path', - help: - 'The path to serve.' - ' If not set, the current directory is used.', - ) - final String? path; - @CliOption( valueHelp: 'headers', help: @@ -41,6 +25,29 @@ class Options { ) final String host; + @CliOption( + abbr: 'l', + negatable: false, + help: 'List the files in the directory if no index.html is present.', + ) + final bool listFiles; + + @CliOption( + valueHelp: 'path', + help: + 'The path to serve.' + ' If not set, the current directory is used.', + ) + final String? path; + + @CliOption( + abbr: 'p', + valueHelp: 'port', + defaultsTo: defaultPort, + help: 'The port to listen on. Provide `0` to use a random port.', + ) + final int port; + @CliOption( valueHelp: 'sslcert', help: 'The SSL certificate to use. Also requires sslkey', @@ -62,26 +69,19 @@ class Options { @CliOption(abbr: 'h', negatable: false, help: 'Displays the help.') final bool help; - @CliOption( - abbr: 'l', - negatable: false, - help: 'List the files in the directory if no index.html is present.', - ) - final bool listFiles; - @CliOption(negatable: false, help: 'Prints the version of dhttpd.') final bool version; Options({ - required this.port, - this.path, required this.headers, required this.host, + this.listFiles = false, + this.path, + required this.port, this.sslcert, this.sslkey, this.sslkeypassword, required this.help, - this.listFiles = false, this.version = false, }); } diff --git a/lib/src/options.g.dart b/lib/src/options.g.dart index 001b689..9da5d72 100644 --- a/lib/src/options.g.dart +++ b/lib/src/options.g.dart @@ -17,33 +17,21 @@ T _$badNumberFormat( ); Options _$parseOptionsResult(ArgResults result) => Options( + headers: result['headers'] as List, + host: result['host'] as String, + listFiles: result['list-files'] as bool, + path: result['path'] as String?, port: int.tryParse(result['port'] as String) ?? _$badNumberFormat(result['port'] as String, 'int', 'port'), - path: result['path'] as String?, - headers: result['headers'] as List, - host: result['host'] as String, sslcert: result['sslcert'] as String?, sslkey: result['sslkey'] as String?, sslkeypassword: result['sslkeypassword'] as String?, help: result['help'] as bool, - listFiles: result['list-files'] as bool, version: result['version'] as bool, ); ArgParser _$populateOptionsParser(ArgParser parser) => parser - ..addOption( - 'port', - abbr: 'p', - help: 'The port to listen on. Provide `0` to use a random port.', - valueHelp: 'port', - defaultsTo: '8080', - ) - ..addOption( - 'path', - help: 'The path to serve. If not set, the current directory is used.', - valueHelp: 'path', - ) ..addMultiOption( 'headers', help: @@ -56,6 +44,24 @@ ArgParser _$populateOptionsParser(ArgParser parser) => parser valueHelp: 'host', defaultsTo: 'localhost', ) + ..addFlag( + 'list-files', + abbr: 'l', + help: 'List the files in the directory if no index.html is present.', + negatable: false, + ) + ..addOption( + 'path', + help: 'The path to serve. If not set, the current directory is used.', + valueHelp: 'path', + ) + ..addOption( + 'port', + abbr: 'p', + help: 'The port to listen on. Provide `0` to use a random port.', + valueHelp: 'port', + defaultsTo: '8080', + ) ..addOption( 'sslcert', help: 'The SSL certificate to use. Also requires sslkey', @@ -72,12 +78,6 @@ ArgParser _$populateOptionsParser(ArgParser parser) => parser valueHelp: 'sslkeypassword', ) ..addFlag('help', abbr: 'h', help: 'Displays the help.', negatable: false) - ..addFlag( - 'list-files', - abbr: 'l', - help: 'List the files in the directory if no index.html is present.', - negatable: false, - ) ..addFlag('version', help: 'Prints the version of dhttpd.', negatable: false); final _$parserForOptions = _$populateOptionsParser(ArgParser()); diff --git a/test/command_test.dart b/test/command_test.dart index d017063..6f1ff85 100644 --- a/test/command_test.dart +++ b/test/command_test.dart @@ -3,13 +3,14 @@ import 'dart:async'; import 'dart:io'; +import 'package:dhttpd/src/version.dart'; import 'package:http/http.dart' as http; import 'package:test/test.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; import 'package:test_process/test_process.dart'; void main() { - test('prints version', () => _versionCheck()); + test('prints version', _versionCheck); test('prints help', () => _readmeCheck(['--help'])); test('serves on specified port', _outputCheck); test('handles custom headers', _headersCheck); @@ -20,7 +21,7 @@ Future _versionCheck() async { final process = await _runApp(['--version']); final output = (await process.stdoutStream().join('\n')).trim(); await process.shouldExit(0); - expect(output, matches(RegExp(r'^\d+\.\d+\.\d+'))); + expect(output, packageVersion); } Future _readmeCheck(List args) async { @@ -42,17 +43,17 @@ $output expect(expected, r'''```console $ dhttpd --help --p, --port= The port to listen on. Provide `0` to use a random port. - (defaults to "8080") - --path= The path to serve. If not set, the current directory is used. - --headers= HTTP headers to apply to each response. Can be used multiple times. Format: header=value;header2=value +--headers= HTTP headers to apply to each response. Can be used multiple times. Format: header=value;header2=value --host= The hostname to listen on. (defaults to "localhost") +-l, --list-files List the files in the directory if no index.html is present. + --path= The path to serve. If not set, the current directory is used. +-p, --port= The port to listen on. Provide `0` to use a random port. + (defaults to "8080") --sslcert= The SSL certificate to use. Also requires sslkey --sslkey= The key of the SSL certificate to use. Also requires sslcert --sslkeypassword= The password for the key of the SSL certificate to use. -h, --help Displays the help. --l, --list-files List the files in the directory if no index.html is present. --version Prints the version of dhttpd. ```''');