github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/runbits/runtime/rationalize.go (about)

     1  package runtime
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/ActiveState/cli/internal/constants"
     9  	"github.com/ActiveState/cli/internal/errs"
    10  	"github.com/ActiveState/cli/internal/locale"
    11  	"github.com/ActiveState/cli/internal/runbits/rationalize"
    12  	"github.com/ActiveState/cli/pkg/platform/api"
    13  	bpResp "github.com/ActiveState/cli/pkg/platform/api/buildplanner/response"
    14  	"github.com/ActiveState/cli/pkg/platform/authentication"
    15  	"github.com/ActiveState/cli/pkg/platform/model"
    16  	"github.com/ActiveState/cli/pkg/platform/runtime"
    17  	"github.com/ActiveState/cli/pkg/platform/runtime/setup"
    18  	"github.com/ActiveState/cli/pkg/platform/runtime/setup/buildlog"
    19  	"github.com/ActiveState/cli/pkg/project"
    20  )
    21  
    22  func rationalizeError(auth *authentication.Auth, proj *project.Project, rerr *error) {
    23  	if *rerr == nil {
    24  		return
    25  	}
    26  	var noMatchingPlatformErr *model.ErrNoMatchingPlatform
    27  	var artifactDownloadErr *setup.ArtifactDownloadError
    28  	var buildPlannerErr *bpResp.BuildPlannerError
    29  	var artifactCachedBuildErr *setup.ArtifactCachedBuildFailed
    30  	var artifactBuildErr *buildlog.ArtifactBuildError
    31  
    32  	switch {
    33  	case errors.Is(*rerr, rationalize.ErrHeadless):
    34  		*rerr = errs.WrapUserFacing(*rerr,
    35  			locale.Tr("err_headless", proj.URL()),
    36  			errs.SetInput())
    37  
    38  	// Could not find a platform that matches on the given branch, so suggest alternate branches if ones exist
    39  	case errors.As(*rerr, &noMatchingPlatformErr):
    40  		branches, err := model.BranchNamesForProjectFiltered(proj.Owner(), proj.Name(), proj.BranchName())
    41  		if err == nil && len(branches) > 0 {
    42  			// Suggest alternate branches
    43  			*rerr = errs.NewUserFacing(locale.Tr(
    44  				"err_alternate_branches",
    45  				noMatchingPlatformErr.HostPlatform, noMatchingPlatformErr.HostArch,
    46  				proj.BranchName(), strings.Join(branches, "\n - ")))
    47  		} else {
    48  			libcErr := noMatchingPlatformErr.LibcVersion != ""
    49  			*rerr = errs.NewUserFacing(
    50  				locale.Tr("err_no_platform_data_remains", noMatchingPlatformErr.HostPlatform, noMatchingPlatformErr.HostArch),
    51  				errs.SetIf(libcErr, errs.SetInput()),
    52  				errs.SetIf(libcErr, errs.SetTips(locale.Tr("err_user_libc_solution", api.GetPlatformURL(fmt.Sprintf("%s/%s", proj.NamespaceString(), "customize")).String()))),
    53  			)
    54  		}
    55  
    56  	// If there was an artifact download error, say so, rather than reporting a generic "could not
    57  	// update runtime" error.
    58  	case errors.As(*rerr, &artifactDownloadErr):
    59  		*rerr = errs.WrapUserFacing(*rerr,
    60  			locale.Tl("err_runtime_setup_download", "Your runtime could not be installed or updated because one or more artifacts failed to download."),
    61  			errs.SetInput(),
    62  			errs.SetTips(locale.Tr("err_user_network_solution", constants.ForumsURL)),
    63  		)
    64  
    65  	// We communicate buildplanner errors verbatim as the intend is that these are curated by the buildplanner
    66  	case errors.As(*rerr, &buildPlannerErr):
    67  		*rerr = errs.WrapUserFacing(*rerr,
    68  			buildPlannerErr.LocalizedError(),
    69  			errs.SetIf(buildPlannerErr.InputError(), errs.SetInput()))
    70  
    71  	// User has modified the buildscript and needs to run `state commit`
    72  	case errors.Is(*rerr, runtime.NeedsCommitError):
    73  		*rerr = errs.WrapUserFacing(*rerr, locale.T("notice_commit_build_script"), errs.SetInput())
    74  
    75  	// Buildscript is missing and needs to be recreated
    76  	case errors.Is(*rerr, runtime.NeedsBuildscriptResetError):
    77  		*rerr = errs.WrapUserFacing(*rerr, locale.T("notice_needs_buildscript_reset"), errs.SetInput())
    78  
    79  	// Artifact cached build errors
    80  	case errors.As(*rerr, &artifactCachedBuildErr):
    81  		errMsg := locale.Tr("err_build_artifact_failed_msg", artifactCachedBuildErr.Artifact.Name())
    82  		*rerr = errs.WrapUserFacing(*rerr,
    83  			locale.Tr("err_build_artifact_failed",
    84  				errMsg, strings.Join(artifactCachedBuildErr.Artifact.Errors, "\n"), artifactCachedBuildErr.Artifact.LogURL,
    85  			),
    86  			errs.SetInput(),
    87  		)
    88  
    89  	// Artifact build errors
    90  	case errors.As(*rerr, &artifactBuildErr):
    91  		errMsg := locale.Tr("err_build_artifact_failed_msg", artifactBuildErr.Artifact.Name())
    92  		*rerr = errs.WrapUserFacing(*rerr,
    93  			locale.Tr("err_build_artifact_failed",
    94  				errMsg, artifactBuildErr.Message.ErrorMessage, artifactBuildErr.Message.LogURI,
    95  			),
    96  			errs.SetInput(),
    97  		)
    98  
    99  	// If updating failed due to unidentified errors, and the user is not authenticated, add a tip suggesting that they authenticate as
   100  	// this may be a private project.
   101  	// Note since we cannot assert the actual error type we do not wrap this as user-facing, as we do not know what we're
   102  	// dealing with so the localized underlying errors are more appropriate.
   103  	default:
   104  		// Add authentication tip if we could not assert the error type
   105  		// This must only happen after all error assertions have failed, because if we can assert the error we can give
   106  		// an appropriate message, rather than a vague tip that suggests MAYBE this is a private project.
   107  		if !auth.Authenticated() {
   108  			*rerr = errs.AddTips(*rerr,
   109  				locale.T("tip_private_project_auth"),
   110  			)
   111  		}
   112  
   113  	}
   114  }