Skip to content

Commit

Permalink
Ipa reader (#237)
Browse files Browse the repository at this point in the history
* Create zip reader using ditto tool

* Unify default zip reader and the new ditto reader

* Move internal zip package to ziputil

* zip.ReadCloser.ReadFile now actualy read the file

* Revert zip error type

* Introduce IsErrFormat

* Add tests for ditto reader

* Renam zip to artifacts and ziputil to zip

* Fix lint issue

* Fix refactor issue

* Add IsDittoReaderAvailable

* Add some comment to the ditto command

* Ditto zip reader: lazy extract archives

* Benchmark test default and ditto zip readers

* Introduce fallbackReader

* Rename defaultRead to stdlibRead

* Rename fallbackReader to defaultReader and add tests

* Fix lint issues

* Move stdlib and ditto zip readers to an internal package

* Define ZipReadCloser interface on the client package (artifacts)

* Update lint issue

* Code cleanup
  • Loading branch information
godrei authored Apr 18, 2024
1 parent 398fbc3 commit e42d0c6
Show file tree
Hide file tree
Showing 16 changed files with 469 additions and 411 deletions.
7 changes: 3 additions & 4 deletions _integration_tests/test_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/bitrise-io/go-utils/command/git"
"github.com/stretchr/testify/require"
Expand All @@ -14,11 +13,11 @@ const sampleArtifactsRepoURL = "https://github.com/bitrise-io/sample-artifacts.g

var reposToDir map[string]map[string]string

func GetSampleArtifactsRepository(t *testing.T) string {
func GetSampleArtifactsRepository(t require.TestingT) string {
return GetRepository(t, sampleArtifactsRepoURL, "master")
}

func GetRepository(t *testing.T, url, branch string) string {
func GetRepository(t require.TestingT, url, branch string) string {
if repoDir := getRepoDir(url, branch); repoDir != "" {
return repoDir
}
Expand Down Expand Up @@ -66,7 +65,7 @@ func saveRepoDir(dir, url, branch string) {
reposToDir[url] = branchToDir
}

func createDirForRepo(t *testing.T, repo, branch string) string {
func createDirForRepo(t require.TestingT, repo, branch string) string {
tmpDir, err := os.MkdirTemp("", "go-xcode")
require.NoError(t, err)

Expand Down
87 changes: 80 additions & 7 deletions _integration_tests/zip/ipa_reader_test.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,105 @@
package zip

import (
"fmt"
"path/filepath"
"testing"

"github.com/bitrise-io/go-utils/v2/log"
"github.com/bitrise-io/go-xcode/plistutil"
"github.com/bitrise-io/go-xcode/profileutil"
"github.com/bitrise-io/go-xcode/v2/_integration_tests"
"github.com/bitrise-io/go-xcode/v2/artifacts"
internalzip "github.com/bitrise-io/go-xcode/v2/internal/zip"
"github.com/bitrise-io/go-xcode/v2/zip"
"github.com/stretchr/testify/require"
)

func TestIPAReader(t *testing.T) {
func TestIPAReader_DefaultZipReader(t *testing.T) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(t)
watchTestIPAPath := filepath.Join(sampleArtifactsDir, "ipas", "watch-test.ipa")

r, err := zip.NewReader(watchTestIPAPath, log.NewLogger())
r, err := zip.NewDefaultReader(watchTestIPAPath, log.NewLogger())
require.NoError(t, err)
defer func() {
require.NoError(t, r.Close())
err := r.Close()
require.NoError(t, err)
}()

ipaReader := zip.NewIPAReader(*r)
plist, err := ipaReader.AppInfoPlist()
require.NoError(t, err)
plist, profile := readIPAWithStdlibZipReader(t, watchTestIPAPath)
bundleID, _ := plist.GetString("CFBundleIdentifier")
require.Equal(t, "bitrise.watch-test", bundleID)
require.Equal(t, "XC iOS: *", profile.Name)
}

func TestIPAReader_StdlibZipReader(t *testing.T) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(t)
watchTestIPAPath := filepath.Join(sampleArtifactsDir, "ipas", "watch-test.ipa")

plist, profile := readIPAWithStdlibZipReader(t, watchTestIPAPath)
bundleID, _ := plist.GetString("CFBundleIdentifier")
require.Equal(t, "bitrise.watch-test", bundleID)
require.Equal(t, "XC iOS: *", profile.Name)
}

func TestIPAReader_DittoZipReader(t *testing.T) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(t)
watchTestIPAPath := filepath.Join(sampleArtifactsDir, "ipas", "watch-test.ipa")

plist, profile := readIPAWithDittoZipReader(t, watchTestIPAPath)
bundleID, _ := plist.GetString("CFBundleIdentifier")
require.Equal(t, "bitrise.watch-test", bundleID)
require.Equal(t, "XC iOS: *", profile.Name)
}

func Benchmark_ZipReaders(b *testing.B) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(b)
watchTestIPAPath := filepath.Join(sampleArtifactsDir, "ipas", "watch-test.ipa")

for name, zipFunc := range map[string]readIPAFunc{
"dittoReader": func() (plistutil.PlistData, *profileutil.ProvisioningProfileInfoModel) {
return readIPAWithDittoZipReader(b, watchTestIPAPath)
},
"stdlibReader": func() (plistutil.PlistData, *profileutil.ProvisioningProfileInfoModel) {
return readIPAWithStdlibZipReader(b, watchTestIPAPath)
},
} {
b.Run(fmt.Sprintf("Benchmarking %s", name), func(b *testing.B) {
_, _ = zipFunc()
})
}
}

type readIPAFunc func() (plistutil.PlistData, *profileutil.ProvisioningProfileInfoModel)

func readIPAWithStdlibZipReader(t require.TestingT, archivePth string) (plistutil.PlistData, *profileutil.ProvisioningProfileInfoModel) {
r, err := internalzip.NewStdlibRead(archivePth, log.NewLogger())
require.NoError(t, err)
defer func() {
err := r.Close()
require.NoError(t, err)
}()

return readIPA(t, r)
}

func readIPAWithDittoZipReader(t require.TestingT, archivePth string) (plistutil.PlistData, *profileutil.ProvisioningProfileInfoModel) {
r := internalzip.NewDittoReader(archivePth, log.NewLogger())
defer func() {
err := r.Close()
require.NoError(t, err)
}()

return readIPA(t, r)
}

func readIPA(t require.TestingT, zipReader artifacts.ZipReadCloser) (plistutil.PlistData, *profileutil.ProvisioningProfileInfoModel) {
ipaReader := artifacts.NewIPAReader(zipReader)
plist, err := ipaReader.AppInfoPlist()
require.NoError(t, err)

profile, err := ipaReader.ProvisioningProfileInfo()
require.NoError(t, err)
require.Equal(t, "XC iOS: *", profile.Name)

return plist, profile
}
106 changes: 99 additions & 7 deletions _integration_tests/zip/xcarchive_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,23 @@ import (

"github.com/bitrise-io/go-utils/v2/log"
"github.com/bitrise-io/go-xcode/v2/_integration_tests"
"github.com/bitrise-io/go-xcode/v2/artifacts"
internalzip "github.com/bitrise-io/go-xcode/v2/internal/zip"
"github.com/bitrise-io/go-xcode/v2/zip"
"github.com/stretchr/testify/require"
)

func TestXCArchiveReader_MacOSArchive(t *testing.T) {
func TestXCArchiveReader_DefaultReader_MacOSArchive(t *testing.T) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(t)
macOSXCArchivePath := filepath.Join(sampleArtifactsDir, "archives", "macos.xcarchive.zip")

r, err := zip.NewReader(macOSXCArchivePath, log.NewLogger())
r, err := zip.NewDefaultReader(macOSXCArchivePath, log.NewLogger())
require.NoError(t, err)
defer func() {
require.NoError(t, r.Close())
}()

xcarchiveReader := zip.NewXCArchiveReader(*r)
xcarchiveReader := artifacts.NewXCArchiveReader(r)
plist, err := xcarchiveReader.InfoPlist()
require.NoError(t, err)
name, _ := plist.GetString("Name")
Expand All @@ -30,17 +32,107 @@ func TestXCArchiveReader_MacOSArchive(t *testing.T) {
require.Equal(t, true, xcarchiveReader.IsMacOS())
}

func TestXCArchiveReader_IOSArchive(t *testing.T) {
func TestXCArchiveReader_StdlibZipReader_MacOSArchive(t *testing.T) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(t)
macOSXCArchivePath := filepath.Join(sampleArtifactsDir, "archives", "macos.xcarchive.zip")

r, err := internalzip.NewStdlibRead(macOSXCArchivePath, log.NewLogger())
require.NoError(t, err)
defer func() {
require.NoError(t, r.Close())
}()

xcarchiveReader := artifacts.NewXCArchiveReader(r)
plist, err := xcarchiveReader.InfoPlist()
require.NoError(t, err)
name, _ := plist.GetString("Name")
require.Equal(t, "ActionExtension", name)

require.NoError(t, err)
require.Equal(t, true, xcarchiveReader.IsMacOS())
}

func TestXCArchiveReader_DittoZipReader_MacOSArchive(t *testing.T) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(t)
macOSXCArchivePath := filepath.Join(sampleArtifactsDir, "archives", "macos.xcarchive.zip")

r := internalzip.NewDittoReader(macOSXCArchivePath, log.NewLogger())
defer func() {
require.NoError(t, r.Close())
}()

xcarchiveReader := artifacts.NewXCArchiveReader(r)
plist, err := xcarchiveReader.InfoPlist()
require.NoError(t, err)
name, _ := plist.GetString("Name")
require.Equal(t, "ActionExtension", name)

require.NoError(t, err)
require.Equal(t, true, xcarchiveReader.IsMacOS())
}

func TestXCArchiveReader_DefaultZipReader_IOSArchive(t *testing.T) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(t)
iosXCArchiveIPAPath := filepath.Join(sampleArtifactsDir, "archives", "ios.xcarchive.zip")

r, err := zip.NewDefaultReader(iosXCArchiveIPAPath, log.NewLogger())
require.NoError(t, err)
defer func() {
require.NoError(t, r.Close())
}()

xcarchiveReader := artifacts.NewXCArchiveReader(r)
plist, err := xcarchiveReader.InfoPlist()
require.NoError(t, err)
name, _ := plist.GetString("Name")
require.Equal(t, "code-sign-test", name)

require.NoError(t, err)
require.Equal(t, false, xcarchiveReader.IsMacOS())

iosXCArchiveReader := artifacts.NewIOSXCArchiveReader(r)
appPlist, err := iosXCArchiveReader.AppInfoPlist()
require.NoError(t, err)
name, _ = appPlist.GetString("CFBundleIdentifier")
require.Equal(t, "com.bitrise.code-sign-test", name)
}

func TestXCArchiveReader_StdlibZipReader_IOSArchive(t *testing.T) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(t)
iosXCArchiveIPAPath := filepath.Join(sampleArtifactsDir, "archives", "ios.xcarchive.zip")

r, err := zip.NewReader(iosXCArchiveIPAPath, log.NewLogger())
r, err := internalzip.NewStdlibRead(iosXCArchiveIPAPath, log.NewLogger())
require.NoError(t, err)
defer func() {
require.NoError(t, r.Close())
}()

xcarchiveReader := artifacts.NewXCArchiveReader(r)
plist, err := xcarchiveReader.InfoPlist()
require.NoError(t, err)
name, _ := plist.GetString("Name")
require.Equal(t, "code-sign-test", name)

require.NoError(t, err)
require.Equal(t, false, xcarchiveReader.IsMacOS())

iosXCArchiveReader := artifacts.NewIOSXCArchiveReader(r)
appPlist, err := iosXCArchiveReader.AppInfoPlist()
require.NoError(t, err)
name, _ = appPlist.GetString("CFBundleIdentifier")
require.Equal(t, "com.bitrise.code-sign-test", name)
}

func TestXCArchiveReader_DittoZipReader_IOSArchive(t *testing.T) {
sampleArtifactsDir := _integration_tests.GetSampleArtifactsRepository(t)
iosXCArchiveIPAPath := filepath.Join(sampleArtifactsDir, "archives", "ios.xcarchive.zip")

r := internalzip.NewDittoReader(iosXCArchiveIPAPath, log.NewLogger())
defer func() {
require.NoError(t, r.Close())
}()

xcarchiveReader := zip.NewXCArchiveReader(*r)
xcarchiveReader := artifacts.NewXCArchiveReader(r)
plist, err := xcarchiveReader.InfoPlist()
require.NoError(t, err)
name, _ := plist.GetString("Name")
Expand All @@ -49,7 +141,7 @@ func TestXCArchiveReader_IOSArchive(t *testing.T) {
require.NoError(t, err)
require.Equal(t, false, xcarchiveReader.IsMacOS())

iosXCArchiveReader := zip.NewIOSXCArchiveReader(*r)
iosXCArchiveReader := artifacts.NewIOSXCArchiveReader(r)
appPlist, err := iosXCArchiveReader.AppInfoPlist()
require.NoError(t, err)
name, _ = appPlist.GetString("CFBundleIdentifier")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package zip
package artifacts

import "github.com/bitrise-io/go-xcode/plistutil"
import (
"github.com/bitrise-io/go-xcode/plistutil"
)

// IOSXCArchiveReader ...
type IOSXCArchiveReader struct {
zipReader Reader
zipReader ZipReadCloser
}

// NewIOSXCArchiveReader ...
func NewIOSXCArchiveReader(reader Reader) IOSXCArchiveReader {
func NewIOSXCArchiveReader(reader ZipReadCloser) IOSXCArchiveReader {
return IOSXCArchiveReader{zipReader: reader}
}

Expand Down
6 changes: 3 additions & 3 deletions zip/ipa_reader.go → artifacts/ipa_reader.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package zip
package artifacts

import (
"fmt"
Expand All @@ -9,11 +9,11 @@ import (

// IPAReader ...
type IPAReader struct {
zipReader Reader
zipReader ZipReadCloser
}

// NewIPAReader ...
func NewIPAReader(zipReader Reader) IPAReader {
func NewIPAReader(zipReader ZipReadCloser) IPAReader {
return IPAReader{zipReader: zipReader}
}

Expand Down
13 changes: 8 additions & 5 deletions zip/xcarchive_reader.go → artifacts/xcarchive_reader.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package zip
package artifacts

import "github.com/bitrise-io/go-xcode/plistutil"
import (
"github.com/bitrise-io/go-xcode/plistutil"
)

// XCArchiveReader ...
type XCArchiveReader struct {
zipReader Reader
zipReader ZipReadCloser
}

// NewXCArchiveReader ...
func NewXCArchiveReader(reader Reader) XCArchiveReader {
func NewXCArchiveReader(reader ZipReadCloser) XCArchiveReader {
return XCArchiveReader{zipReader: reader}
}

Expand All @@ -24,5 +26,6 @@ func (reader XCArchiveReader) InfoPlist() (plistutil.PlistData, error) {

// IsMacOS ...
func (reader XCArchiveReader) IsMacOS() bool {
return reader.zipReader.IsFileOrDirExistsInZipArchive("*.xcarchive/Products/Applications/*.app/Contents/*")
_, err := reader.zipReader.ReadFile("*.xcarchive/Products/Applications/*.app/Contents/Info.plist")
return err == nil
}
7 changes: 7 additions & 0 deletions artifacts/zip_reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package artifacts

// ZipReadCloser ...
type ZipReadCloser interface {
ReadFile(relPthPattern string) ([]byte, error)
Close() error
}
Loading

0 comments on commit e42d0c6

Please sign in to comment.