Skip to content

Commit

Permalink
feat: basic uninstall support
Browse files Browse the repository at this point in the history
Fixes #11
  • Loading branch information
agaffney committed Feb 21, 2024
1 parent 3836326 commit 55f8a97
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 4 deletions.
1 change: 1 addition & 0 deletions cmd/cardano-up/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func installCommand() *cobra.Command {
slog.Error(fmt.Sprintf("no such package: %s", args[0]))
os.Exit(1)
}
slog.Info(fmt.Sprintf("Successfully installed package %s", args[0]))
},
}
}
1 change: 1 addition & 0 deletions cmd/cardano-up/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func main() {
versionCommand(),
listAvailableCommand(),
installCommand(),
uninstallCommand(),
)

if err := rootCmd.Execute(); err != nil {
Expand Down
63 changes: 63 additions & 0 deletions cmd/cardano-up/uninstall.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2024 Blink Labs Software
//
// 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 main

import (
"fmt"
"log/slog"
"os"

"github.com/blinklabs-io/cardano-up/pkgmgr"
"github.com/spf13/cobra"
)

func uninstallCommand() *cobra.Command {
return &cobra.Command{
Use: "uninstall",
Short: "Uninstall package",
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
slog.Error("no package provided")
os.Exit(1)
}
if len(args) > 1 {
slog.Error("only one package may be specified a a time")
os.Exit(1)
}
pm, err := pkgmgr.NewDefaultPackageManager()
if err != nil {
slog.Error(fmt.Sprintf("failed to create package manager: %s", err))
os.Exit(1)
}
installedPackages := pm.InstalledPackages()
foundPackage := false
for _, tmpPackage := range installedPackages {
if tmpPackage.Package.Name == args[0] {
foundPackage = true
if err := pm.Uninstall(tmpPackage); err != nil {
slog.Error(err.Error())
os.Exit(1)
}
break
}
}
if !foundPackage {
slog.Error(fmt.Sprintf("no such installed package: %s", args[0]))
os.Exit(1)
}
slog.Info(fmt.Sprintf("Successfully uninstalled package %s", args[0]))
},
}
}
10 changes: 9 additions & 1 deletion pkgmgr/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func (d *DockerService) Start() error {
if err != nil {
return err
}
d.logger.Debug(fmt.Sprintf("starting container %s", d.ContainerName))
if err := client.ContainerStart(
context.Background(),
d.ContainerId,
Expand All @@ -112,6 +113,7 @@ func (d *DockerService) Stop() error {
if err != nil {
return err
}
d.logger.Debug(fmt.Sprintf("stopping container %s", d.ContainerName))
stopTimeout := 60
if err := client.ContainerStop(
context.Background(),
Expand Down Expand Up @@ -148,6 +150,7 @@ func (d *DockerService) Create() error {
if err != nil {
return err
}
d.logger.Debug(fmt.Sprintf("creating container %s", d.ContainerName))
resp, err := client.ContainerCreate(
context.Background(),
&container.Config{
Expand Down Expand Up @@ -190,6 +193,7 @@ func (d *DockerService) Remove() error {
if err != nil {
return err
}
d.logger.Debug(fmt.Sprintf("removing container %s", d.ContainerName))
if err := client.ContainerRemove(
context.Background(),
d.ContainerId,
Expand All @@ -201,11 +205,11 @@ func (d *DockerService) Remove() error {
}

func (d *DockerService) pullImage() error {
d.logger.Info(fmt.Sprintf("pulling image %s", d.Image))
client, err := d.getClient()
if err != nil {
return err
}
d.logger.Debug(fmt.Sprintf("pulling image %s", d.Image))
out, err := client.ImagePull(context.Background(), d.Image, types.ImagePullOptions{})
if err != nil {
return err
Expand Down Expand Up @@ -264,6 +268,10 @@ func (d *DockerService) refresh() error {
d.Binds = tmpBinds[:]
var tmpPorts []string
for port, portBindings := range container.NetworkSettings.Ports {
// Skip exposed container ports without a mapping
if len(portBindings) == 0 {
continue
}
tmpPort := fmt.Sprintf(
"0.0.0.0:%s:%s",
portBindings[0].HostPort,
Expand Down
57 changes: 55 additions & 2 deletions pkgmgr/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ type Package struct {
InstallSteps []PackageInstallStep `yaml:"installSteps"`
}

func (p Package) install(cfg Config) error {
pkgName := fmt.Sprintf("%s-%s", p.Name, p.Version)
func (p Package) install(cfg Config, context string) error {
pkgName := fmt.Sprintf("%s-%s-%s", p.Name, p.Version, context)
for _, installStep := range p.InstallSteps {
// Make sure only one install method is specified per install step
if installStep.Docker != nil &&
Expand All @@ -51,6 +51,31 @@ func (p Package) install(cfg Config) error {
return nil
}

func (p Package) uninstall(cfg Config, context string) error {
pkgName := fmt.Sprintf("%s-%s-%s", p.Name, p.Version, context)
// Iterate over install steps in reverse
for idx := len(p.InstallSteps) - 1; idx >= 0; idx-- {
installStep := p.InstallSteps[idx]
// Make sure only one install method is specified per install step
if installStep.Docker != nil &&
installStep.File != nil {
return ErrMultipleInstallMethods
}
if installStep.Docker != nil {
if err := installStep.Docker.uninstall(cfg, pkgName); err != nil {
return err
}
} else if installStep.File != nil {
if err := installStep.File.uninstall(cfg, pkgName); err != nil {
return err
}
} else {
return ErrNoInstallMethods
}
}
return nil
}

type PackageInstallStep struct {
Docker *PackageInstallStepDocker `yaml:"docker,omitempty"`
File *PackageInstallStepFile `yaml:"file,omitempty"`
Expand Down Expand Up @@ -87,6 +112,23 @@ func (p *PackageInstallStepDocker) install(cfg Config, pkgName string) error {
return nil
}

func (p *PackageInstallStepDocker) uninstall(cfg Config, pkgName string) error {
containerName := fmt.Sprintf("%s-%s", pkgName, p.ContainerName)
svc, err := NewDockerServiceFromContainerName(containerName, cfg.Logger)
if err != nil {
return err
}
if running, _ := svc.Running(); running {
if err := svc.Stop(); err != nil {
return err
}
}
if err := svc.Remove(); err != nil {
return err
}
return nil
}

type PackageInstallStepFile struct {
Filename string `yaml:"filename"`
Content string `yaml:"content"`
Expand Down Expand Up @@ -116,3 +158,14 @@ func (p *PackageInstallStepFile) install(cfg Config, pkgName string) error {
cfg.Logger.Debug(fmt.Sprintf("wrote file %s", filePath))
return nil
}

func (p *PackageInstallStepFile) uninstall(cfg Config, pkgName string) error {
filePath := filepath.Join(
cfg.ConfigDir,
"data",
pkgName,
p.Filename,
)
cfg.Logger.Debug(fmt.Sprintf("deleting file %s", filePath))
return os.Remove(filePath)
}
27 changes: 26 additions & 1 deletion pkgmgr/pkgmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,12 @@ func (p *PackageManager) AvailablePackages() []Package {
return p.availablePackages[:]
}

func (p *PackageManager) InstalledPackages() []InstalledPackage {
return p.state.InstalledPackages
}

func (p *PackageManager) Install(pkg Package) error {
if err := pkg.install(p.config); err != nil {
if err := pkg.install(p.config, p.state.ActiveContext); err != nil {
return err
}
installedPkg := NewInstalledPackage(pkg, p.state.ActiveContext)
Expand All @@ -78,3 +82,24 @@ func (p *PackageManager) Install(pkg Package) error {
}
return nil
}

func (p *PackageManager) Uninstall(installedPkg InstalledPackage) error {
if err := installedPkg.Package.uninstall(p.config, installedPkg.Context); err != nil {
return err
}
// Remove package from installed packages
var tmpInstalledPackages []InstalledPackage
for _, tmpInstalledPkg := range p.state.InstalledPackages {
if tmpInstalledPkg.Context == installedPkg.Context &&
tmpInstalledPkg.Package.Name == installedPkg.Package.Name &&
tmpInstalledPkg.Package.Version == installedPkg.Package.Version {
continue
}
tmpInstalledPackages = append(tmpInstalledPackages, tmpInstalledPkg)
}
p.state.InstalledPackages = tmpInstalledPackages[:]
if err := p.state.Save(); err != nil {
return err
}
return nil
}

0 comments on commit 55f8a97

Please sign in to comment.