summaryrefslogtreecommitdiff
path: root/cmd/commandfuncs.go
diff options
context:
space:
mode:
authorOleg <musinit@yandex.ru>2021-08-12 02:31:41 +0300
committerGitHub <noreply@github.com>2021-08-11 17:31:41 -0600
commit68c5c71659109b10226f10873f7dc67102b9dc14 (patch)
treeba591e189bd369fffafe95418ff0a6ac1b0d7733 /cmd/commandfuncs.go
parent569ecdbd02a3bdf8589f785cca022240973dea4d (diff)
cmd: New `add-package` and `remove-package` commands (#4226)
* adding package command * add-package command name * refactoring duplicate code * fixed by review * fixed by review * remove-package command * commands in different files, common utils * fix add, remove, upgrade packages in 1 file * copyright and downloadPath moved * refactor * downloadPath do no export * adding/removing multiple packages * addPackages/removePackages, comments, command-desc * add-package, process case len(args) == 0 Co-authored-by: Francis Lavoie <lavofr@gmail.com>
Diffstat (limited to 'cmd/commandfuncs.go')
-rw-r--r--cmd/commandfuncs.go197
1 files changed, 0 insertions, 197 deletions
diff --git a/cmd/commandfuncs.go b/cmd/commandfuncs.go
index 58b9720..c70b57a 100644
--- a/cmd/commandfuncs.go
+++ b/cmd/commandfuncs.go
@@ -25,10 +25,8 @@ import (
"log"
"net"
"net/http"
- "net/url"
"os"
"os/exec"
- "reflect"
"runtime"
"runtime/debug"
"sort"
@@ -570,151 +568,6 @@ func cmdFmt(fl Flags) (int, error) {
return caddy.ExitCodeSuccess, nil
}
-func cmdUpgrade(_ Flags) (int, error) {
- l := caddy.Log()
-
- thisExecPath, err := os.Executable()
- if err != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("determining current executable path: %v", err)
- }
- thisExecStat, err := os.Stat(thisExecPath)
- if err != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("retrieving current executable permission bits: %v", err)
- }
- l.Info("this executable will be replaced", zap.String("path", thisExecPath))
-
- // get the list of nonstandard plugins
- _, nonstandard, _, err := getModules()
- if err != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("unable to enumerate installed plugins: %v", err)
- }
- pluginPkgs := make(map[string]struct{})
- for _, mod := range nonstandard {
- if mod.goModule.Replace != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("cannot auto-upgrade when Go module has been replaced: %s => %s",
- mod.goModule.Path, mod.goModule.Replace.Path)
- }
- l.Info("found non-standard module",
- zap.String("id", mod.caddyModuleID),
- zap.String("package", mod.goModule.Path))
- pluginPkgs[mod.goModule.Path] = struct{}{}
- }
-
- // build the request URL to download this custom build
- qs := url.Values{
- "os": {runtime.GOOS},
- "arch": {runtime.GOARCH},
- }
- for pkg := range pluginPkgs {
- qs.Add("p", pkg)
- }
- urlStr := fmt.Sprintf("https://caddyserver.com/api/download?%s", qs.Encode())
-
- // initiate the build
- l.Info("requesting build",
- zap.String("os", qs.Get("os")),
- zap.String("arch", qs.Get("arch")),
- zap.Strings("packages", qs["p"]))
- resp, err := http.Get(urlStr)
- if err != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("secure request failed: %v", err)
- }
- defer resp.Body.Close()
- if resp.StatusCode >= 400 {
- var details struct {
- StatusCode int `json:"status_code"`
- Error struct {
- Message string `json:"message"`
- ID string `json:"id"`
- } `json:"error"`
- }
- err2 := json.NewDecoder(resp.Body).Decode(&details)
- if err2 != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("download and error decoding failed: HTTP %d: %v", resp.StatusCode, err2)
- }
- return caddy.ExitCodeFailedStartup, fmt.Errorf("download failed: HTTP %d: %s (id=%s)", resp.StatusCode, details.Error.Message, details.Error.ID)
- }
-
- // back up the current binary, in case something goes wrong we can replace it
- backupExecPath := thisExecPath + ".tmp"
- l.Info("build acquired; backing up current executable",
- zap.String("current_path", thisExecPath),
- zap.String("backup_path", backupExecPath))
- err = os.Rename(thisExecPath, backupExecPath)
- if err != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("backing up current binary: %v", err)
- }
- defer func() {
- if err != nil {
- err2 := os.Rename(backupExecPath, thisExecPath)
- if err2 != nil {
- l.Error("restoring original executable failed; will need to be restored manually",
- zap.String("backup_path", backupExecPath),
- zap.String("original_path", thisExecPath),
- zap.Error(err2))
- }
- }
- }()
-
- // download the file; do this in a closure to close reliably before we execute it
- writeFile := func() error {
- destFile, err := os.OpenFile(thisExecPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, thisExecStat.Mode())
- if err != nil {
- return fmt.Errorf("unable to open destination file: %v", err)
- }
- defer destFile.Close()
-
- l.Info("downloading binary", zap.String("source", urlStr), zap.String("destination", thisExecPath))
-
- _, err = io.Copy(destFile, resp.Body)
- if err != nil {
- return fmt.Errorf("unable to download file: %v", err)
- }
-
- err = destFile.Sync()
- if err != nil {
- return fmt.Errorf("syncing downloaded file to device: %v", err)
- }
-
- return nil
- }
- err = writeFile()
- if err != nil {
- return caddy.ExitCodeFailedStartup, err
- }
-
- l.Info("download successful; displaying new binary details", zap.String("location", thisExecPath))
-
- // use the new binary to print out version and module info
- fmt.Print("\nModule versions:\n\n")
- cmd := exec.Command(thisExecPath, "list-modules", "--versions")
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- err = cmd.Run()
- if err != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to execute: %v", err)
- }
- fmt.Println("\nVersion:")
- cmd = exec.Command(thisExecPath, "version")
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- err = cmd.Run()
- if err != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to execute: %v", err)
- }
- fmt.Println()
-
- // clean up the backup file
- err = os.Remove(backupExecPath)
- if err != nil {
- return caddy.ExitCodeFailedStartup, fmt.Errorf("download succeeded, but unable to clean up backup binary: %v", err)
- }
-
- l.Info("upgrade successful; please restart any running Caddy instances", zap.String("executable", thisExecPath))
-
- return caddy.ExitCodeSuccess, nil
-}
-
func cmdHelp(fl Flags) (int, error) {
const fullDocs = `Full documentation is available at:
https://caddyserver.com/docs/command-line`
@@ -779,56 +632,6 @@ commands:
return caddy.ExitCodeSuccess, nil
}
-func getModules() (standard, nonstandard, unknown []moduleInfo, err error) {
- bi, ok := debug.ReadBuildInfo()
- if !ok {
- err = fmt.Errorf("no build info")
- return
- }
-
- for _, modID := range caddy.Modules() {
- modInfo, err := caddy.GetModule(modID)
- if err != nil {
- // that's weird, shouldn't happen
- unknown = append(unknown, moduleInfo{caddyModuleID: modID, err: err})
- continue
- }
-
- // to get the Caddy plugin's version info, we need to know
- // the package that the Caddy module's value comes from; we
- // can use reflection but we need a non-pointer value (I'm
- // not sure why), and since New() should return a pointer
- // value, we need to dereference it first
- iface := interface{}(modInfo.New())
- if rv := reflect.ValueOf(iface); rv.Kind() == reflect.Ptr {
- iface = reflect.New(reflect.TypeOf(iface).Elem()).Elem().Interface()
- }
- modPkgPath := reflect.TypeOf(iface).PkgPath()
-
- // now we find the Go module that the Caddy module's package
- // belongs to; we assume the Caddy module package path will
- // be prefixed by its Go module path, and we will choose the
- // longest matching prefix in case there are nested modules
- var matched *debug.Module
- for _, dep := range bi.Deps {
- if strings.HasPrefix(modPkgPath, dep.Path) {
- if matched == nil || len(dep.Path) > len(matched.Path) {
- matched = dep
- }
- }
- }
-
- caddyModGoMod := moduleInfo{caddyModuleID: modID, goModule: matched}
-
- if strings.HasPrefix(modPkgPath, caddy.ImportPath) {
- standard = append(standard, caddyModGoMod)
- } else {
- nonstandard = append(nonstandard, caddyModGoMod)
- }
- }
- return
-}
-
// apiRequest makes an API request to the endpoint adminAddr with the
// given HTTP method and request URI. If body is non-nil, it will be
// assumed to be Content-Type application/json.