Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ileitch committed Aug 13, 2024
1 parent 47b2211 commit 76089e6
Show file tree
Hide file tree
Showing 11 changed files with 271 additions and 3 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ DerivedData
Tests/Fixtures/.build/

# VSCode
.vscode/*
.vscode/*

# Bazel
bazel-*
/MODULE.bazel.lock
8 changes: 8 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module(
name = "periphery",
version = "0.0.0",
compatibility_level = 1,
)

generated = use_extension("//bazel:extensions.bzl", "generated")
use_repo(generated, "periphery_generated")
64 changes: 64 additions & 0 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 97 additions & 0 deletions Sources/Frontend/Commands/BazelCommand.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import ArgumentParser
import Foundation
import Shared
import SystemPackage

struct BazelScanCommand: FrontendCommand {
static let configuration = CommandConfiguration(
commandName: "bazel-scan",
abstract: "Scan for unused code (for Bazel projects)"
)

@Option(help: "Bazel top-level targets")
var target: [String] = ["//..."]

@Option(help: "Path to configuration file. By default Periphery will look for .periphery.yml in the current directory")
var config: FilePath = FilePath(".periphery.yml")

@Flag(help: "Enable verbose logging")
var verbose: Bool = defaultConfiguration.$verbose.defaultValue

private static let defaultConfiguration = Configuration()

private static let kinds = [
"apple_framework_packaging",
"ios_unit_test",
"ios_ui_test",
"ios_application",
// TODO: tvos, swift_binary, swift_test, etc
]

func run() throws {
guard let executablePath = Bundle.main.executablePath else {
// TODO: throw?
return
}

let configuration = Configuration.shared
configuration.apply(\.$verbose, verbose)

let buildFilePath = FilePath("/var/tmp/periphery_bazel/BUILD")
let fileManager = FileManager.default
try fileManager.createDirectory(at: buildFilePath.removingLastComponent().url, withIntermediateDirectories: true)
try? fileManager.removeItem(at: buildFilePath.url)
defer {
try? fileManager.removeItem(at: buildFilePath.url)
}

let deps = try queryTargets().joined(separator: ",\n")

let buildFileContents = """
load("@periphery//bazel/internal:scan.bzl", "scan")
scan(
name = "scan",
testonly = True,
config = "\(FilePath.makeAbsolute(config))",
periphery_binary = "\(executablePath)",
visibility = [
"@periphery//bazel:generated"
],
deps = [
\(deps)
],
)
"""

try buildFileContents.write(to: buildFilePath.url, atomically: true, encoding: .utf8)

let task = Process()
// TODO: Get bazel bin path
task.launchPath = "/opt/homebrew/bin/bazel"
task.arguments = ["run", "@periphery//bazel:scan"]
try task.run()
task.waitUntilExit()
}

// MARK: - Private

private func queryTargets() throws -> [String] {
try Shell.shared
.exec([
"bazel",
"query",
"--noshow_progress",
"--ui_event_filters=-info,-debug,-warning",
query
])
.split(separator: "\n")
.map { "\"@@\($0)\""}
}

private var query: String {
let depsExpr = target.map { "deps(\($0))" }.joined(separator: " union ")
let kindsExpr = "kind('\(Self.kinds.joined(separator: "|")) rule', \(depsExpr))"
return kindsExpr
}
}
8 changes: 7 additions & 1 deletion Sources/Frontend/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ Logger.configureBuffering()
struct PeripheryCommand: FrontendCommand {
static let configuration = CommandConfiguration(
commandName: "periphery",
subcommands: [ScanCommand.self, CheckUpdateCommand.self, ClearCacheCommand.self, VersionCommand.self]
subcommands: [
ScanCommand.self,
BazelScanCommand.self,
CheckUpdateCommand.self,
ClearCacheCommand.self,
VersionCommand.self
]
)
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Shared/Shell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ open class Shell {
result[pair.0] = pair.1
}

let preservedKeys = ["PATH", "DEVELOPER_DIR"]
let preservedKeys = ["PATH", "DEVELOPER_DIR", "SSH_AUTH_SOCK"]
preservedKeys.forEach { key in
if let value = environment[key] {
newEnv[key] = value
Expand Down
9 changes: 9 additions & 0 deletions bazel/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package_group(
name = "generated",
includes = [
"@periphery_generated//:package_group"
],
)

# TODO: Wrap with another rule to capture the log output?
alias(actual = "@periphery_generated//rule:scan", name = "scan")
23 changes: 23 additions & 0 deletions bazel/extensions.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
def _generated_repo_impl(repository_ctx):
repository_ctx.file(
"BUILD",
content = """
package_group(
name = "package_group",
packages = ["//..."],
)
""",
)

# TODO: output_base_hash like rules_xcodeproj?
# TODO: scoped by project?
repository_ctx.symlink(
"/var/tmp/periphery_bazel/BUILD",
"rule/BUILD",
)

generated_repo = repository_rule(
implementation = _generated_repo_impl,
)

generated = module_extension(implementation = lambda _: generated_repo(name = "periphery_generated"))
3 changes: 3 additions & 0 deletions bazel/internal/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exports_files([
"scan_template.sh"
])
50 changes: 50 additions & 0 deletions bazel/internal/scan.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
def _get_template_substitutions(*, periphery_binary, config_path):
"""Returns the template substitutions for this executable."""
subs = {
"periphery_binary": periphery_binary,
"config_path": config_path,
}
return {"%(" + k + ")s": subs[k] for k in subs}

def _scan_impl(ctx):
# print(ctx.attr.config)
# print(ctx.attr.periphery_binary)
# print(ctx.file._template)

runfiles = ctx.runfiles(
files = [],
)

ctx.actions.expand_template(
template = ctx.file._template,
output = ctx.outputs.scan,
substitutions = _get_template_substitutions(
periphery_binary = ctx.attr.periphery_binary,
config_path = ctx.attr.config,
),
)

return DefaultInfo(
executable = ctx.outputs.scan,
files = depset(
[ctx.outputs.scan],
),
runfiles = runfiles
)

scan = rule(
attrs = {
"deps": attr.label_list(mandatory = True),
"config": attr.string(),
"periphery_binary": attr.string(),
"_template": attr.label(
allow_single_file = True,
default = "@periphery//bazel/internal:scan_template.sh",
),
},
outputs = {
"scan": "scan.sh",
},
implementation = _scan_impl,
executable = True,
)
4 changes: 4 additions & 0 deletions bazel/internal/scan_template.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
echo
echo "Hello from scan_template.sh"
echo %(periphery_binary)s
echo %(config_path)s

0 comments on commit 76089e6

Please sign in to comment.