func (c *Composition) Decompose(dir string) (output string, err error) {
	var outputBytes []byte
	_, err = c.issueCommand([]string{"stop"}, dir)
	if err != nil {
		logger.Fatalf(err.Error())
	}
	outputBytes, err = c.issueCommand([]string{"rm", "-f"}, dir)
	containerErr := c.DockerHelper.RemoveContainersWithNamePrefix(c.ProjectName)
	if containerErr != nil {
		logger.Fatalf(containerErr.Error())
	}
	return string(outputBytes), err
}
Decompose decompose the composition.
Will also remove any containers with the same ProjectName prefix (eg. chaincode containers)
package dockerutil
import (
	"crypto/rand"
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"strings"
	docker "github.com/fsouza/go-dockerclient"
	"github.com/trustbloc/edge-core/pkg/log"
)
const dockerComposeCommand = "docker-compose"
var logger = log.New("bdd-test")
type Composition struct {
	DockerClient     *docker.Client
	APIContainers    []*docker.APIContainers
	ComposeFilesYaml string
	ProjectName      string
	Dir              string
	DockerHelper     DockerHelper
}
func NewComposition(projectName, composeFilesYaml, dir string) (composition *Composition, err error) {
	errRetFunc := func() error {
		return fmt.Errorf("error creating new composition '%s' using compose yaml '%s': %w",
			projectName, composeFilesYaml, err)
	}
	endpoint := "unix:///var/run/docker.sock"
	composition = &Composition{ComposeFilesYaml: composeFilesYaml, ProjectName: projectName, Dir: dir}
	if composition.DockerClient, err = docker.NewClient(endpoint); err != nil {
		return nil, errRetFunc()
	}
	if _, err = composition.issueCommand([]string{"up", "--force-recreate", "-d"}, dir); err != nil {
		return nil, errRetFunc()
	}
	composition.DockerHelper = NewDockerCmdlineHelper()
	return composition, nil
}
func parseComposeFilesArg(composeFileArgs string) []string {
	var args []string
	for _, f := range strings.Fields(composeFileArgs) {
		args = append(args, []string{"-f", f}...)
	}
	return args
}
func (c *Composition) getFileArgs() []string {
	return parseComposeFilesArg(c.ComposeFilesYaml)
}
func (c *Composition) GetContainerIDs(dir string) (containerIDs []string, err error) {
	var cmdOutput []byte
	if cmdOutput, err = c.issueCommand([]string{"ps", "-q"}, dir); err != nil {
		return nil, fmt.Errorf("error getting container IDs for project '%s': %w", c.ProjectName, err)
	}
	containerIDs = splitDockerCommandResults(string(cmdOutput))
	return containerIDs, err
}
func (c *Composition) refreshContainerList() (err error) {
	var thisProjectsContainers []docker.APIContainers
	if thisProjectsContainers, err = c.DockerClient.ListContainers(
		docker.ListContainersOptions{
			All:     true,
			Filters: map[string][]string{"name": {c.ProjectName}}}); err != nil {
		return fmt.Errorf("error refreshing container list for project '%s': %w", c.ProjectName, err)
	}
	c.APIContainers = make([]*docker.APIContainers, len(thisProjectsContainers))
	for i := 0; i < len(thisProjectsContainers); i++ {
		c.APIContainers[i] = &thisProjectsContainers[i]
	}
	return nil
}
func (c *Composition) issueCommand(args []string, dir string) (_ []byte, err error) {
	var cmdOut []byte
	errRetFunc := func() error {
		return fmt.Errorf("error issuing command to docker-compose with args '%s': %w (%s)", args, err, string(cmdOut))
	}
	var cmdArgs []string
	cmdArgs = append(cmdArgs, c.getFileArgs()...)
	cmdArgs = append(cmdArgs, args...)
	cmd := exec.Command(dockerComposeCommand, cmdArgs...)  
	cmd.Dir = dir
	if cmdOut, err = cmd.CombinedOutput(); err != nil {
		return cmdOut, errRetFunc()
	}
	if err = c.refreshContainerList(); err != nil {
		return nil, errRetFunc()
	}
	return cmdOut, err
}