diff --git a/README.md b/README.md index 2896adf..b3ff65c 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,9 @@ Usage: webdev_proxy serve [-- [webdev serve arguments]] --[no-]rewrite-404s Rewrite every request that returns a 404 to /index.html (defaults to on) +The proxy arguments can contain either the webdev [:] syntax +or proxy-specific :: syntax. + Run "webdev_proxy help" to see global options. You may use any of the following options supported by `webdev serve` by passing them after the `--` separator. diff --git a/lib/src/serve_command.dart b/lib/src/serve_command.dart index 5749dba..95759a1 100644 --- a/lib/src/serve_command.dart +++ b/lib/src/serve_command.dart @@ -138,24 +138,27 @@ class ServeCommand extends Command { // Parse the hostname to serve each dir on (defaults to localhost). final hostnameResults = parseHostname(argResults!.rest); final hostname = hostnameResults.hostname; - final remainingArgs = hostnameResults.remainingArgs; // Parse the directory:port mappings that will be used by the proxy servers. // Each proxy will be mapped to a `webdev serve` instance on another port. - final portsToServeByDir = parseDirectoryArgs(argResults!.rest); + final dirResults = parseDirectoryArgs(hostnameResults.remainingArgs); // Find open ports for each of the directories to be served by webdev. - final portsToProxyByDir = { - for (final dir in portsToServeByDir.keys) dir: await findUnusedPort() - }; + final dirPorts = await Future.wait(dirResults.ports + .map((dirPort) async => DirectoryPorts( + directory: dirPort.directory, + proxyPort: dirPort.proxyPort ?? await findUnusedPort(), + servePort: dirPort.servePort)) + .toList()); + + final webdevArgs = [ + if (hostname != 'localhost') '--hostname=$hostname', + ...dirResults.remainingArgs, + for (final dir in dirPorts) '${dir.directory}:${dir.proxyPort}', + ]; // Start the underlying `webdev serve` process. - webdevServer = await WebdevServer.start([ - if (hostname != 'localhost') '--hostname=$hostname', - ...remainingArgs, - for (final dir in portsToServeByDir.keys) - '$dir:${portsToProxyByDir[dir]}', - ]); + webdevServer = await WebdevServer.start(webdevArgs); // Stop proxies and exit if webdev exits. unawaited(webdevServer.exitCode.then((code) { @@ -166,21 +169,19 @@ class ServeCommand extends Command { })); // Start a proxy server for each directory. - for (final dir in portsToServeByDir.keys) { + for (final dirPort in dirPorts) { try { proxies.add(await WebdevProxyServer.start( - dir: dir, + dir: dirPort.directory, hostname: hostname, - portToProxy: portsToProxyByDir[dir], - portToServe: portsToServeByDir[dir]!, + portToProxy: dirPort.proxyPort, + portToServe: dirPort.servePort, rewrite404s: argResults![rewrite404sFlag] == true, )); } catch (e, stackTrace) { proxiesFailed = true; - log.severe( - 'Failed to start proxy server on port ${portsToServeByDir[dir]}', - e, - stackTrace); + log.severe('Failed to start proxy server on port ${dirPort.servePort}', + e, stackTrace); shutDown(ExitCode.unavailable.code); break; } @@ -189,3 +190,13 @@ class ServeCommand extends Command { return exitCodeCompleter.future; } } + +class DirectoryPorts { + final String directory; + final int proxyPort; + final int servePort; + DirectoryPorts( + {required this.directory, + required this.proxyPort, + required this.servePort}); +} diff --git a/lib/src/webdev_arg_utils.dart b/lib/src/webdev_arg_utils.dart index c2b61d9..196711d 100644 --- a/lib/src/webdev_arg_utils.dart +++ b/lib/src/webdev_arg_utils.dart @@ -16,37 +16,57 @@ final _defaultWebDirs = const ['web']; final _dirPattern = RegExp( // Matches and captures any directory path, e.g. `web` or `test/nested/dir/` r'^([\w/]+)' - // Optional non-capturing group since webdev allows for the port to be omitted + // Optional non-capturing group since webdev allows for the ports to be omitted r'(?:' // Matches and captures any port, e.g. `:8080` or `:9001` r':(\d+)' // Ends the optional non-capturing group - r')?$'); + r'){0,2}$'); + +class ParsedDirectoryPorts { + final String directory; + final int? proxyPort; + final int servePort; + ParsedDirectoryPorts( + {required this.directory, this.proxyPort, required this.servePort}); +} /// Returns a mapping of directories to ports parsed from command-line [args] in /// the form of `:`. /// /// If no mappings are specified in [args], the default mapping of web:8080 is /// returned. -Map parseDirectoryArgs(List args) { - final result = {}; +ParseDirectoryArgsResults parseDirectoryArgs(List args) { + final ports = []; + final remainingArgs = []; var basePort = 8080; - final dirArgs = args.where((_dirPattern.hasMatch)); - if (dirArgs.isEmpty) { - for (final dir in _defaultWebDirs) { - result[dir] = basePort++; - } - } else { - for (final arg in dirArgs) { + for (final arg in args) { + if (!_dirPattern.hasMatch(arg)) { + remainingArgs.add(arg); + } else { final splitOption = arg.split(':'); - if (splitOption.length == 2) { - result[splitOption.first] = int.parse(splitOption.last); + if (splitOption.length == 3) { + ports.add(ParsedDirectoryPorts( + directory: splitOption[0], + proxyPort: int.parse(splitOption[1]), + servePort: int.parse(splitOption[2]))); + } else if (splitOption.length == 2) { + ports.add(ParsedDirectoryPorts( + directory: splitOption.first, + servePort: int.parse(splitOption.last))); } else { - result[arg] = basePort++; + ports + .add(ParsedDirectoryPorts(directory: arg, servePort: basePort++)); } } } - return result; + return ParseDirectoryArgsResults(ports, remainingArgs); +} + +class ParseDirectoryArgsResults { + final List ports; + final List remainingArgs; + ParseDirectoryArgsResults(this.ports, this.remainingArgs); } /// Returns the value of the `--hostname` option from a list of command-line