使用 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 文件的格式和内容,以及要搜索的文本类型。例如,可以扩展代码以支持更多类型的文本搜索,或者为不同的团队提供不同的匹配逻辑。此外,可以根据需要添加更多的文件过滤规则或其他自定义逻辑。

总结

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

相关推荐
彩旗工作室9 小时前
将iOS/macOS应用上架至App Store
macos·ios·应用商店·appstore
江东小bug王12 小时前
深入解析 iOS 与 macOS 应用程序生命周期(完整指南)
macos·ios
2501_9160088915 小时前
iOS 发布全流程详解,从开发到上架的流程与跨平台使用 开心上架 发布实战
android·macos·ios·小程序·uni-app·cocoa·iphone
非专业程序员17 小时前
iOS/Swift:深入理解iOS CoreText API
ios·swift
某柚啊17 小时前
iOS移动端H5键盘弹出时页面布局异常和滚动解决方案
前端·javascript·css·ios·html5
xingxing_F19 小时前
Swift Publisher for Mac 版面设计和编辑工具
开发语言·macos·swift
RollingPin1 天前
iOS八股文之 RunLoop
ios·多线程·卡顿·ios面试·runloop·ios保活·ios八股文
2501_916007471 天前
iOS 混淆工具链实战,多工具组合完成 IPA 混淆与加固(iOS混淆|IPA加固|无源码混淆|App 防反编译)
android·ios·小程序·https·uni-app·iphone·webview
LinXunFeng1 天前
Flutter webview 崩溃率上升怎么办?我的分析与解决方案
flutter·ios·webview
游戏开发爱好者81 天前
FTP 抓包分析实战,命令、被动主动模式要点、FTPS 与 SFTP 区别及真机取证流程
运维·服务器·网络·ios·小程序·uni-app·iphone