Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy statedb/couchdb recursively discarding non .json files to create index for public and private data assets. #108

Merged
merged 7 commits into from
Mar 27, 2024
61 changes: 59 additions & 2 deletions cmd/release/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,16 @@ var _ = Describe("Main", func() {

indexPath := filepath.Join(tempDir, "statedb", "couchdb", "indexes", "indexOwner.json")
Expect(indexPath).To(BeARegularFile())

assetPrivateDataCollectionIndexPath := filepath.Join(tempDir, "statedb", "couchdb", "collections", "assetCollection", "indexes", "indexOwner.json")
Expect(assetPrivateDataCollectionIndexPath).To(BeARegularFile(), "Private data index should be copied")

fabCarPrivateDataCollectionIndexPath := filepath.Join(tempDir, "statedb", "couchdb", "collections", "fabCarCollection", "indexes", "indexOwner.json")
Expect(fabCarPrivateDataCollectionIndexPath).To(BeARegularFile(), "Private data index should be copied")

textPath := filepath.Join(tempDir, "statedb", "couchdb", "indexes", "test.txt")
Expect(textPath).NotTo(BeAnExistingFile())
Expect(textPath).NotTo(BeAnExistingFile(), "Unexpected files should not be copied")

subdirPath := filepath.Join(
tempDir,
"statedb",
Expand All @@ -58,6 +66,55 @@ var _ = Describe("Main", func() {
"subdir",
"indexOwner.json",
)
Expect(subdirPath).NotTo(BeAnExistingFile())
Expect(subdirPath).NotTo(BeAnExistingFile(), "Files outside indexes directory should not be copied")

privateDataCollectionSubdirPath := filepath.Join(
tempDir,
"statedb",
"couchdb",
"collections",
"fabCarCollection",
"subdir",
"indexes",
"indexOwner.json",
)
Expect(privateDataCollectionSubdirPath).NotTo(BeAnExistingFile(), "Files outside indexes directory should not be copied")

collectionsdCollectionPath := filepath.Join(
tempDir,
"statedb",
"couchdb",
"collectionsd",
"fabCarCollection",
"indexes",
"indexOwner.json",
)
Expect(collectionsdCollectionPath).NotTo(BeAnExistingFile(), "Files outside indexes directory should not be copied")

indexedCollectionSubdirPath := filepath.Join(
tempDir,
"statedb",
"couchdb",
"indexed",
"indexes",
"indexOwner.json",
)
Expect(indexedCollectionSubdirPath).NotTo(BeAnExistingFile(), "Files outside indexes directory should not be copied")

rootIndexOwnerJSONFile := filepath.Join(
tempDir,
"statedb",
"couchdb",
"indexOwner.json",
)
Expect(rootIndexOwnerJSONFile).NotTo(BeAnExistingFile(), "Files outside indexes directory should not be copied")

roottestTXTFile := filepath.Join(
tempDir,
"statedb",
"couchdb",
"test.txt",
)
Expect(roottestTXTFile).NotTo(BeAnExistingFile(), "Files outside indexes directory should not be copied")
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"index": {
"fields": [
"objectType",
"owner"
]
},
"ddoc": "indexOwnerDoc",
"name": "indexOwner",
"type": "json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"index": {
"fields": [
"model",
"owner"
]
},
"ddoc": "indexOwnerDoc",
"name": "indexOwner",
"type": "json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"index": {
"fields": [
"objectType",
"owner"
]
},
"ddoc": "indexOwnerDoc",
"name": "indexOwner",
"type": "json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"index": {
"fields": [
"model",
"owner"
]
},
"ddoc": "indexOwnerDoc",
"name": "indexOwner",
"type": "json"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Testing
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Testing
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Testing
2 changes: 1 addition & 1 deletion internal/builder/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func (r *Release) Run(ctx context.Context) error {
logger.Debugln("Releasing chaincode...")

// If CouchDB index definitions are required for the chaincode, release is
// responsible for placing the indexes into the statedb/couchdb/indexes
// responsible for placing the indexes into the statedb/couchdb/
// directory under RELEASE_OUTPUT_DIR. The indexes must have a .json
// extension.
err := util.CopyIndexFiles(logger, r.BuildOutputDirectory, r.ReleaseOutputDirectory)
Expand Down
122 changes: 107 additions & 15 deletions internal/util/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,9 @@ func CopyImageJSON(logger *log.CmdLogger, src, dest string) error {

// CopyIndexFiles copies CouchDB index definitions from source to destination directories.
func CopyIndexFiles(logger *log.CmdLogger, src, dest string) error {
indexDir := filepath.Join("statedb", "couchdb", "indexes")
indexSrcDir := filepath.Join(src, MetadataDir, indexDir)
indexDestDir := filepath.Join(dest, indexDir)

logger.Debugf("Copying CouchDB index definitions from %s to %s", indexSrcDir, indexDestDir)
logger.Debugf("Copying couchdb index files from %s to %s", src, dest)

fileInfo, err := os.Lstat(indexSrcDir)
_, err := os.Lstat(src)
if err != nil {
if os.IsNotExist(err) {
// indexes are optional
Expand All @@ -57,17 +53,38 @@ func CopyIndexFiles(logger *log.CmdLogger, src, dest string) error {
return err
}

if !fileInfo.IsDir() {
return fmt.Errorf(
"CouchDB index definitions path %s is not a directory: %w",
indexSrcDir,
err,
)
}
indexDir := filepath.Join("statedb", "couchdb")
indexSrcDir := filepath.Join(src, MetadataDir, indexDir)
indexDestDir := filepath.Join(dest, indexDir)

opt := copy.Options{
Skip: func(_ os.FileInfo, src, _ string) (bool, error) {
return !strings.HasSuffix(src, ".json"), nil
Skip: func(info os.FileInfo, src, _ string) (bool, error) {
logger.Debugf("Checking source copy path: %s", src)
if info.IsDir() {
skip, err := skipFolder(logger, indexSrcDir, src)
if err != nil {
return skip, fmt.Errorf(
"error checking if the folder is eligible to have a couchdb index: %s, %s: %w",
indexSrcDir,
src,
err,
)
}

return skip, nil
}

skip, err := skipFile(logger, indexSrcDir, src)
if err != nil {
jt-nti marked this conversation as resolved.
Show resolved Hide resolved
return skip, fmt.Errorf(
"error checking if the file is eligible to have a couchdb index: %s, %s: %w",
indexSrcDir,
src,
err,
)
}

return skip, nil
},
}

Expand Down Expand Up @@ -115,3 +132,78 @@ func CopyMetadataDir(logger *log.CmdLogger, src, dest string) error {

return nil
}

// skipFile checks if the file will need to be skipped during indexes copy.
func skipFile(logger *log.CmdLogger, indexSrcDir, src string) (bool, error) {
path, err := filepath.Rel(indexSrcDir, src)
if err != nil {
logger.Debugf("error verifying relative path from: %s, src: %s", indexSrcDir, src)

return true, fmt.Errorf(
"error verifying relative path from %s to %s: %w",
indexSrcDir,
src,
err,
)
}

if len(strings.Split(path, string(filepath.Separator))) == 1 { // JSON is in root couchdb folder
logger.Debugf("The JSON file in the root couchdb index folder, should skip: %s, src: %s", path, src)

return true, nil
}

if strings.HasSuffix(src, ".json") {
logger.Debugf("The JSON file is valid, should copy: %s, src: %s", path, src)

return false, nil
}

logger.Debugf("The JSON file is invalid, should skip: %s, src: %s", path, src)

return true, nil
}

// skipFolder checks if the folder will need to be skipped during indexes copy.
func skipFolder(logger *log.CmdLogger, indexSrcDir, src string) (bool, error) {
path, err := filepath.Rel(indexSrcDir, src)
if err != nil {
logger.Debugf("failed resolve relative path: %s, src: %s", indexSrcDir, src)

return true, fmt.Errorf("failed resolve relative path %s to %s: %w", indexSrcDir, src, err)
}

matchContainsPublicIndexFolder, _ := filepath.Match("indexes", path)
matchContainsPrivateDataCollectionFolder, _ := filepath.Match("collections", path)
matchPrivateDataCollectionFolder, _ := filepath.Match("collections/*", path)
matchPrivateDataCollectionIndexFolder, _ := filepath.Match("collections/*/indexes", path)
relativeFoldersLength := len(strings.Split(path, string(filepath.Separator)))

logger.Debugf("Calculated relative path: %s. Total relative folders: %d", path, relativeFoldersLength)
logger.Debugf("Match pattern 'index': %t", matchContainsPublicIndexFolder)
logger.Debugf("Match pattern 'collections': %t", matchContainsPrivateDataCollectionFolder)
logger.Debugf("Match pattern 'collections/*': %t", matchPrivateDataCollectionFolder)
logger.Debugf("Match pattern 'collections/*/indexes': %t", matchPrivateDataCollectionIndexFolder)

switch {
case relativeFoldersLength == 1 && (!matchContainsPublicIndexFolder && !matchContainsPrivateDataCollectionFolder):
logger.Debugf("Should skip folder")

return true, nil

case relativeFoldersLength == 2 && (!matchPrivateDataCollectionFolder):
logger.Debugf("Should skip folder")

return true, nil

case relativeFoldersLength == 3 && (!matchPrivateDataCollectionIndexFolder):
logger.Debugf("Should skip folder")

return true, nil

default:
logger.Debugf("Should not skip folder")

return false, nil
}
}
Loading