1*333d2b36SAndroid Build Coastguard Worker// Copyright (C) 2021 The Android Open Source Project 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage android_sdk 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "fmt" 19*333d2b36SAndroid Build Coastguard Worker "io" 20*333d2b36SAndroid Build Coastguard Worker "path/filepath" 21*333d2b36SAndroid Build Coastguard Worker "strings" 22*333d2b36SAndroid Build Coastguard Worker 23*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint" 24*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/pathtools" 25*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 28*333d2b36SAndroid Build Coastguard Worker "android/soong/cc/config" 29*333d2b36SAndroid Build Coastguard Worker) 30*333d2b36SAndroid Build Coastguard Worker 31*333d2b36SAndroid Build Coastguard Workervar pctx = android.NewPackageContext("android/soong/android_sdk") 32*333d2b36SAndroid Build Coastguard Worker 33*333d2b36SAndroid Build Coastguard Workerfunc init() { 34*333d2b36SAndroid Build Coastguard Worker registerBuildComponents(android.InitRegistrationContext) 35*333d2b36SAndroid Build Coastguard Worker} 36*333d2b36SAndroid Build Coastguard Worker 37*333d2b36SAndroid Build Coastguard Workerfunc registerBuildComponents(ctx android.RegistrationContext) { 38*333d2b36SAndroid Build Coastguard Worker ctx.RegisterModuleType("android_sdk_repo_host", SdkRepoHostFactory) 39*333d2b36SAndroid Build Coastguard Worker} 40*333d2b36SAndroid Build Coastguard Worker 41*333d2b36SAndroid Build Coastguard Workertype sdkRepoHost struct { 42*333d2b36SAndroid Build Coastguard Worker android.ModuleBase 43*333d2b36SAndroid Build Coastguard Worker android.PackagingBase 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard Worker properties sdkRepoHostProperties 46*333d2b36SAndroid Build Coastguard Worker 47*333d2b36SAndroid Build Coastguard Worker outputBaseName string 48*333d2b36SAndroid Build Coastguard Worker outputFile android.OptionalPath 49*333d2b36SAndroid Build Coastguard Worker 50*333d2b36SAndroid Build Coastguard Worker // TODO(b/357908583): Temp field, remove this once we support Android Mk providers 51*333d2b36SAndroid Build Coastguard Worker installFile android.InstallPath 52*333d2b36SAndroid Build Coastguard Worker} 53*333d2b36SAndroid Build Coastguard Worker 54*333d2b36SAndroid Build Coastguard Workertype remapProperties struct { 55*333d2b36SAndroid Build Coastguard Worker From string 56*333d2b36SAndroid Build Coastguard Worker To string 57*333d2b36SAndroid Build Coastguard Worker} 58*333d2b36SAndroid Build Coastguard Worker 59*333d2b36SAndroid Build Coastguard Workertype sdkRepoHostProperties struct { 60*333d2b36SAndroid Build Coastguard Worker // The top level directory to use for the SDK repo. 61*333d2b36SAndroid Build Coastguard Worker Base_dir *string 62*333d2b36SAndroid Build Coastguard Worker 63*333d2b36SAndroid Build Coastguard Worker // List of src:dst mappings to rename files from `deps`. 64*333d2b36SAndroid Build Coastguard Worker Deps_remap []remapProperties `android:"arch_variant"` 65*333d2b36SAndroid Build Coastguard Worker 66*333d2b36SAndroid Build Coastguard Worker // List of zip files to merge into the SDK repo. 67*333d2b36SAndroid Build Coastguard Worker Merge_zips []string `android:"arch_variant,path"` 68*333d2b36SAndroid Build Coastguard Worker 69*333d2b36SAndroid Build Coastguard Worker // List of sources to include into the SDK repo. These are usually raw files, filegroups, 70*333d2b36SAndroid Build Coastguard Worker // or genrules, as most built modules should be referenced via `deps`. 71*333d2b36SAndroid Build Coastguard Worker Srcs []string `android:"arch_variant,path"` 72*333d2b36SAndroid Build Coastguard Worker 73*333d2b36SAndroid Build Coastguard Worker // List of files to strip. This should be a list of files, not modules. This happens after 74*333d2b36SAndroid Build Coastguard Worker // `deps_remap` and `merge_zips` are applied, but before the `base_dir` is added. 75*333d2b36SAndroid Build Coastguard Worker Strip_files []string `android:"arch_variant"` 76*333d2b36SAndroid Build Coastguard Worker} 77*333d2b36SAndroid Build Coastguard Worker 78*333d2b36SAndroid Build Coastguard Worker// android_sdk_repo_host defines an Android SDK repo containing host tools. 79*333d2b36SAndroid Build Coastguard Worker// 80*333d2b36SAndroid Build Coastguard Worker// This implementation is trying to be a faithful reproduction of how these sdk-repos were produced 81*333d2b36SAndroid Build Coastguard Worker// in the Make system, which may explain some of the oddities (like `strip_files` not being 82*333d2b36SAndroid Build Coastguard Worker// automatic) 83*333d2b36SAndroid Build Coastguard Workerfunc SdkRepoHostFactory() android.Module { 84*333d2b36SAndroid Build Coastguard Worker return newSdkRepoHostModule() 85*333d2b36SAndroid Build Coastguard Worker} 86*333d2b36SAndroid Build Coastguard Worker 87*333d2b36SAndroid Build Coastguard Workerfunc newSdkRepoHostModule() *sdkRepoHost { 88*333d2b36SAndroid Build Coastguard Worker s := &sdkRepoHost{} 89*333d2b36SAndroid Build Coastguard Worker s.AddProperties(&s.properties) 90*333d2b36SAndroid Build Coastguard Worker android.InitPackageModule(s) 91*333d2b36SAndroid Build Coastguard Worker android.InitAndroidMultiTargetsArchModule(s, android.HostSupported, android.MultilibCommon) 92*333d2b36SAndroid Build Coastguard Worker return s 93*333d2b36SAndroid Build Coastguard Worker} 94*333d2b36SAndroid Build Coastguard Worker 95*333d2b36SAndroid Build Coastguard Workertype dependencyTag struct { 96*333d2b36SAndroid Build Coastguard Worker blueprint.BaseDependencyTag 97*333d2b36SAndroid Build Coastguard Worker android.PackagingItemAlwaysDepTag 98*333d2b36SAndroid Build Coastguard Worker} 99*333d2b36SAndroid Build Coastguard Worker 100*333d2b36SAndroid Build Coastguard Worker// TODO(b/201696252): Evaluate whether licenses should be propagated through this dependency. 101*333d2b36SAndroid Build Coastguard Workerfunc (d dependencyTag) PropagateLicenses() bool { 102*333d2b36SAndroid Build Coastguard Worker return false 103*333d2b36SAndroid Build Coastguard Worker} 104*333d2b36SAndroid Build Coastguard Worker 105*333d2b36SAndroid Build Coastguard Workervar depTag = dependencyTag{} 106*333d2b36SAndroid Build Coastguard Worker 107*333d2b36SAndroid Build Coastguard Workerfunc (s *sdkRepoHost) DepsMutator(ctx android.BottomUpMutatorContext) { 108*333d2b36SAndroid Build Coastguard Worker s.AddDeps(ctx, depTag) 109*333d2b36SAndroid Build Coastguard Worker} 110*333d2b36SAndroid Build Coastguard Worker 111*333d2b36SAndroid Build Coastguard Workerfunc (s *sdkRepoHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { 112*333d2b36SAndroid Build Coastguard Worker dir := android.PathForModuleOut(ctx, "zip") 113*333d2b36SAndroid Build Coastguard Worker outputZipFile := dir.Join(ctx, "output.zip") 114*333d2b36SAndroid Build Coastguard Worker builder := android.NewRuleBuilder(pctx, ctx). 115*333d2b36SAndroid Build Coastguard Worker Sbox(dir, android.PathForModuleOut(ctx, "out.sbox.textproto")). 116*333d2b36SAndroid Build Coastguard Worker SandboxInputs() 117*333d2b36SAndroid Build Coastguard Worker 118*333d2b36SAndroid Build Coastguard Worker // Get files from modules listed in `deps` 119*333d2b36SAndroid Build Coastguard Worker packageSpecs := s.GatherPackagingSpecs(ctx) 120*333d2b36SAndroid Build Coastguard Worker 121*333d2b36SAndroid Build Coastguard Worker // Handle `deps_remap` renames 122*333d2b36SAndroid Build Coastguard Worker err := remapPackageSpecs(packageSpecs, s.properties.Deps_remap) 123*333d2b36SAndroid Build Coastguard Worker if err != nil { 124*333d2b36SAndroid Build Coastguard Worker ctx.PropertyErrorf("deps_remap", "%s", err.Error()) 125*333d2b36SAndroid Build Coastguard Worker } 126*333d2b36SAndroid Build Coastguard Worker 127*333d2b36SAndroid Build Coastguard Worker s.CopySpecsToDir(ctx, builder, packageSpecs, dir) 128*333d2b36SAndroid Build Coastguard Worker 129*333d2b36SAndroid Build Coastguard Worker noticeFile := android.PathForModuleOut(ctx, "NOTICES.txt") 130*333d2b36SAndroid Build Coastguard Worker android.BuildNoticeTextOutputFromLicenseMetadata( 131*333d2b36SAndroid Build Coastguard Worker ctx, noticeFile, "", "", 132*333d2b36SAndroid Build Coastguard Worker []string{ 133*333d2b36SAndroid Build Coastguard Worker android.PathForModuleInstall(ctx, "sdk-repo").String() + "/", 134*333d2b36SAndroid Build Coastguard Worker outputZipFile.String(), 135*333d2b36SAndroid Build Coastguard Worker }) 136*333d2b36SAndroid Build Coastguard Worker builder.Command().Text("cp"). 137*333d2b36SAndroid Build Coastguard Worker Input(noticeFile). 138*333d2b36SAndroid Build Coastguard Worker Text(filepath.Join(dir.String(), "NOTICE.txt")) 139*333d2b36SAndroid Build Coastguard Worker 140*333d2b36SAndroid Build Coastguard Worker // Handle `merge_zips` by extracting their contents into our tmpdir 141*333d2b36SAndroid Build Coastguard Worker for _, zip := range android.PathsForModuleSrc(ctx, s.properties.Merge_zips) { 142*333d2b36SAndroid Build Coastguard Worker builder.Command(). 143*333d2b36SAndroid Build Coastguard Worker Text("unzip"). 144*333d2b36SAndroid Build Coastguard Worker Flag("-DD"). 145*333d2b36SAndroid Build Coastguard Worker Flag("-q"). 146*333d2b36SAndroid Build Coastguard Worker FlagWithArg("-d ", dir.String()). 147*333d2b36SAndroid Build Coastguard Worker Input(zip) 148*333d2b36SAndroid Build Coastguard Worker } 149*333d2b36SAndroid Build Coastguard Worker 150*333d2b36SAndroid Build Coastguard Worker // Copy files from `srcs` into our tmpdir 151*333d2b36SAndroid Build Coastguard Worker for _, src := range android.PathsForModuleSrc(ctx, s.properties.Srcs) { 152*333d2b36SAndroid Build Coastguard Worker builder.Command(). 153*333d2b36SAndroid Build Coastguard Worker Text("cp").Input(src).Flag(dir.Join(ctx, src.Rel()).String()) 154*333d2b36SAndroid Build Coastguard Worker } 155*333d2b36SAndroid Build Coastguard Worker 156*333d2b36SAndroid Build Coastguard Worker // Handle `strip_files` by calling the necessary strip commands 157*333d2b36SAndroid Build Coastguard Worker // 158*333d2b36SAndroid Build Coastguard Worker // Note: this stripping logic was copied over from the old Make implementation 159*333d2b36SAndroid Build Coastguard Worker // It's not using the same flags as the regular stripping support, nor does it 160*333d2b36SAndroid Build Coastguard Worker // support the array of per-module stripping options. It would be nice if we 161*333d2b36SAndroid Build Coastguard Worker // pulled the stripped versions from the CC modules, but that doesn't exist 162*333d2b36SAndroid Build Coastguard Worker // for host tools today. (And not all the things we strip are CC modules today) 163*333d2b36SAndroid Build Coastguard Worker if ctx.Darwin() { 164*333d2b36SAndroid Build Coastguard Worker macStrip := config.MacStripPath(ctx) 165*333d2b36SAndroid Build Coastguard Worker for _, strip := range s.properties.Strip_files { 166*333d2b36SAndroid Build Coastguard Worker builder.Command(). 167*333d2b36SAndroid Build Coastguard Worker Text(macStrip).Flag("-x"). 168*333d2b36SAndroid Build Coastguard Worker Flag(dir.Join(ctx, strip).String()) 169*333d2b36SAndroid Build Coastguard Worker } 170*333d2b36SAndroid Build Coastguard Worker } else { 171*333d2b36SAndroid Build Coastguard Worker llvmObjCopy := config.ClangPath(ctx, "bin/llvm-objcopy") 172*333d2b36SAndroid Build Coastguard Worker llvmStrip := config.ClangPath(ctx, "bin/llvm-strip") 173*333d2b36SAndroid Build Coastguard Worker llvmLib := config.ClangPath(ctx, "lib/x86_64-unknown-linux-gnu/libc++.so") 174*333d2b36SAndroid Build Coastguard Worker for _, strip := range s.properties.Strip_files { 175*333d2b36SAndroid Build Coastguard Worker cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib).ImplicitTool(llvmObjCopy) 176*333d2b36SAndroid Build Coastguard Worker if !ctx.Windows() { 177*333d2b36SAndroid Build Coastguard Worker cmd.Flag("-x") 178*333d2b36SAndroid Build Coastguard Worker } 179*333d2b36SAndroid Build Coastguard Worker cmd.Flag(dir.Join(ctx, strip).String()) 180*333d2b36SAndroid Build Coastguard Worker } 181*333d2b36SAndroid Build Coastguard Worker } 182*333d2b36SAndroid Build Coastguard Worker 183*333d2b36SAndroid Build Coastguard Worker // Fix up the line endings of all text files. This also removes executable permissions. 184*333d2b36SAndroid Build Coastguard Worker builder.Command(). 185*333d2b36SAndroid Build Coastguard Worker Text("find"). 186*333d2b36SAndroid Build Coastguard Worker Flag(dir.String()). 187*333d2b36SAndroid Build Coastguard Worker Flag("-name '*.aidl' -o -name '*.css' -o -name '*.html' -o -name '*.java'"). 188*333d2b36SAndroid Build Coastguard Worker Flag("-o -name '*.js' -o -name '*.prop' -o -name '*.template'"). 189*333d2b36SAndroid Build Coastguard Worker Flag("-o -name '*.txt' -o -name '*.windows' -o -name '*.xml' -print0"). 190*333d2b36SAndroid Build Coastguard Worker // Using -n 500 for xargs to limit the max number of arguments per call to line_endings 191*333d2b36SAndroid Build Coastguard Worker // to 500. This avoids line_endings failing with "arguments too long". 192*333d2b36SAndroid Build Coastguard Worker Text("| xargs -0 -n 500 "). 193*333d2b36SAndroid Build Coastguard Worker BuiltTool("line_endings"). 194*333d2b36SAndroid Build Coastguard Worker Flag("unix") 195*333d2b36SAndroid Build Coastguard Worker 196*333d2b36SAndroid Build Coastguard Worker // Exclude some file types (roughly matching sdk.exclude.atree) 197*333d2b36SAndroid Build Coastguard Worker builder.Command(). 198*333d2b36SAndroid Build Coastguard Worker Text("find"). 199*333d2b36SAndroid Build Coastguard Worker Flag(dir.String()). 200*333d2b36SAndroid Build Coastguard Worker Flag("'('"). 201*333d2b36SAndroid Build Coastguard Worker Flag("-name '.*' -o -name '*~' -o -name 'Makefile' -o -name 'Android.mk' -o"). 202*333d2b36SAndroid Build Coastguard Worker Flag("-name '.*.swp' -o -name '.DS_Store' -o -name '*.pyc' -o -name 'OWNERS' -o"). 203*333d2b36SAndroid Build Coastguard Worker Flag("-name 'MODULE_LICENSE_*' -o -name '*.ezt' -o -name 'Android.bp'"). 204*333d2b36SAndroid Build Coastguard Worker Flag("')' -print0"). 205*333d2b36SAndroid Build Coastguard Worker Text("| xargs -0 -r rm -rf") 206*333d2b36SAndroid Build Coastguard Worker builder.Command(). 207*333d2b36SAndroid Build Coastguard Worker Text("find"). 208*333d2b36SAndroid Build Coastguard Worker Flag(dir.String()). 209*333d2b36SAndroid Build Coastguard Worker Flag("-name '_*' ! -name '__*' -print0"). 210*333d2b36SAndroid Build Coastguard Worker Text("| xargs -0 -r rm -rf") 211*333d2b36SAndroid Build Coastguard Worker 212*333d2b36SAndroid Build Coastguard Worker if ctx.Windows() { 213*333d2b36SAndroid Build Coastguard Worker // Fix EOL chars to make window users happy 214*333d2b36SAndroid Build Coastguard Worker builder.Command(). 215*333d2b36SAndroid Build Coastguard Worker Text("find"). 216*333d2b36SAndroid Build Coastguard Worker Flag(dir.String()). 217*333d2b36SAndroid Build Coastguard Worker Flag("-maxdepth 2 -name '*.bat' -type f -print0"). 218*333d2b36SAndroid Build Coastguard Worker Text("| xargs -0 -r unix2dos") 219*333d2b36SAndroid Build Coastguard Worker } 220*333d2b36SAndroid Build Coastguard Worker 221*333d2b36SAndroid Build Coastguard Worker // Zip up our temporary directory as the sdk-repo 222*333d2b36SAndroid Build Coastguard Worker builder.Command(). 223*333d2b36SAndroid Build Coastguard Worker BuiltTool("soong_zip"). 224*333d2b36SAndroid Build Coastguard Worker FlagWithOutput("-o ", outputZipFile). 225*333d2b36SAndroid Build Coastguard Worker FlagWithArg("-P ", proptools.StringDefault(s.properties.Base_dir, ".")). 226*333d2b36SAndroid Build Coastguard Worker FlagWithArg("-C ", dir.String()). 227*333d2b36SAndroid Build Coastguard Worker FlagWithArg("-D ", dir.String()) 228*333d2b36SAndroid Build Coastguard Worker builder.Command().Text("rm").Flag("-rf").Text(dir.String()) 229*333d2b36SAndroid Build Coastguard Worker 230*333d2b36SAndroid Build Coastguard Worker builder.Build("build_sdk_repo", "Creating sdk-repo-"+s.BaseModuleName()) 231*333d2b36SAndroid Build Coastguard Worker 232*333d2b36SAndroid Build Coastguard Worker osName := ctx.Os().String() 233*333d2b36SAndroid Build Coastguard Worker if osName == "linux_glibc" { 234*333d2b36SAndroid Build Coastguard Worker osName = "linux" 235*333d2b36SAndroid Build Coastguard Worker } 236*333d2b36SAndroid Build Coastguard Worker name := fmt.Sprintf("sdk-repo-%s-%s", osName, s.BaseModuleName()) 237*333d2b36SAndroid Build Coastguard Worker 238*333d2b36SAndroid Build Coastguard Worker s.outputBaseName = name 239*333d2b36SAndroid Build Coastguard Worker s.outputFile = android.OptionalPathForPath(outputZipFile) 240*333d2b36SAndroid Build Coastguard Worker installPath := android.PathForModuleInstall(ctx, "sdk-repo") 241*333d2b36SAndroid Build Coastguard Worker name = name + ".zip" 242*333d2b36SAndroid Build Coastguard Worker ctx.InstallFile(installPath, name, outputZipFile) 243*333d2b36SAndroid Build Coastguard Worker // TODO(b/357908583): Temp field, remove this once we support Android Mk providers 244*333d2b36SAndroid Build Coastguard Worker s.installFile = installPath.Join(ctx, name) 245*333d2b36SAndroid Build Coastguard Worker} 246*333d2b36SAndroid Build Coastguard Worker 247*333d2b36SAndroid Build Coastguard Workerfunc (s *sdkRepoHost) AndroidMk() android.AndroidMkData { 248*333d2b36SAndroid Build Coastguard Worker return android.AndroidMkData{ 249*333d2b36SAndroid Build Coastguard Worker Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { 250*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(w, ".PHONY:", name, "sdk_repo", "sdk-repo-"+name) 251*333d2b36SAndroid Build Coastguard Worker fmt.Fprintln(w, "sdk_repo", "sdk-repo-"+name+":", s.installFile.String()) 252*333d2b36SAndroid Build Coastguard Worker 253*333d2b36SAndroid Build Coastguard Worker fmt.Fprintf(w, "$(call dist-for-goals,sdk_repo sdk-repo-%s,%s:%s-FILE_NAME_TAG_PLACEHOLDER.zip)\n\n", s.BaseModuleName(), s.outputFile.String(), s.outputBaseName) 254*333d2b36SAndroid Build Coastguard Worker }, 255*333d2b36SAndroid Build Coastguard Worker } 256*333d2b36SAndroid Build Coastguard Worker} 257*333d2b36SAndroid Build Coastguard Worker 258*333d2b36SAndroid Build Coastguard Workerfunc remapPackageSpecs(specs map[string]android.PackagingSpec, remaps []remapProperties) error { 259*333d2b36SAndroid Build Coastguard Worker for _, remap := range remaps { 260*333d2b36SAndroid Build Coastguard Worker for path, spec := range specs { 261*333d2b36SAndroid Build Coastguard Worker if match, err := pathtools.Match(remap.From, path); err != nil { 262*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("Error parsing %q: %v", remap.From, err) 263*333d2b36SAndroid Build Coastguard Worker } else if match { 264*333d2b36SAndroid Build Coastguard Worker newPath := remap.To 265*333d2b36SAndroid Build Coastguard Worker if pathtools.IsGlob(remap.From) { 266*333d2b36SAndroid Build Coastguard Worker rel, err := filepath.Rel(constantPartOfPattern(remap.From), path) 267*333d2b36SAndroid Build Coastguard Worker if err != nil { 268*333d2b36SAndroid Build Coastguard Worker return fmt.Errorf("Error handling %q", path) 269*333d2b36SAndroid Build Coastguard Worker } 270*333d2b36SAndroid Build Coastguard Worker newPath = filepath.Join(remap.To, rel) 271*333d2b36SAndroid Build Coastguard Worker } 272*333d2b36SAndroid Build Coastguard Worker delete(specs, path) 273*333d2b36SAndroid Build Coastguard Worker spec.SetRelPathInPackage(newPath) 274*333d2b36SAndroid Build Coastguard Worker specs[newPath] = spec 275*333d2b36SAndroid Build Coastguard Worker } 276*333d2b36SAndroid Build Coastguard Worker } 277*333d2b36SAndroid Build Coastguard Worker } 278*333d2b36SAndroid Build Coastguard Worker return nil 279*333d2b36SAndroid Build Coastguard Worker} 280*333d2b36SAndroid Build Coastguard Worker 281*333d2b36SAndroid Build Coastguard Workerfunc constantPartOfPattern(pattern string) string { 282*333d2b36SAndroid Build Coastguard Worker ret := "" 283*333d2b36SAndroid Build Coastguard Worker for pattern != "" { 284*333d2b36SAndroid Build Coastguard Worker var first string 285*333d2b36SAndroid Build Coastguard Worker first, pattern = splitFirst(pattern) 286*333d2b36SAndroid Build Coastguard Worker if pathtools.IsGlob(first) { 287*333d2b36SAndroid Build Coastguard Worker return ret 288*333d2b36SAndroid Build Coastguard Worker } 289*333d2b36SAndroid Build Coastguard Worker ret = filepath.Join(ret, first) 290*333d2b36SAndroid Build Coastguard Worker } 291*333d2b36SAndroid Build Coastguard Worker return ret 292*333d2b36SAndroid Build Coastguard Worker} 293*333d2b36SAndroid Build Coastguard Worker 294*333d2b36SAndroid Build Coastguard Workerfunc splitFirst(path string) (string, string) { 295*333d2b36SAndroid Build Coastguard Worker i := strings.IndexRune(path, filepath.Separator) 296*333d2b36SAndroid Build Coastguard Worker if i < 0 { 297*333d2b36SAndroid Build Coastguard Worker return path, "" 298*333d2b36SAndroid Build Coastguard Worker } 299*333d2b36SAndroid Build Coastguard Worker return path[:i], path[i+1:] 300*333d2b36SAndroid Build Coastguard Worker} 301