diff --git a/internal/cli/kraft/kraft.go b/internal/cli/kraft/kraft.go index b74eace38..a6064c0f3 100644 --- a/internal/cli/kraft/kraft.go +++ b/internal/cli/kraft/kraft.go @@ -19,6 +19,7 @@ import ( "kraftkit.sh/config" "kraftkit.sh/internal/bootstrap" "kraftkit.sh/internal/cli" + "kraftkit.sh/internal/cli/kraft/lib" kitupdate "kraftkit.sh/internal/update" kitversion "kraftkit.sh/internal/version" "kraftkit.sh/iostreams" @@ -79,6 +80,9 @@ func NewCmd() *cobra.Command { cmd.AddCommand(set.NewCmd()) cmd.AddCommand(unset.NewCmd()) + cmd.AddGroup(&cobra.Group{ID: "lib", Title: "MICROLIBRARY COMMANDS"}) + cmd.AddCommand(lib.NewCmd()) + cmd.AddGroup(&cobra.Group{ID: "pkg", Title: "PACKAGING COMMANDS"}) cmd.AddCommand(pkg.NewCmd()) diff --git a/internal/cli/kraft/lib/lib.go b/internal/cli/kraft/lib/lib.go new file mode 100644 index 000000000..05d61202e --- /dev/null +++ b/internal/cli/kraft/lib/lib.go @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2022, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. +package lib + +import ( + "context" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "kraftkit.sh/cmdfactory" + "kraftkit.sh/internal/cli/kraft/lib/remove" +) + +type Lib struct{} + +func NewCmd() *cobra.Command { + cmd, err := cmdfactory.New(&Lib{}, cobra.Command{ + Short: "Manage and maintain Unikraft microlibraries", + Use: "lib SUBCOMMAND", + Aliases: []string{"library"}, + Hidden: true, + Annotations: map[string]string{ + cmdfactory.AnnotationHelpGroup: "lib", + }, + }) + if err != nil { + panic(err) + } + + cmd.AddCommand(remove.NewCmd()) + + return cmd +} + +func (opts *Lib) Run(ctx context.Context, args []string) error { + return pflag.ErrHelp +} diff --git a/internal/cli/kraft/lib/remove/remove.go b/internal/cli/kraft/lib/remove/remove.go new file mode 100644 index 000000000..78e7c68e1 --- /dev/null +++ b/internal/cli/kraft/lib/remove/remove.go @@ -0,0 +1,89 @@ +package remove + +import ( + "context" + "os" + + "github.com/spf13/cobra" + "kraftkit.sh/cmdfactory" + "kraftkit.sh/packmanager" + "kraftkit.sh/unikraft/app" +) + +type RemoveOptions struct { + Workdir string `long:"workdir" short:"w" usage:"workdir to remove lib from"` + Kraftfile string `long:"kraftfile" short:"K" usage:"Set an alternative path of the Kraftfile"` +} + +// Remove a Unikraft library from the project directory. +func Remove(ctx context.Context, opts *RemoveOptions, args ...string) error { + if opts == nil { + opts = &RemoveOptions{} + } + + return opts.Run(ctx, args) +} + +func NewCmd() *cobra.Command { + cmd, err := cmdfactory.New(&RemoveOptions{}, cobra.Command{ + Short: "Removes a library dependency from the project directory", + Use: "remove [FLAGS] LIB", + Aliases: []string{"rm"}, + Args: cmdfactory.MinimumArgs(1, "library name is not specified to remove from the project"), + Annotations: map[string]string{ + cmdfactory.AnnotationHelpGroup: "lib", + }, + }) + if err != nil { + panic(err) + } + + return cmd +} + +func (opts *RemoveOptions) Pre(cmd *cobra.Command, _ []string) error { + ctx, err := packmanager.WithDefaultUmbrellaManagerInContext(cmd.Context()) + if err != nil { + return err + } + cmd.SetContext(ctx) + return nil +} + +func (opts *RemoveOptions) Run(ctx context.Context, args []string) error { + var workdir string + var err error + + if len(opts.Workdir) > 0 { + workdir = opts.Workdir + } + + if workdir == "." || workdir == "./" || workdir == "" { + workdir, err = os.Getwd() + } + if err != nil { + return err + } + + popts := []app.ProjectOption{} + + if len(opts.Kraftfile) > 0 { + popts = append(popts, app.WithProjectKraftfile(opts.Kraftfile)) + } else { + popts = append(popts, app.WithProjectDefaultKraftfiles()) + } + + project, err := app.NewProjectFromOptions( + ctx, + append(popts, app.WithProjectWorkdir(workdir))..., + ) + if err != nil { + return err + } + + if err = project.RemoveLibrary(ctx, args[0]); err != nil { + return err + } + + return project.Save(ctx) +} diff --git a/unikraft/app/application.go b/unikraft/app/application.go index 9c8eda251..a90c948c5 100644 --- a/unikraft/app/application.go +++ b/unikraft/app/application.go @@ -140,6 +140,9 @@ type Application interface { // Volumes to be used during runtime of an application. Volumes() []*volume.VolumeConfig + + // Removes library from the project directory + RemoveLibrary(ctx context.Context, libraryName string) error } type application struct { @@ -984,7 +987,7 @@ func saveNewKraftfile(ctx context.Context, app Application) error { defer kraftfile.Close() // Write the schema version to the file - _, err = kraftfile.WriteString(fmt.Sprintf("spec: %s\n", schema.SchemaVersionLatest)) + _, err = kraftfile.WriteString(fmt.Sprintf("spec: '%s'\n", schema.SchemaVersionLatest)) if err != nil { return err } @@ -1030,3 +1033,43 @@ func (app application) Save(ctx context.Context) error { func (app application) Volumes() []*volume.VolumeConfig { return app.volumes } + +func (app application) RemoveLibrary(ctx context.Context, libraryName string) error { + isLibraryExistInProject := false + for libKey, lib := range app.libraries { + if lib.Name() == libraryName { + isLibraryExistInProject = true + delete(app.libraries, libKey) + + yamlFile, err := os.ReadFile(app.kraftfile.path) + if err != nil { + return err + } + + yamlMap := app + err = yaml.Unmarshal(yamlFile, &yamlMap) + if err != nil { + return err + } + + delete(yamlMap.libraries, libKey) + err = saveNewKraftfile(ctx, yamlMap) + if err != nil { + return err + } + + // Remove library directory from the project directory + libPath := filepath.Join(app.WorkingDir(), unikraft.LibsDir, libraryName) + if _, err = os.Stat(libPath); err == nil { + err = os.RemoveAll(libPath) + if err != nil { + return err + } + } + } + } + if !isLibraryExistInProject { + return fmt.Errorf("library %s does not exist in the project", libraryName) + } + return nil +} diff --git a/unikraft/unikraft.go b/unikraft/unikraft.go index 3955b4b48..d5bd91751 100644 --- a/unikraft/unikraft.go +++ b/unikraft/unikraft.go @@ -34,4 +34,5 @@ const ( // Built-in paths VendorDir = ".unikraft" BuildDir = ".unikraft/build" + LibsDir = ".unikraft/libs" )