pulumi/pkg/backend/display/jsonmessage.go
CyrusNajmabadi 66bd3f4aa8
Breaking changes due to Feature 2.0 work
* Make `async:true` the default for `invoke` calls (#3750)

* Switch away from native grpc impl. (#3728)

* Remove usage of the 'deasync' library from @pulumi/pulumi. (#3752)

* Only retry as long as we get unavailable back.  Anything else continues. (#3769)

* Handle all errors for now. (#3781)


* Do not assume --yes was present when using pulumi in non-interactive mode (#3793)

* Upgrade all paths for sdk and pkg to v2

* Backport C# invoke classes and other recent gen changes (#4288)

Adjust C# generation

* Replace IDeployment with a sealed class (#4318)

Replace IDeployment with a sealed class

* .NET: default to args subtype rather than Args.Empty (#4320)

* Adding system namespace for Dotnet code gen

This is required for using Obsolute attributes for deprecations

```
Iam/InstanceProfile.cs(142,10): error CS0246: The type or namespace name 'ObsoleteAttribute' could not be found (are you missing a using directive or an assembly reference?) [/Users/stack72/code/go/src/github.com/pulumi/pulumi-aws/sdk/dotnet/Pulumi.Aws.csproj]
Iam/InstanceProfile.cs(142,10): error CS0246: The type or namespace name 'Obsolete' could not be found (are you missing a using directive or an assembly reference?) [/Users/stack72/code/go/src/github.com/pulumi/pulumi-aws/sdk/dotnet/Pulumi.Aws.csproj]
```

* Fix the nullability of config type properties in C# codegen (#4379)
2020-04-14 09:30:25 +01:00

165 lines
4.2 KiB
Go

// Copyright 2016-2018, Pulumi Corporation.
//
// 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 display
// forked from: https://github.com/moby/moby/blob/master/pkg/jsonmessage/jsonmessage.go
// so we can customize parts of the display of our progress messages
import (
"fmt"
"io"
"os"
gotty "github.com/ijc/Gotty"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
)
/* Satisfied by gotty.TermInfo as well as noTermInfo from below */
type termInfo interface {
Parse(attr string, params ...interface{}) (string, error)
}
type noTermInfo struct{} // canary used when no terminfo.
func (ti *noTermInfo) Parse(attr string, params ...interface{}) (string, error) {
return "", fmt.Errorf("noTermInfo")
}
func clearLine(out io.Writer, ti termInfo) {
// el2 (clear whole line) is not exposed by terminfo.
// First clear line from beginning to cursor
if attr, err := ti.Parse("el1"); err == nil {
fmt.Fprintf(out, "%s", attr)
} else {
fmt.Fprintf(out, "\x1b[1K")
}
// Then clear line from cursor to end
if attr, err := ti.Parse("el"); err == nil {
fmt.Fprintf(out, "%s", attr)
} else {
fmt.Fprintf(out, "\x1b[K")
}
}
func cursorUp(out io.Writer, ti termInfo, l int) {
if l == 0 { // Should never be the case, but be tolerant
return
}
if attr, err := ti.Parse("cuu", l); err == nil {
fmt.Fprintf(out, "%s", attr)
} else {
fmt.Fprintf(out, "\x1b[%dA", l)
}
}
func cursorDown(out io.Writer, ti termInfo, l int) {
if l == 0 { // Should never be the case, but be tolerant
return
}
if attr, err := ti.Parse("cud", l); err == nil {
fmt.Fprintf(out, "%s", attr)
} else {
fmt.Fprintf(out, "\x1b[%dB", l)
}
}
// Display displays the Progress to `out`. `termInfo` is non-nil if `out` is a terminal.
func (jm *Progress) Display(out io.Writer, termInfo termInfo) {
var endl string
if termInfo != nil && /*jm.Stream == "" &&*/ jm.Action != "" {
clearLine(out, termInfo)
endl = "\r"
fmt.Fprint(out, endl)
}
if jm.Action != "" && termInfo != nil {
fmt.Fprintf(out, "%s%s", jm.Action, endl)
} else {
var msg string
if jm.Action != "" {
msg = jm.Action
} else {
msg = jm.Message
}
fmt.Fprintf(out, "%s%s\n", msg, endl)
}
}
// ShowProgressOutput displays a progress stream from `in` to `out`, `isTerminal` describes if
// `out` is a terminal. If this is the case, it will print `\n` at the end of each line and move the
// cursor while displaying.
func ShowProgressOutput(in <-chan Progress, out io.Writer, isTerminal bool) {
var (
ids = make(map[string]int)
)
var info termInfo
if isTerminal {
term := os.Getenv("TERM")
if term == "" {
term = "vt102"
}
var err error
if info, err = gotty.OpenTermInfo(term); err != nil {
info = &noTermInfo{}
}
}
for jm := range in {
diff := 0
if jm.Action != "" {
if jm.ID == "" {
contract.Failf("Must have an ID if we have an action! %s", jm.Action)
}
line, ok := ids[jm.ID]
if !ok {
// NOTE: This approach of using len(id) to
// figure out the number of lines of history
// only works as long as we clear the history
// when we output something that's not
// accounted for in the map, such as a line
// with no ID.
line = len(ids)
ids[jm.ID] = line
if info != nil {
fmt.Fprintf(out, "\n")
}
}
diff = len(ids) - line
if info != nil {
cursorUp(out, info, diff)
}
} else {
// When outputting something that isn't progress
// output, clear the history of previous lines. We
// don't want progress entries from some previous
// operation to be updated (for example, pull -a
// with multiple tags).
ids = make(map[string]int)
}
jm.Display(out, info)
if jm.Action != "" && info != nil {
cursorDown(out, info, diff)
}
}
}