Flutter钩子管理插件hooksman的功能

Flutter钩子管理插件hooksman的功能

概述

hooksman 插件允许你使用 Dart 管理和执行 Git 钩子。你可以将钩子定义为 Dart 文件,并注册它们以在相应的事件发生时自动运行(例如,pre-commit、post-commit 等)。受 lint-stagedhusky 的启发,hooksman 提供了一种灵活且强大的方式来自动化工作流程中的任务,并在团队中共享这些任务。

通过 hooksman,你可以在钩子中运行 shell 命令、Dart 代码或两者的组合,以强制执行编码标准、运行测试或其他任务。

任务用于保护你的代码库,如果任务失败,hooksman 将以非零状态码退出,阻止钩子完成(例如,pre-commit 钩子)。

安装

pubspec.yaml 中添加 hooksman

dart pub add hooksman --dev

然后运行 dart pub get 来安装该包。

注册钩子

要将钩子与 Git 注册,请运行以下命令:

dart run hooksman

此命令将编译你的钩子并将可执行文件复制到钩子目录。

警告

`hooksman` 包会用新的钩子覆盖 所有 存在于 `.git/hooks` 目录中的现有钩子。在运行 `hooksman` 命令之前,请确保备份任何现有的钩子。
Dart钩子

创建钩子目录

在项目的根目录下创建一个 hooks 目录以存储你的钩子。

.
├── hooks
├── lib
│   └── ...
└── pubspec.yaml

创建钩子

hooks 目录中创建你的钩子作为 Dart 文件。每个文件应包含一个返回 Hook 对象的 main 函数,该对象从 hooksman 包导入。

import 'package:hooksman/hooksman.dart';

Hook main() {
    return Hook(
        ... // 任务
    );
}

注意

`hooksman` 扫描 `hooks` 目录中的 Dart 文件以用作钩子。你可以通过在 `hooks` 目录中创建子目录来组织你的代码。这些文件可以导入到你的钩子文件中,并且不会被 `hooksman` 识别为钩子。
.
└── hooks
├── tasks
│   ├── some_dart_task.dart # 被忽略
│   └── ...
└── pre_commit.dart # 被选中

钩子名称

钩子的名称来自文件名。例如,名为 pre_commit.dart 的文件将被注册为 pre-commit 钩子。请确保遵循 Git 钩子的命名约定。

提示

查看 Git 钩子文档以了解可用的钩子:Git 钩子文档
Shell钩子

你可以通过在钩子目录中创建 shell 文件来创建独立的 shell 钩子。这些文件将在相应的 Git 钩子事件发生时被复制到 .git/hooks 目录并执行。

创建 Shell 钩子

hooks 目录中创建一个 shell 文件。文件名应与你要使用的 Git 钩子名称匹配。

touch hooks/post-commit.sh

重要

文件扩展名应为 `.sh` 以便被识别为 shell 钩子。

Shell 钩子内容

在 shell 文件中添加你要运行的 shell 命令。

#!/bin/sh

echo "Running post-commit hook"

提示

你可以通过使用可执行文件的名称从 shell 钩子中执行 Dart 钩子
#!/bin/sh

./pre-commit # 执行 pre-commit Dart 钩子
任务

任务是你定义的模块化的工作单元,用于在特定的 Git 钩子事件期间执行。它们允许你自动化检查、验证或任何自定义脚本,以确保代码质量和一致性。任务很强大,因为它们可以根据项目的需求进行定制,同时针对特定的文件路径或模式。

所有顶级任务都并行执行,而组内的任务则按顺序执行。这允许你并发运行多个任务并将相关的任务分组在一起。

文件模式

你可以使用任何 Pattern 对象(GlobRegExpString 等)指定任务要包含或排除的文件模式。每个任务可以有多个包含和排除模式。

提示

`hooksman` 暴露了来自 Glob 包的 `Glob` 类,以使用 glob 模式匹配文件路径。

hooksman 还有一个 AllFiles 类来匹配所有文件路径。

注意

`exclude` 在应用 `include` 之前过滤任何匹配的文件。

应用过滤器后,剩余的文件将传递给任务的 commandsrun 函数。

任务命名

每个任务都有一个名称,当任务执行时会显示该名称。这对于在输出中识别任务很有用。默认情况下,任务的名称是用于包含文件的模式。如果你想提供一个自定义名称,可以通过设置任务的 name 属性来实现。

ShellTask(
    name: 'Analyze',
    include: [Glob('**.dart')],
    exclude: [Glob('**.g.dart')],
    commands: (filePaths) => [
        'dart analyze --fatal-infos ${filePaths.join(' ')}',
    ],
),

Shell 任务

ShellTask 允许你运行 shell 命令。

ShellTask(
    name: 'Analyze',
    include: [Glob('**.dart')],
    exclude: [Glob('**.g.dart')],
    commands: (filePaths) => [
        'dart analyze --fatal-infos ${filePaths.join(' ')}',
    ],
),

Dart 任务

DartTask 允许你运行 Dart 代码。

DartTask(
    include: [Glob('**.dart')],
    run: (filePaths) async {
        print('Running custom task');

        return 0;
    },
),

顺序任务

你可以使用 SequentialTasks 类将任务分组在一起,该类按顺序运行任务,一个接一个。

SequentialTasks(
    tasks: [
        ShellTask(
            include: [Glob('**.dart')],
            commands: (filePaths) => [
                'dart format ${filePaths.join(' ')}',
            ],
        ),
        ShellTask(
            include: [Glob('**.dart')],
            commands: (filePaths) => [
                'sip test --concurrent --bail',
            ],
        ),
    ],
),

提示

查看 `sip_cli` 以获取用于管理 mono-repos、维护项目脚本并在多个包中运行 `dart|flutter pub get` 的 Dart 基于 CLI 工具。

并行任务

你可以使用 ParallelTasks 类将任务分组在一起,该类并行运行任务。

ParallelTasks(
    tasks: [
        ShellTask(
            include: [Glob('**.dart')],
            commands: (filePaths) => [
                'dart format ${filePaths.join(' ')}',
            ],
        ),
        ShellTask(
            include: [Glob('**.dart')],
            commands: (filePaths) => [
                'sip test --concurrent --bail',
            ],
        ),
    ],
),

提示

查看 `sip_cli` 以获取用于管理 mono-repos、维护项目脚本并在多个包中运行 `dart|flutter pub get` 的 Dart 基于 CLI 工具。
预定义任务

重新注册钩子

忘记重新注册钩子是很常见的。在更改之后重新注册钩子是必要的,因为你的 Dart 文件会被编译成可执行文件,然后复制到 .git/hooks 目录。

为了自动化这个过程,你可以使用 ReRegisterHooks 任务。每当钩子文件被创建、修改或删除时,此任务都会重新注册你的钩子。

Hook main() {
  return Hook(
    tasks: [
      ReRegisterHooks(),
    ],
  );
}

提示

如果你的 `hooks` 目录不在项目的根目录中,你可以将 `hooks` 目录的路径传递给 `ReRegisterHooks` 任务。
ReRegisterHooks(pathToHooksDir: 'path/to/hooks'),
钩子执行

钩子会在相应的事件发生时由 Git 自动执行(例如,pre-commit、post-commit 等)。

添加到提交

类似于 lint-stagedhooksman 会在运行任务后将创建、删除或修改的文件添加到提交中。确保更改包含在提交中。

例如,当你有一个使用 dart format 格式化代码的 ShellTask。如果代码格式不正确,hooksman 将格式化代码并将更改添加到提交中。

部分已暂存文件

部分已暂存文件是指你在索引中暂存了 some_file.dart,同时在同一 some_file.dart 文件的工作目录中也有一些更改。

当任务执行时,hooksman 会将未暂存的更改暂存到部分已暂存的文件中,运行任务,然后弹出带有更改的暂存。这很有益处,因为它确保任务在索引中暂存的文件版本上运行,而不是工作目录中的版本。

错误处理

如果任务执行过程中发生错误,hooksman 将停止剩余任务的执行并以非零状态码退出。这将阻止提交,允许你在再次提交前修复问题。

信号中断

如果用户中断钩子执行(例如,按下 Ctrl+C),hooksman 将停止剩余任务的执行并以非零状态码退出。采取额外预防措施以确保仓库保持干净状态。

配置

钩子最初设置为在 pre-commit 钩子中运行,但你可以通过在 Hook 对象中指定 diffdiffFilters 参数来配置钩子以运行其他事件。

diffFilters 参数

diffFilters 参数允许你指定要包含或排除的文件的状态,例如 addedmodifieddeleted

Hook main() {
  return Hook(
    diffFilters: 'AM', // 包括添加和修改的文件
    tasks: [
      ...
    ],
  );
}

diff 参数

diff 参数允许你指定如何将文件与工作目录、索引或提交进行比较。

下面的示例演示了如何将文件与远程分支(例如 origin/main)进行比较。这可能对 pre-push 钩子有用。

Hook main() {
  return Hook(
    diffArgs: ['@{u}', 'HEAD'], // 将文件与远程分支进行比较
    tasks: [
      ...
    ],
  );
}
详细输出

你可以通过使用 VerboseHook 类启用详细输出。这将 减慢 任务的执行速度并输出有关正在执行的任务的详细信息。这在理解执行顺序和处理的文件方面非常有用。这不是用于非开发环境的。

示例
// hooks/pre_commit.dart

import 'package:hooksman/hooksman.dart';

Hook main() {
  return Hook(
    tasks: [
      ReRegisterHooks(),
      ShellTask(
        name: 'Lint & Format',
        include: [Glob('**.dart')],
        exclude: [
          Glob('**.g.dart'),
        ],
        commands: (filePaths) => [
          'dart analyze --fatal-infos ${filePaths.join(' ')}',
          'dart format ${filePaths.join(' ')}',
        ],
      ),
      ShellTask(
        name: 'Build Runner',
        include: [Glob('lib/models/**.dart')],
        exclude: [Glob('**.g.dart')],
        commands: (filePaths) => [
          'sip run build_runner build',
        ],
      ),
      ShellTask(
        name: 'Tests',
        include: [Glob('**.dart')],
        exclude: [Glob('hooks/**')],
        commands: (filePaths) => [
          'sip test --concurrent --bail',
        ],
      ),
    ],
  );
}

更多关于Flutter钩子管理插件hooksman的功能的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter钩子管理插件hooksman的功能的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,hooksman 是一个用于管理应用生命周期钩子(hooks)的插件。通过 hooksman,开发者可以在应用的特定生命周期事件(如启动、暂停、恢复等)上注册和执行代码。虽然 hooksman 并不是 Flutter 官方插件,但它为管理应用状态提供了便利。

以下是一个简单的示例,展示如何使用 hooksman 来管理应用的生命周期钩子。

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 hooksman 依赖:

dependencies:
  flutter:
    sdk: flutter
  hooksman: ^最新版本号  # 请替换为实际的最新版本号

然后运行 flutter pub get 来获取依赖。

2. 初始化 HooksManager

在你的应用入口文件(通常是 main.dart)中,初始化 HooksManager 并注册钩子。

import 'package:flutter/material.dart';
import 'package:hooksman/hooksman.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 初始化 HooksManager
    HooksManager.instance.init(context);

    // 注册应用生命周期钩子
    HooksManager.instance.registerHooks([
      AppLifecycleHook(
        onResume: () {
          print("App resumed");
          // 在这里添加应用恢复时的逻辑
        },
        onPause: () {
          print("App paused");
          // 在这里添加应用暂停时的逻辑
        },
        onDestroy: () {
          print("App destroyed");
          // 在这里添加应用销毁时的逻辑
        },
      ),
    ]);

    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Demo Home Page'),
      ),
      body: Center(
        child: Text('Hello, Flutter!'),
      ),
    );
  }
}

3. 处理生命周期事件

在上述代码中,我们注册了三个生命周期钩子:onResumeonPauseonDestroy。当应用的状态改变时,这些钩子将被调用,并打印相应的消息。

  • onResume:当应用从暂停状态恢复时调用。
  • onPause:当应用进入暂停状态时调用(例如,当用户切换到另一个应用或锁屏时)。
  • onDestroy:当应用被销毁时调用(例如,当用户关闭应用时)。

注意事项

  • HooksManager.instance.init(context) 需要在你的应用上下文中初始化。通常,这会在 MaterialAppCupertinoApp 的构建方法中完成。
  • HooksManager.instance.registerHooks 方法用于注册钩子。你可以根据需要注册多个钩子。
  • 钩子回调中的逻辑应该尽量简短和高效,以避免影响应用的性能。

请注意,hooksman 插件的具体 API 和使用方法可能会随着版本的更新而变化。因此,建议查阅最新的官方文档或源代码以获取最准确的信息。

回到顶部