Merge "WriteFileRule: Chunk long content and merge them to result"
diff --git a/android/defs.go b/android/defs.go
index 631dfe8..f5bd362 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -15,6 +15,7 @@
package android
import (
+ "fmt"
"strings"
"testing"
@@ -97,7 +98,7 @@
// content to file.
writeFile = pctx.AndroidStaticRule("writeFile",
blueprint.RuleParams{
- Command: `/bin/bash -c 'echo -e "$$0" > $out' $content`,
+ Command: `/bin/bash -c 'echo -e -n "$$0" > $out' $content`,
Description: "writing file $out",
},
"content")
@@ -133,9 +134,7 @@
shellUnescaper = strings.NewReplacer(`'\''`, `'`)
)
-// WriteFileRule creates a ninja rule to write contents to a file. The contents will be escaped
-// so that the file contains exactly the contents passed to the function, plus a trailing newline.
-func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
+func buildWriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
content = echoEscaper.Replace(content)
content = proptools.ShellEscape(content)
if content == "" {
@@ -151,6 +150,31 @@
})
}
+// WriteFileRule creates a ninja rule to write contents to a file. The contents will be escaped
+// so that the file contains exactly the contents passed to the function, plus a trailing newline.
+func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
+ // This is MAX_ARG_STRLEN subtracted with some safety to account for shell escapes
+ const SHARD_SIZE = 131072 - 10000
+
+ content += "\n"
+ if len(content) > SHARD_SIZE {
+ var chunks WritablePaths
+ for i, c := range ShardString(content, SHARD_SIZE) {
+ tempPath := outputFile.ReplaceExtension(ctx, fmt.Sprintf("%s.%d", outputFile.Ext(), i))
+ buildWriteFileRule(ctx, tempPath, c)
+ chunks = append(chunks, tempPath)
+ }
+ ctx.Build(pctx, BuildParams{
+ Rule: Cat,
+ Inputs: chunks.Paths(),
+ Output: outputFile,
+ Description: "Merging to " + outputFile.Base(),
+ })
+ return
+ }
+ buildWriteFileRule(ctx, outputFile, content)
+}
+
// shellUnescape reverses proptools.ShellEscape
func shellUnescape(s string) string {
// Remove leading and trailing quotes if present
diff --git a/android/paths.go b/android/paths.go
index b7117a3..5a41cf1 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -138,6 +138,8 @@
// the writablePath method doesn't directly do anything,
// but it allows a struct to distinguish between whether or not it implements the WritablePath interface
writablePath()
+
+ ReplaceExtension(ctx PathContext, ext string) OutputPath
}
type genPathProvider interface {
@@ -1249,6 +1251,10 @@
return p.config.buildDir
}
+func (p InstallPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
+ panic("Not implemented")
+}
+
var _ Path = InstallPath{}
var _ WritablePath = InstallPath{}
@@ -1511,6 +1517,10 @@
return p.config.buildDir
}
+func (p PhonyPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
+ panic("Not implemented")
+}
+
var _ Path = PhonyPath{}
var _ WritablePath = PhonyPath{}
diff --git a/android/util.go b/android/util.go
index 8e4c0f4..0f940fa 100644
--- a/android/util.go
+++ b/android/util.go
@@ -401,6 +401,23 @@
return ret
}
+// ShardString takes a string and returns a slice of strings where the length of each one is
+// at most shardSize.
+func ShardString(s string, shardSize int) []string {
+ if len(s) == 0 {
+ return nil
+ }
+ ret := make([]string, 0, (len(s)+shardSize-1)/shardSize)
+ for len(s) > shardSize {
+ ret = append(ret, s[0:shardSize])
+ s = s[shardSize:]
+ }
+ if len(s) > 0 {
+ ret = append(ret, s)
+ }
+ return ret
+}
+
// ShardStrings takes a slice of strings, and returns a slice of slices of strings where each one has at most shardSize
// elements.
func ShardStrings(s []string, shardSize int) [][]string {