使用 Swift 递归搜索目录中文件的内容,同时支持 Glob 模式和正则表达式

前言

如果你新加入一个团队,想要快速的了解团队的领域和团队中拥有的代码库的详细信息。

如果新团队中的代码库在 GitHub / GitLab 中并且你不熟悉代码所有权模型的概念或格式。本篇文章以 GitHub 为例,你可以使用 Glob 模式将一个或多个文件链接到 GitHub 团队。

如果新团队中的代码库有一个 GitHub 的 CODEOWNERS 文件,可以反映拥有的每个文件或文件组。这是对了解整个框架有很大帮助,如果没有,可以尝试创建一个。如下:

  • /Tests/ @MyAwesomeOrg/cool-beans
  • /Modules/Account/Tests/* @MyAwesomeOrg/cool-beans
  • /Modules/Account/Settings/**/Views @MyAwesomeOrg/cool-beans

我曾经经历手动去查找团队拥有的文件中的文本出现的次数,比如固定模块的多次重复使用,这非常的耗费时间。

本篇文章讲帮助大家写一个小脚本来自动完成这项任务,给定一些文本片段和一个 GitHub 团队标签,它将在团队拥有的文件中找到该文本的所有出现次数。

项目设置

首先,要做的第一件事是创建一个可执行的 Swift Package:

css 复制代码
mkdir find-code-owner && cd find-code-owner
swift package init --name FindCodeOwner --type executable

然后,将 ChimeHQGlobPattern Swift Package 添加为依赖项,以帮助确定包含查询文本的文件是否由提供的 GitHub 团队拥有:

swift 复制代码
// swift-tools-version: 5.10

import PackageDescription

let package = Package(
    name: "FindCodeOwner",
    platforms: [
        .macOS(.v13)
    ],
    dependencies: [
        .package(url: "https://github.com/ChimeHQ/GlobPattern.git", exact: "0.1.1")
    ],
    targets: [
        .executableTarget(
            name: "FindCodeOwner",
            dependencies: ["GlobPattern"],
            swiftSettings: [
                .enableUpcomingFeature("BareSlashRegexLiterals")
            ]
        ),
    ]
)

查找文件

假设我们的团队想要迁移一个名为 Quick 的依赖,我们想要找到所有我们拥有的导入该库的文件。

让我们在我们的可执行目标中编写一些代码来实现这一点:

swift 复制代码
import Foundation
import GlobPattern

struct OwnershipRule {
    let path: String
    let teams: [String]
}

func getRules(from codeOwnersFile: String, relativeTo repository: String) -> [OwnershipRule] {
    guard let content = try? String(contentsOfFile: codeOwnersFile) else {
        return []
    }
    
    return content
        .components(separatedBy: .newlines)
        .filter { $0.isEmpty || $0.hasPrefix("#") }
        .map { createRule(from: $0, relativeTo: repository) }
}

func createRule(from line: String, relativeTo repository: String) -> OwnershipRule {
    let elements = line.components(separatedBy: .whitespaces)
        .filter { !$0.isEmpty }

    let teams = elements
        .enumerated()
        .filter { $0 != 0 && $1.hasPrefix("@") }
        .map(\.1)
    
    return OwnershipRule(path: repository + elements[0], teams: teams)
}

func getOwnersForFile(_ filePath: String, rules: [OwnershipRule]) -> [String] {
    rules
        .reversed()
        .first { rule in
            let globExpression = URL(string: rule.path)?.hasDirectoryPath == true ? rule.path + "*" : rule.path
            let matcher = try? Glob.Pattern(globExpression)
            return matcher?.match(filePath) == true
        }?
        .teams ?? []
}

// 1
let rootRepositoryDirectory = FileManager.default.currentDirectoryPath
let codeOwnersPath = rootRepositoryDirectory + "/.github/CODEOWNERS"

// 2
let allOwnershipRules = getRules(from: codeOwnersPath, relativeTo: rootRepositoryDirectory)

// 3
let matchingSearch = "import Quick"
let dirEnum = FileManager.default.enumerator(atPath: rootRepositoryDirectory)
var matchedFiles = [String]()
while let file = dirEnum?.nextObject() as? String {
    guard file.hasSuffix(".swift") else { continue }

    let fullPath = rootRepositoryDirectory + "/" + file
    if let contents = FileManager.default.contents(atPath: fullPath),
       let stringContents = String(data: contents, encoding: .utf8),
       stringContents.contains(matchingSearch) {

        matchedFiles.append(fullPath)
    }
}

// 4
let matchedFilesOnwedByTeam = matchedFiles
    .filter { fileContainingSearchQuery in
        getOwnersForFile(fileContainingSearchQuery, rules: allOwnershipRules).contains("@MyAwesomeOrg/cool-beans")
    }

// 5
print(matchedFilesOnwedByTeam)

上面这段代码的主要目的是从代码库中查找特定团队拥有的文件,并筛选出其中包含指定文本的文件。让我们逐步解释代码的意义、作用和可扩展性。

读取CODEOWNERS文件

通过 getRules(from: codeOwnersPath, relativeTo: rootRepositoryDirectory) 函数从 CODEOWNERS 文件中获取规则。 这些规则定义了哪些文件或目录由特定团队拥有。

解析规则

getRules(from: codeOwnersPath, relativeTo: rootRepositoryDirectory) 函数解析 CODEOWNERS 文件的内容,生成 OwnershipRule 结构体的数组。

每个 OwnershipRule 结构体包含文件路径和相应的团队。

搜索匹配的文件

脚本使用 FileManager 遍历当前代码库中的所有 .swift 文件。

对于每个文件,检查是否包含了匹配的文本(例如,import Quick)。

确定文件所有者

对于包含匹配文本的文件,使用 getOwnersForFile(_:_:) 函数确定其所有者。

getOwnersForFile(_:_:) 函数根据文件路径和规则数组,确定文件的拥有者团队。

输出结果

将文件所有者为 @MyAwesomeOrg/cool-beans 的匹配文件打印输出。

通过这段脚本可以帮助开发者快速找到特定团队拥有的文件,并检查其中是否包含特定的文本。它的可扩展性取决于 CODEOWNERS 文件的格式和内容,以及要搜索的文本类型。例如,可以扩展代码以支持更多类型的文本搜索,或者为不同的团队提供不同的匹配逻辑。此外,可以根据需要添加更多的文件过滤规则或其他自定义逻辑。

总结

最后我想到了一些更加实用的功能,抽时间给大家分享。在未来,可以考虑添加更多的文件过滤规则或支持其他类型的文本搜索,以增强功能。例如,可以添加对不同文件类型的支持,或者实现更复杂的团队匹配逻辑。另外,还可以考虑添加用户界面和更友好的输出方式,以提升用户体验。

相关推荐
I烟雨云渊T3 小时前
iOS 门店营收表格功能的实现
ios
明月看潮生9 小时前
青少年编程与数学 01-011 系统软件简介 07 iOS操作系统
ios·青少年编程·操作系统·系统软件
90后的晨仔11 小时前
RxSwift 框架解析
前端·ios
大熊猫侯佩15 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(五)
swiftui·swift·apple watch
大熊猫侯佩15 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(四)
数据库·swiftui·apple watch
可爱小仙子15 小时前
ios苹果系统,js 滑动屏幕、锚定无效
前端·javascript·ios
未来猫咪花16 小时前
# Flutter状态管理对比:view_model vs Riverpod
flutter·ios·android studio
咕噜企业签名分发-淼淼20 小时前
开发源码搭建一码双端应用分发平台教程:逐步分析注意事项
android·ios
键盘敲没电1 天前
【IOS】GCD学习
学习·ios·objective-c·xcode
SY.ZHOU1 天前
Significant Location Change
macos·ios·cocoa