This message was deleted.
# golang
s
This message was deleted.
n
It is not recommended, but you can use
Copy code
// import "<http://github.com/pulumi/pulumi/sdk/v3/go/pulumi/internals|github.com/pulumi/pulumi/sdk/v3/go/pulumi/internals>"

result, _ := internals.UnsafeAwaitOutput(context.Background(), myPulumiOutput)
strValue := result.Value.(string)
if I'm not wrong
p
I'll try now @nice-guitar-7761, thank you very much!
b
yeah i wouldn’t do that. if you want to use a string, do something inside an
ApplyT
p
I tried using
ApplyT
although I keep getting empty strings
Copy code
bucketName := pulumi.String("")
        bucket.ID().ApplyT(func(id pulumi.ID) (string, error) {
            bucketName = pulumi.String(string(id))
            return "", nil
        })
n
Ah, that's probably because the input type of your function in the ApplyT should be a golang type and not a pulumi type there :)
i
@polite-sandwich-68547
ApplyT
doesn't run right away. It runs when the value becomes available, so trying to extract it like that will give you an empty string. The right way of doing this is:
Copy code
bucketName := bucket.ID().ApplyT(func(id pulumi.ID) (string, error) {
  return pulumi.String(string(id)), nil
}).(pulumi.StringOutput)
And then
bucketName
is a
StringOutput
, not
string
. Although for this specific case, you can convert an
IDOutput
(
bucket.ID()
) into a
StringOutput
with the
ToStringOutput()
method of `IDOutput`:
Copy code
bucketName := bucket.ID().ToStringOutput()
With bucketName as a StringOutput, you can pass it into, say
pulumi.Sprintf
to get back a formatted string output. For example:
Copy code
bucketName := bucket.ID().ToStringOutput()
msg := pulumi.Sprintf("Data stored in bucket %s", bucketName)
👍 1
p
func Sprintf(format string, args ...interface{}) StringOutput {
still returns a
StringOutput
though, when we need a
string
msg will be of type
StringOutput
i
Yeah, message will be a StringOutput.
p
we need
string
i
You can't/aren't supposed to break out of a StringOutput—the value isn't available yet. For example, for
bucket.ID()
above, when you run
pulumi preview
, the bucket doesn't have an ID because it hasn't been created yet, so the system can't give you an ID back. The IDOutput is a placeholder for a value that will become available in the future when this code runs for real (and even then, the ID won't be available right away because the operation doesn't run synchronously, but we can skip that detail for now). The idea is that you can feed this
Output
value as input to anything else, and among other things, their dependency relation will be established.
p
then I want to wait until the StringOutput and ready and then gather the string
thought that's what ApplyT is doing
b
you can only retrieve a string inside an
ApplyT
You can’t assign the result of an
ApplyT
to another value and use it elsewhere, because the value is only know inside the ApplyT
i
Sorry, can I ask a different question: Where are you writing this string?
p
oh that's good to know, means I can execute whatever I'm doing outside inside the ApplyT
sure, I'll show you what I'm doing: creating a bucket, waiting for it to be ready then using s3sync library to sync files to it
Copy code
syncManager := s3sync.New(sess)
	// Get the bucket name as a string using Apply
	bucketName, err := internals.UnsafeAwaitOutput(context.Background(), bucket.Bucket)
	if err != nil {
		return err
	}

	err = syncManager.Sync("../../build", fmt.Sprintf("<s3://%s>", bucketName.Value.(string)))
	if err != nil {
		return err
	}
I tried syncing using pulumi's s3.NewBucketObject, although it got messy pretty fast
i
Just a moment; I think we had something to assist here. I need to ask around about it.
b
p
what do you guys think if I put the syncManager code inside the ApplyT func?
i
Aha, that's it! Thanks, @billowy-army-68599.
If you put syncManager inside the ApplyT folder, it'll behave in unexpected ways. At minimum, it'll run twice: once during
preview
and once during
update
. You can verify this by trying to run
fmt.Println
inside the ApplyT function. Trying to have side-effects on the world from inside ApplyT breaks things, somewhat. Do consider the synced-folder package @billowy-army-68599 linked to above. The S3BucketFolderArgs takes a StringInput as argument, so you can feed bucket.ID into it directly. It'll treat every file in the folder as a separate resource, so it'll update files as needed.
p
hmm, could use a sync.Once object to avoid double runs
i
With syncedfolder, your original sample becomes:
Copy code
bucket := // ...

bucketName := bucket.ID().ToStringOutput()
syncedfolder.NewS3BucketFolder(ctx, "build", &synced.S3BucketFolderArgs{
  Path:       pulumi.String("../../build"),
  BucketName: bucketName,
  Acl: // ...
})
p
will definitely refactor using Synced folder, thank you for sharing guys!
loving pulumi more and more every day
❤️ 2