├── .pubignore ├── bin ├── echo.sh ├── pub_get_all ├── vscode_paths.dart ├── dmysql.dart ├── dvirtualbox.dart ├── compile_all.dart ├── dcli.docker ├── gitgc.dart ├── find_old_dart_packages.dart ├── dzfs_clean.dart ├── ipaddr.dart ├── dnsflush.dart ├── gitrename_tag.dart ├── dpath.dart ├── downit.dart ├── kill_tomcat.dart ├── dwc.dart ├── find_text.dart ├── denv.dart ├── bobthefish.dart ├── dcopydir.dart ├── pub_get_all.dart ├── eclipse_launcher.dart ├── simple_dev.dart ├── fetch.dart ├── clean.dart ├── docker_dcli.dart ├── post.dart ├── docker_push.dart ├── tcp_echo.dart ├── dreplace.dart ├── gituncommited.dart ├── gitcreation_date.dart ├── install_flutter.dart ├── dfind.dart ├── certbot_renew.dart ├── dmailhog.dart ├── dcompress.dart ├── gactivate.dart ├── dsetver.dart ├── gitupdate_remote.dart ├── gitadd_team_to_repository.dart ├── bitbucket_import.dart ├── gitsyncfork.dart ├── dport.dart ├── dwhich.dart ├── vscode_backup.dart ├── add_gnome_launcher.dart ├── artifactory.dart ├── hexdump.dart ├── dsort.dart └── hog.dart ├── pubspec_overrides.yaml ├── lib ├── src │ ├── version │ │ └── version.g.dart │ ├── mysql │ │ ├── cli_command.dart │ │ ├── config_command.dart │ │ ├── restore_command.dart │ │ ├── mysql.dart │ │ ├── mysql_settings.dart │ │ └── backup_command.dart │ └── docker │ │ └── publish.dart └── dcli_scripts.dart ├── analysis_options.yaml ├── test ├── src │ └── mysql │ │ └── mysql_test.dart └── editor.dart ├── tool └── post_release_hook │ └── activate.dart ├── .gitignore ├── .vscode_extension.bak ├── LICENSE ├── pubspec.yaml ├── bob.dart ├── .vscode └── launch.json ├── README.md ├── CHANGELOG.md ├── pubspec.lock └── custom_lint.log /.pubignore: -------------------------------------------------------------------------------- 1 | .vscode/launch.json -------------------------------------------------------------------------------- /bin/echo.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo $@ 4 | -------------------------------------------------------------------------------- /bin/pub_get_all: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onepub-dev/dcli_scripts/HEAD/bin/pub_get_all -------------------------------------------------------------------------------- /pubspec_overrides.yaml: -------------------------------------------------------------------------------- 1 | # dependency_overrides: 2 | # dcli_core: 3 | # path: ../dcli-4.x/dcli_core -------------------------------------------------------------------------------- /lib/src/version/version.g.dart: -------------------------------------------------------------------------------- 1 | /// GENERATED BY pub_release do not modify. 2 | /// Instance of 'Name' version 3 | ///ignore: omit_obvious_property_types 4 | String packageVersion = '4.4.0'; 5 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | 2 | analyzer: 3 | errors: 4 | avoid_catches_without_on_clauses: ignore 5 | include: package:lint_hard/all.yaml 6 | 7 | linter: 8 | rules: 9 | avoid_print: false -------------------------------------------------------------------------------- /lib/dcli_scripts.dart: -------------------------------------------------------------------------------- 1 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 2 | * Unauthorized copying of this file, via any medium is strictly prohibited 3 | * Proprietary and confidential 4 | * Written by Brett Sutton , Jan 2022 5 | */ 6 | export 'src/docker/publish.dart'; 7 | -------------------------------------------------------------------------------- /bin/vscode_paths.dart: -------------------------------------------------------------------------------- 1 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 2 | * Unauthorized copying of this file, via any medium is strictly prohibited 3 | * Proprietary and confidential 4 | * Written by Brett Sutton , Jan 2022 5 | */ 6 | void main() { 7 | print('export ANDROID_SDK_ROOT=/home/bsutton/Android/Sdk'); 8 | print('export FLUTTER_SDK=/home/bsutton/apps/flutter'); 9 | } 10 | -------------------------------------------------------------------------------- /test/src/mysql/mysql_test.dart: -------------------------------------------------------------------------------- 1 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 2 | * Unauthorized copying of this file, via any medium is strictly prohibited 3 | * Proprietary and confidential 4 | * Written by Brett Sutton , Jan 2022 5 | */ 6 | import 'package:dcli_scripts/src/mysql/mysql.dart'; 7 | import 'package:test/test.dart'; 8 | 9 | void main() { 10 | test('mysql ...', () async { 11 | await mysqlRun(['backup', 'onepub']); 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /tool/post_release_hook/activate.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env %dcliName% 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | 9 | import 'package:dcli/dcli.dart'; 10 | import 'package:dcli_scripts/src/version/version.g.dart'; 11 | 12 | void main(List args) { 13 | PubCache().globalActivate('dcli_scripts', version: packageVersion); 14 | } 15 | -------------------------------------------------------------------------------- /bin/dmysql.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli_scripts/src/mysql/mysql.dart'; 9 | 10 | /// Connects you to a mysql cli pulling settings (username/password) 11 | /// from a local settings file. 12 | /// Use 13 | 14 | Future main(List args) async { 15 | await mysqlRun(args); 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | namecheap_key 2 | namecheap_username 3 | .dart_tool 4 | .history 5 | .lego 6 | .packages 7 | compile_all 8 | denv 9 | dfind 10 | dpath 11 | dsort 12 | duntar 13 | dwhich 14 | ecliplse_launcher 15 | find_old_dart_packages 16 | future_test 17 | ipaddr 18 | kill_tomcat 19 | rename_tag 20 | show_shell 21 | show_shell.dart 22 | vscode_backup 23 | vscode_paths 24 | tests/editor 25 | .pub-cache 26 | .bash_history 27 | .bashrc 28 | .wget-hsts 29 | repo.list.csv 30 | repo.list.ods 31 | repo.list.processed.csv 32 | bitbucket.yaml 33 | github.yaml 34 | .failed_tracker 35 | bin/tcp_echo 36 | -------------------------------------------------------------------------------- /bin/dvirtualbox.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create dvirtualbox.dart 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | 19 | void main() { 20 | 'sudo modprobe vboxdrv'.run; 21 | 'virtualbox'.start(detached: true); 22 | } 23 | -------------------------------------------------------------------------------- /bin/compile_all.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create compile_all.dart 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | 19 | void main() { 20 | find('*.dart', recursive: false).forEach((file) { 21 | 'dcli compile -i $file'.run; 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /test/editor.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create editor.dart 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | 19 | void main() async { 20 | //'vi'.run; 21 | 22 | await Process.run('vi', []).then((result) { 23 | stdout.write(result.stdout); 24 | stderr.write(result.stderr); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /bin/dcli.docker: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | WORKDIR / 4 | 5 | ENV HOME=/home 6 | RUN touch /home/.profile 7 | 8 | RUN apt -y update 9 | RUN apt -y upgrade 10 | RUN apt -y install vim 11 | RUN apt -y install wget 12 | 13 | 14 | 15 | RUN apt update 16 | RUN apt install --no-install-recommends -y wget ca-certificates gnupg2 procps 17 | RUN wget https://github.com/noojee/dcli/releases/download/latest-linux/dcli_install 18 | RUN chmod +x dcli_install 19 | ENV PATH="${PATH}":/usr/lib/dart/bin:"${HOME}/.pub-cache/bin":"${HOME}/.dcli/bin" 20 | 21 | RUN ulimit -c unlimited 22 | RUN ./dcli_install -v 23 | 24 | # Add the local directory into our container 25 | ADD . /local 26 | 27 | 28 | WORKDIR /home 29 | 30 | 31 | CMD ["/bin/bash"] 32 | 33 | -------------------------------------------------------------------------------- /bin/gitgc.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create hog.dart 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | 19 | void main(List args) { 20 | find('.git', includeHidden: true, types: [Find.directory]).forEach((gitPath) { 21 | print('cleaning $gitPath'); 22 | 23 | 'git gc'.start( 24 | workingDirectory: gitPath, progress: Progress.print(), nothrow: true); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /bin/find_old_dart_packages.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create find_old_dart_packages.dart 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | 19 | void main() { 20 | find('build.gradle').forEach((file) { 21 | print(file); 22 | read(file).forEach((line) { 23 | if (line.contains('compilesdkversion') && line.contains('27')) { 24 | print('file: $file, line: $line'); 25 | } 26 | }); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /bin/dzfs_clean.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | 10 | void main() { 11 | print('clean automatically generated zfs snapshots'); 12 | // check if there are any to delete. 13 | 14 | final snapshots = []; 15 | 16 | final progress = Progress(snapshots.add, stderr: snapshots.add); 17 | 'zfs list -t snapshot -o name -S creation' 18 | .start(privileged: true, progress: progress); 19 | 20 | for (final snapshot in snapshots) { 21 | if (snapshot.contains('@auto')) { 22 | 'zfs destroy -vr $snapshot'.start(privileged: true); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /bin/ipaddr.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create ipaddr.dart 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | 19 | void main() async { 20 | await NetworkInterface.list().then((interfaces) { 21 | for (final interface in interfaces) { 22 | print('name: ${interface.name}'); 23 | var i = 0; 24 | for (final address in interface.addresses) { 25 | print(' ${i++}) ${address.address}'); 26 | } 27 | } 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /bin/dnsflush.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create dnsflush.dart 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | 19 | void main() { 20 | if (which('resolvectl').notfound) { 21 | 'systemd-resolve --flush-caches'.start(privileged: true); 22 | 'systemd-resolve --statistics'.start(privileged: true); 23 | } else { 24 | // 22.04 onward. 25 | 'resolvectl flush-caches'.start(privileged: true); 26 | 'resolvectl statistics'.start(privileged: true); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /bin/gitrename_tag.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:dcli/dcli.dart'; 11 | 12 | /// dcli script generated by: 13 | /// dcli create rename_tag.dart 14 | /// 15 | /// See 16 | /// https://pub.dev/packages/dcli#-installing-tab- 17 | /// 18 | /// For details on installing dcli. 19 | /// 20 | 21 | void main(List args) { 22 | if (args.length != 2) { 23 | printerr('usage rename_tag '); 24 | exit(1); 25 | } 26 | final oldTag = args[0]; 27 | final newTag = args[1]; 28 | 29 | 'git tag $newTag $oldTag'.run; 30 | 'git tag -d $oldTag'.run; 31 | 'git push origin :refs/tags/$oldTag'.run; 32 | 'git push --tags'.run; 33 | } 34 | -------------------------------------------------------------------------------- /.vscode_extension.bak: -------------------------------------------------------------------------------- 1 | ajhyndman.jslint@1.2.1 2 | alexisvt.flutter-snippets@2.0.0 3 | auchenberg.vscode-browser-preview@0.5.9 4 | CoenraadS.bracket-pair-colorizer@1.0.61 5 | Dart-Code.flutter@3.7.1 6 | Dart-Code.dart-code@3.7.1 7 | eamodio.gitlens@10.2.0 8 | emilast.LogFileHighlighter@2.7.1 9 | formulahendry.code-runner@0.9.15 10 | jeroen-meijer.pubspec-assist@0.3.6 11 | kisstkondoros.vscode-gutter-preview@0.25.0 12 | luanpotter.dart-import@0.1.6 13 | mhutchie.git-graph@1.21.0 14 | msjsdiag.debugger-for-chrome@4.12.5 15 | mtxr.sqltools@0.21.6 16 | Nash.awesome-flutter-snippets@2.0.3 17 | naumovs.color-highlight@2.3.0 18 | PKief.material-icon-theme@3.9.2 19 | polymer.polymer-ide@0.6.0 20 | ritwickdey.LiveServer@5.6.1 21 | slevesque.vscode-multiclip@0.1.5 22 | VisualStudioExptTeam.vscodeintellicode@1.2.4 23 | vscjava.vscode-java-dependency@0.8.0 24 | vscjava.vscode-java-pack@0.8.1 25 | vscjava.vscode-java-test@0.22.1 26 | vscjava.vscode-java-debug@0.24.0 27 | xyz.local-history@1.7.0 28 | redhat.java@0.55.1 29 | -------------------------------------------------------------------------------- /bin/dpath.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:args/args.dart'; 9 | import 'package:dcli/dcli.dart'; 10 | import 'package:path/path.dart'; 11 | 12 | /// dpath appname 13 | /// print the systems PATH variable contents and validates each path. 14 | 15 | // for future use. 16 | // ignore: unreachable_from_main 17 | const tick = '''\xE2\x9C\x93'''; 18 | 19 | const posixTick = '''\u2714'''; 20 | 21 | const cross = 'x'; 22 | 23 | void main(List args) { 24 | ArgParser().addFlag('verbose', abbr: 'v', negatable: false); 25 | 26 | for (final path in PATH) { 27 | final pathexists = exists(path); 28 | 29 | if (pathexists) { 30 | print('Test: $posixTick ${normalize(path)}'); 31 | } else { 32 | print(red('Test: $cross ${normalize(path)}')); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/src/mysql/cli_command.dart: -------------------------------------------------------------------------------- 1 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 2 | * Unauthorized copying of this file, via any medium is strictly prohibited 3 | * Proprietary and confidential 4 | * Written by Brett Sutton , Jan 2022 5 | */ 6 | import 'package:args/command_runner.dart'; 7 | import 'package:dcli/dcli.dart'; 8 | 9 | import 'mysql.dart'; 10 | import 'mysql_settings.dart'; 11 | 12 | class CliCommand extends Command { 13 | @override 14 | String get description => 'Connects the MySql client.'; 15 | 16 | @override 17 | String get name => 'cli'; 18 | 19 | @override 20 | void run() { 21 | final args = getArgs(this, argResults); 22 | cli(args[0]); 23 | } 24 | 25 | void cli(String dbName) { 26 | final settings = MySqlSettings.load(dbName); 27 | 'mysql --host ${settings.host} --port=${settings.port} ' 28 | '--user ${settings.user} --password="${settings.password}" ' 29 | '--database ${settings.dbname}' 30 | .start(nothrow: true, terminal: true); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bin/downit.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | 13 | /// This script runs chown for the given path(s) making the calling 14 | /// user the owner. 15 | /// The script uses sudo. 16 | 17 | void main(List args) { 18 | final parser = ArgParser(); 19 | 20 | final results = parser.parse(args); 21 | final rest = results.rest; 22 | 23 | if (rest.isEmpty) { 24 | printerr('You must provide at least one path'); 25 | exit(1); 26 | } 27 | 28 | final user = Shell.current.loggedInUser; 29 | 30 | for (final path in rest.toList()) { 31 | if (!exists(path)) { 32 | print(red("The path ${truepath(path)} doesn't exists. Skipped")); 33 | } 34 | 'chown -R $user:$user $path'.start(privileged: true); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /bin/kill_tomcat.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | 10 | void main() { 11 | // find all java processes 12 | var killed = false; 13 | 'ps aux'.forEach((line) { 14 | if (line.contains('java') && line.contains('tomcat')) { 15 | final parts = line.split(RegExp(r'\s+')); 16 | if (parts.isNotEmpty) { 17 | final pidPart = parts[1]; 18 | final pid = int.tryParse(pidPart) ?? -1; 19 | if (pid != -1) { 20 | try { 21 | 'kill -9 $pid'.start(progress: Progress.devNull()); 22 | } on RunException { 23 | 'kill -9 $pid'.start(privileged: true); 24 | } 25 | print('Killed tomcat with pid=$pid'); 26 | killed = true; 27 | } 28 | } 29 | } 30 | }); 31 | 32 | if (!killed) { 33 | print('tomcat process not found.'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Brett Sutton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bin/dwc.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | 13 | void main(List args) { 14 | final parser = ArgParser()..addFlag('verbose', abbr: 'v', negatable: false); 15 | 16 | final parsed = parser.parse(args); 17 | if (parsed.wasParsed('verbose')) { 18 | Settings().setVerbose(enabled: true); 19 | } 20 | 21 | if (parsed.rest.length != 1) { 22 | printerr(red('You must pass a wildcard for the files you want counted')); 23 | exit(1); 24 | } 25 | 26 | var total = 0; 27 | find(parsed.rest[0], workingDirectory: pwd).forEach((file) { 28 | final line = 'wc -l "$file"'.firstLine!; 29 | final parts = line.split(' '); 30 | if (parts.isEmpty) { 31 | printerr('Invalid line: $line'); 32 | } else { 33 | final count = int.tryParse(parts[0])!; 34 | total += count; 35 | } 36 | }); 37 | 38 | print('Total lines: $total'); 39 | } 40 | -------------------------------------------------------------------------------- /bin/find_text.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:path/path.dart'; 13 | 14 | /// Search for text within files with the given glob 15 | void main(List args) { 16 | final parser = ArgParser(); 17 | 18 | final results = parser.parse(args); 19 | 20 | if (results.rest.length != 2) { 21 | printerr('You must provide a filename and text to search for.'); 22 | print('find_text "glob"'); 23 | print(orange('Note: the glob MUST be enclosed in quotes')); 24 | exit(1); 25 | } 26 | 27 | final text = results.rest[0]; 28 | final glob = results.rest[1]; 29 | print('Looking for $text in $glob'); 30 | 31 | final reg = RegExp(text); 32 | find(glob).forEach((file) { 33 | var count = 0; 34 | read(file).forEach((line) { 35 | count++; 36 | if (reg.hasMatch(line)) { 37 | print('${relative(file)}($count): $line'); 38 | } 39 | }); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dcli_scripts 2 | version: 4.4.0 3 | description: A collection of cli scripts that do odd jobs for me. 4 | repository: https://github.com/bsutton/dcli_scripts 5 | environment: 6 | sdk: '>=3.5.0 <4.0.0' 7 | dependencies: 8 | args: ^2.3.1 9 | dcli: ^8.1.0 10 | dcli_core: ^8.0.0 11 | docker2: ^6.0.0 12 | path: ^1.8.2 13 | pub_release: ^11.4.0 14 | pubspec_manager: ^3.0.1 15 | settings_yaml: ^8.0.1 16 | strings: ^4.0.1 17 | uuid: ^4.0.0 18 | win32: ^5.3.0 19 | dev_dependencies: 20 | lint_hard: ^6.2.1 21 | test: ^1.0.0 22 | executables: 23 | add_gnome_launcher: 24 | artifactory: 25 | bobthefish: 26 | certbot_renew: 27 | clean: 28 | dcompress: 29 | dcopydir: 30 | denv: 31 | dfind: 32 | dmailhog: 33 | dnsflush: 34 | docker_dcli: 35 | docker_push: 36 | downit: 37 | dmysql: 38 | dpath: 39 | dport: 40 | dreplace: 41 | dsetver: 42 | dsort: 43 | dvirtualbox: 44 | dwc: 45 | dwhich: 46 | dzfs_clean: 47 | eclipse_launcher: 48 | find_old_dart_packages: 49 | find_text: 50 | gactivate: 51 | gitadd_team_to_repository: 52 | gitcreation_date: 53 | gitgc: 54 | gituncommited: 55 | gitsyncfork: 56 | gitupdate_remote: 57 | hexdump: 58 | hog: 59 | install_flutter: 60 | ipaddr: 61 | kill_tomcat: 62 | pub_get_all: 63 | -------------------------------------------------------------------------------- /bin/denv.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | 12 | /// prints environment variables that match a passed prefix or 13 | /// all environment variables if the --print flag is passed 14 | void main(List args) { 15 | final parser = ArgParser() 16 | ..addFlag('print', 17 | abbr: 'p', negatable: false, help: 'prints all environment variables'); 18 | 19 | final results = parser.parse(args); 20 | 21 | final doPrint = results['print'] as bool; 22 | 23 | final envVars = Platform.environment; 24 | 25 | if (doPrint) { 26 | envVars.forEach((key, value) => print('$key:$value')); 27 | exit(0); 28 | } 29 | 30 | if (results.rest.length != 1) { 31 | print( 32 | 'You must pass the name (or the begining) of an environment variable'); 33 | exit(1); 34 | } 35 | var name = results.rest[0]; 36 | name = name.toLowerCase(); 37 | 38 | envVars.forEach((key, value) { 39 | if (key.toLowerCase().startsWith(name)) { 40 | print('$key=$value'); 41 | } 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /bob.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) Rhiannon Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Rhiannon Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create bob.dart 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | 19 | void main() { 20 | print(''' 21 | Bob is a fish who really, Really, REALLY wants a cat. 22 | Sadly however, Bob's father is a horrible tyrannical fish who hates the poor innocent cat race. 23 | So, he wont allow his sweet beautiful child get a cat. 24 | How cruel :('''); 25 | final horrible = 26 | confirm(magenta("Do you think Bob's father is a horrible fish being.")); 27 | if (horrible) { 28 | print(blue(''' 29 | "Yay!!!!!:) 30 | I knew you would agree with me. 31 | I mean how could anyone think someone who doesn't like cats could be anything but EVIL >:("''')); 32 | } else { 33 | print(''' 34 | Bob, got so angry with your horrendous claim of his father being right that Bob killed you very slowly and painfully. 35 | you are now dead. 36 | ${red("I wish you a horrible time in hell:)")}'''); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /bin/bobthefish.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create bob.dart 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | 19 | void main() { 20 | print(''' 21 | Bob is a fish who really, Really, REALLY wants a cat. 22 | Sadly however, Bob's father is a horrible tyrannical fish who hates the poor innocent cat race. 23 | So, he wont allow his sweet beautiful child to get a cat. 24 | How cruel :('''); 25 | final horrible = 26 | confirm(magenta("Do you think Bob's father is a horrible fish being.")); 27 | if (horrible) { 28 | print(blue(''' 29 | "Yay!!!!!:) 30 | I knew you would agree with me. 31 | I mean how could anyone think someone who doesn't like cats could be anything but EVIL >:("''')); 32 | } else { 33 | print(''' 34 | Bob, got so angry with your horrendous claim of his father being right, that Bob killed you very slowly and painfully. 35 | you are now dead. 36 | ${red("I wish you a horrible time in hell:)")}'''); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/mysql/config_command.dart: -------------------------------------------------------------------------------- 1 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 2 | * Unauthorized copying of this file, via any medium is strictly prohibited 3 | * Proprietary and confidential 4 | * Written by Brett Sutton , Jan 2022 5 | */ 6 | import 'package:args/command_runner.dart'; 7 | import 'package:dcli/dcli.dart'; 8 | 9 | import 'mysql.dart'; 10 | import 'mysql_settings.dart'; 11 | 12 | class ConfigCommand extends Command { 13 | ConfigCommand() { 14 | argParser.addFlag('remove', 15 | abbr: 'r', 16 | help: 'Removes a database config. Does not touch the actual db'); 17 | } 18 | @override 19 | String get description => 'configures credentials for a database.'; 20 | 21 | @override 22 | String get name => 'config'; 23 | 24 | @override 25 | Future run() async { 26 | final args = getArgs(this, argResults); 27 | 28 | final dbname = args[0]; 29 | 30 | if (argResults!['remove'] as bool) { 31 | final pathTo = MySqlSettings.pathToSettings(dbname); 32 | if (exists(pathTo)) { 33 | delete(pathTo); 34 | } else { 35 | printerr(red('No config for $dbname exits at $pathTo')); 36 | } 37 | } else { 38 | await config(dbname); 39 | } 40 | } 41 | 42 | Future config(String dbname) async { 43 | await MySqlSettings.config(dbname); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /bin/dcopydir.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:dcli/dcli.dart'; 11 | 12 | /// copies the source directory to the target directory 13 | void main(List args) { 14 | if (args.length != 2) { 15 | printerr(red('Expected 2 arguments found ${args.length}')); 16 | showUsage(); 17 | } 18 | 19 | final source = args[0]; 20 | final dest = args[1]; 21 | 22 | if (!exists(source)) { 23 | printerr(red('The source directory "$source" does not exist.')); 24 | showUsage(); 25 | } 26 | 27 | if (exists(dest)) { 28 | printerr(red('The destination directory "$dest" already exists.')); 29 | showUsage(); 30 | } 31 | 32 | if (confirm('Continue?')) { 33 | createDir(dest, recursive: true); 34 | print(green('Copying $source to $dest')); 35 | copyTree(source, dest, includeHidden: true); 36 | print(green('Done')); 37 | } 38 | } 39 | 40 | void showUsage() { 41 | print(blue('dcopydir ')); 42 | print('Recursively copies the source directory to target directory.'); 43 | print('Hidden files are included.'); 44 | print('The dest directory must NOT already exist'); 45 | exit(1); 46 | } 47 | -------------------------------------------------------------------------------- /bin/pub_get_all.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | import 'package:path/path.dart'; 10 | import 'package:pubspec_manager/pubspec_manager.dart'; 11 | 12 | /// Recursively runs pub get on all subdirectories. 13 | void main() { 14 | for (final project in find('pubspec.yaml').toList()) { 15 | try { 16 | final pubspec = PubSpec.loadFromPath(project); 17 | 18 | if (pubspec.dependencies.exists('flutter')) { 19 | print(blue('Flutter project: ${dirname(project)}')); 20 | if (which('flutter').notfound) { 21 | printerr(red('You need to install flutter to pub get this project')); 22 | } else { 23 | 'flutter pub get'.start( 24 | workingDirectory: dirname(project), 25 | progress: Progress.printStdErr()); 26 | } 27 | } else { 28 | print(blue('Dart: project: ${dirname(project)}')); 29 | 'dart pub get'.start( 30 | workingDirectory: dirname(project), 31 | progress: Progress.printStdErr()); 32 | } 33 | } catch (e) { 34 | printerr(red('pub get of ${dirname(project)} failed: $e')); 35 | } 36 | print(''); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /bin/eclipse_launcher.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:dcli/dcli.dart'; 11 | import 'package:path/path.dart'; 12 | 13 | /// dcli script generated by: 14 | /// dcli create ecliplse_launcher.dart 15 | /// 16 | /// See 17 | /// https://pub.dev/packages/dcli#-installing-tab- 18 | /// 19 | /// For details on installing dcli. 20 | /// 21 | 22 | /// eclipse_launcher.dart - create a desktop launcher for eclipse. 23 | void main(List args) { 24 | final installs = find('*', 25 | recursive: false, 26 | workingDirectory: join(HOME, 'apps', 'eclipse'), 27 | types: [FileSystemEntityType.directory]).toList(); 28 | 29 | final install = menu('Select eclipse version to use: ', options: installs); 30 | 31 | final path = join(HOME, '.local', 'share', 'applications', 'eclipse.desktop'); 32 | // create desktop.ini 33 | if (exists(path)) { 34 | delete(path); 35 | } 36 | 37 | path 38 | ..write(''' 39 | [Desktop Entry] 40 | Version=1.0 41 | Type=Application 42 | Name=Eclipse 43 | Comment=Jave IDE 44 | Categories=Development;IDE; 45 | Terminal=false''') 46 | ..append('Icon=${join(install, "icon.xpm")}') 47 | ..append('Exec=env GTK_THEME=Adwaita ${join(install, "eclipse")}'); 48 | 49 | print('Created:'); 50 | cat(path); 51 | } 52 | -------------------------------------------------------------------------------- /bin/simple_dev.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | 3 | import 'dart:io'; 4 | 5 | import 'package:dcli/dcli.dart'; 6 | 7 | void main() { 8 | if (!Shell.current.isPrivilegedProcess) { 9 | printerr(red('You must run this with sudo')); 10 | exit(1); 11 | } 12 | 13 | 'apt-get update'.run; 14 | 'apt-get install apt-transport-https'.run; 15 | 'wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/dart.gpg' 16 | .run; 17 | '''echo 'deb [signed-by=/usr/share/keyrings/dart.gpg arch=amd64] https://storage.googleapis.com/download.dartlang.org/linux/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list''' 18 | .run; 19 | 20 | final installList = ['dart', 'git', 'gh']; 21 | 22 | if (which('curl').notfound) { 23 | installList.add('curl'); 24 | } 25 | 26 | // pipe commands won't work. 27 | 'curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg' 28 | .run; 29 | 'chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg'.run; 30 | 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list' 31 | .run; 32 | 33 | 'apt-get update'.run; 34 | 'apt-get install -y ${installList.join(' ')}'.run; 35 | 36 | final email = ask('Your email address:'); 37 | final name = ask('Your name'); 38 | 'git config --global user.email "$email"'.run; 39 | 'git config --global user.name "$name"'.run; 40 | 41 | 'dart pub global activate dcli'.run; 42 | 'dart pub global activate onepub'.run; 43 | } 44 | -------------------------------------------------------------------------------- /bin/fetch.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:dcli_core/dcli_core.dart' as core; 13 | 14 | void main(List args) async { 15 | final parser = ArgParser()..addFlag('verbose', abbr: 'v', negatable: false); 16 | 17 | late final ArgResults parsed; 18 | try { 19 | parsed = parser.parse(args); 20 | } on FormatException catch (e) { 21 | printerr(red(e.message)); 22 | showUsage(parser); 23 | exit(1); 24 | } 25 | 26 | if (parsed.rest.length != 1) { 27 | printerr(red('You must pass the url as the one and only arg')); 28 | showUsage(parser); 29 | exit(1); 30 | } 31 | 32 | final url = parsed.rest[0]; 33 | await core.withTempFileAsync((file) async { 34 | await fetch(url: url, saveToPath: file, fetchProgress: showProgress); 35 | print(green('Data Recieved')); 36 | cat(file); 37 | }, create: false); 38 | } 39 | 40 | void showProgress(FetchProgress progress) { 41 | if (progress.status == FetchStatus.response) { 42 | print(blue('Response: ${progress.responseCode}')); 43 | } 44 | 45 | if (progress.headers != null) { 46 | print(blue('Headers')); 47 | progress.headers?.forEach((key, value) { 48 | print('$key=>${value.join(',')}'); 49 | }); 50 | } 51 | } 52 | 53 | void showUsage(ArgParser parser) { 54 | print('Gets url'); 55 | print('fetch '); 56 | 57 | print(parser.usage); 58 | } 59 | -------------------------------------------------------------------------------- /bin/clean.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | // this is a main. 9 | // ignore: prefer_relative_imports 10 | import 'dart:io'; 11 | 12 | import 'package:dcli/dcli.dart'; 13 | import 'package:path/path.dart'; 14 | 15 | /// Cleans up disk space usage. 16 | /// Cleans out unused docker objects 17 | /// Performs a git clean 18 | /// Finally runs hog to highlight directories that 19 | /// take up lots of space. 20 | 21 | void main(List args) { 22 | print(blue('cleaning .dart_tools..')); 23 | find('pubspec.yaml').forEach((path) { 24 | final tools = join(dirname(path), '.dart_tools'); 25 | if (exists(tools)) { 26 | print('Deleting $tools'); 27 | deleteDir(tools); 28 | } 29 | }); 30 | 31 | print(blue('Cleaning unused docker containers')); 32 | 'docker container prune -f'.run; 33 | 34 | print(blue('Pruning unused docker volumes ')); 35 | 'docker volume prune'.run; 36 | 37 | print(blue('Pruning docker objects')); 38 | 'docker system prune -a -f'.run; 39 | 40 | print(blue('Running git clean')); 41 | if (which('gitgc').notfound) { 42 | printerr(red('gitgc not found. Run dart pub global activate dcli_scripts')); 43 | exit(1); 44 | } 45 | 'gitgc'.start(terminal: true, workingDirectory: join(HOME, 'git')); 46 | 47 | print(blue('cleaning dcli test directories..')); 48 | if (exists('/tmp/dcli')) { 49 | deleteDir('/tmp/dcli'); 50 | } 51 | 52 | print(blue('Running hog')); 53 | 'hog disk'.start(terminal: true, workingDirectory: HOME); 54 | } 55 | -------------------------------------------------------------------------------- /lib/src/mysql/restore_command.dart: -------------------------------------------------------------------------------- 1 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 2 | * Unauthorized copying of this file, via any medium is strictly prohibited 3 | * Proprietary and confidential 4 | * Written by Brett Sutton , Jan 2022 5 | */ 6 | import 'package:args/command_runner.dart'; 7 | import 'package:dcli/dcli.dart'; 8 | 9 | import 'mysql.dart'; 10 | import 'mysql_settings.dart'; 11 | 12 | class RestoreCommand extends Command { 13 | @override 14 | String get description => ''' 15 | restores a database. 16 | dmysql restore [path to backup]'''; 17 | 18 | @override 19 | String get name => 'restore'; 20 | 21 | @override 22 | void run() { 23 | final args = 24 | getArgs(this, argResults, additionalArgs: ['']); 25 | final dbname = args[0]; 26 | final sqlFile = args[1]; 27 | 28 | restore(MySqlSettings.load(dbname), sqlFile); 29 | } 30 | 31 | void restore(MySqlSettings settings, String sqlFile) { 32 | print('restoring $sqlFile to ${settings.dbname}'); 33 | 34 | 'mysql --host ${settings.host} --port=${settings.port} ' 35 | '--user ${settings.user} --password="${settings.password}" ' 36 | '-e "drop database ${settings.dbname}"' 37 | .start(nothrow: true); 38 | 39 | 'mysql --host ${settings.host} --port=${settings.port} ' 40 | '--user ${settings.user} --password="${settings.password}" ' 41 | '-e "create database ${settings.dbname}"' 42 | .start(nothrow: true); 43 | 44 | 'mysql --host ${settings.host} --port=${settings.port} ' 45 | '--user ${settings.user} --password="${settings.password}" ' 46 | '--database ${settings.dbname} ' 47 | '-e "source $sqlFile"' 48 | .start(nothrow: true); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /bin/docker_dcli.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | 13 | /// 14 | /// Provides access to a clean ubuntu cli. 15 | /// 16 | /// You can run this script in two modes 17 | /// 18 | /// docker_dcli build - builds the docker container 19 | /// docker_dcli - launches the container with your pwd mounted into /home 20 | 21 | void main(List args) { 22 | Settings().setVerbose(enabled: false); 23 | final parser = ArgParser()..addCommand('build'); 24 | 25 | var build = false; 26 | ArgResults results; 27 | 28 | try { 29 | results = parser.parse(args); 30 | } on FormatException catch (e) { 31 | printerr(e.toString()); 32 | print('docker_dcli - starts the cli'); 33 | print('docker_dcli build - builds the docker image'); 34 | print(parser.usage); 35 | exit(1); 36 | } 37 | 38 | if (results.command != null) { 39 | build = results.command!.name == 'build'; 40 | if (!build) { 41 | throw ArgumentError('The command arg must be "build" or nothing.'); 42 | } 43 | } 44 | 45 | if (build) { 46 | // mount the local dcli files from .. 47 | 'sudo docker build -f ./dcli.docker -t dcli:dcli .'.run; 48 | print('Build complete. Run docker_dcli to start the docker cli'); 49 | exit(0); 50 | } 51 | 52 | print('Mounting host ${green(pwd)} into the container at ' 53 | '${orange('/home/local')}'); 54 | 55 | /// mount the current working directory 56 | 'docker run -v $pwd:/home/local --network host -it dcli:dcli /bin/bash'.run; 57 | } 58 | -------------------------------------------------------------------------------- /bin/post.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:dcli_core/dcli_core.dart' as core; 13 | 14 | /// dpath appname 15 | /// print the systems PATH variable contents and validates each path. 16 | 17 | void main(List args) async { 18 | final parser = ArgParser()..addFlag('verbose', abbr: 'v', negatable: false); 19 | 20 | late final ArgResults parsed; 21 | try { 22 | parsed = parser.parse(args); 23 | } on FormatException catch (e) { 24 | printerr(red(e.message)); 25 | showUsage(parser); 26 | exit(1); 27 | } 28 | 29 | if (parsed.rest.length != 1) { 30 | printerr(red('You must pass the url as the one and only arg')); 31 | showUsage(parser); 32 | exit(1); 33 | } 34 | 35 | final url = parsed.rest[0]; 36 | await core.withTempFileAsync((file) async { 37 | await fetch( 38 | url: url, 39 | method: FetchMethod.post, 40 | saveToPath: file, 41 | fetchProgress: showProgress); 42 | print(green('Data Recieved')); 43 | cat(file); 44 | }, create: false); 45 | } 46 | 47 | void showProgress(FetchProgress progress) { 48 | if (progress.status == FetchStatus.response) { 49 | print(blue('Response: ${progress.responseCode}')); 50 | } 51 | 52 | if (progress.headers != null) { 53 | print(blue('Headers')); 54 | progress.headers?.forEach((key, value) { 55 | print('$key=>${value.join(',')}'); 56 | }); 57 | } 58 | } 59 | 60 | void showUsage(ArgParser parser) { 61 | print('Post a post url'); 62 | print('post '); 63 | 64 | print(parser.usage); 65 | } 66 | -------------------------------------------------------------------------------- /bin/docker_push.dart: -------------------------------------------------------------------------------- 1 | #! /bin/env dcli 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:path/path.dart'; 13 | 14 | void main(List args) { 15 | final parser = ArgParser() 16 | ..addOption('repo', 17 | abbr: 'r', 18 | mandatory: true, 19 | help: 'The name of the docker repository to publish to.'); 20 | final project = DartProject.fromPath('.'); 21 | final projectRootPath = project.pathToProjectRoot; 22 | print('projectRoot $projectRootPath'); 23 | 24 | ArgResults parsed; 25 | try { 26 | parsed = parser.parse(args); 27 | } on FormatException catch (e) { 28 | printerr(red('Invalid CLI argument: ${e.message}')); 29 | exit(1); 30 | } 31 | 32 | final repo = parsed['repo'] as String; 33 | final projectName = project.pubSpec.name; 34 | final version = project.pubSpec.version; 35 | final name = '$repo/$projectName'; 36 | 37 | final imageTag = '$name:$version'; 38 | print('Pushing Docker image $imageTag.'); 39 | 40 | print('docker path: ${findDockerFilePath()}'); 41 | print(green('Building $projectName docker image')); 42 | 'docker build -t$imageTag .'.start(workingDirectory: findDockerFilePath()); 43 | print(green('Pushing docker image: $imageTag and latest')); 44 | final latestTag = '$name:latest'; 45 | 'docker image tag $imageTag $latestTag'.run; 46 | 'docker push $imageTag'.run; 47 | 'docker push $latestTag'.run; 48 | } 49 | 50 | String findDockerFilePath() { 51 | var current = pwd; 52 | while (current != rootPath) { 53 | if (exists(join(current, 'Dockerfile'))) { 54 | return current; 55 | } 56 | current = dirname(current); 57 | } 58 | return '.'; 59 | } 60 | -------------------------------------------------------------------------------- /bin/tcp_echo.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | 3 | import 'dart:convert'; 4 | import 'dart:io'; 5 | 6 | import 'package:args/args.dart'; 7 | 8 | /// Listen on the passed tcp port and echo any data back to the client. 9 | void main(List args) async { 10 | final parser = ArgParser() 11 | ..addOption('port', 12 | abbr: 'p', defaultsTo: '3001', help: 'set the port to listen on.'); 13 | 14 | late final int port; 15 | try { 16 | final parsed = parser.parse(args); 17 | port = int.tryParse(parsed['port'] as String) ?? 3001; 18 | } on FormatException catch (_) { 19 | showUsage(parser); 20 | } 21 | try { 22 | final serverSocket = await ServerSocket.bind('0.0.0.0', port); 23 | print('Server listening on ${serverSocket.address}:${serverSocket.port}'); 24 | 25 | await for (final socket in serverSocket) { 26 | await handleConnection(socket); 27 | } 28 | } catch (e) { 29 | print('Error: $e'); 30 | } 31 | } 32 | 33 | Future handleConnection(Socket socket) async { 34 | final remoteAddress = socket.remoteAddress; 35 | final remotePort = socket.remotePort; 36 | print('Client connected: $remoteAddress:$remotePort'); 37 | 38 | socket.listen( 39 | (data) async { 40 | final receivedString = utf8.decode(data); 41 | print('Received: $receivedString'); 42 | 43 | // Echo back the received data 44 | socket.write('Echo: $receivedString'); 45 | await socket.close(); 46 | }, 47 | onDone: () async { 48 | print('Client disconnected: $remoteAddress:$remotePort'); 49 | await socket.close(); 50 | }, 51 | onError: (Object error) async { 52 | print('Error: $error'); 53 | await socket.close(); 54 | }, 55 | cancelOnError: true, 56 | ); 57 | } 58 | 59 | void showUsage(ArgParser parser) { 60 | print(''' 61 | Listens to the passed TCP port and echos any request back to the client. 62 | Defaults to port 3001. 63 | '''); 64 | print(parser.usage); 65 | exit(1); 66 | } 67 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "dwhich", 9 | "request": "launch", 10 | "type": "dart", 11 | "program": "bin/dwhich.dart", 12 | "args": [ 13 | "dswitch" 14 | ] 15 | }, 16 | { 17 | "name": "dmysql - show usage", 18 | "request": "launch", 19 | "type": "dart", 20 | "program": "bin/dmysql.dart", 21 | "args": [ 22 | "backup" 23 | ] 24 | }, 25 | { 26 | "name": "dfind - ", 27 | "request": "launch", 28 | "type": "dart", 29 | "program": "bin/dfind.dart", 30 | "args": [ 31 | "-t", 32 | "kuma" 33 | ] 34 | }, 35 | { 36 | "name": "dfind - text", 37 | "request": "launch", 38 | "type": "dart", 39 | "program": "bin/dfind.dart", 40 | "args": [ 41 | "-t", 42 | "kuma", 43 | "*.dart" 44 | ] 45 | }, 46 | { 47 | "name": "dmysql - backup", 48 | "request": "launch", 49 | "type": "dart", 50 | "program": "bin/dmysql.dart", 51 | "args": [ 52 | "backup", 53 | "onepub" 54 | ], 55 | "pwd": "/home/bsutton/git/onepub.server/schema" 56 | }, 57 | { 58 | "name": "hex_dump", 59 | "request": "launch", 60 | "type": "dart", 61 | "program": "hexdump.dart", 62 | "args": [ 63 | "hexdump.dart" 64 | ] 65 | } 66 | ] 67 | } -------------------------------------------------------------------------------- /bin/dreplace.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | 13 | void main(List args) { 14 | final parser = ArgParser() 15 | ..addOption('dir', abbr: 'd', help: 'root directory to start search from') 16 | ..addOption('find', abbr: 'f', help: 'The text to find') 17 | ..addOption('replace', abbr: 'r', help: 'The text to replace "find" with'); 18 | 19 | final parsed = parser.parse(args); 20 | 21 | if (parsed.rest.isEmpty) { 22 | printerr(red('You must provide a list of files or globs to process')); 23 | showUsage(parser); 24 | } 25 | 26 | var workingDir = pwd; 27 | 28 | if (parsed.wasParsed('dir')) { 29 | workingDir = parsed['dir'] as String; 30 | } 31 | 32 | if (!parsed.wasParsed('find')) { 33 | printerr(red('You must provide a "find" argument')); 34 | showUsage(parser); 35 | } 36 | 37 | if (!parsed.wasParsed('replace')) { 38 | printerr(red('You must provide a "replace" argument')); 39 | showUsage(parser); 40 | } 41 | 42 | final from = parsed['find'] as String; 43 | final to = parsed['replace'] as String; 44 | 45 | workingDir = parsed['dir'] as String; 46 | 47 | final patterns = parsed.rest; 48 | 49 | for (final pattern in patterns) { 50 | print('scanning for $pattern'); 51 | find(pattern, workingDirectory: workingDir) 52 | .forEach((file) => update(file, from, to)); 53 | } 54 | } 55 | 56 | void update(String path, String from, String to) { 57 | print('processing $path'); 58 | replace(path, from, to, all: true); 59 | } 60 | 61 | void showUsage(ArgParser parser) { 62 | print('Searches for and replaces a text string in matching file ' 63 | 'patterns recursively'); 64 | print(parser.usage); 65 | exit(1); 66 | } 67 | -------------------------------------------------------------------------------- /bin/gituncommited.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:path/path.dart'; 13 | 14 | /// Search all subdirectories looking for git projects 15 | /// It then reports any that have uncommited files or which 16 | /// need to be pushed. 17 | void main(List args) { 18 | final parser = ArgParser() 19 | ..addFlag('detail', 20 | abbr: 'd', help: 'Shows a list of any uncommited files'); 21 | 22 | ArgResults results; 23 | try { 24 | results = parser.parse(args); 25 | } on FormatException catch (e) { 26 | printerr(red(e.message)); 27 | print(parser.usage); 28 | exit(1); 29 | } 30 | final detail = results['detail'] as bool; 31 | 32 | find('.git', includeHidden: true, types: [Find.directory]).forEach((gitPath) { 33 | var uncommited = []; 34 | gitPath = dirname(gitPath); 35 | // print('testing $gitPath'); 36 | try { 37 | uncommited = 'git status --porcelain' 38 | .start(workingDirectory: gitPath, progress: Progress.capture()) 39 | .toList(); 40 | 41 | if (uncommited.isNotEmpty) { 42 | print('Uncommited files in $gitPath'); 43 | if (detail) { 44 | uncommited.forEach(print); 45 | } 46 | } else { 47 | /// check if code has been pushed 48 | final status = 'git status' 49 | .start(workingDirectory: gitPath, progress: Progress.capture()) 50 | .toList() 51 | .join('\n'); 52 | 53 | if (!status.contains('Your branch is up to date with')) { 54 | print('Push required on $gitPath'); 55 | } 56 | } 57 | } catch (e) { 58 | print('error: $e'); 59 | print(uncommited); 60 | } 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /bin/gitcreation_date.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:convert'; 9 | import 'dart:io'; 10 | 11 | import 'package:args/args.dart'; 12 | import 'package:dcli/dcli.dart'; 13 | import 'package:dcli_core/dcli_core.dart' as core; 14 | 15 | /// Retrives the date a github repo was created. 16 | void main(List args) async { 17 | final parser = ArgParser() 18 | ..addFlag( 19 | 'verbose', 20 | abbr: 'v', 21 | negatable: false, 22 | help: 'Logs additional details to the cli', 23 | ) 24 | ..addOption('owner', abbr: 'o', help: 'The github owner of the repo.') 25 | ..addOption('repo', abbr: 'r', help: 'The github repo name of the repo.'); 26 | 27 | final parsed = parser.parse(args); 28 | 29 | if (parsed.wasParsed('verbose')) { 30 | Settings().setVerbose(enabled: true); 31 | } 32 | 33 | if (!parsed.wasParsed('owner')) { 34 | printerr(red('You must pass a owner')); 35 | showUsage(parser); 36 | } 37 | 38 | final owner = parsed['owner'] as String; 39 | 40 | if (!parsed.wasParsed('repo')) { 41 | printerr(red('You must pass a repo')); 42 | showUsage(parser); 43 | } 44 | 45 | final repo = parsed['repo'] as String; 46 | 47 | await core.withTempFileAsync((jsonFile) async { 48 | final url = 'https://api.github.com/repos/$owner/$repo'; 49 | print('fetching $url'); 50 | await fetch(url: url, saveToPath: jsonFile); 51 | 52 | final json = 53 | jsonDecode(read(jsonFile).toList().join('\n')) as Map; 54 | if (json.containsKey('created_at')) { 55 | print(json['created_at']); 56 | } else { 57 | print(json); 58 | } 59 | }, create: false); 60 | } 61 | 62 | void showUsage(ArgParser parser) { 63 | print('Usage: gitsyncfork.dart -v -prompt '); 64 | print(parser.usage); 65 | exit(1); 66 | } 67 | -------------------------------------------------------------------------------- /bin/install_flutter.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:dcli/dcli.dart'; 9 | import 'package:path/path.dart'; 10 | 11 | void main() { 12 | print('https://flutter.dev/docs/get-started/install/linux'); 13 | 14 | 'sudo apt install dart'.run; 15 | 16 | //var dartPaths = 'which dart'.toList(); 17 | //if (dartPaths.length != 1) 18 | //{ 19 | //print('unable to find dart on the path. Please check the install)'; 20 | //exit(1); 21 | //} 22 | // 23 | //var dartPath = dartPaths[0]; 24 | 25 | // find a way to search for this. 26 | const dartPath = '/usr/lib/dart/bin'; 27 | 28 | addPathToProfile(dartPath); 29 | 30 | final pubCachePath = '$HOME/.pub-cache/bin'; 31 | addPathToProfile(pubCachePath); 32 | 33 | '$dartPath/pub global activate dcli'.run; 34 | '$pubCachePath/dcli install'.run; 35 | 36 | final appsPath = join(HOME, 'apps'); 37 | 38 | if (!exists(appsPath)) { 39 | createDir(appsPath); 40 | } 41 | 42 | 'git clone https://github.com/flutter/flutter.git' 43 | .start(workingDirectory: appsPath); 44 | 45 | 'flutter/bin/flutter precache'.start(workingDirectory: appsPath); 46 | 47 | 'flutter/bin/flutter doctor -v'.start(workingDirectory: appsPath); 48 | 49 | addPathToProfile('$appsPath/flutter/bin'); 50 | 51 | which('flutter'); 52 | 53 | print('now install Android Stdio'); 54 | print('https://developer.android.com/studio'); 55 | 56 | print('now setup and android emulator as per:'); 57 | print('https://flutter.dev/docs/get-started/install/linux'); 58 | } 59 | 60 | void addPathToProfile(String path) { 61 | final profileLines = read('$HOME/.profile').toList(); 62 | var found = false; 63 | for (final line in profileLines) { 64 | if (line.contains(path)) { 65 | found = true; 66 | break; 67 | } 68 | } 69 | 70 | if (!found) { 71 | print('"adding $path to $HOME/.profile'); 72 | '$HOME/.profile'.append('export PATH="\$PATH:$path"'); 73 | print('You will need to logout for your path to be available'); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /bin/dfind.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:strings/strings.dart'; 13 | 14 | /// ```bash 15 | /// dfind 16 | /// ``` 17 | /// Recursively search for files that match the passed glob pattern. 18 | 19 | void main(List args) { 20 | final parser = ArgParser() 21 | ..addFlag('help', abbr: 'h', help: 'Display this help information.') 22 | ..addOption('text', abbr: 't', help: 'Search for text within files.') 23 | ..addFlag('warnings', abbr: 'w', help: 'Show skipped files.'); 24 | 25 | final results = parser.parse(args); 26 | 27 | if (results['help'] as bool) { 28 | print(''' 29 | dfind [options] 30 | Finds files that match the passed glob pattern 31 | If you pass in --text then dfind will search within the matched files 32 | 33 | ${parser.usage} 34 | '''); 35 | exit(0); 36 | } 37 | 38 | final searchText = results['text'] as String?; 39 | final showWarnings = results['warnings'] as bool; 40 | 41 | if (results.rest.isEmpty) { 42 | printerr('''You must provide a filename (glob pattern) to match on.'''); 43 | exit(1); 44 | } 45 | 46 | final pattern = results.rest[0]; 47 | 48 | if (Strings.isNotBlank(searchText)) { 49 | print(green( 50 | '''Searching for text "$searchText" within files matching pattern "$pattern"''')); 51 | 52 | find(pattern, includeHidden: true).forEach((file) { 53 | try { 54 | if (File(file).readAsStringSync().contains(searchText!)) { 55 | print(orange('Found "$searchText" in $file')); 56 | } 57 | } on FileSystemException catch (e) { 58 | if (e.message == "Failed to decode data using encoding 'utf-8'") { 59 | if (showWarnings) { 60 | print('Skipping binary file: $file'); 61 | } 62 | } else { 63 | print('Error reading file $file: ${e.message}'); 64 | } 65 | } 66 | }); 67 | } else { 68 | print('Searching for files matching pattern $pattern'); 69 | 70 | find(pattern, includeHidden: true).forEach(print); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /bin/certbot_renew.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:path/path.dart'; 13 | 14 | //const tomcatPath = '$HOME/apps/tomcat vi ./apache-tomcat-9.0.16/conf/server.xml'; 15 | 16 | void main(List args) { 17 | final parser = ArgParser()..addFlag('production', abbr: 'p'); 18 | final result = parser.parse(args); 19 | 20 | if (result.rest.length != 2) { 21 | print(''' 22 | You must provide a certificate name like 'host.somedomain.org' and your email address. 23 | '''); 24 | usage(); 25 | exit(0); 26 | } 27 | 28 | final certName = result.rest[0]; 29 | final emailaddress = result.rest[1]; 30 | final useProduction = result['production'] as bool; 31 | 32 | const letsStaging = 'https://acme-staging-v02.api.letsencrypt.org/directory'; 33 | 34 | const letsProduction = 'https://acme-v02.api.letsencrypt.org/directory'; 35 | 36 | var server = letsStaging; 37 | if (useProduction) { 38 | server = letsProduction; 39 | } 40 | 41 | // check that docker is installed 42 | if (which('docker').notfound) { 43 | printerr(red('You need to install docker first')); 44 | exit(1); 45 | } 46 | 47 | print('Using: $server'); 48 | 49 | // namecheap api user and key. 50 | final username = read('namecheap_username').firstLine; 51 | final key = read('namecheap_key').firstLine; 52 | 53 | final saveDir = join(pwd, 'certificates'); 54 | 55 | env['NAMECHEAP_API_USER'] = username; 56 | env['NAMECHEAP_API_KEY'] = key; 57 | 'docker run -v $saveDir:/.lego --env NAMECHEAP_API_USER --env NAMECHEAP_API_KEY goacme/lego --server=$server --dns namecheap --email $emailaddress --domains "$certName" --accept-tos run' 58 | .run; 59 | print('keys have been saved to $saveDir'); 60 | } 61 | 62 | void usage() { 63 | print(''' 64 | Usage: 65 | certbot_renew.dart [--production|-p] 66 | 67 | If the production switch isn't passed then a trial cert is obtained from the 68 | staging server. 69 | 70 | e.g. 71 | certbot_renew.dart host.somedomain.org myemail@somedomain.org 72 | '''); 73 | } 74 | -------------------------------------------------------------------------------- /bin/dmailhog.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:path/path.dart'; 13 | 14 | /// installs (if necessary) and runs mailhog 15 | 16 | void main(List args) { 17 | final parser = ArgParser() 18 | ..addFlag('help', abbr: 'h', help: 'Shows this help message') 19 | ..addFlag('shutdown', abbr: 'd', help: 'Shutdown mailhog'); 20 | 21 | ArgResults parsed; 22 | try { 23 | parsed = parser.parse(args); 24 | } on FormatException catch (e) { 25 | printerr(red(e.message)); 26 | showUsage(parser); 27 | exit(1); 28 | } 29 | 30 | if (parsed['help'] as bool) { 31 | showUsage(parser); 32 | exit(1); 33 | } 34 | 35 | if (parsed['shutdown'] as bool) { 36 | shutdownMailHog(); 37 | } else { 38 | install(); 39 | 40 | startMailHog(); 41 | } 42 | } 43 | 44 | void shutdownMailHog() { 45 | final processes = ProcessHelper().getProcessesByName('mailhog'); 46 | if (processes.isNotEmpty) { 47 | 'killall ${processes.first.name}'.run; 48 | } 49 | } 50 | 51 | void showUsage(ArgParser parser) { 52 | print('Runs and if required installs mailhog '); 53 | print(parser.usage); 54 | } 55 | 56 | void startMailHog() { 57 | print(green('Starting mailhog')); 58 | 59 | print(orange('Access mail hog at: http://localhost:8025')); 60 | mailHogAppPath.run; 61 | } 62 | 63 | void install() { 64 | if (!exists(mailHogDirectoryPath)) { 65 | createDir(mailHogDirectoryPath, recursive: true); 66 | } 67 | 68 | if (!exists(mailHogAppPath)) { 69 | print(orange('Installing mailhog')); 70 | 'wget https://github.com/mailhog/MailHog/releases/download/v1.0.0/MailHog_linux_amd64' 71 | .start(workingDirectory: mailHogDirectoryPath); 72 | 'cp MailHog_linux_amd64 $mailHogAppPath' 73 | .start(privileged: true, workingDirectory: mailHogDirectoryPath); 74 | 'chmod +x $mailHogAppPath'.start(privileged: true, detached: true); 75 | } 76 | } 77 | 78 | String get mailHogDirectoryPath => join(HOME, 'apps', 'mailhog'); 79 | 80 | String get mailHogAppPath => join(mailHogDirectoryPath, mailHogAppname); 81 | 82 | String get mailHogAppname => 'mailhog'; 83 | -------------------------------------------------------------------------------- /bin/dcompress.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | 13 | var extensionToCommand = { 14 | '.tar.gz': 'tar -zxvf %F', 15 | '.tar': 'tar -xvf %F', 16 | '.xz': 'tar -xvf %F', 17 | '.rar': 'unrar e %F', 18 | '.zip': 'unzip %F' 19 | }; 20 | 21 | /// ```bash 22 | /// dcompress 23 | /// ``` 24 | /// de-compresses a variety of file formats. 25 | void main(List args) { 26 | final parser = ArgParser(); 27 | 28 | ArgResults results; 29 | 30 | try { 31 | results = parser.parse(args); 32 | } on FormatException catch (e) { 33 | printerr(red(e.message)); 34 | showUsage(parser); 35 | return; 36 | } 37 | 38 | if (results.rest.length != 1) { 39 | print('Expands a compressed file.'); 40 | print(''); 41 | printerr(red('You must provide the name of the file to expand.')); 42 | print('The file will be expanded in the current working directory.'); 43 | exit(1); 44 | } 45 | 46 | final tarFile = results.rest[0]; 47 | 48 | if (!exists(tarFile)) { 49 | printerr(red("The passed file ${truepath(tarFile)} doesn't exist")); 50 | exit(2); 51 | } 52 | 53 | var cmd = getCommand(tarFile); 54 | 55 | if (cmd != null) { 56 | cmd = cmd.replaceAll('%F', tarFile); 57 | try { 58 | cmd.run; 59 | } catch (e) { 60 | if (e is RunException && e.exitCode == 2) { 61 | printerr(red('The extractor for $tarFile $cmd could not be found.')); 62 | } 63 | // otherwise supress the exception as the command will print 64 | // its own error. 65 | } 66 | } else { 67 | printerr(red('The file $tarFile does not have a know extension.')); 68 | printerr(green('Supported extensions are:')); 69 | for (final key in extensionToCommand.keys) { 70 | printerr(' $key'); 71 | } 72 | exit(1); 73 | } 74 | } 75 | 76 | void showUsage(ArgParser parser) { 77 | print('Expands a compress file, support a wide variety of file types. '); 78 | print(parser.usage); 79 | } 80 | 81 | String? getCommand(String tarFile) { 82 | for (final extension in extensionToCommand.keys) { 83 | if (tarFile.endsWith(extension)) { 84 | return extensionToCommand[extension]; 85 | } 86 | } 87 | return null; 88 | } 89 | -------------------------------------------------------------------------------- /bin/gactivate.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | 3 | import 'dart:io'; 4 | 5 | import 'package:args/args.dart'; 6 | import 'package:dcli/dcli.dart'; 7 | import 'package:path/path.dart'; 8 | import 'package:pubspec_manager/pubspec_manager.dart'; 9 | 10 | /// dcli script generated by: 11 | /// dcli create %scriptname% 12 | /// 13 | /// See 14 | /// https://pub.dev/packages/dcli#-installing-tab- 15 | /// 16 | /// For details on installing dcli. 17 | /// 18 | void main(List args) async { 19 | final parser = ArgParser() 20 | ..addFlag('compile', 21 | abbr: 'c', 22 | help: 'compiles a global activated package and installs it ' 23 | 'into the dcli bin'); 24 | 25 | final ArgResults argResult; 26 | try { 27 | argResult = parser.parse(args); 28 | } on FormatException catch (e) { 29 | printerr(red(e.message)); 30 | print(parser.usage); 31 | exit(1); 32 | } 33 | final compile = argResult['compile'] as bool; 34 | 35 | if (compile) { 36 | await compilePackage(argResult); 37 | } else { 38 | if (args.length != 1) { 39 | printerr(red('You must pass a path.')); 40 | exit(1); 41 | } 42 | 43 | 'dart pub global activate -spath ${args[0]}'.run; 44 | } 45 | } 46 | 47 | Future compilePackage(ArgResults argResults) async { 48 | if (argResults.rest.length != 1) { 49 | printerr(red('You must provide the name of a package to compile')); 50 | } 51 | 52 | final packageName = argResults.rest[0]; 53 | 54 | final version = PubCache().findPrimaryVersion(packageName); 55 | final pathToPackage = 56 | PubCache().pathToPackage(packageName, version.toString()); 57 | 58 | // we can't compile in the .pub_cache as pub get throws errors 59 | // so copy the package to a temp dir. 60 | await withTempDirAsync((tempDir) async { 61 | copyTree(pathToPackage, tempDir); 62 | final pubspec = PubSpec.loadFromPath(join(tempDir, 'pubspec.yaml')); 63 | final execs = pubspec.executables; 64 | if (execs.length == 0) { 65 | printerr(red('No executables listed in the pubspec.yaml')); 66 | throw Exception('No executables listed in the pubspec.yaml'); 67 | } 68 | final binDir = join(tempDir, 'bin'); 69 | for (final executable in execs.list) { 70 | 'dcli compile ${executable.scriptPath}'.start(workingDirectory: tempDir); 71 | final installPath = join(Settings().pathToDCliBin, executable.name); 72 | if (exists(installPath)) { 73 | delete(installPath); 74 | } 75 | move(join(binDir, basenameWithoutExtension(executable.scriptPath)), 76 | installPath); 77 | } 78 | }); 79 | } 80 | -------------------------------------------------------------------------------- /bin/dsetver.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:pub_release/pub_release.dart' as pub; 13 | import 'package:pubspec_manager/pubspec_manager.dart'; 14 | 15 | /// Updates the version no. on your dart package by changing pubspec.yaml 16 | /// version and genearating src/version/version.g.dart which 17 | /// contains a globl variable packageVersion with the version no. 18 | /// Usage: 19 | /// dsetver --version=x.x.x 20 | /// dsetver to display a menu to with suggested version nos. 21 | void main(List args) { 22 | final parser = ArgParser() 23 | ..addOption('version', abbr: 'v', help: 'Set the version no.'); 24 | 25 | final ArgResults results; 26 | try { 27 | results = parser.parse(args); 28 | } on FormatException catch (e) { 29 | printerr(red(e.message)); 30 | showUsage(parser); 31 | exit(1); 32 | } 33 | 34 | final version = results['version'] as String?; 35 | 36 | pub.Version? parsedVersion; 37 | 38 | final project = DartProject.findProject('.'); 39 | if (project == null) { 40 | printerr(red( 41 | 'Unable to find a project in the current directory or any parent.')); 42 | exit(1); 43 | } 44 | 45 | final pathToPubspec = DartProject.fromPath('.').pathToPubSpec; 46 | 47 | if (version != null) { 48 | try { 49 | parsedVersion = pub.Version.parse(version); 50 | } on FormatException catch (_) { 51 | printerr(red('The version no. "$version" passed to setVersion is not a ' 52 | 'valid version.')); 53 | exit(1); 54 | } 55 | } else { 56 | final currentVersion = pub.version(pubspecPath: pathToPubspec); 57 | if (currentVersion == null) { 58 | printerr(red('Unable to get the current version.')); 59 | printerr('Check that you are running from the projects root diretory'); 60 | exit(1); 61 | } 62 | 63 | parsedVersion = pub.askForVersion(currentVersion); 64 | } 65 | 66 | pub.updateVersion( 67 | parsedVersion, PubSpec.loadFromPath(pathToPubspec), pathToPubspec); 68 | } 69 | 70 | void showUsage(ArgParser parser) { 71 | print(''); 72 | print(green('Usage:')); 73 | print(green('dsetver [--version]')); 74 | print(''); 75 | print("If the --version switch isn't passed " 76 | 'then you are prompted to enter a version.'); 77 | print(parser.usage); 78 | } 79 | -------------------------------------------------------------------------------- /bin/gitupdate_remote.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:path/path.dart'; 13 | 14 | /// Updated a git 'remote' to a new owner. 15 | /// 16 | /// Scans all subdirs for git projects 17 | /// and then updates the remote to point the new owner. 18 | /// git_update_remote --owner noojee 19 | /// Handy if you move repos between owners. 20 | void main(List args) { 21 | final parser = ArgParser() 22 | ..addOption('owner', 23 | abbr: 'o', mandatory: true, help: 'The owner/organisation of the repo'); 24 | 25 | ArgResults results; 26 | try { 27 | results = parser.parse(args); 28 | } on FormatException catch (e) { 29 | printerr(red(e.message)); 30 | 31 | print(parser.usage); 32 | exit(1); 33 | } 34 | final owner = results['owner'] as String; 35 | 36 | find('.git', includeHidden: true, types: [Find.directory]).forEach((gitPath) { 37 | final repoDir = dirname(gitPath); 38 | // print('Considering $repoDir'); 39 | var remote = 'git remote -v' 40 | .start(workingDirectory: repoDir, progress: Progress.capture()) 41 | .toList() 42 | .first; 43 | remote = remote.replaceAll(RegExp(r'\s+'), ' '); 44 | 45 | if (remote.contains('bitbucket')) { 46 | print(blue('remote $remote')); 47 | final parts = remote.split(' '); 48 | if (parts.length != 3) { 49 | printerr('Unexpected response: $remote'); 50 | exit(1); 51 | } 52 | 53 | print('parts 1 ${parts[1]}'); 54 | final repoParts = parts[1].split(':'); 55 | if (repoParts.length != 2) { 56 | printerr('Unexpected response: ${parts[1]}'); 57 | exit(1); 58 | } 59 | if (!repoParts[1].contains('$owner/')) { 60 | printerr(red("Skipping $remote as it isn't on the $owner repo")); 61 | } else { 62 | final repo = basenameWithoutExtension(repoParts[1]); 63 | 64 | print(orange( 65 | 'updating remote for $repoDir to git@github.com:$owner/$repo.git')); 66 | 67 | 'git remote set-url origin git@github.com:$owner/$repo.git' 68 | .start(workingDirectory: repoDir, progress: Progress.print()); 69 | 'git pull'.start(workingDirectory: repoDir, progress: Progress.print()); 70 | 'git push'.start(workingDirectory: repoDir, progress: Progress.print()); 71 | } 72 | } else { 73 | // print(blue('Skipping $repoDir')); 74 | } 75 | }); 76 | } 77 | -------------------------------------------------------------------------------- /lib/src/mysql/mysql.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:args/command_runner.dart'; 12 | import 'package:dcli/dcli.dart'; 13 | 14 | import 'backup_command.dart'; 15 | import 'cli_command.dart'; 16 | import 'config_command.dart'; 17 | import 'mysql_settings.dart'; 18 | import 'restore_command.dart'; 19 | 20 | late CommandRunner runner; 21 | 22 | Future mysqlRun(List args) async { 23 | runner = CommandRunner('dmysql', 24 | 'Run various mysql commands using a config to save the credintials') 25 | ..addCommand(BackupCommand()) 26 | ..addCommand(RestoreCommand()) 27 | ..addCommand(CliCommand()) 28 | ..addCommand(ConfigCommand()); 29 | 30 | runner.argParser 31 | .addFlag('debug', abbr: 'd', help: 'Output debug information'); 32 | 33 | try { 34 | await runner.run(args); 35 | } on MissingConfigurationException catch (e) { 36 | printerr(red(e.message)); 37 | showUsage(runner); 38 | } on UsageException catch (e) { 39 | printerr(e.message); 40 | showUsage(runner); 41 | } on ExitException catch (e) { 42 | if (e.message.isNotEmpty) { 43 | printerr(red(e.message)); 44 | } 45 | exit(e.exitCode); 46 | } 47 | } 48 | 49 | void showUsage(CommandRunner runner) { 50 | print(''' 51 | 52 | ${blue('dmysql')} 53 | Runs various mysql command using a settings file containing the user credentials. 54 | 55 | ${green('To run:')} 56 | ${DartScript.self.basename} 57 | 58 | ${green('To configure settings for a db:')} 59 | ${DartScript.self.basename} --config 60 | '''); 61 | print(runner.usage); 62 | exit(1); 63 | } 64 | 65 | List getArgs(Command command, ArgResults? argResults, 66 | {List additionalArgs = const []}) { 67 | Settings().setVerbose(enabled: command.globalResults!['debug'] as bool); 68 | if (argResults!.rest.isEmpty) { 69 | printerr('You must pass a database name.'); 70 | showUsage(runner); 71 | throw ExitException(1, ''); 72 | } 73 | final results = [argResults.rest[0]]; 74 | 75 | for (var i = 1; i < additionalArgs.length + 1; i++) { 76 | final arg = additionalArgs[i - 1]; 77 | if (argResults.rest.length < i + 1) { 78 | printerr("You must pass '$arg'.\n"); 79 | showUsage(runner); 80 | throw ExitException(1, ''); 81 | } 82 | results.add(argResults.rest[i]); 83 | } 84 | return results; 85 | } 86 | 87 | String getDbArg(ArgResults? argResults, {required int position}) => 88 | argResults!.rest[position]; 89 | -------------------------------------------------------------------------------- /bin/gitadd_team_to_repository.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | /// Script to migrate bitbucket repos into github. 9 | /// You need to provide a csv file containing a list of repos on bitbucket 10 | /// The csv file must contain two columns: 11 | /// repo_name, repo_url 12 | /// e.g. 13 | /// `adfiler,https://@bitbucket.org/>/.git` 14 | /// 15 | /// You need to provide a 'github.yaml' file (in the cwd) 16 | /// that contains a git personal access token 17 | /// ```yaml 18 | /// gittoken: ASDFZcvaskjwerf 19 | /// ``` 20 | library; 21 | 22 | import 'dart:io'; 23 | 24 | import 'package:args/args.dart'; 25 | import 'package:dcli/dcli.dart'; 26 | import 'package:settings_yaml/settings_yaml.dart'; 27 | 28 | /// Adds the given team to every repo owned by the passed organisation. 29 | void main(List args) { 30 | final argParser = ArgParser() 31 | ..addOption('team', 32 | abbr: 't', 33 | mandatory: true, 34 | help: 'Name of the team to assign to the repos') 35 | ..addOption('owner', 36 | abbr: 'o', 37 | mandatory: true, 38 | help: 'Name of owner/org that owns the repos') 39 | ..addOption('permission', 40 | abbr: 'p', 41 | allowed: ['admin', 'push', 'pull'], 42 | defaultsTo: 'pull', 43 | help: 'Sets the permission the team has on the repos.'); 44 | 45 | ArgResults results; 46 | 47 | try { 48 | results = argParser.parse(args); 49 | } on FormatException catch (e) { 50 | printerr(e.message); 51 | print(argParser.usage); 52 | exit(1); 53 | } 54 | 55 | final team = results['team'] as String; 56 | final owner = results['owner'] as String; 57 | final permission = results['permission'] as String; 58 | 59 | final json = 'gh repo list --json "owner,name,url" $owner -L 10000' 60 | .parser() 61 | .jsonDecode() as List; 62 | 63 | for (final repo in json) { 64 | final map = repo as Map; 65 | final name = map['name'] as String; 66 | final ownerMap = map['owner'] as Map; 67 | final owner = ownerMap['login'] as String; 68 | // final url = repo['url'] as String; 69 | 70 | addToTeam(owner, team, name, permission: permission); 71 | } 72 | } 73 | 74 | void addToTeam(String owner, String team, String repoName, 75 | {required String permission}) { 76 | final settings = SettingsYaml.load(pathToSettings: 'github.yaml'); 77 | final token = settings['gittoken'] as String; 78 | print('adding $team to $owner/$repoName'); 79 | ''' 80 | curl -X PUT 81 | --header "authorization: Bearer $token" 82 | -H "Accept: application/vnd.github.v3+json" 83 | https://api.github.com/orgs/$owner/teams/$team/repos/$owner/$repoName 84 | -d '{"permission":"$permission"}''' 85 | .run; 86 | } 87 | -------------------------------------------------------------------------------- /bin/bitbucket_import.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | /// Script to migrate bitbucket repos into github. 9 | /// You need to provide a csv file containing a list of repos on bitbucket 10 | /// The csv file must contain two columns: 11 | /// repo_name, repo_url 12 | /// e.g. 13 | /// `adfiler,https://@bitbucket.org/>/.git` 14 | library; 15 | 16 | import 'dart:io'; 17 | 18 | import 'package:dcli/dcli.dart'; 19 | import 'package:path/path.dart'; 20 | import 'package:settings_yaml/settings_yaml.dart'; 21 | 22 | void main() async { 23 | const list = 'repo.list.csv'; 24 | if (!exists(list)) { 25 | printerr('List not found'); 26 | exit(1); 27 | } 28 | final repos = read(list).toList(); 29 | 30 | for (final repo in repos) { 31 | if (repo.trim().isEmpty) { 32 | continue; 33 | } 34 | final parts = repo.split(','); 35 | final name = parts[0].replaceAll('"', ''); 36 | final url = parts[1].replaceAll('"', ''); 37 | await import(name, url); 38 | } 39 | } 40 | 41 | Future import(String name, String url) async { 42 | final settings = SettingsYaml.load(pathToSettings: 'bitbucket.yaml'); 43 | final password = settings['password'] as String; 44 | final token = settings['gittoken'] as String; 45 | final username = settings['gitusername'] as String; 46 | final owner = settings['gitowner'] as String; 47 | 48 | Settings().setVerbose(enabled: false); 49 | 50 | await createGithubRepo(owner, name); 51 | 52 | await withTempDirAsync((dir) async { 53 | print('Cloning into $dir'); 54 | final url0 = url.replaceAll('@', ':$password@'); 55 | 56 | 'git clone --bare $url0' 57 | .start(workingDirectory: dir, progress: Progress.print()); 58 | 59 | 'git push --mirror https://$username:$token@github.com/$owner/$name.git' 60 | .start( 61 | workingDirectory: join(dir, '$name.git'), 62 | progress: Progress.print()); 63 | }, keep: true); 64 | } 65 | 66 | Future createGithubRepo(String owner, String name) async { 67 | await withTempDirAsync((dir) async { 68 | final url = 'git@github.com:$owner/$name.git'; 69 | 'gh repo create $url --confirm --private' 70 | .start(workingDirectory: dir, progress: Progress.print()); 71 | 'git init'.start(workingDirectory: dir, progress: Progress.print()); 72 | touch(join(dir, 'README.md'), create: true); 73 | 'git add README.md' 74 | .start(workingDirectory: dir, progress: Progress.print()); 75 | 'git commit -m "first commit"' 76 | .start(workingDirectory: dir, progress: Progress.print()); 77 | 78 | 'git remote add origin $url' 79 | .start(workingDirectory: dir, progress: Progress.print()); 80 | 81 | 'git push -u origin master' 82 | .start(workingDirectory: dir, progress: Progress.print()); 83 | }); 84 | } 85 | -------------------------------------------------------------------------------- /lib/src/docker/publish.dart: -------------------------------------------------------------------------------- 1 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 2 | * Unauthorized copying of this file, via any medium is strictly prohibited 3 | * Proprietary and confidential 4 | * Written by Brett Sutton , Jan 2022 5 | */ 6 | 7 | import 'dart:io'; 8 | 9 | import 'package:dcli/dcli.dart' as dcli; 10 | import 'package:dcli/dcli.dart' hide confirm; 11 | import 'package:uuid/uuid.dart'; 12 | 13 | /// Designed to build and publish a Docker file built using dcli and 14 | /// some fairly opinionated setup. 15 | /// 16 | /// Your docker file should have the following line just before 17 | /// the packages git clone line. 18 | /// ```docker 19 | /// RUN mkdir -p /BUILD_TOKEN/ 20 | /// ``` 21 | /// We will run a: 22 | /// * dcli pack 23 | /// * git add * 24 | /// * git commit -m 'release' 25 | /// * git push 26 | /// 27 | /// You need to provide the path to your dockerfile via [pathToDockerFile]. 28 | /// The repository name will be generated from your pubspec.yaml and 29 | /// the [repository] argument in the form: 30 | /// 31 | /// `/:` 32 | /// 33 | /// If you pass the [clean] = true then the image will be rebuilt from scratch 34 | /// If you pass the [fresh] = true then we search for the BUILD_TOKEN line 35 | /// in your docker file and update the token UUID. This will cause the docker 36 | /// image to be rebuilt from the BUILD_TOKEN line. This can be used if you need 37 | /// to re-clone a git repo (or any similar action). 38 | /// By default the image will be pushed to docker hub unless 39 | /// you pass [push] = false. 40 | /// By default we ask you to confirm the build process. Pass [confirm] = false 41 | /// to skip the question. 42 | /// If you pass [pack] = true then the 'dcli pack' command will be run 43 | /// before the build starts. 44 | /// 45 | /// The [buildArgs] is a list of arguments that are passed to the docker build 46 | /// command. 47 | void dockerPublish( 48 | {required String pathToDockerFile, 49 | required String repository, 50 | bool pack = false, 51 | bool clean = false, 52 | bool fresh = false, 53 | bool push = true, 54 | bool confirm = true, 55 | List buildArgs = const []}) { 56 | final project = DartProject.self; 57 | final name = project.pubSpec.name.value; 58 | final version = project.pubSpec.version.toString(); 59 | 60 | if (confirm && !dcli.confirm('Building $name $version')) { 61 | printerr(red('Stopping build')); 62 | exit(1); 63 | } 64 | 65 | if (pack) { 66 | 'dcli pack'.run; 67 | fresh = true; 68 | } 69 | 70 | print(blue('Building $name $version')); 71 | 72 | final tag = '$repository/$name:$version'; 73 | final latest = '$repository/$name:latest'; 74 | 75 | var cleanArg = ''; 76 | if (clean) { 77 | cleanArg = ' --no-cache'; 78 | } 79 | 80 | if (fresh) { 81 | final uuid = const Uuid().v4().replaceAll('-', ''); 82 | replace(pathToDockerFile, RegExp('RUN mkdir -p /BUILD_TOKEN/.*'), 83 | 'RUN mkdir -p /BUILD_TOKEN/$uuid'); 84 | } 85 | 86 | 'docker build ${buildArgs.join(' ')} $cleanArg -t $tag ' 87 | '-t $latest -f $pathToDockerFile .' 88 | .run; 89 | 90 | if (push) { 91 | 'docker push $tag'.run; 92 | 'docker push $latest'.run; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /bin/gitsyncfork.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | 13 | /// Syncs the current git repo with the upstream repo it was forked from. 14 | void main(List args) { 15 | final parser = ArgParser() 16 | ..addFlag( 17 | 'verbose', 18 | abbr: 'v', 19 | negatable: false, 20 | help: 'Logs additional details to the cli', 21 | ) 22 | ..addOption('owner', 23 | abbr: 'o', help: 'The github owner of the upstream repo.') 24 | ..addOption('repo', 25 | abbr: 'r', help: 'The github repo name of the upstream repo.'); 26 | 27 | final parsed = parser.parse(args); 28 | 29 | if (parsed.wasParsed('verbose')) { 30 | Settings().setVerbose(enabled: true); 31 | } 32 | 33 | if (!parsed.wasParsed('owner')) { 34 | printerr(red('You must pass a owner')); 35 | showUsage(parser); 36 | } 37 | 38 | final upstreamOwner = parsed['owner'] as String; 39 | 40 | if (!parsed.wasParsed('repo')) { 41 | printerr(red('You must pass a repo')); 42 | showUsage(parser); 43 | } 44 | 45 | final upstreamRepo = parsed['repo'] as String; 46 | 47 | if (!hasUpstream(upstreamOwner, upstreamRepo)) { 48 | addUpstream(upstreamOwner, upstreamRepo); 49 | } 50 | 51 | 'git fetch upstream'.run; 52 | 53 | final defaultBranch = getDefaultBranch(); 54 | 55 | 'git checkout $defaultBranch'.run; 56 | 57 | 'git merge upstream/$defaultBranch'.run; 58 | } 59 | 60 | bool hasUpstream(String upstreamOwner, String upstreamRepo) { 61 | final remotes = getRemotes(); 62 | var found = false; 63 | for (final remote in remotes) { 64 | if (remote.contains('upstream') && 65 | remote.contains(upstreamOwner) && 66 | remote.contains(upstreamRepo)) { 67 | found = true; 68 | break; 69 | } 70 | } 71 | 72 | return found; 73 | } 74 | 75 | void addUpstream(String upstreamOwner, String upstreamRepo) { 76 | 'git remote add upstream https://github.com/$upstreamOwner/$upstreamRepo'.run; 77 | 'git remote -v'.run; 78 | } 79 | 80 | List getRemotes() => 'git remote -v'.toList(); 81 | 82 | String getDefaultBranch() { 83 | final lines = 'git remote show origin'.toList(skipLines: 3); 84 | 85 | if (lines.isEmpty) { 86 | throw Exception('Unable to get default branch name'); 87 | } 88 | 89 | final line = lines.first.trim(); 90 | 91 | final parts = line.split(' '); 92 | 93 | return parts[2]; 94 | } 95 | 96 | // for future use. 97 | // ignore: unreachable_from_main 98 | String getBranch() { 99 | final line = 'git status'.firstLine; 100 | 101 | if (line == null) { 102 | throw Exception('Unable to get branch name'); 103 | } 104 | 105 | final parts = line.trim().split(' '); 106 | 107 | return parts[2]; 108 | } 109 | 110 | void showUsage(ArgParser parser) { 111 | print('Usage: gitsyncfork.dart -v -prompt '); 112 | print(parser.usage); 113 | exit(1); 114 | } 115 | -------------------------------------------------------------------------------- /bin/dport.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | 13 | /// 14 | /// Finds and displays details of any process which is listening on 15 | /// the given port no. 16 | void main(List args) { 17 | final parser = ArgParser()..addFlag('verbose', abbr: 'v', negatable: false); 18 | 19 | final results = parser.parse(args); 20 | 21 | final verbose = results['verbose'] as bool; 22 | Settings().setVerbose(enabled: verbose); 23 | 24 | if (results.rest.length != 1) { 25 | print(red('You must pass the port no to search for.')); 26 | print(green('Usage:')); 27 | print(green(' dport ')); 28 | exit(1); 29 | } 30 | 31 | final port = results.rest[0]; 32 | 33 | final portNo = int.tryParse(port); 34 | if (portNo == null) { 35 | printerr(red('Invalid port No. $port')); 36 | print(parser.usage); 37 | exit(1); 38 | } 39 | 40 | final found = viaNetstat(portNo); 41 | 42 | if (!found) { 43 | print('No process found to be running on $portNo.'); 44 | } 45 | } 46 | 47 | bool viaNetstat(int? portNo) { 48 | var found = false; 49 | final lines = []; 50 | 'netstat -pnat'.start(privileged: true, progress: Progress(lines.add)); 51 | 52 | for (final line in lines.skip(1)) { 53 | if (line.contains(':$portNo ') && line.contains('LISTEN')) { 54 | final columns = line.replaceAll(RegExp(r'\s+'), ' ').trim().split(' '); 55 | if (columns.length == 7) { 56 | var parts = columns[6].split('/'); 57 | final pid = parts[0]; 58 | var name = parts[1]; 59 | if (name.endsWith(':')) { 60 | name = name.substring(0, name.length - 1); 61 | } 62 | 63 | parts = line.split(' '); 64 | final protocol = parts[0]; 65 | 66 | final parentPID = ProcessHelper().getParentPID(int.tryParse(pid) ?? 0); 67 | final parentName = ProcessHelper().getProcessName(parentPID); 68 | 69 | print('${orange('PID: $pid Process: $name Protocol: $protocol')} ' 70 | '${blue('Parent: $parentPID Parent PID: $parentName')}'); 71 | found = true; 72 | } else { 73 | print(line); 74 | } 75 | } 76 | } 77 | 78 | return found; 79 | } 80 | 81 | // for future use. 82 | // ignore: unreachable_from_main 83 | bool viaLsof(int portNo) { 84 | // 'ss -tulpn src :$portNo'.start(privileged: true); 85 | 86 | final processes = 'lsof -n -P -i +c 13'.toList(skipLines: 1); 87 | const found = false; 88 | 89 | for (final process in processes) { 90 | final regexp = RegExp(r':\d+'); 91 | 92 | final match = regexp.firstMatch(process); 93 | if (match != null) { 94 | final port = match.group(0)!.substring(1); 95 | 96 | final processPortNo = int.tryParse(port); 97 | 98 | if (processPortNo == null) { 99 | print(orange("Couldn't parse $process")); 100 | continue; 101 | } 102 | 103 | if (processPortNo == portNo) { 104 | final parts = process.split(' '); 105 | final processName = parts[0]; 106 | final processPID = parts[1]; 107 | print('$processName $processPID'); 108 | } 109 | } 110 | } 111 | return found; 112 | } 113 | -------------------------------------------------------------------------------- /bin/dwhich.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:dcli/dcli.dart'; 11 | import 'package:dcli_scripts/src/dwhich/args.dart'; 12 | import 'package:dcli_scripts/src/dwhich/exit_exception.dart'; 13 | import 'package:path/path.dart'; 14 | 15 | /// dwhich appname - searches for 'appname' on the path 16 | void main(List cliArgs) { 17 | final Args args; 18 | var found = false; 19 | var exectuable = false; 20 | 21 | try { 22 | args = Args.parse(cliArgs); 23 | 24 | Settings().setVerbose(enabled: args.debug); 25 | 26 | // validation(args, () => 'Path: ${env['PATH']}'); 27 | 28 | final paths = dedupPaths(args); 29 | 30 | String? priorPath; 31 | 32 | for (final path in paths) { 33 | // validation(args, () => 'Searching: ${truepath(path)}'); 34 | if (!validatePath(path, args, priorPath)) { 35 | continue; 36 | } 37 | 38 | final pathToCmd = containsCommand(truepath(path, args.command)); 39 | if (pathToCmd != null) { 40 | found = true; 41 | if (!isExecutable(pathToCmd)) { 42 | print('Found at: $pathToCmd but it is not executable.'); 43 | continue; 44 | } 45 | exectuable = true; 46 | 47 | print('Found at: $pathToCmd'); 48 | 49 | // found an exectuable. 50 | if (args.first) { 51 | break; 52 | } 53 | } 54 | priorPath = path; 55 | } 56 | } on ExitException catch (e) { 57 | printerr(red(e.message)); 58 | if (e.exitCode == ExitException.invalidArgs) { 59 | Args.showUsage(); 60 | } 61 | exit(e.exitCode); 62 | } 63 | final goodPath = printProblems(args); 64 | 65 | exit(ExitException.mapExitCode( 66 | found: found, exectuable: exectuable, goodPath: goodPath)); 67 | } 68 | 69 | bool validatePath(String path, Args args, String? lastPath) { 70 | var valid = true; 71 | // validation(args, () => 'Searching: ${truepath(path)}'); 72 | if (path.isEmpty) { 73 | validation(args, () => 'Empty path found'); 74 | if (Platform.isLinux) { 75 | path = '.'; 76 | 77 | /// current 78 | validation( 79 | args, 80 | () => orange('WARNING: current directory is on your path due ' 81 | 'to an empty path ' 82 | '${lastPath == null ? '' : 'after $lastPath'} .')); 83 | } else { 84 | validation(args, () => red(''' 85 | Found empty path ${lastPath == null ? '' : 'after $lastPath'}.''')); 86 | valid = false; 87 | } 88 | } 89 | 90 | if (valid && !exists(path)) { 91 | validation(args, () => red('The path $path does not exist.')); 92 | valid = false; 93 | } 94 | return valid; 95 | } 96 | 97 | /// Returns true if there we no problems dectected with PATH 98 | bool printProblems(Args args) { 99 | if (problems.isNotEmpty) { 100 | print(''); 101 | print(orange('Problems:')); 102 | for (final problem in problems) { 103 | printerr(' ${orange(problem)}'); 104 | } 105 | } 106 | return problems.isEmpty; 107 | } 108 | 109 | /// reports any duplicate path entries. 110 | Set dedupPaths(Args args) { 111 | final paths = {}; 112 | 113 | for (final path in PATH) { 114 | if (paths.contains(path)) { 115 | validation(args, () => orange('Found duplicated path: $path in PATH')); 116 | } else { 117 | paths.add(path); 118 | } 119 | } 120 | return paths; 121 | } 122 | 123 | String? containsCommand(String cmd) { 124 | if (!Platform.isWindows || extension(cmd).isNotEmpty) { 125 | return exists(cmd) ? cmd : null; 126 | } 127 | 128 | for (final ext in env['PATHEXT']!.split(';')) { 129 | final fullCmd = '$cmd$ext'; 130 | if (exists(fullCmd)) { 131 | return fullCmd; 132 | } 133 | } 134 | return null; 135 | } 136 | 137 | final problems = []; 138 | void validation(Args args, String Function() message) { 139 | if (args.validate) { 140 | problems.add(message()); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /lib/src/mysql/mysql_settings.dart: -------------------------------------------------------------------------------- 1 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 2 | * Unauthorized copying of this file, via any medium is strictly prohibited 3 | * Proprietary and confidential 4 | * Written by Brett Sutton , Jan 2022 5 | */ 6 | import 'package:dcli/dcli.dart'; 7 | import 'package:path/path.dart'; 8 | import 'package:settings_yaml/settings_yaml.dart'; 9 | 10 | import 'backup_command.dart'; 11 | 12 | /// Connects you to a mysql cli pulling settings (username/password) 13 | /// from a local settings file. 14 | /// Use 15 | 16 | var pathToDMysql = '$HOME/.dmysql'; 17 | 18 | class MySqlSettings { 19 | final String host; 20 | 21 | final int port; 22 | 23 | final String user; 24 | 25 | final String password; 26 | 27 | final String dbname; 28 | 29 | MySqlSettings( 30 | {required this.host, 31 | required this.port, 32 | required this.user, 33 | required this.password, 34 | required this.dbname}); 35 | 36 | factory MySqlSettings.load(String dbname) { 37 | final pathToDbSettings = pathToSettings(dbname); 38 | if (!exists(pathToDbSettings)) { 39 | throw MissingConfigurationException(''' 40 | No configuration exists for $dbname at ${truepath(pathToDbSettings)}. 41 | Check your database name or run dmysql config $dbname'''); 42 | } 43 | final settings = SettingsYaml.load(pathToSettings: pathToDbSettings); 44 | final host = settings['host'] as String? ?? 'localhost'; 45 | final port = settings['port'] as int? ?? 3306; 46 | final user = settings['user'] as String? ?? 'root'; 47 | final password = settings['password'] as String? ?? ''; 48 | 49 | return MySqlSettings( 50 | host: host, port: port, user: user, password: password, dbname: dbname); 51 | } 52 | 53 | static Future config(String dbname) async { 54 | final pathToDbSettings = MySqlSettings.pathToSettings(dbname); 55 | 56 | if (!exists(dirname(pathToDbSettings))) { 57 | createDir(dirname(pathToDbSettings), recursive: true); 58 | } 59 | final settings = SettingsYaml.load(pathToSettings: pathToDbSettings); 60 | 61 | settings['dbname'] = dbname; 62 | settings['host'] = ask('host:', 63 | defaultValue: settings['host'] as String?, 64 | validator: Ask.any([ 65 | Ask.fqdn, 66 | Ask.ipAddress(), 67 | Ask.inList(['localhost', '127.0.0.1']) 68 | ])); 69 | 70 | settings['port'] = int.parse(ask('port:', 71 | defaultValue: (settings['port'] as int? ?? 3306).toString(), 72 | validator: Ask.integer)); 73 | 74 | settings['user'] = ask('user:', 75 | defaultValue: settings['user'] as String?, validator: Ask.required); 76 | 77 | settings['password'] = ask('password:', 78 | defaultValue: settings['password'] as String?, 79 | validator: Ask.required, 80 | hidden: true); 81 | 82 | if (!_checkDbExists(settings)) { 83 | if (!confirm(orange( 84 | "The database $dbname doesn't exist. Do you want to continue?"))) { 85 | throw ExitException(1, ''); 86 | } 87 | } 88 | 89 | await settings.save(); 90 | return MySqlSettings.load(dbname); 91 | } 92 | 93 | static String pathToSettings(String dbname) => join(pathToDMysql, dbname); 94 | 95 | static bool _checkDbExists(SettingsYaml settings) { 96 | final host = settings['host'] as String; 97 | final port = settings['port'] as int; 98 | final database = settings['dbname'] as String; 99 | final user = settings['user'] as String; 100 | final password = settings['password'] as String; 101 | final result = 'mysqlshow --host=$host --port=$port ' 102 | '--user=$user --password="$password" $database' 103 | .start(nothrow: true, progress: Progress.capture()); 104 | 105 | if (result.exitCode != 0) { 106 | final text = result.toParagraph(); 107 | 108 | if (text.contains('Unknown database')) { 109 | return false; 110 | } else { 111 | throw ExitException(result.exitCode!, text); 112 | } 113 | } 114 | 115 | return true; 116 | } 117 | } 118 | 119 | class MissingConfigurationException implements Exception { 120 | String message; 121 | 122 | MissingConfigurationException(this.message); 123 | 124 | @override 125 | String toString() => message; 126 | } 127 | -------------------------------------------------------------------------------- /bin/vscode_backup.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:path/path.dart'; 13 | 14 | /// dcli script generated by: 15 | /// dcli create vscode_backup.dart 16 | /// 17 | /// See 18 | /// https://pub.dev/packages/dcli#-installing-tab- 19 | /// 20 | /// For details on installing dcli. 21 | /// 22 | 23 | var backupfile = '.vscode_extension.bak'; 24 | 25 | void main(List args) { 26 | final parser = ArgParser()..addCommand('backup'); 27 | final restoreParser = parser.addCommand('restore') 28 | ..addFlag('latest', abbr: 'l', defaultsTo: true); 29 | parser.addCommand('uninstall'); 30 | 31 | final result = parser.parse(args); 32 | 33 | if (result.command == null) { 34 | usage(parser); 35 | exit(1); 36 | } 37 | 38 | switch (result.command!.name) { 39 | case 'backup': 40 | backup(); 41 | 42 | case 'restore': 43 | restore(restoreParser, args.sublist(1)); 44 | 45 | case 'uninstall': 46 | uninstall(); 47 | } 48 | } 49 | 50 | void backup() { 51 | final extensions = 'code --show-versions --list-extensions'.toList(); 52 | 53 | if (exists(backupfile)) { 54 | if (!confirm('overwrite backupfile: $backupfile?')) { 55 | exit(1); 56 | } 57 | backupfile.truncate(); 58 | } 59 | 60 | extensions.forEach(backupfile.append); 61 | 62 | print('extension have been backed up to $backupfile'); 63 | } 64 | 65 | List getCurrent() => 'code --list-extensions'.toList(); 66 | 67 | void restore(ArgParser parser, List args) { 68 | if (!exists(backupfile)) { 69 | print('Unable to find the backupfile ${absolute(backupfile)}'); 70 | print('restore did not complete'); 71 | exit(1); 72 | } 73 | 74 | final result = parser.parse(args); 75 | final latest = result['latest'] as bool; 76 | 77 | final extensions = read(backupfile).toList(); 78 | 79 | var line = 0; 80 | for (final extension in extensions) { 81 | line++; 82 | final parts = extension.split('@'); 83 | 84 | if (parts.length != 2) { 85 | throw Exception('The backupfile ${absolute(backupfile)} contains an ' 86 | 'invalid line ($line) $extension. ' 87 | 'Expected format is @ '); 88 | } 89 | final name = parts[0]; 90 | 91 | // if (current.contains(name)) { 92 | // continue; 93 | // } 94 | 95 | if (latest) { 96 | print('removing $name'); 97 | 'code --install-extension $name'.run; 98 | } else { 99 | 'code --install-extension $extension'.run; 100 | } 101 | } 102 | } 103 | 104 | void uninstall() { 105 | // Doing a backup is likely to over write the backup 106 | // with an incorrect list if extensions of the 107 | // uninstall had previously failed. 108 | // if (confirm(prompt: 'Would you like to backup your extensions first?')) { 109 | // backup(); 110 | // } 111 | 112 | final current = getCurrent(); 113 | 114 | var extensions = read(backupfile).toList(); 115 | 116 | final retries = []; 117 | var hasRetries = false; 118 | 119 | do { 120 | hasRetries = false; 121 | for (final extension in extensions) { 122 | final parts = extension.split('@'); 123 | final name = parts[0]; 124 | // var version = parts[1]; 125 | 126 | if (!current.contains(name)) { 127 | print('The extension $name is not installed. Skipping'); 128 | } else { 129 | try { 130 | 'code --uninstall-extension $name'.run; 131 | } on RunException catch (e) { 132 | final msg = e.message; 133 | if (msg.startsWith('Cannot uninstall extension') && 134 | msg.endsWith('depends on this.')) { 135 | hasRetries = true; 136 | retries.add(extension); 137 | print('adding $name to retry list has it has a dependency'); 138 | } 139 | } 140 | } 141 | } 142 | if (hasRetries) { 143 | extensions = retries; 144 | retries.clear(); 145 | } 146 | } while (hasRetries); 147 | } 148 | 149 | void usage(ArgParser parser) { 150 | print(''' 151 | Usage: 152 | vscode_backup.dart backup 153 | backups up all your vscode extensions 154 | vscode_backup.dart restore <--latest> 155 | restores all your vscode extensions. 156 | If you pass --latest (or -l) then it will upgrade 157 | the extension to the latest version as part of the install. 158 | vscode_backup.dart unistall 159 | uninstalls all of your vscode extensions. 160 | '''); 161 | } 162 | -------------------------------------------------------------------------------- /bin/add_gnome_launcher.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:path/path.dart'; 13 | 14 | String? name; 15 | List? categories; 16 | late bool terminal; 17 | String? comment; 18 | String? iconPath; 19 | String? exePath; 20 | 21 | var parser = ArgParser(); 22 | 23 | /// 24 | /// Creates a gnome launcher. 25 | /// 26 | void main(List args) { 27 | Settings().setVerbose(enabled: false); 28 | 29 | parser 30 | ..addOption('name', 31 | help: 'Name of the application to be displayed in the gnome menu') 32 | ..addMultiOption('categories', 33 | defaultsTo: ['Development'], 34 | help: 35 | "Gnome list of categories. ''Controls where in the gnome menu the " 36 | "entry appears. e.g. 'Development'") 37 | ..addOption('terminal', 38 | defaultsTo: 'true', 39 | help: 'If true (the default) then the app is launched ' 40 | 'in a terminal window.') 41 | ..addOption('comment', help: 'Adds a comment to the Gnome menu item') 42 | ..addOption('iconPath', help: 'Path to an icon for the Gnome menu') 43 | ..addOption('exePath', help: 'Path to an executable to be run'); 44 | 45 | final parsed = parser.parse(args); 46 | 47 | name = getRequiredString(parsed, 'name'); 48 | comment = parsed['comment'] as String?; 49 | terminal = getBool(parsed, 'terminal'); 50 | categories = getList(parsed, 'categories'); 51 | iconPath = getPath(parsed, 'iconPath'); 52 | exePath = getRequiredPath(parsed, 'exePath'); 53 | 54 | writeDesktopEntry(); 55 | } 56 | 57 | String getRequiredPath(ArgResults parsed, String option) { 58 | final path = getRequiredString(parsed, option)!; 59 | 60 | if (!exists(path)) { 61 | print(red('The provided path for $option does not exists.')); 62 | showUsage(); 63 | } 64 | 65 | return truepath(path); 66 | } 67 | 68 | String? getPath(ArgResults parsed, String option) { 69 | if (!parsed.wasParsed(option)) { 70 | return null; 71 | } 72 | 73 | final path = parsed[option] as String; 74 | 75 | if (!exists(path)) { 76 | print(red('The provided path for $option does not exists.')); 77 | showUsage(); 78 | } 79 | 80 | return truepath(path); 81 | } 82 | 83 | String? getRequiredString(ArgResults parsed, String option) { 84 | if (!parsed.wasParsed(option)) { 85 | print(red('You must provide the --$option argument')); 86 | showUsage(); 87 | } 88 | return parsed[option] as String?; 89 | } 90 | 91 | // for future use. 92 | // ignore: unreachable_from_main 93 | bool getRequiredBool(ArgResults parsed, String option) { 94 | if (!parsed.wasParsed(option)) { 95 | print(red('You must provide the --$option argument')); 96 | showUsage(); 97 | } 98 | return parsed[option] == 'true'; 99 | } 100 | 101 | bool getBool(ArgResults parsed, String option) => parsed[option] == 'true'; 102 | 103 | // for future use. 104 | // ignore: unreachable_from_main 105 | List? getRequiredList(ArgResults parsed, String option) { 106 | if (!parsed.wasParsed(option)) { 107 | print(red('You must provide the --$option argument')); 108 | showUsage(); 109 | } 110 | 111 | return parsed[option] as List?; 112 | } 113 | 114 | List? getList(ArgResults parsed, String option) => 115 | parsed[option] as List?; 116 | 117 | void showUsage() { 118 | print(''); 119 | print(green('Usage:')); 120 | print('./add_gnome_laucher.dart [options]'); 121 | print(parser.usage); 122 | exit(-1); 123 | } 124 | 125 | void writeDesktopEntry() { 126 | final path = join(HOME, '.local', 'share', 'applications', 127 | '${name!.replaceAll(RegExp('[^a-zA-Z0-9_]'), '_')}.desktop'); 128 | // create desktop.ini 129 | if (exists(path)) { 130 | delete(path); 131 | } 132 | 133 | final content = StringBuffer()..write(''' 134 | [Desktop Entry] 135 | Version=1.0 136 | Type=Application 137 | Name=$name 138 | '''); 139 | 140 | if (comment != null) { 141 | content.write('Comment=$comment\n'); 142 | } 143 | 144 | content 145 | ..write('Categories=${categories!.join(';')}\n') 146 | ..write('Terminal=$terminal\n'); 147 | 148 | if (iconPath != null) { 149 | content.write('Icon=$iconPath\n'); 150 | } 151 | 152 | if (terminal) { 153 | content.write('''gnome-terminal -e 'bash -c "$exePath;bash"' '''); 154 | } else { 155 | content.write('Exec=$exePath\n'); 156 | } 157 | 158 | path.write(content.toString()); 159 | 160 | print('Created: (in ${truepath(path)})\n'); 161 | 162 | cat(path); 163 | } 164 | -------------------------------------------------------------------------------- /bin/artifactory.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'package:args/args.dart'; 9 | import 'package:dcli/dcli.dart'; 10 | import 'package:docker2/docker2.dart'; 11 | 12 | /// The port that artifactory will listen on. 13 | var port = '8081'; 14 | var port2 = '8082'; 15 | var bind = '127.0.0.1'; 16 | var name = 'artifactory'; 17 | 18 | var imageName = 'docker.bintray.io/jfrog/artifactory-oss:latest'; 19 | 20 | /// installs, starts/stops the artifactory docker container. 21 | void main(List args) { 22 | // if (!DartScript.self.isCompiled) { 23 | // printerr('You must run this as a compiled dart script ' 24 | // 'as sudo is required'); 25 | // exit(1); 26 | // } 27 | // if (!Shell.current.isPrivilegedUser) { 28 | // printerr('You must run this command as sudo.'); 29 | // exit(1); 30 | // } 31 | 32 | Settings().setVerbose(enabled: true); 33 | final parser = ArgParser() 34 | ..addFlag('install', 35 | abbr: 'i', help: 'Install the artifactory OSS docker image') 36 | ..addFlag('run', 37 | abbr: 'r', 38 | help: 'Run the artifactory docker image. This is the default action ') 39 | ..addFlag('delete', 40 | abbr: 'd', 41 | help: 'Delete the artifactory docker container. ' 42 | 'The volume will be unaffected.') 43 | ..addFlag('start', 44 | abbr: 's', help: 'Runs artifactory docker image as a daemon.') 45 | ..addFlag('stop', abbr: 't', help: 'Stops the artifactory docker process') 46 | ..addFlag('attach', 47 | abbr: 'a', help: 'Attach to the artifactory docker cli'); 48 | 49 | final parsed = parser.parse(args); 50 | if (parsed['install'] as bool) { 51 | install(); 52 | } else if (parsed['delete'] as bool) { 53 | delete(); 54 | } else if (parsed['start'] as bool) { 55 | start(daemon: true); 56 | } else if (parsed['stop'] as bool) { 57 | stop(); 58 | } else if (parsed['attach'] as bool) { 59 | attach(); 60 | } else { 61 | /// default action is run. 62 | start(daemon: false); 63 | } 64 | } 65 | 66 | void stop() { 67 | print(blue('Stopping Artifactory')); 68 | final container = Docker().findContainerByName(name); 69 | if (container == null) { 70 | printerr(red("The artifactory container doesn't exist. Run '$name -i'")); 71 | } else { 72 | container.stop(); 73 | } 74 | } 75 | 76 | void attach() { 77 | print(blue('Attaching to the Artifactory cli')); 78 | final container = Docker().findContainerByName(name); 79 | if (container == null) { 80 | printerr(red("The artifactory container doesn't exist. Run '$name -i'")); 81 | } else { 82 | container.cli(); 83 | } 84 | } 85 | 86 | void start({required bool daemon}) { 87 | final container = Docker().findContainerByName(name); 88 | if (container != null && container.isRunning) { 89 | printerr(orange('The $name container is already running.')); 90 | return; 91 | } 92 | 93 | if (!daemon) { 94 | print(blue('Starting Artifactory in interactive mode.')); 95 | } 96 | 97 | final image = Docker().findImageByName(imageName); 98 | if (image == null) { 99 | printerr(red( 100 | "The artificatory image isn't installed. Run ./artifactory.dart --install")); 101 | return; 102 | } 103 | 104 | //Shell.current.withPrivileges(() { 105 | // 'chown -R 1030:1030 /var/opt/jfrog/artifactory'.run; 106 | // chown('/var/opt/jfrog/artifactory', 107 | // user: '1030', group: '1030', recursive: true); 108 | // }); 109 | Docker().run(image, 110 | argString: 111 | 112 | /// list on primary and secondary artifactory ports and mount 113 | /// a host volume. 114 | '-p $bind:$port:8081 -p $bind:$port2:8082 -v /var/opt/jfrog/artifactory:/var/opt/jfrog/artifactory', 115 | daemon: daemon); 116 | 117 | if (daemon) { 118 | print(blue('Artifactory daemon has started')); 119 | } 120 | 121 | // 'docker start --name artifactory -d -p 8081:8081 docker.bintray.io/jfrog/artifactory-oss:latest' 122 | // .run; 123 | } 124 | 125 | void install() { 126 | print(blue('Installing the Artifactory OSS docker image')); 127 | Docker().pull(imageName); 128 | print(blue('Creating the $name container')); 129 | 130 | print(blue('Installing Nginx-LE')); 131 | PubCache().globalActivate('nginx_le'); 132 | } 133 | 134 | void delete() { 135 | print(blue('deleting the docker container')); 136 | 137 | final container = Docker().findContainerByName(name); 138 | if (container != null) { 139 | if (container.isRunning) { 140 | printerr(orange('Stopping the $name container.')); 141 | container.stop(); 142 | } 143 | printerr(orange('Deleting the $name container.')); 144 | container.delete(); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /bin/hexdump.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | 13 | /// Outputs a hexi-decimal representation of a file 14 | /// along with an asci representation. 15 | 16 | void main(List args) { 17 | final parser = ArgParser() 18 | ..addOption('width', 19 | abbr: 'w', 20 | defaultsTo: '16', 21 | help: 'Controls no. of hex characters output per line.') 22 | ..addFlag('offset', 23 | abbr: 'o', negatable: false, help: 'Suppress the offset on each line.') 24 | ..addFlag('ascii', 25 | abbr: 'a', negatable: false, help: 'Suppress ascii output.') 26 | ..addFlag('help', 27 | abbr: 'h', negatable: false, help: 'Shows the usage message.'); 28 | 29 | ArgResults parsed; 30 | try { 31 | parsed = parser.parse(args); 32 | } on FormatException catch (e) { 33 | printerr(red(e.message)); 34 | showUsage(parser); 35 | exit(1); 36 | } 37 | 38 | if (parsed['help'] as bool) { 39 | showUsage(parser); 40 | exit(1); 41 | } 42 | if (parsed.rest.length != 1) { 43 | printerr(red('You must provide one file as an argument.')); 44 | showUsage(parser); 45 | exit(1); 46 | } 47 | 48 | final file = parsed.rest[0]; 49 | if (!exists(file)) { 50 | printerr(red('The file ${truepath(file)} does not exist.')); 51 | showUsage(parser); 52 | exit(1); 53 | } 54 | 55 | if (!isFile(file)) { 56 | printerr(red('$truepath(file)} is not a file.')); 57 | showUsage(parser); 58 | exit(1); 59 | } 60 | 61 | final width = int.tryParse(parsed['width'] as String); 62 | 63 | if (width == null) { 64 | printerr(red('Width must be an integer. Found ${parsed['width']}')); 65 | showUsage(parser); 66 | exit(1); 67 | } 68 | 69 | final showOffset = !(parsed['offset'] as bool); 70 | 71 | final showAscii = !(parsed['ascii'] as bool); 72 | 73 | dump(file, width, parser, showOffset: showOffset, showAscii: showAscii); 74 | } 75 | 76 | void dump(String file, int width, ArgParser parser, 77 | {required bool showOffset, required bool showAscii}) { 78 | withOpenFile(file, (openFile) { 79 | final buffer = List.filled(width, 0); 80 | 81 | try { 82 | var read = 0; 83 | var offset = 0; 84 | 85 | /// read the file into the buffer. 86 | while ((read = openFile.readIntoSync(buffer)) != 0) { 87 | var count = 0; 88 | 89 | // if requested show the byte offset for the current line. 90 | if (showOffset) { 91 | echo('${'$offset'.padLeft(6, '0')}: '); 92 | offset += width; 93 | } 94 | 95 | // dump hex version of buffer 96 | for (final val in buffer) { 97 | count++; 98 | if (count > read) { 99 | echo(' '); 100 | } else { 101 | echo(val.toRadixString(16).padLeft(2, '0')); 102 | } 103 | if (count.isEven) { 104 | echo(' '); 105 | } 106 | } 107 | count = 1; 108 | echo(' '); 109 | 110 | /// dump ascii version of buffer 111 | if (showAscii) { 112 | for (final val in buffer) { 113 | final char = isPrintable(val) ? String.fromCharCode(val) : ' '; 114 | echo(char); 115 | 116 | count++; 117 | if (count > read) { 118 | break; 119 | } 120 | } 121 | } 122 | print(''); 123 | } 124 | } on FileSystemException catch (e) { 125 | printerr(red('Error reading file ${truepath(file)}')); 126 | printerr(e.osError == null ? e.message : e.osError!.message); 127 | showUsage(parser); 128 | } 129 | }, fileMode: FileMode.read); 130 | } 131 | 132 | /// Replaces all non-printable characters in value with a space. 133 | /// tabs, newline etc are all considered non-printable. 134 | // ignore: unreachable_from_main 135 | String replaceNoPrintable(String value) { 136 | final charCodes = []; 137 | 138 | for (final codeUnit in value.codeUnits) { 139 | if (isPrintable(codeUnit)) { 140 | charCodes.add(codeUnit); 141 | } else { 142 | charCodes.add(20); 143 | } 144 | } 145 | 146 | return String.fromCharCodes(charCodes); 147 | } 148 | 149 | bool isPrintable(int codeUnit) { 150 | var printable = true; 151 | 152 | if (codeUnit < 33) { 153 | printable = false; 154 | } 155 | if (codeUnit >= 127) { 156 | printable = false; 157 | } 158 | 159 | return printable; 160 | } 161 | 162 | void showUsage(ArgParser parser) { 163 | print('Usage:'); 164 | print('hexdump '); 165 | print('Outputs a hexidecimal representation of the passed file.'); 166 | print(parser.usage); 167 | } 168 | -------------------------------------------------------------------------------- /bin/dsort.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | 10 | import 'package:args/args.dart'; 11 | import 'package:dcli/dcli.dart'; 12 | import 'package:dcli/src/util/file_sort.dart'; 13 | import 'package:path/path.dart'; 14 | 15 | /// dsort 16 | /// 17 | /// ```bash 18 | /// dsort --field-delimiter= --linedelimiter= --key= 19 | /// --output output 20 | /// 21 | /// =1[type][direction],3,7,1-7 22 | /// = 23 | /// s - case sensitive string sort - the default 24 | /// S - case insensitive string sort 25 | /// n - numeric sort 26 | /// m - month name sort 27 | /// 28 | /// [direction]= 29 | /// a - ascending - the default 30 | /// d - descending 31 | /// 32 | /// e.g. 33 | /// 34 | /// dsort -fd=, -ld=\n --sortkey=1nd,2,3sd,1-7nd unsorted.txt 35 | /// ``` 36 | /// 37 | 38 | const fieldDelimiterOption = 'field-delimiter'; 39 | const lineDelimiterOption = 'line-delimiter'; 40 | const sortkeyOption = 'sortkey'; 41 | const outputOption = 'output'; 42 | 43 | void main(List args) async { 44 | await dsort(args); 45 | } 46 | 47 | Future dsort(List args) async { 48 | final columns = []; 49 | String? fieldDelimiter; 50 | String? lineDelimiter; 51 | String? outputPath; 52 | bool verbose; 53 | 54 | final parser = ArgParser() 55 | ..addFlag('verbose', abbr: 'v') 56 | ..addOption(fieldDelimiterOption, 57 | abbr: 'f', defaultsTo: ',', callback: (value) => fieldDelimiter = value) 58 | ..addOption(lineDelimiterOption, 59 | abbr: 'l', defaultsTo: '\n', callback: (value) => lineDelimiter = value) 60 | ..addMultiOption(sortkeyOption, 61 | abbr: 's', 62 | callback: (values) => columns.addAll(FileSort.expandColumns(values))) 63 | ..addOption(outputOption, abbr: 'o'); 64 | 65 | final results = parser.parse(args); 66 | verbose = results['verbose'] as bool; 67 | 68 | if (results.rest.length != 1) { 69 | usageError('Expected an input_file to sort.'); 70 | } 71 | 72 | final inputPath = absolute(results.rest[0]); 73 | 74 | if (results[outputOption] != null) { 75 | outputPath = results[outputOption].toString(); 76 | } 77 | outputPath ??= inputPath; 78 | 79 | outputPath = absolute(outputPath); 80 | 81 | if (columns.isEmpty) { 82 | /// if no columns defined we sort by the whole line. 83 | columns 84 | .add(Column(0, const CaseInsensitiveSort(), SortDirection.ascending)); 85 | } 86 | 87 | if (verbose) { 88 | print('Columns: ${columns.join("\n")}'); 89 | print('Input File: $inputPath, Output File: $outputPath'); 90 | print("Field Delimiter: '$fieldDelimiter'"); 91 | print("Line Delimiter: '$lineDelimiter'"); 92 | } 93 | 94 | if (!exists(inputPath)) { 95 | usageError('The input file $inputPath does not exist'); 96 | } 97 | 98 | if (exists(outputPath) && outputPath != inputPath) { 99 | usageError('The output_file $outputPath already exist. ' 100 | 'Delete the file and try again.'); 101 | } 102 | 103 | FileSort(inputPath, outputPath, columns, fieldDelimiter, lineDelimiter, 104 | verbose: verbose) 105 | .sort(); 106 | } 107 | 108 | void usageError(String error) { 109 | print(red(error)); 110 | print(''); 111 | print(''' 112 | Example: 113 | 114 | dsort --sortkey=1n unsorted.txt 115 | 116 | Usage Details: 117 | 118 | dsort --field-delimiter= --linedelimiter= --sortkey= --output=output_file 119 | 120 | -f, --field-delimiter= (defaults to ,) 121 | -l, --line-delimiter= (defaults to \n) 122 | -s, --sortkey= (defaults to 0) 123 | -o, --output= (defaults to ) 124 | 125 | --field-delimiter 126 | defines the field delimiter for columns in the file 127 | 128 | --line-delimiter 129 | defines the line delimiter for the input file and the output file. 130 | 131 | --sortkey defines columns to sort on and how each column is sorted. 132 | columns=[][], 133 | column-range=[|-] 134 | column=int 135 | 136 | e.g. --sortkey=1 137 | --sortkey=1,2-5,3 138 | 139 | Define the sort type for a 140 | type= 141 | s - case sensitive string sort - the default 142 | S - case insensitive string sort 143 | n - numeric sort 144 | m - month name sort 145 | 146 | e.g. --sortkey=1s 147 | --sortkey=1s,2-5n,3m 148 | 149 | Define the sort direction for a 150 | [direction]= 151 | a - ascending - the default 152 | d - descending 153 | 154 | e.g. --sortkey=1sd 155 | --sortkey=1sd,2-5na,3md 156 | 157 | --output 158 | Defines the file to write the sorted output to. If not provided then we do an insitu sort. 159 | 160 | ${green("Examples:")} 161 | String sort, ascending, sort using the whole line 162 | ${green("dsort unsorted.txt")} 163 | 164 | Numeric sort, desending on the first column only, using the default column delimiter ',' 165 | ${green("dsort --sortkey=1nd unsorted.txt")} 166 | 167 | Descending, Numeric sort on col 1, 168 | then Ascending string sort on col 2, 169 | then Descending Case Sensitive String sort on col 3, 170 | then Descending numeric sort on cols 5-7 inclusive 171 | using the column delimter ':' 172 | ${green("dsort -f=: --sortkey=1nd,2,3Sd,5-7nd unsorted.txt")} 173 | '''); 174 | 175 | exit(-1); 176 | } 177 | -------------------------------------------------------------------------------- /bin/hog.dart: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env dart 2 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 3 | * Unauthorized copying of this file, via any medium is strictly prohibited 4 | * Proprietary and confidential 5 | * Written by Brett Sutton , Jan 2022 6 | */ 7 | 8 | import 'dart:io'; 9 | import 'dart:math'; 10 | 11 | import 'package:args/args.dart'; 12 | import 'package:args/command_runner.dart'; 13 | import 'package:dcli/dcli.dart'; 14 | 15 | /// dcli script generated by: 16 | /// dcli create hog.dart 17 | /// 18 | /// See 19 | /// https://pub.dev/packages/dcli#-installing-tab- 20 | /// 21 | /// For details on installing dcli. 22 | /// 23 | 24 | void main(List args) async { 25 | // args = ['disk']; 26 | final runner = CommandRunner('hog', 'Find resource hogs') 27 | ..addCommand(DiskCommand()) 28 | ..addCommand(MemoryCommand()) 29 | ..addCommand(CPUCommand()); 30 | await runner.run(args); 31 | } 32 | 33 | class CPUCommand extends Command { 34 | @override 35 | String get description => 'Finds apps that are hogging CPU'; 36 | 37 | @override 38 | String get name => 'cpu'; 39 | 40 | @override 41 | void run() { 42 | print('Not implemented'); 43 | } 44 | } 45 | 46 | class MemoryCommand extends Command { 47 | @override 48 | String get description => 'Finds apps that are hogging Memory'; 49 | 50 | @override 51 | String get name => 'memory'; 52 | 53 | @override 54 | void run() { 55 | print('Not implemented'); 56 | } 57 | } 58 | 59 | class DiskCommand extends Command { 60 | @override 61 | String get description => 62 | 'Displays the top 50 largest directories below the current directory'; 63 | 64 | @override 65 | String get name => 'disk'; 66 | 67 | @override 68 | void run() { 69 | final directories = []; 70 | print(green('Scanning...')); 71 | find('*', includeHidden: true, types: [Find.directory]) 72 | .forEach(directories.add); 73 | 74 | final directorySizes = []; 75 | 76 | print(orange('Found ${directories.length} directories')); 77 | 78 | var totalSpace = 0; 79 | print(green('Calculating sizes...')); 80 | for (final directory in directories) { 81 | final directorySize = DirectorySize(directory); 82 | directorySizes.add(directorySize); 83 | 84 | find('*', 85 | workingDirectory: directory, 86 | includeHidden: true, 87 | recursive: false) 88 | .forEach((file) { 89 | try { 90 | directorySize.size += stat(file).size; 91 | totalSpace += directorySize.size; 92 | } on FileSystemException catch (e) { 93 | printerr(e.toString()); 94 | } 95 | }); 96 | } 97 | 98 | directorySizes.sort((a, b) => b.size - a.size); 99 | 100 | print('${orange('Space Used by ${truepath(pwd)}:')} ' 101 | '${green(humanNumber(totalSpace))}'); 102 | print( 103 | '${orange('Free Space:')} ${green(humanNumber(availableSpace(pwd)))}'); 104 | 105 | for (var i = 0; i < min(50, directorySizes.length); i++) { 106 | if (directorySizes[i].size == 0) { 107 | continue; 108 | } 109 | print(Format().row( 110 | [humanNumber(directorySizes[i].size), directorySizes[i].pathTo], 111 | widths: [10, -1], 112 | alignments: [TableAlignment.right, TableAlignment.left])); 113 | } 114 | } 115 | } 116 | 117 | class DirectorySize { 118 | String pathTo; 119 | 120 | var size = 0; 121 | 122 | DirectorySize(this.pathTo); 123 | } 124 | 125 | // for future use. 126 | // ignore: unreachable_from_main 127 | void showUsage(ArgParser parser) { 128 | print('Usage: hog -v -prompt '); 129 | print(parser.usage); 130 | exit(1); 131 | } 132 | 133 | /// returns the the number [bytes] in a human readable 134 | /// form. e.g. 10G, 100M, 20K, 10B 135 | String humanNumber(int bytes) { 136 | String human; 137 | 138 | final svalue = '$bytes'; 139 | if (bytes > 1000000000) { 140 | human = svalue.substring(0, svalue.length - 9); 141 | human += 'G'; 142 | } else if (bytes > 1000000) { 143 | human = svalue.substring(0, svalue.length - 6); 144 | human += 'M'; 145 | } else if (bytes > 1000) { 146 | human = svalue.substring(0, svalue.length - 3); 147 | human += 'K'; 148 | } else { 149 | human = '${svalue}B'; 150 | } 151 | return human; 152 | } 153 | 154 | int availableSpace(String path) { 155 | if (!exists(path)) { 156 | throw FileSystemException( 157 | "The given path ${truepath(path)} doesn't exists"); 158 | } 159 | 160 | final lines = 'df -h "$path"'.toList(); 161 | if (lines.length != 2) { 162 | throw FileSystemException( 163 | "An error occured retrieving the device path: ${lines.join('\n')}"); 164 | } 165 | 166 | final line = lines[1]; 167 | final parts = line.split(RegExp(r'\s+')); 168 | 169 | if (parts.length != 6) { 170 | throw FileSystemException('An error parsing line: $line'); 171 | } 172 | 173 | final factors = {'G': 1000000000, 'M': 1000000, 'K': 1000, 'B': 1}; 174 | 175 | final havailable = parts[3]; 176 | 177 | if (havailable == '0') { 178 | return 0; 179 | } 180 | 181 | final factorLetter = havailable.substring(havailable.length - 1); 182 | final hsize = havailable.substring(0, havailable.length - 1); 183 | 184 | final factor = factors[factorLetter]; 185 | if (factor == null) { 186 | throw FileSystemException( 187 | "Unrecognized size factor '$factorLetter' in $havailable"); 188 | } 189 | 190 | return (int.tryParse(hsize) ?? 0) * factor; 191 | } 192 | 193 | // for future use. 194 | // ignore: unreachable_from_main 195 | void removeOldKernels() { 196 | r'''dpkg --list | grep 'linux-image' | awk '{ print $2 }' | sort -V | sed -n '/'"$(uname -r | sed "s/\([0-9.-]*\)-\([^0-9]\+\)/\1/")"'/q;p' | xargs sudo apt-get -y purge''' 197 | .run; 198 | 199 | r'''dpkg --list | grep 'linux-headers' | awk '{ print $2 }' | sort -V | sed -n '/'"$(uname -r | sed "s/\([0-9.-]*\)-\([^0-9]\+\)/\1/")"'/q;p' | xargs sudo apt-get -y purge''' 200 | .run; 201 | } 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | An eclectic collection of CLI scripts that help me manage my dev environment. 2 | 3 | Some of my favourites: 4 | 5 | # commands 6 | 7 | | command | description | Example| 8 | | --- | --- | --- | 9 | | dport | finds what process has a tcp port open.| dport 80| 10 | | clean | cleans out stale docker and git files and highlights large directories. | clean| 11 | | dmailhog | installs and starts/stops mailhog. | dmailhog \| dmailhog --shutdown | 12 | | dmysql | Backup/Restore and connects you to a mysql cli pulling settings (username/password) from a per database local settings file. | dmysql mydb backup \| dmysql mydb restore `` 13 | | dwhich | an improved which command that also highlights invalid paths 14 | | gitgc | runs garbage collection on all your git projects. 15 | | hog | finds system resource hogs. 16 | | ipaddr | shows the ip address on your local machine. 17 | | docker_push | builds a docker file and pushes it to docker.hub. 18 | | kill_tomcat | kills any java tomcat instances. 19 | | pub_get_all | recursively runs `dart pub get` 20 | | hex_dump | dumps the contents of a file in hex and ascii. 21 | | find_text | Find a file that contains the given text| 22 | 23 | 24 | 25 | 26 | # dfind 27 | Recursively searches for a file with a matching glob pattern 28 | ## Example 29 | ```bash 30 | dfind '*.dart' 31 | ``` 32 | 33 | # dport 34 | Prints out the name of the process that is listening on the passed tcp port. 35 | 36 | ## Example 37 | ```bash 38 | dport 80 39 | ``` 40 | 41 | # dmysql 42 | Allows you to store the username/password for a mysql database in a configure file and then run a number of mysql commands against that database withouth continuously re-entering the username/password. 43 | 44 | ## Example 45 | 46 | To create a configuration file for a given database run: 47 | ```bash 48 | dmysql config 49 | host: 50 | port: 51 | user: 52 | password: 53 | ``` 54 | 55 | Once you have created a config you can run any of the following commands. 56 | ### backup 57 | Backup the database via: 58 | 59 | ```bash 60 | dmysql backup 61 | ``` 62 | 63 | ### restore 64 | Restore a database 65 | 66 | WARNING: this will delete you existing schema. 67 | 68 | ```bash 69 | dmysql restore 70 | ``` 71 | 72 | ### cli 73 | Connect to the mysql cli 74 | 75 | ```bash 76 | dmysql cli 77 | ``` 78 | 79 | # find_text 80 | 81 | List each file that matches the pass text. The search is run recursively from the current directory. 82 | 83 | ## Example 84 | 85 | Search all dart files for a line that contains 'final String'. 86 | ```bash 87 | find_text 'final String' '*.dart' 88 | ``` 89 | 90 | # apis 91 | The dcli_scripts package also includes some handy apis. 92 | 93 | ## dockerPublish 94 | 95 | Designed to build and publish a docker image which contains a Dart project built with dcli. 96 | 97 | The api assumes that you are cloning a git repo into your docker image and that you need to rebuild you image each time the git repo changes. 98 | 99 | The api allows you to rebuild you docker image from the clone step rather than having to rebuild the entire docker image. 100 | 101 | Your docker file should have the following line just before 102 | the package's git clone line. 103 | 104 | ```docker 105 | RUN mkdir -p /BUILD_TOKEN/ 106 | ``` 107 | 108 | We will run a: 109 | * dcli pack 110 | * git add * 111 | * git commit -m 'release' 112 | * git push 113 | 114 | You need to provide the path to your dockerfile via [pathToDockerFile]. 115 | 116 | The docker tag will be generated from your pubspec.yaml and 117 | the [repository] argument in the form: 118 | 119 | `/:` 120 | 121 | So if you pass in 'noojee' as the repository and your package is dcli then you might get: 122 | 123 | ``` 124 | noojee/dcli:1.16.0 125 | ``` 126 | 127 | If you pass the [clean] = true then the image will be rebuilt from scratch. 128 | 129 | If you pass the [fresh] = true then the Docker image will be rebuilt from the line 130 | that contains `BUILD_TOKEN`. 131 | 132 | We search for the BUILD_TOKEN line in your docker file and update the token UUID. This will cause the docker image to be rebuilt from the BUILD_TOKEN line. This can be used if you need to re-clone a git repo (or any similar action). 133 | 134 | By default the image will be pushed to docker hub unless 135 | you pass [push] = false. 136 | 137 | By default we ask you to confirm the build process. Pass [confirm] = false 138 | to skip the question. 139 | 140 | If you pass [pack] = true then the 'dcli pack' command will be run 141 | and any changes committed to your git repo before the build starts. 142 | If you pass [pack] = true then [fresh] will automatically be set to true to force a fresh git clone. 143 | 144 | Here is an example Dockerfile that builds for an arm64 target ( I use this for raspberry pi testing.) 145 | 146 | ```docker 147 | # used to build the dart exes in a docker arm image 148 | # trying to build dart execs on a pi is just to slow 149 | # hence we do the build in a docker image on our 150 | # development box. 151 | 152 | # docker image instructions came from. 153 | # https://hub.docker.com/r/balenalib/raspberrypi4-64-debian 154 | 155 | 156 | # FROM balenalib/raspberrypi4-64-ubuntu:latest 157 | FROM balenalib/raspberrypi4-64-ubuntu-openjdk:latest 158 | # replace this with your application 159 | 160 | 161 | # install build tools 162 | # && apt install --no-install-recommends -y openjdk-8-jdk-headless maven git \ 163 | 164 | RUN apt update \ 165 | && apt install --no-install-recommends -y \ 166 | wget \ 167 | git \ 168 | maven \ 169 | unzip \ 170 | && rm -rf /var/lib/apt/lists/* 171 | 172 | RUN wget https://storage.googleapis.com/dart-archive/channels/be/raw/latest/sdk/dartsdk-linux-arm64-release.zip --output-document=dart.zip 173 | RUN unzip dart.zip 174 | 175 | # add dart to the path. 176 | ENV PATH="$PATH:/dart-sdk/bin" 177 | 178 | 179 | RUN mkdir -p /BUILD_TOKEN/ 180 | RUN git clone https://github.com/bsutton/IrrigationForPi.git 181 | 182 | 183 | 184 | WORKDIR IrrigationForPi/build_tools 185 | 186 | RUN dart pub get 187 | RUN dart bin/pig_build.dart --current --no-tools --no-full 188 | 189 | ``` 190 | 191 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 4.4.0 2 | - upgraded to dcli 8.2.0 3 | 4 | # 4.3.0 5 | - upgraded packges, dcli, docker2, pubspec_manager and lint_hard 6 | - added the strings dependency. 7 | - added additional test. 8 | - add missing space. 9 | - added usage to the dfind command. Removed the --pattern swithc as it was redundant and confusing. 10 | 11 | # 4.1.0 12 | - upgraded to dcli 7.x 13 | 14 | # 4.0.0 15 | - min dart version 3.5 16 | - Merge branch 'master' of github.com:bsutton/dcli_scripts 17 | - upgraded to dcli 6.x 18 | - Update bobthefish.dart 19 | 20 | # 3.4.4 21 | - change pub_get_all so that it now prints any errors rather than 22 | just reporting a failure. 23 | 24 | # 3.4.3 25 | - added flag to dfind to control whether warnings about skipped files are output. 26 | - added ability for dfind to search for text within files. 27 | 28 | # 3.4.2 29 | - upgraded packages. 30 | 31 | # 3.4.1 32 | - upgraded packages. 33 | 34 | # 3.4.0 35 | - upgraded to release version of dcli 4.x 36 | 37 | # 3.3.0 38 | - changed the #! to use dart rather than dcli. Upgraded to latest version of dcli. 39 | - added a app that listens on a tcp port and echos andy data recieved. 40 | 41 | # 3.2.0-alpha.2 42 | - fixed some async calls after upgrading to dcli 4.x 43 | - Fixed a bug in dockerPublish that was incorrectly getting the pubspec name object rather then the string name. 44 | 45 | # 3.2.0-alpha.1 46 | - upgraded to dcli 4.0.0-alpha.1 47 | 48 | # 3.1.1 49 | - upgraded to pub_release to fix problems with the tool scripts 50 | - migrated to using pubspec_manager 51 | 52 | # 3.1.0 53 | - upgraded dependencies. 54 | 55 | # 3.0.0 56 | - upgraded to dcli 3.x 57 | # 2.1.1 58 | - upgraded to docker2 4.0 59 | 60 | # 2.1.0 61 | - Updated dependencies. 62 | 63 | # 2.0.0 64 | Upgraded to dart 3.0.0 65 | 66 | # 1.6.0 67 | - updated dependencies 68 | - Added better error handling for gactivate. 69 | - clean now delete .dart_tools directories. 70 | 71 | # 1.5.0 72 | - gactivate can now aot compile a package from .pub-cache and add it to the 73 | dcli path. This is usefuly if you switch dart versions a lot and also speeds 74 | up the exection of any cli tool. 75 | 76 | # 1.4.0 77 | - Added gactivate. cleaned out lintes. 78 | - Improved dwhich path dedupliation so we don't get the same error twice. 79 | 80 | # 1.3.0 81 | - Added --routines to the mysql backup so that storedprocs and functions are backed up. 82 | - Improved mysql restore. It now drops and re-creates the db. 83 | - added copyright notices. 84 | 85 | # 1.2.10 86 | - added code to the clean command to prune unused docker volumes 87 | - updated dnsflush to work on ubuntu 22.04 88 | - upgraded to latest version of dcli. 89 | - changed kill_tomcat to try without priviliged escalation and then with if required. 90 | - improved the tomcat killed message. 91 | 92 | # 1.2.8 93 | 94 | # 1.2.7 95 | 96 | # 1.2.6 97 | - changed hog disk to output the total size of scanned files. 98 | 99 | # 1.2.4 100 | - added usage statement to dcompress if the arg parsing fails. 101 | - added nothrow so that a failed git gc doesn't stop the clean process. 102 | 103 | # 1.2.3 104 | - dfind now searches hidden directories. 105 | 106 | # 1.2.2 107 | - changed the backup command to discard a backup if it isdentical to the prior backup. Use the --always option to force it to retain the backup regardless. 108 | 109 | # 1.2.1 110 | - Fixed bug in dmysql when the directory path had a '.' in it. 111 | 112 | # 1.2.0 113 | - updated dcli version. 114 | - Added option to dmysql so it auto generates a sequence of backup files if you don't provide a name. Improved the usage message. 115 | 116 | # 1.1.22 117 | - Added additional optoins and error handling to dmysql. When configuring a db we now check if it exists. We report missing config file rather than trying to use defaults. We won't overwrite an existing backup file. option to remove a config for a db. 118 | 119 | # 1.1.21 120 | Fixed a bug in dmysql when running using the mariad client which doesn't support --column-statistics. 121 | We just retry the command without the switch if it fails. 122 | 123 | 124 | # 1.1.20 125 | - Added doco on the dockerPublish command. 126 | 127 | # 1.1.19 128 | - doco improvements in the readme. 129 | 130 | # 1.1.18 131 | Added --column-statistics=0 to dmysql backup so we can backup a v5 db using v8 tools. 132 | # 1.1.17 133 | - fix: bug in dsetver. It was always trying to set the version of the dcli_scripts package. 134 | 135 | # 1.1.16 136 | - fix: improved error messages when an invalid arg passed to dsetver 137 | 138 | # 1.1.15 139 | - enh: change find_text to output relative paths. 140 | 141 | # 1.1.14 142 | - enh: find_text now otuputing the file name. 143 | - removed debug statement. 144 | 145 | # 1.1.13 146 | - enh: attempt two to publish with find_text as an exe. 147 | 148 | # 1.1.12 149 | Added find_text app to recursively search for text in a file. 150 | # 1.1.11 151 | Improved the DockerPublish api documentation. 152 | 153 | # 1.1.10 154 | Fixed an import. 155 | 156 | # 1.1.9 157 | - restructured the mysql commands into one apps with commands. 158 | - add hook to activate dcli_scripts after doing a pub_relase. 159 | - added check that mysqldump was installed when running mysql_backup 160 | 161 | # 1.1.8 162 | - updated the eclipse desktop launcher builder to work with changes to eclipse paths. 163 | - added mysql_backup and renamed dmysql to mysql_cli 164 | 165 | # 1.1.7 166 | Added no-cofirm option to dockerPublish api. 167 | # 1.1.5 168 | - Added no-push option to the dockerPublish api. 169 | 170 | # 1.1.4 171 | - applied lint_hard 172 | - created barrel file and dockerPublish 173 | 174 | # 1.1.3 175 | - Added logic to check for duplicate path entries when --verbose switch passed. 176 | 177 | # 1.1.2 178 | 179 | # 1.1.1 180 | - Fixed a bug in clean that tries to run hog.dart rather than hog. 181 | 182 | # 1.1.0 183 | - created pub_get_all to run pub get on all subprojects. 184 | - improved dwhich to correctly deal with empty paths. 185 | 186 | # 1.0.10 187 | - added dsetver as an exe. 188 | 189 | # 1.0.9 190 | - added dsetver command which updates pubspec.yaml version from the cli. 191 | 192 | # 1.0.8 193 | - upgraded to dcli 1.11.0 194 | - removed excess logging when running in non-verbose mode. 195 | 196 | # 1.0.7 197 | - Fixed a bug in dwc where it failed if passed a file with a space in the name. 198 | - Added fetch command. 199 | 200 | # 1.0.6 201 | - added test that dcli directory exists. cleanedup home paths. 202 | 203 | # 1.0.5 204 | - upgraded dcli version. 205 | - Add command line flag to shutdown mailhog. 206 | - changed clean to look for gitgc on the path. 207 | - added help option to mailhog. 208 | - Fixed the paths to other scripts which are now in the bin directory. 209 | - moved to lints/recommended lint cleanup 210 | - new app to post an http request and report progress. 211 | 212 | # 1.0.4 213 | Added option to suppress the ascii output and -h to show help. 214 | 215 | 216 | # 1.0.3 217 | * Exposed hexdump as a executable. 218 | * upgraded to dcli 1.8 219 | * Added search for differnt file extensions as windows users expect. 220 | 221 | # 1.0.2 222 | 223 | # 1.0.1 224 | added logic to skip blank lines in the bitbucket_import csv file. 225 | 226 | # 1.0.0 227 | First release. 228 | -------------------------------------------------------------------------------- /lib/src/mysql/backup_command.dart: -------------------------------------------------------------------------------- 1 | /* Copyright (C) S. Brett Sutton - All Rights Reserved 2 | * Unauthorized copying of this file, via any medium is strictly prohibited 3 | * Proprietary and confidential 4 | * Written by Brett Sutton , Jan 2022 5 | */ 6 | import 'dart:io'; 7 | 8 | import 'package:args/command_runner.dart'; 9 | import 'package:dcli/dcli.dart'; 10 | import 'package:path/path.dart'; 11 | 12 | import 'mysql.dart'; 13 | import 'mysql_settings.dart'; 14 | 15 | class BackupCommand extends Command { 16 | BackupCommand() { 17 | argParser 18 | ..addFlag('overwrite', 19 | abbr: 'w', 20 | help: 'If the backup file already exist then overwrite the file.') 21 | ..addFlag('always', 22 | abbr: 'a', 23 | help: 'Create the backup file even if the db ' 24 | "content hasn't changed since the last backup."); 25 | } 26 | @override 27 | String get description => ''' 28 | Backups up a database. 29 | 30 | ${blue('dmysql backup []')} 31 | 32 | If you don't provide the path of a backup file (or path is a directory) 33 | then one will be generated in the form: 34 | 35 | .backup..sql'''; 36 | 37 | @override 38 | String get name => 'backup'; 39 | 40 | @override 41 | Future run() async { 42 | if (which('mysqldump').notfound) { 43 | throw ExitException(1, 'You must install mysqldump first'); 44 | } 45 | 46 | final args = getArgs(this, argResults); 47 | 48 | final dbName = args[0]; 49 | 50 | final overwrite = argResults!['overwrite'] as bool; 51 | final always = argResults!['always'] as bool; 52 | 53 | String pathToBackupFile; 54 | String? pathToMostRecent; 55 | if (argResults!.rest.length == 2) { 56 | final backupArg = argResults!.rest[1]; 57 | if (isDirectory(backupArg)) { 58 | final backupDir = backupArg; 59 | pathToBackupFile = getBackupFileSequence(backupDir, dbName); 60 | pathToMostRecent = getMostRecent(backupDir, dbName); 61 | } else { 62 | pathToBackupFile = backupArg; 63 | } 64 | } else { 65 | // no backuparg 66 | pathToBackupFile = getBackupFileSequence(pwd, dbName); 67 | pathToMostRecent = getMostRecent(pwd, dbName); 68 | } 69 | 70 | // , additionalArgs: ['Path to backup file']) 71 | 72 | if (extension(pathToBackupFile) != '.sql') { 73 | pathToBackupFile += '.sql'; 74 | } 75 | if (exists(pathToBackupFile) && !overwrite) { 76 | printerr('The backup file ${truepath(pathToBackupFile)} already exists. ' 77 | 'Delete it or use --overwrite'); 78 | } 79 | if (await backup( 80 | MySqlSettings.load(dbName), pathToBackupFile, pathToMostRecent, 81 | always: always)) { 82 | print(blue('Backed up database to $pathToBackupFile')); 83 | } 84 | print(''); 85 | } 86 | 87 | Future backup(MySqlSettings settings, String pathToBackupfile, 88 | String? pathToPriorBackup, 89 | {required bool always}) async { 90 | var created = false; 91 | var columnStatistics = '--column-statistics=0 '; 92 | var success = false; 93 | await withTempFileAsync((tmpFile) async { 94 | while (!success) { 95 | final result = 'mysqldump --host ${settings.host} ' 96 | '--port=${settings.port} ' 97 | '--user ${settings.user} ' 98 | // so we can backup a v5 db using v8 tools. For large table this 99 | // is also recommended. 100 | '$columnStatistics' 101 | '--password="${settings.password}" ' 102 | '--databases ${settings.dbname} ' 103 | '--routines ' 104 | '--result-file=$tmpFile ' 105 | .start(nothrow: true, progress: Progress.capture()); 106 | 107 | if (result.toParagraph().contains('column-statistics=0')) { 108 | /// retry without --column-statistics. 109 | columnStatistics = ''; 110 | } else { 111 | success = true; 112 | } 113 | } 114 | if (success) { 115 | if (pathToPriorBackup != null) { 116 | /// If the new backup is identical then we don't create a backup 117 | if (always || !diff(tmpFile, pathToPriorBackup)) { 118 | move(tmpFile, pathToBackupfile); 119 | created = true; 120 | } else { 121 | print(orange("Database hasn't changed. No backup created. " 122 | 'Use --always to force a backup')); 123 | } 124 | } else { 125 | move(tmpFile, pathToBackupfile); 126 | created = true; 127 | } 128 | } 129 | }, keep: true); 130 | return created; 131 | } 132 | 133 | /// Compares two files to see if they have the same content. 134 | bool diff(String pathTobackup, String pathToPriorBackup) { 135 | /// skip the diff if the files sizes are different. 136 | if (stat(pathTobackup).size != stat(pathToPriorBackup).size) { 137 | return false; 138 | } 139 | final backupFile = FileSync(pathTobackup, fileMode: FileMode.read); 140 | final priorFile = FileSync(pathToPriorBackup, fileMode: FileMode.read); 141 | 142 | var count = 0; 143 | String? line; 144 | var same = true; 145 | while ((line = backupFile.readLine()) != null) { 146 | count++; 147 | final other = priorFile.readLine(); 148 | 149 | /// The dump completed is the last line and contains a date stamp 150 | /// so it will always be different so we ignore it. 151 | if (line!.startsWith('-- Dump completed on ')) { 152 | continue; 153 | } 154 | 155 | if (line != other) { 156 | print(orange('found diff at $count: $line')); 157 | same = false; 158 | break; 159 | } 160 | } 161 | 162 | /// check that we also hit the eof for prior 163 | if (same && priorFile.readLine() != null) { 164 | print(orange('prior is shorter at $count')); 165 | same = false; 166 | } 167 | return same; 168 | } 169 | 170 | /// Gets the path to the next backup file in the sequence. 171 | String getBackupFileSequence(String path, String dbName) { 172 | final mostRecent = getMostRecent(path, dbName); 173 | if (mostRecent == null) { 174 | return join(path, '$dbName.backup.0001.sql'); 175 | } 176 | 177 | final version = '${_extractVersion(mostRecent) + 1}'.padLeft(4, '0'); 178 | 179 | return join(path, '$dbName.backup.$version.sql'); 180 | } 181 | 182 | /// Returns the most recent backup file in the sequence. 183 | String? getMostRecent(String path, String dbName) { 184 | final backups = 185 | find('$dbName.backup.*.sql', workingDirectory: path, recursive: false) 186 | .toList() 187 | ..sort((lhs, rhs) => _extractVersion(rhs) - _extractVersion(lhs)); 188 | 189 | if (backups.isEmpty) { 190 | return null; 191 | } 192 | 193 | return join(path, backups.first); 194 | } 195 | 196 | int _extractVersion(String backupName) { 197 | final parts = basename(backupName).split('.'); 198 | if (parts.length != 4) { 199 | throw ExitException( 200 | 1, 'Invalid backup sequence name found ${basename(backupName)}'); 201 | } 202 | final version = int.tryParse(parts[2]); 203 | if (version == null) { 204 | throw ExitException( 205 | 1, 'Invalid backup sequence name found ${basename(backupName)}'); 206 | } 207 | return version; 208 | } 209 | } 210 | 211 | // class InvalidBackupName implements Exception { 212 | // InvalidBackupName(this.backupName); 213 | // String backupName; 214 | 215 | // @override 216 | // String toString() => backupName; 217 | // } 218 | 219 | class ExitException implements Exception { 220 | int exitCode; 221 | 222 | String message; 223 | 224 | ExitException(this.exitCode, this.message); 225 | 226 | @override 227 | String toString() => 'Error: $exitCode $message'; 228 | } 229 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | _fe_analyzer_shared: 5 | dependency: transitive 6 | description: 7 | name: _fe_analyzer_shared 8 | sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "85.0.0" 12 | analyzer: 13 | dependency: transitive 14 | description: 15 | name: analyzer 16 | sha256: f4ad0fea5f102201015c9aae9d93bc02f75dd9491529a8c21f88d17a8523d44c 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "7.6.0" 20 | analyzer_plugin: 21 | dependency: transitive 22 | description: 23 | name: analyzer_plugin 24 | sha256: a5ab7590c27b779f3d4de67f31c4109dbe13dd7339f86461a6f2a8ab2594d8ce 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "0.13.4" 28 | archive: 29 | dependency: transitive 30 | description: 31 | name: archive 32 | sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "4.0.7" 36 | args: 37 | dependency: "direct main" 38 | description: 39 | name: args 40 | sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "2.7.0" 44 | async: 45 | dependency: transitive 46 | description: 47 | name: async 48 | sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "2.13.0" 52 | boolean_selector: 53 | dependency: transitive 54 | description: 55 | name: boolean_selector 56 | sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "2.1.2" 60 | characters: 61 | dependency: transitive 62 | description: 63 | name: characters 64 | sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b 65 | url: "https://pub.dev" 66 | source: hosted 67 | version: "1.4.1" 68 | checked_yaml: 69 | dependency: transitive 70 | description: 71 | name: checked_yaml 72 | sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" 73 | url: "https://pub.dev" 74 | source: hosted 75 | version: "2.0.4" 76 | chunked_stream: 77 | dependency: transitive 78 | description: 79 | name: chunked_stream 80 | sha256: b2fde5f81d780f0c1699b8347cae2e413412ae947fc6e64727cc48c6bb54c95c 81 | url: "https://pub.dev" 82 | source: hosted 83 | version: "1.4.2" 84 | ci: 85 | dependency: transitive 86 | description: 87 | name: ci 88 | sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" 89 | url: "https://pub.dev" 90 | source: hosted 91 | version: "0.1.0" 92 | circular_buffer: 93 | dependency: transitive 94 | description: 95 | name: circular_buffer 96 | sha256: b3a315fef3fee7fe58879643fc8ce21c7c2449d01c1a8a396dc9e24687f335c4 97 | url: "https://pub.dev" 98 | source: hosted 99 | version: "0.12.0" 100 | cli_config: 101 | dependency: transitive 102 | description: 103 | name: cli_config 104 | sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec 105 | url: "https://pub.dev" 106 | source: hosted 107 | version: "0.2.0" 108 | cli_util: 109 | dependency: transitive 110 | description: 111 | name: cli_util 112 | sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c 113 | url: "https://pub.dev" 114 | source: hosted 115 | version: "0.4.2" 116 | clock: 117 | dependency: transitive 118 | description: 119 | name: clock 120 | sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b 121 | url: "https://pub.dev" 122 | source: hosted 123 | version: "1.1.2" 124 | collection: 125 | dependency: transitive 126 | description: 127 | name: collection 128 | sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" 129 | url: "https://pub.dev" 130 | source: hosted 131 | version: "1.19.1" 132 | convert: 133 | dependency: transitive 134 | description: 135 | name: convert 136 | sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 137 | url: "https://pub.dev" 138 | source: hosted 139 | version: "3.1.2" 140 | coverage: 141 | dependency: transitive 142 | description: 143 | name: coverage 144 | sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" 145 | url: "https://pub.dev" 146 | source: hosted 147 | version: "1.15.0" 148 | crypto: 149 | dependency: transitive 150 | description: 151 | name: crypto 152 | sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" 153 | url: "https://pub.dev" 154 | source: hosted 155 | version: "3.0.6" 156 | csv: 157 | dependency: transitive 158 | description: 159 | name: csv 160 | sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c 161 | url: "https://pub.dev" 162 | source: hosted 163 | version: "6.0.0" 164 | custom_lint: 165 | dependency: transitive 166 | description: 167 | name: custom_lint 168 | sha256: "78085fbe842de7c5bef92de811ca81536968dbcbbcdac5c316711add2d15e796" 169 | url: "https://pub.dev" 170 | source: hosted 171 | version: "0.8.0" 172 | custom_lint_builder: 173 | dependency: transitive 174 | description: 175 | name: custom_lint_builder 176 | sha256: cc5532d5733d4eccfccaaec6070a1926e9f21e613d93ad0927fad020b95c9e52 177 | url: "https://pub.dev" 178 | source: hosted 179 | version: "0.8.0" 180 | custom_lint_core: 181 | dependency: transitive 182 | description: 183 | name: custom_lint_core 184 | sha256: cc4684d22ca05bf0a4a51127e19a8aea576b42079ed2bc9e956f11aaebe35dd1 185 | url: "https://pub.dev" 186 | source: hosted 187 | version: "0.8.0" 188 | custom_lint_visitor: 189 | dependency: transitive 190 | description: 191 | name: custom_lint_visitor 192 | sha256: "4a86a0d8415a91fbb8298d6ef03e9034dc8e323a599ddc4120a0e36c433983a2" 193 | url: "https://pub.dev" 194 | source: hosted 195 | version: "1.0.0+7.7.0" 196 | dart_console: 197 | dependency: transitive 198 | description: 199 | name: dart_console 200 | sha256: "03c23e1f9cc3ac02b608f834808003e6510a5b292a0449f43dfac1c78bd8ee85" 201 | url: "https://pub.dev" 202 | source: hosted 203 | version: "4.1.2" 204 | dart_style: 205 | dependency: transitive 206 | description: 207 | name: dart_style 208 | sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" 209 | url: "https://pub.dev" 210 | source: hosted 211 | version: "3.1.1" 212 | dcli: 213 | dependency: "direct main" 214 | description: 215 | name: dcli 216 | sha256: "67eb0be17fb552d3b24eb7749989601b9739eab584d1d007f4a60d1e4c23cae0" 217 | url: "https://pub.dev" 218 | source: hosted 219 | version: "8.2.0" 220 | dcli_common: 221 | dependency: transitive 222 | description: 223 | name: dcli_common 224 | sha256: "6e36a9e2137c5de64c5cfc2f18d824554459e65c6092daf036643574cc9902cf" 225 | url: "https://pub.dev" 226 | source: hosted 227 | version: "8.0.0" 228 | dcli_core: 229 | dependency: "direct main" 230 | description: 231 | name: dcli_core 232 | sha256: "69d030fdca204cd8636ccc7b8e09468d327051298f2ed24cdfe088588f38b5e7" 233 | url: "https://pub.dev" 234 | source: hosted 235 | version: "8.0.0" 236 | dcli_terminal: 237 | dependency: transitive 238 | description: 239 | name: dcli_terminal 240 | sha256: "4837ba720a540c395feb48307b4fa8e5932d8c202fe5768cdb0bc46110b7761b" 241 | url: "https://pub.dev" 242 | source: hosted 243 | version: "8.0.0" 244 | docker2: 245 | dependency: "direct main" 246 | description: 247 | name: docker2 248 | sha256: "9822e5ff417cb20105e0c0dfb19cba7266889cc83cf081e11c8e4abd6c7fa8b6" 249 | url: "https://pub.dev" 250 | source: hosted 251 | version: "6.0.0" 252 | equatable: 253 | dependency: transitive 254 | description: 255 | name: equatable 256 | sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" 257 | url: "https://pub.dev" 258 | source: hosted 259 | version: "2.0.7" 260 | ffi: 261 | dependency: transitive 262 | description: 263 | name: ffi 264 | sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" 265 | url: "https://pub.dev" 266 | source: hosted 267 | version: "2.1.4" 268 | file: 269 | dependency: transitive 270 | description: 271 | name: file 272 | sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 273 | url: "https://pub.dev" 274 | source: hosted 275 | version: "7.0.1" 276 | fixnum: 277 | dependency: transitive 278 | description: 279 | name: fixnum 280 | sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be 281 | url: "https://pub.dev" 282 | source: hosted 283 | version: "1.1.1" 284 | freezed_annotation: 285 | dependency: transitive 286 | description: 287 | name: freezed_annotation 288 | sha256: "7294967ff0a6d98638e7acb774aac3af2550777accd8149c90af5b014e6d44d8" 289 | url: "https://pub.dev" 290 | source: hosted 291 | version: "3.1.0" 292 | frontend_server_client: 293 | dependency: transitive 294 | description: 295 | name: frontend_server_client 296 | sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 297 | url: "https://pub.dev" 298 | source: hosted 299 | version: "4.0.0" 300 | functional_data: 301 | dependency: transitive 302 | description: 303 | name: functional_data 304 | sha256: "76d17dc707c40e552014f5a49c0afcc3f1e3f05e800cd6b7872940bfe41a5039" 305 | url: "https://pub.dev" 306 | source: hosted 307 | version: "1.2.0" 308 | github: 309 | dependency: transitive 310 | description: 311 | name: github 312 | sha256: c88cd9f11e131a05b1910e1c742c80e6dc7708701884d1fcf28147fc95933aa8 313 | url: "https://pub.dev" 314 | source: hosted 315 | version: "9.25.0" 316 | glob: 317 | dependency: transitive 318 | description: 319 | name: glob 320 | sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de 321 | url: "https://pub.dev" 322 | source: hosted 323 | version: "2.1.3" 324 | globbing: 325 | dependency: transitive 326 | description: 327 | name: globbing 328 | sha256: "4f89cfaf6fa74c9c1740a96259da06bd45411ede56744e28017cc534a12b6e2d" 329 | url: "https://pub.dev" 330 | source: hosted 331 | version: "1.0.0" 332 | hotreloader: 333 | dependency: transitive 334 | description: 335 | name: hotreloader 336 | sha256: bc167a1163807b03bada490bfe2df25b0d744df359227880220a5cbd04e5734b 337 | url: "https://pub.dev" 338 | source: hosted 339 | version: "4.3.0" 340 | http: 341 | dependency: transitive 342 | description: 343 | name: http 344 | sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007 345 | url: "https://pub.dev" 346 | source: hosted 347 | version: "1.5.0" 348 | http_multi_server: 349 | dependency: transitive 350 | description: 351 | name: http_multi_server 352 | sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 353 | url: "https://pub.dev" 354 | source: hosted 355 | version: "3.2.2" 356 | http_parser: 357 | dependency: transitive 358 | description: 359 | name: http_parser 360 | sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" 361 | url: "https://pub.dev" 362 | source: hosted 363 | version: "4.1.2" 364 | ini: 365 | dependency: transitive 366 | description: 367 | name: ini 368 | sha256: "12a76c53591ffdf86d1265be3f986888a6dfeb34a85957774bc65912d989a173" 369 | url: "https://pub.dev" 370 | source: hosted 371 | version: "2.1.0" 372 | intl: 373 | dependency: transitive 374 | description: 375 | name: intl 376 | sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" 377 | url: "https://pub.dev" 378 | source: hosted 379 | version: "0.20.2" 380 | io: 381 | dependency: transitive 382 | description: 383 | name: io 384 | sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b 385 | url: "https://pub.dev" 386 | source: hosted 387 | version: "1.0.5" 388 | js: 389 | dependency: transitive 390 | description: 391 | name: js 392 | sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" 393 | url: "https://pub.dev" 394 | source: hosted 395 | version: "0.7.2" 396 | json2yaml: 397 | dependency: transitive 398 | description: 399 | name: json2yaml 400 | sha256: da94630fbc56079426fdd167ae58373286f603371075b69bf46d848d63ba3e51 401 | url: "https://pub.dev" 402 | source: hosted 403 | version: "3.0.1" 404 | json_annotation: 405 | dependency: transitive 406 | description: 407 | name: json_annotation 408 | sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" 409 | url: "https://pub.dev" 410 | source: hosted 411 | version: "4.9.0" 412 | lint_hard: 413 | dependency: "direct dev" 414 | description: 415 | name: lint_hard 416 | sha256: "805771ca5131c1e798ec7e94eb557dc61d6dc1220246855196776f4ac7299446" 417 | url: "https://pub.dev" 418 | source: hosted 419 | version: "6.2.1" 420 | logging: 421 | dependency: transitive 422 | description: 423 | name: logging 424 | sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 425 | url: "https://pub.dev" 426 | source: hosted 427 | version: "1.3.0" 428 | matcher: 429 | dependency: transitive 430 | description: 431 | name: matcher 432 | sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 433 | url: "https://pub.dev" 434 | source: hosted 435 | version: "0.12.17" 436 | meta: 437 | dependency: transitive 438 | description: 439 | name: meta 440 | sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" 441 | url: "https://pub.dev" 442 | source: hosted 443 | version: "1.17.0" 444 | mime: 445 | dependency: transitive 446 | description: 447 | name: mime 448 | sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" 449 | url: "https://pub.dev" 450 | source: hosted 451 | version: "2.0.0" 452 | native_synchronization_temp: 453 | dependency: transitive 454 | description: 455 | name: native_synchronization_temp 456 | sha256: da257795e9af30fcfa9a0df14c7e18aeb1d802dadd98307d684cc7f3ccd93136 457 | url: "https://pub.dev" 458 | source: hosted 459 | version: "0.8.0" 460 | node_preamble: 461 | dependency: transitive 462 | description: 463 | name: node_preamble 464 | sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" 465 | url: "https://pub.dev" 466 | source: hosted 467 | version: "2.0.2" 468 | package_config: 469 | dependency: transitive 470 | description: 471 | name: package_config 472 | sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc 473 | url: "https://pub.dev" 474 | source: hosted 475 | version: "2.2.0" 476 | path: 477 | dependency: "direct main" 478 | description: 479 | name: path 480 | sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" 481 | url: "https://pub.dev" 482 | source: hosted 483 | version: "1.9.1" 484 | pool: 485 | dependency: transitive 486 | description: 487 | name: pool 488 | sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" 489 | url: "https://pub.dev" 490 | source: hosted 491 | version: "1.5.2" 492 | posix: 493 | dependency: transitive 494 | description: 495 | name: posix 496 | sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" 497 | url: "https://pub.dev" 498 | source: hosted 499 | version: "6.0.3" 500 | pub_release: 501 | dependency: "direct main" 502 | description: 503 | name: pub_release 504 | sha256: f361958dae75642ea368a16a873e4660918c80870144a25bc1d07c4d4e80cb4d 505 | url: "https://pub.dev" 506 | source: hosted 507 | version: "11.6.0" 508 | pub_semver: 509 | dependency: transitive 510 | description: 511 | name: pub_semver 512 | sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" 513 | url: "https://pub.dev" 514 | source: hosted 515 | version: "2.2.0" 516 | pubspec_lock: 517 | dependency: transitive 518 | description: 519 | name: pubspec_lock 520 | sha256: ed5fc1ecd0cdc0e14475a091afcb2c4cbb00e74cebff17635e9abbec18d76cc4 521 | url: "https://pub.dev" 522 | source: hosted 523 | version: "3.0.2" 524 | pubspec_manager: 525 | dependency: "direct main" 526 | description: 527 | name: pubspec_manager 528 | sha256: "48f425bb06cb38bb8bda84e70794cb373416033519668bcf481efbda1c10d9a1" 529 | url: "https://pub.dev" 530 | source: hosted 531 | version: "3.0.1" 532 | pubspec_parse: 533 | dependency: transitive 534 | description: 535 | name: pubspec_parse 536 | sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" 537 | url: "https://pub.dev" 538 | source: hosted 539 | version: "1.5.0" 540 | rxdart: 541 | dependency: transitive 542 | description: 543 | name: rxdart 544 | sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" 545 | url: "https://pub.dev" 546 | source: hosted 547 | version: "0.28.0" 548 | scope: 549 | dependency: transitive 550 | description: 551 | name: scope 552 | sha256: "0b056e5b64ca16a2db9e1eb35cf7fd05a9e99a6b15140f82bfa651d081e4819b" 553 | url: "https://pub.dev" 554 | source: hosted 555 | version: "5.1.0" 556 | settings_yaml: 557 | dependency: "direct main" 558 | description: 559 | name: settings_yaml 560 | sha256: "8fec1ab4c6ed5efb61cd336e8a86d62c24026d97b08646db00e959d9cc7b11a2" 561 | url: "https://pub.dev" 562 | source: hosted 563 | version: "8.3.1" 564 | shelf: 565 | dependency: transitive 566 | description: 567 | name: shelf 568 | sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 569 | url: "https://pub.dev" 570 | source: hosted 571 | version: "1.4.2" 572 | shelf_packages_handler: 573 | dependency: transitive 574 | description: 575 | name: shelf_packages_handler 576 | sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" 577 | url: "https://pub.dev" 578 | source: hosted 579 | version: "3.0.2" 580 | shelf_static: 581 | dependency: transitive 582 | description: 583 | name: shelf_static 584 | sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 585 | url: "https://pub.dev" 586 | source: hosted 587 | version: "1.1.3" 588 | shelf_web_socket: 589 | dependency: transitive 590 | description: 591 | name: shelf_web_socket 592 | sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" 593 | url: "https://pub.dev" 594 | source: hosted 595 | version: "3.0.0" 596 | simple_sparse_list: 597 | dependency: transitive 598 | description: 599 | name: simple_sparse_list 600 | sha256: aa648fd240fa39b49dcd11c19c266990006006de6699a412de485695910fbc1f 601 | url: "https://pub.dev" 602 | source: hosted 603 | version: "0.1.4" 604 | source_map_stack_trace: 605 | dependency: transitive 606 | description: 607 | name: source_map_stack_trace 608 | sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b 609 | url: "https://pub.dev" 610 | source: hosted 611 | version: "2.1.2" 612 | source_maps: 613 | dependency: transitive 614 | description: 615 | name: source_maps 616 | sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" 617 | url: "https://pub.dev" 618 | source: hosted 619 | version: "0.10.13" 620 | source_span: 621 | dependency: transitive 622 | description: 623 | name: source_span 624 | sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" 625 | url: "https://pub.dev" 626 | source: hosted 627 | version: "1.10.1" 628 | sprintf: 629 | dependency: transitive 630 | description: 631 | name: sprintf 632 | sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" 633 | url: "https://pub.dev" 634 | source: hosted 635 | version: "7.0.0" 636 | stack_trace: 637 | dependency: transitive 638 | description: 639 | name: stack_trace 640 | sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" 641 | url: "https://pub.dev" 642 | source: hosted 643 | version: "1.12.1" 644 | stream_channel: 645 | dependency: transitive 646 | description: 647 | name: stream_channel 648 | sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" 649 | url: "https://pub.dev" 650 | source: hosted 651 | version: "2.1.4" 652 | stream_transform: 653 | dependency: transitive 654 | description: 655 | name: stream_transform 656 | sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 657 | url: "https://pub.dev" 658 | source: hosted 659 | version: "2.1.1" 660 | string_scanner: 661 | dependency: transitive 662 | description: 663 | name: string_scanner 664 | sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" 665 | url: "https://pub.dev" 666 | source: hosted 667 | version: "1.4.1" 668 | strings: 669 | dependency: "direct main" 670 | description: 671 | name: strings 672 | sha256: "8eccabcaad5f3b2d02b2bf8ca31ce1466fac7339229fd0472d63790f8c18095f" 673 | url: "https://pub.dev" 674 | source: hosted 675 | version: "4.0.1" 676 | sum_types: 677 | dependency: transitive 678 | description: 679 | name: sum_types 680 | sha256: c0a0fad9a518d011987e1d9f27fc336194294e55dafdc3699363e52aa5776e09 681 | url: "https://pub.dev" 682 | source: hosted 683 | version: "0.3.5" 684 | system_info2: 685 | dependency: transitive 686 | description: 687 | name: system_info2 688 | sha256: b937736ecfa63c45b10dde1ceb6bb30e5c0c340e14c441df024150679d65ac43 689 | url: "https://pub.dev" 690 | source: hosted 691 | version: "4.1.0" 692 | term_glyph: 693 | dependency: transitive 694 | description: 695 | name: term_glyph 696 | sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" 697 | url: "https://pub.dev" 698 | source: hosted 699 | version: "1.2.2" 700 | test: 701 | dependency: "direct dev" 702 | description: 703 | name: test 704 | sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" 705 | url: "https://pub.dev" 706 | source: hosted 707 | version: "1.26.3" 708 | test_api: 709 | dependency: transitive 710 | description: 711 | name: test_api 712 | sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 713 | url: "https://pub.dev" 714 | source: hosted 715 | version: "0.7.7" 716 | test_core: 717 | dependency: transitive 718 | description: 719 | name: test_core 720 | sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" 721 | url: "https://pub.dev" 722 | source: hosted 723 | version: "0.6.12" 724 | typed_data: 725 | dependency: transitive 726 | description: 727 | name: typed_data 728 | sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 729 | url: "https://pub.dev" 730 | source: hosted 731 | version: "1.4.0" 732 | unicode: 733 | dependency: transitive 734 | description: 735 | name: unicode 736 | sha256: "0d99edbd2e74726bed2e4989713c8bec02e5581628e334d8c88c0271593fb402" 737 | url: "https://pub.dev" 738 | source: hosted 739 | version: "1.1.8" 740 | uuid: 741 | dependency: "direct main" 742 | description: 743 | name: uuid 744 | sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff 745 | url: "https://pub.dev" 746 | source: hosted 747 | version: "4.5.1" 748 | validators2: 749 | dependency: transitive 750 | description: 751 | name: validators2 752 | sha256: "5c63054b2f47b6a3f39e0d0e3f5d38829db4545250144a34c9e1585466de4814" 753 | url: "https://pub.dev" 754 | source: hosted 755 | version: "5.0.0" 756 | vm_service: 757 | dependency: transitive 758 | description: 759 | name: vm_service 760 | sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" 761 | url: "https://pub.dev" 762 | source: hosted 763 | version: "15.0.2" 764 | watcher: 765 | dependency: transitive 766 | description: 767 | name: watcher 768 | sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a" 769 | url: "https://pub.dev" 770 | source: hosted 771 | version: "1.1.4" 772 | web: 773 | dependency: transitive 774 | description: 775 | name: web 776 | sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" 777 | url: "https://pub.dev" 778 | source: hosted 779 | version: "1.1.1" 780 | web_socket: 781 | dependency: transitive 782 | description: 783 | name: web_socket 784 | sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" 785 | url: "https://pub.dev" 786 | source: hosted 787 | version: "1.0.1" 788 | web_socket_channel: 789 | dependency: transitive 790 | description: 791 | name: web_socket_channel 792 | sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 793 | url: "https://pub.dev" 794 | source: hosted 795 | version: "3.0.3" 796 | webkit_inspection_protocol: 797 | dependency: transitive 798 | description: 799 | name: webkit_inspection_protocol 800 | sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" 801 | url: "https://pub.dev" 802 | source: hosted 803 | version: "1.2.1" 804 | win32: 805 | dependency: "direct main" 806 | description: 807 | name: win32 808 | sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e 809 | url: "https://pub.dev" 810 | source: hosted 811 | version: "5.15.0" 812 | yaml: 813 | dependency: transitive 814 | description: 815 | name: yaml 816 | sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce 817 | url: "https://pub.dev" 818 | source: hosted 819 | version: "3.1.3" 820 | sdks: 821 | dart: ">=3.8.0 <4.0.0" 822 | -------------------------------------------------------------------------------- /custom_lint.log: -------------------------------------------------------------------------------- 1 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 Plugin ReorderMembersFix threw while analyzing /home/bsutton/git/dcli_scripts/lib/src/mysql/mysql_settings.dart: 2 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 ConflictingEditException: {"offset":3695,"length":109,"replacement":" String message;\n\n MissingConfigurationException(this.message);\n\n @override\n String toString() => message;"} conflicts with {"offset":3695,"length":109,"replacement":" String message;\n\n MissingConfigurationException(this.message);\n\n @override\n String toString() => message;"} 3 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #0 addEditForSource (package:analyzer_plugin/src/protocol/protocol_internal.dart:77:7) 4 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #1 SourceFileEdit.add (package:analyzer_plugin/protocol/protocol_common.dart:3778:7) 5 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #2 FileEditBuilderImpl._addEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:624:14) 6 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #3 FileEditBuilderImpl._addEditBuilder (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:639:5) 7 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #4 FileEditBuilderImpl.addSimpleReplacement (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:581:7) 8 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #5 ReorderMembersFix.run..applyTo (package:lint_hard/src/reorder_members_fix.dart:97:17) 9 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #6 ReorderMembersFix.run. (package:lint_hard/src/reorder_members_fix.dart:104:7) 10 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #7 ChangeBuilderImpl.addDartFileEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:170:26) 11 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #8 ChangeBuilderImpl.addDartFileEdit. (package:custom_lint_core/src/change_reporter.dart:242:35) 12 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #9 new Future. (dart:async/future.dart:260:40) 13 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #10 _rootRun (dart:async/zone.dart:1517:47) 14 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #11 _CustomZone.run (dart:async/zone.dart:1422:19) 15 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #12 _CustomZone.runGuarded (dart:async/zone.dart:1321:7) 16 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #13 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1362:23) 17 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #14 _rootRun (dart:async/zone.dart:1525:13) 18 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #15 _CustomZone.run (dart:async/zone.dart:1422:19) 19 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #16 _CustomZone.bindCallback. (dart:async/zone.dart:1345:23) 20 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #17 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15) 21 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #18 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:423:19) 22 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #19 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:454:5) 23 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 #20 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12) 24 | [ReorderMembersFix] 2025-10-18T13:10:36.605735 25 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 Plugin ReorderMembersFix threw while analyzing /home/bsutton/git/dcli_scripts/lib/src/mysql/mysql_settings.dart: 26 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 ConflictingEditException: {"offset":546,"length":3086,"replacement":" final String host;\n\n final int port;\n\n final String user;\n\n final String password;\n\n final String dbname;\n\n MySqlSettings(\n {required this.host,\n required this.port,\n required this.user,\n required this.password,\n required this.dbname});\n\n factory MySqlSettings.load(String dbname) {\n final pathToDbSettings = pathToSettings(dbname);\n if (!exists(pathToDbSettings)) {\n throw MissingConfigurationException('''\nNo configuration exists for $dbname at ${truepath(pathToDbSettings)}. \nCheck your database name or run dmysql config $dbname''');\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n final host = settings['host'] as String? ?? 'localhost';\n final port = settings['port'] as int? ?? 3306;\n final user = settings['user'] as String? ?? 'root';\n final password = settings['password'] as String? ?? '';\n\n return MySqlSettings(\n host: host, port: port, user: user, password: password, dbname: dbname);\n }\n\n static Future config(String dbname) async {\n final pathToDbSettings = MySqlSettings.pathToSettings(dbname);\n\n if (!exists(dirname(pathToDbSettings))) {\n createDir(dirname(pathToDbSettings), recursive: true);\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n\n settings['dbname'] = dbname;\n settings['host'] = ask('host:',\n defaultValue: settings['host'] as String?,\n validator: Ask.any([\n Ask.fqdn,\n Ask.ipAddress(),\n Ask.inList(['localhost', '127.0.0.1'])\n ]));\n\n settings['port'] = int.parse(ask('port:',\n defaultValue: (settings['port'] as int? ?? 3306).toString(),\n validator: Ask.integer));\n\n settings['user'] = ask('user:',\n defaultValue: settings['user'] as String?, validator: Ask.required);\n\n settings['password'] = ask('password:',\n defaultValue: settings['password'] as String?,\n validator: Ask.required,\n hidden: true);\n\n if (!_checkDbExists(settings)) {\n if (!confirm(orange(\n \"The database $dbname doesn't exist. Do you want to continue?\"))) {\n throw ExitException(1, '');\n }\n }\n\n // ignore: discarded_futures\n await settings.save();\n return MySqlSettings.load(dbname);\n }\n\n static String pathToSettings(String dbname) => join(pathToDMysql, dbname);\n\n static bool _checkDbExists(SettingsYaml settings) {\n final host = settings['host'] as String;\n final port = settings['port'] as int;\n final database = settings['dbname'] as String;\n final user = settings['user'] as String;\n final password = settings['password'] as String;\n final result = 'mysqlshow --host=$host --port=$port '\n '--user=$user --password=\"$password\" $database'\n .start(nothrow: true, progress: Progress.capture());\n\n if (result.exitCode != 0) {\n final text = result.toParagraph();\n\n if (text.contains('Unknown database')) {\n return false;\n } else {\n throw ExitException(result.exitCode!, text);\n }\n }\n\n return true;\n }"} conflicts with {"offset":546,"length":3086,"replacement":" final String host;\n\n final int port;\n\n final String user;\n\n final String password;\n\n final String dbname;\n\n MySqlSettings(\n {required this.host,\n required this.port,\n required this.user,\n required this.password,\n required this.dbname});\n\n factory MySqlSettings.load(String dbname) {\n final pathToDbSettings = pathToSettings(dbname);\n if (!exists(pathToDbSettings)) {\n throw MissingConfigurationException('''\nNo configuration exists for $dbname at ${truepath(pathToDbSettings)}. \nCheck your database name or run dmysql config $dbname''');\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n final host = settings['host'] as String? ?? 'localhost';\n final port = settings['port'] as int? ?? 3306;\n final user = settings['user'] as String? ?? 'root';\n final password = settings['password'] as String? ?? '';\n\n return MySqlSettings(\n host: host, port: port, user: user, password: password, dbname: dbname);\n }\n\n static Future config(String dbname) async {\n final pathToDbSettings = MySqlSettings.pathToSettings(dbname);\n\n if (!exists(dirname(pathToDbSettings))) {\n createDir(dirname(pathToDbSettings), recursive: true);\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n\n settings['dbname'] = dbname;\n settings['host'] = ask('host:',\n defaultValue: settings['host'] as String?,\n validator: Ask.any([\n Ask.fqdn,\n Ask.ipAddress(),\n Ask.inList(['localhost', '127.0.0.1'])\n ]));\n\n settings['port'] = int.parse(ask('port:',\n defaultValue: (settings['port'] as int? ?? 3306).toString(),\n validator: Ask.integer));\n\n settings['user'] = ask('user:',\n defaultValue: settings['user'] as String?, validator: Ask.required);\n\n settings['password'] = ask('password:',\n defaultValue: settings['password'] as String?,\n validator: Ask.required,\n hidden: true);\n\n if (!_checkDbExists(settings)) {\n if (!confirm(orange(\n \"The database $dbname doesn't exist. Do you want to continue?\"))) {\n throw ExitException(1, '');\n }\n }\n\n // ignore: discarded_futures\n await settings.save();\n return MySqlSettings.load(dbname);\n }\n\n static String pathToSettings(String dbname) => join(pathToDMysql, dbname);\n\n static bool _checkDbExists(SettingsYaml settings) {\n final host = settings['host'] as String;\n final port = settings['port'] as int;\n final database = settings['dbname'] as String;\n final user = settings['user'] as String;\n final password = settings['password'] as String;\n final result = 'mysqlshow --host=$host --port=$port '\n '--user=$user --password=\"$password\" $database'\n .start(nothrow: true, progress: Progress.capture());\n\n if (result.exitCode != 0) {\n final text = result.toParagraph();\n\n if (text.contains('Unknown database')) {\n return false;\n } else {\n throw ExitException(result.exitCode!, text);\n }\n }\n\n return true;\n }"} 27 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #0 addEditForSource (package:analyzer_plugin/src/protocol/protocol_internal.dart:77:7) 28 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #1 SourceFileEdit.add (package:analyzer_plugin/protocol/protocol_common.dart:3778:7) 29 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #2 FileEditBuilderImpl._addEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:624:14) 30 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #3 FileEditBuilderImpl._addEditBuilder (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:639:5) 31 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #4 FileEditBuilderImpl.addSimpleReplacement (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:581:7) 32 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #5 ReorderMembersFix.run..applyTo (package:lint_hard/src/reorder_members_fix.dart:97:17) 33 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #6 ReorderMembersFix.run. (package:lint_hard/src/reorder_members_fix.dart:110:11) 34 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #7 ChangeBuilderImpl.addDartFileEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:170:26) 35 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #8 ChangeBuilderImpl.addDartFileEdit. (package:custom_lint_core/src/change_reporter.dart:242:35) 36 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #9 new Future. (dart:async/future.dart:260:40) 37 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #10 _rootRun (dart:async/zone.dart:1517:47) 38 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #11 _CustomZone.run (dart:async/zone.dart:1422:19) 39 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #12 _CustomZone.runGuarded (dart:async/zone.dart:1321:7) 40 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #13 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1362:23) 41 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #14 _rootRun (dart:async/zone.dart:1525:13) 42 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #15 _CustomZone.run (dart:async/zone.dart:1422:19) 43 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #16 _CustomZone.bindCallback. (dart:async/zone.dart:1345:23) 44 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #17 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15) 45 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #18 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:423:19) 46 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #19 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:454:5) 47 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 #20 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12) 48 | [ReorderMembersFix] 2025-10-18T13:10:36.606177 49 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 Plugin ReorderMembersFix threw while analyzing /home/bsutton/git/dcli_scripts/lib/src/mysql/mysql_settings.dart: 50 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 ConflictingEditException: {"offset":3695,"length":109,"replacement":" String message;\n\n MissingConfigurationException(this.message);\n\n @override\n String toString() => message;"} conflicts with {"offset":3695,"length":109,"replacement":" String message;\n\n MissingConfigurationException(this.message);\n\n @override\n String toString() => message;"} 51 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #0 addEditForSource (package:analyzer_plugin/src/protocol/protocol_internal.dart:77:7) 52 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #1 SourceFileEdit.add (package:analyzer_plugin/protocol/protocol_common.dart:3778:7) 53 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #2 FileEditBuilderImpl._addEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:624:14) 54 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #3 FileEditBuilderImpl._addEditBuilder (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:639:5) 55 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #4 FileEditBuilderImpl.addSimpleReplacement (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:581:7) 56 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #5 ReorderMembersFix.run..applyTo (package:lint_hard/src/reorder_members_fix.dart:97:17) 57 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #6 ReorderMembersFix.run. (package:lint_hard/src/reorder_members_fix.dart:104:7) 58 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #7 ChangeBuilderImpl.addDartFileEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:170:26) 59 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #8 ChangeBuilderImpl.addDartFileEdit. (package:custom_lint_core/src/change_reporter.dart:242:35) 60 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #9 new Future. (dart:async/future.dart:260:40) 61 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #10 _rootRun (dart:async/zone.dart:1517:47) 62 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #11 _CustomZone.run (dart:async/zone.dart:1422:19) 63 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #12 _CustomZone.runGuarded (dart:async/zone.dart:1321:7) 64 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #13 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1362:23) 65 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #14 _rootRun (dart:async/zone.dart:1525:13) 66 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #15 _CustomZone.run (dart:async/zone.dart:1422:19) 67 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #16 _CustomZone.bindCallback. (dart:async/zone.dart:1345:23) 68 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #17 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15) 69 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #18 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:423:19) 70 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #19 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:454:5) 71 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 #20 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12) 72 | [ReorderMembersFix] 2025-10-18T13:10:36.895984 73 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 Plugin ReorderMembersFix threw while analyzing /home/bsutton/git/dcli_scripts/lib/src/mysql/mysql_settings.dart: 74 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 ConflictingEditException: {"offset":546,"length":3086,"replacement":" final String host;\n\n final int port;\n\n final String user;\n\n final String password;\n\n final String dbname;\n\n MySqlSettings(\n {required this.host,\n required this.port,\n required this.user,\n required this.password,\n required this.dbname});\n\n factory MySqlSettings.load(String dbname) {\n final pathToDbSettings = pathToSettings(dbname);\n if (!exists(pathToDbSettings)) {\n throw MissingConfigurationException('''\nNo configuration exists for $dbname at ${truepath(pathToDbSettings)}. \nCheck your database name or run dmysql config $dbname''');\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n final host = settings['host'] as String? ?? 'localhost';\n final port = settings['port'] as int? ?? 3306;\n final user = settings['user'] as String? ?? 'root';\n final password = settings['password'] as String? ?? '';\n\n return MySqlSettings(\n host: host, port: port, user: user, password: password, dbname: dbname);\n }\n\n static Future config(String dbname) async {\n final pathToDbSettings = MySqlSettings.pathToSettings(dbname);\n\n if (!exists(dirname(pathToDbSettings))) {\n createDir(dirname(pathToDbSettings), recursive: true);\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n\n settings['dbname'] = dbname;\n settings['host'] = ask('host:',\n defaultValue: settings['host'] as String?,\n validator: Ask.any([\n Ask.fqdn,\n Ask.ipAddress(),\n Ask.inList(['localhost', '127.0.0.1'])\n ]));\n\n settings['port'] = int.parse(ask('port:',\n defaultValue: (settings['port'] as int? ?? 3306).toString(),\n validator: Ask.integer));\n\n settings['user'] = ask('user:',\n defaultValue: settings['user'] as String?, validator: Ask.required);\n\n settings['password'] = ask('password:',\n defaultValue: settings['password'] as String?,\n validator: Ask.required,\n hidden: true);\n\n if (!_checkDbExists(settings)) {\n if (!confirm(orange(\n \"The database $dbname doesn't exist. Do you want to continue?\"))) {\n throw ExitException(1, '');\n }\n }\n\n // ignore: discarded_futures\n await settings.save();\n return MySqlSettings.load(dbname);\n }\n\n static String pathToSettings(String dbname) => join(pathToDMysql, dbname);\n\n static bool _checkDbExists(SettingsYaml settings) {\n final host = settings['host'] as String;\n final port = settings['port'] as int;\n final database = settings['dbname'] as String;\n final user = settings['user'] as String;\n final password = settings['password'] as String;\n final result = 'mysqlshow --host=$host --port=$port '\n '--user=$user --password=\"$password\" $database'\n .start(nothrow: true, progress: Progress.capture());\n\n if (result.exitCode != 0) {\n final text = result.toParagraph();\n\n if (text.contains('Unknown database')) {\n return false;\n } else {\n throw ExitException(result.exitCode!, text);\n }\n }\n\n return true;\n }"} conflicts with {"offset":546,"length":3086,"replacement":" final String host;\n\n final int port;\n\n final String user;\n\n final String password;\n\n final String dbname;\n\n MySqlSettings(\n {required this.host,\n required this.port,\n required this.user,\n required this.password,\n required this.dbname});\n\n factory MySqlSettings.load(String dbname) {\n final pathToDbSettings = pathToSettings(dbname);\n if (!exists(pathToDbSettings)) {\n throw MissingConfigurationException('''\nNo configuration exists for $dbname at ${truepath(pathToDbSettings)}. \nCheck your database name or run dmysql config $dbname''');\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n final host = settings['host'] as String? ?? 'localhost';\n final port = settings['port'] as int? ?? 3306;\n final user = settings['user'] as String? ?? 'root';\n final password = settings['password'] as String? ?? '';\n\n return MySqlSettings(\n host: host, port: port, user: user, password: password, dbname: dbname);\n }\n\n static Future config(String dbname) async {\n final pathToDbSettings = MySqlSettings.pathToSettings(dbname);\n\n if (!exists(dirname(pathToDbSettings))) {\n createDir(dirname(pathToDbSettings), recursive: true);\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n\n settings['dbname'] = dbname;\n settings['host'] = ask('host:',\n defaultValue: settings['host'] as String?,\n validator: Ask.any([\n Ask.fqdn,\n Ask.ipAddress(),\n Ask.inList(['localhost', '127.0.0.1'])\n ]));\n\n settings['port'] = int.parse(ask('port:',\n defaultValue: (settings['port'] as int? ?? 3306).toString(),\n validator: Ask.integer));\n\n settings['user'] = ask('user:',\n defaultValue: settings['user'] as String?, validator: Ask.required);\n\n settings['password'] = ask('password:',\n defaultValue: settings['password'] as String?,\n validator: Ask.required,\n hidden: true);\n\n if (!_checkDbExists(settings)) {\n if (!confirm(orange(\n \"The database $dbname doesn't exist. Do you want to continue?\"))) {\n throw ExitException(1, '');\n }\n }\n\n // ignore: discarded_futures\n await settings.save();\n return MySqlSettings.load(dbname);\n }\n\n static String pathToSettings(String dbname) => join(pathToDMysql, dbname);\n\n static bool _checkDbExists(SettingsYaml settings) {\n final host = settings['host'] as String;\n final port = settings['port'] as int;\n final database = settings['dbname'] as String;\n final user = settings['user'] as String;\n final password = settings['password'] as String;\n final result = 'mysqlshow --host=$host --port=$port '\n '--user=$user --password=\"$password\" $database'\n .start(nothrow: true, progress: Progress.capture());\n\n if (result.exitCode != 0) {\n final text = result.toParagraph();\n\n if (text.contains('Unknown database')) {\n return false;\n } else {\n throw ExitException(result.exitCode!, text);\n }\n }\n\n return true;\n }"} 75 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #0 addEditForSource (package:analyzer_plugin/src/protocol/protocol_internal.dart:77:7) 76 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #1 SourceFileEdit.add (package:analyzer_plugin/protocol/protocol_common.dart:3778:7) 77 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #2 FileEditBuilderImpl._addEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:624:14) 78 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #3 FileEditBuilderImpl._addEditBuilder (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:639:5) 79 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #4 FileEditBuilderImpl.addSimpleReplacement (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:581:7) 80 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #5 ReorderMembersFix.run..applyTo (package:lint_hard/src/reorder_members_fix.dart:97:17) 81 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #6 ReorderMembersFix.run. (package:lint_hard/src/reorder_members_fix.dart:110:11) 82 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #7 ChangeBuilderImpl.addDartFileEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:170:26) 83 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #8 ChangeBuilderImpl.addDartFileEdit. (package:custom_lint_core/src/change_reporter.dart:242:35) 84 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #9 new Future. (dart:async/future.dart:260:40) 85 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #10 _rootRun (dart:async/zone.dart:1517:47) 86 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #11 _CustomZone.run (dart:async/zone.dart:1422:19) 87 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #12 _CustomZone.runGuarded (dart:async/zone.dart:1321:7) 88 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #13 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1362:23) 89 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #14 _rootRun (dart:async/zone.dart:1525:13) 90 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #15 _CustomZone.run (dart:async/zone.dart:1422:19) 91 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #16 _CustomZone.bindCallback. (dart:async/zone.dart:1345:23) 92 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #17 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15) 93 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #18 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:423:19) 94 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #19 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:454:5) 95 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 #20 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12) 96 | [ReorderMembersFix] 2025-10-18T13:10:36.896620 97 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 Plugin ReorderMembersFix threw while analyzing /home/bsutton/git/dcli_scripts/lib/src/mysql/mysql_settings.dart: 98 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 ConflictingEditException: {"offset":3695,"length":109,"replacement":" String message;\n\n MissingConfigurationException(this.message);\n\n @override\n String toString() => message;"} conflicts with {"offset":3695,"length":109,"replacement":" String message;\n\n MissingConfigurationException(this.message);\n\n @override\n String toString() => message;"} 99 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #0 addEditForSource (package:analyzer_plugin/src/protocol/protocol_internal.dart:77:7) 100 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #1 SourceFileEdit.add (package:analyzer_plugin/protocol/protocol_common.dart:3778:7) 101 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #2 FileEditBuilderImpl._addEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:624:14) 102 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #3 FileEditBuilderImpl._addEditBuilder (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:639:5) 103 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #4 FileEditBuilderImpl.addSimpleReplacement (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:581:7) 104 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #5 ReorderMembersFix.run..applyTo (package:lint_hard/src/reorder_members_fix.dart:97:17) 105 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #6 ReorderMembersFix.run. (package:lint_hard/src/reorder_members_fix.dart:104:7) 106 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #7 ChangeBuilderImpl.addDartFileEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:170:26) 107 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #8 ChangeBuilderImpl.addDartFileEdit. (package:custom_lint_core/src/change_reporter.dart:242:35) 108 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #9 new Future. (dart:async/future.dart:260:40) 109 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #10 _rootRun (dart:async/zone.dart:1517:47) 110 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #11 _CustomZone.run (dart:async/zone.dart:1422:19) 111 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #12 _CustomZone.runGuarded (dart:async/zone.dart:1321:7) 112 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #13 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1362:23) 113 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #14 _rootRun (dart:async/zone.dart:1525:13) 114 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #15 _CustomZone.run (dart:async/zone.dart:1422:19) 115 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #16 _CustomZone.bindCallback. (dart:async/zone.dart:1345:23) 116 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #17 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15) 117 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #18 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:423:19) 118 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #19 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:454:5) 119 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 #20 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12) 120 | [ReorderMembersFix] 2025-10-18T13:10:37.902331 121 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 Plugin ReorderMembersFix threw while analyzing /home/bsutton/git/dcli_scripts/lib/src/mysql/mysql_settings.dart: 122 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 ConflictingEditException: {"offset":546,"length":3086,"replacement":" final String host;\n\n final int port;\n\n final String user;\n\n final String password;\n\n final String dbname;\n\n MySqlSettings(\n {required this.host,\n required this.port,\n required this.user,\n required this.password,\n required this.dbname});\n\n factory MySqlSettings.load(String dbname) {\n final pathToDbSettings = pathToSettings(dbname);\n if (!exists(pathToDbSettings)) {\n throw MissingConfigurationException('''\nNo configuration exists for $dbname at ${truepath(pathToDbSettings)}. \nCheck your database name or run dmysql config $dbname''');\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n final host = settings['host'] as String? ?? 'localhost';\n final port = settings['port'] as int? ?? 3306;\n final user = settings['user'] as String? ?? 'root';\n final password = settings['password'] as String? ?? '';\n\n return MySqlSettings(\n host: host, port: port, user: user, password: password, dbname: dbname);\n }\n\n static Future config(String dbname) async {\n final pathToDbSettings = MySqlSettings.pathToSettings(dbname);\n\n if (!exists(dirname(pathToDbSettings))) {\n createDir(dirname(pathToDbSettings), recursive: true);\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n\n settings['dbname'] = dbname;\n settings['host'] = ask('host:',\n defaultValue: settings['host'] as String?,\n validator: Ask.any([\n Ask.fqdn,\n Ask.ipAddress(),\n Ask.inList(['localhost', '127.0.0.1'])\n ]));\n\n settings['port'] = int.parse(ask('port:',\n defaultValue: (settings['port'] as int? ?? 3306).toString(),\n validator: Ask.integer));\n\n settings['user'] = ask('user:',\n defaultValue: settings['user'] as String?, validator: Ask.required);\n\n settings['password'] = ask('password:',\n defaultValue: settings['password'] as String?,\n validator: Ask.required,\n hidden: true);\n\n if (!_checkDbExists(settings)) {\n if (!confirm(orange(\n \"The database $dbname doesn't exist. Do you want to continue?\"))) {\n throw ExitException(1, '');\n }\n }\n\n // ignore: discarded_futures\n await settings.save();\n return MySqlSettings.load(dbname);\n }\n\n static String pathToSettings(String dbname) => join(pathToDMysql, dbname);\n\n static bool _checkDbExists(SettingsYaml settings) {\n final host = settings['host'] as String;\n final port = settings['port'] as int;\n final database = settings['dbname'] as String;\n final user = settings['user'] as String;\n final password = settings['password'] as String;\n final result = 'mysqlshow --host=$host --port=$port '\n '--user=$user --password=\"$password\" $database'\n .start(nothrow: true, progress: Progress.capture());\n\n if (result.exitCode != 0) {\n final text = result.toParagraph();\n\n if (text.contains('Unknown database')) {\n return false;\n } else {\n throw ExitException(result.exitCode!, text);\n }\n }\n\n return true;\n }"} conflicts with {"offset":546,"length":3086,"replacement":" final String host;\n\n final int port;\n\n final String user;\n\n final String password;\n\n final String dbname;\n\n MySqlSettings(\n {required this.host,\n required this.port,\n required this.user,\n required this.password,\n required this.dbname});\n\n factory MySqlSettings.load(String dbname) {\n final pathToDbSettings = pathToSettings(dbname);\n if (!exists(pathToDbSettings)) {\n throw MissingConfigurationException('''\nNo configuration exists for $dbname at ${truepath(pathToDbSettings)}. \nCheck your database name or run dmysql config $dbname''');\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n final host = settings['host'] as String? ?? 'localhost';\n final port = settings['port'] as int? ?? 3306;\n final user = settings['user'] as String? ?? 'root';\n final password = settings['password'] as String? ?? '';\n\n return MySqlSettings(\n host: host, port: port, user: user, password: password, dbname: dbname);\n }\n\n static Future config(String dbname) async {\n final pathToDbSettings = MySqlSettings.pathToSettings(dbname);\n\n if (!exists(dirname(pathToDbSettings))) {\n createDir(dirname(pathToDbSettings), recursive: true);\n }\n final settings = SettingsYaml.load(pathToSettings: pathToDbSettings);\n\n settings['dbname'] = dbname;\n settings['host'] = ask('host:',\n defaultValue: settings['host'] as String?,\n validator: Ask.any([\n Ask.fqdn,\n Ask.ipAddress(),\n Ask.inList(['localhost', '127.0.0.1'])\n ]));\n\n settings['port'] = int.parse(ask('port:',\n defaultValue: (settings['port'] as int? ?? 3306).toString(),\n validator: Ask.integer));\n\n settings['user'] = ask('user:',\n defaultValue: settings['user'] as String?, validator: Ask.required);\n\n settings['password'] = ask('password:',\n defaultValue: settings['password'] as String?,\n validator: Ask.required,\n hidden: true);\n\n if (!_checkDbExists(settings)) {\n if (!confirm(orange(\n \"The database $dbname doesn't exist. Do you want to continue?\"))) {\n throw ExitException(1, '');\n }\n }\n\n // ignore: discarded_futures\n await settings.save();\n return MySqlSettings.load(dbname);\n }\n\n static String pathToSettings(String dbname) => join(pathToDMysql, dbname);\n\n static bool _checkDbExists(SettingsYaml settings) {\n final host = settings['host'] as String;\n final port = settings['port'] as int;\n final database = settings['dbname'] as String;\n final user = settings['user'] as String;\n final password = settings['password'] as String;\n final result = 'mysqlshow --host=$host --port=$port '\n '--user=$user --password=\"$password\" $database'\n .start(nothrow: true, progress: Progress.capture());\n\n if (result.exitCode != 0) {\n final text = result.toParagraph();\n\n if (text.contains('Unknown database')) {\n return false;\n } else {\n throw ExitException(result.exitCode!, text);\n }\n }\n\n return true;\n }"} 123 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #0 addEditForSource (package:analyzer_plugin/src/protocol/protocol_internal.dart:77:7) 124 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #1 SourceFileEdit.add (package:analyzer_plugin/protocol/protocol_common.dart:3778:7) 125 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #2 FileEditBuilderImpl._addEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:624:14) 126 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #3 FileEditBuilderImpl._addEditBuilder (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:639:5) 127 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #4 FileEditBuilderImpl.addSimpleReplacement (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:581:7) 128 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #5 ReorderMembersFix.run..applyTo (package:lint_hard/src/reorder_members_fix.dart:97:17) 129 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #6 ReorderMembersFix.run. (package:lint_hard/src/reorder_members_fix.dart:110:11) 130 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #7 ChangeBuilderImpl.addDartFileEdit (package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart:170:26) 131 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #8 ChangeBuilderImpl.addDartFileEdit. (package:custom_lint_core/src/change_reporter.dart:242:35) 132 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #9 new Future. (dart:async/future.dart:260:40) 133 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #10 _rootRun (dart:async/zone.dart:1517:47) 134 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #11 _CustomZone.run (dart:async/zone.dart:1422:19) 135 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #12 _CustomZone.runGuarded (dart:async/zone.dart:1321:7) 136 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #13 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1362:23) 137 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #14 _rootRun (dart:async/zone.dart:1525:13) 138 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #15 _CustomZone.run (dart:async/zone.dart:1422:19) 139 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #16 _CustomZone.bindCallback. (dart:async/zone.dart:1345:23) 140 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #17 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15) 141 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #18 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:423:19) 142 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #19 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:454:5) 143 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 #20 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12) 144 | [ReorderMembersFix] 2025-10-18T13:10:37.902850 145 | --------------------------------------------------------------------------------