Home | History | Annotate | Download | only in build
      1 // Copyright 2017 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package build
     16 
     17 import (
     18 	"fmt"
     19 	"io/ioutil"
     20 	"os"
     21 	"path/filepath"
     22 	"strings"
     23 )
     24 
     25 func removeGlobs(ctx Context, globs ...string) {
     26 	for _, glob := range globs {
     27 		files, err := filepath.Glob(glob)
     28 		if err != nil {
     29 			// Only possible error is ErrBadPattern
     30 			panic(fmt.Errorf("%q: %s", glob, err))
     31 		}
     32 
     33 		for _, file := range files {
     34 			err = os.RemoveAll(file)
     35 			if err != nil {
     36 				ctx.Fatalf("Failed to remove file %q: %v", file, err)
     37 			}
     38 		}
     39 	}
     40 }
     41 
     42 // Remove everything under the out directory. Don't remove the out directory
     43 // itself in case it's a symlink.
     44 func clean(ctx Context, config Config, what int) {
     45 	removeGlobs(ctx, filepath.Join(config.OutDir(), "*"))
     46 	ctx.Println("Entire build directory removed.")
     47 }
     48 
     49 func dataClean(ctx Context, config Config, what int) {
     50 	removeGlobs(ctx, filepath.Join(config.ProductOut(), "data", "*"))
     51 }
     52 
     53 // installClean deletes all of the installed files -- the intent is to remove
     54 // files that may no longer be installed, either because the user previously
     55 // installed them, or they were previously installed by default but no longer
     56 // are.
     57 //
     58 // This is faster than a full clean, since we're not deleting the
     59 // intermediates.  Instead of recompiling, we can just copy the results.
     60 func installClean(ctx Context, config Config, what int) {
     61 	dataClean(ctx, config, what)
     62 
     63 	if hostCrossOutPath := config.hostCrossOut(); hostCrossOutPath != "" {
     64 		hostCrossOut := func(path string) string {
     65 			return filepath.Join(hostCrossOutPath, path)
     66 		}
     67 		removeGlobs(ctx,
     68 			hostCrossOut("bin"),
     69 			hostCrossOut("coverage"),
     70 			hostCrossOut("lib*"),
     71 			hostCrossOut("nativetest*"))
     72 	}
     73 
     74 	hostOutPath := config.HostOut()
     75 	hostOut := func(path string) string {
     76 		return filepath.Join(hostOutPath, path)
     77 	}
     78 
     79 	productOutPath := config.ProductOut()
     80 	productOut := func(path string) string {
     81 		return filepath.Join(productOutPath, path)
     82 	}
     83 
     84 	// Host bin, frameworks, and lib* are intentionally omitted, since
     85 	// otherwise we'd have to rebuild any generated files created with
     86 	// those tools.
     87 	removeGlobs(ctx,
     88 		hostOut("obj/NOTICE_FILES"),
     89 		hostOut("obj/PACKAGING"),
     90 		hostOut("coverage"),
     91 		hostOut("cts"),
     92 		hostOut("nativetest*"),
     93 		hostOut("sdk"),
     94 		hostOut("sdk_addon"),
     95 		hostOut("testcases"),
     96 		hostOut("vts"),
     97 		productOut("*.img"),
     98 		productOut("*.zip"),
     99 		productOut("android-info.txt"),
    100 		productOut("kernel"),
    101 		productOut("data"),
    102 		productOut("skin"),
    103 		productOut("obj/NOTICE_FILES"),
    104 		productOut("obj/PACKAGING"),
    105 		productOut("recovery"),
    106 		productOut("root"),
    107 		productOut("system"),
    108 		productOut("system_other"),
    109 		productOut("vendor"),
    110 		productOut("product"),
    111 		productOut("oem"),
    112 		productOut("obj/FAKE"),
    113 		productOut("breakpad"),
    114 		productOut("cache"),
    115 		productOut("coverage"),
    116 		productOut("installer"),
    117 		productOut("odm"),
    118 		productOut("sysloader"),
    119 		productOut("testcases"))
    120 }
    121 
    122 // Since products and build variants (unfortunately) shared the same
    123 // PRODUCT_OUT staging directory, things can get out of sync if different
    124 // build configurations are built in the same tree. This function will
    125 // notice when the configuration has changed and call installclean to
    126 // remove the files necessary to keep things consistent.
    127 func installCleanIfNecessary(ctx Context, config Config) {
    128 	configFile := config.DevicePreviousProductConfig()
    129 	prefix := "PREVIOUS_BUILD_CONFIG := "
    130 	suffix := "\n"
    131 	currentProduct := prefix + config.TargetProduct() + "-" + config.TargetBuildVariant() + suffix
    132 
    133 	ensureDirectoriesExist(ctx, filepath.Dir(configFile))
    134 
    135 	writeConfig := func() {
    136 		err := ioutil.WriteFile(configFile, []byte(currentProduct), 0666)
    137 		if err != nil {
    138 			ctx.Fatalln("Failed to write product config:", err)
    139 		}
    140 	}
    141 
    142 	prev, err := ioutil.ReadFile(configFile)
    143 	if err != nil {
    144 		if os.IsNotExist(err) {
    145 			writeConfig()
    146 			return
    147 		} else {
    148 			ctx.Fatalln("Failed to read previous product config:", err)
    149 		}
    150 	} else if string(prev) == currentProduct {
    151 		return
    152 	}
    153 
    154 	if disable, _ := config.Environment().Get("DISABLE_AUTO_INSTALLCLEAN"); disable == "true" {
    155 		ctx.Println("DISABLE_AUTO_INSTALLCLEAN is set; skipping auto-clean. Your tree may be in an inconsistent state.")
    156 		return
    157 	}
    158 
    159 	ctx.BeginTrace("installclean")
    160 	defer ctx.EndTrace()
    161 
    162 	prevConfig := strings.TrimPrefix(strings.TrimSuffix(string(prev), suffix), prefix)
    163 	currentConfig := strings.TrimPrefix(strings.TrimSuffix(currentProduct, suffix), prefix)
    164 
    165 	ctx.Printf("Build configuration changed: %q -> %q, forcing installclean\n", prevConfig, currentConfig)
    166 
    167 	installClean(ctx, config, 0)
    168 
    169 	writeConfig()
    170 }
    171