Skip to content

Commit

Permalink
feat: basic package install support
Browse files Browse the repository at this point in the history
Fixes #25
  • Loading branch information
agaffney committed Feb 18, 2024
1 parent 181ee32 commit 17c3301
Show file tree
Hide file tree
Showing 10 changed files with 281 additions and 37 deletions.
48 changes: 24 additions & 24 deletions cmd/cardano-up/test.go → cmd/cardano-up/install.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 Blink Labs Software
// 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.
Expand All @@ -20,41 +20,41 @@ import (
"os"

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

func testCommand() *cobra.Command {
func installCommand() *cobra.Command {
return &cobra.Command{
Use: "test",
Short: "Test subcommand for development work (TODO: remove me)",
Use: "install",
Short: "Install package",
Run: func(cmd *cobra.Command, args []string) {
pm, err := pkgmgr.NewDefaultPackageManager()
if err != nil {
slog.Error(fmt.Sprintf("failed to create package manager: %s", err))
os.Exit(1)
}
slog.Debug(fmt.Sprintf("pm = %#v", pm))
svc, err := service.NewDockerServiceFromContainerName("cadvisor", slog.Default())
if err != nil {
slog.Error(fmt.Sprintf("failed to get Docker service: %s", err))
if len(args) == 0 {
slog.Error("no package provided")
os.Exit(1)
}
slog.Debug(fmt.Sprintf("svc = %#v", svc))
if err := svc.Stop(); err != nil {
slog.Error(fmt.Sprintf("failed to stop service: %s", err))
if len(args) > 1 {
slog.Error("only one package may be specified a a time")
os.Exit(1)
}
if err := svc.Remove(); err != nil {
slog.Error(fmt.Sprintf("failed to remove service: %s", err))
pm, err := pkgmgr.NewDefaultPackageManager()
if err != nil {
slog.Error(fmt.Sprintf("failed to create package manager: %s", err))
os.Exit(1)
}
if err := svc.Create(); err != nil {
slog.Error(fmt.Sprintf("failed to create service: %s", err))
os.Exit(1)
packages := pm.AvailablePackages()
foundPackage := false
for _, tmpPackage := range packages {
if tmpPackage.Name == args[0] {
foundPackage = true
if err := pm.Install(tmpPackage); err != nil {
slog.Error(err.Error())
os.Exit(1)
}
break
}
}
if err := svc.Start(); err != nil {
slog.Error(fmt.Sprintf("failed to start service: %s", err))
if !foundPackage {
slog.Error(fmt.Sprintf("no such package: %s", args[0]))
os.Exit(1)
}
},
Expand Down
44 changes: 44 additions & 0 deletions cmd/cardano-up/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 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 listAvailableCommand() *cobra.Command {
return &cobra.Command{
Use: "list-available",
Short: "List available packages",
Run: func(cmd *cobra.Command, args []string) {
pm, err := pkgmgr.NewDefaultPackageManager()
if err != nil {
slog.Error(fmt.Sprintf("failed to create package manager: %s", err))
os.Exit(1)
}
packages := pm.AvailablePackages()
pkgOutput := "Available packages:\n\n"
for _, tmpPackage := range packages {
pkgOutput += fmt.Sprintf("%s (%s) %s\n", tmpPackage.Name, tmpPackage.Version, tmpPackage.Description)
}
slog.Info(pkgOutput)
},
}
}
4 changes: 2 additions & 2 deletions cmd/cardano-up/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ func main() {
// Add subcommands
rootCmd.AddCommand(
versionCommand(),
// TODO: remove me
testCommand(),
listAvailableCommand(),
installCommand(),
)

if err := rootCmd.Execute(); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/cardano-up/version.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 Blink Labs Software
// 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.
Expand Down
2 changes: 1 addition & 1 deletion internal/version/version.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 Blink Labs Software
// 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.
Expand Down
4 changes: 2 additions & 2 deletions pkgmgr/service/docker.go → pkgmgr/docker.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 Blink Labs Software
// 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.
Expand All @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package service
package pkgmgr

import (
"context"
Expand Down
30 changes: 30 additions & 0 deletions pkgmgr/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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 pkgmgr

import "errors"

// ErrOperationFailed is a placeholder error for operations that directly log errors.
// It's used to signify when an operation has failed when the actual error message is
// sent through the provided logger
var ErrOperationFailed = errors.New("the operation has failed")

// ErrMultipleInstallMethods is returned when a package's install steps specify more than one install method
// on a single install step
var ErrMultipleInstallMethods = errors.New("only one install method may be specified in an install step")

// ErrNoInstallMethods is returned when a package's install steps include an install step which has no
// recognized install method specified
var ErrNoInstallMethods = errors.New("no supported install method specified on install step")
118 changes: 118 additions & 0 deletions pkgmgr/package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// 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 pkgmgr

import (
"fmt"
"io/fs"
"os"
"path/filepath"
)

type Package struct {
Name string
Version string
Description string
InstallSteps []PackageInstallStep
}

func (p Package) install(cfg Config) error {
pkgName := fmt.Sprintf("%s-%s", p.Name, p.Version)
for _, installStep := range p.InstallSteps {
// 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.install(cfg, pkgName); err != nil {
return err
}
} else if installStep.File != nil {
if err := installStep.File.install(cfg, pkgName); err != nil {
return err
}
} else {
return ErrNoInstallMethods
}
}
return nil
}

type PackageInstallStep struct {
Docker *PackageInstallStepDocker
File *PackageInstallStepFile
}

type PackageInstallStepDocker struct {
ContainerName string
Image string
Env map[string]string
Command []string
Args []string
Binds []string
Ports []string
}

func (p *PackageInstallStepDocker) install(cfg Config, pkgName string) error {
containerName := fmt.Sprintf("%s-%s", pkgName, p.ContainerName)
svc := DockerService{
logger: cfg.Logger,
ContainerName: containerName,
Image: p.Image,
Env: p.Env,
Command: p.Command,
Args: p.Args,
Binds: p.Binds,
Ports: p.Ports,
}
if err := svc.Create(); err != nil {
return err
}
if err := svc.Start(); err != nil {
return err
}
return nil
}

type PackageInstallStepFile struct {
Filename string
Content string
Template bool
Mode fs.FileMode
}

func (p *PackageInstallStepFile) install(cfg Config, pkgName string) error {
// TODO: add templating support
filePath := filepath.Join(
cfg.ConfigDir,
"data",
pkgName,
p.Filename,
)
parentDir := filepath.Dir(filePath)
if err := os.MkdirAll(parentDir, fs.ModePerm); err != nil {
return err
}
fileMode := fs.ModePerm
if p.Mode > 0 {
fileMode = p.Mode
}
if err := os.WriteFile(filePath, []byte(p.Content), fileMode); err != nil {
return err
}
cfg.Logger.Debug(fmt.Sprintf("wrote file %s", filePath))
return nil
}
20 changes: 13 additions & 7 deletions pkgmgr/pkgmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,10 @@ import (
"fmt"
)

// ErrOperationFailed is a placeholder error for operations that directly log errors.
// It's used to signify when an operation has failed when the actual error message is
// sent through the provided logger
var ErrOperationFailed = errors.New("the operation has failed")

type PackageManager struct {
config Config
state *State
config Config
state *State
availablePackages []Package
// TODO
}

Expand Down Expand Up @@ -58,9 +54,19 @@ func (p *PackageManager) init() error {
if err := p.state.Load(); err != nil {
return fmt.Errorf("failed to load state: %s", err)
}
// TODO: replace this with syncing a repo and reading from disk
p.availablePackages = append(p.availablePackages, RegistryPackages...)
// TODO: remove me
if err := p.state.Save(); err != nil {
return err
}
return nil
}

func (p *PackageManager) AvailablePackages() []Package {
return p.availablePackages[:]
}

func (p *PackageManager) Install(pkg Package) error {
return pkg.install(p.config)
}
46 changes: 46 additions & 0 deletions pkgmgr/registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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 pkgmgr

var RegistryPackages = []Package{
{
Name: "cardano-node",
Version: "8.7.3",
Description: "Cardano node software by Input Output Global",
InstallSteps: []PackageInstallStep{
{
Docker: &PackageInstallStepDocker{
ContainerName: "cardano-node",
Image: "ghcr.io/blinklabs-io/cardano-node:8.7.3",
Env: map[string]string{
"NETWORK": "preview",
},
Ports: []string{
"3001:3001",
},
},
},
{
// TODO: turn this into a template
File: &PackageInstallStepFile{
Filename: "test-cardano-cli",
Content: `#!/bin/bash
docker exec -ti cardano-node-8.7.3-cardano-node cardano-cli $@
`,
},
},
},
},
}

0 comments on commit 17c3301

Please sign in to comment.