Skip to content

Commit

Permalink
feat: parse output of swift package dump-package (#19)
Browse files Browse the repository at this point in the history
- Add `.swiftformat` and `.swiftlint.yml` to the repo.
- Update `.gitignore` with Swift-specific entries.
- Add `MySwiftPackage` example.
- Implement `jsonutils` package to help with parsing Swift package dump
JSON.
- Implement `swiftpkg` package to parse the Swift package dump JSON.
  • Loading branch information
cgrindel committed Nov 22, 2022
1 parent 6d4bb63 commit 2d67c39
Show file tree
Hide file tree
Showing 27 changed files with 1,071 additions and 1 deletion.
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
# Ignore Bazel symlinks
bazel-*

# Ignore Swift and Xcode stuff
.DS_Store
**/.build
**/Packages
**/*.xcodeproj
**/xcuserdata/
**/DerivedData/
**/.swiftpm/config/registries.json
**/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
**/.netrc
11 changes: 11 additions & 0 deletions .swiftformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# For information on the rules, see
# https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md

--allman false
--indent 2
--semicolons never
--stripunusedargs always
--maxwidth 100
--wraparguments before-first
--wrapparameters before-first
--wrapcollections before-first
11 changes: 11 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# List the rules by running "swiftlint rules"
disabled_rules:
- trailing_comma
excluded:
- .build
identifier_name:
excluded:
- id
- db
nesting:
type_level: 2
14 changes: 14 additions & 0 deletions examples/MySwiftPackage/Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"pins" : [
{
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser",
"state" : {
"revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d",
"version" : "1.2.0"
}
}
],
"version" : 2
}
27 changes: 27 additions & 0 deletions examples/MySwiftPackage/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "MySwiftPackage",
platforms: [.macOS(.v10_15)],
products: [
.executable(name: "printstuff", targets: ["MySwiftPackage"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.0"),
],
targets: [
.executableTarget(
name: "MySwiftPackage",
dependencies: [
.product(name: "ArgumentParser", package: "swift-argument-parser"),
]
),
.testTarget(
name: "MySwiftPackageTests",
dependencies: ["MySwiftPackage"]
),
]
)
3 changes: 3 additions & 0 deletions examples/MySwiftPackage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# MySwiftPackage

A description of this package.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import ArgumentParser

@main
struct MySwiftPackage: AsyncParsableCommand {
public private(set) var text = "Hello, World!"

mutating func main() async throws {
print(MySwiftPackage().text)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import XCTest
@testable import MySwiftPackage

final class MySwiftPackageTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(MySwiftPackage().text, "Hello, World!")
}
}
1 change: 1 addition & 0 deletions gazelle/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ go_library(
deps = [
"//gazelle/internal/stringslices",
"//gazelle/internal/swift",
"//gazelle/internal/swiftbin",
"//gazelle/internal/wspace",
"@bazel_gazelle//config:go_default_library",
"@bazel_gazelle//label:go_default_library",
Expand Down
14 changes: 13 additions & 1 deletion gazelle/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import (
"github.com/bazelbuild/bazel-gazelle/config"
"github.com/bazelbuild/bazel-gazelle/rule"
"github.com/cgrindel/swift_bazel/gazelle/internal/swift"
"github.com/cgrindel/swift_bazel/gazelle/internal/swiftbin"
"github.com/cgrindel/swift_bazel/gazelle/internal/wspace"
)

const swiftConfigName = "swift"

type swiftConfig struct {
moduleIndex *swift.ModuleIndex
moduleIndex *swift.ModuleIndex
swiftBinPath string
}

func getSwiftConfig(c *config.Config) *swiftConfig {
Expand All @@ -29,8 +31,18 @@ func (*swiftLang) RegisterFlags(fs *flag.FlagSet, cmd string, c *config.Config)
}

func (sl *swiftLang) CheckFlags(fs *flag.FlagSet, c *config.Config) error {
var err error
sc := getSwiftConfig(c)

// TODO(chuck): Add flag so that the client can tell use which Swift to use.

// Find the Swift executable
sc.swiftBinPath, err = swiftbin.FindSwiftBinPath()
if err != nil {
return err
}

// Look for http_archive declarations with Swift declarations.
wkspFilePath := wspace.FindWORKSPACEFile(c.RepoRoot)
wkspFile, err := rule.LoadWorkspaceFile(wkspFilePath, "")
if err != nil {
Expand Down
28 changes: 28 additions & 0 deletions gazelle/internal/jsonutils/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
load("@cgrindel_bazel_starlib//bzlformat:defs.bzl", "bzlformat_pkg")
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "jsonutils",
srcs = [
"errors.go",
"json_map.go",
"json_slice.go",
],
importpath = "github.com/cgrindel/swift_bazel/gazelle/internal/jsonutils",
visibility = ["//gazelle:__subpackages__"],
)

go_test(
name = "jsonutils_test",
srcs = [
"errors_test.go",
"json_map_test.go",
"json_slice_test.go",
],
deps = [
":jsonutils",
"@com_github_stretchr_testify//assert",
],
)

bzlformat_pkg(name = "bzlformat")
123 changes: 123 additions & 0 deletions gazelle/internal/jsonutils/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package jsonutils

import (
"fmt"
)

type mapKey struct {
Key string
}

type sliceIndex struct {
Index int
}

type unexpectedType struct {
ExpectedType string
ActualType string
}

// MissingKeyError

type MissingKeyError struct {
mapKey
}

func NewMissingKeyError(key string) *MissingKeyError {
return &MissingKeyError{
mapKey{Key: key},
}
}

func (e *MissingKeyError) Error() string {
return fmt.Sprintf("key '%v' not found", e.Key)
}

// KeyTypeError

type KeyTypeError struct {
mapKey
unexpectedType
}

func NewKeyTypeError(key, expectedType string, actual any) *KeyTypeError {
return &KeyTypeError{
mapKey{Key: key},
unexpectedType{
ExpectedType: expectedType,
ActualType: fmt.Sprintf("%T", actual),
},
}
}

func (e *KeyTypeError) Error() string {
return fmt.Sprintf(
"key '%s' expected to be type '%s', but was type '%s'",
e.Key, e.ExpectedType, e.ActualType)
}

// MarshalKeyError

type KeyError struct {
Err error
mapKey
}

func NewKeyError(k string, err error) *KeyError {
mk := mapKey{Key: k}
return &KeyError{
Err: err,
mapKey: mk,
}
}

func (e *KeyError) Error() string {
return fmt.Sprintf("error occurred processing '%v', %v", e.Key, e.Err)
}

func (e *KeyError) Unwrap() error {
return e.Err
}

// IndexTypeError

type IndexTypeError struct {
sliceIndex
unexpectedType
}

func NewIndexTypeError(index int, expectedType string, actual any) *IndexTypeError {
return &IndexTypeError{
sliceIndex{Index: index},
unexpectedType{
ExpectedType: expectedType,
ActualType: fmt.Sprintf("%T", actual),
},
}
}

func (e *IndexTypeError) Error() string {
return fmt.Sprintf(
"index %d expected to be type '%s', but was type '%s'",
e.Index, e.ExpectedType, e.ActualType)
}

// IndexOutOfBoundsError

type IndexOutOfBoundsError struct {
sliceIndex
ActualLen int
}

func NewIndexOutOfBoundsError(idx, actualLen int) *IndexOutOfBoundsError {
return &IndexOutOfBoundsError{
sliceIndex: sliceIndex{Index: idx},
ActualLen: actualLen,
}
}

func (e *IndexOutOfBoundsError) Error() string {
return fmt.Sprintf(
"index %d out of bounds for slice with length %d",
e.Index, e.ActualLen)
}
45 changes: 45 additions & 0 deletions gazelle/internal/jsonutils/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package jsonutils_test

import (
"fmt"
"testing"

"github.com/cgrindel/swift_bazel/gazelle/internal/jsonutils"
"github.com/stretchr/testify/assert"
)

func TestMissingKeyError(t *testing.T) {
key := "foo"
mke := jsonutils.NewMissingKeyError(key)
assert.Equal(t, key, mke.Key)
assert.Implements(t, (*error)(nil), mke)
}

func TestKeyTypeError(t *testing.T) {
key := "foo"
expectedType := "string"
kte := jsonutils.NewKeyTypeError(key, expectedType, 123)
assert.Equal(t, key, kte.Key)
assert.Equal(t, expectedType, kte.ExpectedType)
assert.Equal(t, "int", kte.ActualType)
assert.Implements(t, (*error)(nil), kte)
}

func TestKeyError(t *testing.T) {
key := "foo"
oerr := fmt.Errorf("original error")
ke := jsonutils.NewKeyError(key, oerr)
assert.Equal(t, ke.Key, key)
assert.Equal(t, ke.Err, oerr)
assert.Implements(t, (*error)(nil), ke)
}

func TestIndexTypeError(t *testing.T) {
index := 3
expectedType := "string"
ite := jsonutils.NewIndexTypeError(index, expectedType, 123)
assert.Equal(t, index, ite.Index)
assert.Equal(t, expectedType, ite.ExpectedType)
assert.Equal(t, "int", ite.ActualType)
assert.Implements(t, (*error)(nil), ite)
}
Loading

0 comments on commit 2d67c39

Please sign in to comment.