Skip to content

Commit bbf1e16

Browse files
authored
feat: specify module directory using swift_default_module_name directive (#566)
This allows a client to define the location where `swift_library` and `swift_test` declarations should be written. Also, this PR updates two of the examples to use this new feature.
1 parent 320e16f commit bbf1e16

File tree

7 files changed

+128
-21
lines changed

7 files changed

+128
-21
lines changed

examples/firebase_example/crashlytics/BUILD.bazel

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ load("@build_bazel_rules_apple//apple:ios.bzl", "ios_application")
33
load("@build_bazel_rules_apple//apple:macos.bzl", "macos_application")
44
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
55

6-
# Exclude this entire directory from having anything generated by Gazelle. That
7-
# way the test cases won't be fixed by `bazel run //:update_build_files` when
8-
# run in this repository.
9-
# gazelle:exclude **
6+
# gazelle:swift_default_module_name CrashlyticsSwiftUIExample
7+
# gazelle:exclude Shared/UITests.swift
108

119
swift_library(
1210
name = "CrashlyticsSwiftUIExample",

examples/snapkit_example/BUILD.bazel

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ tidy(
1818
# Ignore the Swift build folder
1919
# gazelle:exclude .build
2020

21-
# The example code has a strange layout. Do not generate swift_xxx for this
22-
# example.
23-
# gazelle:exclude **
24-
2521
gazelle_binary(
2622
name = "gazelle_bin",
2723
languages = [
@@ -42,6 +38,8 @@ swift_update_packages(
4238
update_bzlmod_stanzas = True,
4339
)
4440

41+
# gazelle:swift_default_module_name SnapkitExample
42+
4543
swift_library(
4644
name = "SnapkitExample",
4745
srcs = [

gazelle/generate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func genRulesFromSrcFiles(sc *swiftcfg.SwiftConfig, args language.GenerateArgs)
4242

4343
// Be sure to use args.Rel when determining whether this is a module directory. We do not want
4444
// to check directories that are outside of the workspace.
45-
moduleDir := swift.ModuleDir(args.Rel)
45+
moduleDir := swift.ModuleDir(sc.ConfigModulePaths(), args.Rel)
4646
if args.Rel != moduleDir {
4747
relDir, err := filepath.Rel(moduleDir, args.Rel)
4848
if err != nil {

gazelle/internal/swift/module_dir.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package swift
22

3-
import "github.com/cgrindel/rules_swift_package_manager/gazelle/internal/pathdistance"
3+
import (
4+
"path/filepath"
5+
"strings"
6+
7+
"github.com/cgrindel/rules_swift_package_manager/gazelle/internal/pathdistance"
8+
)
49

510
var moduleParentDirNames = []string{
611
"Sources",
@@ -9,7 +14,22 @@ var moduleParentDirNames = []string{
914
}
1015

1116
// ModuleDir returns the module root directory.
12-
func ModuleDir(path string) string {
17+
// The configModPaths is a list of relative paths to module directories defined by
18+
// swift_default_module_name directives.
19+
func ModuleDir(configModPaths []string, path string) string {
20+
// Check if the path is a child of any of the directive paths
21+
for _, modPath := range configModPaths {
22+
// If modPath is empty string, then the module is set at the root of the workspace. So
23+
// everything under the workspace is in this module.
24+
if modPath == "" || modPath == path {
25+
return modPath
26+
}
27+
modPathWithSlash := modPath + string(filepath.Separator)
28+
if strings.HasPrefix(path, modPathWithSlash) {
29+
return modPath
30+
}
31+
}
32+
1333
// If we do not see the module parent in the path, we could be a Swift module
1434
moduleParentDistance := pathdistance.DistanceFrom(moduleParentDirNames, path)
1535
switch moduleParentDistance {

gazelle/internal/swift/module_dir_test.go

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,63 @@ import (
99

1010
func TestModuleRootDir(t *testing.T) {
1111
tests := []struct {
12-
path string
13-
wval string
12+
msg string
13+
cModPaths []string
14+
path string
15+
wval string
1416
}{
15-
{path: "Sources/Chicken", wval: "Sources/Chicken"},
16-
{path: "foo/Source/Chicken", wval: "foo/Source/Chicken"},
17-
{path: "foo/Sources/Chicken/Panther", wval: "foo/Sources/Chicken"},
18-
{path: "Tests/ChickenTests/PantherTests", wval: "Tests/ChickenTests"},
19-
// path does not contain module directory
20-
{path: "foo/Chicken", wval: "foo/Chicken"},
17+
{
18+
msg: "path is module, Sources at root",
19+
path: "Sources/Chicken",
20+
wval: "Sources/Chicken",
21+
},
22+
{
23+
msg: "path is module, Sources in sub-dir",
24+
path: "foo/Source/Chicken",
25+
wval: "foo/Source/Chicken",
26+
},
27+
{
28+
msg: "path is under a module path",
29+
path: "foo/Sources/Chicken/Panther",
30+
wval: "foo/Sources/Chicken",
31+
},
32+
{
33+
msg: "path is under a test module path",
34+
path: "Tests/ChickenTests/PantherTests",
35+
wval: "Tests/ChickenTests",
36+
},
37+
{
38+
msg: "path does not contain module directory",
39+
path: "foo/Chicken",
40+
wval: "foo/Chicken",
41+
},
42+
{
43+
msg: "path is module, config module paths provided",
44+
cModPaths: []string{"foo", "bar"},
45+
path: "Sources/Chicken",
46+
wval: "Sources/Chicken",
47+
},
48+
{
49+
msg: "path is under config module path",
50+
cModPaths: []string{"foo", "bar"},
51+
path: "foo/Chicken",
52+
wval: "foo",
53+
},
54+
{
55+
msg: "path is not a child of standard module dir, not in config module paths",
56+
cModPaths: []string{"bar"},
57+
path: "foo/Chicken",
58+
wval: "foo/Chicken",
59+
},
60+
{
61+
msg: "module path is set to root of the workspace",
62+
cModPaths: []string{""},
63+
path: "foo/Chicken",
64+
wval: "",
65+
},
2166
}
2267
for _, tc := range tests {
23-
actual := swift.ModuleDir(tc.path)
24-
assert.Equal(t, tc.wval, actual)
68+
actual := swift.ModuleDir(tc.cModPaths, tc.path)
69+
assert.Equal(t, tc.wval, actual, tc.msg)
2570
}
2671
}

gazelle/internal/swiftcfg/swift_config.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package swiftcfg
33
import (
44
"errors"
55
"os"
6+
"sort"
67

78
"github.com/bazelbuild/bazel-gazelle/config"
89
"github.com/bazelbuild/bazel-gazelle/language"
@@ -61,6 +62,20 @@ func NewSwiftConfig() *SwiftConfig {
6162
}
6263
}
6364

65+
func (sc *SwiftConfig) ConfigModulePaths() []string {
66+
dmnLen := len(sc.DefaultModuleNames)
67+
if dmnLen == 0 {
68+
return nil
69+
}
70+
modPaths := make([]string, 0, dmnLen)
71+
for modPath := range sc.DefaultModuleNames {
72+
modPaths = append(modPaths, modPath)
73+
}
74+
// Ensure that the results are consistent
75+
sort.Strings(modPaths)
76+
return modPaths
77+
}
78+
6479
// SwiftBin returns the Swift binary.
6580
func (sc *SwiftConfig) SwiftBin() *swiftbin.SwiftBin {
6681
if sc.SwiftBinPath == "" {

gazelle/internal/swiftcfg/swift_config_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,34 @@ func TestWriteAndReadDependencyIndex(t *testing.T) {
7878
// Ensure that the indexes are that same
7979
assert.Equal(t, origsc.DependencyIndex, newsc.DependencyIndex)
8080
}
81+
82+
func TestConfigModulePaths(t *testing.T) {
83+
tests := []struct {
84+
msg string
85+
dmn map[string]string
86+
exp []string
87+
}{
88+
{
89+
msg: "no default module names",
90+
dmn: nil,
91+
exp: nil,
92+
},
93+
{
94+
msg: "with default module names",
95+
dmn: map[string]string{
96+
"path/to/foo": "Foo",
97+
"bar": "Bar",
98+
},
99+
exp: []string{
100+
"bar",
101+
"path/to/foo",
102+
},
103+
},
104+
}
105+
for _, tt := range tests {
106+
sc := swiftcfg.NewSwiftConfig()
107+
sc.DefaultModuleNames = tt.dmn
108+
actual := sc.ConfigModulePaths()
109+
assert.Equal(t, tt.exp, actual, tt.msg)
110+
}
111+
}

0 commit comments

Comments
 (0)