Merge "Prevent GKI APEXes to write to $OUT/apex."
diff --git a/android/Android.bp b/android/Android.bp
index 6ddcc14..50faa44 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -24,6 +24,7 @@
"filegroup.go",
"hooks.go",
"image.go",
+ "makefile_goal.go",
"makevars.go",
"metrics.go",
"module.go",
diff --git a/android/config.go b/android/config.go
index cafc71b..aeed81d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -337,8 +337,8 @@
config: config,
}
- // Sanity check the build and source directories. This won't catch strange
- // configurations with symlinks, but at least checks the obvious cases.
+ // Soundness check of the build and source directories. This won't catch strange
+ // configurations with symlinks, but at least checks the obvious case.
absBuildDir, err := filepath.Abs(buildDir)
if err != nil {
return Config{}, err
diff --git a/android/makefile_goal.go b/android/makefile_goal.go
new file mode 100644
index 0000000..eae3976
--- /dev/null
+++ b/android/makefile_goal.go
@@ -0,0 +1,99 @@
+// Copyright 2020 Google Inc. 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 android
+
+import (
+ "fmt"
+ "io"
+ "path/filepath"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ RegisterModuleType("makefile_goal", MakefileGoalFactory)
+}
+
+type makefileGoalProperties struct {
+ // Sources.
+
+ // Makefile goal output file path, relative to PRODUCT_OUT.
+ Product_out_path *string
+}
+
+type makefileGoal struct {
+ ModuleBase
+
+ properties makefileGoalProperties
+
+ // Destination. Output file path of this module.
+ outputFilePath OutputPath
+}
+
+var _ AndroidMkEntriesProvider = (*makefileGoal)(nil)
+var _ OutputFileProducer = (*makefileGoal)(nil)
+
+// Input file of this makefile_goal module. Nil if none specified. May use variable names in makefiles.
+func (p *makefileGoal) inputPath() *string {
+ if p.properties.Product_out_path != nil {
+ return proptools.StringPtr(filepath.Join("$(PRODUCT_OUT)", proptools.String(p.properties.Product_out_path)))
+ }
+ return nil
+}
+
+// OutputFileProducer
+func (p *makefileGoal) OutputFiles(tag string) (Paths, error) {
+ if tag != "" {
+ return nil, fmt.Errorf("unsupported tag %q", tag)
+ }
+ return Paths{p.outputFilePath}, nil
+}
+
+// AndroidMkEntriesProvider
+func (p *makefileGoal) DepsMutator(ctx BottomUpMutatorContext) {
+ if p.inputPath() == nil {
+ ctx.PropertyErrorf("product_out_path", "Path relative to PRODUCT_OUT required")
+ }
+}
+
+func (p *makefileGoal) GenerateAndroidBuildActions(ctx ModuleContext) {
+ filename := filepath.Base(proptools.String(p.inputPath()))
+ p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
+
+ ctx.InstallFile(PathForModuleInstall(ctx, "etc"), ctx.ModuleName(), p.outputFilePath)
+}
+
+func (p *makefileGoal) AndroidMkEntries() []AndroidMkEntries {
+ return []AndroidMkEntries{AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: OptionalPathForPath(p.outputFilePath),
+ ExtraFooters: []AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries) {
+ // Can't use Cp because inputPath() is not a valid Path.
+ fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath)
+ },
+ },
+ }}
+}
+
+// Import a Makefile goal to Soong by copying the file built by
+// the goal to a path visible to Soong. This rule only works on boot images.
+func MakefileGoalFactory() Module {
+ module := &makefileGoal{}
+ module.AddProperties(&module.properties)
+ // This module is device-only
+ InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
+ return module
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index 526d399..73829f1 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -56,6 +56,7 @@
AddNeverAllowRules(createJavaDeviceForHostRules()...)
AddNeverAllowRules(createCcSdkVariantRules()...)
AddNeverAllowRules(createUncompressDexRules()...)
+ AddNeverAllowRules(createMakefileGoalRules()...)
}
// Add a NeverAllow rule to the set of rules to apply.
@@ -231,6 +232,15 @@
}
}
+func createMakefileGoalRules() []Rule {
+ return []Rule{
+ NeverAllow().
+ ModuleType("makefile_goal").
+ WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
+ Because("Only boot images may be imported as a makefile goal."),
+ }
+}
+
func neverallowMutator(ctx BottomUpMutatorContext) {
m, ok := ctx.Module().(Module)
if !ok {
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 45d36a6..56a07dc 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -326,6 +326,20 @@
"module \"outside_art_libraries\": violates neverallow",
},
},
+ {
+ name: "disallowed makefile_goal",
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ makefile_goal {
+ name: "foo",
+ product_out_path: "boot/trap.img"
+ }
+ `),
+ },
+ expectedErrors: []string{
+ "Only boot images may be imported as a makefile goal.",
+ },
+ },
}
func TestNeverallow(t *testing.T) {
@@ -350,6 +364,7 @@
ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
+ ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule)
ctx.PostDepsMutators(RegisterNeverallowMutator)
ctx.Register(config)
@@ -438,3 +453,22 @@
func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
+
+type mockMakefileGoalProperties struct {
+ Product_out_path *string
+}
+
+type mockMakefileGoalModule struct {
+ ModuleBase
+ properties mockMakefileGoalProperties
+}
+
+func newMockMakefileGoalModule() Module {
+ m := &mockMakefileGoalModule{}
+ m.AddProperties(&m.properties)
+ InitAndroidModule(m)
+ return m
+}
+
+func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) {
+}
diff --git a/apex/apex.go b/apex/apex.go
index f9c902c..9905b79 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -704,7 +704,7 @@
if !ok || !am.CanHaveApexVariants() {
return false
}
- if !parent.(android.DepIsInSameApex).DepIsInSameApex(mctx, child) && !inAnySdk(child) {
+ if !parent.(android.DepIsInSameApex).DepIsInSameApex(mctx, child) {
return false
}
if excludeVndkLibs {
@@ -2162,10 +2162,7 @@
return false
}
if cc.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && cc.IsVndk() {
- // For vendor APEX with use_vndk_as_stable: true, we don't include VNDK libs
- // and use them from VNDK APEX.
- // TODO(b/159576928): add "vndk" as requiredDeps so that linkerconfig can make "vndk"
- // linker namespace avaiable to this apex.
+ requireNativeLibs = append(requireNativeLibs, ":vndk")
return false
}
af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7db61d5..0959a49 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2201,6 +2201,10 @@
data.Custom(&builder, name, prefix, "", data)
androidMk := builder.String()
ensureContains(t, androidMk, `LOCAL_MODULE_PATH := /tmp/target/product/test_device/vendor/apex`)
+
+ apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+ requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
+ ensureListNotContains(t, requireNativeLibs, ":vndk")
}
func TestVendorApex_use_vndk_as_stable(t *testing.T) {
@@ -2250,6 +2254,10 @@
"bin/mybin",
"lib64/libvendor.so",
})
+
+ apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+ requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
+ ensureListContains(t, requireNativeLibs, ":vndk")
}
func TestAndroidMk_UseVendorRequired(t *testing.T) {
diff --git a/cc/cc.go b/cc/cc.go
index 57fe9ba..962da4c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3034,7 +3034,7 @@
var _ android.ImageInterface = (*Module)(nil)
func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
- // Sanity check
+ // Validation check
vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
productSpecific := mctx.ProductSpecific()
diff --git a/cc/vndk.go b/cc/vndk.go
index 15843c6..f9adec7 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -340,7 +340,7 @@
}
}
-// Sanity check for modules that mustn't be VNDK
+// Check for modules that mustn't be VNDK
func shouldSkipVndkMutator(m *Module) bool {
if !m.Enabled() {
return true
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index a95aca9..274c8ee 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -429,7 +429,7 @@
if maxOpenZips < 3 {
panic(fmt.Errorf("open zips limit should be above 3"))
}
- // In the dummy element .older points to the most recently opened InputZip, and .newer points to the oldest.
+ // In the fake element .older points to the most recently opened InputZip, and .newer points to the oldest.
head := new(ManagedInputZip)
head.older = head
head.newer = head
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index e485c60..69e4f69 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -35,14 +35,14 @@
// A command represents an operation to be executed in the soong build
// system.
type command struct {
- // the flag name (must have double dashes)
+ // The flag name (must have double dashes).
flag string
- // description for the flag (to display when running help)
+ // Description for the flag (to display when running help).
description string
- // Forces the status output into dumb terminal mode.
- forceDumbOutput bool
+ // Stream the build status output into the simple terminal mode.
+ simpleOutput bool
// Sets a prefix string to use for filenames of log files.
logsPrefix string
@@ -70,21 +70,21 @@
stdio: stdio,
run: make,
}, {
- flag: "--dumpvar-mode",
- description: "print the value of the legacy make variable VAR to stdout",
- forceDumbOutput: true,
- logsPrefix: "dumpvars-",
- config: dumpVarConfig,
- stdio: customStdio,
- run: dumpVar,
+ flag: "--dumpvar-mode",
+ description: "print the value of the legacy make variable VAR to stdout",
+ simpleOutput: true,
+ logsPrefix: "dumpvars-",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVar,
}, {
- flag: "--dumpvars-mode",
- description: "dump the values of one or more legacy make variables, in shell syntax",
- forceDumbOutput: true,
- logsPrefix: "dumpvars-",
- config: dumpVarConfig,
- stdio: customStdio,
- run: dumpVars,
+ flag: "--dumpvars-mode",
+ description: "dump the values of one or more legacy make variables, in shell syntax",
+ simpleOutput: true,
+ logsPrefix: "dumpvars-",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVars,
}, {
flag: "--build-mode",
description: "build modules based on the specified build action",
@@ -125,7 +125,7 @@
os.Exit(1)
}
- output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.forceDumbOutput,
+ output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.simpleOutput,
build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
log := logger.New(output)
@@ -172,7 +172,7 @@
buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
- defer build.UploadMetrics(buildCtx, config, c.forceDumbOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
+ defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
os.MkdirAll(logsDir, 0777)
log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index bff591c..7afba2a 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -208,7 +208,7 @@
}
// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
-// the greylists.
+// the unsupported API.
func flagsRule(ctx android.SingletonContext) android.Path {
var flagsCSV android.Paths
var greylistRemovedApis android.Paths
@@ -247,18 +247,18 @@
Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")).
FlagWithInput("--csv ", stubFlags).
Inputs(flagsCSV).
- FlagWithInput("--greylist ",
+ FlagWithInput("--unsupported ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")).
- FlagWithInput("--greylist-ignore-conflicts ", combinedRemovedApis).
- FlagWithInput("--greylist-max-q ",
+ FlagWithInput("--unsupported-ignore-conflicts ", combinedRemovedApis).
+ FlagWithInput("--max-target-q ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-q.txt")).
- FlagWithInput("--greylist-max-p ",
+ FlagWithInput("--max-target-p ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt")).
- FlagWithInput("--greylist-max-o-ignore-conflicts ",
+ FlagWithInput("--max-target-o-ignore-conflicts ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt")).
- FlagWithInput("--blacklist ",
+ FlagWithInput("--blocked ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt")).
- FlagWithInput("--greylist-packages ",
+ FlagWithInput("--unsupported-packages ",
android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-packages.txt")).
FlagWithOutput("--output ", tempPath)
diff --git a/java/java_test.go b/java/java_test.go
index 73e6792..582ebe9 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -489,7 +489,7 @@
ctx, _ := testJavaWithConfig(t, config)
- // first, sanity check that the -g flag is added to target modules
+ // first, check that the -g flag is added to target modules
targetLibrary := ctx.ModuleForTests("target_library", "android_common")
targetJavaFlags := targetLibrary.Module().VariablesForTests()["javacFlags"]
if !strings.Contains(targetJavaFlags, "-g:source,lines") {
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index a2198e9..931ca3c 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -204,8 +204,8 @@
}
`)
- sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output
- sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output
+ sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common").Rule("combineJar").Output
+ sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common").Rule("combineJar").Output
javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_myapex")
javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_myapex2")
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 3e76008..7591020 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -406,13 +406,17 @@
// Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its
// descendants
func sdkDepsMutator(mctx android.TopDownMutatorContext) {
- if m, ok := mctx.Module().(android.SdkAware); ok {
+ if parent, ok := mctx.Module().(interface {
+ android.DepIsInSameApex
+ android.RequiredSdks
+ }); ok {
// Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks()
// by reading its own properties like `uses_sdks`.
- requiredSdks := m.RequiredSdks()
+ requiredSdks := parent.RequiredSdks()
if len(requiredSdks) > 0 {
mctx.VisitDirectDeps(func(m android.Module) {
- if dep, ok := m.(android.SdkAware); ok {
+ // Only propagate required sdks from the apex onto its contents.
+ if dep, ok := m.(android.SdkAware); ok && parent.DepIsInSameApex(mctx, dep) {
dep.BuildWithSdks(requiredSdks)
}
})
@@ -423,15 +427,28 @@
// Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the
// versioned module is used instead of the un-versioned (in-development) module libfoo
func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) {
- if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
- if sdk := m.ContainingSdk(); !sdk.Unversioned() {
- if m.RequiredSdks().Contains(sdk) {
- // Note that this replacement is done only for the modules that have the same
- // variations as the current module. Since current module is already mutated for
- // apex references in other APEXes are not affected by this replacement.
- memberName := m.MemberName()
- mctx.ReplaceDependencies(memberName)
- }
+ if versionedSdkMember, ok := mctx.Module().(android.SdkAware); ok && versionedSdkMember.IsInAnySdk() {
+ if sdk := versionedSdkMember.ContainingSdk(); !sdk.Unversioned() {
+ // Only replace dependencies to <sdkmember> with <sdkmember@required-version>
+ // if the depending module requires it. e.g.
+ // foo -> sdkmember
+ // will be transformed to:
+ // foo -> sdkmember@1
+ // if and only if foo is a member of an APEX that requires version 1 of the
+ // sdk containing sdkmember.
+ memberName := versionedSdkMember.MemberName()
+
+ // Replace dependencies on sdkmember with a dependency on the current module which
+ // is a versioned prebuilt of the sdkmember if required.
+ mctx.ReplaceDependenciesIf(memberName, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
+ // from - foo
+ // to - sdkmember
+ replace := false
+ if parent, ok := from.(android.RequiredSdks); ok {
+ replace = parent.RequiredSdks().Contains(sdk)
+ }
+ return replace
+ })
}
}
}
diff --git a/ui/build/config.go b/ui/build/config.go
index ba477e6..3fa0479 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -96,7 +96,7 @@
environ: OsEnvironment(),
}
- // Sane default matching ninja
+ // Default matching ninja
ret.parallel = runtime.NumCPU() + 2
ret.keepGoing = 1
diff --git a/ui/build/upload.go b/ui/build/upload.go
index 1cc2e94..a9346e0 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -44,7 +44,7 @@
// environment variable. The metrics files are copied to a temporary directory
// and the uploader is then executed in the background to allow the user to continue
// working.
-func UploadMetrics(ctx Context, config Config, forceDumbOutput bool, buildStarted time.Time, files ...string) {
+func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, files ...string) {
ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
defer ctx.EndTrace()
@@ -105,7 +105,7 @@
// Start the uploader in the background as it takes several milliseconds to start the uploader
// and prepare the metrics for upload. This affects small commands like "lunch".
cmd := Command(ctx, config, "upload metrics", uploader, "--upload-metrics", pbFile)
- if forceDumbOutput {
+ if simpleOutput {
cmd.RunOrFatal()
} else {
cmd.RunAndStreamOrFatal()
diff --git a/ui/terminal/Android.bp b/ui/terminal/Android.bp
index b533b0d..aa6e35d 100644
--- a/ui/terminal/Android.bp
+++ b/ui/terminal/Android.bp
@@ -17,7 +17,7 @@
pkgPath: "android/soong/ui/terminal",
deps: ["soong-ui-status"],
srcs: [
- "dumb_status.go",
+ "simple_status.go",
"format.go",
"smart_status.go",
"status.go",
diff --git a/ui/terminal/dumb_status.go b/ui/terminal/simple_status.go
similarity index 70%
rename from ui/terminal/dumb_status.go
rename to ui/terminal/simple_status.go
index 201770f..4e8c568 100644
--- a/ui/terminal/dumb_status.go
+++ b/ui/terminal/simple_status.go
@@ -21,31 +21,31 @@
"android/soong/ui/status"
)
-type dumbStatusOutput struct {
+type simpleStatusOutput struct {
writer io.Writer
formatter formatter
}
-// NewDumbStatusOutput returns a StatusOutput that represents the
+// NewSimpleStatusOutput returns a StatusOutput that represents the
// current build status similarly to Ninja's built-in terminal
// output.
-func NewDumbStatusOutput(w io.Writer, formatter formatter) status.StatusOutput {
- return &dumbStatusOutput{
+func NewSimpleStatusOutput(w io.Writer, formatter formatter) status.StatusOutput {
+ return &simpleStatusOutput{
writer: w,
formatter: formatter,
}
}
-func (s *dumbStatusOutput) Message(level status.MsgLevel, message string) {
+func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) {
if level >= status.StatusLvl {
fmt.Fprintln(s.writer, s.formatter.message(level, message))
}
}
-func (s *dumbStatusOutput) StartAction(action *status.Action, counts status.Counts) {
+func (s *simpleStatusOutput) StartAction(action *status.Action, counts status.Counts) {
}
-func (s *dumbStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
+func (s *simpleStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
str := result.Description
if str == "" {
str = result.Command
@@ -63,9 +63,9 @@
}
}
-func (s *dumbStatusOutput) Flush() {}
+func (s *simpleStatusOutput) Flush() {}
-func (s *dumbStatusOutput) Write(p []byte) (int, error) {
+func (s *simpleStatusOutput) Write(p []byte) (int, error) {
fmt.Fprint(s.writer, string(p))
return len(p), nil
}
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index 60dfc70..d8e7392 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -26,12 +26,12 @@
//
// statusFormat takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported.
-func NewStatusOutput(w io.Writer, statusFormat string, forceDumbOutput, quietBuild bool) status.StatusOutput {
+func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild bool) status.StatusOutput {
formatter := newFormatter(statusFormat, quietBuild)
- if !forceDumbOutput && isSmartTerminal(w) {
+ if !forceSimpleOutput && isSmartTerminal(w) {
return NewSmartStatusOutput(w, formatter)
} else {
- return NewDumbStatusOutput(w, formatter)
+ return NewSimpleStatusOutput(w, formatter)
}
}
diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go
index 9f60829..aa69dff 100644
--- a/ui/terminal/status_test.go
+++ b/ui/terminal/status_test.go
@@ -26,64 +26,64 @@
func TestStatusOutput(t *testing.T) {
tests := []struct {
- name string
- calls func(stat status.StatusOutput)
- smart string
- dumb string
+ name string
+ calls func(stat status.StatusOutput)
+ smart string
+ simple string
}{
{
- name: "two actions",
- calls: twoActions,
- smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
- dumb: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
+ name: "two actions",
+ calls: twoActions,
+ smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+ simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
},
{
- name: "two parallel actions",
- calls: twoParallelActions,
- smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
- dumb: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
+ name: "two parallel actions",
+ calls: twoParallelActions,
+ smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+ simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
},
{
- name: "action with output",
- calls: actionsWithOutput,
- smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
- dumb: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
+ name: "action with output",
+ calls: actionsWithOutput,
+ smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+ simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
},
{
- name: "action with output without newline",
- calls: actionsWithOutputWithoutNewline,
- smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
- dumb: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
+ name: "action with output without newline",
+ calls: actionsWithOutputWithoutNewline,
+ smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+ simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
},
{
- name: "action with error",
- calls: actionsWithError,
- smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
- dumb: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n",
+ name: "action with error",
+ calls: actionsWithError,
+ smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+ simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n",
},
{
- name: "action with empty description",
- calls: actionWithEmptyDescription,
- smart: "\r\x1b[1m[ 0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n",
- dumb: "[100% 1/1] command1\n",
+ name: "action with empty description",
+ calls: actionWithEmptyDescription,
+ smart: "\r\x1b[1m[ 0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n",
+ simple: "[100% 1/1] command1\n",
},
{
- name: "messages",
- calls: actionsWithMessages,
- smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
- dumb: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n",
+ name: "messages",
+ calls: actionsWithMessages,
+ smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+ simple: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n",
},
{
- name: "action with long description",
- calls: actionWithLongDescription,
- smart: "\r\x1b[1m[ 0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n",
- dumb: "[ 50% 1/2] action with very long description to test eliding\n",
+ name: "action with long description",
+ calls: actionWithLongDescription,
+ smart: "\r\x1b[1m[ 0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n",
+ simple: "[ 50% 1/2] action with very long description to test eliding\n",
},
{
- name: "action with output with ansi codes",
- calls: actionWithOuptutWithAnsiCodes,
- smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n",
- dumb: "[100% 1/1] action1\ncolor\n",
+ name: "action with output with ansi codes",
+ calls: actionWithOuptutWithAnsiCodes,
+ smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n",
+ simple: "[100% 1/1] action1\ncolor\n",
},
}
@@ -103,24 +103,24 @@
}
})
- t.Run("dumb", func(t *testing.T) {
- dumb := &bytes.Buffer{}
- stat := NewStatusOutput(dumb, "", false, false)
+ t.Run("simple", func(t *testing.T) {
+ simple := &bytes.Buffer{}
+ stat := NewStatusOutput(simple, "", false, false)
tt.calls(stat)
stat.Flush()
- if g, w := dumb.String(), tt.dumb; g != w {
+ if g, w := simple.String(), tt.simple; g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g)
}
})
- t.Run("force dumb", func(t *testing.T) {
+ t.Run("force simple", func(t *testing.T) {
smart := &fakeSmartTerminal{termWidth: 40}
stat := NewStatusOutput(smart, "", true, false)
tt.calls(stat)
stat.Flush()
- if g, w := smart.String(), tt.dumb; g != w {
+ if g, w := smart.String(), tt.simple; g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g)
}
})