func (tp *taskPlugin) Finished(success bool) error {
	file, err := tp.context.ExtractLog()
	if err != nil {
		return err
	}
	defer file.Close()

	tempFile, err := tp.environment.TemporaryStorage.NewFile()
	if err != nil {
		return err
	}

	defer tempFile.Close()

	zip := gzip.NewWriter(tempFile)
	if _, err = io.Copy(zip, file); err != nil {
		return err
	}

	if err = zip.Close(); err != nil {
		return err
	}

	_, err = tempFile.Seek(0, 0)
	if err != nil {
		return err
	}

	err = runtime.UploadS3Artifact(runtime.S3Artifact{
		Name:     "public/logs/live_backing.log",
		Mimetype: "text/plain",
		Expires:  tp.context.TaskInfo.Expires,
		Stream:   tempFile,
		AdditionalHeaders: map[string]string{
			"Content-Encoding": "gzip",
		},
	}, tp.context)

	if err != nil {
		return err
	}

	backingURL := fmt.Sprintf("https://queue.taskcluster.net/v1/task/%s/runs/%d/artifacts/public/logs/live_backing.log", tp.context.TaskInfo.TaskID, tp.context.TaskInfo.RunID)
	err = runtime.CreateRedirectArtifact(runtime.RedirectArtifact{
		Name:     "public/logs/live.log",
		Mimetype: "text/plain",
		URL:      backingURL,
		Expires:  tp.context.TaskInfo.Expires,
	}, tp.context)
	if err != nil {
		tp.log.Error(err)
		return err
	}

	return nil
}
func (s *sandbox) uploadArtifacts() error {
	folder := filepath.Join(s.folder.Path(), artifactFolder)
	return filepath.Walk(folder, func(p string, info os.FileInfo, err error) error {
		// Abort if there is an error
		if err != nil {
			return err
		}

		// Skip folders
		if info.IsDir() {
			return nil
		}

		// Guess mimetype
		mimeType := mime.TypeByExtension(filepath.Ext(p))
		if mimeType == "" {
			// application/octet-stream is the mime type for "unknown"
			mimeType = "application/octet-stream"
		}

		// Open file
		f, err := os.Open(p)
		if err != nil {
			return err
		}

		// Find filename
		name, _ := filepath.Rel(folder, p)

		// Ensure expiration is no later than task.expires
		expires := time.Now().Add(time.Duration(s.engine.config.Expiration) * 24 * time.Hour)
		if time.Time(s.context.Expires).Before(expires) {
			expires = time.Time(s.context.Expires)
		}

		// Upload artifact
		err = runtime.UploadS3Artifact(runtime.S3Artifact{
			Name:     filepath.ToSlash(name),
			Mimetype: mimeType,
			Expires:  tcclient.Time(expires),
			Stream:   f,
		}, s.context)

		// Ensure that we close the file
		cerr := f.Close()

		// Return first error, if any
		if err != nil {
			err = cerr
		}
		return err
	})
}
func (tp taskPlugin) attemptUpload(fileReader ioext.ReadSeekCloser, path string, name string, expires time.Time) error {
	mimeType := mime.TypeByExtension(filepath.Ext(path))
	if mimeType == "" {
		// application/octet-stream is the mime type for "unknown"
		mimeType = "application/octet-stream"
	}
	return runtime.UploadS3Artifact(runtime.S3Artifact{
		Name:     name,
		Mimetype: mimeType,
		Stream:   fileReader,
		Expires:  tcclient.Time(expires),
	}, tp.context)
}
func (p *taskPlugin) createSocketsFile() error {
	debug("Uploading sockets.json")
	// Create sockets.json
	sockets := map[string]interface{}{
		"version": 2,
	}
	if p.shellURL != "" {
		sockets["shellSocketUrl"] = p.shellURL
	}
	if p.displaysURL != "" {
		sockets["displaysUrl"] = p.displaysURL
	}
	if p.displaySocketURL != "" {
		sockets["displaySocketUrl"] = p.displaySocketURL
	}
	data, _ := json.MarshalIndent(sockets, "", "  ")
	return runtime.UploadS3Artifact(runtime.S3Artifact{
		Name:     p.opts.ArtifactPrefix + "sockets.json",
		Mimetype: "application/json",
		Expires:  p.context.TaskInfo.Deadline,
		Stream:   ioext.NopCloser(bytes.NewReader(data)),
	}, p.context)
}