Skip to content

Commit

Permalink
Merge pull request #30 from kyoshidajp/support_cocoapods
Browse files Browse the repository at this point in the history
Support cocoapods
  • Loading branch information
kyoshidajp authored Nov 2, 2023
2 parents c9a476c + c7ecf5b commit fd8476a
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 12 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ However, some packages have archived their source code repositories or have had

| language | package manager | file (e.g.) | status |
| -------- | ------------- | -- | :----: |
| Ruby | bundler | Gemfile.lock | :heavy_check_mark: |
| JavaScript | yarn | yarn.lock | :heavy_check_mark: |
| Go | golang | go.mod | :heavy_check_mark: |
| JavaScript | npm | package-lock.json | :heavy_check_mark: |
| JavaScript | yarn | yarn.lock | :heavy_check_mark: |
| PHP | composer | composer.lock | :heavy_check_mark: |
| Python | pip | requirements.txt | :heavy_check_mark: |
| Python | poetry | poetry.lock | (later) |
| Python | pipenv | Pipfile.lock | (later) |
| PHP | composer | composer.lock | :heavy_check_mark: |
| Go | golang | go.mod | :heavy_check_mark: |
| Python | poetry | poetry.lock | (later) |
| Ruby | bundler | Gemfile.lock | :heavy_check_mark: |
| Rust | cargo | Cargo.lock | :heavy_check_mark: |
| Swift | cocoapods | Podfile.lock | :heavy_check_mark: |

## Support repository hosting services

Expand Down
98 changes: 98 additions & 0 deletions cmd/cocoapods.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package cmd

import (
"crypto/md5"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"

parser_io "github.com/aquasecurity/go-dep-parser/pkg/io"
"github.com/aquasecurity/go-dep-parser/pkg/swift/cocoapods"
"github.com/aquasecurity/go-dep-parser/pkg/types"
)

// It will redirected from https://cdn.cocoapods.org/
// Should be used origin URL?
const COCOA_PODS_REGISTRY_API = "https://cdn.jsdelivr.net/cocoa/Specs/%s"

type CocoaPodsDoctor struct {
HTTPClient http.Client
}

func NewCococaPodsDoctor() *CocoaPodsDoctor {
client := &http.Client{}
return &CocoaPodsDoctor{HTTPClient: *client}
}

func (d *CocoaPodsDoctor) Libraries(r parser_io.ReadSeekerAt) []types.Library {
p := &cocoapods.Parser{}
libs, _, _ := p.Parse(r)
return libs
}

func (d *CocoaPodsDoctor) SourceCodeURL(lib types.Library) (string, error) {
pod := CocoaPod{
name: lib.Name,
version: lib.Version,
}
url, err := pod.fetchURLFromRegistry(d.HTTPClient)
return url, err
}

type CocoaPodsRegistryResponse struct {
Homepage string `json:"homepage"`
Source struct {
Git string `json:"git"`
} `json:"source"`
}

type CocoaPod struct {
name string
version string
}

func (c *CocoaPod) BaseName() string {
splittedName := strings.Split(c.name, "/")
return splittedName[0]
}

func (c *CocoaPod) PodspecPath() string {
md5 := md5.Sum([]byte(c.BaseName()))
hashString := fmt.Sprintf("%x", md5)
return fmt.Sprintf("%c/%c/%c/%s/%s/%s.podspec.json", hashString[0], hashString[1], hashString[2], c.BaseName(), c.version, c.BaseName())
}

func (c *CocoaPod) fetchURLFromRegistry(client http.Client) (string, error) {
url := fmt.Sprintf(COCOA_PODS_REGISTRY_API, c.PodspecPath())
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return "", err
}

resp, err := client.Do(req)
if err != nil {
return "", err
}

defer resp.Body.Close()
if resp.StatusCode < 200 || 299 < resp.StatusCode {
m := fmt.Sprintf("Got status code: %d from %s", resp.StatusCode, url)
return "", errors.New(m)
}

body, _ := io.ReadAll(resp.Body)

var CocoaPodsRegistryResponse CocoaPodsRegistryResponse
err = json.Unmarshal(body, &CocoaPodsRegistryResponse)
if err != nil {
return "", err
}

if CocoaPodsRegistryResponse.Source.Git != "" {
return CocoaPodsRegistryResponse.Source.Git, nil
}
return CocoaPodsRegistryResponse.Homepage, nil
}
50 changes: 50 additions & 0 deletions cmd/cocoapods_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package cmd

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestCocoaPod_PodspecPath(t *testing.T) {
tests := []struct {
name string
pod CocoaPod
}{
{
name: "KeychanAccess",
pod: CocoaPod{
name: "KeychainAccess",
version: "4.2.2",
},
},
{
name: "GoogleUtilities/Logger",
pod: CocoaPod{
name: "GoogleUtilities/Logger",
version: "7.11.0",
},
},
}
expects := []struct {
name string
path string
}{
{
name: "KeychainAccess",
path: "f/6/3/KeychainAccess/4.2.2/KeychainAccess.podspec.json",
},
{
name: "GoogleUtilities/Logger",
path: "0/8/4/GoogleUtilities/7.11.0/GoogleUtilities.podspec.json",
},
}

for i, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual := tt.pod.PodspecPath()
expect := expects[i].path
assert.Equal(t, expect, actual)
})
}
}
15 changes: 8 additions & 7 deletions cmd/diagnose.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,14 @@ var (
)

var doctors = map[string]MedicalTechnician{
"bundler": NewBundlerDoctor(),
"yarn": NewYarnDoctor(),
"pip": NewPipDoctor(),
"npm": NewNPMDoctor(),
"composer": NewComposerDoctor(),
"golang": NewGolangDoctor(),
"cargo": NewCargoDoctor(),
"bundler": NewBundlerDoctor(),
"yarn": NewYarnDoctor(),
"pip": NewPipDoctor(),
"npm": NewNPMDoctor(),
"composer": NewComposerDoctor(),
"golang": NewGolangDoctor(),
"cargo": NewCargoDoctor(),
"cocoapods": NewCococaPodsDoctor(),
}

var diagnoseCmd = &cobra.Command{
Expand Down
11 changes: 11 additions & 0 deletions cmd/swift/cocoapods/testdata/Podfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PODS:
- GoogleUtilities (7.10.0):
- GoogleUtilities/Logger (= 7.10.0)
- GoogleUtilities/Logger (7.10.0):
- GoogleUtilities/Environment
- AppCenter (4.2.0):
- AppCenter/Analytics (= 4.2.0)
- AppCenter/Crashes (= 4.2.0)
- KeychainAccess (4.2.1)

COCOAPODS: 1.11.2

0 comments on commit fd8476a

Please sign in to comment.