Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/compozify.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ compozify is a tool mainly for converting docker run commands to docker compose

### SEE ALSO

* [compozify add-service](compozify_add-service.md) - Add a service to an existing docker-compose file
* [compozify convert](compozify_convert.md) - convert docker run command to docker compose file

56 changes: 56 additions & 0 deletions docs/compozify_add-service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
## compozify add-service

Add a service to an existing docker-compose file

### Synopsis

Converts the docker run command to docker compose and adds as a new service to an existing docker-compose file.
If no file is specified, compozify will look for a docker compose file in the current directory.
If no file is found, compozify will create one in the current directory.
Expected file names are docker-compose.[yml,yaml], compose.[yml,yaml]


```
compozify add-service [flags] DOCKER_RUN_COMMAND
```

### Examples

```

# add service to existing docker-compose file in current directory
$ compozify add-service "docker run -i -t --rm alpine"

# add service to existing docker-compose file
$ compozify add-service -f /path/to/docker-compose.yml "docker run -i -t --rm alpine"

# write to file
$ compozify add-service -w -f /path/to/docker-compose.yml "docker run -i -t --rm alpine"

# alternative usage specifying beginning of docker run command without quotes
$ compozify add-service -w -f /path/to/docker-compose.yml -- docker run -i -t --rm alpine

# add service with custom name
$ compozify add-service -w -f /path/to/docker-compose.yml -n my-service "docker run -i -t --rm alpine"

```

### Options

```
-f, --file string Compose file path
-h, --help help for add-service
-n, --service-name string Name of the service
-w, --write write to file
```

### Options inherited from parent commands

```
-v, --verbose verbose output
```

### SEE ALSO

* [compozify](compozify.md) - compozify is a tool mainly for converting docker run commands to docker compose files

7 changes: 4 additions & 3 deletions docs/compozify_convert.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ $ compozify convert -w -- docker run -i -t --rm alpine
### Options

```
-h, --help help for convert
-o, --out string output file path (default "compose.yml")
-w, --write write to file
-a, --append-service append service to existing compose file. Requires --out flag
-h, --help help for convert
-o, --out string output file path (default "compose.yml")
-w, --write write to file
```

### Options inherited from parent commands
Expand Down
112 changes: 112 additions & 0 deletions internal/commands/add-service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package commands

import (
"os"

"github.com/rs/zerolog"
"github.com/spf13/cobra"

"github.com/profclems/compozify/pkg/parser"
)

type addServiceOpts struct {
Logger *zerolog.Logger

File string
Command string
Write bool
ServiceName string
}

func newAddServiceCmd(logger *zerolog.Logger) *cobra.Command {
opts := addServiceOpts{
Logger: logger,
}
cmd := &cobra.Command{
Use: "add-service [flags] DOCKER_RUN_COMMAND",
Short: "Add a service to an existing docker-compose file",
Long: `Converts the docker run command to docker compose and adds as a new service to an existing docker-compose file.
If no file is specified, compozify will look for a docker compose file in the current directory.
If no file is found, compozify will create one in the current directory.
Expected file names are docker-compose.[yml,yaml], compose.[yml,yaml]
`,
Example: `
# add service to existing docker-compose file in current directory
$ compozify add-service "docker run -i -t --rm alpine"

# add service to existing docker-compose file
$ compozify add-service -f /path/to/docker-compose.yml "docker run -i -t --rm alpine"

# write to file
$ compozify add-service -w -f /path/to/docker-compose.yml "docker run -i -t --rm alpine"

# alternative usage specifying beginning of docker run command without quotes
$ compozify add-service -w -f /path/to/docker-compose.yml -- docker run -i -t --rm alpine

# add service with custom name
$ compozify add-service -w -f /path/to/docker-compose.yml -n my-service "docker run -i -t --rm alpine"
`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return cmd.Help()
}
opts.Command = args[0]

return addServiceRun(&opts)
},
}

cmd.Flags().StringVarP(&opts.ServiceName, "service-name", "n", "", "Name of the service")
cmd.Flags().BoolVarP(&opts.Write, "write", "w", false, "write to file")
cmd.Flags().StringVarP(&opts.File, "file", "f", "", "Compose file path")

return cmd
}

func addServiceRun(opts *addServiceOpts) error {
readFile := opts.File != ""
if opts.File == "" {
opts.Logger.Info().Msg("No compose file specified. Searching for compose file in current directory")
expectedFiles := []string{"docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"}

for _, file := range expectedFiles {
if _, err := os.Stat(file); err == nil {
opts.File = file
opts.Logger.Info().Msgf("Found compose file: %s", file)
break
}
}

if opts.File == "" {
opts.Logger.Warn().Msg("No compose file found. Specify with --file or -f flag")
opts.File = defaultFilename
readFile = false
}
}

var b []byte
var err error

if readFile {
b, err = os.ReadFile(opts.File)
if err != nil {
return err
}
}

p, err := parser.AppendToYAML(b, opts.Command)
if err != nil {
return err
}

if opts.ServiceName != "" {
p.SetServiceName(opts.ServiceName)
}

err = p.Parse()
if err != nil {
return err
}

return printOutput(p, opts.Logger, opts.Write, opts.File)
}
31 changes: 31 additions & 0 deletions internal/commands/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package commands

import (
"fmt"
"os"

"github.com/rs/zerolog"

"github.com/profclems/compozify/pkg/parser"
)

func printOutput(parser *parser.Parser, log *zerolog.Logger, writeToFile bool, path string) error {
writer := os.Stdout
var err error
if writeToFile {
log.Info().Msgf("Writing to file %s", path)
writer, err = os.Create(path)
if err != nil {
return err
}
defer func(writer *os.File) {
e := writer.Close()
if e != nil {
log.Error().Err(e).Msg("Error closing file")
}
err = e
}(writer)
}
_, err = fmt.Fprintf(writer, "%s", parser.String())
return err
}
46 changes: 22 additions & 24 deletions internal/commands/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package commands

import (
"fmt"
"os"
"strings"

"github.com/rs/zerolog"
Expand All @@ -14,9 +13,10 @@ import (
var defaultFilename = "compose.yml"

type convertOpts struct {
Command string
Write bool
OutFilePath string
Command string
OutFilePath string
Write bool
AppendService bool

Logger *zerolog.Logger
}
Expand Down Expand Up @@ -53,11 +53,16 @@ $ compozify convert -w -- docker run -i -t --rm alpine
opts.Command = strings.Join(args, " ")
}

if opts.AppendService && opts.OutFilePath == "" {
return fmt.Errorf("--append-service requires --out flag")
}

return convertRun(&opts)
},
Args: cobra.MinimumNArgs(1),
}

cmd.Flags().BoolVarP(&opts.AppendService, "append-service", "a", false, "append service to existing compose file. Requires --out flag")
cmd.Flags().BoolVarP(&opts.Write, "write", "w", false, "write to file")
cmd.Flags().StringVarP(&opts.OutFilePath, "out", "o", defaultFilename, "output file path")

Expand All @@ -70,34 +75,27 @@ func convertRun(opts *convertOpts) (err error) {
log.Info().Msg("Parsing Docker run command")
log.Debug().Msgf("Docker run command: %s", opts.Command)

parser, err := parser.New(opts.Command)
if opts.AppendService {
log.Info().Msg("Appending service to existing compose file")
return addServiceRun(&addServiceOpts{
Logger: log,
File: opts.OutFilePath,
Command: opts.Command,
Write: opts.Write,
})
}

p, err := parser.New(opts.Command)
if err != nil {
return err
}

log.Info().Msg("Generating Docker compose file")
err = parser.Parse()
err = p.Parse()
if err != nil {
return err
}
log.Info().Msg("Docker compose file generated")

writer := os.Stdout
if opts.Write {
log.Info().Msgf("Writing to file %s", opts.OutFilePath)
writer, err = os.Create(opts.OutFilePath)
if err != nil {
return err
}
defer func(writer *os.File) {
e := writer.Close()
if e != nil {
log.Error().Err(e).Msg("Error closing file")
}
err = e
}(writer)
}
fmt.Fprintf(writer, "%s", parser.String())

return err
return printOutput(p, log, opts.Write, opts.OutFilePath)
}
1 change: 1 addition & 0 deletions internal/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func NewRootCmd(logger *zerolog.Logger, version version.Info) *cobra.Command {
cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", version.IsDev(), "verbose output")

cmd.AddCommand(newConvertCmd(logger))
cmd.AddCommand(newAddServiceCmd(logger))

return cmd
}
3 changes: 3 additions & 0 deletions pkg/parser/argv.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (
// (same as most other *nix shells do). This is secure in the sense that it doesn't do any
// executing or interpeting.
func parseArgs(str string) ([]string, error) {
if str == "" {
return []string{}, nil
}
var m []string
var s string

Expand Down
Loading