// Copyright 2018 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package patch sets/replaces the application class/package in a given AndroidManifest.xml. package patch import ( "bytes" "encoding/xml" "flag" "io/ioutil" "log" "os" "strings" "sync" "src/common/golang/flags" "src/tools/ak/manifestutils" "src/tools/ak/types" ) var stubManifest = ` ` var ( // Cmd defines the command to run patch Cmd = types.Command{ Init: Init, Run: Run, Desc: desc, Flags: []string{"in", "out", "attr", "app", "oldapp", "pkg"}, } // Variables that hold flag values split flags.StringList attr flags.StringList in string out string app string oldApp string pkg string initOnce sync.Once ) // Init initializes patch. func Init() { initOnce.Do(func() { flag.StringVar(&in, "in", "", "Path to the input xml file.") flag.StringVar(&out, "out", "", "Path to the output xml file.") flag.Var(&attr, "attr", "(optional) attr(s) to set. {element}:{attr}:{value}.") flag.Var(&split, "split", "(optional) splits(s) to write. {name}:{file}.") flag.StringVar(&oldApp, "oldapp", "", "(optional) Path to output the old application class name.") flag.StringVar(&pkg, "pkg", "", "(optional) Path to output the package name.") }) } func desc() string { return "Setapp sets/replaces the application class in a given AndroidManifest.xml." } // Run is the entry point for patch. func Run() { if in == "" || (out == "" && split == nil) { log.Fatal("fields and -in and -out|-splits and must be defined.") } elems := manifestutils.CreatePatchElements(attr) elems[manifestutils.ElemManifest] = make(map[string]xml.Attr) b, err := ioutil.ReadFile(in) if err != nil { log.Fatalf("ioutil.ReadFile(%q) failed: %v", in, err) } var manifest manifestutils.Manifest xml.Unmarshal(b, &manifest) // Optional parse package name and/or application class name before replacing if pkg != "" || oldApp != "" { if pkg != "" { err = ioutil.WriteFile(pkg, []byte(manifest.Package), 0644) if err != nil { log.Fatalf("ioutil.WriteFile(%q) failed: %v", pkg, err) } } if oldApp != "" { appName := manifest.Application.Name if appName == "" { appName = "android.app.Application" } err := ioutil.WriteFile(oldApp, []byte(appName), 0644) if err != nil { log.Fatalf("ioutil.WriteFile(%q) failed: %v", oldApp, err) } } } // parse manifest attrs if any for stub manifest if manifest.Package != "" { elems[manifestutils.ElemManifest][manifestutils.AttrPackage] = xml.Attr{ Name: xml.Name{Local: manifestutils.AttrPackage}, Value: manifest.Package} } if manifest.SharedUserID != "" { elems[manifestutils.ElemManifest][manifestutils.AttrSharedUserID] = xml.Attr{ Name: xml.Name{Space: manifestutils.NameSpace, Local: manifestutils.AttrSharedUserID}, Value: manifest.SharedUserID} } if manifest.SharedUserLabel != "" { elems[manifestutils.ElemManifest][manifestutils.AttrSharedUserLabel] = xml.Attr{ Name: xml.Name{Space: manifestutils.NameSpace, Local: manifestutils.AttrSharedUserLabel}, Value: manifest.SharedUserLabel} } if manifest.VersionCode != "" { elems[manifestutils.ElemManifest][manifestutils.AttrVersionCode] = xml.Attr{ Name: xml.Name{Space: manifestutils.NameSpace, Local: manifestutils.AttrVersionCode}, Value: manifest.VersionCode} } if manifest.VersionName != "" { elems[manifestutils.ElemManifest][manifestutils.AttrVersionName] = xml.Attr{ Name: xml.Name{Space: manifestutils.NameSpace, Local: manifestutils.AttrVersionName}, Value: manifest.VersionName} } if out != "" { o, err := os.Create(out) if err != nil { log.Fatalf("Error creating output file %q: %v", out, err) } defer o.Close() if err := manifestutils.WriteManifest(o, bytes.NewReader(b), elems); err != nil { log.Fatalf("Error setting fields: %v", err) } } // Patch the splits b = []byte(stubManifest) for _, s := range split { pts := strings.Split(s, ":") if len(pts) != 2 { log.Fatalf("Failed to parse split %s", s) } elems[manifestutils.ElemManifest][manifestutils.AttrSplit] = xml.Attr{ Name: xml.Name{Local: manifestutils.AttrSplit}, Value: pts[0]} o, err := os.Create(pts[1]) if err != nil { log.Fatalf("Error creating output file %q: %v", pts[1], err) } if err := manifestutils.WriteManifest(o, bytes.NewReader(b), elems); err != nil { log.Fatalf("Error setting fields: %v", err) } } }